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