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