xref: /dpdk/drivers/common/cnxk/roc_bphy_cgx.c (revision 7be78d02)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 
5 #include <pthread.h>
6 
7 #include "roc_api.h"
8 #include "roc_priv.h"
9 
10 #define CGX_CMRX_CONFIG		       0x00
11 #define CGX_CMRX_CONFIG_DATA_PKT_RX_EN BIT_ULL(54)
12 #define CGX_CMRX_CONFIG_DATA_PKT_TX_EN BIT_ULL(53)
13 #define CGX_CMRX_INT		       0x40
14 #define CGX_CMRX_INT_OVERFLW	       BIT_ULL(1)
15 /*
16  * CN10K stores number of lmacs in 4 bit filed
17  * in contrary to CN9K which uses only 3 bits.
18  *
19  * In theory masks should differ yet on CN9K
20  * bits beyond specified range contain zeros.
21  *
22  * Hence common longer mask may be used.
23  */
24 #define CGX_CMRX_RX_LMACS	0x128
25 #define CGX_CMRX_RX_LMACS_LMACS GENMASK_ULL(3, 0)
26 #define CGX_CMRX_SCRATCH0	0x1050
27 #define CGX_CMRX_SCRATCH1	0x1058
28 
29 static uint64_t
roc_bphy_cgx_read(struct roc_bphy_cgx * roc_cgx,uint64_t lmac,uint64_t offset)30 roc_bphy_cgx_read(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset)
31 {
32 	int shift = roc_model_is_cn10k() ? 20 : 18;
33 	uint64_t base = (uint64_t)roc_cgx->bar0_va;
34 
35 	return plt_read64(base + (lmac << shift) + offset);
36 }
37 
38 static void
roc_bphy_cgx_write(struct roc_bphy_cgx * roc_cgx,uint64_t lmac,uint64_t offset,uint64_t value)39 roc_bphy_cgx_write(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset,
40 		   uint64_t value)
41 {
42 	int shift = roc_model_is_cn10k() ? 20 : 18;
43 	uint64_t base = (uint64_t)roc_cgx->bar0_va;
44 
45 	plt_write64(value, base + (lmac << shift) + offset);
46 }
47 
48 static void
roc_bphy_cgx_ack(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,uint64_t * scr0)49 roc_bphy_cgx_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
50 		 uint64_t *scr0)
51 {
52 	uint64_t val;
53 
54 	/* clear interrupt */
55 	val = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_INT);
56 	val |= FIELD_PREP(CGX_CMRX_INT_OVERFLW, 1);
57 	roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_INT, val);
58 
59 	/* ack fw response */
60 	*scr0 &= ~SCR0_ETH_EVT_STS_S_ACK;
61 	roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH0, *scr0);
62 }
63 
64 static int
roc_bphy_cgx_wait_for_ownership(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,uint64_t * scr0)65 roc_bphy_cgx_wait_for_ownership(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
66 				uint64_t *scr0)
67 {
68 	int tries = 5000;
69 	uint64_t scr1;
70 
71 	do {
72 		*scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
73 		scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
74 
75 		if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
76 		    FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0) == 0)
77 			break;
78 
79 		/* clear async events if any */
80 		if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) ==
81 		    ETH_EVT_ASYNC &&
82 		    FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
83 			roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
84 
85 		plt_delay_ms(1);
86 	} while (--tries);
87 
88 	return tries ? 0 : -ETIMEDOUT;
89 }
90 
91 static int
roc_bphy_cgx_wait_for_ack(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,uint64_t * scr0)92 roc_bphy_cgx_wait_for_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
93 			  uint64_t *scr0)
94 {
95 	int tries = 5000;
96 	uint64_t scr1;
97 
98 	do {
99 		*scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0);
100 		scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1);
101 
102 		if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW &&
103 		    FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0))
104 			break;
105 
106 		plt_delay_ms(1);
107 	} while (--tries);
108 
109 	return tries ? 0 : -ETIMEDOUT;
110 }
111 
112 static int
roc_bphy_cgx_intf_req(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,uint64_t scr1,uint64_t * scr0)113 roc_bphy_cgx_intf_req(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
114 		      uint64_t scr1, uint64_t *scr0)
115 {
116 	uint8_t cmd_id = FIELD_GET(SCR1_ETH_CMD_ID, scr1);
117 	int ret;
118 
119 	pthread_mutex_lock(&roc_cgx->lock);
120 
121 	/* wait for ownership */
122 	ret = roc_bphy_cgx_wait_for_ownership(roc_cgx, lmac, scr0);
123 	if (ret) {
124 		plt_err("timed out waiting for ownership");
125 		goto out;
126 	}
127 
128 	/* write command */
129 	scr1 |= FIELD_PREP(SCR1_OWN_STATUS, ETH_OWN_FIRMWARE);
130 	roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH1, scr1);
131 
132 	/* wait for command ack */
133 	ret = roc_bphy_cgx_wait_for_ack(roc_cgx, lmac, scr0);
134 	if (ret) {
135 		plt_err("timed out waiting for response");
136 		goto out;
137 	}
138 
139 	if (cmd_id == ETH_CMD_INTF_SHUTDOWN)
140 		goto out;
141 
142 	if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) != ETH_EVT_CMD_RESP) {
143 		plt_err("received async event instead of cmd resp event");
144 		ret = -EIO;
145 		goto out;
146 	}
147 
148 	if (FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0) != cmd_id) {
149 		plt_err("received resp for cmd %d expected for cmd %d",
150 			(int)FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0), cmd_id);
151 		ret = -EIO;
152 		goto out;
153 	}
154 
155 	if (FIELD_GET(SCR0_ETH_EVT_STS_S_STAT, *scr0) != ETH_STAT_SUCCESS) {
156 		plt_err("cmd %d failed on cgx%u lmac%u with errcode %d", cmd_id,
157 			roc_cgx->id, lmac,
158 			(int)FIELD_GET(SCR0_ETH_LNK_STS_S_ERR_TYPE, *scr0));
159 		ret = -EIO;
160 	}
161 
162 out:
163 	roc_bphy_cgx_ack(roc_cgx, lmac, scr0);
164 
165 	pthread_mutex_unlock(&roc_cgx->lock);
166 
167 	return ret;
168 }
169 
170 static unsigned int
roc_bphy_cgx_dev_id(struct roc_bphy_cgx * roc_cgx)171 roc_bphy_cgx_dev_id(struct roc_bphy_cgx *roc_cgx)
172 {
173 	uint64_t cgx_id = roc_model_is_cn10k() ? GENMASK_ULL(26, 24) :
174 						 GENMASK_ULL(25, 24);
175 
176 	return FIELD_GET(cgx_id, roc_cgx->bar0_pa);
177 }
178 
179 int
roc_bphy_cgx_dev_init(struct roc_bphy_cgx * roc_cgx)180 roc_bphy_cgx_dev_init(struct roc_bphy_cgx *roc_cgx)
181 {
182 	uint64_t val;
183 	int ret;
184 
185 	if (!roc_cgx || !roc_cgx->bar0_va || !roc_cgx->bar0_pa)
186 		return -EINVAL;
187 
188 	ret = pthread_mutex_init(&roc_cgx->lock, NULL);
189 	if (ret)
190 		return ret;
191 
192 	val = roc_bphy_cgx_read(roc_cgx, 0, CGX_CMRX_RX_LMACS);
193 	val = FIELD_GET(CGX_CMRX_RX_LMACS_LMACS, val);
194 	if (roc_model_is_cn9k())
195 		val = GENMASK_ULL(val - 1, 0);
196 	roc_cgx->lmac_bmap = val;
197 	roc_cgx->id = roc_bphy_cgx_dev_id(roc_cgx);
198 
199 	return 0;
200 }
201 
202 int
roc_bphy_cgx_dev_fini(struct roc_bphy_cgx * roc_cgx)203 roc_bphy_cgx_dev_fini(struct roc_bphy_cgx *roc_cgx)
204 {
205 	if (!roc_cgx)
206 		return -EINVAL;
207 
208 	pthread_mutex_destroy(&roc_cgx->lock);
209 
210 	return 0;
211 }
212 
213 static bool
roc_bphy_cgx_lmac_exists(struct roc_bphy_cgx * roc_cgx,unsigned int lmac)214 roc_bphy_cgx_lmac_exists(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
215 {
216 	return (lmac < MAX_LMACS_PER_CGX) &&
217 	       (roc_cgx->lmac_bmap & BIT_ULL(lmac));
218 }
219 
220 static int
roc_bphy_cgx_start_stop_rxtx(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,bool start)221 roc_bphy_cgx_start_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
222 			     bool start)
223 {
224 	uint64_t val;
225 
226 	if (!roc_cgx)
227 		return -EINVAL;
228 
229 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
230 		return -ENODEV;
231 
232 	pthread_mutex_lock(&roc_cgx->lock);
233 	val = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_CONFIG);
234 	val &= ~(CGX_CMRX_CONFIG_DATA_PKT_RX_EN |
235 		 CGX_CMRX_CONFIG_DATA_PKT_TX_EN);
236 
237 	if (start)
238 		val |= FIELD_PREP(CGX_CMRX_CONFIG_DATA_PKT_RX_EN, 1) |
239 		       FIELD_PREP(CGX_CMRX_CONFIG_DATA_PKT_TX_EN, 1);
240 
241 	roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_CONFIG, val);
242 	pthread_mutex_unlock(&roc_cgx->lock);
243 
244 	return 0;
245 }
246 
247 static int
roc_bphy_cgx_intlbk_ena_dis(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,bool enable)248 roc_bphy_cgx_intlbk_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
249 			    bool enable)
250 {
251 	uint64_t scr1, scr0;
252 
253 	if (!roc_cgx)
254 		return -EINVAL;
255 
256 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
257 		return -ENODEV;
258 
259 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_INTERNAL_LBK) |
260 	       FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable);
261 
262 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
263 }
264 
265 static int
roc_bphy_cgx_ptp_rx_ena_dis(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,bool enable)266 roc_bphy_cgx_ptp_rx_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
267 			    bool enable)
268 {
269 	uint64_t scr1, scr0;
270 
271 	if (roc_model_is_cn10k())
272 		return -ENOTSUP;
273 
274 	if (!roc_cgx)
275 		return -EINVAL;
276 
277 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
278 		return -ENODEV;
279 
280 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_PTP_MODE) |
281 	       FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable);
282 
283 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
284 }
285 
286 int
roc_bphy_cgx_start_rxtx(struct roc_bphy_cgx * roc_cgx,unsigned int lmac)287 roc_bphy_cgx_start_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
288 {
289 	return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, true);
290 }
291 
292 int
roc_bphy_cgx_stop_rxtx(struct roc_bphy_cgx * roc_cgx,unsigned int lmac)293 roc_bphy_cgx_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
294 {
295 	return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, false);
296 }
297 
298 int
roc_bphy_cgx_set_link_state(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,bool state)299 roc_bphy_cgx_set_link_state(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
300 			    bool state)
301 {
302 	uint64_t scr1, scr0;
303 
304 	if (!roc_cgx)
305 		return -EINVAL;
306 
307 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
308 		return -ENODEV;
309 
310 	scr1 = state ? FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_UP) :
311 		       FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_DOWN);
312 
313 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
314 }
315 
316 int
roc_bphy_cgx_get_linkinfo(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,struct roc_bphy_cgx_link_info * info)317 roc_bphy_cgx_get_linkinfo(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
318 			  struct roc_bphy_cgx_link_info *info)
319 {
320 	uint64_t scr1, scr0;
321 	int ret;
322 
323 	if (!roc_cgx)
324 		return -EINVAL;
325 
326 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
327 		return -ENODEV;
328 
329 	if (!info)
330 		return -EINVAL;
331 
332 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_LINK_STS);
333 	ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
334 	if (ret)
335 		return ret;
336 
337 	info->link_up = FIELD_GET(SCR0_ETH_LNK_STS_S_LINK_UP, scr0);
338 	info->full_duplex = FIELD_GET(SCR0_ETH_LNK_STS_S_FULL_DUPLEX, scr0);
339 	info->speed = FIELD_GET(SCR0_ETH_LNK_STS_S_SPEED, scr0);
340 	info->an = FIELD_GET(SCR0_ETH_LNK_STS_S_AN, scr0);
341 	info->fec = FIELD_GET(SCR0_ETH_LNK_STS_S_FEC, scr0);
342 	info->mode = FIELD_GET(SCR0_ETH_LNK_STS_S_MODE, scr0);
343 
344 	return 0;
345 }
346 
347 int
roc_bphy_cgx_set_link_mode(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,struct roc_bphy_cgx_link_mode * mode)348 roc_bphy_cgx_set_link_mode(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
349 			   struct roc_bphy_cgx_link_mode *mode)
350 {
351 	uint64_t scr1, scr0;
352 
353 	if (roc_model_is_cn10k())
354 		return -ENOTSUP;
355 
356 	if (!roc_cgx)
357 		return -EINVAL;
358 
359 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
360 		return -ENODEV;
361 
362 	if (!mode)
363 		return -EINVAL;
364 
365 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_MODE_CHANGE) |
366 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_SPEED, mode->speed) |
367 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_DUPLEX, mode->full_duplex) |
368 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_AN, mode->an) |
369 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_PORT, mode->port) |
370 	       FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_MODE, BIT_ULL(mode->mode));
371 
372 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
373 }
374 
375 int
roc_bphy_cgx_intlbk_enable(struct roc_bphy_cgx * roc_cgx,unsigned int lmac)376 roc_bphy_cgx_intlbk_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
377 {
378 	return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, true);
379 }
380 
381 int
roc_bphy_cgx_intlbk_disable(struct roc_bphy_cgx * roc_cgx,unsigned int lmac)382 roc_bphy_cgx_intlbk_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
383 {
384 	return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, false);
385 }
386 
387 int
roc_bphy_cgx_ptp_rx_enable(struct roc_bphy_cgx * roc_cgx,unsigned int lmac)388 roc_bphy_cgx_ptp_rx_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
389 {
390 	return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, true);
391 }
392 
393 int
roc_bphy_cgx_ptp_rx_disable(struct roc_bphy_cgx * roc_cgx,unsigned int lmac)394 roc_bphy_cgx_ptp_rx_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac)
395 {
396 	return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, false);
397 }
398 
399 int
roc_bphy_cgx_fec_set(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,enum roc_bphy_cgx_eth_link_fec fec)400 roc_bphy_cgx_fec_set(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
401 		     enum roc_bphy_cgx_eth_link_fec fec)
402 {
403 	uint64_t scr1, scr0;
404 
405 	if (!roc_cgx)
406 		return -EINVAL;
407 
408 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
409 		return -ENODEV;
410 
411 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_FEC) |
412 	       FIELD_PREP(SCR1_ETH_SET_FEC_ARGS, fec);
413 
414 	return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
415 }
416 
417 int
roc_bphy_cgx_fec_supported_get(struct roc_bphy_cgx * roc_cgx,unsigned int lmac,enum roc_bphy_cgx_eth_link_fec * fec)418 roc_bphy_cgx_fec_supported_get(struct roc_bphy_cgx *roc_cgx, unsigned int lmac,
419 			       enum roc_bphy_cgx_eth_link_fec *fec)
420 {
421 	uint64_t scr1, scr0;
422 	int ret;
423 
424 	if (!roc_cgx || !fec)
425 		return -EINVAL;
426 
427 	if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac))
428 		return -ENODEV;
429 
430 	scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_SUPPORTED_FEC);
431 
432 	ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0);
433 	if (ret)
434 		return ret;
435 
436 	scr0 = FIELD_GET(SCR0_ETH_FEC_TYPES_S_FEC, scr0);
437 	*fec = (enum roc_bphy_cgx_eth_link_fec)scr0;
438 
439 	return 0;
440 }
441