xref: /dpdk/drivers/common/octeontx/octeontx_mbox.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
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 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 	for (i = 0; i < size; i++)
80 		d[i] = s[i];
81 }
82 
83 static inline void
84 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 	struct mbox_ram_hdr new_hdr = { {0} };
89 	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 	m->tag_own = (old_hdr.tag + 2) & (~0x1ul); /* next even number */
99 
100 	/* Copy msg body */
101 	if (txmsg)
102 		mbox_msgcpy(ram_mbox_msg, txmsg, txsize);
103 
104 	/* Prepare new hdr */
105 	new_hdr.chan_state = MBOX_CHAN_STATE_REQ;
106 	new_hdr.coproc = hdr->coproc;
107 	new_hdr.msg = hdr->msg;
108 	new_hdr.vfid = hdr->vfid;
109 	new_hdr.tag = m->tag_own;
110 	new_hdr.len = txsize;
111 
112 	/* Write the msg header */
113 	rte_write64(new_hdr.u64, ram_mbox_hdr);
114 	rte_smp_wmb();
115 	/* Notify PF about the new msg - write to MBOX reg generates PF IRQ */
116 	rte_write64(0, m->reg);
117 }
118 
119 static inline int
120 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 	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 	while (wait > 0) {
132 		rte_delay_us(100);
133 		rx_hdr.u64 = rte_read64(ram_mbox_hdr);
134 		if (rx_hdr.chan_state == MBOX_CHAN_STATE_RES)
135 			break;
136 		--wait;
137 	}
138 
139 	hdr->res_code = rx_hdr.res_code;
140 	m->tag_own++;
141 
142 	/* Timeout */
143 	if (wait <= 0) {
144 		res = -ETIMEDOUT;
145 		goto error;
146 	}
147 
148 	/* Tag mismatch */
149 	if (m->tag_own != rx_hdr.tag) {
150 		res = -EINVAL;
151 		goto error;
152 	}
153 
154 	/* PF nacked the msg */
155 	if (rx_hdr.res_code != MBOX_RET_SUCCESS) {
156 		res = -EBADMSG;
157 		goto error;
158 	}
159 
160 	len = RTE_MIN(rx_hdr.len, rxsize);
161 	if (rxmsg)
162 		mbox_msgcpy(rxmsg, ram_mbox_msg, len);
163 
164 	return len;
165 
166 error:
167 	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 	return res;
171 }
172 
173 static inline int
174 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 	if (m->init_once == 0 || hdr == NULL ||
180 		txsize > MAX_RAM_MBOX_LEN || rxsize > MAX_RAM_MBOX_LEN) {
181 		mbox_log_err("Invalid init_once=%d hdr=%p txsz=%d rxsz=%d",
182 				m->init_once, hdr, txsize, rxsize);
183 		return res;
184 	}
185 
186 	rte_spinlock_lock(&m->lock);
187 
188 	mbox_send_request(m, hdr, txmsg, txsize);
189 	res = mbox_wait_response(m, hdr, rxmsg, rxsize);
190 
191 	rte_spinlock_unlock(&m->lock);
192 	return res;
193 }
194 
195 int
196 octeontx_mbox_set_ram_mbox_base(uint8_t *ram_mbox_base, uint16_t domain)
197 {
198 	struct mbox *m = &octeontx_mbox;
199 
200 	if (m->init_once)
201 		return -EALREADY;
202 
203 	if (ram_mbox_base == NULL) {
204 		mbox_log_err("Invalid ram_mbox_base=%p", ram_mbox_base);
205 		return -EINVAL;
206 	}
207 
208 	m->ram_mbox_base = ram_mbox_base;
209 
210 	if (m->reg != NULL) {
211 		rte_spinlock_init(&m->lock);
212 		m->init_once = 1;
213 		m->domain = domain;
214 	}
215 
216 	return 0;
217 }
218 
219 int
220 octeontx_mbox_set_reg(uint8_t *reg, uint16_t domain)
221 {
222 	struct mbox *m = &octeontx_mbox;
223 
224 	if (m->init_once)
225 		return -EALREADY;
226 
227 	if (reg == NULL) {
228 		mbox_log_err("Invalid reg=%p", reg);
229 		return -EINVAL;
230 	}
231 
232 	m->reg = reg;
233 
234 	if (m->ram_mbox_base != NULL) {
235 		rte_spinlock_init(&m->lock);
236 		m->init_once = 1;
237 		m->domain = domain;
238 	}
239 
240 	return 0;
241 }
242 
243 int
244 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 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
251 		return -EINVAL;
252 
253 	return mbox_send(m, hdr, txdata, txlen, rxdata, rxlen);
254 }
255 
256 static int
257 octeontx_start_domain(void)
258 {
259 	struct octeontx_mbox_hdr hdr = {0};
260 	int result = -EINVAL;
261 
262 	hdr.coproc = NO_COPROC;
263 	hdr.msg = RM_START_APP;
264 
265 	result = octeontx_mbox_send(&hdr, NULL, 0, NULL, 0);
266 	if (result != 0) {
267 		mbox_log_err("Could not start domain. Err=%d. FuncErr=%d",
268 			     result, hdr.res_code);
269 		result = -EINVAL;
270 	}
271 
272 	return result;
273 }
274 
275 static int
276 octeontx_check_mbox_version(struct mbox_intf_ver *app_intf_ver,
277 			    struct mbox_intf_ver *intf_ver)
278 {
279 	struct mbox_intf_ver kernel_intf_ver = {0};
280 	struct octeontx_mbox_hdr hdr = {0};
281 	int result = 0;
282 
283 
284 	hdr.coproc = NO_COPROC;
285 	hdr.msg = RM_INTERFACE_VERSION;
286 
287 	result = octeontx_mbox_send(&hdr, app_intf_ver,
288 				    sizeof(struct mbox_intf_ver),
289 				    &kernel_intf_ver, sizeof(kernel_intf_ver));
290 	if (result != sizeof(kernel_intf_ver)) {
291 		mbox_log_err("Could not send interface version. Err=%d. FuncErr=%d",
292 			     result, hdr.res_code);
293 		result = -EINVAL;
294 	}
295 
296 	if (intf_ver)
297 		*intf_ver = kernel_intf_ver;
298 
299 	if (app_intf_ver->platform != kernel_intf_ver.platform ||
300 			app_intf_ver->major != kernel_intf_ver.major ||
301 			app_intf_ver->minor != kernel_intf_ver.minor)
302 		result = -EINVAL;
303 
304 	return result;
305 }
306 
307 int
308 octeontx_mbox_init(void)
309 {
310 	struct mbox_intf_ver MBOX_INTERFACE_VERSION = {
311 		.platform = 0x01,
312 		.major = 0x01,
313 		.minor = 0x03
314 	};
315 	struct mbox_intf_ver rm_intf_ver = {0};
316 	struct mbox *m = &octeontx_mbox;
317 	int ret;
318 
319 	if (m->ready)
320 		return 0;
321 
322 	ret = octeontx_start_domain();
323 	if (ret < 0) {
324 		m->init_once = 0;
325 		return ret;
326 	}
327 
328 	ret = octeontx_check_mbox_version(&MBOX_INTERFACE_VERSION,
329 					  &rm_intf_ver);
330 	if (ret < 0) {
331 		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 		m->init_once = 0;
337 		return -EINVAL;
338 	}
339 
340 	m->ready = 1;
341 	rte_mb();
342 
343 	return 0;
344 }
345 
346 uint16_t
347 octeontx_get_global_domain(void)
348 {
349 	struct mbox *m = &octeontx_mbox;
350 
351 	return m->domain;
352 }
353