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 .get_nr_lmacs = rpm_get_nr_lmacs, 24 .get_lmac_type = rpm_get_lmac_type, 25 .lmac_fifo_len = rpm_get_lmac_fifo_len, 26 .mac_lmac_intl_lbk = rpm_lmac_internal_loopback, 27 .mac_get_rx_stats = rpm_get_rx_stats, 28 .mac_get_tx_stats = rpm_get_tx_stats, 29 .mac_enadis_rx_pause_fwding = rpm_lmac_enadis_rx_pause_fwding, 30 .mac_get_pause_frm_status = rpm_lmac_get_pause_frm_status, 31 .mac_enadis_pause_frm = rpm_lmac_enadis_pause_frm, 32 .mac_pause_frm_config = rpm_lmac_pause_frm_config, 33 .mac_enadis_ptp_config = rpm_lmac_ptp_config, 34 .mac_rx_tx_enable = rpm_lmac_rx_tx_enable, 35 .mac_tx_enable = rpm_lmac_tx_enable, 36 .pfc_config = rpm_lmac_pfc_config, 37 .mac_get_pfc_frm_cfg = rpm_lmac_get_pfc_frm_cfg, 38 }; 39 40 struct mac_ops *rpm_get_mac_ops(void) 41 { 42 return &rpm_mac_ops; 43 } 44 45 static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val) 46 { 47 cgx_write(rpm, lmac, offset, val); 48 } 49 50 static u64 rpm_read(rpm_t *rpm, u64 lmac, u64 offset) 51 { 52 return cgx_read(rpm, lmac, offset); 53 } 54 55 int rpm_get_nr_lmacs(void *rpmd) 56 { 57 rpm_t *rpm = rpmd; 58 59 return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL); 60 } 61 62 int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable) 63 { 64 rpm_t *rpm = rpmd; 65 u64 cfg, last; 66 67 if (!is_lmac_valid(rpm, lmac_id)) 68 return -ENODEV; 69 70 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 71 last = cfg; 72 if (enable) 73 cfg |= RPM_TX_EN; 74 else 75 cfg &= ~(RPM_TX_EN); 76 77 if (cfg != last) 78 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 79 return !!(last & RPM_TX_EN); 80 } 81 82 int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable) 83 { 84 rpm_t *rpm = rpmd; 85 u64 cfg; 86 87 if (!is_lmac_valid(rpm, lmac_id)) 88 return -ENODEV; 89 90 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 91 if (enable) 92 cfg |= RPM_RX_EN | RPM_TX_EN; 93 else 94 cfg &= ~(RPM_RX_EN | RPM_TX_EN); 95 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 96 return 0; 97 } 98 99 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable) 100 { 101 rpm_t *rpm = rpmd; 102 struct lmac *lmac; 103 u64 cfg; 104 105 if (!rpm) 106 return; 107 108 lmac = lmac_pdata(lmac_id, rpm); 109 if (!lmac) 110 return; 111 112 /* Pause frames are not enabled just return */ 113 if (!bitmap_weight(lmac->rx_fc_pfvf_bmap.bmap, lmac->rx_fc_pfvf_bmap.max)) 114 return; 115 116 if (enable) { 117 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 118 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 119 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 120 } else { 121 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 122 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 123 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 124 } 125 } 126 127 int rpm_lmac_get_pause_frm_status(void *rpmd, int lmac_id, 128 u8 *tx_pause, u8 *rx_pause) 129 { 130 rpm_t *rpm = rpmd; 131 u64 cfg; 132 133 if (!is_lmac_valid(rpm, lmac_id)) 134 return -ENODEV; 135 136 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 137 if (!(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE)) { 138 *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE); 139 *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE); 140 } 141 142 return 0; 143 } 144 145 static void rpm_cfg_pfc_quanta_thresh(rpm_t *rpm, int lmac_id, 146 unsigned long pfc_en, 147 bool enable) 148 { 149 u64 quanta_offset = 0, quanta_thresh = 0, cfg; 150 int i, shift; 151 152 /* Set pause time and interval */ 153 for_each_set_bit(i, &pfc_en, 16) { 154 switch (i) { 155 case 0: 156 case 1: 157 quanta_offset = RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA; 158 quanta_thresh = RPMX_MTI_MAC100X_CL01_QUANTA_THRESH; 159 break; 160 case 2: 161 case 3: 162 quanta_offset = RPMX_MTI_MAC100X_CL23_PAUSE_QUANTA; 163 quanta_thresh = RPMX_MTI_MAC100X_CL23_QUANTA_THRESH; 164 break; 165 case 4: 166 case 5: 167 quanta_offset = RPMX_MTI_MAC100X_CL45_PAUSE_QUANTA; 168 quanta_thresh = RPMX_MTI_MAC100X_CL45_QUANTA_THRESH; 169 break; 170 case 6: 171 case 7: 172 quanta_offset = RPMX_MTI_MAC100X_CL67_PAUSE_QUANTA; 173 quanta_thresh = RPMX_MTI_MAC100X_CL67_QUANTA_THRESH; 174 break; 175 case 8: 176 case 9: 177 quanta_offset = RPMX_MTI_MAC100X_CL89_PAUSE_QUANTA; 178 quanta_thresh = RPMX_MTI_MAC100X_CL89_QUANTA_THRESH; 179 break; 180 case 10: 181 case 11: 182 quanta_offset = RPMX_MTI_MAC100X_CL1011_PAUSE_QUANTA; 183 quanta_thresh = RPMX_MTI_MAC100X_CL1011_QUANTA_THRESH; 184 break; 185 case 12: 186 case 13: 187 quanta_offset = RPMX_MTI_MAC100X_CL1213_PAUSE_QUANTA; 188 quanta_thresh = RPMX_MTI_MAC100X_CL1213_QUANTA_THRESH; 189 break; 190 case 14: 191 case 15: 192 quanta_offset = RPMX_MTI_MAC100X_CL1415_PAUSE_QUANTA; 193 quanta_thresh = RPMX_MTI_MAC100X_CL1415_QUANTA_THRESH; 194 break; 195 } 196 197 if (!quanta_offset || !quanta_thresh) 198 continue; 199 200 shift = (i % 2) ? 1 : 0; 201 cfg = rpm_read(rpm, lmac_id, quanta_offset); 202 if (enable) { 203 cfg |= ((u64)RPM_DEFAULT_PAUSE_TIME << shift * 16); 204 } else { 205 if (!shift) 206 cfg &= ~GENMASK_ULL(15, 0); 207 else 208 cfg &= ~GENMASK_ULL(31, 16); 209 } 210 rpm_write(rpm, lmac_id, quanta_offset, cfg); 211 212 cfg = rpm_read(rpm, lmac_id, quanta_thresh); 213 if (enable) { 214 cfg |= ((u64)(RPM_DEFAULT_PAUSE_TIME / 2) << shift * 16); 215 } else { 216 if (!shift) 217 cfg &= ~GENMASK_ULL(15, 0); 218 else 219 cfg &= ~GENMASK_ULL(31, 16); 220 } 221 rpm_write(rpm, lmac_id, quanta_thresh, cfg); 222 } 223 } 224 225 int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause, 226 u8 rx_pause) 227 { 228 rpm_t *rpm = rpmd; 229 u64 cfg; 230 231 if (!is_lmac_valid(rpm, lmac_id)) 232 return -ENODEV; 233 234 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 235 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 236 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 237 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 238 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 239 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 240 241 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 242 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 243 cfg |= tx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 244 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 245 246 cfg = rpm_read(rpm, 0, RPMX_CMR_RX_OVR_BP); 247 if (tx_pause) { 248 /* Configure CL0 Pause Quanta & threshold for 802.3X frames */ 249 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 1, true); 250 cfg &= ~RPMX_CMR_RX_OVR_BP_EN(lmac_id); 251 } else { 252 /* Disable all Pause Quanta & threshold values */ 253 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xffff, false); 254 cfg |= RPMX_CMR_RX_OVR_BP_EN(lmac_id); 255 cfg &= ~RPMX_CMR_RX_OVR_BP_BP(lmac_id); 256 } 257 rpm_write(rpm, 0, RPMX_CMR_RX_OVR_BP, cfg); 258 return 0; 259 } 260 261 void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable) 262 { 263 rpm_t *rpm = rpmd; 264 u64 cfg; 265 266 /* ALL pause frames received are completely ignored */ 267 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 268 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 269 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 270 271 /* Disable forward pause to TX block */ 272 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 273 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 274 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 275 276 /* Disable pause frames transmission */ 277 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 278 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 279 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 280 281 /* Disable all PFC classes */ 282 cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL); 283 cfg = FIELD_SET(RPM_PFC_CLASS_MASK, 0, cfg); 284 rpm_write(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL, cfg); 285 286 /* Enable channel mask for all LMACS */ 287 rpm_write(rpm, 0, RPMX_CMR_CHAN_MSK_OR, ~0ULL); 288 } 289 290 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat) 291 { 292 rpm_t *rpm = rpmd; 293 u64 val_lo, val_hi; 294 295 if (!rpm || lmac_id >= rpm->lmac_count) 296 return -ENODEV; 297 298 mutex_lock(&rpm->lock); 299 300 /* Update idx to point per lmac Rx statistics page */ 301 idx += lmac_id * rpm->mac_ops->rx_stats_cnt; 302 303 /* Read lower 32 bits of counter */ 304 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_RX_STAT_PAGES_COUNTERX + 305 (idx * 8)); 306 307 /* upon read of lower 32 bits, higher 32 bits are written 308 * to RPMX_MTI_STAT_DATA_HI_CDC 309 */ 310 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); 311 312 *rx_stat = (val_hi << 32 | val_lo); 313 314 mutex_unlock(&rpm->lock); 315 return 0; 316 } 317 318 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat) 319 { 320 rpm_t *rpm = rpmd; 321 u64 val_lo, val_hi; 322 323 if (!rpm || lmac_id >= rpm->lmac_count) 324 return -ENODEV; 325 326 mutex_lock(&rpm->lock); 327 328 /* Update idx to point per lmac Tx statistics page */ 329 idx += lmac_id * rpm->mac_ops->tx_stats_cnt; 330 331 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_TX_STAT_PAGES_COUNTERX + 332 (idx * 8)); 333 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); 334 335 *tx_stat = (val_hi << 32 | val_lo); 336 337 mutex_unlock(&rpm->lock); 338 return 0; 339 } 340 341 u8 rpm_get_lmac_type(void *rpmd, int lmac_id) 342 { 343 rpm_t *rpm = rpmd; 344 u64 req = 0, resp; 345 int err; 346 347 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_LINK_STS, req); 348 err = cgx_fwi_cmd_generic(req, &resp, rpm, 0); 349 if (!err) 350 return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp); 351 return err; 352 } 353 354 u32 rpm_get_lmac_fifo_len(void *rpmd, int lmac_id) 355 { 356 rpm_t *rpm = rpmd; 357 u64 hi_perf_lmac; 358 u8 num_lmacs; 359 u32 fifo_len; 360 361 fifo_len = rpm->mac_ops->fifo_len; 362 num_lmacs = rpm->mac_ops->get_nr_lmacs(rpm); 363 364 switch (num_lmacs) { 365 case 1: 366 return fifo_len; 367 case 2: 368 return fifo_len / 2; 369 case 3: 370 /* LMAC marked as hi_perf gets half of the FIFO and rest 1/4th */ 371 hi_perf_lmac = rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS); 372 hi_perf_lmac = (hi_perf_lmac >> 4) & 0x3ULL; 373 if (lmac_id == hi_perf_lmac) 374 return fifo_len / 2; 375 return fifo_len / 4; 376 case 4: 377 default: 378 return fifo_len / 4; 379 } 380 return 0; 381 } 382 383 int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable) 384 { 385 rpm_t *rpm = rpmd; 386 u8 lmac_type; 387 u64 cfg; 388 389 if (!rpm || lmac_id >= rpm->lmac_count) 390 return -ENODEV; 391 lmac_type = rpm->mac_ops->get_lmac_type(rpm, lmac_id); 392 393 if (lmac_type == LMAC_MODE_QSGMII || lmac_type == LMAC_MODE_SGMII) { 394 dev_err(&rpm->pdev->dev, "loopback not supported for LPC mode\n"); 395 return 0; 396 } 397 398 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1); 399 400 if (enable) 401 cfg |= RPMX_MTI_PCS_LBK; 402 else 403 cfg &= ~RPMX_MTI_PCS_LBK; 404 rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg); 405 406 return 0; 407 } 408 409 void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable) 410 { 411 rpm_t *rpm = rpmd; 412 u64 cfg; 413 414 if (!is_lmac_valid(rpm, lmac_id)) 415 return; 416 417 cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_CFG); 418 if (enable) 419 cfg |= RPMX_RX_TS_PREPEND; 420 else 421 cfg &= ~RPMX_RX_TS_PREPEND; 422 rpm_write(rpm, lmac_id, RPMX_CMRX_CFG, cfg); 423 } 424 425 int rpm_lmac_pfc_config(void *rpmd, int lmac_id, u8 tx_pause, u8 rx_pause, u16 pfc_en) 426 { 427 rpm_t *rpm = rpmd; 428 u64 cfg, class_en; 429 430 if (!is_lmac_valid(rpm, lmac_id)) 431 return -ENODEV; 432 433 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 434 class_en = rpm_read(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL); 435 pfc_en |= FIELD_GET(RPM_PFC_CLASS_MASK, class_en); 436 437 if (rx_pause) { 438 cfg &= ~(RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE | 439 RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE | 440 RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_FWD); 441 } else { 442 cfg |= (RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE | 443 RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE | 444 RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_FWD); 445 } 446 447 if (tx_pause) { 448 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, pfc_en, true); 449 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 450 class_en = FIELD_SET(RPM_PFC_CLASS_MASK, pfc_en, class_en); 451 } else { 452 rpm_cfg_pfc_quanta_thresh(rpm, lmac_id, 0xfff, false); 453 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 454 class_en = FIELD_SET(RPM_PFC_CLASS_MASK, 0, class_en); 455 } 456 457 if (!rx_pause && !tx_pause) 458 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE; 459 else 460 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE; 461 462 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 463 464 rpm_write(rpm, lmac_id, RPMX_CMRX_PRT_CBFC_CTL, class_en); 465 466 return 0; 467 } 468 469 int rpm_lmac_get_pfc_frm_cfg(void *rpmd, int lmac_id, u8 *tx_pause, u8 *rx_pause) 470 { 471 rpm_t *rpm = rpmd; 472 u64 cfg; 473 474 if (!is_lmac_valid(rpm, lmac_id)) 475 return -ENODEV; 476 477 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 478 if (cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE) { 479 *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE); 480 *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE); 481 } 482 483 return 0; 484 } 485