File Index
Files and directories
Sign in
FILE

rpm.c

File preview with syntax highlighting.

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