common/octeontx2: add polling based response mbox message
[dpdk.git] / drivers / common / octeontx2 / otx2_mbox.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2019 Marvell International Ltd.
3  */
4
5 #include <errno.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <rte_atomic.h>
11 #include <rte_cycles.h>
12
13 #include "otx2_mbox.h"
14 #include "otx2_dev.h"
15
16 #define RVU_AF_AFPF_MBOX0       (0x02000)
17 #define RVU_AF_AFPF_MBOX1       (0x02008)
18
19 #define RVU_PF_PFAF_MBOX0       (0xC00)
20 #define RVU_PF_PFAF_MBOX1       (0xC08)
21
22 #define RVU_PF_VFX_PFVF_MBOX0   (0x0000)
23 #define RVU_PF_VFX_PFVF_MBOX1   (0x0008)
24
25 #define RVU_VF_VFPF_MBOX0       (0x0000)
26 #define RVU_VF_VFPF_MBOX1       (0x0008)
27
28 static inline uint16_t
29 msgs_offset(void)
30 {
31         return RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
32 }
33
34 void
35 otx2_mbox_fini(struct otx2_mbox *mbox)
36 {
37         mbox->reg_base = 0;
38         mbox->hwbase = 0;
39         free(mbox->dev);
40         mbox->dev = NULL;
41 }
42
43 void
44 otx2_mbox_reset(struct otx2_mbox *mbox, int devid)
45 {
46         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
47         struct mbox_hdr *tx_hdr =
48                 (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
49         struct mbox_hdr *rx_hdr =
50                 (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
51
52         rte_spinlock_lock(&mdev->mbox_lock);
53         mdev->msg_size = 0;
54         mdev->rsp_size = 0;
55         tx_hdr->msg_size = 0;
56         tx_hdr->num_msgs = 0;
57         rx_hdr->msg_size = 0;
58         rx_hdr->num_msgs = 0;
59         rte_spinlock_unlock(&mdev->mbox_lock);
60 }
61
62 int
63 otx2_mbox_init(struct otx2_mbox *mbox, uintptr_t hwbase, uintptr_t reg_base,
64                int direction, int ndevs, uint64_t intr_offset)
65 {
66         struct otx2_mbox_dev *mdev;
67         int devid;
68
69         mbox->intr_offset = intr_offset;
70         mbox->reg_base = reg_base;
71         mbox->hwbase = hwbase;
72
73         switch (direction) {
74         case MBOX_DIR_AFPF:
75         case MBOX_DIR_PFVF:
76                 mbox->tx_start = MBOX_DOWN_TX_START;
77                 mbox->rx_start = MBOX_DOWN_RX_START;
78                 mbox->tx_size  = MBOX_DOWN_TX_SIZE;
79                 mbox->rx_size  = MBOX_DOWN_RX_SIZE;
80                 break;
81         case MBOX_DIR_PFAF:
82         case MBOX_DIR_VFPF:
83                 mbox->tx_start = MBOX_DOWN_RX_START;
84                 mbox->rx_start = MBOX_DOWN_TX_START;
85                 mbox->tx_size  = MBOX_DOWN_RX_SIZE;
86                 mbox->rx_size  = MBOX_DOWN_TX_SIZE;
87                 break;
88         case MBOX_DIR_AFPF_UP:
89         case MBOX_DIR_PFVF_UP:
90                 mbox->tx_start = MBOX_UP_TX_START;
91                 mbox->rx_start = MBOX_UP_RX_START;
92                 mbox->tx_size  = MBOX_UP_TX_SIZE;
93                 mbox->rx_size  = MBOX_UP_RX_SIZE;
94                 break;
95         case MBOX_DIR_PFAF_UP:
96         case MBOX_DIR_VFPF_UP:
97                 mbox->tx_start = MBOX_UP_RX_START;
98                 mbox->rx_start = MBOX_UP_TX_START;
99                 mbox->tx_size  = MBOX_UP_RX_SIZE;
100                 mbox->rx_size  = MBOX_UP_TX_SIZE;
101                 break;
102         default:
103                 return -ENODEV;
104         }
105
106         switch (direction) {
107         case MBOX_DIR_AFPF:
108         case MBOX_DIR_AFPF_UP:
109                 mbox->trigger = RVU_AF_AFPF_MBOX0;
110                 mbox->tr_shift = 4;
111                 break;
112         case MBOX_DIR_PFAF:
113         case MBOX_DIR_PFAF_UP:
114                 mbox->trigger = RVU_PF_PFAF_MBOX1;
115                 mbox->tr_shift = 0;
116                 break;
117         case MBOX_DIR_PFVF:
118         case MBOX_DIR_PFVF_UP:
119                 mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
120                 mbox->tr_shift = 12;
121                 break;
122         case MBOX_DIR_VFPF:
123         case MBOX_DIR_VFPF_UP:
124                 mbox->trigger = RVU_VF_VFPF_MBOX1;
125                 mbox->tr_shift = 0;
126                 break;
127         default:
128                 return -ENODEV;
129         }
130
131         mbox->dev = malloc(ndevs * sizeof(struct otx2_mbox_dev));
132         if (!mbox->dev) {
133                 otx2_mbox_fini(mbox);
134                 return -ENOMEM;
135         }
136         mbox->ndevs = ndevs;
137         for (devid = 0; devid < ndevs; devid++) {
138                 mdev = &mbox->dev[devid];
139                 mdev->mbase = (void *)(mbox->hwbase + (devid * MBOX_SIZE));
140                 rte_spinlock_init(&mdev->mbox_lock);
141                 /* Init header to reset value */
142                 otx2_mbox_reset(mbox, devid);
143         }
144
145         return 0;
146 }
147
148 /**
149  * @internal
150  * Allocate a message response
151  */
152 struct mbox_msghdr *
153 otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, int size,
154                         int size_rsp)
155 {
156         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
157         struct mbox_msghdr *msghdr = NULL;
158
159         rte_spinlock_lock(&mdev->mbox_lock);
160         size = RTE_ALIGN(size, MBOX_MSG_ALIGN);
161         size_rsp = RTE_ALIGN(size_rsp, MBOX_MSG_ALIGN);
162         /* Check if there is space in mailbox */
163         if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset())
164                 goto exit;
165         if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset())
166                 goto exit;
167         if (mdev->msg_size == 0)
168                 mdev->num_msgs = 0;
169         mdev->num_msgs++;
170
171         msghdr = (struct mbox_msghdr *)(((uintptr_t)mdev->mbase +
172                         mbox->tx_start + msgs_offset() + mdev->msg_size));
173
174         /* Clear the whole msg region */
175         otx2_mbox_memset(msghdr, 0, sizeof(*msghdr) + size);
176         /* Init message header with reset values */
177         msghdr->ver = OTX2_MBOX_VERSION;
178         mdev->msg_size += size;
179         mdev->rsp_size += size_rsp;
180         msghdr->next_msgoff = mdev->msg_size + msgs_offset();
181 exit:
182         rte_spinlock_unlock(&mdev->mbox_lock);
183
184         return msghdr;
185 }
186
187 /**
188  * @internal
189  * Send a mailbox message
190  */
191 void
192 otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid)
193 {
194         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
195         struct mbox_hdr *tx_hdr =
196                 (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
197         struct mbox_hdr *rx_hdr =
198                 (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
199
200         /* Reset header for next messages */
201         tx_hdr->msg_size = mdev->msg_size;
202         mdev->msg_size = 0;
203         mdev->rsp_size = 0;
204         mdev->msgs_acked = 0;
205
206         /* num_msgs != 0 signals to the peer that the buffer has a number of
207          * messages. So this should be written after copying txmem
208          */
209         tx_hdr->num_msgs = mdev->num_msgs;
210         rx_hdr->num_msgs = 0;
211
212         /* Sync mbox data into memory */
213         rte_wmb();
214
215         /* The interrupt should be fired after num_msgs is written
216          * to the shared memory
217          */
218         rte_write64(1, (volatile void *)(mbox->reg_base +
219                 (mbox->trigger | (devid << mbox->tr_shift))));
220 }
221
222 /**
223  * @internal
224  * Wait and get mailbox response
225  */
226 int
227 otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, void **msg)
228 {
229         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
230         struct mbox_msghdr *msghdr;
231         uint64_t offset;
232         int rc;
233
234         rc = otx2_mbox_wait_for_rsp(mbox, devid);
235         if (rc != 1)
236                 return -EIO;
237
238         rte_rmb();
239
240         offset = mbox->rx_start +
241                 RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
242         msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
243         if (msg != NULL)
244                 *msg = msghdr;
245
246         return msghdr->rc;
247 }
248
249 /**
250  * Polling for given wait time to get mailbox response
251  */
252 static int
253 mbox_poll(struct otx2_mbox *mbox, uint32_t wait)
254 {
255         uint32_t timeout = 0, sleep = 1;
256         uint32_t wait_us = wait * 1000;
257         uint64_t rsp_reg = 0;
258         uintptr_t reg_addr;
259
260         reg_addr = mbox->reg_base + mbox->intr_offset;
261         do {
262                 rsp_reg = otx2_read64(reg_addr);
263
264                 if (timeout >= wait_us)
265                         return -ETIMEDOUT;
266
267                 rte_delay_us(sleep);
268                 timeout += sleep;
269         } while (!rsp_reg);
270
271         rte_smp_rmb();
272
273         /* Clear interrupt */
274         otx2_write64(rsp_reg, reg_addr);
275
276         /* Reset mbox */
277         otx2_mbox_reset(mbox, 0);
278
279         return 0;
280 }
281
282 /**
283  * @internal
284  * Wait and get mailbox response with timeout
285  */
286 int
287 otx2_mbox_get_rsp_tmo(struct otx2_mbox *mbox, int devid, void **msg,
288                       uint32_t tmo)
289 {
290         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
291         struct mbox_msghdr *msghdr;
292         uint64_t offset;
293         int rc;
294
295         rc = otx2_mbox_wait_for_rsp_tmo(mbox, devid, tmo);
296         if (rc != 1)
297                 return -EIO;
298
299         rte_rmb();
300
301         offset = mbox->rx_start +
302                         RTE_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
303         msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
304         if (msg != NULL)
305                 *msg = msghdr;
306
307         return msghdr->rc;
308 }
309
310 static int
311 mbox_wait(struct otx2_mbox *mbox, int devid, uint32_t rst_timo)
312 {
313         volatile struct otx2_mbox_dev *mdev = &mbox->dev[devid];
314         uint32_t timeout = 0, sleep = 1;
315
316         rst_timo  = rst_timo * 1000; /* Milli seconds to micro seconds */
317         while (mdev->num_msgs > mdev->msgs_acked) {
318                 rte_delay_us(sleep);
319                 timeout += sleep;
320                 if (timeout >= rst_timo) {
321                         struct mbox_hdr *tx_hdr =
322                                 (struct mbox_hdr *)((uintptr_t)mdev->mbase +
323                                                         mbox->tx_start);
324                         struct mbox_hdr *rx_hdr =
325                                 (struct mbox_hdr *)((uintptr_t)mdev->mbase +
326                                                         mbox->rx_start);
327
328                         otx2_err("MBOX[devid: %d] message wait timeout %d, "
329                                  "num_msgs: %d, msgs_acked: %d "
330                                  "(tx/rx num_msgs: %d/%d), msg_size: %d, "
331                                  "rsp_size: %d",
332                                  devid, timeout, mdev->num_msgs,
333                                  mdev->msgs_acked, tx_hdr->num_msgs,
334                                  rx_hdr->num_msgs, mdev->msg_size,
335                                  mdev->rsp_size);
336
337                         return -EIO;
338                 }
339                 rte_rmb();
340         }
341         return 0;
342 }
343
344 int
345 otx2_mbox_wait_for_rsp_tmo(struct otx2_mbox *mbox, int devid, uint32_t tmo)
346 {
347         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
348         int rc = 0;
349
350         /* Sync with mbox region */
351         rte_rmb();
352
353         if (mbox->trigger == RVU_PF_VFX_PFVF_MBOX1 ||
354                 mbox->trigger == RVU_PF_VFX_PFVF_MBOX0) {
355                 /* In case of VF, Wait a bit more to account round trip delay */
356                 tmo = tmo * 2;
357         }
358
359         /* Wait message */
360         if (rte_thread_is_intr())
361                 rc = mbox_poll(mbox, tmo);
362         else
363                 rc = mbox_wait(mbox, devid, tmo);
364
365         if (!rc)
366                 rc = mdev->num_msgs;
367
368         return rc;
369 }
370
371 /**
372  * @internal
373  * Wait for the mailbox response
374  */
375 int
376 otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid)
377 {
378         return otx2_mbox_wait_for_rsp_tmo(mbox, devid, MBOX_RSP_TIMEOUT);
379 }
380
381 int
382 otx2_mbox_get_availmem(struct otx2_mbox *mbox, int devid)
383 {
384         struct otx2_mbox_dev *mdev = &mbox->dev[devid];
385         int avail;
386
387         rte_spinlock_lock(&mdev->mbox_lock);
388         avail = mbox->tx_size - mdev->msg_size - msgs_offset();
389         rte_spinlock_unlock(&mdev->mbox_lock);
390
391         return avail;
392 }
393
394 int
395 otx2_send_ready_msg(struct otx2_mbox *mbox, uint16_t *pcifunc)
396 {
397         struct ready_msg_rsp *rsp;
398         int rc;
399
400         otx2_mbox_alloc_msg_ready(mbox);
401
402         otx2_mbox_msg_send(mbox, 0);
403         rc = otx2_mbox_get_rsp(mbox, 0, (void *)&rsp);
404         if (rc)
405                 return rc;
406
407         if (rsp->hdr.ver != OTX2_MBOX_VERSION) {
408                 otx2_err("Incompatible MBox versions(AF: 0x%04x DPDK: 0x%04x)",
409                           rsp->hdr.ver, OTX2_MBOX_VERSION);
410                 return -EPIPE;
411         }
412
413         if (pcifunc)
414                 *pcifunc = rsp->hdr.pcifunc;
415
416         return 0;
417 }
418
419 int
420 otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, uint16_t pcifunc,
421                        uint16_t id)
422 {
423         struct msg_rsp *rsp;
424
425         rsp = (struct msg_rsp *)otx2_mbox_alloc_msg(mbox, devid, sizeof(*rsp));
426         if (!rsp)
427                 return -ENOMEM;
428         rsp->hdr.id = id;
429         rsp->hdr.sig = OTX2_MBOX_RSP_SIG;
430         rsp->hdr.rc = MBOX_MSG_INVALID;
431         rsp->hdr.pcifunc = pcifunc;
432
433         return 0;
434 }
435
436 /**
437  * @internal
438  * Convert mail box ID to name
439  */
440 const char *otx2_mbox_id2name(uint16_t id)
441 {
442         switch (id) {
443 #define M(_name, _id, _1, _2, _3) case _id: return # _name;
444         MBOX_MESSAGES
445         MBOX_UP_CGX_MESSAGES
446 #undef M
447         default :
448                 return "INVALID ID";
449         }
450 }
451
452 int otx2_mbox_id2size(uint16_t id)
453 {
454         switch (id) {
455 #define M(_1, _id, _2, _req_type, _3) case _id: return sizeof(struct _req_type);
456         MBOX_MESSAGES
457         MBOX_UP_CGX_MESSAGES
458 #undef M
459         default :
460                 return 0;
461         }
462 }