[PATCH v6 2/3] sbi_utils: mpxy: add FDT-based MPXY bridge driver

Anup Patel anup at brainfault.org
Sun Nov 1 04:32:31 PST 2026


On Mon, Oct 26, 2026 at 9:44 PM Pawandeep Oza
<pawandeep.oza at oss.qualcomm.com> wrote:
>
> From: Oza Pawandeep <pawandeep.oza at oss.qualcomm.com>

Patch subject should be: "sbi_utils: mpxy: Add FDT-based MPXY RPMI
bridge driver"

The word RPMI is very important because the bridge assumes RPMI protocol
and request forward service group is defined in RPMI spec.

>
> Introduce an FDT-configured MPXY bridge driver that enables

same comment as above.

> cooperative message passing between two SBI domains sharing the
> same physical hart via domain context switching.
>
> MPXY channels are registered at runtime when the named domains
> appear via the domain registration notifier:
>
>   - src_ch: used by the source domain to send messages
>   - dst_ch: used by the destination domain to retrieve and
>     complete forwarded messages via RPMI REQFWD service group
>
> Signed-off-by: Oza Pawandeep <pawandeep.oza at oss.qualcomm.com>
> ---
>  include/sbi_utils/mailbox/rpmi_msgprot.h |    1 +
>  include/sbi_utils/mpxy/fdt_mpxy_bridge.h |   61 ++
>  lib/utils/mpxy/Kconfig                   |    4 +
>  lib/utils/mpxy/fdt_mpxy_bridge.c         | 1000 ++++++++++++++++++++++
>  lib/utils/mpxy/objects.mk                |    3 +
>  platform/generic/configs/defconfig       |    2 +
>  6 files changed, 1071 insertions(+)
>  create mode 100644 include/sbi_utils/mpxy/fdt_mpxy_bridge.h
>  create mode 100644 lib/utils/mpxy/fdt_mpxy_bridge.c
>
> diff --git a/include/sbi_utils/mailbox/rpmi_msgprot.h b/include/sbi_utils/mailbox/rpmi_msgprot.h
> index c5d564ac..fce08a9d 100644
> --- a/include/sbi_utils/mailbox/rpmi_msgprot.h
> +++ b/include/sbi_utils/mailbox/rpmi_msgprot.h
> @@ -225,6 +225,7 @@ enum rpmi_servicegroup_id {
>         RPMI_SRVGRP_DEVICE_POWER = 0x0009,
>         RPMI_SRVGRP_PERFORMANCE = 0x0000A,
>         RPMI_SRVGRP_MANAGEMENT_MODE = 0x000B,
> +       RPMI_SRVGRP_REQFWD = 0x000D,
>         RPMI_SRVGRP_LOGGING = 0x000E,
>         RPMI_SRVGRP_ID_MAX_COUNT,

This change belongs to PATCH1.

>
> diff --git a/include/sbi_utils/mpxy/fdt_mpxy_bridge.h b/include/sbi_utils/mpxy/fdt_mpxy_bridge.h
> new file mode 100644
> index 00000000..c86fb6ae
> --- /dev/null
> +++ b/include/sbi_utils/mpxy/fdt_mpxy_bridge.h
> @@ -0,0 +1,61 @@
> +/* SPDX-License-Identifier: BSD-2-Clause */
> +/*
> + * Copyright (c) 2026 Qualcomm, Inc
> + *
> + * Authors:
> + *   Pawandeep Oza <pawandeep.oza at oss.qualcomm.com>
> + */
> +
> +#ifndef __FDT_MPXY_BRIDGE_H__
> +#define __FDT_MPXY_BRIDGE_H__
> +
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_types.h>
> +#include <sbi/sbi_domain.h>
> +#include <sbi/sbi_string.h>
> +#include <sbi_utils/mpxy/fdt_mpxy_rpmi.h>
> +
> +#define SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN  4096
> +#define SBI_MPXY_BRIDGE_DOMAIN_NAME_MAXLEN       64
> +
> +struct mpxy_bridge_source;
> +
> +struct mpxy_bridge_dst_ctx {
> +       void          *respbuf;
> +       u32            resp_bufsize;
> +       unsigned long *resp_len_ptr;
> +       u32            start_index;
> +};
> +
> +struct mpxy_bridge_src_ctx {
> +       struct rpmi_message_header header;;
> +       bool occupied;
> +       bool retrieved;
> +       bool completed;
> +       void *msgbuf;
> +       void *respbuf;
> +       u32  msg_len;
> +       u32  resp_bufsize;
> +       u32  resp_length;
> +};
> +
> +struct mpxy_bridge_source_driver {
> +    const struct fdt_match *match_table;
> +    int (*probe)(const void *fdt,
> +                       int nodeoff, const struct fdt_match *match);
> +};
> +
> +struct mpxy_bridge_source_ops {
> +       int (*xfer) (struct mpxy_bridge_src_ctx *src,
> +                               struct mpxy_bridge_dst_ctx *dst);
> +       int (*complete) (struct mpxy_bridge_src_ctx *src,
> +                               void *msgbuf, u32 msg_len);
> +};
> +
> +int mpxy_bridge_register_source(const void *fdt, int nodeoff,
> +                           const struct mpxy_bridge_source_ops *ops,
> +                           struct mpxy_rpmi_service_data *srvcdata,
> +                           u32 num_services,
> +                           enum rpmi_servicegroup_id srvgrpid);
> +
> +#endif /* __FDT_MPXY_BRIDGE_H__ */
> diff --git a/lib/utils/mpxy/Kconfig b/lib/utils/mpxy/Kconfig
> index 74cd3a32..13aa27ec 100644
> --- a/lib/utils/mpxy/Kconfig
> +++ b/lib/utils/mpxy/Kconfig
> @@ -7,6 +7,10 @@ config FDT_MPXY
>         depends on FDT
>         default n
>
> +config FDT_MPXY_BRIDGE
> +       bool "MPXY bridge driver for interdomain communication"
> +       default n
> +

This config option should be FDT_MPXY_RPMI_BRIDGE instead of FDT_MPXY_BRIDGE
Also, update option description accordingly.

Add the FDT_MPXY_RPMI_BRIDGE option under "if FDT_MPXY_RPMI"
because the MPXY RPMI bridge driver depends upon FDT_MPXY_RPMI.

>  config FDT_MPXY_RPMI
>         bool "FDT based MPXY RPMI drivers"
>         depends on FDT_MAILBOX && FDT_MPXY
> diff --git a/lib/utils/mpxy/fdt_mpxy_bridge.c b/lib/utils/mpxy/fdt_mpxy_bridge.c
> new file mode 100644
> index 00000000..ac44c3a6
> --- /dev/null
> +++ b/lib/utils/mpxy/fdt_mpxy_bridge.c

The source file should be named fdt_mpxy_rpmi_bridge.c

> @@ -0,0 +1,1000 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2026 Qualcomm, Inc
> + *
> + * Authors:
> + *   Pawandeep Oza <pawandeep.oza at oss.qualcomm.com>
> + */
> +
> +#include <libfdt.h>
> +#include <stdbool.h>
> +#include <stddef.h>
> +#include <sbi/riscv_asm.h>
> +#include <sbi/sbi_byteorder.h>
> +#include <sbi/sbi_domain_context.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi/sbi_list.h>
> +#include <sbi/sbi_mpxy.h>
> +#include <sbi/sbi_platform.h>
> +#include <sbi/sbi_scratch.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +#include <sbi_utils/mailbox/rpmi_msgprot.h>
> +#include <sbi_utils/mailbox/rpmi_mailbox.h>
> +#include <sbi_utils/mailbox/mailbox.h>
> +#include <sbi_utils/mpxy/fdt_mpxy_bridge.h>
> +
> +#define SBI_MPXY_BRIDGE_COMPATIBLE  "opensbi,rpmi-mpxy-reqfwd-bridge"
> +#define SBI_MPXY_BRIDGE_PROP_DOMAIN_NAME "riscv,domain"

Drop the "_NAME" from the define because "riscv,domain" points to
domain DT node using phandle.

> +#define SBI_MPXY_BRIDGE_PROP_CHAN "riscv,sbi-mpxy-channel-id"
> +
> +
> +static const struct mpxy_bridge_source_driver *source_drivers[] = {
> +};

It is better to create new carray fdt_mpxy_rpmi_bridge_source_drivers
under lib/utils/mpxy

This will allow us to add bridge source drivers without any
changes in the fdt_mpxy_rpmi_bridge.c

> +
> +static uint16_t token = 0;
> +
> +struct mpxy_bridge_hart_slot {
> +       int                        active_source;
> +       struct mpxy_bridge_src_ctx *src_ctx;
> +       struct mpxy_bridge_dst_ctx  dst_resp;
> +};
> +
> +struct mpxy_bridge_slot_store {
> +       struct mpxy_bridge_hart_slot *slots;
> +       u32 hart_count;
> +};
> +
> +struct bridge_rpmi_endpoint {
> +       struct mpxy_rpmi_data rpmi_data;
> +       struct mpxy_bridge *bridge;
> +       struct sbi_domain *domain;
> +       struct sbi_mpxy_channel *channel;
> +};
> +
> +struct mpxy_bridge_endpoint {
> +       char domain_name[SBI_MPXY_BRIDGE_DOMAIN_NAME_MAXLEN];
> +       u32  channel_id;
> +       struct sbi_domain *dom;
> +       struct sbi_mpxy_channel ch;
> +       struct bridge_rpmi_endpoint rpmi_endpoint;
> +};

Merge "struct bridge_rpmi_endpoint" into "struct mpxy_bridge_endpoint"
otherwise endpoint related code is confusing.

> +
> +struct mpxy_bridge_source {
> +       int nodeoff;
> +       struct mpxy_bridge_endpoint ep;
> +       const struct mpxy_bridge_source_ops *ops;
> +};
> +
> +struct mpxy_bridge_destination {
> +       struct mpxy_bridge_endpoint ep;
> +};
> +
> +struct mpxy_bridge {
> +       struct sbi_dlist node;
> +       int nodeoff;
> +       struct mpxy_bridge_destination dst;
> +       struct mpxy_bridge_source *sources;
> +       u32 source_count;
> +       struct mpxy_bridge_slot_store store;
> +};
> +
> +static SBI_LIST_HEAD(mpxy_bridge_list);
> +static bool mpxy_bridge_notifier_registered;
> +
> +static bool bridge_name_match(const char *a, const char *b)
> +{
> +       return a && b && !sbi_strcmp(a, b);
> +}
> +
> +static int bridge_source_index(struct mpxy_bridge *br,
> +                              struct sbi_mpxy_channel *channel)
> +{
> +       u32 i;
> +
> +       for (i = 0; i < br->source_count; i++)
> +               if (&br->sources[i].ep.ch == channel)
> +                       return (int)i;
> +
> +       return -1;
> +}
> +
> +static struct mpxy_bridge *bridge_from_channel(
> +                                       struct sbi_mpxy_channel *channel)
> +{
> +       struct mpxy_bridge *br;
> +       u32 i;
> +
> +       sbi_list_for_each_entry(br, &mpxy_bridge_list, node) {
> +               if (&br->dst.ep.ch == channel)
> +                       return br;
> +               for (i = 0; i < br->source_count; i++)
> +                       if (&br->sources[i].ep.ch == channel)
> +                               return br;
> +       }
> +
> +       return NULL;
> +}
> +
> +static int bridge_get_current_slot(struct mpxy_bridge *br,
> +                                  struct mpxy_bridge_hart_slot **slot)
> +{
> +       u32 hartindex = current_hartindex();
> +
> +       if (hartindex >= br->store.hart_count)
> +               return SBI_ERR_INVALID_PARAM;
> +
> +       *slot = &br->store.slots[hartindex];
> +       return SBI_OK;
> +}
> +
> +static void bridge_src_ctx_set(struct mpxy_bridge_src_ctx *src,
> +                              void *msgbuf, u32 msg_len,
> +                              void *respbuf, u32 resp_bufsize,
> +                              unsigned long *resp_len)
> +{
> +       src->msgbuf       = msgbuf;
> +       src->msg_len      = msg_len;
> +       src->respbuf      = respbuf;
> +       src->resp_bufsize = resp_bufsize;
> +}
> +
> +static void bridge_src_ctx_release(struct mpxy_bridge_src_ctx *src)
> +{
> +       if (src)
> +               *src = (struct mpxy_bridge_src_ctx){ 0 };
> +}
> +
> +static void bridge_slot_release(struct mpxy_bridge *br,
> +                               struct mpxy_bridge_hart_slot *slot)
> +{
> +       u32 i;
> +
> +       if (!br || !slot)
> +               return;
> +
> +       for (i = 0; i < br->source_count; i++)
> +               bridge_src_ctx_release(&slot->src_ctx[i]);
> +
> +       slot->active_source = -1;
> +       slot->dst_resp = (struct mpxy_bridge_dst_ctx){ 0 };
> +}
> +
> +static int bridge_find_pending_source(struct mpxy_bridge *br,
> +                                     struct mpxy_bridge_hart_slot *slot)
> +{
> +       u32 i;
> +
> +       for (i = 0; i < br->source_count; i++)
> +               if (slot->src_ctx[i].occupied && !slot->src_ctx[i].retrieved)
> +                       return (int)i;
> +
> +       return -1;
> +}
> +
> +static int bridge_find_completed_source(struct mpxy_bridge *br,
> +                                     struct mpxy_bridge_hart_slot *slot)
> +{
> +       u32 i;
> +
> +       for (i = 0; i < br->source_count; i++)
> +               if (slot->src_ctx[i].occupied &&
> +                       slot->src_ctx[i].retrieved &&
> +                       slot->src_ctx[i].completed )
> +                       return (int)i;
> +
> +       return -1;
> +}
> +
> +struct mpxy_bridge *bridge_find_by_nodeoff(int nodeoff)
> +{
> +       struct mpxy_bridge *br;
> +
> +       sbi_list_for_each_entry(br, &mpxy_bridge_list, node) {
> +               if (br->nodeoff == nodeoff)
> +                       return br;
> +       }
> +
> +       return NULL;
> +}
> +
> +static void bridge_switch_domain(struct mpxy_bridge *br,
> +                                struct sbi_mpxy_channel *channel)
> +{
> +       if (channel == &br->dst.ep.ch)
> +               sbi_domain_context_exit();
> +       else
> +               sbi_domain_context_enter(br->dst.ep.ch.owner_domain);
> +}
> +
> +static void bridge_save_dst_ctx(struct mpxy_bridge_hart_slot *slot,
> +                               void *respbuf, u32 resp_bufsize,
> +                               unsigned long *resp_len, void *msgbuf)
> +{
> +       slot->dst_resp.respbuf      = respbuf;
> +       slot->dst_resp.resp_bufsize = resp_bufsize;
> +       slot->dst_resp.resp_len_ptr = resp_len;
> +       slot->dst_resp.start_index  = msgbuf ? ((u32 *)msgbuf)[0] : 0;
> +}
> +
> +static int bridge_dst_complete(struct mpxy_bridge *br,
> +                              struct mpxy_bridge_hart_slot *slot,
> +                              void *msgbuf, u32 msg_len, void *respbuf,
> +                              u32 resp_max_len, unsigned long *resp_len)
> +{
> +       struct rpmi_request_complete_resp *resp;
> +       struct mpxy_bridge_src_ctx *src = NULL;
> +       struct mpxy_bridge_source *source;
> +       int active_source;
> +       int ret = SBI_OK;
> +
> +       resp = (struct rpmi_request_complete_resp *)respbuf;
> +       active_source = slot->active_source;
> +
> +       do {
> +               if (active_source < 0) {
> +                       resp->status = RPMI_ERR_NO_DATA;
> +                       break;
> +               }
> +
> +               src = &slot->src_ctx[active_source];
> +
> +               if (!src->occupied || !src->retrieved) {
> +                       resp->status = RPMI_ERR_NO_DATA;
> +                       break;
> +               }
> +
> +               source = &br->sources[active_source];
> +               ret = source->ops->complete(src, msgbuf, msg_len);
> +               src->completed = true;
> +               if (ret)
> +                       resp->status   = RPMI_ERR_NOTSUPP;
> +               else
> +                       resp->status   = RPMI_SUCCESS;
> +       } while (0);

Why do we need this "do { } while (0)" ??

> +
> +       /*
> +        * Number of forwarded messages available for retrieval
> +        * this is always 0 as source is stalled on the same hart till the complete
> +        * completes.
> +        */
> +       resp->num_of_messages = 0;
> +       *resp_len = sizeof(*resp);
> +
> +       return SBI_OK;
> +}
> +
> +static int bridge_dst_send_message_with_response(
> +                               struct mpxy_bridge *br,
> +                               struct mpxy_bridge_hart_slot *slot,
> +                               u32 msg_id, void *msgbuf, u32 msg_len,
> +                               void *respbuf, u32 resp_bufsize,
> +                               unsigned long *resp_len)
> +{
> +       struct mpxy_bridge_source *source;
> +       struct mpxy_bridge_src_ctx *src;
> +       int source_index;
> +       int ret = SBI_OK;
> +
> +       switch (msg_id) {
> +               case REQFWD_RETRIEVE_CURRENT_MESSAGE:
> +                       source_index = bridge_find_pending_source(br, slot);
> +                       bridge_save_dst_ctx(slot, respbuf, resp_bufsize, resp_len, msgbuf);
> +                       /*
> +                        * Waiting for the message from one of the sources.
> +                        * schedule the next domain.
> +                        */
> +                       if (source_index < 0) {
> +                                       source_index = bridge_find_completed_source(br, slot);
> +                                       if (source_index >= 0) {
> +                                               /* it is time to send reponse back to the source domain. */
> +                                               source = &br->sources[source_index];
> +                                               src = &slot->src_ctx[source_index];
> +                                               slot->active_source = -1;
> +                                               *resp_len = src->resp_length;
> +                                               bridge_src_ctx_release(src);
> +                                       }
> +                               bridge_switch_domain(br, &br->dst.ep.ch);
> +                       } else {
> +                               source = &br->sources[source_index];
> +                               src = &slot->src_ctx[source_index];
> +                               /* hand over the transfer to the source driver. */
> +                               ret = source->ops->xfer(src, &slot->dst_resp);
> +                               src->retrieved = true;
> +                       }
> +                       break;
> +
> +               case REQFWD_COMPLETE_CURRENT_MESSAGE:
> +                       ret = bridge_dst_complete(br, slot, msgbuf, msg_len,
> +                                               respbuf, resp_bufsize, resp_len);
> +                       break;
> +
> +               default:
> +                       ret = SBI_ERR_NOT_SUPPORTED;
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +
> +static int bridge_src_ctx_occupy(struct mpxy_bridge_src_ctx *src)
> +{
> +       if (src->occupied) {
> +               sbi_printf("%s: slot occupied\n", __func__);
> +               return SBI_ERR_FAILED;
> +       }
> +       src->occupied = true;
> +       src->retrieved = false;
> +
> +       return SBI_OK;
> +}
> +
> +static int bridge_send_message_with_response(struct sbi_mpxy_channel *channel,
> +                                            u32 msg_id, void *msgbuf, u32 msg_len,
> +                                            void *respbuf, u32 resp_bufsize,
> +                                            unsigned long *resp_len)
> +{
> +       struct mpxy_bridge *br;
> +       struct mpxy_bridge_src_ctx *src;
> +       struct mpxy_bridge_source *source;
> +       struct mpxy_bridge_hart_slot *slot = NULL;
> +       int source_index;
> +       int ret = SBI_OK;
> +
> +       do {
> +               br = bridge_from_channel(channel);
> +               if (!br) {
> +                       ret = SBI_ERR_NOT_SUPPORTED;
> +                       break;
> +               }
> +
> +               ret = bridge_get_current_slot(br, &slot);
> +               if (ret)
> +                       break;
> +
> +               if (channel == &br->dst.ep.ch) {
> +                       ret = bridge_dst_send_message_with_response(br, slot, msg_id,
> +                                                                   msgbuf, msg_len,
> +                                                                   respbuf, resp_bufsize,
> +                                                                   resp_len);
> +                       break;
> +               }
> +
> +               source_index = bridge_source_index(br, channel);
> +               if (source_index < 0) {
> +                       ret = SBI_ERR_NOT_SUPPORTED;
> +                       break;
> +               }
> +
> +               src    = &slot->src_ctx[source_index];
> +               source = &br->sources[source_index];
> +
> +               src->header.servicegroup_id =
> +                       cpu_to_le16(source->ep.rpmi_endpoint.rpmi_data.servicegrp_id);
> +               src->header.service_id = msg_id;
> +               src->header.flags = 0;
> +               src->header.datalen = cpu_to_le16(sizeof(src->header)) + msg_len;
> +               src->header.token = cpu_to_le16(++token);
> +
> +               bridge_src_ctx_set(src, msgbuf, msg_len, respbuf,
> +                                  resp_bufsize, resp_len);
> +
> +               ret = bridge_src_ctx_occupy(src);
> +               slot->active_source = source_index;
> +
> +               if (!ret) {
> +                       if (slot->dst_resp.respbuf) {
> +                               ret = source->ops->xfer(src, &slot->dst_resp);
> +                               src->retrieved = true;
> +                       }
> +                       bridge_switch_domain(br, &br->sources[source_index].ep.ch);
> +               }
> +       } while (0);
> +
> +       return ret;
> +}
> +
> +static int bridge_rpmi_get_attribute_group(void *context,
> +                                          struct mbox_chan *chan,
> +                                          enum rpmi_channel_attribute_id attr_id,
> +                                          u32 *out_value)
> +{
> +       struct bridge_rpmi_endpoint *ep = context;
> +       (void)chan;
> +
> +       switch (attr_id) {
> +               case RPMI_CHANNEL_ATTR_PROTOCOL_VERSION:
> +                       *((u32 *)out_value) = 1;
> +                       break;
> +               case RPMI_CHANNEL_ATTR_MAX_DATA_LEN:
> +                       *((u32 *)out_value) = SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN;
> +                       break;
> +               case RPMI_CHANNEL_ATTR_TX_TIMEOUT:
> +                       *((u32 *)out_value) = RPMI_DEF_TX_TIMEOUT;
> +                       break;
> +               case RPMI_CHANNEL_ATTR_RX_TIMEOUT:
> +                       *((u32 *)out_value) = RPMI_DEF_RX_TIMEOUT;
> +                       break;
> +               case RPMI_CHANNEL_ATTR_SERVICEGROUP_ID:
> +                       *((u32 *)out_value) = ep->rpmi_data.servicegrp_id;
> +                       break;
> +               default:
> +                       *((u32 *)out_value) = 0;
> +                       break;
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static int bridge_rpmi_xfer_group(void *context,
> +                                 struct mbox_chan *chan,
> +                                 struct mbox_xfer *xfer)
> +{
> +       struct bridge_rpmi_endpoint *ep = context;
> +       struct rpmi_message_args *args;
> +       unsigned long ack_len = 0;
> +       int ret;
> +
> +       (void)chan;
> +
> +       args = xfer->args;
> +
> +       /*
> +        * we only support send message with response.
> +        * TDO: bridge_send_message_without_response
> +        */
> +       if (! (args->flags & RPMI_MSG_FLAGS_NO_RX)) {
> +               ret = bridge_send_message_with_response(
> +                               ep->channel,
> +                               args->service_id,
> +                               xfer->tx, xfer->tx_len,
> +                               xfer->rx, xfer->rx_len,
> +                               &ack_len);
> +
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       args->rx_data_len = ack_len;
> +       xfer->rx_len      = ack_len;
> +
> +       return SBI_OK;
> +}
> +
> +static int bridge_rpmi_setup_group(void **context,
> +                                  struct mbox_chan *chan,
> +                                  struct sbi_domain *dom,
> +                                  const struct mpxy_rpmi_data *data)
> +{
> +       struct bridge_rpmi_endpoint *ep;
> +       int ret = SBI_OK;
> +
> +       (void)chan;
> +
> +       if (!context || !dom || !data)
> +               return SBI_EINVAL;
> +
> +       ep = container_of(data, struct bridge_rpmi_endpoint, rpmi_data);
> +
> +       ep->domain = dom;
> +       *context = ep;
> +       return ret;
> +}
> +
> +static struct mpxy_rpmi_service_data bridge_dst_rpmi_services[] = {
> +       {
> +               .id          = REQFWD_RETRIEVE_CURRENT_MESSAGE,
> +               .min_tx_len  = 0,
> +               .max_tx_len  = SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN,
> +               .min_rx_len  = sizeof(struct rpmi_request_forward_resp),
> +               .max_rx_len  = SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN,
> +       },
> +       {
> +               .id          = REQFWD_COMPLETE_CURRENT_MESSAGE,
> +               .min_tx_len  = 0,
> +               .max_tx_len  = SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN,
> +               .min_rx_len  = sizeof(struct rpmi_request_complete_resp),
> +               .max_rx_len  = sizeof(struct rpmi_request_complete_resp),
> +       },
> +};
> +
> +static const struct mpxy_rpmi_data bridge_dst_rpmi_data_template = {
> +       .servicegrp_id    = RPMI_SRVGRP_REQFWD,
> +       .num_services     = sizeof(bridge_dst_rpmi_services) /
> +                           sizeof(bridge_dst_rpmi_services[0]),
> +       .service_data     = bridge_dst_rpmi_services,
> +       .get_attribute_group = bridge_rpmi_get_attribute_group,
> +       .xfer_group       = bridge_rpmi_xfer_group,
> +       .setup_group      = bridge_rpmi_setup_group,
> +};
> +
> +static const struct mpxy_rpmi_data bridge_src_rpmi_data_template = {
> +       .get_attribute_group = bridge_rpmi_get_attribute_group,
> +       .xfer_group       = bridge_rpmi_xfer_group,
> +       .setup_group      = bridge_rpmi_setup_group,
> +};
> +
> +static void bridge_init_internal_channel(struct sbi_mpxy_channel *ch,
> +                                        struct sbi_domain *dom, u32 id)
> +{
> +       sbi_memset(ch, 0, sizeof(*ch));
> +       ch->owner_domain            = dom;
> +       ch->channel_id              = id;
> +       ch->attrs.msg_data_maxlen   = SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN;
> +}
> +
> +static int bridge_register_destination(struct mpxy_bridge *br,
> +                                       struct sbi_domain *dom)
> +{
> +       struct bridge_rpmi_endpoint *ep;
> +       int ret;
> +
> +       ep             = &br->dst.ep.rpmi_endpoint;
> +       ep->rpmi_data  = bridge_dst_rpmi_data_template;
> +       ep->bridge     = br;
> +       ep->domain     = dom;
> +
> +       bridge_init_internal_channel(&br->dst.ep.ch, dom,
> +                                    br->dst.ep.channel_id);
> +       ep->channel = &br->dst.ep.ch;
> +
> +       ret = mpxy_rpmi_no_mbox_init(&ep->rpmi_data,
> +                                    br->dst.ep.channel_id,
> +                                    br->dst.ep.domain_name);
> +

Redundant new line.

> +       if (!ret)
> +               br->dst.ep.dom = dom;
> +
> +       return ret;
> +}
> +
> +int mpxy_bridge_register_source(const void *fdt,
> +                               int nodeoff, const struct mpxy_bridge_source_ops *ops,
> +                               struct mpxy_rpmi_service_data *srvcdata,
> +                               u32 num_services,
> +                               enum rpmi_servicegroup_id srvgrpid)
> +{
> +       struct mpxy_bridge *br;
> +       struct mpxy_bridge_source *src;
> +       struct bridge_rpmi_endpoint *ep;
> +       int parent_nodeoff;
> +       int ret = SBI_OK;
> +       u32 i;
> +
> +       do {
> +               if (!fdt || nodeoff < 0 || !ops) {
> +                       ret = SBI_EINVAL;
> +                       break;
> +               }
> +
> +               parent_nodeoff = fdt_parent_offset(fdt, nodeoff);
> +               if (parent_nodeoff < 0) {
> +                       ret = SBI_ENODEV;
> +                       break;
> +               }
> +
> +               br = bridge_find_by_nodeoff(parent_nodeoff);
> +               if (!br) {
> +                       ret = SBI_ENODEV;
> +                       break;
> +               }
> +
> +               src = NULL;
> +               for (i = 0; i < br->source_count; i++) {
> +                       if (br->sources[i].nodeoff == nodeoff) {
> +                               src = &br->sources[i];
> +                               break;
> +                       }
> +               }
> +
> +               if (!src) {
> +                       ret = SBI_ENODEV;
> +                       break;
> +               }
> +
> +               src->ops = ops;
> +               if (!src->ops->xfer || !src->ops->complete) {
> +                       ret = SBI_ENOTSUPP;
> +                       sbi_printf("source driver must provide xfer and complete\n");
> +                       src->ep.dom = NULL;
> +                       break;
> +               }
> +
> +               ep               = &src->ep.rpmi_endpoint;
> +               ep->bridge       = br;
> +               ep->channel      = &src->ep.ch;
> +               ep->rpmi_data    = bridge_src_rpmi_data_template;
> +               ep->rpmi_data.service_data  = srvcdata;
> +               ep->rpmi_data.servicegrp_id = srvgrpid;
> +               ep->rpmi_data.num_services  = num_services;
> +
> +               src->ep.ch.channel_id   = src->ep.channel_id;
> +               src->ep.ch.owner_domain = src->ep.dom;
> +       } while (0);

Why do we need this "do { } while (0)" ??

> +
> +       return ret;
> +}

Add empty newline between two consecutive functions here and
wherever it is missing.

> +static int bridge_get_domain_prop(const void *fdt, int nodeoff,
> +                                 const char *propname, char *out,
> +                                 size_t outsz)
> +{
> +       const fdt32_t *value;
> +       const char    *name;
> +       int            len, domain_nodeoff;
> +       size_t         n;
> +
> +       value = fdt_getprop(fdt, nodeoff, propname, &len);
> +       if (!value || len < (int)sizeof(*value))
> +               return SBI_ENODEV;
> +
> +       domain_nodeoff = fdt_node_offset_by_phandle(fdt,
> +                                       fdt32_to_cpu(*value));
> +       if (domain_nodeoff < 0)
> +               return SBI_ENODEV;
> +
> +       name = fdt_get_name(fdt, domain_nodeoff, NULL);
> +       if (!name || !name[0] || !outsz)
> +               return SBI_ENODEV;
> +
> +       n = sbi_strlen(name);
> +       if (n >= outsz)
> +               n = outsz - 1;
> +       sbi_memcpy(out, name, n);
> +       out[n] = '\0';
> +
> +       return SBI_OK;
> +}
> +
> +static int bridge_get_u32_prop(const void *fdt, int nodeoff,
> +                              const char *propname, u32 *out)
> +{
> +       const fdt32_t *value;
> +       int            len;
> +
> +       value = fdt_getprop(fdt, nodeoff, propname, &len);
> +       if (!value || len < (int)sizeof(*value))
> +               return SBI_ENODEV;
> +
> +       *out = fdt32_to_cpu(*value);
> +       return SBI_OK;
> +}
> +
> +static bool sbi_hartmask_equal(const struct sbi_hartmask *a,
> +                              const struct sbi_hartmask *b)
> +{
> +       u32 hartindex;
> +
> +       sbi_hartmask_for_each_hartindex(hartindex, a)
> +               if (!sbi_hartmask_test_hartindex(hartindex, b))
> +                       return false;
> +
> +       sbi_hartmask_for_each_hartindex(hartindex, b)
> +               if (!sbi_hartmask_test_hartindex(hartindex, a))
> +                       return false;
> +
> +       return true;
> +}
> +
> +static void bridge_try_bind_domain(struct mpxy_bridge *br,
> +                                  const struct sbi_domain *dom)
> +{
> +       u32 i, rc;
> +
> +       if (!br || !dom)
> +               return;
> +
> +       if (!br->dst.ep.dom &&
> +           bridge_name_match(dom->name, br->dst.ep.domain_name)) {
> +               bridge_register_destination(br, (struct sbi_domain *)dom);
> +       }
> +
> +       for (i = 0; i < br->source_count; i++) {
> +               if (!br->sources[i].ep.dom &&
> +                       bridge_name_match(dom->name, br->sources[i].ep.domain_name)) {
> +                       br->sources[i].ep.dom = (struct sbi_domain *)dom;
> +
> +                       rc = mpxy_rpmi_no_mbox_init(&br->sources[i].ep.rpmi_endpoint.rpmi_data,
> +                                   br->sources[i].ep.channel_id,
> +                                   br->sources[i].ep.domain_name);
> +                       if (rc) {
> +                               sbi_printf("%s: mpxy_rpmi_no_mbox_init failed with ret %d for source[%u]\n",
> +                                  __func__, rc, i);
> +                               br->sources[i].ep.dom = NULL;
> +                       }
> +               }
> +       }
> +
> +       if (br->dst.ep.dom) {
> +               for (i = 0; i < br->source_count; i++) {
> +                       if (br->sources[i].ep.dom &&
> +                           !sbi_hartmask_equal(
> +                               br->sources[i].ep.dom->possible_harts,
> +                               br->dst.ep.dom->possible_harts)) {
> +                               sbi_printf("%s: source[%u] and destination "
> +                                          "have different possible harts\n",
> +                                          __func__, i);
> +                               br->sources[i].ep.dom = NULL;
> +                       }
> +               }
> +       }
> +}
> +
> +static int bridge_domain_notifier(struct sbi_domain *dom,
> +                                 enum sbi_domain_notify_event event,
> +                                 void *priv)
> +{
> +       struct mpxy_bridge *br;
> +
> +       (void)priv;
> +
> +       if (event == SBI_DOMAIN_NOTIFY_EVENT_REGISTER)
> +               sbi_list_for_each_entry(br, &mpxy_bridge_list, node)
> +                       bridge_try_bind_domain(br, dom);
> +
> +       return SBI_OK;
> +}
> +
> +static int bridge_parse_fdt(const void *fdt, int nodeoff,
> +                           struct mpxy_bridge *br)
> +{
> +       int ret;
> +
> +       ret = bridge_get_domain_prop(fdt, nodeoff,
> +                                    SBI_MPXY_BRIDGE_PROP_DOMAIN_NAME,
> +                                    br->dst.ep.domain_name,
> +                                    sizeof(br->dst.ep.domain_name));
> +       if (ret)
> +               return ret;
> +
> +       return bridge_get_u32_prop(fdt, nodeoff,
> +                                  SBI_MPXY_BRIDGE_PROP_CHAN,
> +                                  &br->dst.ep.channel_id);
> +}
> +
> +static int bridge_count_sources(const void *fdt, int nodeoff)
> +{
> +       int child, count = 0;
> +
> +       fdt_for_each_subnode(child, fdt, nodeoff)
> +               count++;
> +
> +       return count;
> +}
> +
> +static const struct fdt_match *bridge_match_node(const void *fdt, int nodeoff,
> +                 const struct fdt_match *match_table)
> +{
> +       const struct fdt_match *m;
> +
> +       for (m = match_table; m->compatible; m++) {
> +               if (!fdt_node_check_compatible(fdt, nodeoff, m->compatible))
> +                       return m;
> +       }
> +
> +       return NULL;
> +}
> +
> +static const struct mpxy_bridge_source_driver *
> +bridge_find_source_driver(const void *fdt, int nodeoff,
> +                         const struct fdt_match **match)
> +{
> +       const struct mpxy_bridge_source_driver *driver;
> +       int i;
> +
> +       for (i = 0; i < array_size(source_drivers); i++) {
> +               driver = source_drivers[i];
> +               *match = bridge_match_node(fdt, nodeoff, driver->match_table);
> +               if (*match)
> +                       return driver;
> +       }
> +
> +       return NULL;
> +}
> +
> +static int bridge_probe_sources(const void *fdt, int bridge_nodeoff,
> +                               struct mpxy_bridge *bridge)
> +{
> +       const struct mpxy_bridge_source_driver *driver;
> +       const struct fdt_match *match;
> +       int child_nodeoff;
> +
> +       fdt_for_each_subnode(child_nodeoff, fdt, bridge_nodeoff) {
> +               driver = bridge_find_source_driver(fdt, child_nodeoff, &match);
> +               if (!driver)
> +                       continue;
> +
> +               if (driver->probe(fdt, child_nodeoff, match)) {
> +                       sbi_printf("%s: failed to probe source at node %d\n",
> +                                  __func__, child_nodeoff);
> +               }
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static int bridge_parse_sources(const void *fdt, int nodeoff,
> +                               struct mpxy_bridge *br)
> +{
> +       struct mpxy_bridge_source *src;
> +       int   child;
> +       u32   index = 0;
> +       int   ret = SBI_OK;
> +
> +       fdt_for_each_subnode(child, fdt, nodeoff) {
> +               src = &br->sources[index];
> +               src->nodeoff = child;
> +
> +               if ((ret = bridge_get_domain_prop(fdt, child,
> +                               SBI_MPXY_BRIDGE_PROP_DOMAIN_NAME,
> +                               src->ep.domain_name,
> +                               sizeof(src->ep.domain_name))))
> +                       continue;
> +
> +               if ((ret = bridge_get_u32_prop(fdt, child,
> +                               SBI_MPXY_BRIDGE_PROP_CHAN,
> +                               &src->ep.channel_id)))
> +                       continue;
> +
> +               index++;
> +       }
> +
> +       return ret;
> +}
> +
> +static int bridge_validate(struct mpxy_bridge *br)
> +{
> +       u32 i, j;
> +
> +       if (!br->dst.ep.domain_name[0] || !br->source_count)
> +               return SBI_EINVAL;
> +
> +       for (i = 0; i < br->source_count; i++) {
> +               if (!br->sources[i].ep.domain_name[0] ||
> +                   br->sources[i].ep.channel_id == br->dst.ep.channel_id)
> +                       return SBI_EINVAL;
> +
> +               for (j = i + 1; j < br->source_count; j++)
> +                       if (br->sources[i].ep.channel_id ==
> +                           br->sources[j].ep.channel_id)
> +                               return SBI_EINVAL;
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static void bridge_free(struct mpxy_bridge *br)
> +{
> +       u32 i;
> +
> +       if (!br)
> +               return;
> +
> +       for (i = 0; i < br->store.hart_count; i++)
> +               if (br->store.slots[i].src_ctx)
> +                       sbi_free(br->store.slots[i].src_ctx);
> +
> +       if (br->store.slots)
> +               sbi_free(br->store.slots);
> +
> +       if (br->sources)
> +               sbi_free(br->sources);
> +
> +       sbi_free(br);
> +}
> +
> +static struct mpxy_bridge *bridge_alloc(u32 hart_count, u32 source_count)
> +{
> +       struct mpxy_bridge *br;
> +       u32 i;
> +
> +       if (!hart_count || !source_count)
> +               return NULL;
> +
> +       br = sbi_zalloc(sizeof(*br));
> +       if (!br)
> +               return NULL;
> +
> +       br->sources     = sbi_zalloc(sizeof(*br->sources) * source_count);
> +       br->store.slots = sbi_zalloc(sizeof(*br->store.slots) * hart_count);
> +
> +       if (!br->sources || !br->store.slots) {
> +               bridge_free(br);
> +               return NULL;
> +       }
> +
> +       for (i = 0; i < hart_count; i++) {
> +               br->store.slots[i].src_ctx = sbi_zalloc(
> +                       sizeof(struct mpxy_bridge_src_ctx) * source_count);
> +               if (!br->store.slots[i].src_ctx) {
> +                       bridge_free(br);
> +                       return NULL;
> +               }
> +       }
> +
> +       br->source_count      = source_count;
> +       br->store.hart_count  = hart_count;
> +       return br;
> +}
> +
> +static int bridge_register_notifier(void)
> +{
> +       int ret = SBI_OK;
> +
> +       if (!mpxy_bridge_notifier_registered) {
> +               ret = sbi_domain_register_notifier(
> +                               bridge_domain_notifier,
> +                               SBI_DOMAIN_NOTIFY_EVENT_REGISTER,
> +                               NULL);
> +               if (!ret)
> +                       mpxy_bridge_notifier_registered = true;
> +       }
> +
> +       return ret;
> +}
> +
> +static int bridge_init(const void *fdt, int nodeoff,
> +                      const struct fdt_match *match)
> +{
> +       struct mpxy_bridge *br = NULL;
> +       struct sbi_scratch *scratch;
> +       u32                 hart_count;
> +       u32                 source_count;
> +       u32                 i;
> +       int                 ret = SBI_OK;
> +
> +       (void)match;
> +
> +       scratch    = sbi_hartindex_to_scratch(current_hartindex());
> +       hart_count = sbi_platform_hart_count(sbi_platform_ptr(scratch));
> +
> +       do {
> +               source_count = bridge_count_sources(fdt, nodeoff);
> +               br           = bridge_alloc(hart_count, source_count);
> +               if (!br) {
> +                       ret = SBI_ENOMEM;
> +                       break;
> +               }
> +
> +               br->nodeoff = nodeoff;
> +
> +               if ((ret = bridge_parse_fdt(fdt, nodeoff, br)))
> +                       break;
> +
> +               if ((ret = bridge_parse_sources(fdt, nodeoff, br)))
> +                       break;
> +
> +               if ((ret = bridge_validate(br)))
> +                       break;
> +
> +               sbi_list_add_tail(&br->node, &mpxy_bridge_list);
> +
> +               if ((ret = bridge_probe_sources(fdt, nodeoff, br))) {
> +                       sbi_list_del(&br->node);
> +                       break;
> +               }
> +
> +               for (i = 0; i < hart_count; i++)
> +                       bridge_slot_release(br, &br->store.slots[i]);
> +
> +               if ((ret = bridge_register_notifier()))
> +                       sbi_list_del(&br->node);
> +
> +       } while (0);
> +
> +       if (ret && br)
> +               bridge_free(br);
> +
> +       return ret;
> +}
> +
> +static const struct fdt_match bridge_match[] = {
> +       { .compatible = SBI_MPXY_BRIDGE_COMPATIBLE },
> +       { }
> +};
> +
> +const struct fdt_driver fdt_mpxy_bridge = {
> +       .match_table = bridge_match,
> +       .init        = bridge_init,
> +};
> diff --git a/lib/utils/mpxy/objects.mk b/lib/utils/mpxy/objects.mk
> index 7645d13a..0ba79d59 100644
> --- a/lib/utils/mpxy/objects.mk
> +++ b/lib/utils/mpxy/objects.mk
> @@ -32,3 +32,6 @@ libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_MM) += mpxy/fdt_mpxy_rpmi_mm.o
>
>  carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_RPMI_LOGGING) += fdt_mpxy_rpmi_logging
>  libsbiutils-objs-$(CONFIG_FDT_MPXY_RPMI_LOGGING) += mpxy/fdt_mpxy_rpmi_logging.o
> +
> +carray-fdt_mpxy_drivers-$(CONFIG_FDT_MPXY_BRIDGE) += fdt_mpxy_bridge
> +libsbiutils-objs-$(CONFIG_FDT_MPXY_BRIDGE) += mpxy/fdt_mpxy_bridge.o
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index 2617ea19..fc138659 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -86,3 +86,5 @@ CONFIG_FDT_MPXY_RPMI_PERFORMANCE=y
>  CONFIG_FDT_MPXY_RPMI_SYSMSI=y
>  CONFIG_FDT_MPXY_RPMI_MM=y
>  CONFIG_FDT_MPXY_RPMI_LOGGING=y
> +CONFIG_FDT_MPXY_BRIDGE=y

s/CONFIG_FDT_MPXY_BRIDGE/CONFIG_FDT_MPXY_RPMI_BRIDGE

> +

Redundant new line.

> --
> 2.43.0
>

Regards,
Anup



More information about the opensbi mailing list