1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright(c) 2007-2010 Intel Corporation. All rights reserved. 24 */ 25 26 /* 27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 28 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 29 * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved. 30 */ 31 32 #include "ixgbe_sw.h" 33 34 /* 35 * Bring the device out of the reset/quiesced state that it 36 * was in when the interface was registered. 37 */ 38 int 39 ixgbe_m_start(void *arg) 40 { 41 ixgbe_t *ixgbe = (ixgbe_t *)arg; 42 43 mutex_enter(&ixgbe->gen_lock); 44 45 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 46 mutex_exit(&ixgbe->gen_lock); 47 return (ECANCELED); 48 } 49 50 if (ixgbe_start(ixgbe, B_TRUE) != IXGBE_SUCCESS) { 51 mutex_exit(&ixgbe->gen_lock); 52 return (EIO); 53 } 54 55 atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED); 56 57 mutex_exit(&ixgbe->gen_lock); 58 59 /* 60 * Enable and start the watchdog timer 61 */ 62 ixgbe_enable_watchdog_timer(ixgbe); 63 64 return (0); 65 } 66 67 /* 68 * Stop the device and put it in a reset/quiesced state such 69 * that the interface can be unregistered. 70 */ 71 void 72 ixgbe_m_stop(void *arg) 73 { 74 ixgbe_t *ixgbe = (ixgbe_t *)arg; 75 76 mutex_enter(&ixgbe->gen_lock); 77 78 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 79 mutex_exit(&ixgbe->gen_lock); 80 return; 81 } 82 83 atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED); 84 85 ixgbe_stop(ixgbe, B_TRUE); 86 87 mutex_exit(&ixgbe->gen_lock); 88 89 /* 90 * Disable and stop the watchdog timer 91 */ 92 ixgbe_disable_watchdog_timer(ixgbe); 93 } 94 95 /* 96 * Set the promiscuity of the device. 97 */ 98 int 99 ixgbe_m_promisc(void *arg, boolean_t on) 100 { 101 ixgbe_t *ixgbe = (ixgbe_t *)arg; 102 uint32_t reg_val; 103 struct ixgbe_hw *hw = &ixgbe->hw; 104 105 mutex_enter(&ixgbe->gen_lock); 106 107 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 108 mutex_exit(&ixgbe->gen_lock); 109 return (ECANCELED); 110 } 111 reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); 112 113 if (on) 114 reg_val |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 115 else 116 reg_val &= (~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE)); 117 118 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_FCTRL, reg_val); 119 120 mutex_exit(&ixgbe->gen_lock); 121 122 return (0); 123 } 124 125 /* 126 * Add/remove the addresses to/from the set of multicast 127 * addresses for which the device will receive packets. 128 */ 129 int 130 ixgbe_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr) 131 { 132 ixgbe_t *ixgbe = (ixgbe_t *)arg; 133 int result; 134 135 mutex_enter(&ixgbe->gen_lock); 136 137 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 138 mutex_exit(&ixgbe->gen_lock); 139 return (ECANCELED); 140 } 141 142 result = (add) ? ixgbe_multicst_add(ixgbe, mcst_addr) 143 : ixgbe_multicst_remove(ixgbe, mcst_addr); 144 145 mutex_exit(&ixgbe->gen_lock); 146 147 return (result); 148 } 149 150 /* 151 * Pass on M_IOCTL messages passed to the DLD, and support 152 * private IOCTLs for debugging and ndd. 153 */ 154 void 155 ixgbe_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 156 { 157 ixgbe_t *ixgbe = (ixgbe_t *)arg; 158 struct iocblk *iocp; 159 enum ioc_reply status; 160 161 iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 162 iocp->ioc_error = 0; 163 164 mutex_enter(&ixgbe->gen_lock); 165 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 166 mutex_exit(&ixgbe->gen_lock); 167 miocnak(q, mp, 0, EINVAL); 168 return; 169 } 170 mutex_exit(&ixgbe->gen_lock); 171 172 switch (iocp->ioc_cmd) { 173 case LB_GET_INFO_SIZE: 174 case LB_GET_INFO: 175 case LB_GET_MODE: 176 case LB_SET_MODE: 177 status = ixgbe_loopback_ioctl(ixgbe, iocp, mp); 178 break; 179 180 default: 181 status = IOC_INVAL; 182 break; 183 } 184 185 /* 186 * Decide how to reply 187 */ 188 switch (status) { 189 default: 190 case IOC_INVAL: 191 /* 192 * Error, reply with a NAK and EINVAL or the specified error 193 */ 194 miocnak(q, mp, 0, iocp->ioc_error == 0 ? 195 EINVAL : iocp->ioc_error); 196 break; 197 198 case IOC_DONE: 199 /* 200 * OK, reply already sent 201 */ 202 break; 203 204 case IOC_ACK: 205 /* 206 * OK, reply with an ACK 207 */ 208 miocack(q, mp, 0, 0); 209 break; 210 211 case IOC_REPLY: 212 /* 213 * OK, send prepared reply as ACK or NAK 214 */ 215 mp->b_datap->db_type = iocp->ioc_error == 0 ? 216 M_IOCACK : M_IOCNAK; 217 qreply(q, mp); 218 break; 219 } 220 } 221 222 /* 223 * Obtain the MAC's capabilities and associated data from 224 * the driver. 225 */ 226 boolean_t 227 ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 228 { 229 ixgbe_t *ixgbe = (ixgbe_t *)arg; 230 231 switch (cap) { 232 case MAC_CAPAB_HCKSUM: { 233 uint32_t *tx_hcksum_flags = cap_data; 234 235 /* 236 * We advertise our capabilities only if tx hcksum offload is 237 * enabled. On receive, the stack will accept checksummed 238 * packets anyway, even if we haven't said we can deliver 239 * them. 240 */ 241 if (!ixgbe->tx_hcksum_enable) 242 return (B_FALSE); 243 244 *tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; 245 break; 246 } 247 case MAC_CAPAB_LSO: { 248 mac_capab_lso_t *cap_lso = cap_data; 249 250 if (ixgbe->lso_enable) { 251 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4; 252 cap_lso->lso_basic_tcp_ipv4.lso_max = IXGBE_LSO_MAXLEN; 253 break; 254 } else { 255 return (B_FALSE); 256 } 257 } 258 case MAC_CAPAB_RINGS: { 259 mac_capab_rings_t *cap_rings = cap_data; 260 261 switch (cap_rings->mr_type) { 262 case MAC_RING_TYPE_RX: 263 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 264 cap_rings->mr_rnum = ixgbe->num_rx_rings; 265 cap_rings->mr_gnum = ixgbe->num_rx_groups; 266 cap_rings->mr_rget = ixgbe_fill_ring; 267 cap_rings->mr_gget = ixgbe_fill_group; 268 cap_rings->mr_gaddring = NULL; 269 cap_rings->mr_gremring = NULL; 270 break; 271 case MAC_RING_TYPE_TX: 272 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 273 cap_rings->mr_rnum = ixgbe->num_tx_rings; 274 cap_rings->mr_gnum = 0; 275 cap_rings->mr_rget = ixgbe_fill_ring; 276 cap_rings->mr_gget = NULL; 277 break; 278 default: 279 break; 280 } 281 break; 282 } 283 default: 284 return (B_FALSE); 285 } 286 return (B_TRUE); 287 } 288 289 int 290 ixgbe_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 291 uint_t pr_valsize, const void *pr_val) 292 { 293 ixgbe_t *ixgbe = (ixgbe_t *)arg; 294 struct ixgbe_hw *hw = &ixgbe->hw; 295 int err = 0; 296 uint32_t flow_control; 297 uint32_t cur_mtu, new_mtu; 298 uint32_t rx_size; 299 uint32_t tx_size; 300 301 mutex_enter(&ixgbe->gen_lock); 302 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 303 mutex_exit(&ixgbe->gen_lock); 304 return (ECANCELED); 305 } 306 307 if (ixgbe->loopback_mode != IXGBE_LB_NONE && 308 ixgbe_param_locked(pr_num)) { 309 /* 310 * All en_* parameters are locked (read-only) 311 * while the device is in any sort of loopback mode. 312 */ 313 mutex_exit(&ixgbe->gen_lock); 314 return (EBUSY); 315 } 316 317 switch (pr_num) { 318 case MAC_PROP_EN_10GFDX_CAP: 319 /* read/write on copper, read-only on serdes */ 320 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) { 321 err = ENOTSUP; 322 break; 323 } else { 324 ixgbe->param_en_10000fdx_cap = *(uint8_t *)pr_val; 325 ixgbe->param_adv_10000fdx_cap = *(uint8_t *)pr_val; 326 goto setup_link; 327 } 328 case MAC_PROP_EN_1000FDX_CAP: 329 /* read/write on copper, read-only on serdes */ 330 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) { 331 err = ENOTSUP; 332 break; 333 } else { 334 ixgbe->param_en_1000fdx_cap = *(uint8_t *)pr_val; 335 ixgbe->param_adv_1000fdx_cap = *(uint8_t *)pr_val; 336 goto setup_link; 337 } 338 case MAC_PROP_EN_100FDX_CAP: 339 /* read/write on copper, read-only on serdes */ 340 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) { 341 err = ENOTSUP; 342 break; 343 } else { 344 ixgbe->param_en_100fdx_cap = *(uint8_t *)pr_val; 345 ixgbe->param_adv_100fdx_cap = *(uint8_t *)pr_val; 346 goto setup_link; 347 } 348 case MAC_PROP_AUTONEG: 349 /* read/write on copper, read-only on serdes */ 350 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) { 351 err = ENOTSUP; 352 break; 353 } else { 354 ixgbe->param_adv_autoneg_cap = *(uint8_t *)pr_val; 355 goto setup_link; 356 } 357 case MAC_PROP_FLOWCTRL: 358 bcopy(pr_val, &flow_control, sizeof (flow_control)); 359 360 switch (flow_control) { 361 default: 362 err = EINVAL; 363 break; 364 case LINK_FLOWCTRL_NONE: 365 hw->fc.requested_mode = ixgbe_fc_none; 366 break; 367 case LINK_FLOWCTRL_RX: 368 hw->fc.requested_mode = ixgbe_fc_rx_pause; 369 break; 370 case LINK_FLOWCTRL_TX: 371 hw->fc.requested_mode = ixgbe_fc_tx_pause; 372 break; 373 case LINK_FLOWCTRL_BI: 374 hw->fc.requested_mode = ixgbe_fc_full; 375 break; 376 } 377 setup_link: 378 if (err == 0) { 379 if (ixgbe_driver_setup_link(ixgbe, B_TRUE) != 380 IXGBE_SUCCESS) 381 err = EINVAL; 382 } 383 break; 384 case MAC_PROP_ADV_10GFDX_CAP: 385 case MAC_PROP_ADV_1000FDX_CAP: 386 case MAC_PROP_ADV_100FDX_CAP: 387 case MAC_PROP_STATUS: 388 case MAC_PROP_SPEED: 389 case MAC_PROP_DUPLEX: 390 err = ENOTSUP; /* read-only prop. Can't set this. */ 391 break; 392 case MAC_PROP_MTU: 393 cur_mtu = ixgbe->default_mtu; 394 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 395 if (new_mtu == cur_mtu) { 396 err = 0; 397 break; 398 } 399 400 if (new_mtu < DEFAULT_MTU || new_mtu > ixgbe->capab->max_mtu) { 401 err = EINVAL; 402 break; 403 } 404 405 if (ixgbe->ixgbe_state & IXGBE_STARTED) { 406 err = EBUSY; 407 break; 408 } 409 410 err = mac_maxsdu_update(ixgbe->mac_hdl, new_mtu); 411 if (err == 0) { 412 ixgbe->default_mtu = new_mtu; 413 ixgbe->max_frame_size = ixgbe->default_mtu + 414 sizeof (struct ether_vlan_header) + ETHERFCSL; 415 416 /* 417 * Set rx buffer size 418 */ 419 rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM; 420 ixgbe->rx_buf_size = ((rx_size >> 10) + ((rx_size & 421 (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 422 423 /* 424 * Set tx buffer size 425 */ 426 tx_size = ixgbe->max_frame_size; 427 ixgbe->tx_buf_size = ((tx_size >> 10) + ((tx_size & 428 (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10; 429 } 430 break; 431 case MAC_PROP_PRIVATE: 432 err = ixgbe_set_priv_prop(ixgbe, pr_name, pr_valsize, pr_val); 433 break; 434 default: 435 err = ENOTSUP; 436 break; 437 } 438 mutex_exit(&ixgbe->gen_lock); 439 return (err); 440 } 441 442 int 443 ixgbe_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 444 uint_t pr_valsize, void *pr_val) 445 { 446 ixgbe_t *ixgbe = (ixgbe_t *)arg; 447 struct ixgbe_hw *hw = &ixgbe->hw; 448 int err = 0; 449 uint32_t flow_control; 450 uint64_t tmp = 0; 451 452 switch (pr_num) { 453 case MAC_PROP_DUPLEX: 454 ASSERT(pr_valsize >= sizeof (link_duplex_t)); 455 bcopy(&ixgbe->link_duplex, pr_val, 456 sizeof (link_duplex_t)); 457 break; 458 case MAC_PROP_SPEED: 459 ASSERT(pr_valsize >= sizeof (uint64_t)); 460 tmp = ixgbe->link_speed * 1000000ull; 461 bcopy(&tmp, pr_val, sizeof (tmp)); 462 break; 463 case MAC_PROP_AUTONEG: 464 *(uint8_t *)pr_val = ixgbe->param_adv_autoneg_cap; 465 break; 466 case MAC_PROP_FLOWCTRL: 467 ASSERT(pr_valsize >= sizeof (uint32_t)); 468 469 switch (hw->fc.requested_mode) { 470 case ixgbe_fc_none: 471 flow_control = LINK_FLOWCTRL_NONE; 472 break; 473 case ixgbe_fc_rx_pause: 474 flow_control = LINK_FLOWCTRL_RX; 475 break; 476 case ixgbe_fc_tx_pause: 477 flow_control = LINK_FLOWCTRL_TX; 478 break; 479 case ixgbe_fc_full: 480 flow_control = LINK_FLOWCTRL_BI; 481 break; 482 } 483 bcopy(&flow_control, pr_val, sizeof (flow_control)); 484 break; 485 case MAC_PROP_ADV_10GFDX_CAP: 486 *(uint8_t *)pr_val = ixgbe->param_adv_10000fdx_cap; 487 break; 488 case MAC_PROP_EN_10GFDX_CAP: 489 *(uint8_t *)pr_val = ixgbe->param_en_10000fdx_cap; 490 break; 491 case MAC_PROP_ADV_1000FDX_CAP: 492 *(uint8_t *)pr_val = ixgbe->param_adv_1000fdx_cap; 493 break; 494 case MAC_PROP_EN_1000FDX_CAP: 495 *(uint8_t *)pr_val = ixgbe->param_en_1000fdx_cap; 496 break; 497 case MAC_PROP_ADV_100FDX_CAP: 498 *(uint8_t *)pr_val = ixgbe->param_adv_100fdx_cap; 499 break; 500 case MAC_PROP_EN_100FDX_CAP: 501 *(uint8_t *)pr_val = ixgbe->param_en_100fdx_cap; 502 break; 503 case MAC_PROP_PRIVATE: 504 err = ixgbe_get_priv_prop(ixgbe, pr_name, 505 pr_valsize, pr_val); 506 break; 507 default: 508 err = ENOTSUP; 509 break; 510 } 511 return (err); 512 } 513 514 void 515 ixgbe_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 516 mac_prop_info_handle_t prh) 517 { 518 ixgbe_t *ixgbe = (ixgbe_t *)arg; 519 uint_t perm; 520 521 switch (pr_num) { 522 case MAC_PROP_DUPLEX: 523 case MAC_PROP_SPEED: 524 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 525 break; 526 527 case MAC_PROP_ADV_100FDX_CAP: 528 case MAC_PROP_ADV_1000FDX_CAP: 529 case MAC_PROP_ADV_10GFDX_CAP: 530 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 531 mac_prop_info_set_default_uint8(prh, 1); 532 break; 533 534 case MAC_PROP_AUTONEG: 535 case MAC_PROP_EN_10GFDX_CAP: 536 case MAC_PROP_EN_1000FDX_CAP: 537 case MAC_PROP_EN_100FDX_CAP: 538 perm = (ixgbe->hw.phy.media_type == ixgbe_media_type_copper) ? 539 MAC_PROP_PERM_RW : MAC_PROP_PERM_READ; 540 mac_prop_info_set_perm(prh, perm); 541 mac_prop_info_set_default_uint8(prh, 1); 542 break; 543 544 case MAC_PROP_FLOWCTRL: 545 mac_prop_info_set_default_link_flowctrl(prh, 546 LINK_FLOWCTRL_NONE); 547 break; 548 549 case MAC_PROP_MTU: 550 mac_prop_info_set_range_uint32(prh, 551 DEFAULT_MTU, ixgbe->capab->max_mtu); 552 break; 553 554 case MAC_PROP_PRIVATE: { 555 char valstr[64]; 556 int value; 557 558 bzero(valstr, sizeof (valstr)); 559 560 if (strcmp(pr_name, "_adv_pause_cap") == 0 || 561 strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 562 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 563 return; 564 } 565 566 if (strcmp(pr_name, "_tx_copy_thresh") == 0) { 567 value = DEFAULT_TX_COPY_THRESHOLD; 568 } else if (strcmp(pr_name, "_tx_recycle_thresh") == 0) { 569 value = DEFAULT_TX_RECYCLE_THRESHOLD; 570 } else if (strcmp(pr_name, "_tx_overload_thresh") == 0) { 571 value = DEFAULT_TX_OVERLOAD_THRESHOLD; 572 } else if (strcmp(pr_name, "_tx_resched_thresh") == 0) { 573 value = DEFAULT_TX_RESCHED_THRESHOLD; 574 } else if (strcmp(pr_name, "_rx_copy_thresh") == 0) { 575 value = DEFAULT_RX_COPY_THRESHOLD; 576 } else if (strcmp(pr_name, "_rx_limit_per_intr") == 0) { 577 value = DEFAULT_RX_LIMIT_PER_INTR; 578 } if (strcmp(pr_name, "_intr_throttling") == 0) { 579 value = ixgbe->capab->def_intr_throttle; 580 } else { 581 return; 582 } 583 584 (void) snprintf(valstr, sizeof (valstr), "%x", value); 585 } 586 } 587 } 588 589 boolean_t 590 ixgbe_param_locked(mac_prop_id_t pr_num) 591 { 592 /* 593 * All en_* parameters are locked (read-only) while 594 * the device is in any sort of loopback mode ... 595 */ 596 switch (pr_num) { 597 case MAC_PROP_EN_10GFDX_CAP: 598 case MAC_PROP_EN_1000FDX_CAP: 599 case MAC_PROP_EN_100FDX_CAP: 600 case MAC_PROP_AUTONEG: 601 case MAC_PROP_FLOWCTRL: 602 return (B_TRUE); 603 } 604 return (B_FALSE); 605 } 606 607 /* ARGSUSED */ 608 int 609 ixgbe_set_priv_prop(ixgbe_t *ixgbe, const char *pr_name, 610 uint_t pr_valsize, const void *pr_val) 611 { 612 int err = 0; 613 long result; 614 struct ixgbe_hw *hw = &ixgbe->hw; 615 int i; 616 617 if (strcmp(pr_name, "_tx_copy_thresh") == 0) { 618 if (pr_val == NULL) { 619 err = EINVAL; 620 return (err); 621 } 622 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 623 if (result < MIN_TX_COPY_THRESHOLD || 624 result > MAX_TX_COPY_THRESHOLD) 625 err = EINVAL; 626 else { 627 ixgbe->tx_copy_thresh = (uint32_t)result; 628 } 629 return (err); 630 } 631 if (strcmp(pr_name, "_tx_recycle_thresh") == 0) { 632 if (pr_val == NULL) { 633 err = EINVAL; 634 return (err); 635 } 636 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 637 if (result < MIN_TX_RECYCLE_THRESHOLD || 638 result > MAX_TX_RECYCLE_THRESHOLD) 639 err = EINVAL; 640 else { 641 ixgbe->tx_recycle_thresh = (uint32_t)result; 642 } 643 return (err); 644 } 645 if (strcmp(pr_name, "_tx_overload_thresh") == 0) { 646 if (pr_val == NULL) { 647 err = EINVAL; 648 return (err); 649 } 650 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 651 if (result < MIN_TX_OVERLOAD_THRESHOLD || 652 result > MAX_TX_OVERLOAD_THRESHOLD) 653 err = EINVAL; 654 else { 655 ixgbe->tx_overload_thresh = (uint32_t)result; 656 } 657 return (err); 658 } 659 if (strcmp(pr_name, "_tx_resched_thresh") == 0) { 660 if (pr_val == NULL) { 661 err = EINVAL; 662 return (err); 663 } 664 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 665 if (result < MIN_TX_RESCHED_THRESHOLD || 666 result > MAX_TX_RESCHED_THRESHOLD) 667 err = EINVAL; 668 else { 669 ixgbe->tx_resched_thresh = (uint32_t)result; 670 } 671 return (err); 672 } 673 if (strcmp(pr_name, "_rx_copy_thresh") == 0) { 674 if (pr_val == NULL) { 675 err = EINVAL; 676 return (err); 677 } 678 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 679 if (result < MIN_RX_COPY_THRESHOLD || 680 result > MAX_RX_COPY_THRESHOLD) 681 err = EINVAL; 682 else { 683 ixgbe->rx_copy_thresh = (uint32_t)result; 684 } 685 return (err); 686 } 687 if (strcmp(pr_name, "_rx_limit_per_intr") == 0) { 688 if (pr_val == NULL) { 689 err = EINVAL; 690 return (err); 691 } 692 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 693 if (result < MIN_RX_LIMIT_PER_INTR || 694 result > MAX_RX_LIMIT_PER_INTR) 695 err = EINVAL; 696 else { 697 ixgbe->rx_limit_per_intr = (uint32_t)result; 698 } 699 return (err); 700 } 701 if (strcmp(pr_name, "_intr_throttling") == 0) { 702 if (pr_val == NULL) { 703 err = EINVAL; 704 return (err); 705 } 706 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); 707 708 if (result < ixgbe->capab->min_intr_throttle || 709 result > ixgbe->capab->max_intr_throttle) 710 err = EINVAL; 711 else { 712 ixgbe->intr_throttling[0] = (uint32_t)result; 713 714 /* 715 * 82599 and X540 require the interrupt throttling 716 * rate is a multiple of 8. This is enforced by the 717 * register definiton. 718 */ 719 if (hw->mac.type == ixgbe_mac_82599EB || 720 hw->mac.type == ixgbe_mac_X540) { 721 ixgbe->intr_throttling[0] = 722 ixgbe->intr_throttling[0] & 0xFF8; 723 } 724 725 for (i = 0; i < MAX_INTR_VECTOR; i++) 726 ixgbe->intr_throttling[i] = 727 ixgbe->intr_throttling[0]; 728 729 /* Set interrupt throttling rate */ 730 for (i = 0; i < ixgbe->intr_cnt; i++) 731 IXGBE_WRITE_REG(hw, IXGBE_EITR(i), 732 ixgbe->intr_throttling[i]); 733 } 734 return (err); 735 } 736 return (ENOTSUP); 737 } 738 739 int 740 ixgbe_get_priv_prop(ixgbe_t *ixgbe, const char *pr_name, 741 uint_t pr_valsize, void *pr_val) 742 { 743 int err = ENOTSUP; 744 int value; 745 746 if (strcmp(pr_name, "_adv_pause_cap") == 0) { 747 value = ixgbe->param_adv_pause_cap; 748 err = 0; 749 goto done; 750 } 751 if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) { 752 value = ixgbe->param_adv_asym_pause_cap; 753 err = 0; 754 goto done; 755 } 756 if (strcmp(pr_name, "_tx_copy_thresh") == 0) { 757 value = ixgbe->tx_copy_thresh; 758 err = 0; 759 goto done; 760 } 761 if (strcmp(pr_name, "_tx_recycle_thresh") == 0) { 762 value = ixgbe->tx_recycle_thresh; 763 err = 0; 764 goto done; 765 } 766 if (strcmp(pr_name, "_tx_overload_thresh") == 0) { 767 value = ixgbe->tx_overload_thresh; 768 err = 0; 769 goto done; 770 } 771 if (strcmp(pr_name, "_tx_resched_thresh") == 0) { 772 value = ixgbe->tx_resched_thresh; 773 err = 0; 774 goto done; 775 } 776 if (strcmp(pr_name, "_rx_copy_thresh") == 0) { 777 value = ixgbe->rx_copy_thresh; 778 err = 0; 779 goto done; 780 } 781 if (strcmp(pr_name, "_rx_limit_per_intr") == 0) { 782 value = ixgbe->rx_limit_per_intr; 783 err = 0; 784 goto done; 785 } 786 if (strcmp(pr_name, "_intr_throttling") == 0) { 787 value = ixgbe->intr_throttling[0]; 788 err = 0; 789 goto done; 790 } 791 done: 792 if (err == 0) { 793 (void) snprintf(pr_val, pr_valsize, "%d", value); 794 } 795 return (err); 796 } 797