xref: /dpdk/drivers/common/octeontx/octeontx_mbox.c (revision 7efe28bd07b3ac8cbc5cbc35ca6c5bc2f30c6a5b)
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 }
358