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 #include <sys/ddi.h> 24 #include <sys/sunddi.h> 25 #include <sys/dlpi.h> 26 #include <sys/mac_provider.h> 27 #include <sys/mac_ether.h> 28 #include <sys/strsubr.h> 29 #include <sys/queue.h> 30 31 #include "common/common.h" 32 #include "common/t4_regs.h" 33 34 static int t4_mc_getstat(void *arg, uint_t stat, uint64_t *val); 35 static int t4_mc_start(void *arg); 36 static void t4_mc_stop(void *arg); 37 static int t4_mc_setpromisc(void *arg, boolean_t on); 38 static int t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr); 39 static int t4_mc_unicst(void *arg, const uint8_t *ucaddr); 40 static mblk_t *t4_mc_tx(void *arg, mblk_t *m); 41 static boolean_t t4_mc_getcapab(void *arg, mac_capab_t cap, void *data); 42 static int t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id, 43 uint_t size, const void *val); 44 static int t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id, 45 uint_t size, void *val); 46 static void t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id, 47 mac_prop_info_handle_t ph); 48 49 static int begin_synchronized_op(struct port_info *pi, int hold, int waitok); 50 static void end_synchronized_op(struct port_info *pi, int held); 51 static int t4_init_synchronized(struct port_info *pi); 52 static int t4_uninit_synchronized(struct port_info *pi); 53 static void propinfo(struct port_info *pi, const char *name, 54 mac_prop_info_handle_t ph); 55 static int getprop(struct port_info *pi, const char *name, uint_t size, 56 void *val); 57 static int setprop(struct port_info *pi, const char *name, const void *val); 58 59 mac_callbacks_t t4_m_callbacks = { 60 .mc_callbacks = MC_GETCAPAB | MC_PROPERTIES, 61 .mc_getstat = t4_mc_getstat, 62 .mc_start = t4_mc_start, 63 .mc_stop = t4_mc_stop, 64 .mc_setpromisc = t4_mc_setpromisc, 65 .mc_multicst = t4_mc_multicst, 66 .mc_unicst = t4_mc_unicst, 67 .mc_tx = t4_mc_tx, 68 .mc_getcapab = t4_mc_getcapab, 69 .mc_setprop = t4_mc_setprop, 70 .mc_getprop = t4_mc_getprop, 71 .mc_propinfo = t4_mc_propinfo, 72 }; 73 74 #define T4PROP_TMR_IDX "_holdoff_timer_idx" 75 #define T4PROP_PKTC_IDX "_holdoff_pktc_idx" 76 #define T4PROP_MTU "_mtu" 77 #define T4PROP_HW_CSUM "_hw_csum" 78 #define T4PROP_HW_LSO "_hw_lso" 79 #define T4PROP_TX_PAUSE "_tx_pause" 80 #define T4PROP_RX_PAUSE "_rx_pause" 81 82 char *t4_priv_props[] = { 83 T4PROP_TMR_IDX, 84 T4PROP_PKTC_IDX, 85 #if MAC_VERSION == 1 86 /* MAC_VERSION 1 doesn't seem to use MAC_PROP_MTU, hmmmm */ 87 T4PROP_MTU, 88 #endif 89 T4PROP_HW_CSUM, 90 T4PROP_HW_LSO, 91 T4PROP_TX_PAUSE, 92 T4PROP_RX_PAUSE, 93 NULL 94 }; 95 96 static int 97 t4_mc_getstat(void *arg, uint_t stat, uint64_t *val) 98 { 99 struct port_info *pi = arg; 100 struct adapter *sc = pi->adapter; 101 struct link_config *lc = &pi->link_cfg; 102 103 #define GET_STAT(name) \ 104 t4_read_reg64(sc, PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_##name##_L)) 105 106 switch (stat) { 107 case MAC_STAT_IFSPEED: 108 if (lc->link_ok != 0) { 109 *val = lc->speed; 110 *val *= 1000000; 111 } else 112 *val = 0; 113 break; 114 115 case MAC_STAT_MULTIRCV: 116 *val = GET_STAT(RX_PORT_MCAST); 117 break; 118 119 case MAC_STAT_BRDCSTRCV: 120 *val = GET_STAT(RX_PORT_BCAST); 121 break; 122 123 case MAC_STAT_MULTIXMT: 124 *val = GET_STAT(TX_PORT_MCAST); 125 break; 126 127 case MAC_STAT_BRDCSTXMT: 128 *val = GET_STAT(TX_PORT_BCAST); 129 break; 130 131 case MAC_STAT_NORCVBUF: 132 *val = 0; /* TODO should come from rxq->nomem */ 133 break; 134 135 case MAC_STAT_IERRORS: 136 *val = GET_STAT(RX_PORT_MTU_ERROR) + 137 GET_STAT(RX_PORT_MTU_CRC_ERROR) + 138 GET_STAT(RX_PORT_CRC_ERROR) + 139 GET_STAT(RX_PORT_LEN_ERROR) + 140 GET_STAT(RX_PORT_SYM_ERROR) + 141 GET_STAT(RX_PORT_LESS_64B); 142 break; 143 144 case MAC_STAT_UNKNOWNS: 145 return (ENOTSUP); 146 147 case MAC_STAT_NOXMTBUF: 148 *val = GET_STAT(TX_PORT_DROP); 149 break; 150 151 case MAC_STAT_OERRORS: 152 *val = GET_STAT(TX_PORT_ERROR); 153 break; 154 155 case MAC_STAT_COLLISIONS: 156 return (ENOTSUP); 157 158 case MAC_STAT_RBYTES: 159 *val = GET_STAT(RX_PORT_BYTES); 160 break; 161 162 case MAC_STAT_IPACKETS: 163 *val = GET_STAT(RX_PORT_FRAMES); 164 break; 165 166 case MAC_STAT_OBYTES: 167 *val = GET_STAT(TX_PORT_BYTES); 168 break; 169 170 case MAC_STAT_OPACKETS: 171 *val = GET_STAT(TX_PORT_FRAMES); 172 break; 173 174 case ETHER_STAT_ALIGN_ERRORS: 175 return (ENOTSUP); 176 177 case ETHER_STAT_FCS_ERRORS: 178 *val = GET_STAT(RX_PORT_CRC_ERROR); 179 break; 180 181 case ETHER_STAT_FIRST_COLLISIONS: 182 case ETHER_STAT_MULTI_COLLISIONS: 183 case ETHER_STAT_SQE_ERRORS: 184 case ETHER_STAT_DEFER_XMTS: 185 case ETHER_STAT_TX_LATE_COLLISIONS: 186 case ETHER_STAT_EX_COLLISIONS: 187 return (ENOTSUP); 188 189 case ETHER_STAT_MACXMT_ERRORS: 190 *val = GET_STAT(TX_PORT_ERROR); 191 break; 192 193 case ETHER_STAT_CARRIER_ERRORS: 194 return (ENOTSUP); 195 196 case ETHER_STAT_TOOLONG_ERRORS: 197 *val = GET_STAT(RX_PORT_MTU_ERROR); 198 break; 199 200 case ETHER_STAT_MACRCV_ERRORS: 201 *val = GET_STAT(RX_PORT_MTU_ERROR) + 202 GET_STAT(RX_PORT_MTU_CRC_ERROR) + 203 GET_STAT(RX_PORT_CRC_ERROR) + 204 GET_STAT(RX_PORT_LEN_ERROR) + 205 GET_STAT(RX_PORT_SYM_ERROR) + 206 GET_STAT(RX_PORT_LESS_64B); 207 break; 208 209 case ETHER_STAT_XCVR_ADDR: 210 case ETHER_STAT_XCVR_ID: 211 case ETHER_STAT_XCVR_INUSE: 212 return (ENOTSUP); 213 214 case ETHER_STAT_CAP_1000FDX: 215 *val = !!(lc->supported & FW_PORT_CAP_SPEED_1G); 216 break; 217 218 case ETHER_STAT_CAP_1000HDX: 219 return (ENOTSUP); 220 221 case ETHER_STAT_CAP_100FDX: 222 *val = !!(lc->supported & FW_PORT_CAP_SPEED_100M); 223 break; 224 225 case ETHER_STAT_CAP_100HDX: 226 return (ENOTSUP); 227 228 case ETHER_STAT_CAP_10FDX: 229 case ETHER_STAT_CAP_10HDX: 230 return (ENOTSUP); 231 232 case ETHER_STAT_CAP_ASMPAUSE: 233 *val = 0; 234 break; 235 236 case ETHER_STAT_CAP_PAUSE: 237 *val = 1; 238 break; 239 240 case ETHER_STAT_CAP_AUTONEG: 241 *val = !!(lc->supported & FW_PORT_CAP_ANEG); 242 break; 243 244 /* 245 * We have set flow control configuration based on tx_pause and rx_pause 246 * values supported through ndd. Now, we need to translate the settings 247 * we have in link_config structure to adv_cap_asmpause and 248 * adv_cap_pause. 249 * 250 * There are 4 combinations possible and the translation is as below: 251 * tx_pause = 0 => We don't send pause frames during Rx congestion 252 * tx_pause = 1 => We send pause frames during Rx congestion 253 * rx_pause = 0 => We ignore received pause frames 254 * rx_pause = 1 => We pause transmission when we receive pause frames 255 * 256 * +----------------------------+----------------------------------+ 257 * | tx_pause | rx_pause | adv_cap_asmpause | adv_cap_pause | 258 * +-------------------------+-------------------------------------+ 259 * | 0 | 0 | 0 | 0 | 260 * | 0 | 1 | 1 | 0 | 261 * | 1 | 0 | 1 | 1 | 262 * | 1 | 1 | 0 | 1 | 263 * +----------------------------+----------------------------------+ 264 */ 265 266 /* Advertised asymmetric pause capability */ 267 case ETHER_STAT_ADV_CAP_ASMPAUSE: 268 *val = (((lc->requested_fc & PAUSE_TX) ? 1 : 0) ^ 269 (lc->requested_fc & PAUSE_RX)); 270 break; 271 272 /* Advertised pause capability */ 273 case ETHER_STAT_ADV_CAP_PAUSE: 274 *val = (lc->requested_fc & PAUSE_TX) ? 1 : 0; 275 break; 276 277 case ETHER_STAT_ADV_CAP_1000FDX: 278 case ETHER_STAT_ADV_CAP_1000HDX: 279 case ETHER_STAT_ADV_CAP_100FDX: 280 case ETHER_STAT_ADV_CAP_100HDX: 281 case ETHER_STAT_ADV_CAP_10FDX: 282 case ETHER_STAT_ADV_CAP_10HDX: 283 case ETHER_STAT_ADV_CAP_AUTONEG: 284 return (ENOTSUP); /* TODO */ 285 286 case ETHER_STAT_LP_CAP_1000FDX: 287 case ETHER_STAT_LP_CAP_1000HDX: 288 case ETHER_STAT_LP_CAP_100FDX: 289 case ETHER_STAT_LP_CAP_100HDX: 290 case ETHER_STAT_LP_CAP_10FDX: 291 case ETHER_STAT_LP_CAP_10HDX: 292 case ETHER_STAT_LP_CAP_ASMPAUSE: 293 case ETHER_STAT_LP_CAP_PAUSE: 294 case ETHER_STAT_LP_CAP_AUTONEG: 295 return (ENOTSUP); 296 297 case ETHER_STAT_LINK_ASMPAUSE: 298 *val = 0; 299 break; 300 301 case ETHER_STAT_LINK_PAUSE: 302 *val = 1; 303 break; 304 305 case ETHER_STAT_LINK_AUTONEG: 306 *val = lc->autoneg == AUTONEG_ENABLE; 307 break; 308 309 case ETHER_STAT_LINK_DUPLEX: 310 if (lc->link_ok != 0) 311 *val = LINK_DUPLEX_FULL; 312 else 313 *val = LINK_DUPLEX_UNKNOWN; 314 break; 315 316 default: 317 #ifdef DEBUG 318 cxgb_printf(pi->dip, CE_NOTE, "stat %d not implemented.", stat); 319 #endif 320 return (ENOTSUP); 321 } 322 #undef GET_STAT 323 324 return (0); 325 } 326 327 static int 328 t4_mc_start(void *arg) 329 { 330 struct port_info *pi = arg; 331 int rc; 332 333 rc = begin_synchronized_op(pi, 0, 1); 334 if (rc != 0) 335 return (rc); 336 rc = t4_init_synchronized(pi); 337 end_synchronized_op(pi, 0); 338 339 return (rc); 340 } 341 342 static void 343 t4_mc_stop(void *arg) 344 { 345 struct port_info *pi = arg; 346 347 while (begin_synchronized_op(pi, 0, 1) != 0) 348 continue; 349 (void) t4_uninit_synchronized(pi); 350 end_synchronized_op(pi, 0); 351 } 352 353 static int 354 t4_mc_setpromisc(void *arg, boolean_t on) 355 { 356 struct port_info *pi = arg; 357 struct adapter *sc = pi->adapter; 358 int rc; 359 360 rc = begin_synchronized_op(pi, 1, 1); 361 if (rc != 0) 362 return (rc); 363 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, -1, on ? 1 : 0, -1, -1, -1, 364 false); 365 end_synchronized_op(pi, 1); 366 367 return (rc); 368 } 369 370 /* 371 * TODO: Starts failing as soon as the 336 entry table fills up. Need to use 372 * hash in that case. 373 */ 374 static int 375 t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr) 376 { 377 struct port_info *pi = arg; 378 struct adapter *sc = pi->adapter; 379 struct fw_vi_mac_cmd c; 380 int len16, rc; 381 382 len16 = howmany(sizeof (c.op_to_viid) + sizeof (c.freemacs_to_len16) + 383 sizeof (c.u.exact[0]), 16); 384 c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST | 385 F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(pi->viid)); 386 c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(len16)); 387 c.u.exact[0].valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID | 388 V_FW_VI_MAC_CMD_IDX(add ? FW_VI_MAC_ADD_MAC : 389 FW_VI_MAC_MAC_BASED_FREE)); 390 bcopy(mcaddr, &c.u.exact[0].macaddr, ETHERADDRL); 391 392 rc = begin_synchronized_op(pi, 1, 1); 393 if (rc != 0) 394 return (rc); 395 rc = -t4_wr_mbox_meat(sc, sc->mbox, &c, len16 * 16, &c, true); 396 end_synchronized_op(pi, 1); 397 if (rc != 0) 398 return (rc); 399 #ifdef DEBUG 400 /* 401 * TODO: Firmware doesn't seem to return the correct index on removal 402 * (it gives back 0x3fd FW_VI_MAC_MAC_BASED_FREE unchanged. Remove this 403 * code once it is fixed. 404 */ 405 else { 406 uint16_t idx; 407 408 idx = G_FW_VI_MAC_CMD_IDX(ntohs(c.u.exact[0].valid_to_idx)); 409 cxgb_printf(pi->dip, CE_NOTE, 410 "%02x:%02x:%02x:%02x:%02x:%02x %s %d", mcaddr[0], 411 mcaddr[1], mcaddr[2], mcaddr[3], mcaddr[4], mcaddr[5], 412 add ? "added at index" : "removed from index", idx); 413 } 414 #endif 415 416 return (0); 417 } 418 419 static int 420 t4_mc_unicst(void *arg, const uint8_t *ucaddr) 421 { 422 struct port_info *pi = arg; 423 struct adapter *sc = pi->adapter; 424 int rc; 425 426 rc = begin_synchronized_op(pi, 1, 1); 427 if (rc != 0) 428 return (rc); 429 rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, ucaddr, 430 true, true); 431 if (rc < 0) 432 rc = -rc; 433 else { 434 /* LINTED: E_CONSTANT_CONDITION */ 435 pi->xact_addr_filt = rc; 436 rc = 0; 437 } 438 end_synchronized_op(pi, 1); 439 440 return (rc); 441 } 442 443 static mblk_t * 444 t4_mc_tx(void *arg, mblk_t *m) 445 { 446 struct port_info *pi = arg; 447 struct adapter *sc = pi->adapter; 448 struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 449 450 return (t4_eth_tx(pi, txq, m)); 451 } 452 453 static boolean_t 454 t4_mc_getcapab(void *arg, mac_capab_t cap, void *data) 455 { 456 struct port_info *pi = arg; 457 boolean_t status = B_TRUE; 458 459 switch (cap) { 460 case MAC_CAPAB_HCKSUM: 461 if (pi->features & CXGBE_HW_CSUM) { 462 uint32_t *d = data; 463 *d = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM; 464 } else 465 status = B_FALSE; 466 break; 467 468 case MAC_CAPAB_LSO: 469 /* Enabling LSO requires Checksum offloading */ 470 if (pi->features & CXGBE_HW_LSO && 471 pi->features & CXGBE_HW_CSUM) { 472 mac_capab_lso_t *d = data; 473 474 d->lso_flags = LSO_TX_BASIC_TCP_IPV4; 475 d->lso_basic_tcp_ipv4.lso_max = 65535; 476 } else 477 status = B_FALSE; 478 break; 479 480 default: 481 status = B_FALSE; /* cap not supported */ 482 } 483 484 return (status); 485 } 486 487 /* ARGSUSED */ 488 static int 489 t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t size, 490 const void *val) 491 { 492 struct port_info *pi = arg; 493 struct adapter *sc = pi->adapter; 494 struct link_config lc_copy, *lc = &pi->link_cfg; 495 uint8_t v8 = *(uint8_t *)val; 496 uint32_t v32 = *(uint32_t *)val; 497 int old, new = 0, relink = 0, rx_mode = 0, rc = 0; 498 link_flowctrl_t fc; 499 500 /* 501 * Save a copy of link_config. This can be used to restore link_config 502 * if t4_link_start() fails. 503 */ 504 bcopy(lc, &lc_copy, sizeof (struct link_config)); 505 506 switch (id) { 507 case MAC_PROP_AUTONEG: 508 if (lc->supported & FW_PORT_CAP_ANEG) { 509 old = lc->autoneg; 510 new = v8 ? AUTONEG_ENABLE : AUTONEG_DISABLE; 511 if (old != new) { 512 /* LINTED: E_CONSTANT_CONDITION */ 513 lc->autoneg = new; 514 relink = 1; 515 if (new == AUTONEG_DISABLE) { 516 /* Only 100M is available */ 517 lc->requested_speed = 518 FW_PORT_CAP_SPEED_100M; 519 lc->advertising = 520 FW_PORT_CAP_SPEED_100M; 521 } else { 522 /* 523 * Advertise autonegotiation capability 524 * along with supported speeds 525 */ 526 lc->advertising |= (FW_PORT_CAP_ANEG | 527 (lc->supported & 528 (FW_PORT_CAP_SPEED_100M | 529 FW_PORT_CAP_SPEED_1G))); 530 lc->requested_speed = 0; 531 } 532 } 533 } else 534 rc = ENOTSUP; 535 break; 536 537 case MAC_PROP_MTU: 538 if (v32 < 46 || v32 > MAX_MTU) { 539 rc = EINVAL; 540 } else if (v32 != pi->mtu) { 541 pi->mtu = v32; 542 (void) mac_maxsdu_update(pi->mh, v32); 543 rx_mode = 1; 544 } 545 546 break; 547 548 case MAC_PROP_FLOWCTRL: 549 fc = *(link_flowctrl_t *)val; 550 old = lc->requested_fc & (PAUSE_TX | PAUSE_RX); 551 552 if (fc == LINK_FLOWCTRL_BI) 553 new = (PAUSE_TX | PAUSE_RX); 554 else if (fc == LINK_FLOWCTRL_TX) 555 new = PAUSE_TX; 556 else if (fc == LINK_FLOWCTRL_RX) 557 new = PAUSE_RX; 558 559 if (new != old) { 560 lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX); 561 lc->requested_fc |= new; 562 relink = 1; 563 } 564 break; 565 566 case MAC_PROP_EN_10GFDX_CAP: 567 if (lc->supported & FW_PORT_CAP_ANEG && is_10G_port(pi)) { 568 old = lc->advertising & FW_PORT_CAP_SPEED_10G; 569 new = v8 ? FW_PORT_CAP_SPEED_10G : 0; 570 if (new != old) { 571 lc->advertising &= ~FW_PORT_CAP_SPEED_10G; 572 lc->advertising |= new; 573 relink = 1; 574 } 575 } else 576 rc = ENOTSUP; 577 578 break; 579 580 case MAC_PROP_EN_1000FDX_CAP: 581 /* Forced 1G */ 582 if (lc->autoneg == AUTONEG_ENABLE) { 583 old = lc->advertising & FW_PORT_CAP_SPEED_1G; 584 new = v8 ? FW_PORT_CAP_SPEED_1G : 0; 585 586 if (old != new) { 587 lc->advertising &= ~FW_PORT_CAP_SPEED_1G; 588 lc->advertising |= new; 589 relink = 1; 590 } 591 } else 592 rc = ENOTSUP; 593 break; 594 595 case MAC_PROP_EN_100FDX_CAP: 596 /* Forced 100M */ 597 if (lc->autoneg == AUTONEG_ENABLE) { 598 old = lc->advertising & FW_PORT_CAP_SPEED_100M; 599 new = v8 ? FW_PORT_CAP_SPEED_100M : 0; 600 if (old != new) { 601 lc->advertising &= ~FW_PORT_CAP_SPEED_100M; 602 lc->advertising |= new; 603 relink = 1; 604 } 605 } else 606 rc = ENOTSUP; 607 break; 608 609 case MAC_PROP_PRIVATE: 610 rc = setprop(pi, name, val); 611 break; 612 613 default: 614 rc = ENOTSUP; 615 } 616 617 if (isset(&sc->open_device_map, pi->port_id) != 0) { 618 if (relink != 0) { 619 t4_os_link_changed(pi->adapter, pi->port_id, 0); 620 rc = begin_synchronized_op(pi, 1, 1); 621 if (rc != 0) 622 return (rc); 623 rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, 624 &pi->link_cfg); 625 end_synchronized_op(pi, 1); 626 if (rc != 0) { 627 cxgb_printf(pi->dip, CE_WARN, 628 "start_link failed:%d", rc); 629 630 /* Restore link_config */ 631 bcopy(&lc_copy, lc, 632 sizeof (struct link_config)); 633 } 634 } 635 636 if (rx_mode != 0) { 637 rc = begin_synchronized_op(pi, 1, 1); 638 if (rc != 0) 639 return (rc); 640 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v32, -1, 641 -1, -1, -1, false); 642 end_synchronized_op(pi, 1); 643 if (rc != 0) { 644 cxgb_printf(pi->dip, CE_WARN, 645 "set_rxmode failed: %d", rc); 646 } 647 } 648 } 649 650 return (rc); 651 } 652 653 static int 654 t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t size, 655 void *val) 656 { 657 struct port_info *pi = arg; 658 struct link_config *lc = &pi->link_cfg; 659 uint8_t *u = val; 660 661 switch (id) { 662 case MAC_PROP_DUPLEX: 663 *(link_duplex_t *)val = lc->link_ok ? LINK_DUPLEX_FULL : 664 LINK_DUPLEX_UNKNOWN; 665 break; 666 667 case MAC_PROP_SPEED: 668 if (lc->link_ok != 0) { 669 *(uint64_t *)val = lc->speed; 670 *(uint64_t *)val *= 1000000; 671 } else 672 *(uint64_t *)val = 0; 673 break; 674 675 case MAC_PROP_STATUS: 676 *(link_state_t *)val = lc->link_ok ? LINK_STATE_UP : 677 LINK_STATE_DOWN; 678 break; 679 680 case MAC_PROP_AUTONEG: 681 *u = lc->autoneg == AUTONEG_ENABLE; 682 break; 683 684 case MAC_PROP_MTU: 685 *(uint32_t *)val = pi->mtu; 686 break; 687 688 case MAC_PROP_FLOWCTRL: 689 if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) == 690 (PAUSE_TX | PAUSE_RX)) 691 *(link_flowctrl_t *)val = LINK_FLOWCTRL_BI; 692 else if (lc->requested_fc & PAUSE_TX) 693 *(link_flowctrl_t *)val = LINK_FLOWCTRL_TX; 694 else if (lc->requested_fc & PAUSE_RX) 695 *(link_flowctrl_t *)val = LINK_FLOWCTRL_RX; 696 else 697 *(link_flowctrl_t *)val = LINK_FLOWCTRL_NONE; 698 break; 699 700 case MAC_PROP_ADV_10GFDX_CAP: 701 case MAC_PROP_EN_10GFDX_CAP: 702 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_10G); 703 break; 704 705 case MAC_PROP_ADV_1000FDX_CAP: 706 case MAC_PROP_EN_1000FDX_CAP: 707 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_1G); 708 break; 709 710 case MAC_PROP_ADV_100FDX_CAP: 711 case MAC_PROP_EN_100FDX_CAP: 712 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_100M); 713 break; 714 715 case MAC_PROP_PRIVATE: 716 return (getprop(pi, name, size, val)); 717 718 default: 719 return (ENOTSUP); 720 } 721 722 return (0); 723 } 724 725 static void 726 t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id, 727 mac_prop_info_handle_t ph) 728 { 729 struct port_info *pi = arg; 730 struct link_config *lc = &pi->link_cfg; 731 732 switch (id) { 733 case MAC_PROP_DUPLEX: 734 case MAC_PROP_SPEED: 735 case MAC_PROP_STATUS: 736 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 737 break; 738 739 case MAC_PROP_AUTONEG: 740 if (lc->supported & FW_PORT_CAP_ANEG) 741 mac_prop_info_set_default_uint8(ph, 1); 742 else 743 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 744 break; 745 746 case MAC_PROP_MTU: 747 mac_prop_info_set_range_uint32(ph, 46, MAX_MTU); 748 break; 749 750 case MAC_PROP_FLOWCTRL: 751 mac_prop_info_set_default_link_flowctrl(ph, LINK_FLOWCTRL_BI); 752 break; 753 754 case MAC_PROP_EN_10GFDX_CAP: 755 if (lc->supported & FW_PORT_CAP_ANEG && 756 lc->supported & FW_PORT_CAP_SPEED_10G) 757 mac_prop_info_set_default_uint8(ph, 1); 758 else 759 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 760 break; 761 762 case MAC_PROP_EN_1000FDX_CAP: 763 if (lc->supported & FW_PORT_CAP_ANEG && 764 lc->supported & FW_PORT_CAP_SPEED_1G) 765 mac_prop_info_set_default_uint8(ph, 1); 766 else 767 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 768 break; 769 770 case MAC_PROP_EN_100FDX_CAP: 771 if (lc->supported & FW_PORT_CAP_ANEG && 772 lc->supported & FW_PORT_CAP_SPEED_100M) 773 mac_prop_info_set_default_uint8(ph, 1); 774 else 775 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 776 break; 777 778 case MAC_PROP_ADV_10GFDX_CAP: 779 case MAC_PROP_ADV_1000FDX_CAP: 780 case MAC_PROP_ADV_100FDX_CAP: 781 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ); 782 break; 783 784 case MAC_PROP_PRIVATE: 785 propinfo(pi, name, ph); 786 break; 787 788 default: 789 break; 790 } 791 } 792 793 static int 794 begin_synchronized_op(struct port_info *pi, int hold, int waitok) 795 { 796 struct adapter *sc = pi->adapter; 797 int rc = 0; 798 799 ADAPTER_LOCK(sc); 800 while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 801 if (!waitok) { 802 rc = EBUSY; 803 goto failed; 804 } else if (cv_wait_sig(&sc->cv, &sc->lock) == 0) { 805 rc = EINTR; 806 goto failed; 807 } 808 } 809 if (IS_DOOMED(pi) != 0) { /* shouldn't happen on Solaris */ 810 rc = ENXIO; 811 goto failed; 812 } 813 ASSERT(!IS_BUSY(sc)); 814 /* LINTED: E_CONSTANT_CONDITION */ 815 SET_BUSY(sc); 816 817 if (!hold) 818 ADAPTER_UNLOCK(sc); 819 820 return (0); 821 failed: 822 ADAPTER_UNLOCK(sc); 823 return (rc); 824 } 825 826 static void 827 end_synchronized_op(struct port_info *pi, int held) 828 { 829 struct adapter *sc = pi->adapter; 830 831 if (!held) 832 ADAPTER_LOCK(sc); 833 834 ADAPTER_LOCK_ASSERT_OWNED(sc); 835 ASSERT(IS_BUSY(sc)); 836 /* LINTED: E_CONSTANT_CONDITION */ 837 CLR_BUSY(sc); 838 cv_signal(&sc->cv); 839 ADAPTER_UNLOCK(sc); 840 } 841 842 static int 843 t4_init_synchronized(struct port_info *pi) 844 { 845 struct adapter *sc = pi->adapter; 846 int rc = 0; 847 848 ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 849 850 if (isset(&sc->open_device_map, pi->port_id) != 0) 851 return (0); /* already running */ 852 853 if (!(sc->flags & FULL_INIT_DONE) && 854 ((rc = adapter_full_init(sc)) != 0)) 855 return (rc); /* error message displayed already */ 856 857 if (!(pi->flags & PORT_INIT_DONE)) { 858 rc = port_full_init(pi); 859 if (rc != 0) 860 return (rc); /* error message displayed already */ 861 } else 862 enable_port_queues(pi); 863 864 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, pi->mtu, 0, 0, 1, 0, false); 865 if (rc != 0) { 866 cxgb_printf(pi->dip, CE_WARN, "set_rxmode failed: %d", rc); 867 goto done; 868 } 869 rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 870 pi->hw_addr, true, true); 871 if (rc < 0) { 872 cxgb_printf(pi->dip, CE_WARN, "change_mac failed: %d", rc); 873 rc = -rc; 874 goto done; 875 } else 876 /* LINTED: E_ASSIGN_NARROW_CONV */ 877 pi->xact_addr_filt = rc; 878 879 rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 880 if (rc != 0) { 881 cxgb_printf(pi->dip, CE_WARN, "start_link failed: %d", rc); 882 goto done; 883 } 884 885 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 886 if (rc != 0) { 887 cxgb_printf(pi->dip, CE_WARN, "enable_vi failed: %d", rc); 888 goto done; 889 } 890 891 /* all ok */ 892 setbit(&sc->open_device_map, pi->port_id); 893 done: 894 if (rc != 0) 895 (void) t4_uninit_synchronized(pi); 896 897 return (rc); 898 } 899 900 /* 901 * Idempotent. 902 */ 903 static int 904 t4_uninit_synchronized(struct port_info *pi) 905 { 906 struct adapter *sc = pi->adapter; 907 int rc; 908 909 ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 910 911 /* 912 * Disable the VI so that all its data in either direction is discarded 913 * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 914 * tick) intact as the TP can deliver negative advice or data that it's 915 * holding in its RAM (for an offloaded connection) even after the VI is 916 * disabled. 917 */ 918 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 919 if (rc != 0) { 920 cxgb_printf(pi->dip, CE_WARN, "disable_vi failed: %d", rc); 921 return (rc); 922 } 923 924 disable_port_queues(pi); 925 926 clrbit(&sc->open_device_map, pi->port_id); 927 928 pi->link_cfg.link_ok = 0; 929 pi->link_cfg.speed = 0; 930 mac_link_update(pi->mh, LINK_STATE_UNKNOWN); 931 932 return (0); 933 } 934 935 static void 936 propinfo(struct port_info *pi, const char *name, mac_prop_info_handle_t ph) 937 { 938 struct adapter *sc = pi->adapter; 939 struct driver_properties *p = &sc->props; 940 struct link_config *lc = &pi->link_cfg; 941 int v; 942 char str[16]; 943 944 if (strcmp(name, T4PROP_TMR_IDX) == 0) 945 v = is_10G_port(pi) ? p->tmr_idx_10g : p->tmr_idx_1g; 946 else if (strcmp(name, T4PROP_PKTC_IDX) == 0) 947 v = is_10G_port(pi) ? p->pktc_idx_10g : p->pktc_idx_1g; 948 else if (strcmp(name, T4PROP_HW_CSUM) == 0) 949 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0; 950 else if (strcmp(name, T4PROP_HW_LSO) == 0) 951 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0; 952 else if (strcmp(name, T4PROP_TX_PAUSE) == 0) 953 v = (lc->fc & PAUSE_TX) ? 1 : 0; 954 else if (strcmp(name, T4PROP_RX_PAUSE) == 0) 955 v = (lc->fc & PAUSE_RX) ? 1 : 0; 956 #if MAC_VERSION == 1 957 else if (strcmp(name, T4PROP_MTU) == 0) 958 v = ETHERMTU; 959 #endif 960 else 961 return; 962 963 (void) snprintf(str, sizeof (str), "%d", v); 964 mac_prop_info_set_default_str(ph, str); 965 } 966 967 static int 968 getprop(struct port_info *pi, const char *name, uint_t size, void *val) 969 { 970 struct link_config *lc = &pi->link_cfg; 971 int v; 972 973 if (strcmp(name, T4PROP_TMR_IDX) == 0) 974 v = pi->tmr_idx; 975 else if (strcmp(name, T4PROP_PKTC_IDX) == 0) 976 v = pi->pktc_idx; 977 else if (strcmp(name, T4PROP_HW_CSUM) == 0) 978 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0; 979 else if (strcmp(name, T4PROP_HW_LSO) == 0) 980 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0; 981 else if (strcmp(name, T4PROP_TX_PAUSE) == 0) 982 v = (lc->fc & PAUSE_TX) ? 1 : 0; 983 else if (strcmp(name, T4PROP_RX_PAUSE) == 0) 984 v = (lc->fc & PAUSE_RX) ? 1 : 0; 985 #if MAC_VERSION == 1 986 else if (strcmp(name, T4PROP_MTU) == 0) 987 v = pi->mtu; 988 #endif 989 else 990 return (ENOTSUP); 991 992 (void) snprintf(val, size, "%d", v); 993 return (0); 994 } 995 996 static int 997 setprop(struct port_info *pi, const char *name, const void *val) 998 { 999 struct adapter *sc = pi->adapter; 1000 long v; 1001 int i, rc = 0, relink = 0, rx_mode = 0; 1002 struct sge_rxq *rxq; 1003 struct link_config lc_old, *lc = &pi->link_cfg; 1004 1005 /* 1006 * Save a copy of link_config. This can be used to restore link_config 1007 * if t4_link_start() fails. 1008 */ 1009 bcopy(lc, &lc_old, sizeof (struct link_config)); 1010 1011 (void) ddi_strtol(val, NULL, 0, &v); 1012 1013 if (strcmp(name, T4PROP_TMR_IDX) == 0) { 1014 if (v < 0 || v >= SGE_NTIMERS) 1015 return (EINVAL); 1016 if (v == pi->tmr_idx) 1017 return (0); 1018 1019 /* LINTED: E_ASSIGN_NARROW_CONV */ 1020 pi->tmr_idx = v; 1021 for_each_rxq(pi, i, rxq) { 1022 rxq->iq.intr_params = V_QINTR_TIMER_IDX(v) | 1023 V_QINTR_CNT_EN(pi->pktc_idx >= 0); 1024 } 1025 1026 } else if (strcmp(name, T4PROP_PKTC_IDX) == 0) { 1027 if (v >= SGE_NCOUNTERS) 1028 return (EINVAL); 1029 if (v == pi->pktc_idx || (v < 0 && pi->pktc_idx == -1)) 1030 return (0); 1031 1032 /* LINTED: E_ASSIGN_NARROW_CONV */ 1033 pi->pktc_idx = v < 0 ? -1 : v; 1034 for_each_rxq(pi, i, rxq) { 1035 rxq->iq.intr_params = V_QINTR_TIMER_IDX(pi->tmr_idx) | 1036 /* takes effect right away */ 1037 V_QINTR_CNT_EN(v >= 0); 1038 /* LINTED: E_ASSIGN_NARROW_CONV */ 1039 rxq->iq.intr_pktc_idx = v; /* this needs fresh plumb */ 1040 } 1041 } else if (strcmp(name, T4PROP_HW_CSUM) == 0) { 1042 if (v != 0 && v != 1) 1043 return (EINVAL); 1044 if (v == 1) 1045 pi->features |= CXGBE_HW_CSUM; 1046 else 1047 pi->features &= ~CXGBE_HW_CSUM; 1048 } else if (strcmp(name, T4PROP_HW_LSO) == 0) { 1049 if (v != 0 && v != 1) 1050 return (EINVAL); 1051 if (v == 1) 1052 pi->features |= CXGBE_HW_LSO; 1053 else 1054 pi->features &= ~CXGBE_HW_LSO; 1055 } else if (strcmp(name, T4PROP_TX_PAUSE) == 0) { 1056 if (v != 0 && v != 1) 1057 return (EINVAL); 1058 1059 if (v != 0) 1060 lc->requested_fc |= PAUSE_TX; 1061 else 1062 lc->requested_fc &= ~PAUSE_TX; 1063 1064 relink = 1; 1065 1066 } else if (strcmp(name, T4PROP_RX_PAUSE) == 0) { 1067 if (v != 0 && v != 1) 1068 return (EINVAL); 1069 1070 if (v != 0) 1071 lc->requested_fc |= PAUSE_RX; 1072 else 1073 lc->requested_fc &= ~PAUSE_RX; 1074 1075 relink = 1; 1076 } 1077 #if MAC_VERSION == 1 1078 else if (strcmp(name, T4PROP_MTU) == 0) { 1079 if (v < 46 || v > MAX_MTU) 1080 return (EINVAL); 1081 if (v == pi->mtu) 1082 return (0); 1083 1084 pi->mtu = (int)v; 1085 (void) mac_maxsdu_update(pi->mh, v); 1086 rx_mode = 1; 1087 } 1088 #endif 1089 else 1090 return (ENOTSUP); 1091 1092 if (!(relink || rx_mode)) 1093 return (0); 1094 1095 /* If we are here, either relink or rx_mode is 1 */ 1096 if (isset(&sc->open_device_map, pi->port_id) != 0) { 1097 if (relink != 0) { 1098 rc = begin_synchronized_op(pi, 1, 1); 1099 if (rc != 0) 1100 return (rc); 1101 rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, lc); 1102 end_synchronized_op(pi, 1); 1103 if (rc != 0) { 1104 cxgb_printf(pi->dip, CE_WARN, 1105 "start_link failed:%d", rc); 1106 /* Restore link_config */ 1107 bcopy(&lc_old, lc, sizeof (struct link_config)); 1108 } 1109 } else if (rx_mode != 0) { 1110 rc = begin_synchronized_op(pi, 1, 1); 1111 if (rc != 0) 1112 return (rc); 1113 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v, -1, -1, 1114 -1, -1, false); 1115 end_synchronized_op(pi, 1); 1116 if (rc != 0) { 1117 cxgb_printf(pi->dip, CE_WARN, 1118 "set_rxmode failed: %d", rc); 1119 } 1120 } 1121 return (rc); 1122 } 1123 1124 return (0); 1125 } 1126 1127 void 1128 t4_mc_init(struct port_info *pi) 1129 { 1130 pi->mc = &t4_m_callbacks; 1131 pi->props = t4_priv_props; 1132 } 1133 1134 void 1135 t4_os_link_changed(struct adapter *sc, int idx, int link_stat) 1136 { 1137 struct port_info *pi = sc->port[idx]; 1138 1139 mac_link_update(pi->mh, link_stat ? LINK_STATE_UP : LINK_STATE_DOWN); 1140 } 1141 1142 /* ARGSUSED */ 1143 void 1144 t4_mac_rx(struct port_info *pi, struct sge_rxq *rxq, mblk_t *m) 1145 { 1146 mac_rx(pi->mh, NULL, m); 1147 } 1148