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