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 | }; |
42 | |
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), |
51 | .lmac_fwi = RPM2_LMAC_FWI, |
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, |
62 | .get_fec_stats = rpm_get_fec_stats, |
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, |
72 | .mac_reset = rpm_lmac_reset, |
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) |
83 | { |
84 | if (is_dev_rpm2(rpmd: rpm)) |
85 | return &rpm2_mac_ops; |
86 | else |
87 | return &rpm_mac_ops; |
88 | } |
89 | |
90 | static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val) |
91 | { |
92 | cgx_write(cgx: rpm, lmac, offset, val); |
93 | } |
94 | |
95 | static u64 rpm_read(rpm_t *rpm, u64 lmac, u64 offset) |
96 | { |
97 | return cgx_read(cgx: rpm, lmac, offset); |
98 | } |
99 | |
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, lmac: 0, RPMX_CONST1) & 0x700ULL; |
108 | } |
109 | |
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 | } |
116 | |
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 | |
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(cgx: rpm, lmac_id)) |
130 | return -ENODEV; |
131 | |
132 | cfg = rpm_read(rpm, lmac: 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: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: 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(cgx: rpm, lmac_id)) |
150 | return -ENODEV; |
151 | |
152 | cfg = rpm_read(rpm, lmac: 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: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
158 | return 0; |
159 | } |
160 | |
161 | void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable) |
162 | { |
163 | rpm_t *rpm = rpmd; |
164 | struct lmac *lmac; |
165 | u64 cfg; |
166 | |
167 | if (!rpm) |
168 | return; |
169 | |
170 | lmac = lmac_pdata(lmac_id, cgx: rpm); |
171 | if (!lmac) |
172 | return; |
173 | |
174 | /* Pause frames are not enabled just return */ |
175 | if (!bitmap_weight(src: lmac->rx_fc_pfvf_bmap.bmap, nbits: lmac->rx_fc_pfvf_bmap.max)) |
176 | return; |
177 | |
178 | if (enable) { |
179 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
180 | cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; |
181 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
182 | } else { |
183 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
184 | cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; |
185 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: 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(cgx: rpm, lmac_id)) |
196 | return -ENODEV; |
197 | |
198 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
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 | } |
203 | |
204 | return 0; |
205 | } |
206 | |
207 | static void rpm_cfg_pfc_quanta_thresh(rpm_t *rpm, int lmac_id, |
208 | unsigned long pfc_en, |
209 | bool enable) |
210 | { |
211 | u64 quanta_offset = 0, quanta_thresh = 0, cfg; |
212 | int i, shift; |
213 | |
214 | /* Set pause time and interval */ |
215 | for_each_set_bit(i, &pfc_en, 16) { |
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: lmac_id, offset: 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: lmac_id, offset: quanta_offset, val: cfg); |
273 | |
274 | cfg = rpm_read(rpm, lmac: lmac_id, offset: 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: lmac_id, offset: quanta_thresh, val: cfg); |
284 | } |
285 | } |
286 | |
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: 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, pfc_en: 1, enable: 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, pfc_en: 0xffff, enable: false); |
301 | cfg |= RPM2_CMR_RX_OVR_BP_EN; |
302 | cfg &= ~RPM2_CMR_RX_OVR_BP_BP; |
303 | } |
304 | rpm_write(rpm, lmac: lmac_id, RPM2_CMR_RX_OVR_BP, val: 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, lmac: 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, pfc_en: 1, enable: 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, pfc_en: 0xffff, enable: 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, lmac: 0, RPMX_CMR_RX_OVR_BP, val: cfg); |
325 | } |
326 | |
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(cgx: rpm, lmac_id)) |
334 | return -ENODEV; |
335 | |
336 | cfg = rpm_read(rpm, lmac: 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: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
342 | |
343 | cfg = rpm_read(rpm, lmac: 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: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
347 | |
348 | if (is_dev_rpm2(rpmd: 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 | |
353 | return 0; |
354 | } |
355 | |
356 | void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable) |
357 | { |
358 | u64 cfg, pfc_class_mask_cfg; |
359 | rpm_t *rpm = rpmd; |
360 | |
361 | /* ALL pause frames received are completely ignored */ |
362 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
363 | cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; |
364 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
365 | |
366 | /* Disable forward pause to TX block */ |
367 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
368 | cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; |
369 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
370 | |
371 | /* Disable pause frames transmission */ |
372 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
373 | cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; |
374 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
375 | |
376 | /* Disable forward pause to driver */ |
377 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
378 | cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_FWD; |
379 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
380 | |
381 | /* Enable channel mask for all LMACS */ |
382 | if (is_dev_rpm2(rpmd: rpm)) |
383 | rpm_write(rpm, lmac: lmac_id, RPM2_CMR_CHAN_MSK_OR, val: 0xffff); |
384 | else |
385 | rpm_write(rpm, lmac: 0, RPMX_CMR_CHAN_MSK_OR, val: ~0ULL); |
386 | |
387 | /* Disable all PFC classes */ |
388 | pfc_class_mask_cfg = is_dev_rpm2(rpmd: rpm) ? RPM2_CMRX_PRT_CBFC_CTL : |
389 | RPMX_CMRX_PRT_CBFC_CTL; |
390 | cfg = rpm_read(rpm, lmac: lmac_id, offset: pfc_class_mask_cfg); |
391 | cfg = FIELD_SET(RPM_PFC_CLASS_MASK, 0, cfg); |
392 | rpm_write(rpm, lmac: lmac_id, offset: pfc_class_mask_cfg, val: cfg); |
393 | } |
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 | |
400 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
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, lmac: 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, lmac: 0, RPMX_MTI_STAT_DATA_HI_CDC); |
416 | |
417 | *rx_stat = (val_hi << 32 | val_lo); |
418 | |
419 | mutex_unlock(lock: &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 | |
428 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
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, lmac: 0, RPMX_MTI_STAT_TX_STAT_PAGES_COUNTERX + |
437 | (idx * 8)); |
438 | val_hi = rpm_read(rpm, lmac: 0, RPMX_MTI_STAT_DATA_HI_CDC); |
439 | |
440 | *tx_stat = (val_hi << 32 | val_lo); |
441 | |
442 | mutex_unlock(lock: &rpm->lock); |
443 | return 0; |
444 | } |
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: &resp, cgx: rpm, lmac_id: 0); |
454 | if (!err) |
455 | return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp); |
456 | return err; |
457 | } |
458 | |
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, lmac: 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 | |
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: 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: lmac_id, RPM2_USX_PCSX_CONTROL1, val: 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 | u16 max_lmac; |
510 | |
511 | lmac_info = rpm_read(rpm, lmac: 0, RPM2_CMRX_RX_LMACS); |
512 | /* LMACs are divided into two groups and each group |
513 | * gets half of the FIFO |
514 | * Group0 lmac_id range {0..3} |
515 | * Group1 lmac_id range {4..7} |
516 | */ |
517 | max_lmac = (rpm_read(rpm, lmac: 0, CGX_CONST) >> 24) & 0xFF; |
518 | if (max_lmac > 4) |
519 | fifo_len = rpm->mac_ops->fifo_len / 2; |
520 | else |
521 | fifo_len = rpm->mac_ops->fifo_len; |
522 | |
523 | if (lmac_id < 4) { |
524 | num_lmacs = hweight8(lmac_info & 0xF); |
525 | hi_perf_lmac = (lmac_info >> 8) & 0x3ULL; |
526 | } else { |
527 | num_lmacs = hweight8(lmac_info & 0xF0); |
528 | hi_perf_lmac = (lmac_info >> 10) & 0x3ULL; |
529 | hi_perf_lmac += 4; |
530 | } |
531 | |
532 | switch (num_lmacs) { |
533 | case 1: |
534 | return fifo_len; |
535 | case 2: |
536 | return fifo_len / 2; |
537 | case 3: |
538 | /* LMAC marked as hi_perf gets half of the FIFO |
539 | * and rest 1/4th |
540 | */ |
541 | if (lmac_id == hi_perf_lmac) |
542 | return fifo_len / 2; |
543 | return fifo_len / 4; |
544 | case 4: |
545 | default: |
546 | return fifo_len / 4; |
547 | } |
548 | return 0; |
549 | } |
550 | |
551 | int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable) |
552 | { |
553 | rpm_t *rpm = rpmd; |
554 | struct lmac *lmac; |
555 | u64 cfg; |
556 | |
557 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
558 | return -ENODEV; |
559 | |
560 | lmac = lmac_pdata(lmac_id, cgx: rpm); |
561 | if (lmac->lmac_type == LMAC_MODE_QSGMII || |
562 | lmac->lmac_type == LMAC_MODE_SGMII) { |
563 | dev_err(&rpm->pdev->dev, "loopback not supported for LPC mode\n" ); |
564 | return 0; |
565 | } |
566 | |
567 | if (is_dev_rpm2(rpmd: rpm) && is_mac_rpmusx(rpmd: rpm)) |
568 | return rpmusx_lmac_internal_loopback(rpm, lmac_id, enable); |
569 | |
570 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_PCS100X_CONTROL1); |
571 | |
572 | if (enable) |
573 | cfg |= RPMX_MTI_PCS_LBK; |
574 | else |
575 | cfg &= ~RPMX_MTI_PCS_LBK; |
576 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_PCS100X_CONTROL1, val: cfg); |
577 | |
578 | return 0; |
579 | } |
580 | |
581 | void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable) |
582 | { |
583 | rpm_t *rpm = rpmd; |
584 | u64 cfg; |
585 | |
586 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
587 | return; |
588 | |
589 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_CMRX_CFG); |
590 | if (enable) { |
591 | cfg |= RPMX_RX_TS_PREPEND; |
592 | cfg |= RPMX_TX_PTP_1S_SUPPORT; |
593 | } else { |
594 | cfg &= ~RPMX_RX_TS_PREPEND; |
595 | cfg &= ~RPMX_TX_PTP_1S_SUPPORT; |
596 | } |
597 | |
598 | rpm_write(rpm, lmac: lmac_id, RPMX_CMRX_CFG, val: cfg); |
599 | |
600 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_XIF_MODE); |
601 | |
602 | if (enable) { |
603 | cfg |= RPMX_ONESTEP_ENABLE; |
604 | cfg &= ~RPMX_TS_BINARY_MODE; |
605 | } else { |
606 | cfg &= ~RPMX_ONESTEP_ENABLE; |
607 | } |
608 | |
609 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_XIF_MODE, val: cfg); |
610 | } |
611 | |
612 | int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 pfc_en) |
613 | { |
614 | u64 cfg, class_en, pfc_class_mask_cfg; |
615 | rpm_t *rpm = rpmd; |
616 | |
617 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
618 | return -ENODEV; |
619 | |
620 | pfc_class_mask_cfg = is_dev_rpm2(rpmd: rpm) ? RPM2_CMRX_PRT_CBFC_CTL : |
621 | RPMX_CMRX_PRT_CBFC_CTL; |
622 | |
623 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
624 | class_en = rpm_read(rpm, lmac: lmac_id, offset: pfc_class_mask_cfg); |
625 | pfc_en |= FIELD_GET(RPM_PFC_CLASS_MASK, class_en); |
626 | |
627 | if (rx_pause) { |
628 | cfg &= ~(RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE | |
629 | RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE); |
630 | } else { |
631 | cfg |= (RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE | |
632 | RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE); |
633 | } |
634 | |
635 | if (tx_pause) { |
636 | rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, pfc_en, enable: true); |
637 | cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; |
638 | class_en = FIELD_SET(RPM_PFC_CLASS_MASK, pfc_en, class_en); |
639 | } else { |
640 | rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, pfc_en: 0xfff, enable: false); |
641 | cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; |
642 | class_en = FIELD_SET(RPM_PFC_CLASS_MASK, 0, class_en); |
643 | } |
644 | |
645 | if (!rx_pause && !tx_pause) |
646 | cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE; |
647 | else |
648 | cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE; |
649 | |
650 | rpm_write(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, val: cfg); |
651 | rpm_write(rpm, lmac: lmac_id, offset: pfc_class_mask_cfg, val: class_en); |
652 | |
653 | return 0; |
654 | } |
655 | |
656 | int rpm_lmac_get_pfc_frm_cfg(void *rpmd, int lmac_id, u8 *tx_pause, u8 *rx_pause) |
657 | { |
658 | rpm_t *rpm = rpmd; |
659 | u64 cfg; |
660 | |
661 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
662 | return -ENODEV; |
663 | |
664 | cfg = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); |
665 | if (cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE) { |
666 | *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE); |
667 | *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE); |
668 | } |
669 | |
670 | return 0; |
671 | } |
672 | |
673 | int rpm_get_fec_stats(void *rpmd, int lmac_id, struct cgx_fec_stats_rsp *rsp) |
674 | { |
675 | u64 val_lo, val_hi; |
676 | rpm_t *rpm = rpmd; |
677 | u64 cfg; |
678 | |
679 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
680 | return -ENODEV; |
681 | |
682 | if (rpm->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_NONE) |
683 | return 0; |
684 | |
685 | if (rpm->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_BASER) { |
686 | val_lo = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_FCFECX_VL0_CCW_LO); |
687 | val_hi = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_FCFECX_CW_HI); |
688 | rsp->fec_corr_blks = (val_hi << 16 | val_lo); |
689 | |
690 | val_lo = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_FCFECX_VL0_NCCW_LO); |
691 | val_hi = rpm_read(rpm, lmac: lmac_id, RPMX_MTI_FCFECX_CW_HI); |
692 | rsp->fec_uncorr_blks = (val_hi << 16 | val_lo); |
693 | |
694 | /* 50G uses 2 Physical serdes lines */ |
695 | if (rpm->lmac_idmap[lmac_id]->link_info.lmac_type_id == |
696 | LMAC_MODE_50G_R) { |
697 | val_lo = rpm_read(rpm, lmac: lmac_id, |
698 | RPMX_MTI_FCFECX_VL1_CCW_LO); |
699 | val_hi = rpm_read(rpm, lmac: lmac_id, |
700 | RPMX_MTI_FCFECX_CW_HI); |
701 | rsp->fec_corr_blks += (val_hi << 16 | val_lo); |
702 | |
703 | val_lo = rpm_read(rpm, lmac: lmac_id, |
704 | RPMX_MTI_FCFECX_VL1_NCCW_LO); |
705 | val_hi = rpm_read(rpm, lmac: lmac_id, |
706 | RPMX_MTI_FCFECX_CW_HI); |
707 | rsp->fec_uncorr_blks += (val_hi << 16 | val_lo); |
708 | } |
709 | } else { |
710 | /* enable RS-FEC capture */ |
711 | cfg = rpm_read(rpm, lmac: 0, RPMX_MTI_STAT_STATN_CONTROL); |
712 | cfg |= RPMX_RSFEC_RX_CAPTURE | BIT(lmac_id); |
713 | rpm_write(rpm, lmac: 0, RPMX_MTI_STAT_STATN_CONTROL, val: cfg); |
714 | |
715 | val_lo = rpm_read(rpm, lmac: 0, |
716 | RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_2); |
717 | val_hi = rpm_read(rpm, lmac: 0, RPMX_MTI_STAT_DATA_HI_CDC); |
718 | rsp->fec_corr_blks = (val_hi << 32 | val_lo); |
719 | |
720 | val_lo = rpm_read(rpm, lmac: 0, |
721 | RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_3); |
722 | val_hi = rpm_read(rpm, lmac: 0, RPMX_MTI_STAT_DATA_HI_CDC); |
723 | rsp->fec_uncorr_blks = (val_hi << 32 | val_lo); |
724 | } |
725 | |
726 | return 0; |
727 | } |
728 | |
729 | int rpm_lmac_reset(void *rpmd, int lmac_id, u8 pf_req_flr) |
730 | { |
731 | u64 rx_logl_xon, cfg; |
732 | rpm_t *rpm = rpmd; |
733 | |
734 | if (!is_lmac_valid(cgx: rpm, lmac_id)) |
735 | return -ENODEV; |
736 | |
737 | /* Resetting PFC related CSRs */ |
738 | rx_logl_xon = is_dev_rpm2(rpmd: rpm) ? RPM2_CMRX_RX_LOGL_XON : |
739 | RPMX_CMRX_RX_LOGL_XON; |
740 | cfg = 0xff; |
741 | |
742 | rpm_write(rpm, lmac: lmac_id, offset: rx_logl_xon, val: cfg); |
743 | |
744 | if (pf_req_flr) |
745 | rpm_lmac_internal_loopback(rpmd: rpm, lmac_id, enable: false); |
746 | |
747 | return 0; |
748 | } |
749 | |