forked from Mirrors/opensbi

No need to initialise the nodes to be added to the linked list Signed-off-by: Xiang W <wxjstz@126.com> Reviewed-by: Samuel Holland <samuel.holland@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20250319123944.505756-1-wxjstz@126.com Signed-off-by: Anup Patel <anup@brainfault.org>
137 lines
2.9 KiB
C
137 lines
2.9 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2024 Ventana Micro Systems Inc.
|
|
*
|
|
* Authors:
|
|
* Anup Patel <apatel@ventanamicro.com>
|
|
*/
|
|
|
|
#include <sbi/sbi_error.h>
|
|
#include <sbi/sbi_string.h>
|
|
#include <sbi_utils/mailbox/mailbox.h>
|
|
|
|
static SBI_LIST_HEAD(mbox_list);
|
|
|
|
struct mbox_controller *mbox_controller_find(unsigned int id)
|
|
{
|
|
struct sbi_dlist *pos;
|
|
|
|
sbi_list_for_each(pos, &mbox_list) {
|
|
struct mbox_controller *mbox = to_mbox_controller(pos);
|
|
|
|
if (mbox->id == id)
|
|
return mbox;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int mbox_controller_add(struct mbox_controller *mbox)
|
|
{
|
|
if (!mbox || !mbox->max_xfer_len)
|
|
return SBI_EINVAL;
|
|
if (mbox_controller_find(mbox->id))
|
|
return SBI_EALREADY;
|
|
|
|
ATOMIC_INIT(&mbox->xfer_next_seq, 0);
|
|
SBI_INIT_LIST_HEAD(&mbox->chan_list);
|
|
sbi_list_add(&mbox->node, &mbox_list);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void mbox_controller_remove(struct mbox_controller *mbox)
|
|
{
|
|
struct mbox_chan *chan;
|
|
|
|
if (!mbox)
|
|
return;
|
|
|
|
while (!sbi_list_empty(&mbox->chan_list)) {
|
|
chan = sbi_list_first_entry(&mbox->chan_list,
|
|
struct mbox_chan, node);
|
|
if (mbox->free_chan)
|
|
mbox->free_chan(mbox, chan);
|
|
sbi_list_del(&chan->node);
|
|
}
|
|
|
|
sbi_list_del(&mbox->node);
|
|
}
|
|
|
|
struct mbox_chan *mbox_controller_request_chan(struct mbox_controller *mbox,
|
|
u32 *chan_args)
|
|
{
|
|
struct mbox_chan *ret;
|
|
struct sbi_dlist *pos;
|
|
|
|
if (!chan_args || !mbox || !mbox->request_chan)
|
|
return NULL;
|
|
|
|
sbi_list_for_each(pos, &mbox->chan_list) {
|
|
ret = to_mbox_chan(pos);
|
|
if (!sbi_memcmp(ret->chan_args, chan_args,
|
|
sizeof(ret->chan_args)))
|
|
return ret;
|
|
}
|
|
|
|
ret = mbox->request_chan(mbox, chan_args);
|
|
if (!ret)
|
|
return NULL;
|
|
|
|
ret->mbox = mbox;
|
|
sbi_memcpy(ret->chan_args, chan_args, sizeof(ret->chan_args));
|
|
sbi_list_add(&ret->node, &mbox->chan_list);
|
|
return ret;
|
|
}
|
|
|
|
void mbox_controller_free_chan(struct mbox_chan *chan)
|
|
{
|
|
if (!chan || !chan->mbox)
|
|
return;
|
|
|
|
if (chan->mbox->free_chan)
|
|
chan->mbox->free_chan(chan->mbox, chan);
|
|
sbi_list_del(&chan->node);
|
|
}
|
|
|
|
int mbox_chan_xfer(struct mbox_chan *chan, struct mbox_xfer *xfer)
|
|
{
|
|
if (!xfer || !chan || !chan->mbox || !chan->mbox->xfer)
|
|
return SBI_EINVAL;
|
|
|
|
if (xfer->tx && (xfer->tx_len > chan->mbox->max_xfer_len))
|
|
return SBI_EINVAL;
|
|
|
|
if (xfer->rx && (xfer->rx_len > chan->mbox->max_xfer_len))
|
|
return SBI_EINVAL;
|
|
|
|
if (!(xfer->flags & MBOX_XFER_SEQ))
|
|
mbox_xfer_set_sequence(xfer,
|
|
atomic_add_return(&chan->mbox->xfer_next_seq, 1));
|
|
|
|
return chan->mbox->xfer(chan, xfer);
|
|
}
|
|
|
|
int mbox_chan_get_attribute(struct mbox_chan *chan, int attr_id, void *out_value)
|
|
{
|
|
if (!chan || !chan->mbox || !out_value)
|
|
return SBI_EINVAL;
|
|
|
|
if (!chan->mbox->get_attribute)
|
|
return SBI_ENOTSUPP;
|
|
|
|
return chan->mbox->get_attribute(chan, attr_id, out_value);
|
|
}
|
|
|
|
int mbox_chan_set_attribute(struct mbox_chan *chan, int attr_id, void *new_value)
|
|
{
|
|
if (!chan || !chan->mbox || !new_value)
|
|
return SBI_EINVAL;
|
|
|
|
if (!chan->mbox->set_attribute)
|
|
return SBI_ENOTSUPP;
|
|
|
|
return chan->mbox->set_attribute(chan, attr_id, new_value);
|
|
}
|