Print this page
6064 ixgbe needs X550 support

*** 27,42 **** * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 Saso Kiselkov. All rights reserved. * Copyright (c) 2013 OSN Online Service Nuernberg GmbH. All rights reserved. */ #include "ixgbe_sw.h" static char ixgbe_ident[] = "Intel 10Gb Ethernet"; - static char ixgbe_version[] = "ixgbe 1.1.7"; /* * Local function protoypes */ static int ixgbe_register_mac(ixgbe_t *); --- 27,42 ---- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 Saso Kiselkov. All rights reserved. * Copyright (c) 2013 OSN Online Service Nuernberg GmbH. All rights reserved. + * Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved. */ #include "ixgbe_sw.h" static char ixgbe_ident[] = "Intel 10Gb Ethernet"; /* * Local function protoypes */ static int ixgbe_register_mac(ixgbe_t *);
*** 63,72 **** --- 63,73 ---- static void ixgbe_setup_rx_ring(ixgbe_rx_ring_t *); static void ixgbe_setup_tx_ring(ixgbe_tx_ring_t *); static void ixgbe_setup_rss(ixgbe_t *); static void ixgbe_setup_vmdq(ixgbe_t *); static void ixgbe_setup_vmdq_rss(ixgbe_t *); + static void ixgbe_setup_rss_table(ixgbe_t *); static void ixgbe_init_unicst(ixgbe_t *); static int ixgbe_unicst_find(ixgbe_t *, const uint8_t *); static void ixgbe_setup_multicst(ixgbe_t *); static void ixgbe_get_hw_state(ixgbe_t *); static void ixgbe_setup_vmdq_rss_conf(ixgbe_t *ixgbe);
*** 74,83 **** --- 75,85 ---- static void ixgbe_init_params(ixgbe_t *); static int ixgbe_get_prop(ixgbe_t *, char *, int, int, int); static void ixgbe_driver_link_check(ixgbe_t *); static void ixgbe_sfp_check(void *); static void ixgbe_overtemp_check(void *); + static void ixgbe_phy_check(void *); static void ixgbe_link_timer(void *); static void ixgbe_local_timer(void *); static void ixgbe_arm_watchdog_timer(ixgbe_t *); static void ixgbe_restart_watchdog_timer(ixgbe_t *); static void ixgbe_disable_adapter_interrupts(ixgbe_t *);
*** 312,333 **** 200, /* default interrupt throttle rate */ 64, /* maximum total msix vectors */ 16, /* maximum number of ring vectors */ 2, /* maximum number of other vectors */ (IXGBE_EICR_LSC ! | IXGBE_EICR_GPI_SDP1 ! | IXGBE_EICR_GPI_SDP2), /* "other" interrupt types handled */ ! (IXGBE_SDP1_GPIEN ! | IXGBE_SDP2_GPIEN), /* "other" interrupt types enable mask */ (IXGBE_FLAG_DCA_CAPABLE | IXGBE_FLAG_RSS_CAPABLE | IXGBE_FLAG_VMDQ_CAPABLE | IXGBE_FLAG_RSC_CAPABLE) /* capability flags */ }; /* * Module Initialization Functions. */ int --- 314,359 ---- 200, /* default interrupt throttle rate */ 64, /* maximum total msix vectors */ 16, /* maximum number of ring vectors */ 2, /* maximum number of other vectors */ (IXGBE_EICR_LSC ! | IXGBE_EICR_GPI_SDP1_X540 ! | IXGBE_EICR_GPI_SDP2_X540), /* "other" interrupt types handled */ ! (IXGBE_SDP1_GPIEN_X540 ! | IXGBE_SDP2_GPIEN_X540), /* "other" interrupt types enable mask */ (IXGBE_FLAG_DCA_CAPABLE | IXGBE_FLAG_RSS_CAPABLE | IXGBE_FLAG_VMDQ_CAPABLE | IXGBE_FLAG_RSC_CAPABLE) /* capability flags */ }; + static adapter_info_t ixgbe_X550_cap = { + 128, /* maximum number of rx queues */ + 1, /* minimum number of rx queues */ + 128, /* default number of rx queues */ + 64, /* maximum number of rx groups */ + 1, /* minimum number of rx groups */ + 1, /* default number of rx groups */ + 128, /* maximum number of tx queues */ + 1, /* minimum number of tx queues */ + 8, /* default number of tx queues */ + 15500, /* maximum MTU size */ + 0xFF8, /* maximum interrupt throttle rate */ + 0, /* minimum interrupt throttle rate */ + 0x200, /* default interrupt throttle rate */ + 64, /* maximum total msix vectors */ + 16, /* maximum number of ring vectors */ + 2, /* maximum number of other vectors */ + IXGBE_EICR_LSC, /* "other" interrupt types handled */ + 0, /* "other" interrupt types enable mask */ + (IXGBE_FLAG_RSS_CAPABLE + | IXGBE_FLAG_VMDQ_CAPABLE + | IXGBE_FLAG_RSC_CAPABLE) /* capability flags */ + }; + /* * Module Initialization Functions. */ int
*** 424,434 **** /* Attach the instance pointer to the dev_info data structure */ ddi_set_driver_private(devinfo, ixgbe); /* ! * Initialize for fma support */ ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE, 0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); ixgbe_fm_init(ixgbe); --- 450,460 ---- /* Attach the instance pointer to the dev_info data structure */ ddi_set_driver_private(devinfo, ixgbe); /* ! * Initialize for FMA support */ ixgbe->fm_capabilities = ixgbe_get_prop(ixgbe, PROP_FM_CAPABLE, 0, 0x0f, DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); ixgbe_fm_init(ixgbe);
*** 533,542 **** --- 559,579 ---- goto attach_fail; } ixgbe->attach_progress |= ATTACH_PROGRESS_OVERTEMP_TASKQ; /* + * Create a taskq for processing external PHY interrupts + */ + (void) sprintf(taskqname, "ixgbe%d_phy_taskq", instance); + if ((ixgbe->phy_taskq = ddi_taskq_create(devinfo, taskqname, + 1, TASKQ_DEFAULTPRI, 0)) == NULL) { + ixgbe_error(ixgbe, "phy_taskq create failed"); + goto attach_fail; + } + ixgbe->attach_progress |= ATTACH_PROGRESS_PHY_TASKQ; + + /* * Initialize driver parameters */ if (ixgbe_init_driver_settings(ixgbe) != IXGBE_SUCCESS) { ixgbe_error(ixgbe, "Failed to initialize driver settings"); goto attach_fail;
*** 567,576 **** --- 604,618 ---- ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); goto attach_fail; } /* + * Initialize adapter capabilities + */ + ixgbe_init_params(ixgbe); + + /* * Initialize statistics */ if (ixgbe_init_stats(ixgbe) != IXGBE_SUCCESS) { ixgbe_error(ixgbe, "Failed to initialize statistics"); goto attach_fail;
*** 603,613 **** ixgbe_error(ixgbe, "Failed to enable DDI interrupts"); goto attach_fail; } ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; ! ixgbe_log(ixgbe, "%s, %s", ixgbe_ident, ixgbe_version); atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED); return (DDI_SUCCESS); attach_fail: --- 645,655 ---- ixgbe_error(ixgbe, "Failed to enable DDI interrupts"); goto attach_fail; } ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR; ! ixgbe_log(ixgbe, "%s", ixgbe_ident); atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED); return (DDI_SUCCESS); attach_fail:
*** 786,795 **** --- 828,844 ---- if (ixgbe->attach_progress & ATTACH_PROGRESS_OVERTEMP_TASKQ) { ddi_taskq_destroy(ixgbe->overtemp_taskq); } /* + * Remove taskq for external PHYs + */ + if (ixgbe->attach_progress & ATTACH_PROGRESS_PHY_TASKQ) { + ddi_taskq_destroy(ixgbe->phy_taskq); + } + + /* * Remove interrupts */ if (ixgbe->attach_progress & ATTACH_PROGRESS_ALLOC_INTR) { ixgbe_rem_intrs(ixgbe); }
*** 955,964 **** --- 1004,1032 ---- * For now, X540 is all set in its capab structure. * As other X540 variants show up, things can change here. */ break; + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + IXGBE_DEBUGLOG_0(ixgbe, "identify X550 adapter\n"); + ixgbe->capab = &ixgbe_X550_cap; + + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) + ixgbe->capab->flags |= IXGBE_FLAG_SFP_PLUG_CAPABLE; + + /* + * Link detection on X552 SFP+ and X552/X557-AT + */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || + hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + ixgbe->capab->other_intr |= + IXGBE_EIMS_GPI_SDP0_BY_MAC(hw); + ixgbe->capab->other_gpie |= IXGBE_SDP0_GPIEN_X540; + } + break; + default: IXGBE_DEBUGLOG_1(ixgbe, "adapter not supported in ixgbe_identify_hardware(): %d\n", hw->mac.type); return (IXGBE_FAILURE);
*** 1009,1020 **** /* * Get conf file properties, including link settings * jumbo frames, ring number, descriptor number, etc. */ ixgbe_get_conf(ixgbe); - - ixgbe_init_params(ixgbe); } /* * ixgbe_init_driver_settings - Initialize driver settings. * --- 1077,1086 ----
*** 1245,1265 **** static int ixgbe_init(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; u8 pbanum[IXGBE_PBANUM_LENGTH]; mutex_enter(&ixgbe->gen_lock); /* ! * Reset chipset to put the hardware in a known state ! * before we try to do anything with the eeprom. */ ! if (ixgbe_reset_hw(hw) != IXGBE_SUCCESS) { ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); goto init_fail; } /* * Need to init eeprom before validating the checksum. */ if (ixgbe_init_eeprom_params(hw) < 0) { --- 1311,1367 ---- static int ixgbe_init(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; u8 pbanum[IXGBE_PBANUM_LENGTH]; + int rv; mutex_enter(&ixgbe->gen_lock); /* ! * Configure/Initialize hardware */ ! rv = ixgbe_init_hw(hw); ! if (rv != IXGBE_SUCCESS) { ! switch (rv) { ! ! /* ! * The first three errors are not prohibitive to us progressing ! * further, and are maily advisory in nature. In the case of a ! * SFP module not being present or not deemed supported by the ! * common code, we adivse the operator of this fact but carry on ! * instead of failing hard, as SFPs can be inserted or replaced ! * while the driver is running. In the case of a unknown error, ! * we fail-hard, logging the reason and emitting a FMA event. ! */ ! case IXGBE_ERR_EEPROM_VERSION: ! ixgbe_error(ixgbe, ! "This Intel 10Gb Ethernet device is pre-release and" ! " contains outdated firmware. Please contact your" ! " hardware vendor for a replacement."); ! break; ! case IXGBE_ERR_SFP_NOT_PRESENT: ! ixgbe_error(ixgbe, ! "No SFP+ module detected on this interface. Please " ! "install a supported SFP+ module for this " ! "interface to become operational."); ! break; ! case IXGBE_ERR_SFP_NOT_SUPPORTED: ! ixgbe_error(ixgbe, ! "Unsupported SFP+ module detected. Please replace " ! "it with a supported SFP+ module per Intel " ! "documentation, or bypass this check with " ! "allow_unsupported_sfp=1 in ixgbe.conf."); ! break; ! default: ! ixgbe_error(ixgbe, ! "Failed to initialize hardware. ixgbe_init_hw " ! "returned %d", rv); ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); goto init_fail; } + } /* * Need to init eeprom before validating the checksum. */ if (ixgbe_init_eeprom_params(hw) < 0) {
*** 1295,1304 **** --- 1397,1411 ---- hw->fc.low_water[0] = DEFAULT_FCRTL; hw->fc.pause_time = DEFAULT_FCPAUSE; hw->fc.send_xon = B_TRUE; /* + * Initialize flow control + */ + (void) ixgbe_start_hw(hw); + + /* * Initialize link settings */ (void) ixgbe_driver_setup_link(ixgbe, B_FALSE); /*
*** 1342,1352 **** */ static int ixgbe_chip_start(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! int ret_val, i; ASSERT(mutex_owned(&ixgbe->gen_lock)); /* * Get the mac address --- 1449,1459 ---- */ static int ixgbe_chip_start(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! int i; ASSERT(mutex_owned(&ixgbe->gen_lock)); /* * Get the mac address
*** 1365,1390 **** ixgbe_error(ixgbe, "Invalid mac address"); return (IXGBE_FAILURE); } /* - * Configure/Initialize hardware - */ - ret_val = ixgbe_init_hw(hw); - if (ret_val != IXGBE_SUCCESS) { - if (ret_val == IXGBE_ERR_EEPROM_VERSION) { - ixgbe_error(ixgbe, - "This 82599 device is pre-release and contains" - " outdated firmware, please contact your hardware" - " vendor for a replacement."); - } else { - ixgbe_error(ixgbe, "Failed to initialize hardware"); - return (IXGBE_FAILURE); - } - } - - /* * Re-enable relaxed ordering for performance. It is disabled * by default in the hardware init. */ if (ixgbe->relax_order_enable == B_TRUE) ixgbe_enable_relaxed_ordering(hw); --- 1472,1481 ----
*** 1410,1421 **** for (i = 0; i < ixgbe->intr_cnt; i++) { IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]); } /* ! * Save the state of the phy */ ixgbe_get_hw_state(ixgbe); /* * Make sure driver has control */ --- 1501,1538 ---- for (i = 0; i < ixgbe->intr_cnt; i++) { IXGBE_WRITE_REG(hw, IXGBE_EITR(i), ixgbe->intr_throttling[i]); } /* ! * Disable Wake-on-LAN */ + IXGBE_WRITE_REG(hw, IXGBE_WUC, 0); + + /* + * Some adapters offer Energy Efficient Ethernet (EEE) support. + * Due to issues with EEE in e1000g/igb, we disable this by default + * as a precautionary measure. + * + * Currently, the only known adapter which supports EEE in the ixgbe + * line is 8086,15AB (IXGBE_DEV_ID_X550EM_X_KR), and only after the + * first revision of it, as well as any X550 with MAC type 6 (non-EM) + */ + (void) ixgbe_setup_eee(hw, B_FALSE); + + /* + * Turn on any present SFP Tx laser + */ + ixgbe_enable_tx_laser(hw); + + /* + * Power on the PHY + */ + (void) ixgbe_set_phy_power(hw, B_TRUE); + + /* + * Save the state of the PHY + */ ixgbe_get_hw_state(ixgbe); /* * Make sure driver has control */
*** 1429,1445 **** */ static void ixgbe_chip_stop(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ASSERT(mutex_owned(&ixgbe->gen_lock)); /* ! * Tell firmware driver is no longer in control */ ! ixgbe_release_driver_control(hw); /* * Reset the chipset */ (void) ixgbe_reset_hw(hw); --- 1546,1564 ---- */ static void ixgbe_chip_stop(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; + int rv; ASSERT(mutex_owned(&ixgbe->gen_lock)); /* ! * Stop interupt generation and disable Tx unit */ ! hw->adapter_stopped = B_FALSE; ! (void) ixgbe_stop_adapter(hw); /* * Reset the chipset */ (void) ixgbe_reset_hw(hw);
*** 1446,1455 **** --- 1565,1600 ---- /* * Reset PHY */ (void) ixgbe_reset_phy(hw); + + /* + * Enter LPLU (Low Power, Link Up) mode, if available. Avoid resetting + * the PHY while doing so. Else, just power down the PHY. + */ + if (hw->phy.ops.enter_lplu != NULL) { + hw->phy.reset_disable = B_TRUE; + rv = hw->phy.ops.enter_lplu(hw); + if (rv != IXGBE_SUCCESS) + ixgbe_error(ixgbe, "Error while entering LPLU: %d", rv); + hw->phy.reset_disable = B_FALSE; + } else { + (void) ixgbe_set_phy_power(hw, B_FALSE); + } + + /* + * Turn off any present SFP Tx laser + * Expected for health and safety reasons + */ + ixgbe_disable_tx_laser(hw); + + /* + * Tell firmware driver is no longer in control + */ + ixgbe_release_driver_control(hw); + } /* * ixgbe_reset - Reset the chipset and re-start the driver. *
*** 1647,1656 **** --- 1792,1802 ---- * ixgbe_start - Start the driver/chipset. */ int ixgbe_start(ixgbe_t *ixgbe, boolean_t alloc_buffer) { + struct ixgbe_hw *hw = &ixgbe->hw; int i; ASSERT(mutex_owned(&ixgbe->gen_lock)); if (alloc_buffer) {
*** 1682,1691 **** --- 1828,1855 ---- if (ixgbe_chip_start(ixgbe) != IXGBE_SUCCESS) { ixgbe_fm_ereport(ixgbe, DDI_FM_DEVICE_INVAL_STATE); goto start_failure; } + /* + * Configure link now for X550 + * + * X550 possesses a LPLU (Low-Power Link Up) mode which keeps the + * resting state of the adapter at a 1Gb FDX speed. Prior to the X550, + * the resting state of the link would be the maximum speed that + * autonegotiation will allow (usually 10Gb, infrastructure allowing) + * so we never bothered with explicitly setting the link to 10Gb as it + * would already be at that state on driver attach. With X550, we must + * trigger a re-negotiation of the link in order to switch from a LPLU + * 1Gb link to 10Gb (cable and link partner permitting.) + */ + if (hw->mac.type == ixgbe_mac_X550 || + hw->mac.type == ixgbe_mac_X550EM_x) { + (void) ixgbe_driver_setup_link(ixgbe, B_TRUE); + ixgbe_get_hw_state(ixgbe); + } + if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) { goto start_failure; } /*
*** 2189,2206 **** * WTHRESH defaults to 1 (writeback each descriptor) */ reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index)); reg_val |= IXGBE_RXDCTL_ENABLE; /* enable queue */ ! /* Not a valid value for 82599 or X540 */ if (hw->mac.type == ixgbe_mac_82598EB) { reg_val |= 0x0020; /* pthresh */ } IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val); if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540) { reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS); IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); } --- 2353,2372 ---- * WTHRESH defaults to 1 (writeback each descriptor) */ reg_val = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index)); reg_val |= IXGBE_RXDCTL_ENABLE; /* enable queue */ ! /* Not a valid value for 82599, X540 or X550 */ if (hw->mac.type == ixgbe_mac_82598EB) { reg_val |= 0x0020; /* pthresh */ } IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rx_ring->hw_index), reg_val); if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540 || ! hw->mac.type == ixgbe_mac_X550 || ! hw->mac.type == ixgbe_mac_X550EM_x) { reg_val = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); reg_val |= (IXGBE_RDRXCTL_CRCSTRIP | IXGBE_RDRXCTL_AGGDIS); IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg_val); }
*** 2222,2231 **** --- 2388,2403 ---- uint32_t reg_val; uint32_t ring_mapping; uint32_t i, index; uint32_t psrtype_rss_bit; + /* + * Ensure that Rx is disabled while setting up + * the Rx unit and Rx descriptor ring(s) + */ + ixgbe_disable_rx(hw); + /* PSRTYPE must be configured for 82599 */ if (ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ && ixgbe->classify_mode != IXGBE_CLASSIFY_VMDQ_RSS) { reg_val = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR;
*** 2246,2269 **** IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val); } } /* ! * Set filter control in FCTRL to accept broadcast packets and do ! * not pass pause frames to host. Flow control settings are already ! * in this register, so preserve them. */ reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); ! reg_val |= IXGBE_FCTRL_BAM; /* broadcast accept mode */ ! reg_val |= IXGBE_FCTRL_DPF; /* discard pause frames */ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val); /* * Hardware checksum settings */ if (ixgbe->rx_hcksum_enable) { ! reg_val = IXGBE_RXCSUM_IPPCSE; /* IP checksum */ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val); } /* * Setup VMDq and RSS for multiple receive queues --- 2418,2445 ---- IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(i), reg_val); } } /* ! * Set filter control in FCTRL to determine types of packets are passed ! * up to the driver. ! * - Pass broadcast packets. ! * - Do not pass flow control pause frames (82598-specific) */ reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); ! reg_val |= IXGBE_FCTRL_BAM; /* Broadcast Accept Mode */ ! if (hw->mac.type == ixgbe_mac_82598EB) { ! reg_val |= IXGBE_FCTRL_DPF; /* Discard Pause Frames */ ! } IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_val); /* * Hardware checksum settings */ if (ixgbe->rx_hcksum_enable) { ! reg_val = IXGBE_READ_REG(hw, IXGBE_RXCSUM); ! reg_val |= IXGBE_RXCSUM_IPPCSE; /* IP checksum */ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, reg_val); } /* * Setup VMDq and RSS for multiple receive queues
*** 2297,2311 **** break; } /* * Enable the receive unit. This must be done after filter ! * control is set in FCTRL. */ ! reg_val = (IXGBE_RXCTRL_RXEN /* Enable Receive Unit */ ! | IXGBE_RXCTRL_DMBYPS); /* descriptor monitor bypass */ ! IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val); /* * ixgbe_setup_rx_ring must be called after configuring RXCTRL */ for (i = 0; i < ixgbe->num_rx_rings; i++) { --- 2473,2490 ---- break; } /* * Enable the receive unit. This must be done after filter ! * control is set in FCTRL. On 82598, we disable the descriptor monitor. ! * 82598 is the only adapter which defines this RXCTRL option. */ ! reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL); ! if (hw->mac.type == ixgbe_mac_82598EB) ! reg_val |= IXGBE_RXCTRL_DMBYPS; /* descriptor monitor bypass */ ! reg_val |= IXGBE_RXCTRL_RXEN; ! (void) ixgbe_enable_rx_dma(hw, reg_val); /* * ixgbe_setup_rx_ring must be called after configuring RXCTRL */ for (i = 0; i < ixgbe->num_rx_rings; i++) {
*** 2328,2349 **** * The Max Frame Size in MHADD/MAXFRS will be internally increased * by four bytes if the packet has a VLAN field, so includes MTU, * ethernet header and frame check sequence. * Register is MAXFRS in 82599. */ ! reg_val = (ixgbe->default_mtu + sizeof (struct ether_header) + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT; IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val); /* * Setup Jumbo Frame enable bit */ - if (ixgbe->default_mtu > ETHERMTU) { reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); reg_val |= IXGBE_HLREG0_JUMBOEN; IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); - } /* * Setup RSC for multiple receive queues. */ if (ixgbe->lro_enable) { --- 2507,2531 ---- * The Max Frame Size in MHADD/MAXFRS will be internally increased * by four bytes if the packet has a VLAN field, so includes MTU, * ethernet header and frame check sequence. * Register is MAXFRS in 82599. */ ! reg_val = IXGBE_READ_REG(hw, IXGBE_MHADD); ! reg_val &= ~IXGBE_MHADD_MFS_MASK; ! reg_val |= (ixgbe->default_mtu + sizeof (struct ether_header) + ETHERFCSL) << IXGBE_MHADD_MFS_SHIFT; IXGBE_WRITE_REG(hw, IXGBE_MHADD, reg_val); /* * Setup Jumbo Frame enable bit */ reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); + if (ixgbe->default_mtu > ETHERMTU) reg_val |= IXGBE_HLREG0_JUMBOEN; + else + reg_val &= ~IXGBE_HLREG0_JUMBOEN; IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); /* * Setup RSC for multiple receive queues. */ if (ixgbe->lro_enable) {
*** 2494,2503 **** --- 2676,2687 ---- ring_mapping); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping); break; default:
*** 2513,2522 **** --- 2697,2708 ---- IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i >> 2), ring_mapping); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: IXGBE_WRITE_REG(hw, IXGBE_TQSM(i >> 2), ring_mapping); break; default: break;
*** 2529,2542 **** reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN; IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); /* ! * enable DMA for 82599 and X540 parts */ if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540) { /* DMATXCTL.TE must be set after all Tx config is complete */ reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); reg_val |= IXGBE_DMATXCTL_TE; IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val); --- 2715,2730 ---- reg_val = IXGBE_READ_REG(hw, IXGBE_HLREG0); reg_val |= IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN; IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_val); /* ! * enable DMA for 82599, X540 and X550 parts */ if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540 || ! hw->mac.type == ixgbe_mac_X550 || ! hw->mac.type == ixgbe_mac_X550EM_x) { /* DMATXCTL.TE must be set after all Tx config is complete */ reg_val = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); reg_val |= IXGBE_DMATXCTL_TE; IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_val);
*** 2566,2603 **** */ static void ixgbe_setup_rss(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! uint32_t i, mrqc, rxcsum; ! uint32_t random; ! uint32_t reta; ! uint32_t ring_per_group; /* ! * Fill out redirection table */ ! reta = 0; ! ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; - for (i = 0; i < 128; i++) { - reta = (reta << 8) | (i % ring_per_group) | - ((i % ring_per_group) << 4); - if ((i & 3) == 3) - IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); - } - /* - * Fill out hash function seeds with a random constant - */ - for (i = 0; i < 10; i++) { - (void) random_get_pseudo_bytes((uint8_t *)&random, - sizeof (uint32_t)); - IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); - } - - /* * Enable RSS & perform hash on these packet types */ mrqc = IXGBE_MRQC_RSSEN | IXGBE_MRQC_RSS_FIELD_IPV4 | IXGBE_MRQC_RSS_FIELD_IPV4_TCP | --- 2754,2771 ---- */ static void ixgbe_setup_rss(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! uint32_t mrqc; /* ! * Initialize RETA/ERETA table */ ! ixgbe_setup_rss_table(ixgbe); /* * Enable RSS & perform hash on these packet types */ mrqc = IXGBE_MRQC_RSSEN | IXGBE_MRQC_RSS_FIELD_IPV4 | IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
*** 2607,2626 **** IXGBE_MRQC_RSS_FIELD_IPV6 | IXGBE_MRQC_RSS_FIELD_IPV6_TCP | IXGBE_MRQC_RSS_FIELD_IPV6_UDP | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); - - /* - * Disable Packet Checksum to enable RSS for multiple receive queues. - * It is an adapter hardware limitation that Packet Checksum is - * mutually exclusive with RSS. - */ - rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); - rxcsum |= IXGBE_RXCSUM_PCSD; - rxcsum &= ~IXGBE_RXCSUM_IPPCSE; - IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); } /* * ixgbe_setup_vmdq - Setup MAC classification feature */ --- 2775,2784 ----
*** 2645,2654 **** --- 2803,2814 ---- IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: /* * Enable VMDq-only. */ vmdctl = IXGBE_MRQC_VMDQEN; IXGBE_WRITE_REG(hw, IXGBE_MRQC, vmdctl);
*** 2681,2718 **** */ static void ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! uint32_t i, mrqc, rxcsum; ! uint32_t random; ! uint32_t reta; ! uint32_t ring_per_group; ! uint32_t vmdctl, vtctl; /* ! * Fill out redirection table */ ! reta = 0; ! ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; ! for (i = 0; i < 128; i++) { ! reta = (reta << 8) | (i % ring_per_group) | ! ((i % ring_per_group) << 4); ! if ((i & 3) == 3) ! IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); ! } /* - * Fill out hash function seeds with a random constant - */ - for (i = 0; i < 10; i++) { - (void) random_get_pseudo_bytes((uint8_t *)&random, - sizeof (uint32_t)); - IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); - } - - /* * Enable and setup RSS and VMDq */ switch (hw->mac.type) { case ixgbe_mac_82598EB: /* --- 2841,2859 ---- */ static void ixgbe_setup_vmdq_rss(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! uint32_t i, mrqc; ! uint32_t vtctl, vmdctl; /* ! * Initialize RETA/ERETA table */ ! ixgbe_setup_rss_table(ixgbe); /* * Enable and setup RSS and VMDq */ switch (hw->mac.type) { case ixgbe_mac_82598EB: /*
*** 2739,2748 **** --- 2880,2891 ---- IXGBE_WRITE_REG(hw, IXGBE_VMD_CTL, vmdctl); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: /* * Enable RSS & Setup RSS Hash functions */ mrqc = IXGBE_MRQC_RSS_FIELD_IPV4 | IXGBE_MRQC_RSS_FIELD_IPV4_TCP |
*** 2774,2795 **** default: break; } - /* - * Disable Packet Checksum to enable RSS for multiple receive queues. - * It is an adapter hardware limitation that Packet Checksum is - * mutually exclusive with RSS. - */ - rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); - rxcsum |= IXGBE_RXCSUM_PCSD; - rxcsum &= ~IXGBE_RXCSUM_IPPCSE; - IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); - if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540) { /* * Enable Virtualization and Replication. */ vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl); --- 2917,2930 ---- default: break; } if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540 || ! hw->mac.type == ixgbe_mac_X550 || ! hw->mac.type == ixgbe_mac_X550EM_x) { /* * Enable Virtualization and Replication. */ vtctl = IXGBE_VT_CTL_VT_ENABLE | IXGBE_VT_CTL_REPLEN; IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vtctl);
*** 2801,2810 **** --- 2936,3038 ---- IXGBE_WRITE_REG(hw, IXGBE_VFRE(1), IXGBE_VFRE_ENABLE_ALL); } } /* + * ixgbe_setup_rss_table - Setup RSS table + */ + static void + ixgbe_setup_rss_table(ixgbe_t *ixgbe) + { + struct ixgbe_hw *hw = &ixgbe->hw; + uint32_t i, j; + uint32_t random; + uint32_t reta; + uint32_t ring_per_group; + uint32_t ring; + uint32_t table_size; + uint32_t index_mult; + uint32_t rxcsum; + + /* + * Set multiplier for RETA setup and table size based on MAC type. + * RETA table sizes vary by model: + * + * 82598, 82599, X540: 128 table entries. + * X550: 512 table entries. + */ + index_mult = 0x1; + table_size = 128; + switch (ixgbe->hw.mac.type) { + case ixgbe_mac_82598EB: + index_mult = 0x11; + break; + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + table_size = 512; + break; + default: + break; + } + + /* + * Fill out RSS redirection table. The configuation of the indices is + * hardware-dependent. + * + * 82598: 8 bits wide containing two 4 bit RSS indices + * 82599, X540: 8 bits wide containing one 4 bit RSS index + * X550: 8 bits wide containing one 6 bit RSS index + */ + reta = 0; + ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; + + for (i = 0, j = 0; i < table_size; i++, j++) { + if (j == ring_per_group) j = 0; + + /* + * The low 8 bits are for hash value (n+0); + * The next 8 bits are for hash value (n+1), etc. + */ + ring = (j * index_mult); + reta = reta >> 8; + reta = reta | (((uint32_t)ring) << 24); + + if ((i & 3) == 3) + /* + * The first 128 table entries are programmed into the + * RETA register, with any beyond that (eg; on X550) + * into ERETA. + */ + if (i < 128) + IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); + else + IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), + reta); + reta = 0; + } + + /* + * Fill out hash function seeds with a random constant + */ + for (i = 0; i < 10; i++) { + (void) random_get_pseudo_bytes((uint8_t *)&random, + sizeof (uint32_t)); + IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random); + } + + /* + * Disable Packet Checksum to enable RSS for multiple receive queues. + * It is an adapter hardware limitation that Packet Checksum is + * mutually exclusive with RSS. + */ + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + rxcsum |= IXGBE_RXCSUM_PCSD; + rxcsum &= ~IXGBE_RXCSUM_IPPCSE; + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); + } + + /* * ixgbe_init_unicst - Initialize the unicast addresses. */ static void ixgbe_init_unicst(ixgbe_t *ixgbe) {
*** 2997,3016 **** break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: /* * 82599 supports the following combination: * vmdq no. x rss no. * [33..64] x [1..2] * [2..32] x [1..4] * 1 x [1..16] * However 8 rss queue per pool (vmdq) is sufficient for * most cases. * ! * For now, treat X540 like the 82599. */ ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; if (ixgbe->num_rx_groups == 1) { ixgbe->num_rx_rings = min(8, ring_per_group); } else if (ixgbe->num_rx_groups <= 32) { --- 3225,3246 ---- break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: /* * 82599 supports the following combination: * vmdq no. x rss no. * [33..64] x [1..2] * [2..32] x [1..4] * 1 x [1..16] * However 8 rss queue per pool (vmdq) is sufficient for * most cases. * ! * For now, treat X540 and X550 like the 82599. */ ring_per_group = ixgbe->num_rx_rings / ixgbe->num_rx_groups; if (ixgbe->num_rx_groups == 1) { ixgbe->num_rx_rings = min(8, ring_per_group); } else if (ixgbe->num_rx_groups <= 32) {
*** 3169,3181 **** ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE, 0, 1, DEFAULT_TX_HEAD_WB_ENABLE); ixgbe->relax_order_enable = ixgbe_get_prop(ixgbe, PROP_RELAX_ORDER_ENABLE, 0, 1, DEFAULT_RELAX_ORDER_ENABLE); ! /* Head Write Back not recommended for 82599 and X540 */ if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540) { ixgbe->tx_head_wb_enable = B_FALSE; } /* * ixgbe LSO needs the tx h/w checksum support. --- 3399,3413 ---- ixgbe->tx_head_wb_enable = ixgbe_get_prop(ixgbe, PROP_TX_HEAD_WB_ENABLE, 0, 1, DEFAULT_TX_HEAD_WB_ENABLE); ixgbe->relax_order_enable = ixgbe_get_prop(ixgbe, PROP_RELAX_ORDER_ENABLE, 0, 1, DEFAULT_RELAX_ORDER_ENABLE); ! /* Head Write Back not recommended for 82599, X540 and X550 */ if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540 || ! hw->mac.type == ixgbe_mac_X550 || ! hw->mac.type == ixgbe_mac_X550EM_x) { ixgbe->tx_head_wb_enable = B_FALSE; } /* * ixgbe LSO needs the tx h/w checksum support.
*** 3194,3204 **** if (ixgbe->rx_hcksum_enable == B_FALSE) { ixgbe->lro_enable = B_FALSE; } /* ! * ixgbe LRO only been supported by 82599 and X540 now */ if (hw->mac.type == ixgbe_mac_82598EB) { ixgbe->lro_enable = B_FALSE; } ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD, --- 3426,3436 ---- if (ixgbe->rx_hcksum_enable == B_FALSE) { ixgbe->lro_enable = B_FALSE; } /* ! * ixgbe LRO only supported by 82599, X540 and X550 */ if (hw->mac.type == ixgbe_mac_82598EB) { ixgbe->lro_enable = B_FALSE; } ixgbe->tx_copy_thresh = ixgbe_get_prop(ixgbe, PROP_TX_COPY_THRESHOLD,
*** 3224,3253 **** ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING, ixgbe->capab->min_intr_throttle, ixgbe->capab->max_intr_throttle, ixgbe->capab->def_intr_throttle); /* ! * 82599 and X540 require the interrupt throttling rate is ! * a multiple of 8. This is enforced by the register ! * definiton. */ ! if (hw->mac.type == ixgbe_mac_82599EB || hw->mac.type == ixgbe_mac_X540) ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8; hw->allow_unsupported_sfp = ixgbe_get_prop(ixgbe, PROP_ALLOW_UNSUPPORTED_SFP, 0, 1, DEFAULT_ALLOW_UNSUPPORTED_SFP); } static void ixgbe_init_params(ixgbe_t *ixgbe) { ixgbe->param_en_10000fdx_cap = 1; - ixgbe->param_en_1000fdx_cap = 1; - ixgbe->param_en_100fdx_cap = 1; ixgbe->param_adv_10000fdx_cap = 1; ixgbe->param_adv_1000fdx_cap = 1; ixgbe->param_adv_100fdx_cap = 1; ixgbe->param_pause_cap = 1; ixgbe->param_asym_pause_cap = 1; ixgbe->param_rem_fault = 0; --- 3456,3556 ---- ixgbe->intr_throttling[0] = ixgbe_get_prop(ixgbe, PROP_INTR_THROTTLING, ixgbe->capab->min_intr_throttle, ixgbe->capab->max_intr_throttle, ixgbe->capab->def_intr_throttle); /* ! * 82599, X540 and X550 require the interrupt throttling rate is ! * a multiple of 8. This is enforced by the register definiton. */ ! if (hw->mac.type == ixgbe_mac_82599EB || ! hw->mac.type == ixgbe_mac_X540 || ! hw->mac.type == ixgbe_mac_X550 || ! hw->mac.type == ixgbe_mac_X550EM_x) ixgbe->intr_throttling[0] = ixgbe->intr_throttling[0] & 0xFF8; hw->allow_unsupported_sfp = ixgbe_get_prop(ixgbe, PROP_ALLOW_UNSUPPORTED_SFP, 0, 1, DEFAULT_ALLOW_UNSUPPORTED_SFP); } static void ixgbe_init_params(ixgbe_t *ixgbe) { + struct ixgbe_hw *hw = &ixgbe->hw; + ixgbe_link_speed speeds_supported = 0; + boolean_t negotiate; + + /* + * Get a list of speeds the adapter supports. If the hw struct hasn't + * been populated with this information yet, retrieve it from the + * adapter and save it to our own variable. + * + * On certain adapters, such as ones which use SFPs, the contents of + * hw->phy.speeds_supported (and hw->phy.autoneg_advertised) are not + * updated, so we must rely on calling ixgbe_get_link_capabilities() + * in order to ascertain the speeds which we are capable of supporting, + * and in the case of SFP-equipped adapters, which speed we are + * advertising. If ixgbe_get_link_capabilities() fails for some reason, + * we'll go with a default list of speeds as a last resort. + */ + speeds_supported = hw->phy.speeds_supported; + + if (speeds_supported == 0) { + if (ixgbe_get_link_capabilities(hw, &speeds_supported, + &negotiate) != IXGBE_SUCCESS) { + if (hw->mac.type == ixgbe_mac_82598EB) { + speeds_supported = + IXGBE_LINK_SPEED_82598_AUTONEG; + } else { + speeds_supported = + IXGBE_LINK_SPEED_82599_AUTONEG; + } + } + } + ixgbe->speeds_supported = speeds_supported; + + /* + * By default, all supported speeds are enabled and advertised. + */ + if (speeds_supported & IXGBE_LINK_SPEED_10GB_FULL) { ixgbe->param_en_10000fdx_cap = 1; ixgbe->param_adv_10000fdx_cap = 1; + } else { + ixgbe->param_en_10000fdx_cap = 0; + ixgbe->param_adv_10000fdx_cap = 0; + } + + if (speeds_supported & IXGBE_LINK_SPEED_5GB_FULL) { + ixgbe->param_en_5000fdx_cap = 1; + ixgbe->param_adv_5000fdx_cap = 1; + } else { + ixgbe->param_en_5000fdx_cap = 0; + ixgbe->param_adv_5000fdx_cap = 0; + } + + if (speeds_supported & IXGBE_LINK_SPEED_2_5GB_FULL) { + ixgbe->param_en_2500fdx_cap = 1; + ixgbe->param_adv_2500fdx_cap = 1; + } else { + ixgbe->param_en_2500fdx_cap = 0; + ixgbe->param_adv_2500fdx_cap = 0; + } + + if (speeds_supported & IXGBE_LINK_SPEED_1GB_FULL) { + ixgbe->param_en_1000fdx_cap = 1; ixgbe->param_adv_1000fdx_cap = 1; + } else { + ixgbe->param_en_1000fdx_cap = 0; + ixgbe->param_adv_1000fdx_cap = 0; + } + + if (speeds_supported & IXGBE_LINK_SPEED_100_FULL) { + ixgbe->param_en_100fdx_cap = 1; ixgbe->param_adv_100fdx_cap = 1; + } else { + ixgbe->param_en_100fdx_cap = 0; + ixgbe->param_adv_100fdx_cap = 0; + } ixgbe->param_pause_cap = 1; ixgbe->param_asym_pause_cap = 1; ixgbe->param_rem_fault = 0;
*** 3255,3264 **** --- 3558,3569 ---- ixgbe->param_adv_pause_cap = 1; ixgbe->param_adv_asym_pause_cap = 1; ixgbe->param_adv_rem_fault = 0; ixgbe->param_lp_10000fdx_cap = 0; + ixgbe->param_lp_5000fdx_cap = 0; + ixgbe->param_lp_2500fdx_cap = 0; ixgbe->param_lp_1000fdx_cap = 0; ixgbe->param_lp_100fdx_cap = 0; ixgbe->param_lp_autoneg_cap = 0; ixgbe->param_lp_pause_cap = 0; ixgbe->param_lp_asym_pause_cap = 0;
*** 3302,3337 **** * ixgbe_driver_setup_link - Using the link properties to setup the link. */ int ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw) { ! u32 autoneg_advertised = 0; /* ! * No half duplex support with 10Gb parts */ ! if (ixgbe->param_adv_10000fdx_cap == 1) ! autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL; ! if (ixgbe->param_adv_1000fdx_cap == 1) ! autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL; ! if (ixgbe->param_adv_100fdx_cap == 1) ! autoneg_advertised |= IXGBE_LINK_SPEED_100_FULL; ! if (ixgbe->param_adv_autoneg_cap == 1 && autoneg_advertised == 0) { ! ixgbe_notice(ixgbe, "Invalid link settings. Setup link " ! "to autonegotiation with full link capabilities."); ! autoneg_advertised = IXGBE_LINK_SPEED_10GB_FULL | ! IXGBE_LINK_SPEED_1GB_FULL | ! IXGBE_LINK_SPEED_100_FULL; } if (setup_hw) { ! if (ixgbe_setup_link(&ixgbe->hw, autoneg_advertised, ! ixgbe->param_adv_autoneg_cap, B_TRUE) != IXGBE_SUCCESS) { ixgbe_notice(ixgbe, "Setup link failed on this " "device."); return (IXGBE_FAILURE); } } --- 3607,3653 ---- * ixgbe_driver_setup_link - Using the link properties to setup the link. */ int ixgbe_driver_setup_link(ixgbe_t *ixgbe, boolean_t setup_hw) { ! struct ixgbe_hw *hw = &ixgbe->hw; ! ixgbe_link_speed advertised = 0; /* ! * Assemble a list of enabled speeds to auto-negotiate with. */ ! if (ixgbe->param_en_10000fdx_cap == 1) ! advertised |= IXGBE_LINK_SPEED_10GB_FULL; ! if (ixgbe->param_en_5000fdx_cap == 1) ! advertised |= IXGBE_LINK_SPEED_5GB_FULL; ! if (ixgbe->param_en_2500fdx_cap == 1) ! advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; ! if (ixgbe->param_en_1000fdx_cap == 1) ! advertised |= IXGBE_LINK_SPEED_1GB_FULL; ! if (ixgbe->param_en_100fdx_cap == 1) ! advertised |= IXGBE_LINK_SPEED_100_FULL; ! ! /* ! * As a last resort, autoneg with a default list of speeds. ! */ ! if (ixgbe->param_adv_autoneg_cap == 1 && advertised == 0) { ! ixgbe_notice(ixgbe, "Invalid link settings. Setting link " ! "to autonegotiate with full capabilities."); ! ! if (hw->mac.type == ixgbe_mac_82598EB) ! advertised = IXGBE_LINK_SPEED_82598_AUTONEG; ! else ! advertised = IXGBE_LINK_SPEED_82599_AUTONEG; } if (setup_hw) { ! if (ixgbe_setup_link(&ixgbe->hw, advertised, ! ixgbe->param_adv_autoneg_cap) != IXGBE_SUCCESS) { ixgbe_notice(ixgbe, "Setup link failed on this " "device."); return (IXGBE_FAILURE); } }
*** 3352,3362 **** boolean_t link_up = B_FALSE; boolean_t link_changed = B_FALSE; ASSERT(mutex_owned(&ixgbe->gen_lock)); ! (void) ixgbe_check_link(hw, &speed, &link_up, false); if (link_up) { ixgbe->link_check_complete = B_TRUE; /* Link is up, enable flow control settings */ (void) ixgbe_fc_enable(hw); --- 3668,3678 ---- boolean_t link_up = B_FALSE; boolean_t link_changed = B_FALSE; ASSERT(mutex_owned(&ixgbe->gen_lock)); ! (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE); if (link_up) { ixgbe->link_check_complete = B_TRUE; /* Link is up, enable flow control settings */ (void) ixgbe_fc_enable(hw);
*** 3367,3376 **** --- 3683,3698 ---- if (ixgbe->link_state != LINK_STATE_UP) { switch (speed) { case IXGBE_LINK_SPEED_10GB_FULL: ixgbe->link_speed = SPEED_10GB; break; + case IXGBE_LINK_SPEED_5GB_FULL: + ixgbe->link_speed = SPEED_5GB; + break; + case IXGBE_LINK_SPEED_2_5GB_FULL: + ixgbe->link_speed = SPEED_2_5GB; + break; case IXGBE_LINK_SPEED_1GB_FULL: ixgbe->link_speed = SPEED_1GB; break; case IXGBE_LINK_SPEED_100_FULL: ixgbe->link_speed = SPEED_100;
*** 3420,3448 **** ixgbe_t *ixgbe = (ixgbe_t *)arg; uint32_t eicr = ixgbe->eicr; struct ixgbe_hw *hw = &ixgbe->hw; mutex_enter(&ixgbe->gen_lock); ! if (eicr & IXGBE_EICR_GPI_SDP1) { /* clear the interrupt */ ! IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); /* if link up, do multispeed fiber setup */ (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, ! B_TRUE, B_TRUE); ixgbe_driver_link_check(ixgbe); ixgbe_get_hw_state(ixgbe); ! } else if (eicr & IXGBE_EICR_GPI_SDP2) { /* clear the interrupt */ ! IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); /* if link up, do sfp module setup */ (void) hw->mac.ops.setup_sfp(hw); /* do multispeed fiber setup */ (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, ! B_TRUE, B_TRUE); ixgbe_driver_link_check(ixgbe); ixgbe_get_hw_state(ixgbe); } mutex_exit(&ixgbe->gen_lock); --- 3742,3770 ---- ixgbe_t *ixgbe = (ixgbe_t *)arg; uint32_t eicr = ixgbe->eicr; struct ixgbe_hw *hw = &ixgbe->hw; mutex_enter(&ixgbe->gen_lock); ! if (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { /* clear the interrupt */ ! IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); /* if link up, do multispeed fiber setup */ (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, ! B_TRUE); ixgbe_driver_link_check(ixgbe); ixgbe_get_hw_state(ixgbe); ! } else if (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)) { /* clear the interrupt */ ! IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2_BY_MAC(hw)); /* if link up, do sfp module setup */ (void) hw->mac.ops.setup_sfp(hw); /* do multispeed fiber setup */ (void) ixgbe_setup_link(hw, IXGBE_LINK_SPEED_82599_AUTONEG, ! B_TRUE); ixgbe_driver_link_check(ixgbe); ixgbe_get_hw_state(ixgbe); } mutex_exit(&ixgbe->gen_lock);
*** 3471,3484 **** boolean_t link_up; mutex_enter(&ixgbe->gen_lock); /* make sure we know current state of link */ ! (void) ixgbe_check_link(hw, &speed, &link_up, false); /* check over-temp condition */ ! if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) || (eicr & IXGBE_EICR_LSC)) { if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) { atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP); /* --- 3793,3806 ---- boolean_t link_up; mutex_enter(&ixgbe->gen_lock); /* make sure we know current state of link */ ! (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE); /* check over-temp condition */ ! if (((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) && (!link_up)) || (eicr & IXGBE_EICR_LSC)) { if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) { atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP); /*
*** 3507,3516 **** --- 3829,3897 ---- mutex_exit(&ixgbe->gen_lock); } /* + * ixgbe_phy_check - taskq to process interrupts from an external PHY + * + * This routine will only be called on adapters with external PHYs + * (such as X550) that may be trying to raise our attention to some event. + * Currently, this is limited to claiming PHY overtemperature and link status + * change (LSC) events, however this may expand to include other things in + * future adapters. + */ + static void + ixgbe_phy_check(void *arg) + { + ixgbe_t *ixgbe = (ixgbe_t *)arg; + struct ixgbe_hw *hw = &ixgbe->hw; + int rv; + + mutex_enter(&ixgbe->gen_lock); + + /* + * X550 baseT PHY overtemp and LSC events are handled here. + * + * If an overtemp event occurs, it will be reflected in the + * return value of phy.ops.handle_lasi() and the common code will + * automatically power off the baseT PHY. This is our cue to trigger + * an FMA event. + * + * If a link status change event occurs, phy.ops.handle_lasi() will + * automatically initiate a link setup between the integrated KR PHY + * and the external X557 PHY to ensure that the link speed between + * them matches the link speed of the baseT link. + */ + rv = ixgbe_handle_lasi(hw); + + if (rv == IXGBE_ERR_OVERTEMP) { + atomic_or_32(&ixgbe->ixgbe_state, IXGBE_OVERTEMP); + + /* + * Disable the adapter interrupts + */ + ixgbe_disable_adapter_interrupts(ixgbe); + + /* + * Disable Rx/Tx units + */ + (void) ixgbe_stop_adapter(hw); + + ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_LOST); + ixgbe_error(ixgbe, + "Problem: Network adapter has been stopped due to a " + "overtemperature event being detected."); + ixgbe_error(ixgbe, + "Action: Shut down or restart the computer. If the issue " + "persists, please take action in accordance with the " + "recommendations from your system vendor."); + } + + mutex_exit(&ixgbe->gen_lock); + } + + /* * ixgbe_link_timer - timer for link status detection */ static void ixgbe_link_timer(void *arg) {
*** 3670,3680 **** /* * Finally(!), if there's a valid "mac-address" property (created * if we netbooted from this interface), we must use this instead * of any of the above to ensure that the NFS/install server doesn't ! * get confused by the address changing as Solaris takes over! */ err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); if (err == DDI_PROP_SUCCESS) { if (nelts == ETHERADDRL) { --- 4051,4061 ---- /* * Finally(!), if there's a valid "mac-address" property (created * if we netbooted from this interface), we must use this instead * of any of the above to ensure that the NFS/install server doesn't ! * get confused by the address changing as illumos takes over! */ err = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, ixgbe->dip, DDI_PROP_DONTPASS, "mac-address", &bytes, &nelts); if (err == DDI_PROP_SUCCESS) { if (nelts == ETHERADDRL) {
*** 3860,3871 **** /* disable autoclear, leave gpie at default */ eiac = 0; /* * General purpose interrupt enable. ! * For 82599 or X540, extended interrupt automask enable ! * only in MSI or MSI-X mode */ if ((hw->mac.type == ixgbe_mac_82598EB) || (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) { gpie |= IXGBE_GPIE_EIAME; } --- 4241,4252 ---- /* disable autoclear, leave gpie at default */ eiac = 0; /* * General purpose interrupt enable. ! * For 82599, X540 and X550, extended interrupt ! * automask enable only in MSI or MSI-X mode */ if ((hw->mac.type == ixgbe_mac_82598EB) || (ixgbe->intr_type == DDI_INTR_TYPE_MSI)) { gpie |= IXGBE_GPIE_EIAME; }
*** 3877,3886 **** --- 4258,4269 ---- gpie |= ixgbe->capab->other_gpie; break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: gpie |= ixgbe->capab->other_gpie; /* Enable RSC Delay 8us when LRO enabled */ if (ixgbe->lro_enable) { gpie |= (1 << IXGBE_GPIE_RSC_DELAY_SHIFT);
*** 4071,4087 **** atlas); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); reg |= (IXGBE_AUTOC_FLU | IXGBE_AUTOC_10G_KX4); IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); (void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL, ! B_FALSE, B_TRUE); break; default: break; } --- 4454,4472 ---- atlas); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: reg = IXGBE_READ_REG(&ixgbe->hw, IXGBE_AUTOC); reg |= (IXGBE_AUTOC_FLU | IXGBE_AUTOC_10G_KX4); IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_AUTOC, reg); (void) ixgbe_setup_link(&ixgbe->hw, IXGBE_LINK_SPEED_10GB_FULL, ! B_FALSE); break; default: break; }
*** 4137,4146 **** --- 4522,4533 ---- * ixgbe_intr_other_work - Process interrupt types other than tx/rx */ static void ixgbe_intr_other_work(ixgbe_t *ixgbe, uint32_t eicr) { + struct ixgbe_hw *hw = &ixgbe->hw; + ASSERT(mutex_owned(&ixgbe->gen_lock)); /* * handle link status change */
*** 4179,4189 **** /* * Do SFP check for adapters with hot-plug capability */ if ((ixgbe->capab->flags & IXGBE_FLAG_SFP_PLUG_CAPABLE) && ! ((eicr & IXGBE_EICR_GPI_SDP1) || (eicr & IXGBE_EICR_GPI_SDP2))) { ixgbe->eicr = eicr; if ((ddi_taskq_dispatch(ixgbe->sfp_taskq, ixgbe_sfp_check, (void *)ixgbe, DDI_NOSLEEP)) != DDI_SUCCESS) { ixgbe_log(ixgbe, "No memory available to dispatch " --- 4566,4577 ---- /* * Do SFP check for adapters with hot-plug capability */ if ((ixgbe->capab->flags & IXGBE_FLAG_SFP_PLUG_CAPABLE) && ! ((eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) || ! (eicr & IXGBE_EICR_GPI_SDP2_BY_MAC(hw)))) { ixgbe->eicr = eicr; if ((ddi_taskq_dispatch(ixgbe->sfp_taskq, ixgbe_sfp_check, (void *)ixgbe, DDI_NOSLEEP)) != DDI_SUCCESS) { ixgbe_log(ixgbe, "No memory available to dispatch "
*** 4193,4211 **** /* * Do over-temperature check for adapters with temp sensor */ if ((ixgbe->capab->flags & IXGBE_FLAG_TEMP_SENSOR_CAPABLE) && ! ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { ixgbe->eicr = eicr; if ((ddi_taskq_dispatch(ixgbe->overtemp_taskq, ixgbe_overtemp_check, (void *)ixgbe, DDI_NOSLEEP)) != DDI_SUCCESS) { ixgbe_log(ixgbe, "No memory available to dispatch " "taskq for overtemp check"); } } } /* * ixgbe_intr_legacy - Interrupt handler for legacy interrupts. */ --- 4581,4614 ---- /* * Do over-temperature check for adapters with temp sensor */ if ((ixgbe->capab->flags & IXGBE_FLAG_TEMP_SENSOR_CAPABLE) && ! ((eicr & IXGBE_EICR_GPI_SDP0_BY_MAC(hw)) || ! (eicr & IXGBE_EICR_LSC))) { ixgbe->eicr = eicr; if ((ddi_taskq_dispatch(ixgbe->overtemp_taskq, ixgbe_overtemp_check, (void *)ixgbe, DDI_NOSLEEP)) != DDI_SUCCESS) { ixgbe_log(ixgbe, "No memory available to dispatch " "taskq for overtemp check"); } } + + /* + * Process an external PHY interrupt + */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && + (eicr & IXGBE_EICR_GPI_SDP0_X540)) { + ixgbe->eicr = eicr; + if ((ddi_taskq_dispatch(ixgbe->phy_taskq, + ixgbe_phy_check, (void *)ixgbe, + DDI_NOSLEEP)) != DDI_SUCCESS) { + ixgbe_log(ixgbe, "No memory available to dispatch " + "taskq for PHY check"); + } + } } /* * ixgbe_intr_legacy - Interrupt handler for legacy interrupts. */
*** 4290,4299 **** --- 4693,4704 ---- ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: ixgbe->eimc = IXGBE_82599_OTHER_INTR; IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); break; default:
*** 4384,4393 **** --- 4789,4800 ---- ixgbe->eims &= ~(eicr & IXGBE_OTHER_INTR); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: ixgbe->eimc = IXGBE_82599_OTHER_INTR; IXGBE_WRITE_REG(hw, IXGBE_EIMC, ixgbe->eimc); break; default:
*** 4464,4473 **** --- 4871,4882 ---- ixgbe_intr_other_work(ixgbe, eicr); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: ixgbe->eims |= IXGBE_EICR_RTX_QUEUE; ixgbe_intr_other_work(ixgbe, eicr); break; default:
*** 4553,4562 **** --- 4962,4988 ---- /* * Install legacy interrupts */ if (intr_types & DDI_INTR_TYPE_FIXED) { + /* + * Disallow legacy interrupts for X550. X550 has a silicon + * bug which prevents Shared Legacy interrupts from working. + * For details, please reference: + * + * Intel Ethernet Controller X550 Specification Update rev. 2.1 + * May 2016, erratum 22: PCIe Interrupt Status Bit + */ + if (ixgbe->hw.mac.type == ixgbe_mac_X550 || + ixgbe->hw.mac.type == ixgbe_mac_X550EM_x || + ixgbe->hw.mac.type == ixgbe_mac_X550_vf || + ixgbe->hw.mac.type == ixgbe_mac_X550EM_x_vf) { + ixgbe_log(ixgbe, + "Legacy interrupts are not supported on this " + "adapter. Please use MSI or MSI-X instead."); + return (IXGBE_FAILURE); + } rc = ixgbe_alloc_intr_handles(ixgbe, DDI_INTR_TYPE_FIXED); if (rc == IXGBE_SUCCESS) return (IXGBE_SUCCESS); ixgbe_log(ixgbe,
*** 4865,4874 **** --- 5291,5302 ---- IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: if (cause == -1) { /* other causes */ msix_vector |= IXGBE_IVAR_ALLOC_VAL; index = (intr_alloc_entry & 1) * 8; ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC);
*** 4919,4928 **** --- 5347,5358 ---- IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: if (cause == -1) { /* other causes */ index = (intr_alloc_entry & 1) * 8; ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); ivar |= (IXGBE_IVAR_ALLOC_VAL << index);
*** 4969,4978 **** --- 5399,5410 ---- IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: if (cause == -1) { /* other causes */ index = (intr_alloc_entry & 1) * 8; ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); ivar &= ~(IXGBE_IVAR_ALLOC_VAL << index);
*** 5012,5021 **** --- 5444,5455 ---- case ixgbe_mac_82598EB: return (sw_rx_index); case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: return (sw_rx_index * 2); default: break; }
*** 5028,5037 **** --- 5462,5473 ---- 16 + (sw_rx_index % rx_ring_per_group); return (hw_rx_index); case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: if (ixgbe->num_rx_groups > 32) { hw_rx_index = (sw_rx_index / rx_ring_per_group) * 2 + (sw_rx_index % rx_ring_per_group); } else {
*** 5133,5142 **** --- 5569,5580 ---- IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: for (v_idx = 0; v_idx < 64; v_idx++) IXGBE_WRITE_REG(hw, IXGBE_IVAR(v_idx), 0); IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, 0); break;
*** 5308,5346 **** */ static void ixgbe_get_hw_state(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! ixgbe_link_speed speed = IXGBE_LINK_SPEED_UNKNOWN; boolean_t link_up = B_FALSE; uint32_t pcs1g_anlp = 0; - uint32_t pcs1g_ana = 0; - boolean_t autoneg = B_FALSE; ASSERT(mutex_owned(&ixgbe->gen_lock)); ixgbe->param_lp_1000fdx_cap = 0; ixgbe->param_lp_100fdx_cap = 0; /* check for link, don't wait */ ! (void) ixgbe_check_link(hw, &speed, &link_up, false); ! pcs1g_ana = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); if (link_up) { pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); ixgbe->param_lp_1000fdx_cap = (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; ixgbe->param_lp_100fdx_cap = (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; } ! (void) ixgbe_get_link_capabilities(hw, &speed, &autoneg); ! ixgbe->param_adv_1000fdx_cap = ((pcs1g_ana & IXGBE_PCS1GANA_FDC) && ! (speed & IXGBE_LINK_SPEED_1GB_FULL)) ? 1 : 0; ! ixgbe->param_adv_100fdx_cap = ((pcs1g_ana & IXGBE_PCS1GANA_FDC) && ! (speed & IXGBE_LINK_SPEED_100_FULL)) ? 1 : 0; } /* * ixgbe_get_driver_control - Notify that driver is in control of device. */ --- 5746,5810 ---- */ static void ixgbe_get_hw_state(ixgbe_t *ixgbe) { struct ixgbe_hw *hw = &ixgbe->hw; ! ixgbe_link_speed speed = 0; boolean_t link_up = B_FALSE; uint32_t pcs1g_anlp = 0; ASSERT(mutex_owned(&ixgbe->gen_lock)); ixgbe->param_lp_1000fdx_cap = 0; ixgbe->param_lp_100fdx_cap = 0; /* check for link, don't wait */ ! (void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE); + /* + * Update the observed Link Partner's capabilities. Not all adapters + * can provide full information on the LP's capable speeds, so we + * provide what we can. + */ if (link_up) { pcs1g_anlp = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); ixgbe->param_lp_1000fdx_cap = (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; ixgbe->param_lp_100fdx_cap = (pcs1g_anlp & IXGBE_PCS1GANLP_LPFD) ? 1 : 0; } ! /* ! * Update GLD's notion of the adapter's currently advertised speeds. ! * Since the common code doesn't always record the current autonegotiate ! * settings in the phy struct for all parts (specifically, adapters with ! * SFPs) we first test to see if it is 0, and if so, we fall back to ! * using the adapter's speed capabilities which we saved during instance ! * init in ixgbe_init_params(). ! * ! * Adapters with SFPs will always be shown as advertising all of their ! * supported speeds, and adapters with baseT PHYs (where the phy struct ! * is maintained by the common code) will always have a factual view of ! * their currently-advertised speeds. In the case of SFPs, this is ! * acceptable as we default to advertising all speeds that the adapter ! * claims to support, and those properties are immutable; unlike on ! * baseT (copper) PHYs, where speeds can be enabled or disabled at will. ! */ ! speed = hw->phy.autoneg_advertised; ! if (speed == 0) ! speed = ixgbe->speeds_supported; ! ixgbe->param_adv_10000fdx_cap = ! (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 1 : 0; ! ixgbe->param_adv_5000fdx_cap = ! (speed & IXGBE_LINK_SPEED_5GB_FULL) ? 1 : 0; ! ixgbe->param_adv_2500fdx_cap = ! (speed & IXGBE_LINK_SPEED_2_5GB_FULL) ? 1 : 0; ! ixgbe->param_adv_1000fdx_cap = ! (speed & IXGBE_LINK_SPEED_1GB_FULL) ? 1 : 0; ! ixgbe->param_adv_100fdx_cap = ! (speed & IXGBE_LINK_SPEED_100_FULL) ? 1 : 0; } /* * ixgbe_get_driver_control - Notify that driver is in control of device. */