1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2021 Marvell. 3 */ 4 5 #include <pthread.h> 6 7 #include "roc_api.h" 8 #include "roc_priv.h" 9 10 #define CGX_CMRX_CONFIG 0x00 11 #define CGX_CMRX_CONFIG_DATA_PKT_RX_EN BIT_ULL(54) 12 #define CGX_CMRX_CONFIG_DATA_PKT_TX_EN BIT_ULL(53) 13 #define CGX_CMRX_INT 0x40 14 #define CGX_CMRX_INT_OVERFLW BIT_ULL(1) 15 /* 16 * CN10K stores number of lmacs in 4 bit filed 17 * in contrary to CN9K which uses only 3 bits. 18 * 19 * In theory masks should differ yet on CN9K 20 * bits beyond specified range contain zeros. 21 * 22 * Hence common longer mask may be used. 23 */ 24 #define CGX_CMRX_RX_LMACS 0x128 25 #define CGX_CMRX_RX_LMACS_LMACS GENMASK_ULL(3, 0) 26 #define CGX_CMRX_SCRATCH0 0x1050 27 #define CGX_CMRX_SCRATCH1 0x1058 28 #define CGX_MTI_MAC100X_COMMAND_CONFIG 0x8010 29 #define CGX_MTI_MAC100X_COMMAND_CONFIG_RX_ENA BIT_ULL(1) 30 #define CGX_MTI_MAC100X_COMMAND_CONFIG_TX_ENA BIT_ULL(0) 31 32 static uint64_t 33 roc_bphy_cgx_read(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset) 34 { 35 int shift = roc_model_is_cn10k() ? 20 : 18; 36 uint64_t base = (uint64_t)roc_cgx->bar0_va; 37 38 return plt_read64(base + (lmac << shift) + offset); 39 } 40 41 static void 42 roc_bphy_cgx_write(struct roc_bphy_cgx *roc_cgx, uint64_t lmac, uint64_t offset, 43 uint64_t value) 44 { 45 int shift = roc_model_is_cn10k() ? 20 : 18; 46 uint64_t base = (uint64_t)roc_cgx->bar0_va; 47 48 plt_write64(value, base + (lmac << shift) + offset); 49 } 50 51 static void 52 roc_bphy_cgx_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 53 uint64_t *scr0) 54 { 55 uint64_t val; 56 57 /* clear interrupt */ 58 val = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_INT); 59 val |= FIELD_PREP(CGX_CMRX_INT_OVERFLW, 1); 60 roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_INT, val); 61 62 /* ack fw response */ 63 *scr0 &= ~SCR0_ETH_EVT_STS_S_ACK; 64 roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH0, *scr0); 65 } 66 67 static int 68 roc_bphy_cgx_wait_for_ownership(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 69 uint64_t *scr0) 70 { 71 int tries = 5000; 72 uint64_t scr1; 73 74 do { 75 *scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0); 76 scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1); 77 78 if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW && 79 FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0) == 0) 80 break; 81 82 /* clear async events if any */ 83 if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) == 84 ETH_EVT_ASYNC && 85 FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0)) 86 roc_bphy_cgx_ack(roc_cgx, lmac, scr0); 87 88 plt_delay_ms(1); 89 } while (--tries); 90 91 return tries ? 0 : -ETIMEDOUT; 92 } 93 94 static int 95 roc_bphy_cgx_wait_for_ack(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 96 uint64_t *scr0) 97 { 98 int tries = 5000; 99 uint64_t scr1; 100 101 do { 102 *scr0 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH0); 103 scr1 = roc_bphy_cgx_read(roc_cgx, lmac, CGX_CMRX_SCRATCH1); 104 105 if (FIELD_GET(SCR1_OWN_STATUS, scr1) == ETH_OWN_NON_SECURE_SW && 106 FIELD_GET(SCR0_ETH_EVT_STS_S_ACK, *scr0)) 107 break; 108 109 plt_delay_ms(1); 110 } while (--tries); 111 112 return tries ? 0 : -ETIMEDOUT; 113 } 114 115 static int 116 roc_bphy_cgx_intf_req(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 117 uint64_t scr1, uint64_t *scr0) 118 { 119 uint8_t cmd_id = FIELD_GET(SCR1_ETH_CMD_ID, scr1); 120 int ret; 121 122 pthread_mutex_lock(&roc_cgx->lock); 123 124 /* wait for ownership */ 125 ret = roc_bphy_cgx_wait_for_ownership(roc_cgx, lmac, scr0); 126 if (ret) { 127 plt_err("timed out waiting for ownership"); 128 goto out; 129 } 130 131 /* write command */ 132 scr1 |= FIELD_PREP(SCR1_OWN_STATUS, ETH_OWN_FIRMWARE); 133 roc_bphy_cgx_write(roc_cgx, lmac, CGX_CMRX_SCRATCH1, scr1); 134 135 /* wait for command ack */ 136 ret = roc_bphy_cgx_wait_for_ack(roc_cgx, lmac, scr0); 137 if (ret) { 138 plt_err("timed out waiting for response"); 139 goto out; 140 } 141 142 if (cmd_id == ETH_CMD_INTF_SHUTDOWN) 143 goto out; 144 145 if (FIELD_GET(SCR0_ETH_EVT_STS_S_EVT_TYPE, *scr0) != ETH_EVT_CMD_RESP) { 146 plt_err("received async event instead of cmd resp event"); 147 ret = -EIO; 148 goto out; 149 } 150 151 if (FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0) != cmd_id) { 152 plt_err("received resp for cmd %d expected for cmd %d", 153 (int)FIELD_GET(SCR0_ETH_EVT_STS_S_ID, *scr0), cmd_id); 154 ret = -EIO; 155 goto out; 156 } 157 158 if (FIELD_GET(SCR0_ETH_EVT_STS_S_STAT, *scr0) != ETH_STAT_SUCCESS) { 159 plt_err("cmd %d failed on cgx%u lmac%u with errcode %d", cmd_id, 160 roc_cgx->id, lmac, 161 (int)FIELD_GET(SCR0_ETH_LNK_STS_S_ERR_TYPE, *scr0)); 162 ret = -EIO; 163 } 164 165 out: 166 roc_bphy_cgx_ack(roc_cgx, lmac, scr0); 167 168 pthread_mutex_unlock(&roc_cgx->lock); 169 170 return ret; 171 } 172 173 static unsigned int 174 roc_bphy_cgx_dev_id(struct roc_bphy_cgx *roc_cgx) 175 { 176 uint64_t cgx_id; 177 178 if (roc_model_is_cnf10kb()) 179 cgx_id = GENMASK_ULL(27, 24); 180 else if (roc_model_is_cn10k()) 181 cgx_id = GENMASK_ULL(26, 24); 182 else 183 cgx_id = GENMASK_ULL(25, 24); 184 185 return FIELD_GET(cgx_id, roc_cgx->bar0_pa); 186 } 187 188 int 189 roc_bphy_cgx_dev_init(struct roc_bphy_cgx *roc_cgx) 190 { 191 uint64_t val; 192 193 if (!roc_cgx || !roc_cgx->bar0_va || !roc_cgx->bar0_pa) 194 return -EINVAL; 195 196 pthread_mutex_init(&roc_cgx->lock, NULL); 197 198 val = roc_bphy_cgx_read(roc_cgx, 0, CGX_CMRX_RX_LMACS); 199 val = FIELD_GET(CGX_CMRX_RX_LMACS_LMACS, val); 200 if (roc_model_is_cn9k()) 201 val = GENMASK_ULL(val - 1, 0); 202 roc_cgx->lmac_bmap = val; 203 roc_cgx->id = roc_bphy_cgx_dev_id(roc_cgx); 204 205 return 0; 206 } 207 208 int 209 roc_bphy_cgx_dev_fini(struct roc_bphy_cgx *roc_cgx) 210 { 211 if (!roc_cgx) 212 return -EINVAL; 213 214 pthread_mutex_destroy(&roc_cgx->lock); 215 216 return 0; 217 } 218 219 static bool 220 roc_bphy_cgx_lmac_exists(struct roc_bphy_cgx *roc_cgx, unsigned int lmac) 221 { 222 return (lmac < MAX_LMACS_PER_CGX) && 223 (roc_cgx->lmac_bmap & BIT_ULL(lmac)); 224 } 225 226 static int 227 roc_bphy_cgx_start_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 228 bool start) 229 { 230 uint64_t val, reg, rx_field, tx_field; 231 232 if (!roc_cgx) 233 return -EINVAL; 234 235 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 236 return -ENODEV; 237 238 if (roc_model_is_cnf10kb()) { 239 reg = CGX_MTI_MAC100X_COMMAND_CONFIG; 240 rx_field = CGX_MTI_MAC100X_COMMAND_CONFIG_RX_ENA; 241 tx_field = CGX_MTI_MAC100X_COMMAND_CONFIG_TX_ENA; 242 } else { 243 reg = CGX_CMRX_CONFIG; 244 rx_field = CGX_CMRX_CONFIG_DATA_PKT_RX_EN; 245 tx_field = CGX_CMRX_CONFIG_DATA_PKT_TX_EN; 246 } 247 248 pthread_mutex_lock(&roc_cgx->lock); 249 val = roc_bphy_cgx_read(roc_cgx, lmac, reg); 250 val &= ~(rx_field | tx_field); 251 252 if (start) 253 val |= FIELD_PREP(rx_field, 1) | FIELD_PREP(tx_field, 1); 254 255 roc_bphy_cgx_write(roc_cgx, lmac, reg, val); 256 pthread_mutex_unlock(&roc_cgx->lock); 257 258 return 0; 259 } 260 261 static int 262 roc_bphy_cgx_intlbk_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 263 bool enable) 264 { 265 uint64_t scr1, scr0; 266 267 if (!roc_cgx) 268 return -EINVAL; 269 270 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 271 return -ENODEV; 272 273 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_INTERNAL_LBK) | 274 FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable); 275 276 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 277 } 278 279 static int 280 roc_bphy_cgx_ptp_rx_ena_dis(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 281 bool enable) 282 { 283 uint64_t scr1, scr0; 284 285 if (!roc_cgx) 286 return -EINVAL; 287 288 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 289 return -ENODEV; 290 291 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_PTP_MODE) | 292 FIELD_PREP(SCR1_ETH_CTL_ARGS_ENABLE, enable); 293 294 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 295 } 296 297 int 298 roc_bphy_cgx_start_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac) 299 { 300 return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, true); 301 } 302 303 int 304 roc_bphy_cgx_stop_rxtx(struct roc_bphy_cgx *roc_cgx, unsigned int lmac) 305 { 306 return roc_bphy_cgx_start_stop_rxtx(roc_cgx, lmac, false); 307 } 308 309 int 310 roc_bphy_cgx_set_link_state(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 311 struct roc_bphy_cgx_link_state *state) 312 { 313 uint64_t scr1, scr0; 314 315 if (!roc_cgx) 316 return -EINVAL; 317 318 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 319 return -ENODEV; 320 321 if (!state) 322 return -EINVAL; 323 324 scr1 = (state->state ? FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_UP) : 325 FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_LINK_BRING_DOWN)) | 326 FIELD_PREP(SCR1_CGX_LINK_BRINGUP_ARGS_TIMEOUT, state->timeout) | 327 FIELD_PREP(SCR1_CGX_LINK_BRINGUP_ARGS_RX_TX_DIS, state->rx_tx_dis); 328 329 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 330 } 331 332 int 333 roc_bphy_cgx_get_linkinfo(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 334 struct roc_bphy_cgx_link_info *info) 335 { 336 uint64_t scr1, scr0; 337 int ret; 338 339 if (!roc_cgx) 340 return -EINVAL; 341 342 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 343 return -ENODEV; 344 345 if (!info) 346 return -EINVAL; 347 348 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_LINK_STS); 349 ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 350 if (ret) 351 return ret; 352 353 info->link_up = FIELD_GET(SCR0_ETH_LNK_STS_S_LINK_UP, scr0); 354 info->full_duplex = FIELD_GET(SCR0_ETH_LNK_STS_S_FULL_DUPLEX, scr0); 355 info->speed = FIELD_GET(SCR0_ETH_LNK_STS_S_SPEED, scr0); 356 info->an = FIELD_GET(SCR0_ETH_LNK_STS_S_AN, scr0); 357 info->fec = FIELD_GET(SCR0_ETH_LNK_STS_S_FEC, scr0); 358 info->mode = FIELD_GET(SCR0_ETH_LNK_STS_S_MODE, scr0); 359 360 return 0; 361 } 362 363 int 364 roc_bphy_cgx_set_link_mode(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 365 struct roc_bphy_cgx_link_mode *mode) 366 { 367 uint64_t scr1, scr0; 368 369 if (roc_model_is_cn9k() && 370 (mode->use_portm_idx || mode->portm_idx || mode->mode_group_idx)) { 371 return -ENOTSUP; 372 } 373 374 if (!roc_cgx) 375 return -EINVAL; 376 377 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 378 return -ENODEV; 379 380 if (!mode) 381 return -EINVAL; 382 383 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_MODE_CHANGE) | 384 FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_SPEED, mode->speed) | 385 FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_DUPLEX, mode->full_duplex) | 386 FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_AN, mode->an) | 387 FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_USE_PORTM_IDX, 388 mode->use_portm_idx) | 389 FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_PORTM_IDX, 390 mode->portm_idx) | 391 FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_MODE_GROUP_IDX, 392 mode->mode_group_idx) | 393 FIELD_PREP(SCR1_ETH_MODE_CHANGE_ARGS_MODE, BIT_ULL(mode->mode)); 394 395 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 396 } 397 398 int 399 roc_bphy_cgx_intlbk_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac) 400 { 401 return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, true); 402 } 403 404 int 405 roc_bphy_cgx_intlbk_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac) 406 { 407 return roc_bphy_cgx_intlbk_ena_dis(roc_cgx, lmac, false); 408 } 409 410 int 411 roc_bphy_cgx_ptp_rx_enable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac) 412 { 413 return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, true); 414 } 415 416 int 417 roc_bphy_cgx_ptp_rx_disable(struct roc_bphy_cgx *roc_cgx, unsigned int lmac) 418 { 419 return roc_bphy_cgx_ptp_rx_ena_dis(roc_cgx, lmac, false); 420 } 421 422 int 423 roc_bphy_cgx_fec_set(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 424 enum roc_bphy_cgx_eth_link_fec fec) 425 { 426 uint64_t scr1, scr0; 427 428 if (!roc_cgx) 429 return -EINVAL; 430 431 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 432 return -ENODEV; 433 434 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_SET_FEC) | 435 FIELD_PREP(SCR1_ETH_SET_FEC_ARGS, fec); 436 437 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 438 } 439 440 int 441 roc_bphy_cgx_fec_supported_get(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 442 enum roc_bphy_cgx_eth_link_fec *fec) 443 { 444 uint64_t scr1, scr0; 445 int ret; 446 447 if (!roc_cgx || !fec) 448 return -EINVAL; 449 450 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 451 return -ENODEV; 452 453 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_GET_SUPPORTED_FEC); 454 455 ret = roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 456 if (ret) 457 return ret; 458 459 scr0 = FIELD_GET(SCR0_ETH_FEC_TYPES_S_FEC, scr0); 460 *fec = (enum roc_bphy_cgx_eth_link_fec)scr0; 461 462 return 0; 463 } 464 465 int 466 roc_bphy_cgx_cpri_mode_change(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 467 struct roc_bphy_cgx_cpri_mode_change *mode) 468 { 469 uint64_t scr1, scr0; 470 471 if (!(roc_model_is_cnf95xxn_a0() || 472 roc_model_is_cnf95xxn_a1() || 473 roc_model_is_cnf95xxn_b0())) 474 return -ENOTSUP; 475 476 if (!roc_cgx) 477 return -EINVAL; 478 479 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 480 return -ENODEV; 481 482 if (!mode) 483 return -EINVAL; 484 485 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_CPRI_MODE_CHANGE) | 486 FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_GSERC_IDX, 487 mode->gserc_idx) | 488 FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_LANE_IDX, mode->lane_idx) | 489 FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_RATE, mode->rate) | 490 FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_DISABLE_LEQ, 491 mode->disable_leq) | 492 FIELD_PREP(SCR1_CPRI_MODE_CHANGE_ARGS_DISABLE_DFE, 493 mode->disable_dfe); 494 495 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 496 } 497 498 int 499 roc_bphy_cgx_cpri_mode_tx_control(struct roc_bphy_cgx *roc_cgx, 500 unsigned int lmac, 501 struct roc_bphy_cgx_cpri_mode_tx_ctrl *mode) 502 { 503 uint64_t scr1, scr0; 504 505 if (!(roc_model_is_cnf95xxn_a0() || 506 roc_model_is_cnf95xxn_a1() || 507 roc_model_is_cnf95xxn_b0())) 508 return -ENOTSUP; 509 510 if (!roc_cgx) 511 return -EINVAL; 512 513 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 514 return -ENODEV; 515 516 if (!mode) 517 return -EINVAL; 518 519 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_CPRI_TX_CONTROL) | 520 FIELD_PREP(SCR1_CPRI_MODE_TX_CTRL_ARGS_GSERC_IDX, 521 mode->gserc_idx) | 522 FIELD_PREP(SCR1_CPRI_MODE_TX_CTRL_ARGS_LANE_IDX, 523 mode->lane_idx) | 524 FIELD_PREP(SCR1_CPRI_MODE_TX_CTRL_ARGS_ENABLE, mode->enable); 525 526 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 527 } 528 529 int 530 roc_bphy_cgx_cpri_mode_misc(struct roc_bphy_cgx *roc_cgx, unsigned int lmac, 531 struct roc_bphy_cgx_cpri_mode_misc *mode) 532 { 533 uint64_t scr1, scr0; 534 535 if (!(roc_model_is_cnf95xxn_a0() || 536 roc_model_is_cnf95xxn_a1() || 537 roc_model_is_cnf95xxn_b0())) 538 return -ENOTSUP; 539 540 if (!roc_cgx) 541 return -EINVAL; 542 543 if (!roc_bphy_cgx_lmac_exists(roc_cgx, lmac)) 544 return -ENODEV; 545 546 if (!mode) 547 return -EINVAL; 548 549 scr1 = FIELD_PREP(SCR1_ETH_CMD_ID, ETH_CMD_CPRI_MISC) | 550 FIELD_PREP(SCR1_CPRI_MODE_MISC_ARGS_GSERC_IDX, 551 mode->gserc_idx) | 552 FIELD_PREP(SCR1_CPRI_MODE_MISC_ARGS_LANE_IDX, 553 mode->lane_idx) | 554 FIELD_PREP(SCR1_CPRI_MODE_MISC_ARGS_FLAGS, mode->flags); 555 556 return roc_bphy_cgx_intf_req(roc_cgx, lmac, scr1, &scr0); 557 } 558