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