1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell CN10K RPM driver
3 *
4 * Copyright (C) 2020 Marvell.
5 *
6 */
7
8 #include "cgx.h"
9 #include "lmac_common.h"
10
11 static struct mac_ops rpm_mac_ops = {
12 .name = "rpm",
13 .csr_offset = 0x4e00,
14 .lmac_offset = 20,
15 .int_register = RPMX_CMRX_SW_INT,
16 .int_set_reg = RPMX_CMRX_SW_INT_ENA_W1S,
17 .irq_offset = 1,
18 .int_ena_bit = BIT_ULL(0),
19 .lmac_fwi = RPM_LMAC_FWI,
20 .non_contiguous_serdes_lane = true,
21 .rx_stats_cnt = 43,
22 .tx_stats_cnt = 34,
23 .dmac_filter_count = 32,
24 .get_nr_lmacs = rpm_get_nr_lmacs,
25 .get_lmac_type = rpm_get_lmac_type,
26 .lmac_fifo_len = rpm_get_lmac_fifo_len,
27 .mac_lmac_intl_lbk = rpm_lmac_internal_loopback,
28 .mac_get_rx_stats = rpm_get_rx_stats,
29 .mac_get_tx_stats = rpm_get_tx_stats,
30 .get_fec_stats = rpm_get_fec_stats,
31 .mac_enadis_rx_pause_fwding = rpm_lmac_enadis_rx_pause_fwding,
32 .mac_get_pause_frm_status = rpm_lmac_get_pause_frm_status,
33 .mac_enadis_pause_frm = rpm_lmac_enadis_pause_frm,
34 .mac_pause_frm_config = rpm_lmac_pause_frm_config,
35 .mac_enadis_ptp_config = rpm_lmac_ptp_config,
36 .mac_rx_tx_enable = rpm_lmac_rx_tx_enable,
37 .mac_tx_enable = rpm_lmac_tx_enable,
38 .pfc_config = rpm_lmac_pfc_config,
39 .mac_get_pfc_frm_cfg = rpm_lmac_get_pfc_frm_cfg,
40 .mac_reset = rpm_lmac_reset,
41 .mac_stats_reset = rpm_stats_reset,
42 };
43
44 static struct mac_ops rpm2_mac_ops = {
45 .name = "rpm",
46 .csr_offset = RPM2_CSR_OFFSET,
47 .lmac_offset = 20,
48 .int_register = RPM2_CMRX_SW_INT,
49 .int_set_reg = RPM2_CMRX_SW_INT_ENA_W1S,
50 .irq_offset = 1,
51 .int_ena_bit = BIT_ULL(0),
52 .lmac_fwi = RPM2_LMAC_FWI,
53 .non_contiguous_serdes_lane = true,
54 .rx_stats_cnt = 43,
55 .tx_stats_cnt = 34,
56 .dmac_filter_count = 64,
57 .get_nr_lmacs = rpm2_get_nr_lmacs,
58 .get_lmac_type = rpm_get_lmac_type,
59 .lmac_fifo_len = rpm2_get_lmac_fifo_len,
60 .mac_lmac_intl_lbk = rpm_lmac_internal_loopback,
61 .mac_get_rx_stats = rpm_get_rx_stats,
62 .mac_get_tx_stats = rpm_get_tx_stats,
63 .get_fec_stats = rpm_get_fec_stats,
64 .mac_enadis_rx_pause_fwding = rpm_lmac_enadis_rx_pause_fwding,
65 .mac_get_pause_frm_status = rpm_lmac_get_pause_frm_status,
66 .mac_enadis_pause_frm = rpm_lmac_enadis_pause_frm,
67 .mac_pause_frm_config = rpm_lmac_pause_frm_config,
68 .mac_enadis_ptp_config = rpm_lmac_ptp_config,
69 .mac_rx_tx_enable = rpm_lmac_rx_tx_enable,
70 .mac_tx_enable = rpm_lmac_tx_enable,
71 .pfc_config = rpm_lmac_pfc_config,
72 .mac_get_pfc_frm_cfg = rpm_lmac_get_pfc_frm_cfg,
73 .mac_reset = rpm_lmac_reset,
74 .mac_stats_reset = rpm_stats_reset,
75 };
76
is_dev_rpm2(void * rpmd)77 bool is_dev_rpm2(void *rpmd)
78 {
79 rpm_t *rpm = rpmd;
80
81 return (rpm->pdev->device == PCI_DEVID_CN10KB_RPM);
82 }
83
rpm_get_mac_ops(rpm_t * rpm)84 struct mac_ops *rpm_get_mac_ops(rpm_t *rpm)
85 {
86 if (is_dev_rpm2(rpm))
87 return &rpm2_mac_ops;
88 else
89 return &rpm_mac_ops;
90 }
91
rpm_write(rpm_t * rpm,u64 lmac,u64 offset,u64 val)92 static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val)
93 {
94 cgx_write(rpm, lmac, offset, val);
95 }
96
rpm_read(rpm_t * rpm,u64 lmac,u64 offset)97 static u64 rpm_read(rpm_t *rpm, u64 lmac, u64 offset)
98 {
99 return cgx_read(rpm, lmac, offset);
100 }
101
102 /* Read HW major version to determine RPM
103 * MAC type 100/USX
104 */
is_mac_rpmusx(void * rpmd)105 static bool is_mac_rpmusx(void *rpmd)
106 {
107 rpm_t *rpm = rpmd;
108
109 return rpm_read(rpm, 0, RPMX_CONST1) & 0x700ULL;
110 }
111
rpm_get_nr_lmacs(void * rpmd)112 int rpm_get_nr_lmacs(void *rpmd)
113 {
114 rpm_t *rpm = rpmd;
115
116 return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL);
117 }
118
rpm2_get_nr_lmacs(void * rpmd)119 int rpm2_get_nr_lmacs(void *rpmd)
120 {
121 rpm_t *rpm = rpmd;
122
123 return hweight8(rpm_read(rpm, 0, RPM2_CMRX_RX_LMACS) & 0xFFULL);
124 }
125
rpm_lmac_tx_enable(void * rpmd,int lmac_id,bool enable)126 int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable)
127 {
128 rpm_t *rpm = rpmd;
129 u64 cfg, last;
130
131 if (!is_lmac_valid(rpm, lmac_id))
132 return -ENODEV;
133
134 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
135 last = cfg;
136 if (enable)
137 cfg |= RPM_TX_EN;
138 else
139 cfg &= ~(RPM_TX_EN);
140
141 if (cfg != last)
142 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
143 return !!(last & RPM_TX_EN);
144 }
145
rpm_lmac_rx_tx_enable(void * rpmd,int lmac_id,bool enable)146 int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable)
147 {
148 rpm_t *rpm = rpmd;
149 u64 cfg;
150
151 if (!is_lmac_valid(rpm, lmac_id))
152 return -ENODEV;
153
154 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
155 if (enable)
156 cfg |= RPM_RX_EN | RPM_TX_EN;
157 else
158 cfg &= ~(RPM_RX_EN | RPM_TX_EN);
159 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
160 return 0;
161 }
162
rpm_lmac_enadis_rx_pause_fwding(void * rpmd,int lmac_id,bool enable)163 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable)
164 {
165 rpm_t *rpm = rpmd;
166 struct lmac *lmac;
167 u64 cfg;
168
169 if (!rpm)
170 return;
171
172 lmac = lmac_pdata(lmac_id, rpm);
173 if (!lmac)
174 return;
175
176 /* Pause frames are not enabled just return */
177 if (!bitmap_weight(lmac->rx_fc_pfvf_bmap.bmap, lmac->rx_fc_pfvf_bmap.max))
178 return;
179
180 if (enable) {
181 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
182 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
183 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
184 } else {
185 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
186 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
187 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
188 }
189 }
190
rpm_lmac_get_pause_frm_status(void * rpmd,int lmac_id,u8 * tx_pause,u8 * rx_pause)191 int rpm_lmac_get_pause_frm_status(void *rpmd, int lmac_id,
192 u8 *tx_pause, u8 *rx_pause)
193 {
194 rpm_t *rpm = rpmd;
195 u64 cfg;
196
197 if (!is_lmac_valid(rpm, lmac_id))
198 return -ENODEV;
199
200 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
201 if (!(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE)) {
202 *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE);
203 *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE);
204 }
205
206 return 0;
207 }
208
rpm_cfg_pfc_quanta_thresh(rpm_t * rpm,int lmac_id,unsigned long pfc_en,bool enable)209 static void rpm_cfg_pfc_quanta_thresh(rpm_t *rpm, int lmac_id,
210 unsigned long pfc_en,
211 bool enable)
212 {
213 u64 quanta_offset = 0, quanta_thresh = 0, cfg;
214 int i, shift;
215
216 /* Set pause time and interval */
217 for_each_set_bit(i, &pfc_en, 16) {
218 switch (i) {
219 case 0:
220 case 1:
221 quanta_offset = RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA;
222 quanta_thresh = RPMX_MTI_MAC100X_CL01_QUANTA_THRESH;
223 break;
224 case 2:
225 case 3:
226 quanta_offset = RPMX_MTI_MAC100X_CL23_PAUSE_QUANTA;
227 quanta_thresh = RPMX_MTI_MAC100X_CL23_QUANTA_THRESH;
228 break;
229 case 4:
230 case 5:
231 quanta_offset = RPMX_MTI_MAC100X_CL45_PAUSE_QUANTA;
232 quanta_thresh = RPMX_MTI_MAC100X_CL45_QUANTA_THRESH;
233 break;
234 case 6:
235 case 7:
236 quanta_offset = RPMX_MTI_MAC100X_CL67_PAUSE_QUANTA;
237 quanta_thresh = RPMX_MTI_MAC100X_CL67_QUANTA_THRESH;
238 break;
239 case 8:
240 case 9:
241 quanta_offset = RPMX_MTI_MAC100X_CL89_PAUSE_QUANTA;
242 quanta_thresh = RPMX_MTI_MAC100X_CL89_QUANTA_THRESH;
243 break;
244 case 10:
245 case 11:
246 quanta_offset = RPMX_MTI_MAC100X_CL1011_PAUSE_QUANTA;
247 quanta_thresh = RPMX_MTI_MAC100X_CL1011_QUANTA_THRESH;
248 break;
249 case 12:
250 case 13:
251 quanta_offset = RPMX_MTI_MAC100X_CL1213_PAUSE_QUANTA;
252 quanta_thresh = RPMX_MTI_MAC100X_CL1213_QUANTA_THRESH;
253 break;
254 case 14:
255 case 15:
256 quanta_offset = RPMX_MTI_MAC100X_CL1415_PAUSE_QUANTA;
257 quanta_thresh = RPMX_MTI_MAC100X_CL1415_QUANTA_THRESH;
258 break;
259 }
260
261 if (!quanta_offset || !quanta_thresh)
262 continue;
263
264 shift = (i % 2) ? 1 : 0;
265 cfg = rpm_read(rpm, lmac_id, quanta_offset);
266 if (enable) {
267 cfg |= ((u64)RPM_DEFAULT_PAUSE_TIME << shift * 16);
268 } else {
269 if (!shift)
270 cfg &= ~GENMASK_ULL(15, 0);
271 else
272 cfg &= ~GENMASK_ULL(31, 16);
273 }
274 rpm_write(rpm, lmac_id, quanta_offset, cfg);
275
276 cfg = rpm_read(rpm, lmac_id, quanta_thresh);
277 if (enable) {
278 cfg |= ((u64)(RPM_DEFAULT_PAUSE_TIME / 2) << shift * 16);
279 } else {
280 if (!shift)
281 cfg &= ~GENMASK_ULL(15, 0);
282 else
283 cfg &= ~GENMASK_ULL(31, 16);
284 }
285 rpm_write(rpm, lmac_id, quanta_thresh, cfg);
286 }
287 }
288
rpm2_lmac_cfg_bp(rpm_t * rpm,int lmac_id,u8 tx_pause,u8 rx_pause)289 static void rpm2_lmac_cfg_bp(rpm_t *rpm, int lmac_id, u8 tx_pause, u8 rx_pause)
290 {
291 u64 cfg;
292
293 cfg = rpm_read(rpm, lmac_id, RPM2_CMR_RX_OVR_BP);
294 if (tx_pause) {
295 /* Configure CL0 Pause Quanta & threshold
296 * for 802.3X frames
297 */
298 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 1, true);
299 cfg &= ~RPM2_CMR_RX_OVR_BP_EN;
300 } else {
301 /* Disable all Pause Quanta & threshold values */
302 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xffff, false);
303 cfg |= RPM2_CMR_RX_OVR_BP_EN;
304 cfg &= ~RPM2_CMR_RX_OVR_BP_BP;
305 }
306 rpm_write(rpm, lmac_id, RPM2_CMR_RX_OVR_BP, cfg);
307 }
308
rpm_lmac_cfg_bp(rpm_t * rpm,int lmac_id,u8 tx_pause,u8 rx_pause)309 static void rpm_lmac_cfg_bp(rpm_t *rpm, int lmac_id, u8 tx_pause, u8 rx_pause)
310 {
311 u64 cfg;
312
313 cfg = rpm_read(rpm, 0, RPMX_CMR_RX_OVR_BP);
314 if (tx_pause) {
315 /* Configure CL0 Pause Quanta & threshold for
316 * 802.3X frames
317 */
318 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 1, true);
319 cfg &= ~RPMX_CMR_RX_OVR_BP_EN(lmac_id);
320 } else {
321 /* Disable all Pause Quanta & threshold values */
322 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xffff, false);
323 cfg |= RPMX_CMR_RX_OVR_BP_EN(lmac_id);
324 cfg &= ~RPMX_CMR_RX_OVR_BP_BP(lmac_id);
325 }
326 rpm_write(rpm, 0, RPMX_CMR_RX_OVR_BP, cfg);
327 }
328
rpm_lmac_enadis_pause_frm(void * rpmd,int lmac_id,u8 tx_pause,u8 rx_pause)329 int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause,
330 u8 rx_pause)
331 {
332 rpm_t *rpm = rpmd;
333 u64 cfg;
334
335 if (!is_lmac_valid(rpm, lmac_id))
336 return -ENODEV;
337
338 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
339 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
340 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
341 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
342 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
343 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
344
345 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
346 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
347 cfg |= tx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
348 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
349
350 if (is_dev_rpm2(rpm))
351 rpm2_lmac_cfg_bp(rpm, lmac_id, tx_pause, rx_pause);
352 else
353 rpm_lmac_cfg_bp(rpm, lmac_id, tx_pause, rx_pause);
354
355 return 0;
356 }
357
rpm_lmac_pause_frm_config(void * rpmd,int lmac_id,bool enable)358 void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable)
359 {
360 u64 cfg, pfc_class_mask_cfg;
361 rpm_t *rpm = rpmd;
362
363 /* ALL pause frames received are completely ignored */
364 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
365 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE;
366 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
367
368 /* Disable forward pause to TX block */
369 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
370 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE;
371 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
372
373 /* Disable pause frames transmission */
374 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
375 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
376 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
377
378 /* Disable forward pause to driver */
379 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
380 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_FWD;
381 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
382
383 /* Enable channel mask for all LMACS */
384 if (is_dev_rpm2(rpm))
385 rpm_write(rpm, lmac_id, RPM2_CMR_CHAN_MSK_OR, 0xffff);
386 else
387 rpm_write(rpm, 0, RPMX_CMR_CHAN_MSK_OR, ~0ULL);
388
389 /* Disable all PFC classes */
390 pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL :
391 RPMX_CMRX_PRT_CBFC_CTL;
392 cfg = rpm_read(rpm, lmac_id, pfc_class_mask_cfg);
393 cfg = FIELD_SET(RPM_PFC_CLASS_MASK, 0, cfg);
394 rpm_write(rpm, lmac_id, pfc_class_mask_cfg, cfg);
395 }
396
rpm_get_rx_stats(void * rpmd,int lmac_id,int idx,u64 * rx_stat)397 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat)
398 {
399 rpm_t *rpm = rpmd;
400 u64 val_lo, val_hi;
401
402 if (!is_lmac_valid(rpm, lmac_id))
403 return -ENODEV;
404
405 mutex_lock(&rpm->lock);
406
407 /* Update idx to point per lmac Rx statistics page */
408 idx += lmac_id * rpm->mac_ops->rx_stats_cnt;
409
410 /* Read lower 32 bits of counter */
411 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_RX_STAT_PAGES_COUNTERX +
412 (idx * 8));
413
414 /* upon read of lower 32 bits, higher 32 bits are written
415 * to RPMX_MTI_STAT_DATA_HI_CDC
416 */
417 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
418
419 *rx_stat = (val_hi << 32 | val_lo);
420
421 mutex_unlock(&rpm->lock);
422 return 0;
423 }
424
rpm_get_tx_stats(void * rpmd,int lmac_id,int idx,u64 * tx_stat)425 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat)
426 {
427 rpm_t *rpm = rpmd;
428 u64 val_lo, val_hi;
429
430 if (!is_lmac_valid(rpm, lmac_id))
431 return -ENODEV;
432
433 mutex_lock(&rpm->lock);
434
435 /* Update idx to point per lmac Tx statistics page */
436 idx += lmac_id * rpm->mac_ops->tx_stats_cnt;
437
438 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_TX_STAT_PAGES_COUNTERX +
439 (idx * 8));
440 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
441
442 *tx_stat = (val_hi << 32 | val_lo);
443
444 mutex_unlock(&rpm->lock);
445 return 0;
446 }
447
rpm_stats_reset(void * rpmd,int lmac_id)448 int rpm_stats_reset(void *rpmd, int lmac_id)
449 {
450 rpm_t *rpm = rpmd;
451 u64 cfg;
452
453 if (!is_lmac_valid(rpm, lmac_id))
454 return -ENODEV;
455
456 cfg = rpm_read(rpm, 0, RPMX_MTI_STAT_STATN_CONTROL);
457 cfg |= RPMX_CMD_CLEAR_TX | RPMX_CMD_CLEAR_RX | BIT_ULL(lmac_id);
458 rpm_write(rpm, 0, RPMX_MTI_STAT_STATN_CONTROL, cfg);
459
460 return 0;
461 }
462
rpm_get_lmac_type(void * rpmd,int lmac_id)463 u8 rpm_get_lmac_type(void *rpmd, int lmac_id)
464 {
465 rpm_t *rpm = rpmd;
466 u64 req = 0, resp;
467 int err;
468
469 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_LINK_STS, req);
470 err = cgx_fwi_cmd_generic(req, &resp, rpm, 0);
471 if (!err)
472 return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp);
473 return err;
474 }
475
rpm_get_lmac_fifo_len(void * rpmd,int lmac_id)476 u32 rpm_get_lmac_fifo_len(void *rpmd, int lmac_id)
477 {
478 rpm_t *rpm = rpmd;
479 u64 hi_perf_lmac;
480 u8 num_lmacs;
481 u32 fifo_len;
482
483 fifo_len = rpm->mac_ops->fifo_len;
484 num_lmacs = rpm->mac_ops->get_nr_lmacs(rpm);
485
486 switch (num_lmacs) {
487 case 1:
488 return fifo_len;
489 case 2:
490 return fifo_len / 2;
491 case 3:
492 /* LMAC marked as hi_perf gets half of the FIFO and rest 1/4th */
493 hi_perf_lmac = rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS);
494 hi_perf_lmac = (hi_perf_lmac >> 4) & 0x3ULL;
495 if (lmac_id == hi_perf_lmac)
496 return fifo_len / 2;
497 return fifo_len / 4;
498 case 4:
499 default:
500 return fifo_len / 4;
501 }
502 return 0;
503 }
504
rpmusx_lmac_internal_loopback(rpm_t * rpm,int lmac_id,bool enable)505 static int rpmusx_lmac_internal_loopback(rpm_t *rpm, int lmac_id, bool enable)
506 {
507 u64 cfg;
508
509 cfg = rpm_read(rpm, lmac_id, RPM2_USX_PCSX_CONTROL1);
510
511 if (enable)
512 cfg |= RPM2_USX_PCS_LBK;
513 else
514 cfg &= ~RPM2_USX_PCS_LBK;
515 rpm_write(rpm, lmac_id, RPM2_USX_PCSX_CONTROL1, cfg);
516
517 return 0;
518 }
519
rpm2_get_lmac_fifo_len(void * rpmd,int lmac_id)520 u32 rpm2_get_lmac_fifo_len(void *rpmd, int lmac_id)
521 {
522 u64 hi_perf_lmac, lmac_info;
523 rpm_t *rpm = rpmd;
524 u8 num_lmacs;
525 u32 fifo_len;
526 u16 max_lmac;
527
528 lmac_info = rpm_read(rpm, 0, RPM2_CMRX_RX_LMACS);
529 /* LMACs are divided into two groups and each group
530 * gets half of the FIFO
531 * Group0 lmac_id range {0..3}
532 * Group1 lmac_id range {4..7}
533 */
534 max_lmac = (rpm_read(rpm, 0, CGX_CONST) >> 24) & 0xFF;
535 if (max_lmac > 4)
536 fifo_len = rpm->mac_ops->fifo_len / 2;
537 else
538 fifo_len = rpm->mac_ops->fifo_len;
539
540 if (lmac_id < 4) {
541 num_lmacs = hweight8(lmac_info & 0xF);
542 hi_perf_lmac = (lmac_info >> 8) & 0x3ULL;
543 } else {
544 num_lmacs = hweight8(lmac_info & 0xF0);
545 hi_perf_lmac = (lmac_info >> 10) & 0x3ULL;
546 hi_perf_lmac += 4;
547 }
548
549 switch (num_lmacs) {
550 case 1:
551 return fifo_len;
552 case 2:
553 return fifo_len / 2;
554 case 3:
555 /* LMAC marked as hi_perf gets half of the FIFO
556 * and rest 1/4th
557 */
558 if (lmac_id == hi_perf_lmac)
559 return fifo_len / 2;
560 return fifo_len / 4;
561 case 4:
562 default:
563 return fifo_len / 4;
564 }
565 return 0;
566 }
567
rpm_lmac_internal_loopback(void * rpmd,int lmac_id,bool enable)568 int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable)
569 {
570 rpm_t *rpm = rpmd;
571 struct lmac *lmac;
572 u64 cfg;
573
574 if (!is_lmac_valid(rpm, lmac_id))
575 return -ENODEV;
576
577 lmac = lmac_pdata(lmac_id, rpm);
578 if (lmac->lmac_type == LMAC_MODE_QSGMII ||
579 lmac->lmac_type == LMAC_MODE_SGMII) {
580 dev_err(&rpm->pdev->dev, "loopback not supported for LPC mode\n");
581 return 0;
582 }
583
584 if (is_dev_rpm2(rpm) && is_mac_rpmusx(rpm))
585 return rpmusx_lmac_internal_loopback(rpm, lmac_id, enable);
586
587 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1);
588
589 if (enable)
590 cfg |= RPMX_MTI_PCS_LBK;
591 else
592 cfg &= ~RPMX_MTI_PCS_LBK;
593 rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg);
594
595 return 0;
596 }
597
rpm_lmac_ptp_config(void * rpmd,int lmac_id,bool enable)598 void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable)
599 {
600 rpm_t *rpm = rpmd;
601 u64 cfg;
602
603 if (!is_lmac_valid(rpm, lmac_id))
604 return;
605
606 cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_CFG);
607 if (enable) {
608 cfg |= RPMX_RX_TS_PREPEND;
609 cfg |= RPMX_TX_PTP_1S_SUPPORT;
610 } else {
611 cfg &= ~RPMX_RX_TS_PREPEND;
612 cfg &= ~RPMX_TX_PTP_1S_SUPPORT;
613 }
614
615 rpm_write(rpm, lmac_id, RPMX_CMRX_CFG, cfg);
616
617 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_XIF_MODE);
618
619 if (enable) {
620 cfg |= RPMX_ONESTEP_ENABLE;
621 cfg &= ~RPMX_TS_BINARY_MODE;
622 } else {
623 cfg &= ~RPMX_ONESTEP_ENABLE;
624 }
625
626 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_XIF_MODE, cfg);
627 }
628
rpm_lmac_pfc_config(void * rpmd,int lmac_id,u8 tx_pause,u8 rx_pause,u16 pfc_en)629 int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 pfc_en)
630 {
631 u64 cfg, class_en, pfc_class_mask_cfg;
632 rpm_t *rpm = rpmd;
633
634 if (!is_lmac_valid(rpm, lmac_id))
635 return -ENODEV;
636
637 pfc_class_mask_cfg = is_dev_rpm2(rpm) ? RPM2_CMRX_PRT_CBFC_CTL :
638 RPMX_CMRX_PRT_CBFC_CTL;
639
640 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
641 class_en = rpm_read(rpm, lmac_id, pfc_class_mask_cfg);
642 pfc_en |= FIELD_GET(RPM_PFC_CLASS_MASK, class_en);
643
644 if (rx_pause) {
645 cfg &= ~(RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE |
646 RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE);
647 } else {
648 cfg |= (RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE |
649 RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE);
650 }
651
652 if (tx_pause) {
653 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, pfc_en, true);
654 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
655 class_en = FIELD_SET(RPM_PFC_CLASS_MASK, pfc_en, class_en);
656 } else {
657 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xfff, false);
658 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE;
659 class_en = FIELD_SET(RPM_PFC_CLASS_MASK, 0, class_en);
660 }
661
662 if (!rx_pause && !tx_pause)
663 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE;
664 else
665 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE;
666
667 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg);
668 rpm_write(rpm, lmac_id, pfc_class_mask_cfg, class_en);
669
670 return 0;
671 }
672
rpm_lmac_get_pfc_frm_cfg(void * rpmd,int lmac_id,u8 * tx_pause,u8 * rx_pause)673 int rpm_lmac_get_pfc_frm_cfg(void *rpmd, int lmac_id, u8 *tx_pause, u8 *rx_pause)
674 {
675 rpm_t *rpm = rpmd;
676 u64 cfg;
677
678 if (!is_lmac_valid(rpm, lmac_id))
679 return -ENODEV;
680
681 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG);
682 if (cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE) {
683 *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE);
684 *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE);
685 }
686
687 return 0;
688 }
689
rpm_get_fec_stats(void * rpmd,int lmac_id,struct cgx_fec_stats_rsp * rsp)690 int rpm_get_fec_stats(void *rpmd, int lmac_id, struct cgx_fec_stats_rsp *rsp)
691 {
692 u64 val_lo, val_hi;
693 rpm_t *rpm = rpmd;
694 u64 cfg;
695
696 if (!is_lmac_valid(rpm, lmac_id))
697 return -ENODEV;
698
699 if (rpm->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_NONE)
700 return 0;
701
702 if (rpm->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_BASER) {
703 val_lo = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_VL0_CCW_LO);
704 val_hi = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_CW_HI);
705 rsp->fec_corr_blks = (val_hi << 16 | val_lo);
706
707 val_lo = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_VL0_NCCW_LO);
708 val_hi = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_CW_HI);
709 rsp->fec_uncorr_blks = (val_hi << 16 | val_lo);
710
711 /* 50G uses 2 Physical serdes lines */
712 if (rpm->lmac_idmap[lmac_id]->link_info.lmac_type_id ==
713 LMAC_MODE_50G_R) {
714 val_lo = rpm_read(rpm, lmac_id,
715 RPMX_MTI_FCFECX_VL1_CCW_LO);
716 val_hi = rpm_read(rpm, lmac_id,
717 RPMX_MTI_FCFECX_CW_HI);
718 rsp->fec_corr_blks += (val_hi << 16 | val_lo);
719
720 val_lo = rpm_read(rpm, lmac_id,
721 RPMX_MTI_FCFECX_VL1_NCCW_LO);
722 val_hi = rpm_read(rpm, lmac_id,
723 RPMX_MTI_FCFECX_CW_HI);
724 rsp->fec_uncorr_blks += (val_hi << 16 | val_lo);
725 }
726 } else {
727 /* enable RS-FEC capture */
728 cfg = rpm_read(rpm, 0, RPMX_MTI_STAT_STATN_CONTROL);
729 cfg |= RPMX_RSFEC_RX_CAPTURE | BIT(lmac_id);
730 rpm_write(rpm, 0, RPMX_MTI_STAT_STATN_CONTROL, cfg);
731
732 val_lo = rpm_read(rpm, 0,
733 RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_2);
734 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
735 rsp->fec_corr_blks = (val_hi << 32 | val_lo);
736
737 val_lo = rpm_read(rpm, 0,
738 RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_3);
739 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC);
740 rsp->fec_uncorr_blks = (val_hi << 32 | val_lo);
741 }
742
743 return 0;
744 }
745
rpm_lmac_reset(void * rpmd,int lmac_id,u8 pf_req_flr)746 int rpm_lmac_reset(void *rpmd, int lmac_id, u8 pf_req_flr)
747 {
748 u64 rx_logl_xon, cfg;
749 rpm_t *rpm = rpmd;
750
751 if (!is_lmac_valid(rpm, lmac_id))
752 return -ENODEV;
753
754 /* Resetting PFC related CSRs */
755 rx_logl_xon = is_dev_rpm2(rpm) ? RPM2_CMRX_RX_LOGL_XON :
756 RPMX_CMRX_RX_LOGL_XON;
757 cfg = 0xff;
758
759 rpm_write(rpm, lmac_id, rx_logl_xon, cfg);
760
761 if (pf_req_flr)
762 rpm_lmac_internal_loopback(rpm, lmac_id, false);
763
764 return 0;
765 }
766