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