Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : :
5 : : #include <errno.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : :
10 : : #include "roc_api.h"
11 : : #include "roc_priv.h"
12 : :
13 : : /* RCLK, SCLK in MHz */
14 : : uint16_t dev_rclk_freq;
15 : : uint16_t dev_sclk_freq;
16 : :
17 : : static inline uint16_t
18 : : msgs_offset(void)
19 : : {
20 : : return PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
21 : : }
22 : :
23 : : void
24 : 0 : mbox_fini(struct mbox *mbox)
25 : : {
26 : 0 : mbox->reg_base = 0;
27 : 0 : mbox->hwbase = 0;
28 : 0 : plt_free(mbox->dev);
29 : 0 : mbox->dev = NULL;
30 : 0 : }
31 : :
32 : : void
33 : 0 : mbox_reset(struct mbox *mbox, int devid)
34 : : {
35 : 0 : struct mbox_dev *mdev = &mbox->dev[devid];
36 : 0 : struct mbox_hdr *tx_hdr =
37 : 0 : (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
38 : 0 : struct mbox_hdr *rx_hdr =
39 : 0 : (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
40 : :
41 : 0 : mdev->msg_size = 0;
42 : 0 : mdev->rsp_size = 0;
43 : 0 : tx_hdr->msg_size = 0;
44 : 0 : tx_hdr->num_msgs = 0;
45 : 0 : rx_hdr->msg_size = 0;
46 : 0 : rx_hdr->num_msgs = 0;
47 : 0 : }
48 : :
49 : : int
50 : 0 : mbox_init(struct mbox *mbox, uintptr_t hwbase, uintptr_t reg_base,
51 : : int direction, int ndevs, uint64_t intr_offset)
52 : : {
53 : : struct mbox_dev *mdev;
54 : : char *var, *var_to;
55 : : int devid;
56 : :
57 : 0 : mbox->intr_offset = intr_offset;
58 : 0 : mbox->reg_base = reg_base;
59 : 0 : mbox->hwbase = hwbase;
60 : :
61 [ # # # # : 0 : switch (direction) {
# ]
62 : 0 : case MBOX_DIR_AFPF:
63 : : case MBOX_DIR_PFVF:
64 : 0 : mbox->tx_start = MBOX_DOWN_TX_START;
65 : 0 : mbox->rx_start = MBOX_DOWN_RX_START;
66 : 0 : mbox->tx_size = MBOX_DOWN_TX_SIZE;
67 : 0 : mbox->rx_size = MBOX_DOWN_RX_SIZE;
68 : 0 : break;
69 : 0 : case MBOX_DIR_PFAF:
70 : : case MBOX_DIR_VFPF:
71 : 0 : mbox->tx_start = MBOX_DOWN_RX_START;
72 : 0 : mbox->rx_start = MBOX_DOWN_TX_START;
73 : 0 : mbox->tx_size = MBOX_DOWN_RX_SIZE;
74 : 0 : mbox->rx_size = MBOX_DOWN_TX_SIZE;
75 : 0 : break;
76 : 0 : case MBOX_DIR_AFPF_UP:
77 : : case MBOX_DIR_PFVF_UP:
78 : 0 : mbox->tx_start = MBOX_UP_TX_START;
79 : 0 : mbox->rx_start = MBOX_UP_RX_START;
80 : 0 : mbox->tx_size = MBOX_UP_TX_SIZE;
81 : 0 : mbox->rx_size = MBOX_UP_RX_SIZE;
82 : 0 : break;
83 : 0 : case MBOX_DIR_PFAF_UP:
84 : : case MBOX_DIR_VFPF_UP:
85 : 0 : mbox->tx_start = MBOX_UP_RX_START;
86 : 0 : mbox->rx_start = MBOX_UP_TX_START;
87 : 0 : mbox->tx_size = MBOX_UP_RX_SIZE;
88 : 0 : mbox->rx_size = MBOX_UP_TX_SIZE;
89 : 0 : break;
90 : : default:
91 : : return -ENODEV;
92 : : }
93 : :
94 [ # # # # ]: 0 : switch (direction) {
95 : 0 : case MBOX_DIR_AFPF:
96 : : case MBOX_DIR_AFPF_UP:
97 : 0 : mbox->trigger = RVU_AF_AFPF_MBOX0;
98 : 0 : mbox->tr_shift = 4;
99 : 0 : break;
100 : 0 : case MBOX_DIR_PFAF:
101 : : case MBOX_DIR_PFAF_UP:
102 : 0 : mbox->trigger = RVU_PF_PFAF_MBOX1;
103 : 0 : mbox->tr_shift = 0;
104 : 0 : break;
105 : 0 : case MBOX_DIR_PFVF:
106 : : case MBOX_DIR_PFVF_UP:
107 : 0 : mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
108 : 0 : mbox->tr_shift = 12;
109 : 0 : break;
110 : 0 : case MBOX_DIR_VFPF:
111 : : case MBOX_DIR_VFPF_UP:
112 : 0 : mbox->trigger = RVU_VF_VFPF_MBOX1;
113 : 0 : mbox->tr_shift = 0;
114 : 0 : break;
115 : : default:
116 : : return -ENODEV;
117 : : }
118 : :
119 : 0 : mbox->dev = plt_zmalloc(ndevs * sizeof(struct mbox_dev), ROC_ALIGN);
120 [ # # ]: 0 : if (!mbox->dev) {
121 : 0 : mbox_fini(mbox);
122 : 0 : return -ENOMEM;
123 : : }
124 : 0 : mbox->ndevs = ndevs;
125 [ # # ]: 0 : for (devid = 0; devid < ndevs; devid++) {
126 : 0 : mdev = &mbox->dev[devid];
127 : 0 : mdev->mbase = (void *)(mbox->hwbase + (devid * MBOX_SIZE));
128 : : plt_spinlock_init(&mdev->mbox_lock);
129 : : /* Init header to reset value */
130 : 0 : mbox_reset(mbox, devid);
131 : : }
132 : :
133 : 0 : var = getenv("ROC_CN10K_MBOX_TIMEOUT");
134 : 0 : var_to = getenv("ROC_MBOX_TIMEOUT");
135 : :
136 [ # # ]: 0 : if (var)
137 : 0 : mbox->rsp_tmo = atoi(var);
138 [ # # ]: 0 : else if (var_to)
139 : 0 : mbox->rsp_tmo = atoi(var_to);
140 : : else
141 : 0 : mbox->rsp_tmo = MBOX_RSP_TIMEOUT;
142 : :
143 : : return 0;
144 : : }
145 : :
146 : : /**
147 : : * @internal
148 : : * Allocate a message response
149 : : */
150 : : struct mbox_msghdr *
151 : 0 : mbox_alloc_msg_rsp(struct mbox *mbox, int devid, int size, int size_rsp)
152 : : {
153 : 0 : struct mbox_dev *mdev = &mbox->dev[devid];
154 : : struct mbox_msghdr *msghdr = NULL;
155 : :
156 : 0 : size = PLT_ALIGN(size, MBOX_MSG_ALIGN);
157 : 0 : size_rsp = PLT_ALIGN(size_rsp, MBOX_MSG_ALIGN);
158 : : /* Check if there is space in mailbox */
159 [ # # ]: 0 : if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset())
160 : 0 : goto exit;
161 [ # # ]: 0 : if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset())
162 : 0 : goto exit;
163 [ # # ]: 0 : if (mdev->msg_size == 0)
164 : 0 : mdev->num_msgs = 0;
165 : 0 : mdev->num_msgs++;
166 : :
167 : 0 : msghdr = (struct mbox_msghdr *)(((uintptr_t)mdev->mbase +
168 : 0 : mbox->tx_start + msgs_offset() +
169 : 0 : mdev->msg_size));
170 : :
171 : : /* Clear the whole msg region */
172 [ # # ]: 0 : mbox_memset(msghdr, 0, sizeof(*msghdr) + size);
173 : : /* Init message header with reset values */
174 : 0 : msghdr->ver = MBOX_VERSION;
175 : 0 : mdev->msg_size += size;
176 : 0 : mdev->rsp_size += size_rsp;
177 : 0 : msghdr->next_msgoff = mdev->msg_size + msgs_offset();
178 : 0 : exit:
179 : :
180 : 0 : return msghdr;
181 : : }
182 : :
183 : : /**
184 : : * @internal
185 : : * Synchronization between UP and DOWN messages
186 : : */
187 : : bool
188 : 0 : mbox_wait_for_zero(struct mbox *mbox, int devid)
189 : : {
190 : : uint64_t data;
191 : :
192 [ # # ]: 0 : data = plt_read64((volatile void *)(mbox->reg_base +
193 : : (mbox->trigger | (devid << mbox->tr_shift))));
194 : :
195 : : /* If data is non-zero wait for ~1ms and return to caller
196 : : * whether data has changed to zero or not after the wait.
197 : : */
198 [ # # ]: 0 : if (data)
199 : 0 : usleep(1000);
200 : : else
201 : : return true;
202 : :
203 : 0 : data = plt_read64((volatile void *)(mbox->reg_base +
204 : : (mbox->trigger | (devid << mbox->tr_shift))));
205 : 0 : return data == 0;
206 : : }
207 : :
208 : : static void
209 : 0 : mbox_msg_send_data(struct mbox *mbox, int devid, uint8_t data)
210 : : {
211 : 0 : struct mbox_dev *mdev = &mbox->dev[devid];
212 : 0 : struct mbox_hdr *tx_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
213 : 0 : struct mbox_hdr *rx_hdr = (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
214 : : uint64_t intr_val;
215 : :
216 : : /* Reset header for next messages */
217 : 0 : tx_hdr->msg_size = mdev->msg_size;
218 : 0 : mdev->msg_size = 0;
219 : 0 : mdev->rsp_size = 0;
220 : 0 : mdev->msgs_acked = 0;
221 : :
222 : : /* num_msgs != 0 signals to the peer that the buffer has a number of
223 : : * messages. So this should be written after copying txmem
224 : : */
225 : 0 : tx_hdr->num_msgs = mdev->num_msgs;
226 : 0 : rx_hdr->num_msgs = 0;
227 : :
228 : : /* Sync mbox data into memory */
229 : : plt_wmb();
230 : :
231 : : /* Check for any pending interrupt */
232 : 0 : intr_val = plt_read64(
233 : : (volatile void *)(mbox->reg_base + (mbox->trigger | (devid << mbox->tr_shift))));
234 : :
235 : 0 : intr_val |= (uint64_t)data;
236 : : /* The interrupt should be fired after num_msgs is written
237 : : * to the shared memory
238 : : */
239 : : plt_write64(intr_val, (volatile void *)(mbox->reg_base +
240 : : (mbox->trigger | (devid << mbox->tr_shift))));
241 : 0 : }
242 : :
243 : : /**
244 : : * @internal
245 : : * Send a mailbox message
246 : : */
247 : : void
248 : 0 : mbox_msg_send(struct mbox *mbox, int devid)
249 : : {
250 : 0 : mbox_msg_send_data(mbox, devid, MBOX_DOWN_MSG);
251 : 0 : }
252 : :
253 : : /**
254 : : * @internal
255 : : * Send an UP mailbox message
256 : : */
257 : : void
258 : 0 : mbox_msg_send_up(struct mbox *mbox, int devid)
259 : : {
260 : 0 : mbox_msg_send_data(mbox, devid, MBOX_UP_MSG);
261 : 0 : }
262 : :
263 : : /**
264 : : * @internal
265 : : * Wait and get mailbox response
266 : : */
267 : : int
268 : 0 : mbox_get_rsp(struct mbox *mbox, int devid, void **msg)
269 : : {
270 : 0 : struct mbox_dev *mdev = &mbox->dev[devid];
271 : : struct mbox_msghdr *msghdr;
272 : : uint64_t offset;
273 : : int rc;
274 : :
275 : 0 : rc = mbox_wait_for_rsp(mbox, devid);
276 [ # # ]: 0 : if (rc < 0)
277 : : return -EIO;
278 : :
279 : : plt_rmb();
280 : :
281 : 0 : offset = mbox->rx_start +
282 : : PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
283 : 0 : msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
284 [ # # ]: 0 : if (msg != NULL)
285 : 0 : *msg = msghdr;
286 : :
287 : 0 : return msghdr->rc;
288 : : }
289 : :
290 : : /**
291 : : * Polling for given wait time to get mailbox response
292 : : */
293 : : static int
294 : 0 : mbox_poll(struct mbox *mbox, uint32_t wait)
295 : : {
296 : : uint32_t timeout = 0, sleep = 1;
297 : 0 : uint32_t wait_us = wait * 1000;
298 : : uint64_t rsp_reg = 0;
299 : : uintptr_t reg_addr;
300 : :
301 : 0 : reg_addr = mbox->reg_base + mbox->intr_offset;
302 : : do {
303 [ # # ]: 0 : rsp_reg = plt_read64(reg_addr);
304 : :
305 [ # # ]: 0 : if (timeout >= wait_us)
306 : : return -ETIMEDOUT;
307 : :
308 : 0 : plt_delay_us(sleep);
309 : 0 : timeout += sleep;
310 [ # # ]: 0 : } while (!rsp_reg);
311 : :
312 : : plt_rmb();
313 : :
314 : : /* Clear interrupt */
315 : : plt_write64(rsp_reg, reg_addr);
316 : :
317 : : /* Reset mbox */
318 : 0 : mbox_reset(mbox, 0);
319 : :
320 : 0 : return 0;
321 : : }
322 : :
323 : : /**
324 : : * @internal
325 : : * Wait and get mailbox response with timeout
326 : : */
327 : : int
328 : 0 : mbox_get_rsp_tmo(struct mbox *mbox, int devid, void **msg, uint32_t tmo)
329 : : {
330 : 0 : struct mbox_dev *mdev = &mbox->dev[devid];
331 : : struct mbox_msghdr *msghdr;
332 : : uint64_t offset;
333 : : int rc;
334 : :
335 : 0 : rc = mbox_wait_for_rsp_tmo(mbox, devid, tmo);
336 [ # # ]: 0 : if (rc != 1)
337 : : return -EIO;
338 : :
339 : : plt_rmb();
340 : :
341 : 0 : offset = mbox->rx_start +
342 : : PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
343 : 0 : msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
344 [ # # ]: 0 : if (msg != NULL)
345 : 0 : *msg = msghdr;
346 : :
347 : 0 : return msghdr->rc;
348 : : }
349 : :
350 : : static int
351 : 0 : mbox_wait(struct mbox *mbox, int devid, uint32_t rst_timo)
352 : : {
353 : 0 : volatile struct mbox_dev *mdev = &mbox->dev[devid];
354 : : uint32_t timeout = 0, sleep = 1;
355 : :
356 : 0 : rst_timo = rst_timo * 1000; /* Milli seconds to micro seconds */
357 : :
358 : : /* Waiting for mdev->msgs_acked tp become equal to mdev->num_msgs,
359 : : * mdev->msgs_acked are incremented at process_msgs() in interrupt
360 : : * thread context.
361 : : */
362 [ # # ]: 0 : while (mdev->num_msgs > mdev->msgs_acked) {
363 : 0 : plt_delay_us(sleep);
364 : 0 : timeout += sleep;
365 [ # # ]: 0 : if (timeout >= rst_timo) {
366 : 0 : struct mbox_hdr *tx_hdr =
367 : 0 : (struct mbox_hdr *)((uintptr_t)mdev->mbase +
368 : 0 : mbox->tx_start);
369 : 0 : struct mbox_hdr *rx_hdr =
370 : 0 : (struct mbox_hdr *)((uintptr_t)mdev->mbase +
371 : 0 : mbox->rx_start);
372 : :
373 : 0 : plt_err("MBOX[devid: %d] message wait timeout %d, "
374 : : "num_msgs: %d, msgs_acked: %d "
375 : : "(tx/rx num_msgs: %d/%d), msg_size: %d, "
376 : : "rsp_size: %d",
377 : : devid, timeout, mdev->num_msgs,
378 : : mdev->msgs_acked, tx_hdr->num_msgs,
379 : : rx_hdr->num_msgs, mdev->msg_size,
380 : : mdev->rsp_size);
381 : :
382 : 0 : return -EIO;
383 : : }
384 : : plt_rmb();
385 : : }
386 : : return 0;
387 : : }
388 : :
389 : : int
390 : 0 : mbox_wait_for_rsp_tmo(struct mbox *mbox, int devid, uint32_t tmo)
391 : : {
392 : 0 : struct mbox_dev *mdev = &mbox->dev[devid];
393 : : int rc = 0;
394 : :
395 : : /* Sync with mbox region */
396 : : plt_rmb();
397 : :
398 [ # # ]: 0 : if (mbox->trigger == RVU_PF_VFX_PFVF_MBOX1 ||
399 : : mbox->trigger == RVU_PF_VFX_PFVF_MBOX0) {
400 : : /* In case of VF, Wait a bit more to account round trip delay */
401 : 0 : tmo = tmo * 2;
402 : : }
403 : :
404 : : /* Wait message */
405 [ # # ]: 0 : if (plt_thread_is_intr())
406 : 0 : rc = mbox_poll(mbox, tmo);
407 : : else
408 : 0 : rc = mbox_wait(mbox, devid, tmo);
409 : :
410 [ # # ]: 0 : if (!rc)
411 : 0 : rc = mdev->num_msgs;
412 : :
413 : 0 : return rc;
414 : : }
415 : :
416 : : /**
417 : : * @internal
418 : : * Wait for the mailbox response
419 : : */
420 : : int
421 : 0 : mbox_wait_for_rsp(struct mbox *mbox, int devid)
422 : : {
423 : 0 : return mbox_wait_for_rsp_tmo(mbox, devid, mbox->rsp_tmo);
424 : : }
425 : :
426 : : int
427 : 0 : mbox_get_availmem(struct mbox *mbox, int devid)
428 : : {
429 : 0 : struct mbox_dev *mdev = &mbox->dev[devid];
430 : : int avail;
431 : :
432 : 0 : plt_spinlock_lock(&mdev->mbox_lock);
433 : 0 : avail = mbox->tx_size - mdev->msg_size - msgs_offset();
434 : : plt_spinlock_unlock(&mdev->mbox_lock);
435 : :
436 : 0 : return avail;
437 : : }
438 : :
439 : : int
440 : 0 : send_ready_msg(struct mbox *mbox, uint16_t *pcifunc)
441 : : {
442 : : struct ready_msg_rsp *rsp;
443 : : int rc;
444 : :
445 : 0 : mbox_alloc_msg_ready(mbox_get(mbox));
446 : :
447 : : rc = mbox_process_msg(mbox, (void *)&rsp);
448 [ # # ]: 0 : if (rc) {
449 : : mbox_put(mbox);
450 : 0 : return rc;
451 : : }
452 : : mbox_put(mbox);
453 : :
454 [ # # ]: 0 : if (rsp->hdr.ver != MBOX_VERSION) {
455 : 0 : plt_err("Incompatible MBox versions(AF: 0x%04x Client: 0x%04x)",
456 : : rsp->hdr.ver, MBOX_VERSION);
457 : 0 : return -EPIPE;
458 : : }
459 : :
460 [ # # ]: 0 : if (pcifunc)
461 : 0 : *pcifunc = rsp->hdr.pcifunc;
462 : :
463 : : /* Save rclk & sclk freq */
464 [ # # # # ]: 0 : if (!dev_rclk_freq || !dev_sclk_freq) {
465 : 0 : dev_rclk_freq = rsp->rclk_freq;
466 : 0 : dev_sclk_freq = rsp->sclk_freq;
467 : : }
468 : : return 0;
469 : : }
470 : :
471 : : int
472 : 0 : reply_invalid_msg(struct mbox *mbox, int devid, uint16_t pcifunc, uint16_t id)
473 : : {
474 : : struct msg_rsp *rsp;
475 : :
476 : : rsp = (struct msg_rsp *)mbox_alloc_msg(mbox, devid, sizeof(*rsp));
477 [ # # ]: 0 : if (!rsp)
478 : : return -ENOMEM;
479 : 0 : rsp->hdr.id = id;
480 : 0 : rsp->hdr.sig = MBOX_RSP_SIG;
481 : 0 : rsp->hdr.rc = MBOX_MSG_INVALID;
482 : 0 : rsp->hdr.pcifunc = pcifunc;
483 : :
484 : 0 : return 0;
485 : : }
486 : :
487 : : /**
488 : : * @internal
489 : : * Convert mail box ID to name
490 : : */
491 : : const char *
492 : 0 : mbox_id2name(uint16_t id)
493 : : {
494 [ # # # # : 0 : switch (id) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
495 : : default:
496 : : return "INVALID ID";
497 : : #define M(_name, _id, _1, _2, _3) \
498 : : case _id: \
499 : : return #_name;
500 : 0 : MBOX_MESSAGES
501 : 0 : MBOX_UP_CGX_MESSAGES
502 : 0 : MBOX_UP_REP_MESSAGES
503 : : #undef M
504 : : }
505 : : }
506 : :
507 : : int
508 : 0 : mbox_id2size(uint16_t id)
509 : : {
510 [ # # # # : 0 : switch (id) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
511 : : default:
512 : : return 0;
513 : : #define M(_1, _id, _2, _req_type, _3) \
514 : : case _id: \
515 : : return sizeof(struct _req_type);
516 : 0 : MBOX_MESSAGES
517 : 0 : MBOX_UP_CGX_MESSAGES
518 : 0 : MBOX_UP_REP_MESSAGES
519 : : #undef M
520 : : }
521 : : }
|