1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * This file is part of the Chelsio T4 support code. 14 * 15 * Copyright (C) 2010-2013 Chelsio Communications. All rights reserved. 16 * 17 * This program is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this 20 * release for licensing terms and conditions. 21 */ 22 23 /* 24 * Copyright 2020 RackTop Systems, Inc. 25 * Copyright 2021 Oxide Computer Company 26 */ 27 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/dlpi.h> 31 #include <sys/mac_provider.h> 32 #include <sys/mac_ether.h> 33 #include <sys/strsubr.h> 34 #include <sys/queue.h> 35 36 #include "common/common.h" 37 #include "common/t4_regs.h" 38 39 static int t4_mc_getstat(void *arg, uint_t stat, uint64_t *val); 40 static int t4_mc_start(void *arg); 41 static void t4_mc_stop(void *arg); 42 static int t4_mc_setpromisc(void *arg, boolean_t on); 43 static int t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr); 44 static int t4_mc_unicst(void *arg, const uint8_t *ucaddr); 45 static boolean_t t4_mc_getcapab(void *arg, mac_capab_t cap, void *data); 46 static int t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id, 47 uint_t size, const void *val); 48 static int t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id, 49 uint_t size, void *val); 50 static void t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id, 51 mac_prop_info_handle_t ph); 52 53 static int t4_init_synchronized(struct port_info *pi); 54 static int t4_uninit_synchronized(struct port_info *pi); 55 static void propinfo(struct port_info *pi, const char *name, 56 mac_prop_info_handle_t ph); 57 static int getprop(struct port_info *pi, const char *name, uint_t size, 58 void *val); 59 static int setprop(struct port_info *pi, const char *name, const void *val); 60 61 mac_callbacks_t t4_m_callbacks = { 62 .mc_callbacks = MC_GETCAPAB | MC_PROPERTIES, 63 .mc_getstat = t4_mc_getstat, 64 .mc_start = t4_mc_start, 65 .mc_stop = t4_mc_stop, 66 .mc_setpromisc = t4_mc_setpromisc, 67 .mc_multicst = t4_mc_multicst, 68 .mc_unicst = t4_mc_unicst, 69 .mc_tx = t4_mc_tx, 70 .mc_getcapab = t4_mc_getcapab, 71 .mc_setprop = t4_mc_setprop, 72 .mc_getprop = t4_mc_getprop, 73 .mc_propinfo = t4_mc_propinfo, 74 }; 75 76 /* I couldn't comeup with a better idea of not redefine 77 * another strcture and instead somehow reuse the earlier 78 * above structure and modify its members. 79 */ 80 mac_callbacks_t t4_m_ring_callbacks = { 81 .mc_callbacks = MC_GETCAPAB | MC_PROPERTIES, 82 .mc_getstat = t4_mc_getstat, 83 .mc_start = t4_mc_start, 84 .mc_stop = t4_mc_stop, 85 .mc_setpromisc =t4_mc_setpromisc, 86 .mc_multicst = t4_mc_multicst, 87 .mc_unicst = NULL, /* t4_addmac */ 88 .mc_tx = NULL, /* t4_eth_tx */ 89 .mc_getcapab = t4_mc_getcapab, 90 .mc_setprop = t4_mc_setprop, 91 .mc_getprop = t4_mc_getprop, 92 .mc_propinfo = t4_mc_propinfo, 93 }; 94 95 #define T4PROP_TMR_IDX "_holdoff_timer_idx" 96 #define T4PROP_PKTC_IDX "_holdoff_pktc_idx" 97 #define T4PROP_MTU "_mtu" 98 #define T4PROP_HW_CSUM "_hw_csum" 99 #define T4PROP_HW_LSO "_hw_lso" 100 #define T4PROP_TX_PAUSE "_tx_pause" 101 #define T4PROP_RX_PAUSE "_rx_pause" 102 103 char *t4_priv_props[] = { 104 T4PROP_TMR_IDX, 105 T4PROP_PKTC_IDX, 106 #if MAC_VERSION == 1 107 /* MAC_VERSION 1 doesn't seem to use MAC_PROP_MTU, hmmmm */ 108 T4PROP_MTU, 109 #endif 110 T4PROP_HW_CSUM, 111 T4PROP_HW_LSO, 112 T4PROP_TX_PAUSE, 113 T4PROP_RX_PAUSE, 114 NULL 115 }; 116 117 static int 118 t4_mc_getstat(void *arg, uint_t stat, uint64_t *val) 119 { 120 struct port_info *pi = arg; 121 struct adapter *sc = pi->adapter; 122 struct link_config *lc = &pi->link_cfg; 123 124 #define GET_STAT(name) \ 125 t4_read_reg64(sc, PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_##name##_L)) 126 127 switch (stat) { 128 case MAC_STAT_IFSPEED: 129 if (lc->link_ok != 0) { 130 *val = lc->speed; 131 *val *= 1000000; 132 } else 133 *val = 0; 134 break; 135 136 case MAC_STAT_MULTIRCV: 137 *val = GET_STAT(RX_PORT_MCAST); 138 break; 139 140 case MAC_STAT_BRDCSTRCV: 141 *val = GET_STAT(RX_PORT_BCAST); 142 break; 143 144 case MAC_STAT_MULTIXMT: 145 *val = GET_STAT(TX_PORT_MCAST); 146 break; 147 148 case MAC_STAT_BRDCSTXMT: 149 *val = GET_STAT(TX_PORT_BCAST); 150 break; 151 152 case MAC_STAT_NORCVBUF: 153 *val = 0; /* TODO should come from rxq->nomem */ 154 break; 155 156 case MAC_STAT_IERRORS: 157 *val = GET_STAT(RX_PORT_MTU_ERROR) + 158 GET_STAT(RX_PORT_MTU_CRC_ERROR) + 159 GET_STAT(RX_PORT_CRC_ERROR) + 160 GET_STAT(RX_PORT_LEN_ERROR) + 161 GET_STAT(RX_PORT_SYM_ERROR) + 162 GET_STAT(RX_PORT_LESS_64B); 163 break; 164 165 case MAC_STAT_UNKNOWNS: 166 return (ENOTSUP); 167 168 case MAC_STAT_NOXMTBUF: 169 *val = GET_STAT(TX_PORT_DROP); 170 break; 171 172 case MAC_STAT_OERRORS: 173 *val = GET_STAT(TX_PORT_ERROR); 174 break; 175 176 case MAC_STAT_COLLISIONS: 177 return (ENOTSUP); 178 179 case MAC_STAT_RBYTES: 180 *val = GET_STAT(RX_PORT_BYTES); 181 break; 182 183 case MAC_STAT_IPACKETS: 184 *val = GET_STAT(RX_PORT_FRAMES); 185 break; 186 187 case MAC_STAT_OBYTES: 188 *val = GET_STAT(TX_PORT_BYTES); 189 break; 190 191 case MAC_STAT_OPACKETS: 192 *val = GET_STAT(TX_PORT_FRAMES); 193 break; 194 195 case ETHER_STAT_ALIGN_ERRORS: 196 return (ENOTSUP); 197 198 case ETHER_STAT_FCS_ERRORS: 199 *val = GET_STAT(RX_PORT_CRC_ERROR); 200 break; 201 202 case ETHER_STAT_FIRST_COLLISIONS: 203 case ETHER_STAT_MULTI_COLLISIONS: 204 case ETHER_STAT_SQE_ERRORS: 205 case ETHER_STAT_DEFER_XMTS: 206 case ETHER_STAT_TX_LATE_COLLISIONS: 207 case ETHER_STAT_EX_COLLISIONS: 208 return (ENOTSUP); 209 210 case ETHER_STAT_MACXMT_ERRORS: 211 *val = GET_STAT(TX_PORT_ERROR); 212 break; 213 214 case ETHER_STAT_CARRIER_ERRORS: 215 return (ENOTSUP); 216 217 case ETHER_STAT_TOOLONG_ERRORS: 218 *val = GET_STAT(RX_PORT_MTU_ERROR); 219 break; 220 221 case ETHER_STAT_MACRCV_ERRORS: 222 *val = GET_STAT(RX_PORT_MTU_ERROR) + 223 GET_STAT(RX_PORT_MTU_CRC_ERROR) + 224 GET_STAT(RX_PORT_CRC_ERROR) + 225 GET_STAT(RX_PORT_LEN_ERROR) + 226 GET_STAT(RX_PORT_SYM_ERROR) + 227 GET_STAT(RX_PORT_LESS_64B); 228 break; 229 230 case ETHER_STAT_XCVR_ADDR: 231 case ETHER_STAT_XCVR_ID: 232 case ETHER_STAT_XCVR_INUSE: 233 return (ENOTSUP); 234 235 case ETHER_STAT_CAP_100GFDX: 236 *val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_100G); 237 break; 238 239 case ETHER_STAT_CAP_40GFDX: 240 *val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_40G); 241 break; 242 243 case ETHER_STAT_CAP_25GFDX: 244 *val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_25G); 245 break; 246 247 case ETHER_STAT_CAP_10GFDX: 248 *val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_10G); 249 break; 250 251 case ETHER_STAT_CAP_1000FDX: 252 *val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_1G); 253 break; 254 255 case ETHER_STAT_CAP_1000HDX: 256 return (ENOTSUP); 257 258 case ETHER_STAT_CAP_100FDX: 259 *val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_100M); 260 break; 261 262 case ETHER_STAT_CAP_100HDX: 263 return (ENOTSUP); 264 265 case ETHER_STAT_CAP_10FDX: 266 case ETHER_STAT_CAP_10HDX: 267 return (ENOTSUP); 268 269 case ETHER_STAT_CAP_ASMPAUSE: 270 *val = 0; 271 break; 272 273 case ETHER_STAT_CAP_PAUSE: 274 *val = 1; 275 break; 276 277 case ETHER_STAT_CAP_AUTONEG: 278 *val = !!(lc->pcaps & FW_PORT_CAP32_ANEG); 279 break; 280 281 /* 282 * We have set flow control configuration based on tx_pause and rx_pause 283 * values supported through ndd. Now, we need to translate the settings 284 * we have in link_config structure to adv_cap_asmpause and 285 * adv_cap_pause. 286 * 287 * There are 4 combinations possible and the translation is as below: 288 * tx_pause = 0 => We don't send pause frames during Rx congestion 289 * tx_pause = 1 => We send pause frames during Rx congestion 290 * rx_pause = 0 => We ignore received pause frames 291 * rx_pause = 1 => We pause transmission when we receive pause frames 292 * 293 * +----------------------------+----------------------------------+ 294 * | tx_pause | rx_pause | adv_cap_asmpause | adv_cap_pause | 295 * +-------------------------+-------------------------------------+ 296 * | 0 | 0 | 0 | 0 | 297 * | 0 | 1 | 1 | 0 | 298 * | 1 | 0 | 1 | 1 | 299 * | 1 | 1 | 0 | 1 | 300 * +----------------------------+----------------------------------+ 301 */ 302 303 /* Advertised asymmetric pause capability */ 304 case ETHER_STAT_ADV_CAP_ASMPAUSE: 305 *val = (((lc->requested_fc & PAUSE_TX) ? 1 : 0) ^ 306 (lc->requested_fc & PAUSE_RX)); 307 break; 308 309 /* Advertised pause capability */ 310 case ETHER_STAT_ADV_CAP_PAUSE: 311 *val = (lc->requested_fc & PAUSE_TX) ? 1 : 0; 312 break; 313 314 case ETHER_STAT_ADV_CAP_100GFDX: 315 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_100G); 316 break; 317 318 case ETHER_STAT_ADV_CAP_40GFDX: 319 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_40G); 320 break; 321 322 case ETHER_STAT_ADV_CAP_25GFDX: 323 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_25G); 324 break; 325 326 case ETHER_STAT_ADV_CAP_10GFDX: 327 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_10G); 328 break; 329 330 case ETHER_STAT_ADV_CAP_1000FDX: 331 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_1G); 332 break; 333 334 case ETHER_STAT_ADV_CAP_AUTONEG: 335 *val = !!(lc->acaps & FW_PORT_CAP32_ANEG); 336 break; 337 338 case ETHER_STAT_ADV_CAP_1000HDX: 339 case ETHER_STAT_ADV_CAP_100FDX: 340 case ETHER_STAT_ADV_CAP_100HDX: 341 case ETHER_STAT_ADV_CAP_10FDX: 342 case ETHER_STAT_ADV_CAP_10HDX: 343 return (ENOTSUP); /* TODO */ 344 345 346 case ETHER_STAT_LP_CAP_100GFDX: 347 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_100G); 348 break; 349 350 case ETHER_STAT_LP_CAP_40GFDX: 351 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_40G); 352 break; 353 354 case ETHER_STAT_LP_CAP_25GFDX: 355 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_25G); 356 break; 357 358 case ETHER_STAT_LP_CAP_10GFDX: 359 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_10G); 360 break; 361 362 case ETHER_STAT_LP_CAP_1000FDX: 363 *val = !!(lc->acaps & FW_PORT_CAP32_SPEED_1G); 364 break; 365 366 case ETHER_STAT_LP_CAP_AUTONEG: 367 *val = !!(lc->acaps & FW_PORT_CAP32_ANEG); 368 break; 369 370 case ETHER_STAT_LP_CAP_1000HDX: 371 case ETHER_STAT_LP_CAP_100FDX: 372 case ETHER_STAT_LP_CAP_100HDX: 373 case ETHER_STAT_LP_CAP_10FDX: 374 case ETHER_STAT_LP_CAP_10HDX: 375 case ETHER_STAT_LP_CAP_ASMPAUSE: 376 case ETHER_STAT_LP_CAP_PAUSE: 377 return (ENOTSUP); 378 379 case ETHER_STAT_LINK_ASMPAUSE: 380 *val = 0; 381 break; 382 383 case ETHER_STAT_LINK_PAUSE: 384 *val = 1; 385 break; 386 387 case ETHER_STAT_LINK_AUTONEG: 388 *val = lc->autoneg == AUTONEG_ENABLE; 389 break; 390 391 case ETHER_STAT_LINK_DUPLEX: 392 if (lc->link_ok != 0) 393 *val = LINK_DUPLEX_FULL; 394 else 395 *val = LINK_DUPLEX_UNKNOWN; 396 break; 397 398 default: 399 #ifdef DEBUG 400 cxgb_printf(pi->dip, CE_NOTE, "stat %d not implemented.", stat); 401 #endif 402 return (ENOTSUP); 403 } 404 #undef GET_STAT 405 406 return (0); 407 } 408 409 static int 410 t4_mc_start(void *arg) 411 { 412 struct port_info *pi = arg; 413 int rc; 414 415 rc = begin_synchronized_op(pi, 0, 1); 416 if (rc != 0) 417 return (rc); 418 rc = t4_init_synchronized(pi); 419 end_synchronized_op(pi, 0); 420 421 return (rc); 422 } 423 424 static void 425 t4_mc_stop(void *arg) 426 { 427 struct port_info *pi = arg; 428 429 while (begin_synchronized_op(pi, 0, 1) != 0) 430 continue; 431 (void) t4_uninit_synchronized(pi); 432 end_synchronized_op(pi, 0); 433 } 434 435 static int 436 t4_mc_setpromisc(void *arg, boolean_t on) 437 { 438 struct port_info *pi = arg; 439 struct adapter *sc = pi->adapter; 440 int rc; 441 442 rc = begin_synchronized_op(pi, 1, 1); 443 if (rc != 0) 444 return (rc); 445 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, -1, on ? 1 : 0, -1, -1, -1, 446 false); 447 end_synchronized_op(pi, 1); 448 449 return (rc); 450 } 451 452 /* 453 * TODO: Starts failing as soon as the 336 entry table fills up. Need to use 454 * hash in that case. 455 */ 456 static int 457 t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr) 458 { 459 struct port_info *pi = arg; 460 struct adapter *sc = pi->adapter; 461 struct fw_vi_mac_cmd c; 462 int len16, rc; 463 464 len16 = howmany(sizeof (c.op_to_viid) + sizeof (c.freemacs_to_len16) + 465 sizeof (c.u.exact[0]), 16); 466 c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST | 467 F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(pi->viid)); 468 c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(len16)); 469 c.u.exact[0].valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID | 470 V_FW_VI_MAC_CMD_IDX(add ? FW_VI_MAC_ADD_MAC : 471 FW_VI_MAC_MAC_BASED_FREE)); 472 bcopy(mcaddr, &c.u.exact[0].macaddr, ETHERADDRL); 473 474 rc = begin_synchronized_op(pi, 1, 1); 475 if (rc != 0) 476 return (rc); 477 rc = -t4_wr_mbox_meat(sc, sc->mbox, &c, len16 * 16, &c, true); 478 end_synchronized_op(pi, 1); 479 if (rc != 0) 480 return (rc); 481 #ifdef DEBUG 482 /* 483 * TODO: Firmware doesn't seem to return the correct index on removal 484 * (it gives back 0x3fd FW_VI_MAC_MAC_BASED_FREE unchanged. Remove this 485 * code once it is fixed. 486 */ 487 else { 488 uint16_t idx; 489 490 idx = G_FW_VI_MAC_CMD_IDX(ntohs(c.u.exact[0].valid_to_idx)); 491 cxgb_printf(pi->dip, CE_NOTE, 492 "%02x:%02x:%02x:%02x:%02x:%02x %s %d", mcaddr[0], 493 mcaddr[1], mcaddr[2], mcaddr[3], mcaddr[4], mcaddr[5], 494 add ? "added at index" : "removed from index", idx); 495 } 496 #endif 497 498 return (0); 499 } 500 501 int 502 t4_mc_unicst(void *arg, const uint8_t *ucaddr) 503 { 504 struct port_info *pi = arg; 505 struct adapter *sc = pi->adapter; 506 int rc; 507 508 if (ucaddr == NULL) 509 return (EINVAL); 510 511 rc = begin_synchronized_op(pi, 1, 1); 512 if (rc != 0) 513 return (rc); 514 515 /* We will support adding only one mac address */ 516 if (pi->adapter->props.multi_rings && pi->macaddr_cnt) { 517 end_synchronized_op(pi, 1); 518 return (ENOSPC); 519 } 520 rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, ucaddr, 521 true, &pi->smt_idx); 522 if (rc < 0) 523 rc = -rc; 524 else { 525 pi->macaddr_cnt++; 526 pi->xact_addr_filt = rc; 527 rc = 0; 528 } 529 end_synchronized_op(pi, 1); 530 531 return (rc); 532 } 533 534 int 535 t4_addmac(void *arg, const uint8_t *ucaddr) 536 { 537 return (t4_mc_unicst(arg, ucaddr)); 538 } 539 540 static int 541 t4_remmac(void *arg, const uint8_t *mac_addr) 542 { 543 struct port_info *pi = arg; 544 int rc; 545 546 rc = begin_synchronized_op(pi, 1, 1); 547 if (rc != 0) 548 return (rc); 549 550 pi->macaddr_cnt--; 551 end_synchronized_op(pi, 1); 552 553 return (0); 554 } 555 556 /* 557 * Callback funtion for MAC layer to register all groups. 558 */ 559 void 560 t4_fill_group(void *arg, mac_ring_type_t rtype, const int rg_index, 561 mac_group_info_t *infop, mac_group_handle_t gh) 562 { 563 struct port_info *pi = arg; 564 565 switch (rtype) { 566 case MAC_RING_TYPE_RX: { 567 infop->mgi_driver = (mac_group_driver_t)arg; 568 infop->mgi_start = NULL; 569 infop->mgi_stop = NULL; 570 infop->mgi_addmac = t4_addmac; 571 infop->mgi_remmac = t4_remmac; 572 infop->mgi_count = pi->nrxq; 573 break; 574 } 575 case MAC_RING_TYPE_TX: 576 default: 577 ASSERT(0); 578 break; 579 } 580 } 581 582 static int 583 t4_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num) 584 { 585 struct sge_rxq *rxq = (struct sge_rxq *)rh; 586 587 RXQ_LOCK(rxq); 588 rxq->ring_gen_num = mr_gen_num; 589 RXQ_UNLOCK(rxq); 590 return (0); 591 } 592 593 /* 594 * Enable interrupt on the specificed rx ring. 595 */ 596 int 597 t4_ring_intr_enable(mac_intr_handle_t intrh) 598 { 599 struct sge_rxq *rxq = (struct sge_rxq *)intrh; 600 struct adapter *sc = rxq->port->adapter; 601 struct sge_iq *iq; 602 603 iq = &rxq->iq; 604 RXQ_LOCK(rxq); 605 iq->polling = 0; 606 iq->state = IQS_IDLE; 607 t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS), 608 V_SEINTARM(iq->intr_params) | V_INGRESSQID(iq->cntxt_id)); 609 RXQ_UNLOCK(rxq); 610 return (0); 611 } 612 613 /* 614 * Disable interrupt on the specificed rx ring. 615 */ 616 int 617 t4_ring_intr_disable(mac_intr_handle_t intrh) 618 { 619 struct sge_rxq *rxq = (struct sge_rxq *)intrh; 620 struct sge_iq *iq; 621 622 /* Nothing to be done here wrt interrupt, as it 623 * will not fire, until we write back to 624 * A_SGE_PF_GTS.SEIntArm in t4_ring_intr_enable. 625 */ 626 627 iq = &rxq->iq; 628 RXQ_LOCK(rxq); 629 iq->polling = 1; 630 iq->state = IQS_BUSY; 631 RXQ_UNLOCK(rxq); 632 return (0); 633 } 634 635 mblk_t * 636 t4_poll_ring(void *arg, int n_bytes) 637 { 638 struct sge_rxq *rxq = (struct sge_rxq *)arg; 639 mblk_t *mp = NULL; 640 641 ASSERT(n_bytes >= 0); 642 if (n_bytes == 0) 643 return (NULL); 644 645 RXQ_LOCK(rxq); 646 mp = t4_ring_rx(rxq, n_bytes); 647 RXQ_UNLOCK(rxq); 648 649 return (mp); 650 } 651 652 /* 653 * Retrieve a value for one of the statistics for a particular rx ring 654 */ 655 int 656 t4_rx_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val) 657 { 658 struct sge_rxq *rxq = (struct sge_rxq *)rh; 659 660 switch (stat) { 661 case MAC_STAT_RBYTES: 662 *val = rxq->rxbytes; 663 break; 664 665 case MAC_STAT_IPACKETS: 666 *val = rxq->rxpkts; 667 break; 668 669 default: 670 *val = 0; 671 return (ENOTSUP); 672 } 673 674 return (0); 675 } 676 677 /* 678 * Retrieve a value for one of the statistics for a particular tx ring 679 */ 680 int 681 t4_tx_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val) 682 { 683 struct sge_txq *txq = (struct sge_txq *)rh; 684 685 switch (stat) { 686 case MAC_STAT_RBYTES: 687 *val = txq->txbytes; 688 break; 689 690 case MAC_STAT_IPACKETS: 691 *val = txq->txpkts; 692 break; 693 694 default: 695 *val = 0; 696 return (ENOTSUP); 697 } 698 699 return (0); 700 } 701 702 /* 703 * Callback funtion for MAC layer to register all rings 704 * for given ring_group, noted by group_index. 705 * Since we have only one group, ring index becomes 706 * absolute index. 707 */ 708 void 709 t4_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index, 710 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 711 { 712 struct port_info *pi = arg; 713 mac_intr_t *mintr; 714 715 switch (rtype) { 716 case MAC_RING_TYPE_RX: { 717 struct sge_rxq *rxq; 718 719 rxq = &pi->adapter->sge.rxq[pi->first_rxq + ring_index]; 720 rxq->ring_handle = rh; 721 722 infop->mri_driver = (mac_ring_driver_t)rxq; 723 infop->mri_start = t4_ring_start; 724 infop->mri_stop = NULL; 725 infop->mri_poll = t4_poll_ring; 726 infop->mri_stat = t4_rx_stat; 727 728 mintr = &infop->mri_intr; 729 mintr->mi_handle = (mac_intr_handle_t)rxq; 730 mintr->mi_enable = t4_ring_intr_enable; 731 mintr->mi_disable = t4_ring_intr_disable; 732 733 break; 734 } 735 case MAC_RING_TYPE_TX: { 736 struct sge_txq *txq = &pi->adapter->sge.txq[pi->first_txq + ring_index]; 737 txq->ring_handle = rh; 738 infop->mri_driver = (mac_ring_driver_t)txq; 739 infop->mri_start = NULL; 740 infop->mri_stop = NULL; 741 infop->mri_tx = t4_eth_tx; 742 infop->mri_stat = t4_tx_stat; 743 break; 744 } 745 default: 746 ASSERT(0); 747 break; 748 } 749 } 750 751 mblk_t * 752 t4_mc_tx(void *arg, mblk_t *m) 753 { 754 struct port_info *pi = arg; 755 struct adapter *sc = pi->adapter; 756 struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 757 758 return (t4_eth_tx(txq, m)); 759 } 760 761 static int 762 t4_mc_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) 763 { 764 struct port_info *pi = arg; 765 766 if (id != 0 || infop == NULL) 767 return (EINVAL); 768 769 switch (pi->mod_type) { 770 case FW_PORT_MOD_TYPE_NONE: 771 mac_transceiver_info_set_present(infop, B_FALSE); 772 break; 773 case FW_PORT_MOD_TYPE_NOTSUPPORTED: 774 mac_transceiver_info_set_present(infop, B_TRUE); 775 mac_transceiver_info_set_usable(infop, B_FALSE); 776 break; 777 default: 778 mac_transceiver_info_set_present(infop, B_TRUE); 779 mac_transceiver_info_set_usable(infop, B_TRUE); 780 break; 781 } 782 783 return (0); 784 } 785 786 static int 787 t4_mc_transceiver_read(void *arg, uint_t id, uint_t page, void *bp, 788 size_t nbytes, off_t offset, size_t *nread) 789 { 790 struct port_info *pi = arg; 791 struct adapter *sc = pi->adapter; 792 int rc; 793 size_t i, maxread; 794 /* LINTED: E_FUNC_VAR_UNUSED */ 795 struct fw_ldst_cmd ldst __unused; 796 797 if (id != 0 || bp == NULL || nbytes == 0 || nread == NULL || 798 (page != 0xa0 && page != 0xa2) || offset < 0) 799 return (EINVAL); 800 801 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) 802 return (EINVAL); 803 804 rc = begin_synchronized_op(pi, 0, 1); 805 if (rc != 0) 806 return (rc); 807 808 /* 809 * Firmware has a maximum size that we can read. Don't read more than it 810 * allows. 811 */ 812 maxread = sizeof (ldst.u.i2c.data); 813 for (i = 0; i < nbytes; i += maxread) { 814 size_t toread = MIN(maxread, nbytes - i); 815 rc = -t4_i2c_rd(sc, sc->mbox, pi->port_id, page, offset, toread, 816 bp); 817 if (rc != 0) 818 break; 819 offset += toread; 820 bp = (void *)((uintptr_t)bp + toread); 821 } 822 end_synchronized_op(pi, 0); 823 if (rc == 0) 824 *nread = nbytes; 825 return (rc); 826 } 827 828 static int 829 t4_port_led_set(void *arg, mac_led_mode_t mode, uint_t flags) 830 { 831 struct port_info *pi = arg; 832 struct adapter *sc = pi->adapter; 833 int val, rc; 834 835 if (flags != 0) 836 return (EINVAL); 837 838 switch (mode) { 839 case MAC_LED_DEFAULT: 840 val = 0; 841 break; 842 case MAC_LED_IDENT: 843 val = 0xffff; 844 break; 845 846 default: 847 return (ENOTSUP); 848 } 849 850 rc = begin_synchronized_op(pi, 1, 1); 851 if (rc != 0) 852 return (rc); 853 rc = -t4_identify_port(sc, sc->mbox, pi->viid, val); 854 end_synchronized_op(pi, 1); 855 856 return (rc); 857 } 858 859 static boolean_t 860 t4_mc_getcapab(void *arg, mac_capab_t cap, void *data) 861 { 862 struct port_info *pi = arg; 863 boolean_t status = B_TRUE; 864 mac_capab_transceiver_t *mct; 865 mac_capab_led_t *mcl; 866 867 switch (cap) { 868 case MAC_CAPAB_HCKSUM: 869 if (pi->features & CXGBE_HW_CSUM) { 870 uint32_t *d = data; 871 *d = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM | 872 HCKSUM_INET_FULL_V6; 873 } else 874 status = B_FALSE; 875 break; 876 877 case MAC_CAPAB_LSO: 878 /* Enabling LSO requires Checksum offloading */ 879 if (pi->features & CXGBE_HW_LSO && 880 pi->features & CXGBE_HW_CSUM) { 881 mac_capab_lso_t *d = data; 882 883 d->lso_flags = LSO_TX_BASIC_TCP_IPV4 | 884 LSO_TX_BASIC_TCP_IPV6; 885 d->lso_basic_tcp_ipv4.lso_max = 65535; 886 d->lso_basic_tcp_ipv6.lso_max = 65535; 887 } else 888 status = B_FALSE; 889 break; 890 891 case MAC_CAPAB_RINGS: { 892 mac_capab_rings_t *cap_rings = data; 893 894 if (!pi->adapter->props.multi_rings) { 895 status = B_FALSE; 896 break; 897 } 898 switch (cap_rings->mr_type) { 899 case MAC_RING_TYPE_RX: 900 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 901 cap_rings->mr_rnum = pi->nrxq; 902 cap_rings->mr_gnum = 1; 903 cap_rings->mr_rget = t4_fill_ring; 904 cap_rings->mr_gget = t4_fill_group; 905 cap_rings->mr_gaddring = NULL; 906 cap_rings->mr_gremring = NULL; 907 break; 908 case MAC_RING_TYPE_TX: 909 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 910 cap_rings->mr_rnum = pi->ntxq; 911 cap_rings->mr_gnum = 0; 912 cap_rings->mr_rget = t4_fill_ring; 913 cap_rings->mr_gget = NULL; 914 break; 915 } 916 break; 917 } 918 919 case MAC_CAPAB_TRANSCEIVER: 920 mct = data; 921 922 mct->mct_flags = 0; 923 mct->mct_ntransceivers = 1; 924 mct->mct_info = t4_mc_transceiver_info; 925 mct->mct_read = t4_mc_transceiver_read; 926 break; 927 case MAC_CAPAB_LED: 928 mcl = data; 929 mcl->mcl_flags = 0; 930 mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT; 931 mcl->mcl_set = t4_port_led_set; 932 break; 933 934 default: 935 status = B_FALSE; /* cap not supported */ 936 } 937 938 return (status); 939 } 940 941 static link_fec_t 942 fec_to_link_fec(cc_fec_t cc_fec) 943 { 944 link_fec_t link_fec = 0; 945 946 if ((cc_fec & (FEC_RS | FEC_BASER_RS)) == (FEC_RS | FEC_BASER_RS)) 947 return (LINK_FEC_AUTO); 948 949 if ((cc_fec & FEC_NONE) != 0) 950 link_fec |= LINK_FEC_NONE; 951 952 if ((cc_fec & FEC_AUTO) != 0) 953 link_fec |= LINK_FEC_AUTO; 954 955 if ((cc_fec & FEC_RS) != 0) 956 link_fec |= LINK_FEC_RS; 957 958 if ((cc_fec & FEC_BASER_RS) != 0) 959 link_fec |= LINK_FEC_BASE_R; 960 961 return (link_fec); 962 } 963 964 static int 965 link_fec_to_fec(int v) 966 { 967 int fec = 0; 968 969 if ((v & LINK_FEC_AUTO) != 0) { 970 fec = FEC_AUTO; 971 v &= ~LINK_FEC_AUTO; 972 } else { 973 if ((v & LINK_FEC_NONE) != 0) { 974 fec = FEC_NONE; 975 v &= ~LINK_FEC_NONE; 976 } 977 978 if ((v & LINK_FEC_RS) != 0) { 979 fec |= FEC_RS; 980 v &= ~LINK_FEC_RS; 981 } 982 983 if ((v & LINK_FEC_BASE_R) != 0) { 984 fec |= FEC_BASER_RS; 985 v &= ~LINK_FEC_BASE_R; 986 } 987 } 988 989 if (v != 0) 990 return (-1); 991 992 ASSERT3S(fec, !=, 0); 993 994 return (fec); 995 } 996 997 /* ARGSUSED */ 998 static int 999 t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t size, 1000 const void *val) 1001 { 1002 struct port_info *pi = arg; 1003 struct adapter *sc = pi->adapter; 1004 struct link_config lc_copy, *lc = &pi->link_cfg; 1005 uint8_t v8 = *(uint8_t *)val; 1006 uint32_t v32 = *(uint32_t *)val; 1007 int old, new = 0, relink = 0, rx_mode = 0, rc = 0; 1008 boolean_t down_link = B_TRUE; 1009 link_flowctrl_t fc; 1010 link_fec_t fec; 1011 1012 /* 1013 * Save a copy of link_config. This can be used to restore link_config 1014 * if t4_link_l1cfg() fails. 1015 */ 1016 bcopy(lc, &lc_copy, sizeof (struct link_config)); 1017 1018 switch (id) { 1019 case MAC_PROP_AUTONEG: 1020 if (lc->pcaps & FW_PORT_CAP32_ANEG) { 1021 old = lc->autoneg; 1022 new = v8 ? AUTONEG_ENABLE : AUTONEG_DISABLE; 1023 if (old != new) { 1024 /* LINTED: E_CONSTANT_CONDITION */ 1025 lc->autoneg = new; 1026 relink = 1; 1027 if (new == AUTONEG_DISABLE) { 1028 /* Only 100M is available */ 1029 lc->speed_caps = 1030 FW_PORT_CAP32_SPEED_100M; 1031 lc->acaps = 1032 FW_PORT_CAP32_SPEED_100M; 1033 } else { 1034 /* 1035 * Advertise autonegotiation capability 1036 * along with supported speeds 1037 */ 1038 lc->acaps |= (FW_PORT_CAP32_ANEG | 1039 (lc->pcaps & 1040 (FW_PORT_CAP32_SPEED_100M | 1041 FW_PORT_CAP32_SPEED_1G))); 1042 lc->speed_caps = 0; 1043 } 1044 } 1045 } else 1046 rc = ENOTSUP; 1047 break; 1048 1049 case MAC_PROP_MTU: 1050 if (v32 < 46 || v32 > MAX_MTU) { 1051 rc = EINVAL; 1052 } else if (v32 != pi->mtu) { 1053 pi->mtu = v32; 1054 (void) mac_maxsdu_update(pi->mh, v32); 1055 rx_mode = 1; 1056 } 1057 1058 break; 1059 1060 case MAC_PROP_FLOWCTRL: 1061 fc = *(link_flowctrl_t *)val; 1062 old = lc->requested_fc & (PAUSE_TX | PAUSE_RX); 1063 1064 if (fc == LINK_FLOWCTRL_BI) 1065 new = (PAUSE_TX | PAUSE_RX); 1066 else if (fc == LINK_FLOWCTRL_TX) 1067 new = PAUSE_TX; 1068 else if (fc == LINK_FLOWCTRL_RX) 1069 new = PAUSE_RX; 1070 1071 if (new != old) { 1072 lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX); 1073 lc->requested_fc |= new; 1074 relink = 1; 1075 } 1076 break; 1077 1078 case MAC_PROP_EN_FEC_CAP: 1079 if (!fec_supported(lc->pcaps)) { 1080 rc = ENOTSUP; 1081 break; 1082 } 1083 1084 fec = *(link_fec_t *)val; 1085 new = link_fec_to_fec(fec); 1086 if (new < 0) { 1087 rc = EINVAL; 1088 } else if (new != lc->requested_fec) { 1089 lc->requested_fec = new; 1090 relink = 1; 1091 /* 1092 * For fec, do not preemptively force the link 1093 * down. If changing fec causes the link state 1094 * to transition, then appropriate asynchronous 1095 * events are generated which correctly reflect 1096 * the link state. 1097 */ 1098 down_link = B_FALSE; 1099 } 1100 break; 1101 1102 case MAC_PROP_EN_10GFDX_CAP: 1103 if (lc->pcaps & FW_PORT_CAP32_ANEG && is_10G_port(pi)) { 1104 old = lc->acaps & FW_PORT_CAP32_SPEED_10G; 1105 new = v8 ? FW_PORT_CAP32_SPEED_10G : 0; 1106 if (new != old) { 1107 lc->acaps &= ~FW_PORT_CAP32_SPEED_10G; 1108 lc->acaps |= new; 1109 relink = 1; 1110 } 1111 } else 1112 rc = ENOTSUP; 1113 1114 break; 1115 1116 case MAC_PROP_EN_1000FDX_CAP: 1117 /* Forced 1G */ 1118 if (lc->autoneg == AUTONEG_ENABLE) { 1119 old = lc->acaps & FW_PORT_CAP32_SPEED_1G; 1120 new = v8 ? FW_PORT_CAP32_SPEED_1G : 0; 1121 1122 if (old != new) { 1123 lc->acaps &= ~FW_PORT_CAP32_SPEED_1G; 1124 lc->acaps |= new; 1125 relink = 1; 1126 } 1127 } else 1128 rc = ENOTSUP; 1129 break; 1130 1131 case MAC_PROP_EN_100FDX_CAP: 1132 /* Forced 100M */ 1133 if (lc->autoneg == AUTONEG_ENABLE) { 1134 old = lc->acaps & FW_PORT_CAP32_SPEED_100M; 1135 new = v8 ? FW_PORT_CAP32_SPEED_100M : 0; 1136 if (old != new) { 1137 lc->acaps &= ~FW_PORT_CAP32_SPEED_100M; 1138 lc->acaps |= new; 1139 relink = 1; 1140 } 1141 } else 1142 rc = ENOTSUP; 1143 break; 1144 1145 case MAC_PROP_PRIVATE: 1146 rc = setprop(pi, name, val); 1147 break; 1148 1149 default: 1150 rc = ENOTSUP; 1151 } 1152 1153 if (isset(&sc->open_device_map, pi->port_id) != 0) { 1154 if (relink != 0) { 1155 if (down_link) 1156 t4_os_link_changed(pi->adapter, pi->port_id, 0); 1157 rc = begin_synchronized_op(pi, 1, 1); 1158 if (rc != 0) 1159 return (rc); 1160 rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, 1161 &pi->link_cfg); 1162 end_synchronized_op(pi, 1); 1163 if (rc != 0) { 1164 cxgb_printf(pi->dip, CE_WARN, 1165 "start_link failed:%d", rc); 1166 1167 /* Restore link_config */ 1168 bcopy(&lc_copy, lc, 1169 sizeof (struct link_config)); 1170 } 1171 } 1172 1173 if (rx_mode != 0) { 1174 rc = begin_synchronized_op(pi, 1, 1); 1175 if (rc != 0) 1176 return (rc); 1177 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v32, -1, 1178 -1, -1, -1, false); 1179 end_synchronized_op(pi, 1); 1180 if (rc != 0) { 1181 cxgb_printf(pi->dip, CE_WARN, 1182 "set_rxmode failed: %d", rc); 1183 } 1184 } 1185 } 1186 1187 return (rc); 1188 } 1189 1190 static int 1191 t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t size, 1192 void *val) 1193 { 1194 struct port_info *pi = arg; 1195 struct link_config *lc = &pi->link_cfg; 1196 uint8_t *u = val; 1197 1198 switch (id) { 1199 case MAC_PROP_DUPLEX: 1200 *(link_duplex_t *)val = lc->link_ok ? LINK_DUPLEX_FULL : 1201 LINK_DUPLEX_UNKNOWN; 1202 break; 1203 1204 case MAC_PROP_SPEED: 1205 if (lc->link_ok != 0) { 1206 *(uint64_t *)val = lc->speed; 1207 *(uint64_t *)val *= 1000000; 1208 } else 1209 *(uint64_t *)val = 0; 1210 break; 1211 1212 case MAC_PROP_STATUS: 1213 *(link_state_t *)val = lc->link_ok ? LINK_STATE_UP : 1214 LINK_STATE_DOWN; 1215 break; 1216 1217 case MAC_PROP_AUTONEG: 1218 *u = lc->autoneg == AUTONEG_ENABLE; 1219 break; 1220 1221 case MAC_PROP_MTU: 1222 *(uint32_t *)val = pi->mtu; 1223 break; 1224 1225 case MAC_PROP_FLOWCTRL: 1226 if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) == 1227 (PAUSE_TX | PAUSE_RX)) 1228 *(link_flowctrl_t *)val = LINK_FLOWCTRL_BI; 1229 else if (lc->requested_fc & PAUSE_TX) 1230 *(link_flowctrl_t *)val = LINK_FLOWCTRL_TX; 1231 else if (lc->requested_fc & PAUSE_RX) 1232 *(link_flowctrl_t *)val = LINK_FLOWCTRL_RX; 1233 else 1234 *(link_flowctrl_t *)val = LINK_FLOWCTRL_NONE; 1235 break; 1236 1237 case MAC_PROP_ADV_FEC_CAP: 1238 if (!fec_supported(lc->pcaps)) 1239 return (ENOTSUP); 1240 1241 *(link_fec_t *)val = fec_to_link_fec(lc->fec); 1242 break; 1243 1244 case MAC_PROP_EN_FEC_CAP: 1245 if (!fec_supported(lc->pcaps)) 1246 return (ENOTSUP); 1247 1248 *(link_fec_t *)val = fec_to_link_fec(lc->requested_fec); 1249 break; 1250 1251 case MAC_PROP_ADV_100GFDX_CAP: 1252 case MAC_PROP_EN_100GFDX_CAP: 1253 *u = !!(lc->acaps & FW_PORT_CAP32_SPEED_100G); 1254 break; 1255 1256 case MAC_PROP_ADV_40GFDX_CAP: 1257 case MAC_PROP_EN_40GFDX_CAP: 1258 *u = !!(lc->acaps & FW_PORT_CAP32_SPEED_40G); 1259 break; 1260 1261 case MAC_PROP_ADV_25GFDX_CAP: 1262 case MAC_PROP_EN_25GFDX_CAP: 1263 *u = !!(lc->acaps & FW_PORT_CAP32_SPEED_25G); 1264 break; 1265 1266 case MAC_PROP_ADV_10GFDX_CAP: 1267 case MAC_PROP_EN_10GFDX_CAP: 1268 *u = !!(lc->acaps & FW_PORT_CAP32_SPEED_10G); 1269 break; 1270 1271 case MAC_PROP_ADV_1000FDX_CAP: 1272 case MAC_PROP_EN_1000FDX_CAP: 1273 *u = !!(lc->acaps & FW_PORT_CAP32_SPEED_1G); 1274 break; 1275 1276 case MAC_PROP_ADV_100FDX_CAP: 1277 case MAC_PROP_EN_100FDX_CAP: 1278 *u = !!(lc->acaps & FW_PORT_CAP32_SPEED_100M); 1279 break; 1280 1281 case MAC_PROP_PRIVATE: 1282 return (getprop(pi, name, size, val)); 1283 1284 default: 1285 return (ENOTSUP); 1286 } 1287 1288 return (0); 1289 } 1290 1291 static void 1292 t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id, 1293 mac_prop_info_handle_t ph) 1294 { 1295 struct port_info *pi = arg; 1296 struct link_config *lc = &pi->link_cfg; 1297 1298 switch (id) { 1299 case MAC_PROP_DUPLEX: 1300 case MAC_PROP_SPEED: 1301 case MAC_PROP_STATUS: 1302 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 1303 break; 1304 1305 case MAC_PROP_AUTONEG: 1306 if (lc->pcaps & FW_PORT_CAP32_ANEG) 1307 mac_prop_info_set_default_uint8(ph, 1); 1308 else 1309 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 1310 break; 1311 1312 case MAC_PROP_MTU: 1313 mac_prop_info_set_range_uint32(ph, 46, MAX_MTU); 1314 break; 1315 1316 case MAC_PROP_FLOWCTRL: 1317 mac_prop_info_set_default_link_flowctrl(ph, LINK_FLOWCTRL_BI); 1318 break; 1319 1320 case MAC_PROP_EN_FEC_CAP: 1321 mac_prop_info_set_default_fec(ph, LINK_FEC_AUTO); 1322 break; 1323 1324 case MAC_PROP_ADV_FEC_CAP: 1325 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 1326 mac_prop_info_set_default_fec(ph, LINK_FEC_AUTO); 1327 break; 1328 1329 case MAC_PROP_EN_10GFDX_CAP: 1330 if (lc->pcaps & FW_PORT_CAP32_ANEG && 1331 lc->pcaps & FW_PORT_CAP32_SPEED_10G) 1332 mac_prop_info_set_default_uint8(ph, 1); 1333 else 1334 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 1335 break; 1336 1337 case MAC_PROP_EN_1000FDX_CAP: 1338 if (lc->pcaps & FW_PORT_CAP32_ANEG && 1339 lc->pcaps & FW_PORT_CAP32_SPEED_1G) 1340 mac_prop_info_set_default_uint8(ph, 1); 1341 else 1342 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 1343 break; 1344 1345 case MAC_PROP_EN_100FDX_CAP: 1346 if (lc->pcaps & FW_PORT_CAP32_ANEG && 1347 lc->pcaps & FW_PORT_CAP32_SPEED_100M) 1348 mac_prop_info_set_default_uint8(ph, 1); 1349 else 1350 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 1351 break; 1352 1353 case MAC_PROP_ADV_10GFDX_CAP: 1354 case MAC_PROP_ADV_1000FDX_CAP: 1355 case MAC_PROP_ADV_100FDX_CAP: 1356 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 1357 break; 1358 1359 case MAC_PROP_PRIVATE: 1360 propinfo(pi, name, ph); 1361 break; 1362 1363 default: 1364 break; 1365 } 1366 } 1367 1368 int 1369 begin_synchronized_op(struct port_info *pi, int hold, int waitok) 1370 { 1371 struct adapter *sc = pi->adapter; 1372 int rc = 0; 1373 1374 ADAPTER_LOCK(sc); 1375 while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 1376 if (!waitok) { 1377 rc = EBUSY; 1378 goto failed; 1379 } else if (cv_wait_sig(&sc->cv, &sc->lock) == 0) { 1380 rc = EINTR; 1381 goto failed; 1382 } 1383 } 1384 if (IS_DOOMED(pi) != 0) { /* shouldn't happen on Solaris */ 1385 rc = ENXIO; 1386 goto failed; 1387 } 1388 ASSERT(!IS_BUSY(sc)); 1389 /* LINTED: E_CONSTANT_CONDITION */ 1390 SET_BUSY(sc); 1391 1392 if (!hold) 1393 ADAPTER_UNLOCK(sc); 1394 1395 return (0); 1396 failed: 1397 ADAPTER_UNLOCK(sc); 1398 return (rc); 1399 } 1400 1401 void 1402 end_synchronized_op(struct port_info *pi, int held) 1403 { 1404 struct adapter *sc = pi->adapter; 1405 1406 if (!held) 1407 ADAPTER_LOCK(sc); 1408 1409 ADAPTER_LOCK_ASSERT_OWNED(sc); 1410 ASSERT(IS_BUSY(sc)); 1411 /* LINTED: E_CONSTANT_CONDITION */ 1412 CLR_BUSY(sc); 1413 cv_signal(&sc->cv); 1414 ADAPTER_UNLOCK(sc); 1415 } 1416 1417 static int 1418 t4_init_synchronized(struct port_info *pi) 1419 { 1420 struct adapter *sc = pi->adapter; 1421 int rc = 0; 1422 1423 ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1424 1425 if (isset(&sc->open_device_map, pi->port_id) != 0) 1426 return (0); /* already running */ 1427 1428 if (!(sc->flags & FULL_INIT_DONE) && 1429 ((rc = adapter_full_init(sc)) != 0)) 1430 return (rc); /* error message displayed already */ 1431 1432 if (!(pi->flags & PORT_INIT_DONE)) { 1433 rc = port_full_init(pi); 1434 if (rc != 0) 1435 return (rc); /* error message displayed already */ 1436 } else 1437 enable_port_queues(pi); 1438 1439 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, pi->mtu, 0, 0, 1, 0, false); 1440 if (rc != 0) { 1441 cxgb_printf(pi->dip, CE_WARN, "set_rxmode failed: %d", rc); 1442 goto done; 1443 } 1444 rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 1445 pi->hw_addr, true, &pi->smt_idx); 1446 if (rc < 0) { 1447 cxgb_printf(pi->dip, CE_WARN, "change_mac failed: %d", rc); 1448 rc = -rc; 1449 goto done; 1450 } else 1451 /* LINTED: E_ASSIGN_NARROW_CONV */ 1452 pi->xact_addr_filt = rc; 1453 1454 rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 1455 if (rc != 0) { 1456 cxgb_printf(pi->dip, CE_WARN, "start_link failed: %d", rc); 1457 goto done; 1458 } 1459 1460 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 1461 if (rc != 0) { 1462 cxgb_printf(pi->dip, CE_WARN, "enable_vi failed: %d", rc); 1463 goto done; 1464 } 1465 1466 /* all ok */ 1467 setbit(&sc->open_device_map, pi->port_id); 1468 done: 1469 if (rc != 0) 1470 (void) t4_uninit_synchronized(pi); 1471 1472 return (rc); 1473 } 1474 1475 /* 1476 * Idempotent. 1477 */ 1478 static int 1479 t4_uninit_synchronized(struct port_info *pi) 1480 { 1481 struct adapter *sc = pi->adapter; 1482 int rc; 1483 1484 ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1485 1486 /* 1487 * Disable the VI so that all its data in either direction is discarded 1488 * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 1489 * tick) intact as the TP can deliver negative advice or data that it's 1490 * holding in its RAM (for an offloaded connection) even after the VI is 1491 * disabled. 1492 */ 1493 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 1494 if (rc != 0) { 1495 cxgb_printf(pi->dip, CE_WARN, "disable_vi failed: %d", rc); 1496 return (rc); 1497 } 1498 1499 disable_port_queues(pi); 1500 1501 clrbit(&sc->open_device_map, pi->port_id); 1502 1503 pi->link_cfg.link_ok = 0; 1504 pi->link_cfg.speed = 0; 1505 mac_link_update(pi->mh, LINK_STATE_UNKNOWN); 1506 1507 return (0); 1508 } 1509 1510 static void 1511 propinfo(struct port_info *pi, const char *name, mac_prop_info_handle_t ph) 1512 { 1513 struct adapter *sc = pi->adapter; 1514 struct driver_properties *p = &sc->props; 1515 struct link_config *lc = &pi->link_cfg; 1516 int v; 1517 char str[16]; 1518 1519 if (strcmp(name, T4PROP_TMR_IDX) == 0) 1520 v = is_10G_port(pi) ? p->tmr_idx_10g : p->tmr_idx_1g; 1521 else if (strcmp(name, T4PROP_PKTC_IDX) == 0) 1522 v = is_10G_port(pi) ? p->pktc_idx_10g : p->pktc_idx_1g; 1523 else if (strcmp(name, T4PROP_HW_CSUM) == 0) 1524 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0; 1525 else if (strcmp(name, T4PROP_HW_LSO) == 0) 1526 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0; 1527 else if (strcmp(name, T4PROP_TX_PAUSE) == 0) 1528 v = (lc->fc & PAUSE_TX) ? 1 : 0; 1529 else if (strcmp(name, T4PROP_RX_PAUSE) == 0) 1530 v = (lc->fc & PAUSE_RX) ? 1 : 0; 1531 #if MAC_VERSION == 1 1532 else if (strcmp(name, T4PROP_MTU) == 0) 1533 v = ETHERMTU; 1534 #endif 1535 else 1536 return; 1537 1538 (void) snprintf(str, sizeof (str), "%d", v); 1539 mac_prop_info_set_default_str(ph, str); 1540 } 1541 1542 static int 1543 getprop(struct port_info *pi, const char *name, uint_t size, void *val) 1544 { 1545 struct link_config *lc = &pi->link_cfg; 1546 int v; 1547 1548 if (strcmp(name, T4PROP_TMR_IDX) == 0) 1549 v = pi->tmr_idx; 1550 else if (strcmp(name, T4PROP_PKTC_IDX) == 0) 1551 v = pi->pktc_idx; 1552 else if (strcmp(name, T4PROP_HW_CSUM) == 0) 1553 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0; 1554 else if (strcmp(name, T4PROP_HW_LSO) == 0) 1555 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0; 1556 else if (strcmp(name, T4PROP_TX_PAUSE) == 0) 1557 v = (lc->fc & PAUSE_TX) ? 1 : 0; 1558 else if (strcmp(name, T4PROP_RX_PAUSE) == 0) 1559 v = (lc->fc & PAUSE_RX) ? 1 : 0; 1560 #if MAC_VERSION == 1 1561 else if (strcmp(name, T4PROP_MTU) == 0) 1562 v = pi->mtu; 1563 #endif 1564 else 1565 return (ENOTSUP); 1566 1567 (void) snprintf(val, size, "%d", v); 1568 return (0); 1569 } 1570 1571 static int 1572 setprop(struct port_info *pi, const char *name, const void *val) 1573 { 1574 struct adapter *sc = pi->adapter; 1575 long v; 1576 int i, rc = 0, relink = 0, rx_mode = 0; 1577 struct sge_rxq *rxq; 1578 struct link_config lc_old, *lc = &pi->link_cfg; 1579 1580 /* 1581 * Save a copy of link_config. This can be used to restore link_config 1582 * if t4_link_l1cfg() fails. 1583 */ 1584 bcopy(lc, &lc_old, sizeof (struct link_config)); 1585 1586 (void) ddi_strtol(val, NULL, 0, &v); 1587 1588 if (strcmp(name, T4PROP_TMR_IDX) == 0) { 1589 if (v < 0 || v >= SGE_NTIMERS) 1590 return (EINVAL); 1591 if (v == pi->tmr_idx) 1592 return (0); 1593 1594 /* LINTED: E_ASSIGN_NARROW_CONV */ 1595 pi->tmr_idx = v; 1596 for_each_rxq(pi, i, rxq) { 1597 rxq->iq.intr_params = V_QINTR_TIMER_IDX(v) | 1598 V_QINTR_CNT_EN(pi->pktc_idx >= 0); 1599 } 1600 1601 } else if (strcmp(name, T4PROP_PKTC_IDX) == 0) { 1602 if (v >= SGE_NCOUNTERS) 1603 return (EINVAL); 1604 if (v == pi->pktc_idx || (v < 0 && pi->pktc_idx == -1)) 1605 return (0); 1606 1607 /* LINTED: E_ASSIGN_NARROW_CONV */ 1608 pi->pktc_idx = v < 0 ? -1 : v; 1609 for_each_rxq(pi, i, rxq) { 1610 rxq->iq.intr_params = V_QINTR_TIMER_IDX(pi->tmr_idx) | 1611 /* takes effect right away */ 1612 V_QINTR_CNT_EN(v >= 0); 1613 /* LINTED: E_ASSIGN_NARROW_CONV */ 1614 rxq->iq.intr_pktc_idx = v; /* this needs fresh plumb */ 1615 } 1616 } else if (strcmp(name, T4PROP_HW_CSUM) == 0) { 1617 if (v != 0 && v != 1) 1618 return (EINVAL); 1619 if (v == 1) 1620 pi->features |= CXGBE_HW_CSUM; 1621 else 1622 pi->features &= ~CXGBE_HW_CSUM; 1623 } else if (strcmp(name, T4PROP_HW_LSO) == 0) { 1624 if (v != 0 && v != 1) 1625 return (EINVAL); 1626 if (v == 1) 1627 pi->features |= CXGBE_HW_LSO; 1628 else 1629 pi->features &= ~CXGBE_HW_LSO; 1630 } else if (strcmp(name, T4PROP_TX_PAUSE) == 0) { 1631 if (v != 0 && v != 1) 1632 return (EINVAL); 1633 1634 if (v != 0) 1635 lc->requested_fc |= PAUSE_TX; 1636 else 1637 lc->requested_fc &= ~PAUSE_TX; 1638 1639 relink = 1; 1640 1641 } else if (strcmp(name, T4PROP_RX_PAUSE) == 0) { 1642 if (v != 0 && v != 1) 1643 return (EINVAL); 1644 1645 if (v != 0) 1646 lc->requested_fc |= PAUSE_RX; 1647 else 1648 lc->requested_fc &= ~PAUSE_RX; 1649 1650 relink = 1; 1651 } 1652 #if MAC_VERSION == 1 1653 else if (strcmp(name, T4PROP_MTU) == 0) { 1654 if (v < 46 || v > MAX_MTU) 1655 return (EINVAL); 1656 if (v == pi->mtu) 1657 return (0); 1658 1659 pi->mtu = (int)v; 1660 (void) mac_maxsdu_update(pi->mh, v); 1661 rx_mode = 1; 1662 } 1663 #endif 1664 else 1665 return (ENOTSUP); 1666 1667 if (!(relink || rx_mode)) 1668 return (0); 1669 1670 /* If we are here, either relink or rx_mode is 1 */ 1671 if (isset(&sc->open_device_map, pi->port_id) != 0) { 1672 if (relink != 0) { 1673 rc = begin_synchronized_op(pi, 1, 1); 1674 if (rc != 0) 1675 return (rc); 1676 rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc); 1677 end_synchronized_op(pi, 1); 1678 if (rc != 0) { 1679 cxgb_printf(pi->dip, CE_WARN, 1680 "start_link failed:%d", rc); 1681 /* Restore link_config */ 1682 bcopy(&lc_old, lc, sizeof (struct link_config)); 1683 } 1684 } else if (rx_mode != 0) { 1685 rc = begin_synchronized_op(pi, 1, 1); 1686 if (rc != 0) 1687 return (rc); 1688 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v, -1, -1, 1689 -1, -1, false); 1690 end_synchronized_op(pi, 1); 1691 if (rc != 0) { 1692 cxgb_printf(pi->dip, CE_WARN, 1693 "set_rxmode failed: %d", rc); 1694 } 1695 } 1696 return (rc); 1697 } 1698 1699 return (0); 1700 } 1701 1702 void 1703 t4_mc_init(struct port_info *pi) 1704 { 1705 pi->props = t4_priv_props; 1706 } 1707 1708 void 1709 t4_mc_cb_init(struct port_info *pi) 1710 { 1711 if (pi->adapter->props.multi_rings) 1712 pi->mc = &t4_m_ring_callbacks; 1713 else 1714 pi->mc = &t4_m_callbacks; 1715 } 1716 1717 void 1718 t4_os_link_changed(struct adapter *sc, int idx, int link_stat) 1719 { 1720 struct port_info *pi = sc->port[idx]; 1721 1722 mac_link_update(pi->mh, link_stat ? LINK_STATE_UP : LINK_STATE_DOWN); 1723 } 1724 1725 /* ARGSUSED */ 1726 void 1727 t4_mac_rx(struct port_info *pi, struct sge_rxq *rxq, mblk_t *m) 1728 { 1729 mac_rx(pi->mh, NULL, m); 1730 } 1731 1732 void 1733 t4_mac_tx_update(struct port_info *pi, struct sge_txq *txq) 1734 { 1735 if (pi->adapter->props.multi_rings) 1736 mac_tx_ring_update(pi->mh, txq->ring_handle); 1737 else 1738 mac_tx_update(pi->mh); 1739 } 1740