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