xref: /linux/drivers/net/ethernet/marvell/octeontx2/af/rpm.c (revision 40ccd6aa3e2e05be93394e3cd560c718dedfcc77)
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 
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 
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 
92 static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val)
93 {
94 	cgx_write(rpm, lmac, offset, val);
95 }
96 
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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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