[PATCH v4 3/3] sbi_utils: mpxy: add FDT-based MPXY bridge driver
Anup Patel
anup at brainfault.org
Mon Sep 21 08:53:27 PDT 2026
On Fri, Sep 11, 2026 at 2:38 AM Pawandeep Oza
<pawandeep.oza at oss.qualcomm.com> wrote:
>
> From: Oza Pawandeep <pawandeep.oza at oss.qualcomm.com>
>
> Introduce an FDT-configured MPXY bridge driver that enables
> 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
>
> Key design points:
> - bridge_slot_put(): implements sbi_mpxy_send_message_without_response
> stores message pointer and switches to destination domain
> - bridge_src_send(): mplements sbi_mpxy_send_message_with_response
> stores message and response buffer context then switches to destination
> - bridge_dst_retrieve(): REQFWD retrieve path — if slot is
> occupied delivers message immediately, otherwise saves
> response buffer context and yields to source domain to wait
> - bridge_switch_domain(): unified domain switch wrapper —
> enters destination domain from source side or exits back
> to source domain from destination side
> - at present this bridge driver supports domains with same possible_harts.
>
> Signed-off-by: Oza Pawandeep <pawandeep.oza at oss.qualcomm.com>
> ---
> lib/utils/mpxy/Kconfig | 4 +
> lib/utils/mpxy/fdt_mpxy_bridge.c | 820 +++++++++++++++++++++++++++++
> lib/utils/mpxy/objects.mk | 3 +
> platform/generic/configs/defconfig | 2 +
> 4 files changed, 829 insertions(+)
> create mode 100644 lib/utils/mpxy/fdt_mpxy_bridge.c
>
> diff --git a/lib/utils/mpxy/Kconfig b/lib/utils/mpxy/Kconfig
> index a3ed1c22..017a6b06 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 interdomina communication"
> + default n
> +
> config FDT_MPXY_RPMI_MBOX
> bool "MPXY drivers as RPMI mailbox client"
> 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..578dc9b0
> --- /dev/null
> +++ b/lib/utils/mpxy/fdt_mpxy_bridge.c
> @@ -0,0 +1,820 @@
> +/*
> + * 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_console.h>
> +#include <sbi/sbi_domain.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/sbi_string.h>
> +#include <sbi/sbi_types.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +#include <sbi_utils/mailbox/rpmi_msgprot.h>
> +
> +#define SBI_MPXY_BRIDGE_COMPATIBLE "opensbi,mpxy-bridge"
> +#define SBI_MPXY_BRIDGE_PROP_SRC_DOMAIN_NAME "opensbi,source-domain-name"
> +#define SBI_MPXY_BRIDGE_PROP_DST_DOMAIN_NAME "opensbi,destination-domain-name"
> +#define SBI_MPXY_BRIDGE_PROP_SRC_CHAN "opensbi,source-channel-id"
> +#define SBI_MPXY_BRIDGE_PROP_DST_CHAN "opensbi,destination-channel-id"
> +
> +#define SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN 4096
> +#define SBI_MPXY_BRIDGE_DOMAIN_NAME_MAXLEN 64
> +
> +#define BRIDGE_FILL_FORWARD_RESP(resp_, status_, remaining_, returned_) \
> + do { \
> + (resp_)->status = (status_); \
> + (resp_)->remaining = (remaining_); \
> + (resp_)->returned = (returned_); \
> + } while (0)
> +
> +#define BRIDGE_FILL_COMPLETE_RESP(resp_, status_, messages_) \
> + do { \
> + (resp_)->status = (status_); \
> + (resp_)->num_of_messages = (messages_); \
> + } while (0)
> +
> +struct mpxy_bridge_dst_ctx {
> + void *respbuf;
> + u32 resp_bufsize;
> + unsigned long *resp_len_ptr;
> + u32 start_index;
> +};
> +
> +struct mpxy_bridge_src_ctx {
> + bool occupied;
> + bool retrieved;
> + void *msgbuf;
> + void *respbuf;
> + u32 msg_len;
> + u32 resp_bufsize;
> + unsigned long *resp_len_ptr;
> +};
> +
> +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;
> + u32 lost;
> +};
> +
> +struct mpxy_bridge_source {
> + char src_domain_name[SBI_MPXY_BRIDGE_DOMAIN_NAME_MAXLEN];
> + u32 src_channel_id;
> + struct sbi_domain *src_dom;
> + struct sbi_mpxy_channel src_ch;
> +};
> +
> +struct mpxy_bridge {
> + struct sbi_dlist node;
> + char dst_domain_name[SBI_MPXY_BRIDGE_DOMAIN_NAME_MAXLEN];
> + u32 dst_channel_id;
> + struct sbi_domain *dst_dom;
> + struct sbi_mpxy_channel dst_ch;
> + 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].src_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_ch == channel)
> + return br;
> + for (i = 0; i < br->source_count; i++)
> + if (&br->sources[i].src_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();
> + int ret = SBI_OK;
> +
> + if (hartindex >= br->store.hart_count)
> + ret = SBI_ERR_INVALID_PARAM;
> + else
> + *slot = &br->store.slots[hartindex];
> +
> + return ret;
> +}
> +
> +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;
> + src->resp_len_ptr = resp_len;
> +}
> +
> +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_src_ctx_occupy(struct mpxy_bridge *br,
> + struct mpxy_bridge_hart_slot *slot,
> + u32 source_index)
> +{
> + struct mpxy_bridge_src_ctx *src = &slot->src_ctx[source_index];
> + int ret = SBI_OK;
> +
> + if (src->occupied) {
> + /*
> + * this should never happen, as speicifc source would be blocked
> + * till the reciever receievs the message and completes it.
> + */
> + br->store.lost++;
> + sbi_printf("%s: slot occupied, message lost for domain=%s\n",
> + __func__, br->sources[source_index].src_domain_name);
> + ret = SBI_ERR_FAILED;
> + } else {
> + src->occupied = true;
> + src->retrieved = false;
> + }
> +
> + return ret;
> +}
> +
> +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 void bridge_switch_domain(struct mpxy_bridge *br,
> + struct sbi_mpxy_channel *channel)
> +{
> + if (channel == &br->dst_ch)
> + sbi_domain_context_exit();
> + else
> + sbi_domain_context_enter(br->dst_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 void bridge_fill_forward_resp(struct mpxy_bridge_hart_slot *slot,
> + u32 source_index,
> + struct mpxy_bridge_src_ctx *src)
> +{
> + struct rpmi_request_forward_resp *resp;
> + u32 offset = slot->dst_resp.start_index;
> + u32 returned_len;
> +
> + if (!slot->dst_resp.respbuf)
> + return;
> +
> + returned_len = offset > src->msg_len ? 0 : src->msg_len - offset;
> + resp = (struct rpmi_request_forward_resp *)slot->dst_resp.respbuf;
> +
> + if (slot->dst_resp.resp_bufsize < sizeof(*resp) + returned_len) {
> + BRIDGE_FILL_FORWARD_RESP(resp, RPMI_ERR_INVALID_PARAM, 0, 0);
> + if (slot->dst_resp.resp_len_ptr)
> + *slot->dst_resp.resp_len_ptr = sizeof(*resp);
> + } else {
> + BRIDGE_FILL_FORWARD_RESP(resp, RPMI_SUCCESS, 0, returned_len);
> + if (returned_len)
> + sbi_memcpy(resp->data, (u8 *)src->msgbuf + offset, returned_len);
> + if (slot->dst_resp.resp_len_ptr)
> + *slot->dst_resp.resp_len_ptr = sizeof(*resp) + returned_len;
> + src->retrieved = true;
> + slot->active_source = (int)source_index;
> + slot->dst_resp = (struct mpxy_bridge_dst_ctx){ 0 };
> + }
> +}
> +
> +static int bridge_src_send(struct mpxy_bridge *br,
> + struct mpxy_bridge_hart_slot *slot,
> + struct mpxy_bridge_src_ctx *src,
> + u32 source_index)
> +{
> + int ret;
> +
> + ret = bridge_src_ctx_occupy(br, slot, source_index);
> + if (!ret) {
> + bridge_fill_forward_resp(slot, source_index, src);
> + bridge_switch_domain(br, &br->sources[source_index].src_ch);
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_build_retrieve_resp(struct mpxy_bridge *br,
> + struct mpxy_bridge_hart_slot *slot,
> + u32 source_index, void *respbuf,
> + u32 resp_bufsize,
> + unsigned long *resp_len)
> +{
> + struct mpxy_bridge_src_ctx *src;
> + struct rpmi_request_forward_resp *resp;
> + int ret = SBI_OK;
> +
> + if (source_index >= br->source_count || !respbuf || !resp_len)
> + ret = SBI_ERR_INVALID_PARAM;
> + else {
> + src = &slot->src_ctx[source_index];
> + resp = (struct rpmi_request_forward_resp *)respbuf;
> + if (!src->occupied || !src->msgbuf) {
> + BRIDGE_FILL_FORWARD_RESP(resp, RPMI_ERR_NO_DATA, 0, 0);
> + *resp_len = sizeof(*resp);
> + } else if (resp_bufsize < sizeof(*resp) + src->msg_len) {
> + BRIDGE_FILL_FORWARD_RESP(resp, RPMI_ERR_INVALID_PARAM, 0, 0);
> + *resp_len = sizeof(*resp);
> + } else {
> + BRIDGE_FILL_FORWARD_RESP(resp, RPMI_SUCCESS, 0, src->msg_len);
> + sbi_memcpy(resp->data, src->msgbuf, src->msg_len);
> + *resp_len = sizeof(*resp) + src->msg_len;
> + src->retrieved = true;
> + slot->active_source = (int)source_index;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_dst_retrieve(struct mpxy_bridge *br,
> + struct mpxy_bridge_hart_slot *slot,
> + void *msgbuf, u32 msg_len, void *respbuf,
> + u32 resp_bufsize, unsigned long *resp_len)
> +{
> + int source_index = bridge_find_pending_source(br, slot);
> + int ret = SBI_OK;
> +
> + (void)msg_len;
> +
> + if (source_index < 0) {
> + bridge_save_dst_ctx(slot, respbuf, resp_bufsize, resp_len, msgbuf);
> + bridge_switch_domain(br, &br->dst_ch);
> + } else {
> + ret = bridge_build_retrieve_resp(br, slot, (u32)source_index,
> + respbuf, resp_bufsize, resp_len);
> + }
> +
> + return ret;
> +}
> +
> +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;
> + int ret = SBI_OK;
> +
> + if (!respbuf || !resp_len || resp_max_len < sizeof(*resp))
> + ret = SBI_ERR_INVALID_PARAM;
> + else if (slot->active_source < 0 ||
> + (u32)slot->active_source >= br->source_count) {
> + resp = (struct rpmi_request_complete_resp *)respbuf;
> + BRIDGE_FILL_COMPLETE_RESP(resp, RPMI_ERR_NO_DATA, 0);
> + *resp_len = sizeof(*resp);
> + } else {
> + src = &slot->src_ctx[slot->active_source];
> + resp = (struct rpmi_request_complete_resp *)respbuf;
> + if (!src->occupied || !src->retrieved) {
> + BRIDGE_FILL_COMPLETE_RESP(resp, RPMI_ERR_NO_DATA, 0);
> + *resp_len = sizeof(*resp);
> + } else if (src->respbuf && msg_len > src->resp_bufsize) {
> + BRIDGE_FILL_COMPLETE_RESP(resp, RPMI_ERR_INVALID_PARAM, 0);
> + *resp_len = sizeof(*resp);
> + } else {
> + if (src->respbuf && msg_len)
> + sbi_memcpy(src->respbuf, msgbuf, msg_len);
> + if (src->resp_len_ptr)
> + *src->resp_len_ptr = msg_len;
> + BRIDGE_FILL_COMPLETE_RESP(resp, RPMI_SUCCESS, 0);
> + *resp_len = sizeof(*resp);
> + bridge_src_ctx_release(src);
> + slot->active_source = -1;
> + bridge_switch_domain(br, &br->dst_ch);
> + }
> + }
> +
> + return ret;
> +}
> +
> +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)
> +{
> + int ret = SBI_ERR_NOT_SUPPORTED;
> +
> + if (msg_id == REQFWD_RETRIEVE_CURRENT_MESSAGE)
> + ret = bridge_dst_retrieve(br, slot, msgbuf, msg_len,
> + respbuf, resp_bufsize, resp_len);
> + else if (msg_id == REQFWD_COMPLETE_CURRENT_MESSAGE)
> + ret = bridge_dst_complete(br, slot, msgbuf, msg_len,
> + respbuf, resp_bufsize, resp_len);
> +
> + return ret;
> +}
> +
> +static int bridge_src_send_message_with_response(
> + struct mpxy_bridge *br,
> + struct mpxy_bridge_hart_slot *slot,
> + struct sbi_mpxy_channel *channel,
> + void *msgbuf, u32 msg_len, void *respbuf,
> + u32 resp_bufsize, unsigned long *resp_len)
> +{
> + struct mpxy_bridge_src_ctx *src;
> + int source_index = bridge_source_index(br, channel);
> + int ret = SBI_ERR_NOT_SUPPORTED;
> +
> + if (source_index >= 0) {
> + src = &slot->src_ctx[source_index];
> + bridge_src_ctx_set(src, msgbuf, msg_len, respbuf,
> + resp_bufsize, resp_len);
> + ret = bridge_src_send(br, slot, src, (u32)source_index);
> + }
> +
> + return ret;
> +}
> +
> +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 = bridge_from_channel(channel);
> + struct mpxy_bridge_hart_slot *slot = NULL;
> + int ret = SBI_ERR_NOT_SUPPORTED;
> +
> + if (br) {
> + ret = bridge_get_current_slot(br, &slot);
> + if (!ret) {
> + if (channel == &br->dst_ch)
> + ret = bridge_dst_send_message_with_response(
> + br, slot, msg_id, msgbuf, msg_len,
> + respbuf, resp_bufsize, resp_len);
> + else
> + ret = bridge_src_send_message_with_response(
> + br, slot, channel, msgbuf, msg_len,
> + respbuf, resp_bufsize, resp_len);
> + }
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_post_message(struct sbi_mpxy_channel *channel,
> + u32 msg_id, void *msgbuf, u32 msg_len)
> +{
> + struct mpxy_bridge *br = bridge_from_channel(channel);
> + struct mpxy_bridge_hart_slot *slot;
> + struct mpxy_bridge_src_ctx *src;
> + u32 hartindex = current_hartindex();
> + int source_index;
> + int ret = SBI_OK;
> +
> + (void)msg_id;
> +
> + if (!br || !br->dst_dom)
> + ret = SBI_ERR_NOT_SUPPORTED;
> + else if (hartindex >= br->store.hart_count)
> + ret = SBI_ERR_INVALID_PARAM;
> + else {
> + source_index = bridge_source_index(br, channel);
> + if (source_index < 0)
> + ret = SBI_ERR_NOT_SUPPORTED;
> + else {
> + ret = bridge_get_current_slot(br, &slot);
> + if (!ret) {
> + src = &slot->src_ctx[source_index];
> + bridge_src_ctx_set(src, msgbuf, msg_len, NULL, 0, NULL);
> + ret = bridge_src_send(br, slot, src, (u32)source_index);
> + }
> + }
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_send_message_without_response(
> + struct sbi_mpxy_channel *channel, u32 msg_id,
> + void *msgbuf, u32 msg_len)
> +{
> + return bridge_post_message(channel, msg_id, msgbuf, msg_len);
> +}
> +
> +static void bridge_init_channel(struct sbi_mpxy_channel *channel,
> + struct sbi_domain *dom, u32 channel_id)
> +{
> + sbi_memset(channel, 0, sizeof(*channel));
> + channel->owner_domain = dom;
> + channel->channel_id = channel_id;
> + channel->attrs.msg_data_maxlen =
> + SBI_MPXY_BRIDGE_DEFAULT_MSG_DATA_MAXLEN;
> + channel->attrs.msi_control = 0;
> + channel->attrs.eventsstate_ctrl = 0;
> + channel->send_message_with_response = bridge_send_message_with_response;
> + channel->send_message_without_response =
> + bridge_send_message_without_response;
read_attributes() and write_attributes() calls are missing.
Also, I think it is possible to share MPXY channel emulation code with
fdt_mpxy_rpmi_mbox. Let me take a crack at it.
> +}
> +
> +static int bridge_register_source(struct mpxy_bridge *br,
> + u32 source_index, struct sbi_domain *dom)
> +{
> + struct mpxy_bridge_source *src = &br->sources[source_index];
> + int ret = SBI_OK;
> +
> + if (source_index >= br->source_count)
> + ret = SBI_ERR_INVALID_PARAM;
> + else if (!src->src_dom) {
> + bridge_init_channel(&src->src_ch, dom, src->src_channel_id);
> + ret = sbi_mpxy_register_channel(&src->src_ch);
> + if (!ret)
> + src->src_dom = dom;
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_register_destination(struct mpxy_bridge *br,
> + struct sbi_domain *dom)
> +{
> + int ret = SBI_OK;
> +
> + if (!br->dst_dom) {
> + bridge_init_channel(&br->dst_ch, dom, br->dst_channel_id);
> + ret = sbi_mpxy_register_channel(&br->dst_ch);
> + if (!ret)
> + br->dst_dom = dom;
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_get_string_prop(const void *fdt, int nodeoff,
> + const char *propname, char *out, size_t outsz)
> +{
> + const char *value;
> + int len;
> + int ret = SBI_OK;
> +
> + value = fdt_getprop(fdt, nodeoff, propname, &len);
> + if (!value || len <= 0)
> + ret = SBI_ENODEV;
> + else {
> + if ((size_t)len >= outsz)
> + len = (int)outsz - 1;
> + sbi_memcpy(out, value, len);
> + out[len] = '\0';
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_get_u32_prop(const void *fdt, int nodeoff,
> + const char *propname, u32 *out)
> +{
> + const fdt32_t *value;
> + int len;
> + int ret = SBI_OK;
> +
> + value = fdt_getprop(fdt, nodeoff, propname, &len);
> + if (!value || len < (int)sizeof(*value))
> + ret = SBI_ENODEV;
> + else
> + *out = fdt32_to_cpu(*value);
> +
> + return ret;
> +}
> +
> +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;
> +
> + if (!br || !dom)
> + return;
> +
> + for (i = 0; i < br->source_count; i++)
> + if (!br->sources[i].src_dom &&
> + bridge_name_match(dom->name,
> + br->sources[i].src_domain_name))
> + bridge_register_source(br, i, (struct sbi_domain *)dom);
> +
> + if (!br->dst_dom &&
> + bridge_name_match(dom->name, br->dst_domain_name))
> + bridge_register_destination(br, (struct sbi_domain *)dom);
> +
> + if (br->dst_dom)
> + for (i = 0; i < br->source_count; i++)
> + if (br->sources[i].src_dom &&
> + !sbi_hartmask_equal(
> + br->sources[i].src_dom->possible_harts,
> + br->dst_dom->possible_harts))
> + sbi_printf("%s: source[%u] and destination have "
> + "different possible harts\n", __func__, i);
> +}
> +
> +static void bridge_domain_notifier(const struct sbi_domain *dom, void *priv)
> +{
> + struct mpxy_bridge *br;
> +
> + (void)priv;
> + sbi_list_for_each_entry(br, &mpxy_bridge_list, node)
> + bridge_try_bind_domain(br, dom);
> +}
> +
> +static int bridge_parse_fdt(const void *fdt, int nodeoff,
> + struct mpxy_bridge *br)
> +{
> + int ret;
> +
> + ret = bridge_get_string_prop(fdt, nodeoff,
> + SBI_MPXY_BRIDGE_PROP_DST_DOMAIN_NAME,
> + br->dst_domain_name,
> + sizeof(br->dst_domain_name));
> + if (ret)
> + return ret;
> +
> + return bridge_get_u32_prop(fdt, nodeoff,
> + SBI_MPXY_BRIDGE_PROP_DST_CHAN,
> + &br->dst_channel_id);
> +}
> +
> +static int bridge_count_sources(const void *fdt, int nodeoff)
> +{
> + int child;
> + int count = 0;
> +
> + fdt_for_each_subnode(child, fdt, nodeoff)
> + count++;
> + return count;
> +}
> +
> +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];
> + ret = bridge_get_string_prop(fdt, child,
> + SBI_MPXY_BRIDGE_PROP_SRC_DOMAIN_NAME,
> + src->src_domain_name,
> + sizeof(src->src_domain_name));
> + if (ret)
> + break;
> + ret = bridge_get_u32_prop(fdt, child,
> + SBI_MPXY_BRIDGE_PROP_SRC_CHAN,
> + &src->src_channel_id);
> + if (ret)
> + break;
> + index++;
> + }
> +
> + return ret;
> +}
> +
> +static int bridge_validate(struct mpxy_bridge *br)
> +{
> + u32 i, j;
> + int ret = SBI_OK;
> +
> + if (!br->dst_domain_name[0] || !br->source_count)
> + ret = SBI_EINVAL;
> +
> + for (i = 0; !ret && i < br->source_count; i++) {
> + if (!br->sources[i].src_domain_name[0] ||
> + br->sources[i].src_channel_id == br->dst_channel_id)
> + ret = SBI_EINVAL;
> + for (j = i + 1; !ret && j < br->source_count; j++)
> + if (br->sources[i].src_channel_id ==
> + br->sources[j].src_channel_id)
> + ret = SBI_EINVAL;
> + }
> +
> + return ret;
> +}
> +
> +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(struct mpxy_bridge *br)
> +{
> + int ret = SBI_OK;
> +
> + if (!mpxy_bridge_notifier_registered) {
> + ret = sbi_domain_register_notifier(bridge_domain_notifier, 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, j;
> + int ret;
> +
> + (void)match;
> +
> + scratch = sbi_hartindex_to_scratch(current_hartindex());
> + hart_count = sbi_platform_hart_count(
> + sbi_platform_ptr(scratch));
> +
> + source_count = bridge_count_sources(fdt, nodeoff);
> + br = bridge_alloc(hart_count, source_count);
> + ret = br ? SBI_OK : SBI_ENOMEM;
> +
> + if (!ret)
> + ret = bridge_parse_fdt(fdt, nodeoff, br);
> +
> + if (!ret)
> + ret = bridge_parse_sources(fdt, nodeoff, br);
> +
> + if (!ret)
> + ret = bridge_validate(br);
> +
> + if (!ret) {
> + for (i = 0; i < hart_count; i++) {
> + bridge_slot_release(br, &br->store.slots[i]);
> + for (j = 0; j < source_count; j++)
> + bridge_src_ctx_release(&br->store.slots[i].src_ctx[j]);
> + }
> +
> + sbi_list_add_tail(&br->node, &mpxy_bridge_list);
> +
> + ret = bridge_register_notifier(br);
> +
> + if (ret)
> + sbi_list_del(&br->node);
> + }
> +
> + 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 1f1bf0a0..4f1e73de 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 341f6b25..c6b3dbfd 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -84,3 +84,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
> +
> --
> 2.43.0
>
Regards,
Anup
More information about the opensbi
mailing list