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