common/octeontx: update mbox to version 1.1.3
[dpdk.git] / drivers / common / octeontx / octeontx_mbox.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Cavium, Inc
3  */
4
5 #include <string.h>
6
7 #include <rte_atomic.h>
8 #include <rte_common.h>
9 #include <rte_cycles.h>
10 #include <rte_io.h>
11 #include <rte_spinlock.h>
12
13 #include "octeontx_mbox.h"
14
15 /* Mbox operation timeout in seconds */
16 #define MBOX_WAIT_TIME_SEC      3
17 #define MAX_RAM_MBOX_LEN        ((SSOW_BAR4_LEN >> 1) - 8 /* Mbox header */)
18
19 /* Mbox channel state */
20 enum {
21         MBOX_CHAN_STATE_REQ = 1,
22         MBOX_CHAN_STATE_RES = 0,
23 };
24
25 /* Response messages */
26 enum {
27         MBOX_RET_SUCCESS,
28         MBOX_RET_INVALID,
29         MBOX_RET_INTERNAL_ERR,
30 };
31
32 struct mbox {
33         int init_once;
34         uint8_t ready;
35         uint8_t *ram_mbox_base; /* Base address of mbox message stored in ram */
36         uint8_t *reg; /* Store to this register triggers PF mbox interrupt */
37         uint16_t tag_own; /* Last tag which was written to own channel */
38         rte_spinlock_t lock;
39 };
40
41 static struct mbox octeontx_mbox;
42
43 /*
44  * Structure used for mbox synchronization
45  * This structure sits at the begin of Mbox RAM and used as main
46  * synchronization point for channel communication
47  */
48 struct mbox_ram_hdr {
49         union {
50                 uint64_t u64;
51                 struct {
52                         uint8_t chan_state : 1;
53                         uint8_t coproc : 7;
54                         uint8_t msg;
55                         uint8_t vfid;
56                         uint8_t res_code;
57                         uint16_t tag;
58                         uint16_t len;
59                 };
60         };
61 };
62
63 /* MBOX interface version message */
64 struct mbox_intf_ver {
65         uint32_t platform:12;
66         uint32_t major:10;
67         uint32_t minor:10;
68 };
69
70 int octeontx_logtype_mbox;
71
72 RTE_INIT(otx_init_log)
73 {
74         octeontx_logtype_mbox = rte_log_register("pmd.octeontx.mbox");
75         if (octeontx_logtype_mbox >= 0)
76                 rte_log_set_level(octeontx_logtype_mbox, RTE_LOG_NOTICE);
77 }
78
79 static inline void
80 mbox_msgcpy(volatile uint8_t *d, volatile const uint8_t *s, uint16_t size)
81 {
82         uint16_t i;
83
84         for (i = 0; i < size; i++)
85                 d[i] = s[i];
86 }
87
88 static inline void
89 mbox_send_request(struct mbox *m, struct octeontx_mbox_hdr *hdr,
90                         const void *txmsg, uint16_t txsize)
91 {
92         struct mbox_ram_hdr old_hdr;
93         struct mbox_ram_hdr new_hdr = { {0} };
94         uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
95         uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
96
97         /*
98          * Initialize the channel with the tag left by last send.
99          * On success full mbox send complete, PF increments the tag by one.
100          * The sender can validate integrity of PF message with this scheme
101          */
102         old_hdr.u64 = rte_read64(ram_mbox_hdr);
103         m->tag_own = (old_hdr.tag + 2) & (~0x1ul); /* next even number */
104
105         /* Copy msg body */
106         if (txmsg)
107                 mbox_msgcpy(ram_mbox_msg, txmsg, txsize);
108
109         /* Prepare new hdr */
110         new_hdr.chan_state = MBOX_CHAN_STATE_REQ;
111         new_hdr.coproc = hdr->coproc;
112         new_hdr.msg = hdr->msg;
113         new_hdr.vfid = hdr->vfid;
114         new_hdr.tag = m->tag_own;
115         new_hdr.len = txsize;
116
117         /* Write the msg header */
118         rte_write64(new_hdr.u64, ram_mbox_hdr);
119         rte_smp_wmb();
120         /* Notify PF about the new msg - write to MBOX reg generates PF IRQ */
121         rte_write64(0, m->reg);
122 }
123
124 static inline int
125 mbox_wait_response(struct mbox *m, struct octeontx_mbox_hdr *hdr,
126                         void *rxmsg, uint16_t rxsize)
127 {
128         int res = 0, wait;
129         uint16_t len;
130         struct mbox_ram_hdr rx_hdr;
131         uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
132         uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
133
134         /* Wait for response */
135         wait = MBOX_WAIT_TIME_SEC * 1000 * 10;
136         while (wait > 0) {
137                 rte_delay_us(100);
138                 rx_hdr.u64 = rte_read64(ram_mbox_hdr);
139                 if (rx_hdr.chan_state == MBOX_CHAN_STATE_RES)
140                         break;
141                 --wait;
142         }
143
144         hdr->res_code = rx_hdr.res_code;
145         m->tag_own++;
146
147         /* Timeout */
148         if (wait <= 0) {
149                 res = -ETIMEDOUT;
150                 goto error;
151         }
152
153         /* Tag mismatch */
154         if (m->tag_own != rx_hdr.tag) {
155                 res = -EINVAL;
156                 goto error;
157         }
158
159         /* PF nacked the msg */
160         if (rx_hdr.res_code != MBOX_RET_SUCCESS) {
161                 res = -EBADMSG;
162                 goto error;
163         }
164
165         len = RTE_MIN(rx_hdr.len, rxsize);
166         if (rxmsg)
167                 mbox_msgcpy(rxmsg, ram_mbox_msg, len);
168
169         return len;
170
171 error:
172         mbox_log_err("Failed to send mbox(%d/%d) coproc=%d msg=%d ret=(%d,%d)",
173                         m->tag_own, rx_hdr.tag, hdr->coproc, hdr->msg, res,
174                         hdr->res_code);
175         return res;
176 }
177
178 static inline int
179 mbox_send(struct mbox *m, struct octeontx_mbox_hdr *hdr, const void *txmsg,
180                 uint16_t txsize, void *rxmsg, uint16_t rxsize)
181 {
182         int res = -EINVAL;
183
184         if (m->init_once == 0 || hdr == NULL ||
185                 txsize > MAX_RAM_MBOX_LEN || rxsize > MAX_RAM_MBOX_LEN) {
186                 mbox_log_err("Invalid init_once=%d hdr=%p txsz=%d rxsz=%d",
187                                 m->init_once, hdr, txsize, rxsize);
188                 return res;
189         }
190
191         rte_spinlock_lock(&m->lock);
192
193         mbox_send_request(m, hdr, txmsg, txsize);
194         res = mbox_wait_response(m, hdr, rxmsg, rxsize);
195
196         rte_spinlock_unlock(&m->lock);
197         return res;
198 }
199
200 int
201 octeontx_mbox_set_ram_mbox_base(uint8_t *ram_mbox_base)
202 {
203         struct mbox *m = &octeontx_mbox;
204
205         if (m->init_once)
206                 return -EALREADY;
207
208         if (ram_mbox_base == NULL) {
209                 mbox_log_err("Invalid ram_mbox_base=%p", ram_mbox_base);
210                 return -EINVAL;
211         }
212
213         m->ram_mbox_base = ram_mbox_base;
214
215         if (m->reg != NULL) {
216                 rte_spinlock_init(&m->lock);
217                 m->init_once = 1;
218         }
219
220         return 0;
221 }
222
223 int
224 octeontx_mbox_set_reg(uint8_t *reg)
225 {
226         struct mbox *m = &octeontx_mbox;
227
228         if (m->init_once)
229                 return -EALREADY;
230
231         if (reg == NULL) {
232                 mbox_log_err("Invalid reg=%p", reg);
233                 return -EINVAL;
234         }
235
236         m->reg = reg;
237
238         if (m->ram_mbox_base != NULL) {
239                 rte_spinlock_init(&m->lock);
240                 m->init_once = 1;
241         }
242
243         return 0;
244 }
245
246 int
247 octeontx_mbox_send(struct octeontx_mbox_hdr *hdr, void *txdata,
248                                  uint16_t txlen, void *rxdata, uint16_t rxlen)
249 {
250         struct mbox *m = &octeontx_mbox;
251
252         RTE_BUILD_BUG_ON(sizeof(struct mbox_ram_hdr) != 8);
253         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
254                 return -EINVAL;
255
256         return mbox_send(m, hdr, txdata, txlen, rxdata, rxlen);
257 }
258
259 static int
260 octeontx_start_domain(void)
261 {
262         struct octeontx_mbox_hdr hdr = {0};
263         int result = -EINVAL;
264
265         hdr.coproc = NO_COPROC;
266         hdr.msg = RM_START_APP;
267
268         result = octeontx_mbox_send(&hdr, NULL, 0, NULL, 0);
269         if (result != 0) {
270                 mbox_log_err("Could not start domain. Err=%d. FuncErr=%d\n",
271                              result, hdr.res_code);
272                 result = -EINVAL;
273         }
274
275         return result;
276 }
277
278 static int
279 octeontx_check_mbox_version(struct mbox_intf_ver app_intf_ver,
280                             struct mbox_intf_ver *intf_ver)
281 {
282         struct mbox_intf_ver kernel_intf_ver = {0};
283         struct octeontx_mbox_hdr hdr = {0};
284         int result = 0;
285
286
287         hdr.coproc = NO_COPROC;
288         hdr.msg = RM_INTERFACE_VERSION;
289
290         result = octeontx_mbox_send(&hdr, &app_intf_ver, sizeof(app_intf_ver),
291                         &kernel_intf_ver, sizeof(kernel_intf_ver));
292         if (result != sizeof(kernel_intf_ver)) {
293                 mbox_log_err("Could not send interface version. Err=%d. FuncErr=%d\n",
294                              result, hdr.res_code);
295                 result = -EINVAL;
296         }
297
298         if (intf_ver)
299                 *intf_ver = kernel_intf_ver;
300
301         if (app_intf_ver.platform != kernel_intf_ver.platform ||
302                         app_intf_ver.major != kernel_intf_ver.major ||
303                         app_intf_ver.minor != kernel_intf_ver.minor)
304                 result = -EINVAL;
305
306         return result;
307 }
308
309 int
310 octeontx_mbox_init(void)
311 {
312         const struct mbox_intf_ver MBOX_INTERFACE_VERSION = {
313                 .platform = 0x01,
314                 .major = 0x01,
315                 .minor = 0x03
316         };
317         struct mbox_intf_ver rm_intf_ver = {0};
318         struct mbox *m = &octeontx_mbox;
319         int ret;
320
321         if (m->ready)
322                 return 0;
323
324         ret = octeontx_start_domain();
325         if (ret < 0) {
326                 m->init_once = 0;
327                 return ret;
328         }
329
330         ret = octeontx_check_mbox_version(MBOX_INTERFACE_VERSION,
331                                           &rm_intf_ver);
332         if (ret < 0) {
333                 mbox_log_err("MBOX version: Kernel(%d.%d.%d) != DPDK(%d.%d.%d)",
334                              rm_intf_ver.platform, rm_intf_ver.major,
335                              rm_intf_ver.minor, MBOX_INTERFACE_VERSION.platform,
336                              MBOX_INTERFACE_VERSION.major,
337                              MBOX_INTERFACE_VERSION.minor);
338                 m->init_once = 0;
339                 return -EINVAL;
340         }
341
342         m->ready = 1;
343         rte_mb();
344
345         return 0;
346 }