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
137
138
|
/*
* 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;
SBI_INIT_LIST_HEAD(&mbox->node);
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;
SBI_INIT_LIST_HEAD(&ret->node);
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);
}
|