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