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