1
2
3
4
5
6
7
8
9
10
11#include <linux/module.h>
12#include <linux/interrupt.h>
13#include <linux/pci.h>
14
15#include "rvu_reg.h"
16#include "mbox.h"
17
18static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
19
20void __otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
21{
22 void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
23 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
24 struct mbox_hdr *tx_hdr, *rx_hdr;
25
26 tx_hdr = hw_mbase + mbox->tx_start;
27 rx_hdr = hw_mbase + mbox->rx_start;
28
29 mdev->msg_size = 0;
30 mdev->rsp_size = 0;
31 tx_hdr->num_msgs = 0;
32 tx_hdr->msg_size = 0;
33 rx_hdr->num_msgs = 0;
34 rx_hdr->msg_size = 0;
35}
36EXPORT_SYMBOL(__otx2_mbox_reset);
37
38void otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
39{
40 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
41
42 spin_lock(&mdev->mbox_lock);
43 __otx2_mbox_reset(mbox, devid);
44 spin_unlock(&mdev->mbox_lock);
45}
46EXPORT_SYMBOL(otx2_mbox_reset);
47
48void otx2_mbox_destroy(struct otx2_mbox *mbox)
49{
50 mbox->reg_base = NULL;
51 mbox->hwbase = NULL;
52
53 kfree(mbox->dev);
54 mbox->dev = NULL;
55}
56EXPORT_SYMBOL(otx2_mbox_destroy);
57
58int otx2_mbox_init(struct otx2_mbox *mbox, void *hwbase, struct pci_dev *pdev,
59 void *reg_base, int direction, int ndevs)
60{
61 struct otx2_mbox_dev *mdev;
62 int devid;
63
64 switch (direction) {
65 case MBOX_DIR_AFPF:
66 case MBOX_DIR_PFVF:
67 mbox->tx_start = MBOX_DOWN_TX_START;
68 mbox->rx_start = MBOX_DOWN_RX_START;
69 mbox->tx_size = MBOX_DOWN_TX_SIZE;
70 mbox->rx_size = MBOX_DOWN_RX_SIZE;
71 break;
72 case MBOX_DIR_PFAF:
73 case MBOX_DIR_VFPF:
74 mbox->tx_start = MBOX_DOWN_RX_START;
75 mbox->rx_start = MBOX_DOWN_TX_START;
76 mbox->tx_size = MBOX_DOWN_RX_SIZE;
77 mbox->rx_size = MBOX_DOWN_TX_SIZE;
78 break;
79 case MBOX_DIR_AFPF_UP:
80 case MBOX_DIR_PFVF_UP:
81 mbox->tx_start = MBOX_UP_TX_START;
82 mbox->rx_start = MBOX_UP_RX_START;
83 mbox->tx_size = MBOX_UP_TX_SIZE;
84 mbox->rx_size = MBOX_UP_RX_SIZE;
85 break;
86 case MBOX_DIR_PFAF_UP:
87 case MBOX_DIR_VFPF_UP:
88 mbox->tx_start = MBOX_UP_RX_START;
89 mbox->rx_start = MBOX_UP_TX_START;
90 mbox->tx_size = MBOX_UP_RX_SIZE;
91 mbox->rx_size = MBOX_UP_TX_SIZE;
92 break;
93 default:
94 return -ENODEV;
95 }
96
97 switch (direction) {
98 case MBOX_DIR_AFPF:
99 case MBOX_DIR_AFPF_UP:
100 mbox->trigger = RVU_AF_AFPF_MBOX0;
101 mbox->tr_shift = 4;
102 break;
103 case MBOX_DIR_PFAF:
104 case MBOX_DIR_PFAF_UP:
105 mbox->trigger = RVU_PF_PFAF_MBOX1;
106 mbox->tr_shift = 0;
107 break;
108 case MBOX_DIR_PFVF:
109 case MBOX_DIR_PFVF_UP:
110 mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
111 mbox->tr_shift = 12;
112 break;
113 case MBOX_DIR_VFPF:
114 case MBOX_DIR_VFPF_UP:
115 mbox->trigger = RVU_VF_VFPF_MBOX1;
116 mbox->tr_shift = 0;
117 break;
118 default:
119 return -ENODEV;
120 }
121
122 mbox->reg_base = reg_base;
123 mbox->hwbase = hwbase;
124 mbox->pdev = pdev;
125
126 mbox->dev = kcalloc(ndevs, sizeof(struct otx2_mbox_dev), GFP_KERNEL);
127 if (!mbox->dev) {
128 otx2_mbox_destroy(mbox);
129 return -ENOMEM;
130 }
131
132 mbox->ndevs = ndevs;
133 for (devid = 0; devid < ndevs; devid++) {
134 mdev = &mbox->dev[devid];
135 mdev->mbase = mbox->hwbase + (devid * MBOX_SIZE);
136 spin_lock_init(&mdev->mbox_lock);
137
138 otx2_mbox_reset(mbox, devid);
139 }
140
141 return 0;
142}
143EXPORT_SYMBOL(otx2_mbox_init);
144
145int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
146{
147 unsigned long timeout = jiffies + msecs_to_jiffies(MBOX_RSP_TIMEOUT);
148 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
149 struct device *sender = &mbox->pdev->dev;
150
151 while (!time_after(jiffies, timeout)) {
152 if (mdev->num_msgs == mdev->msgs_acked)
153 return 0;
154 usleep_range(800, 1000);
155 }
156 dev_dbg(sender, "timed out while waiting for rsp\n");
157 return -EIO;
158}
159EXPORT_SYMBOL(otx2_mbox_wait_for_rsp);
160
161int otx2_mbox_busy_poll_for_rsp(struct otx2_mbox *mbox, int devid)
162{
163 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
164 unsigned long timeout = jiffies + 1 * HZ;
165
166 while (!time_after(jiffies, timeout)) {
167 if (mdev->num_msgs == mdev->msgs_acked)
168 return 0;
169 cpu_relax();
170 }
171 return -EIO;
172}
173EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp);
174
175void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
176{
177 void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE);
178 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
179 struct mbox_hdr *tx_hdr, *rx_hdr;
180
181 tx_hdr = hw_mbase + mbox->tx_start;
182 rx_hdr = hw_mbase + mbox->rx_start;
183
184
185
186
187 if (mdev->mbase != hw_mbase)
188 memcpy(hw_mbase + mbox->tx_start + msgs_offset,
189 mdev->mbase + mbox->tx_start + msgs_offset,
190 mdev->msg_size);
191
192 spin_lock(&mdev->mbox_lock);
193
194 tx_hdr->msg_size = mdev->msg_size;
195
196
197 mdev->msg_size = 0;
198 mdev->rsp_size = 0;
199 mdev->msgs_acked = 0;
200
201
202 smp_wmb();
203
204
205
206
207
208 tx_hdr->num_msgs = mdev->num_msgs;
209 rx_hdr->num_msgs = 0;
210 spin_unlock(&mdev->mbox_lock);
211
212
213
214
215 writeq(1, (void __iomem *)mbox->reg_base +
216 (mbox->trigger | (devid << mbox->tr_shift)));
217}
218EXPORT_SYMBOL(otx2_mbox_msg_send);
219
220struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid,
221 int size, int size_rsp)
222{
223 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
224 struct mbox_msghdr *msghdr = NULL;
225
226 spin_lock(&mdev->mbox_lock);
227 size = ALIGN(size, MBOX_MSG_ALIGN);
228 size_rsp = ALIGN(size_rsp, MBOX_MSG_ALIGN);
229
230 if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset)
231 goto exit;
232 if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset)
233 goto exit;
234
235 if (mdev->msg_size == 0)
236 mdev->num_msgs = 0;
237 mdev->num_msgs++;
238
239 msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size;
240
241
242 memset(msghdr, 0, size);
243
244 msghdr->ver = OTX2_MBOX_VERSION;
245 mdev->msg_size += size;
246 mdev->rsp_size += size_rsp;
247 msghdr->next_msgoff = mdev->msg_size + msgs_offset;
248exit:
249 spin_unlock(&mdev->mbox_lock);
250
251 return msghdr;
252}
253EXPORT_SYMBOL(otx2_mbox_alloc_msg_rsp);
254
255struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid,
256 struct mbox_msghdr *msg)
257{
258 unsigned long imsg = mbox->tx_start + msgs_offset;
259 unsigned long irsp = mbox->rx_start + msgs_offset;
260 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
261 u16 msgs;
262
263 spin_lock(&mdev->mbox_lock);
264
265 if (mdev->num_msgs != mdev->msgs_acked)
266 goto error;
267
268 for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
269 struct mbox_msghdr *pmsg = mdev->mbase + imsg;
270 struct mbox_msghdr *prsp = mdev->mbase + irsp;
271
272 if (msg == pmsg) {
273 if (pmsg->id != prsp->id)
274 goto error;
275 spin_unlock(&mdev->mbox_lock);
276 return prsp;
277 }
278
279 imsg = mbox->tx_start + pmsg->next_msgoff;
280 irsp = mbox->rx_start + prsp->next_msgoff;
281 }
282
283error:
284 spin_unlock(&mdev->mbox_lock);
285 return ERR_PTR(-ENODEV);
286}
287EXPORT_SYMBOL(otx2_mbox_get_rsp);
288
289int otx2_mbox_check_rsp_msgs(struct otx2_mbox *mbox, int devid)
290{
291 unsigned long ireq = mbox->tx_start + msgs_offset;
292 unsigned long irsp = mbox->rx_start + msgs_offset;
293 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
294 int rc = -ENODEV;
295 u16 msgs;
296
297 spin_lock(&mdev->mbox_lock);
298
299 if (mdev->num_msgs != mdev->msgs_acked)
300 goto exit;
301
302 for (msgs = 0; msgs < mdev->msgs_acked; msgs++) {
303 struct mbox_msghdr *preq = mdev->mbase + ireq;
304 struct mbox_msghdr *prsp = mdev->mbase + irsp;
305
306 if (preq->id != prsp->id)
307 goto exit;
308 if (prsp->rc) {
309 rc = prsp->rc;
310 goto exit;
311 }
312
313 ireq = mbox->tx_start + preq->next_msgoff;
314 irsp = mbox->rx_start + prsp->next_msgoff;
315 }
316 rc = 0;
317exit:
318 spin_unlock(&mdev->mbox_lock);
319 return rc;
320}
321EXPORT_SYMBOL(otx2_mbox_check_rsp_msgs);
322
323int
324otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id)
325{
326 struct msg_rsp *rsp;
327
328 rsp = (struct msg_rsp *)
329 otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
330 if (!rsp)
331 return -ENOMEM;
332 rsp->hdr.id = id;
333 rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
334 rsp->hdr.rc = MBOX_MSG_INVALID;
335 rsp->hdr.pcifunc = pcifunc;
336 return 0;
337}
338EXPORT_SYMBOL(otx2_reply_invalid_msg);
339
340bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid)
341{
342 struct otx2_mbox_dev *mdev = &mbox->dev[devid];
343 bool ret;
344
345 spin_lock(&mdev->mbox_lock);
346 ret = mdev->num_msgs != 0;
347 spin_unlock(&mdev->mbox_lock);
348
349 return ret;
350}
351EXPORT_SYMBOL(otx2_mbox_nonempty);
352
353const char *otx2_mbox_id2name(u16 id)
354{
355 switch (id) {
356#define M(_name, _id, _1, _2, _3) case _id: return # _name;
357 MBOX_MESSAGES
358#undef M
359 default:
360 return "INVALID ID";
361 }
362}
363EXPORT_SYMBOL(otx2_mbox_id2name);
364
365MODULE_AUTHOR("Marvell International Ltd.");
366MODULE_LICENSE("GPL v2");
367