1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
/*
* 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);
}
|