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