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