On Thu, Nov 17, 2016 at 23:23 +0100, Mike Belopuhov wrote: > On Thu, Nov 17, 2016 at 22:24 +0100, Mike Belopuhov wrote: > > On Wed, Nov 16, 2016 at 23:04 +0100, Mike Belopuhov wrote: > > > Hi, > > > > > > I've done a massive update of our ix(4) driver that brings > > > support for X550 family of controllers including those > > > integrated into new Xeon chips as well as QSFP support for > > > X520 (82599) but this needs thorough testing. If you're > > > using Intel 10Gb controllers, please make sure that you > > > either (or both!) test the complete diff found at this URL: > > > http://gir.theapt.org/~mike/ixgbe.diff or next few snapshots > > > that will (hopefully) contain bits of this monster diff. > > > > > > To test the monster diff, make sure that you are running a > > > recent snapshot and your kernel source code is up-to-date, > > > then reset a few files to the specified revisions and > > > remove the support file for X550: > > > > > > % pwd > > > /usr/src > > > % cvs up -r1.326 sys/dev/pci/files.pci > > > % cvs up -r1.133 sys/dev/pci/if_ix.c > > > % cvs up -r1.14 sys/dev/pci/ixgbe.c > > > % cvs up -r1.23 sys/dev/pci/ixgbe.h > > > % cvs up -r1.11 sys/dev/pci/ixgbe_82598.c > > > % cvs up -r1.12 sys/dev/pci/ixgbe_82599.c > > > % cvs up -r1.13 sys/dev/pci/ixgbe_phy.c > > > % cvs up -r1.22 sys/dev/pci/ixgbe_type.h > > > % cvs up -r1.4 sys/dev/pci/ixgbe_x540.c > > > % rm -f sys/dev/pci/ixgbe_x550.c > > > > > > To verify that files have been reset: > > > > > > % pwd > > > /usr/src > > > % fgrep "//T1" sys/dev/pci/CVS/Entries > > > /files.pci/1.326/Mon Sep 12 09:45:53 2016//T1.326 > > > /if_ix.c/1.133/Thu Oct 27 05:00:50 2016//T1.133 > > > /ixgbe.c/1.14/Wed Nov 26 17:03:52 2014//T1.14 > > > /ixgbe.h/1.23/Tue Oct 4 09:24:02 2016//T1.23 > > > /ixgbe_82598.c/1.11/Mon Aug 5 19:58:06 2013//T1.11 > > > /ixgbe_82599.c/1.12/Fri May 1 04:15:00 2015//T1.12 > > > /ixgbe_phy.c/1.13/Fri May 1 04:15:00 2015//T1.13 > > > /ixgbe_type.h/1.22/Wed Nov 16 21:53:57 2016//T1.22 > > > /ixgbe_x540.c/1.4/Wed May 20 14:34:27 2015//T1.4 > > > > > > And then test and apply the diff: > > > > > > % pwd > > > /usr/src > > > % patch -Csp0 </tmp/ixgbe.diff && patch -sp0 </tmp/ixgbe.diff > > > > > > Make sure to reset files every time the source tree gets updated. > > > > > > Cheers, > > > Mike > > > > As of today and file revisions below, most of the boilerplate > > code is now committed. I've tried very hard to not introduce > > any noticeable changes in behavior so far. > > > > if_ix.c/1.133 > > ixgbe_82598.c/1.15 > > ixgbe_x550.c/1.1 > > ixgbe.c/1.19 > > ixgbe.h/1.26 > > ixgbe_82599.c/1.16 > > ixgbe_x540.c/1.9 > > ixgbe_type.h/1.29 > > ixgbe_phy.c/1.18 > > > > Remaining bits are below. I'll start picking at low hanging fruits, > > but won't mind another pair of eyes. > > > > I've just realised I forgot to commit one small bit that is > also not part of this diff that might fail the kernel compile. > I'll post an update in about 12 hours.
OK, the issue is resolved now. ixgbe_x550.c should be at 1.2 now. Here's an updated diff (Hrvoje Popovski has found out that enable_tx_laser function pointers can be not set by X550). diff --git sys/dev/pci/files.pci sys/dev/pci/files.pci index a6b91fb..34ce9bf 100644 --- sys/dev/pci/files.pci +++ sys/dev/pci/files.pci @@ -356,10 +356,11 @@ attach ix at pci file dev/pci/if_ix.c ix file dev/pci/ixgbe.c ix file dev/pci/ixgbe_82598.c ix file dev/pci/ixgbe_82599.c ix file dev/pci/ixgbe_x540.c ix +file dev/pci/ixgbe_x550.c ix file dev/pci/ixgbe_phy.c ix # Neterion Xframe 10 Gigabit ethernet device xge: ether, ifnet, ifmedia attach xge at pci diff --git sys/dev/pci/if_ix.c sys/dev/pci/if_ix.c index d13baea..c07758b 100644 --- sys/dev/pci/if_ix.c +++ sys/dev/pci/if_ix.c @@ -69,14 +69,24 @@ const struct pci_matchid ixgbe_devices[] = { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_BPLANE_FCOE }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_CX4 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_T3_LOM }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_SFP }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_SFP_EM }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_SFP_SF_QP }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_SFP_SF2 }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_SFP_FCOE }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599EN_SFP }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_QSFP_SF_QP }, { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X540T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X540T1 }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550T1 }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550EM_X_KX4 }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550EM_X_KR }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550EM_X_SFP }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550EM_X_10G_T }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_X550EM_X_1G_T }, }; /********************************************************************* * Function prototypes *********************************************************************/ @@ -96,11 +106,13 @@ int ixgbe_allocate_pci_resources(struct ix_softc *); int ixgbe_allocate_legacy(struct ix_softc *); int ixgbe_allocate_queues(struct ix_softc *); void ixgbe_free_pci_resources(struct ix_softc *); void ixgbe_local_timer(void *); void ixgbe_setup_interface(struct ix_softc *); -void ixgbe_config_link(struct ix_softc *sc); +void ixgbe_config_gpie(struct ix_softc *); +void ixgbe_config_delay_values(struct ix_softc *); +void ixgbe_config_link(struct ix_softc *); int ixgbe_allocate_transmit_buffers(struct tx_ring *); int ixgbe_setup_transmit_structures(struct ix_softc *); int ixgbe_setup_transmit_ring(struct tx_ring *); void ixgbe_initialize_transmit_units(struct ix_softc *); @@ -111,10 +123,11 @@ int ixgbe_allocate_receive_buffers(struct rx_ring *); int ixgbe_setup_receive_structures(struct ix_softc *); int ixgbe_setup_receive_ring(struct rx_ring *); void ixgbe_initialize_receive_units(struct ix_softc *); void ixgbe_free_receive_structures(struct ix_softc *); void ixgbe_free_receive_buffers(struct rx_ring *); +void ixgbe_initialize_rss_mapping(struct ix_softc *); int ixgbe_rxfill(struct rx_ring *); void ixgbe_rxrefill(void *); void ixgbe_enable_intr(struct ix_softc *); void ixgbe_disable_intr(struct ix_softc *); @@ -144,10 +157,11 @@ void ixgbe_setup_vlan_hw_support(struct ix_softc *); /* Support for pluggable optic modules */ void ixgbe_setup_optics(struct ix_softc *); void ixgbe_handle_mod(struct ix_softc *); void ixgbe_handle_msf(struct ix_softc *); +void ixgbe_handle_phy(struct ix_softc *); /* Legacy (single vector interrupt handler */ int ixgbe_intr(void *); void ixgbe_enable_queue(struct ix_softc *, uint32_t); void ixgbe_disable_queue(struct ix_softc *, uint32_t); @@ -252,11 +266,11 @@ ixgbe_attach(struct device *parent, struct device *self, void *aux) error = ixgbe_init_hw(hw); if (error == IXGBE_ERR_EEPROM_VERSION) { printf(": This device is a pre-production adapter/" "LOM. Please be aware there may be issues associated " - "with your hardware.\n If you are experiencing problems " + "with your hardware.\nIf you are experiencing problems " "please contact your Intel or hardware representative " "who provided you with this hardware.\n"); } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { printf(": Unsupported SFP+ Module\n"); } @@ -274,10 +288,18 @@ ixgbe_attach(struct device *parent, struct device *self, void *aux) error = ixgbe_allocate_legacy(sc); if (error) goto err_late; + /* Enable the optics for 82599 SFP+ fiber */ + if (sc->hw.mac.ops.enable_tx_laser) + sc->hw.mac.ops.enable_tx_laser(&sc->hw); + + /* Enable power to the phy */ + if (hw->phy.ops.set_phy_power) + hw->phy.ops.set_phy_power(&sc->hw, TRUE); + /* Setup OS specific network interface */ ixgbe_setup_interface(sc); /* Initialize statistics */ ixgbe_update_stats_counters(sc); @@ -583,11 +605,11 @@ void ixgbe_init(void *arg) { struct ix_softc *sc = (struct ix_softc *)arg; struct ifnet *ifp = &sc->arpcom.ac_if; struct rx_ring *rxr = sc->rx_rings; - uint32_t k, txdctl, rxdctl, rxctrl, mhadd, gpie, itr; + uint32_t k, txdctl, rxdctl, rxctrl, mhadd, itr; int i, s, err; INIT_DEBUGOUT("ixgbe_init: begin"); s = splnet(); @@ -628,56 +650,23 @@ ixgbe_init(void *arg) } /* Configure RX settings */ ixgbe_initialize_receive_units(sc); + /* Enable SDP & MSIX interrupts based on adapter */ + ixgbe_config_gpie(sc); + /* Program promiscuous mode and multicast filters. */ ixgbe_iff(sc); - gpie = IXGBE_READ_REG(&sc->hw, IXGBE_GPIE); - - /* Enable Fan Failure Interrupt */ - gpie |= IXGBE_SDP1_GPIEN; - - if (sc->hw.mac.type == ixgbe_mac_82599EB) { - /* Add for Module detection */ - gpie |= IXGBE_SDP2_GPIEN; - - /* - * Set LL interval to max to reduce the number of low latency - * interrupts hitting the card when the ring is getting full. - */ - gpie |= 0xf << IXGBE_GPIE_LLI_DELAY_SHIFT; - } - - if (sc->hw.mac.type == ixgbe_mac_X540) { - /* Thermal Failure Detection */ - gpie |= IXGBE_SDP0_GPIEN; - - /* - * Set LL interval to max to reduce the number of low latency - * interrupts hitting the card when the ring is getting full. - */ - gpie |= 0xf << IXGBE_GPIE_LLI_DELAY_SHIFT; - } - - if (sc->msix > 1) { - /* Enable Enhanced MSIX mode */ - gpie |= IXGBE_GPIE_MSIX_MODE; - gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | - IXGBE_GPIE_OCD; - } - IXGBE_WRITE_REG(&sc->hw, IXGBE_GPIE, gpie); - /* Set MRU size */ mhadd = IXGBE_READ_REG(&sc->hw, IXGBE_MHADD); mhadd &= ~IXGBE_MHADD_MFS_MASK; mhadd |= sc->max_frame_size << IXGBE_MHADD_MFS_SHIFT; IXGBE_WRITE_REG(&sc->hw, IXGBE_MHADD, mhadd); /* Now enable all the queues */ - for (i = 0; i < sc->num_queues; i++) { txdctl = IXGBE_READ_REG(&sc->hw, IXGBE_TXDCTL(i)); txdctl |= IXGBE_TXDCTL_ENABLE; /* Set WTHRESH to 8, burst writeback */ txdctl |= (8 << 16); @@ -756,39 +745,20 @@ ixgbe_init(void *arg) itr = (4000000 / IXGBE_INTS_PER_SEC) & 0xff8; if (sc->hw.mac.type != ixgbe_mac_82598EB) itr |= IXGBE_EITR_LLI_MOD | IXGBE_EITR_CNT_WDIS; IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(0), itr); + /* Enable power to the phy */ + if (sc->hw.phy.ops.set_phy_power) + sc->hw.phy.ops.set_phy_power(&sc->hw, TRUE); + /* Config/Enable Link */ ixgbe_config_link(sc); /* Hardware Packet Buffer & Flow Control setup */ - { - uint32_t rxpb, frame, size, tmp; - - frame = sc->max_frame_size; - - /* Calculate High Water */ - if (sc->hw.mac.type == ixgbe_mac_X540) - tmp = IXGBE_DV_X540(frame, frame); - else - tmp = IXGBE_DV(frame, frame); - size = IXGBE_BT2KB(tmp); - rxpb = IXGBE_READ_REG(&sc->hw, IXGBE_RXPBSIZE(0)) >> 10; - sc->hw.fc.high_water[0] = rxpb - size; - - /* Now calculate Low Water */ - if (sc->hw.mac.type == ixgbe_mac_X540) - tmp = IXGBE_LOW_DV_X540(frame); - else - tmp = IXGBE_LOW_DV(frame); - sc->hw.fc.low_water[0] = IXGBE_BT2KB(tmp); + ixgbe_config_delay_values(sc); - sc->hw.fc.requested_mode = sc->fc; - sc->hw.fc.pause_time = IXGBE_FC_PAUSE; - sc->hw.fc.send_xon = TRUE; - } /* Initialize the FC settings */ sc->hw.mac.ops.start_hw(&sc->hw); /* And now turn on interrupts */ ixgbe_enable_intr(sc); @@ -798,10 +768,107 @@ ixgbe_init(void *arg) ifq_clr_oactive(&ifp->if_snd); splx(s); } +void +ixgbe_config_gpie(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t gpie; + + gpie = IXGBE_READ_REG(&sc->hw, IXGBE_GPIE); + + /* Fan Failure Interrupt */ + if (hw->device_id == IXGBE_DEV_ID_82598AT) + gpie |= IXGBE_SDP1_GPIEN; + + if (sc->hw.mac.type == ixgbe_mac_82599EB) { + /* Add for Module detection */ + gpie |= IXGBE_SDP2_GPIEN; + + /* Media ready */ + if (hw->device_id != IXGBE_DEV_ID_82599_QSFP_SF_QP) + gpie |= IXGBE_SDP1_GPIEN; + + /* + * Set LL interval to max to reduce the number of low latency + * interrupts hitting the card when the ring is getting full. + */ + gpie |= 0xf << IXGBE_GPIE_LLI_DELAY_SHIFT; + } + + if (sc->hw.mac.type == ixgbe_mac_X540 || + hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || + hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + /* + * Thermal Failure Detection (X540) + * Link Detection (X552 SFP+, X552/X557-AT) + */ + gpie |= IXGBE_SDP0_GPIEN_X540; + + /* + * Set LL interval to max to reduce the number of low latency + * interrupts hitting the card when the ring is getting full. + */ + gpie |= 0xf << IXGBE_GPIE_LLI_DELAY_SHIFT; + } + + if (sc->msix > 1) { + /* Enable Enhanced MSIX mode */ + gpie |= IXGBE_GPIE_MSIX_MODE; + gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | + IXGBE_GPIE_OCD; + } + + IXGBE_WRITE_REG(&sc->hw, IXGBE_GPIE, gpie); +} + +/* + * Requires sc->max_frame_size to be set. + */ +void +ixgbe_config_delay_values(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t rxpb, frame, size, tmp; + + frame = sc->max_frame_size; + + /* Calculate High Water */ + switch (hw->mac.type) { + case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + tmp = IXGBE_DV_X540(frame, frame); + break; + default: + tmp = IXGBE_DV(frame, frame); + break; + } + size = IXGBE_BT2KB(tmp); + rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; + hw->fc.high_water[0] = rxpb - size; + + /* Now calculate Low Water */ + switch (hw->mac.type) { + case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + tmp = IXGBE_LOW_DV_X540(frame); + break; + default: + tmp = IXGBE_LOW_DV(frame); + break; + } + hw->fc.low_water[0] = IXGBE_BT2KB(tmp); + + hw->fc.requested_mode = sc->fc; + hw->fc.pause_time = IXGBE_FC_PAUSE; + hw->fc.send_xon = TRUE; +} + /* * MSIX Interrupt Handlers */ void ixgbe_enable_queue(struct ix_softc *sc, uint32_t vector) @@ -853,11 +920,11 @@ ixgbe_intr(void *arg) struct ix_softc *sc = (struct ix_softc *)arg; struct ix_queue *que = sc->queues; struct ifnet *ifp = &sc->arpcom.ac_if; struct tx_ring *txr = sc->tx_rings; struct ixgbe_hw *hw = &sc->hw; - uint32_t reg_eicr; + uint32_t reg_eicr, mod_mask, msf_mask; int i, refill = 0; reg_eicr = IXGBE_READ_REG(&sc->hw, IXGBE_EICR); if (reg_eicr == 0) { ixgbe_enable_intr(sc); @@ -885,25 +952,47 @@ ixgbe_intr(void *arg) ixgbe_update_link_status(sc); KERNEL_UNLOCK(); ifq_start(&ifp->if_snd); } - /* ... more link status change */ if (hw->mac.type != ixgbe_mac_82598EB) { - if (reg_eicr & IXGBE_EICR_GPI_SDP2) { + if (reg_eicr & IXGBE_EICR_ECC) { + printf("%s: CRITICAL: ECC ERROR!! " + "Please Reboot!!\n", sc->dev.dv_xname); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); + } + /* Check for over temp condition */ + if (reg_eicr & IXGBE_EICR_TS) { + printf("%s: CRITICAL: OVER TEMP!! " + "PHY IS SHUT DOWN!!\n", ifp->if_xname); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); + } + } + + /* Pluggable optics-related interrupt */ + if (ixgbe_is_sfp(hw)) { + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) { + mod_mask = IXGBE_EICR_GPI_SDP0_X540; + msf_mask = IXGBE_EICR_GPI_SDP1_X540; + } else if (hw->mac.type == ixgbe_mac_X540 || + hw->mac.type == ixgbe_mac_X550 || + hw->mac.type == ixgbe_mac_X550EM_x) { + mod_mask = IXGBE_EICR_GPI_SDP2_X540; + msf_mask = IXGBE_EICR_GPI_SDP1_X540; + } else { + mod_mask = IXGBE_EICR_GPI_SDP2; + msf_mask = IXGBE_EICR_GPI_SDP1; + } + if (reg_eicr & mod_mask) { /* Clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); - KERNEL_LOCK(); + IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask); ixgbe_handle_mod(sc); - KERNEL_UNLOCK(); } else if ((hw->phy.media_type != ixgbe_media_type_copper) && - (reg_eicr & IXGBE_EICR_GPI_SDP1)) { + (reg_eicr & msf_mask)) { /* Clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); - KERNEL_LOCK(); + IXGBE_WRITE_REG(hw, IXGBE_EICR, msf_mask); ixgbe_handle_msf(sc); - KERNEL_UNLOCK(); } } /* Check for fan failure */ if ((hw->device_id == IXGBE_DEV_ID_82598AT) && @@ -911,16 +1000,16 @@ ixgbe_intr(void *arg) printf("%s: CRITICAL: FAN FAILURE!! " "REPLACE IMMEDIATELY!!\n", ifp->if_xname); IXGBE_WRITE_REG(&sc->hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); } - /* Check for over temp condition */ - if ((hw->mac.type == ixgbe_mac_X540) && - (reg_eicr & IXGBE_EICR_TS)) { - printf("%s: CRITICAL: OVER TEMP!! " - "PHY IS SHUT DOWN!!\n", ifp->if_xname); - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); + /* External PHY interrupt */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && + (reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) { + /* Clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); + ixgbe_handle_phy(sc); } for (i = 0; i < sc->num_queues; i++, que++) ixgbe_enable_queue(sc, que->msix); @@ -1284,11 +1373,11 @@ ixgbe_stop(void *arg) sc->hw.adapter_stopped = FALSE; sc->hw.mac.ops.stop_adapter(&sc->hw); if (sc->hw.mac.type == ixgbe_mac_82599EB) sc->hw.mac.ops.stop_mac_link_on_d3(&sc->hw); /* Turn off the laser */ - if (sc->hw.phy.multispeed_fiber) + if (sc->hw.mac.ops.disable_tx_laser) sc->hw.mac.ops.disable_tx_laser(&sc->hw); timeout_del(&sc->timer); timeout_del(&sc->rx_refill); /* reprogram the RAR[0] in case user changed it. */ @@ -1328,54 +1417,19 @@ ixgbe_identify_hardware(struct ix_softc *sc) reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); sc->hw.subsystem_vendor_id = PCI_VENDOR(reg); sc->hw.subsystem_device_id = PCI_PRODUCT(reg); - switch (sc->hw.device_id) { - case PCI_PRODUCT_INTEL_82598: - case PCI_PRODUCT_INTEL_82598AF_DUAL: - case PCI_PRODUCT_INTEL_82598_DA_DUAL: - case PCI_PRODUCT_INTEL_82598AF: - case PCI_PRODUCT_INTEL_82598_SR_DUAL_EM: - case PCI_PRODUCT_INTEL_82598EB_SFP: - case PCI_PRODUCT_INTEL_82598EB_CX4_DUAL: - case PCI_PRODUCT_INTEL_82598EB_CX4: - case PCI_PRODUCT_INTEL_82598EB_XF_LR: - case PCI_PRODUCT_INTEL_82598AT: - case PCI_PRODUCT_INTEL_82598AT2: - case PCI_PRODUCT_INTEL_82598AT_DUAL: - case PCI_PRODUCT_INTEL_82598_BX: - sc->hw.mac.type = ixgbe_mac_82598EB; - break; - case PCI_PRODUCT_INTEL_82599EN_SFP: - case PCI_PRODUCT_INTEL_82599_SFP: - case PCI_PRODUCT_INTEL_82599_SFP_EM: - case PCI_PRODUCT_INTEL_82599_SFP_FCOE: - case PCI_PRODUCT_INTEL_82599_SFP_SF2: - case PCI_PRODUCT_INTEL_82599_KX4: - case PCI_PRODUCT_INTEL_82599_KX4_MEZZ: - case PCI_PRODUCT_INTEL_82599_CX4: - case PCI_PRODUCT_INTEL_82599_T3_LOM: - case PCI_PRODUCT_INTEL_82599_XAUI: - case PCI_PRODUCT_INTEL_82599_COMBO_BP: - case PCI_PRODUCT_INTEL_82599_BPLANE_FCOE: - sc->hw.mac.type = ixgbe_mac_82599EB; - break; - case PCI_PRODUCT_INTEL_82599VF: - sc->hw.mac.type = ixgbe_mac_82599_vf; - break; - case PCI_PRODUCT_INTEL_X540T: - sc->hw.mac.type = ixgbe_mac_X540; - break; - default: - break; - } + /* We need this here to set the num_segs below */ + ixgbe_set_mac_type(&sc->hw); /* Pick up the 82599 and VF settings */ - if (sc->hw.mac.type != ixgbe_mac_82598EB) + if (sc->hw.mac.type != ixgbe_mac_82598EB) { sc->hw.phy.smart_speed = ixgbe_smart_speed; - sc->num_segs = IXGBE_82599_SCATTER; + sc->num_segs = IXGBE_82599_SCATTER; + } else + sc->num_segs = IXGBE_82598_SCATTER; } /********************************************************************* * * Determine optic type @@ -1407,10 +1461,12 @@ ixgbe_setup_optics(struct ix_softc *sc) sc->optics = IFM_10G_CX4; else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) sc->optics = IFM_1000_SX; else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_LX) sc->optics = IFM_1000_LX; + /* If we get here just set the default */ + sc->optics = IFM_ETHER | IFM_AUTO; } /********************************************************************* * * Setup the Legacy or MSI Interrupt handler @@ -1566,30 +1622,17 @@ ixgbe_setup_interface(struct ix_softc *sc) void ixgbe_config_link(struct ix_softc *sc) { uint32_t autoneg, err = 0; - bool sfp, negotiate; - - switch (sc->hw.phy.type) { - case ixgbe_phy_sfp_avago: - case ixgbe_phy_sfp_ftl: - case ixgbe_phy_sfp_intel: - case ixgbe_phy_sfp_unknown: - case ixgbe_phy_sfp_passive_tyco: - case ixgbe_phy_sfp_passive_unknown: - sfp = TRUE; - break; - default: - sfp = FALSE; - break; - } + bool negotiate; - if (sfp) { + if (ixgbe_is_sfp(&sc->hw)) { if (sc->hw.phy.multispeed_fiber) { sc->hw.mac.ops.setup_sfp(&sc->hw); - sc->hw.mac.ops.enable_tx_laser(&sc->hw); + if (sc->hw.mac.ops.enable_tx_laser) + sc->hw.mac.ops.enable_tx_laser(&sc->hw); ixgbe_handle_msf(sc); } else ixgbe_handle_mod(sc); } else { if (sc->hw.mac.ops.check_link) @@ -1602,11 +1645,11 @@ ixgbe_config_link(struct ix_softc *sc) err = sc->hw.mac.ops.get_link_capabilities(&sc->hw, &autoneg, &negotiate); if (err) return; if (sc->hw.mac.ops.setup_link) - err = sc->hw.mac.ops.setup_link(&sc->hw, + sc->hw.mac.ops.setup_link(&sc->hw, autoneg, sc->link_up); } } /******************************************************************** @@ -2188,133 +2231,10 @@ ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp, atomic_dec_int(&txr->tx_avail); return (0); } -#ifdef notyet -/********************************************************************** - * - * Setup work for hardware segmentation offload (TSO) on - * adapters using advanced tx descriptors - * - **********************************************************************/ -int -ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp, - uint32_t *cmd_type_len, uint32_t *olinfo_status) -{ - struct ix_softc *sc = txr->sc; - struct ixgbe_adv_tx_context_desc *TXD; - uint32_t vlan_macip_lens = 0, type_tucmd_mlhl = 0; - uint32_t mss_l4len_idx = 0, paylen; - int ctxd, ehdrlen, ip_hlen, tcp_hlen; - uint16_t etype; -#if NVLAN > 0 - uint16_t vtag = 0; - struct ether_vlan_header *eh; -#else - struct ether_header *eh; -#endif - struct ip *ip; - struct ip6_hdr *ip6; - struct tcphdr *th; - - /* - * Determine where frame payload starts. - * Jump over vlan headers if already present - */ -#if NVLAN > 0 - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - etype = ntohs(eh->evl_proto); - ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - etype = ntohs(eh->evl_encap_proto); - ehdrlen = ETHER_HDR_LEN; - } -#else - eh = mtod(mp, struct ether_header *); - etype = ntohs(eh->ether_type); - ehdrlen = ETHER_HDR_LEN; -#endif - - switch (etype) { - case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - /* XXX-BZ For now we do not pretend to support ext. hdrs. */ - if (ip6->ip6_nxt != IPPROTO_TCP) - return (ENXIO); - ip_hlen = sizeof(struct ip6_hdr); - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); - th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; - break; - case ETHERTYPE_IP: - ip = (struct ip *)(mp->m_data + ehdrlen); - if (ip->ip_p != IPPROTO_TCP) - return (ENXIO); - ip->ip_sum = 0; - ip_hlen = ip->ip_hl << 2; - th = (struct tcphdr *)((caddr_t)ip + ip_hlen); - th->th_sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htons(IPPROTO_TCP)); - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; - /* Tell transmit desc to also do IPv4 checksum. */ - *olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; - break; - default: - panic("%s: CSUM_TSO but no supported IP version (0x%04x)", - __func__, ntohs(etype)); - break; - } - - ctxd = txr->next_avail_desc; - TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; - - tcp_hlen = th->th_off << 2; - - /* This is used in the transmit desc in encap */ - paylen = mp->m_pkthdr.len - ehdrlen - ip_hlen - tcp_hlen; - -#if NVLAN > 0 - /* VLAN MACLEN IPLEN */ - if (mp->m_flags & M_VLANTAG) { - vtag = mp->m_pkthdr.ether_vtag; - vlan_macip_lens |= (vtag << IXGBE_ADVTXD_VLAN_SHIFT); - } -#endif - - vlan_macip_lens |= ehdrlen << IXGBE_ADVTXD_MACLEN_SHIFT; - vlan_macip_lens |= ip_hlen; - TXD->vlan_macip_lens = htole32(vlan_macip_lens); - - /* ADV DTYPE TUCMD */ - type_tucmd_mlhl |= IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT; - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; - TXD->type_tucmd_mlhl = htole32(type_tucmd_mlhl); - - /* MSS L4LEN IDX */ - mss_l4len_idx |= (mp->m_pkthdr.tso_segsz << IXGBE_ADVTXD_MSS_SHIFT); - mss_l4len_idx |= (tcp_hlen << IXGBE_ADVTXD_L4LEN_SHIFT); - TXD->mss_l4len_idx = htole32(mss_l4len_idx); - - TXD->seqnum_seed = htole32(0); - - membar_producer(); - - if (++ctxd == sc->num_tx_desc) - ctxd = 0; - - atomic_dec_int(&txr->tx_avail); - txr->next_avail_desc = ctxd; - *cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; - *olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; - *olinfo_status |= paylen << IXGBE_ADVTXD_PAYLEN_SHIFT; - return TRUE; -} -#endif - /********************************************************************** * * Examine each tx_buffer in the used queue. If the hardware is done * processing the packet then free associated resources. The * tx_buffer is put back on the free queue. @@ -2490,21 +2410,19 @@ int ixgbe_allocate_receive_buffers(struct rx_ring *rxr) { struct ix_softc *sc = rxr->sc; struct ifnet *ifp = &sc->arpcom.ac_if; struct ixgbe_rx_buf *rxbuf; - int i, bsize, error; + int i, error; - bsize = sizeof(struct ixgbe_rx_buf) * sc->num_rx_desc; if (!(rxr->rx_buffers = mallocarray(sc->num_rx_desc, sizeof(struct ixgbe_rx_buf), M_DEVBUF, M_NOWAIT | M_ZERO))) { printf("%s: Unable to allocate rx_buffer memory\n", ifp->if_xname); error = ENOMEM; goto fail; } - bsize = sizeof(struct ixgbe_rx_buf) * sc->num_rx_desc; rxbuf = rxr->rx_buffers; for (i = 0; i < sc->num_rx_desc; i++, rxbuf++) { error = bus_dmamap_create(rxr->rxdma.dma_tag, 16 * 1024, 1, 16 * 1024, 0, BUS_DMA_NOWAIT, &rxbuf->map); @@ -2633,109 +2551,144 @@ fail: #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 void ixgbe_initialize_receive_units(struct ix_softc *sc) { - struct rx_ring *rxr = sc->rx_rings; - uint32_t bufsz, rxctrl, fctrl, srrctl, rxcsum; - uint32_t reta, mrqc = 0, hlreg; - uint32_t random[10]; + struct rx_ring *rxr = sc->rx_rings; + struct ixgbe_hw *hw = &sc->hw; + uint32_t bufsz, fctrl, srrctl, rxcsum; + uint32_t hlreg; int i; /* * Make sure receives are disabled while * setting up the descriptor ring */ - rxctrl = IXGBE_READ_REG(&sc->hw, IXGBE_RXCTRL); - IXGBE_WRITE_REG(&sc->hw, IXGBE_RXCTRL, - rxctrl & ~IXGBE_RXCTRL_RXEN); + ixgbe_disable_rx(hw); /* Enable broadcasts */ - fctrl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL); + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); fctrl |= IXGBE_FCTRL_BAM; - fctrl |= IXGBE_FCTRL_DPF; - fctrl |= IXGBE_FCTRL_PMCF; - IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, fctrl); + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + fctrl |= IXGBE_FCTRL_DPF; + fctrl |= IXGBE_FCTRL_PMCF; + } + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); /* Always enable jumbo frame reception */ - hlreg = IXGBE_READ_REG(&sc->hw, IXGBE_HLREG0); + hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); hlreg |= IXGBE_HLREG0_JUMBOEN; - IXGBE_WRITE_REG(&sc->hw, IXGBE_HLREG0, hlreg); + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); bufsz = (sc->rx_mbuf_sz - ETHER_ALIGN) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; for (i = 0; i < sc->num_queues; i++, rxr++) { uint64_t rdba = rxr->rxdma.dma_map->dm_segs[0].ds_addr; /* Setup the Base and Length of the Rx Descriptor Ring */ - IXGBE_WRITE_REG(&sc->hw, IXGBE_RDBAL(i), + IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & 0x00000000ffffffffULL)); - IXGBE_WRITE_REG(&sc->hw, IXGBE_RDBAH(i), (rdba >> 32)); - IXGBE_WRITE_REG(&sc->hw, IXGBE_RDLEN(i), + IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), sc->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); /* Set up the SRRCTL register */ srrctl = bufsz | IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; - IXGBE_WRITE_REG(&sc->hw, IXGBE_SRRCTL(i), srrctl); + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); /* Setup the HW Rx Head and Tail Descriptor Pointers */ - IXGBE_WRITE_REG(&sc->hw, IXGBE_RDH(i), 0); - IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); } if (sc->hw.mac.type != ixgbe_mac_82598EB) { uint32_t psrtype = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR; - IXGBE_WRITE_REG(&sc->hw, IXGBE_PSRTYPE(0), psrtype); + IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); } - rxcsum = IXGBE_READ_REG(&sc->hw, IXGBE_RXCSUM); - rxcsum &= ~IXGBE_RXCSUM_PCSD; - - /* Setup RSS */ - if (sc->num_queues > 1) { - int j; - reta = 0; - /* set up random bits */ - arc4random_buf(&random, sizeof(random)); - - /* Set up the redirection table */ - for (i = 0, j = 0; i < 128; i++, j++) { - if (j == sc->num_queues) - j = 0; - reta = (reta << 8) | (j * 0x11); - if ((i & 3) == 3) - IXGBE_WRITE_REG(&sc->hw, IXGBE_RETA(i >> 2), reta); - } + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); - /* Now fill our hash function seeds */ - for (i = 0; i < 10; i++) - IXGBE_WRITE_REG(&sc->hw, IXGBE_RSSRK(i), random[i]); - - /* Perform hash on these packet types */ - mrqc = IXGBE_MRQC_RSSEN - | IXGBE_MRQC_RSS_FIELD_IPV4 - | IXGBE_MRQC_RSS_FIELD_IPV4_TCP - | IXGBE_MRQC_RSS_FIELD_IPV4_UDP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP - | IXGBE_MRQC_RSS_FIELD_IPV6_EX - | 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(&sc->hw, IXGBE_MRQC, mrqc); + ixgbe_initialize_rss_mapping(sc); + if (sc->num_queues > 1) { /* RSS and RX IPP Checksum are mutually exclusive */ rxcsum |= IXGBE_RXCSUM_PCSD; } + /* This is useful for calculating UDP/IP fragment checksums */ if (!(rxcsum & IXGBE_RXCSUM_PCSD)) rxcsum |= IXGBE_RXCSUM_IPPCSE; - IXGBE_WRITE_REG(&sc->hw, IXGBE_RXCSUM, rxcsum); + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); +} + +void +ixgbe_initialize_rss_mapping(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t reta = 0, mrqc, rss_key[10]; + int i, j, queue_id, table_size, index_mult; + + /* set up random bits */ + arc4random_buf(&rss_key, sizeof(rss_key)); + + /* Set multiplier for RETA setup and table size based on MAC */ + index_mult = 0x1; + table_size = 128; + switch (sc->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; + } + + /* Set up the redirection table */ + for (i = 0, j = 0; i < table_size; i++, j++) { + if (j == sc->num_queues) j = 0; + queue_id = (j * index_mult); + /* + * The low 8 bits are for hash value (n+0); + * The next 8 bits are for hash value (n+1), etc. + */ + reta = reta >> 8; + reta = reta | ( ((uint32_t) queue_id) << 24); + if ((i & 3) == 3) { + 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; + } + } + + /* Now fill our hash function seeds */ + for (i = 0; i < 10; i++) + IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); + + /* + * Disable UDP - IP fragments aren't currently being handled + * and so we end up with a mix of 2-tuple and 4-tuple + * traffic. + */ + mrqc = IXGBE_MRQC_RSSEN + | IXGBE_MRQC_RSS_FIELD_IPV4 + | IXGBE_MRQC_RSS_FIELD_IPV4_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6_EX + | IXGBE_MRQC_RSS_FIELD_IPV6 + | IXGBE_MRQC_RSS_FIELD_IPV6_TCP + ; + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); } /********************************************************************* * * Free all receive rings. @@ -3018,34 +2971,45 @@ ixgbe_enable_intr(struct ix_softc *sc) mask |= IXGBE_EIMS_GPI_SDP1; switch (sc->hw.mac.type) { case ixgbe_mac_82599EB: mask |= IXGBE_EIMS_ECC; + /* Temperature sensor on some adapters */ mask |= IXGBE_EIMS_GPI_SDP0; + /* SFP+ (RX_LOS_N & MOD_ABS_N) */ mask |= IXGBE_EIMS_GPI_SDP1; mask |= IXGBE_EIMS_GPI_SDP2; break; case ixgbe_mac_X540: mask |= IXGBE_EIMS_ECC; /* Detect if Thermal Sensor is enabled */ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); if (fwsm & IXGBE_FWSM_TS_ENABLED) mask |= IXGBE_EIMS_TS; break; + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + mask |= IXGBE_EIMS_ECC; + /* MAC thermal sensor is automatically enabled */ + mask |= IXGBE_EIMS_TS; + /* Some devices use SDP0 for important information */ + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || + hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) + mask |= IXGBE_EIMS_GPI_SDP0_X540; default: break; } IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); - /* With RSS we use auto clear */ + /* With MSI-X we use auto clear */ if (sc->msix > 1) { mask = IXGBE_EIMS_ENABLE_MASK; /* Don't autoclear Link */ mask &= ~IXGBE_EIMS_OTHER; mask &= ~IXGBE_EIMS_LSC; - IXGBE_WRITE_REG(&sc->hw, IXGBE_EIAC, mask); + IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); } /* * Now enable all queues, this is done separately to * allow for handling the extended (beyond 32) MSIX @@ -3142,10 +3106,12 @@ ixgbe_set_ivar(struct ix_softc *sc, uint8_t entry, uint8_t vector, int8_t type) IXGBE_WRITE_REG(&sc->hw, IXGBE_IVAR(index), ivar); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: if (type == -1) { /* MISC IVAR */ index = (entry & 1) * 8; ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); ivar &= ~(0xFF << index); ivar |= (vector << index); @@ -3196,12 +3162,32 @@ ixgbe_configure_ivars(struct ix_softc *sc) */ void ixgbe_handle_mod(struct ix_softc *sc) { struct ixgbe_hw *hw = &sc->hw; + enum ixgbe_phy_type orig_type = hw->phy.type; uint32_t err; + /* Check to see if the PHY type changed */ + if (hw->phy.ops.identify) { + hw->phy.type = ixgbe_phy_unknown; + hw->phy.ops.identify(hw); + } + + if (hw->phy.type != orig_type) { + if (hw->phy.type == ixgbe_phy_none) { + hw->phy.sfp_type = ixgbe_sfp_type_unknown; + goto out; + } + + /* Try to do the initialization that was skipped before */ + if (hw->phy.ops.init) + hw->phy.ops.init(hw); + if (hw->phy.ops.reset) + hw->phy.ops.reset(hw); + } + err = hw->phy.ops.identify_sfp(hw); if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { printf("%s: Unsupported SFP+ module type was detected!\n", sc->dev.dv_xname); return; @@ -3210,10 +3196,11 @@ ixgbe_handle_mod(struct ix_softc *sc) if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { printf("%s: Setup failure - unsupported SFP+ module type!\n", sc->dev.dv_xname); return; } + out: /* Set the optics type so system reports correctly */ ixgbe_setup_optics(sc); ixgbe_handle_msf(sc); } @@ -3236,10 +3223,30 @@ ixgbe_handle_msf(struct ix_softc *sc) } if (hw->mac.ops.setup_link) hw->mac.ops.setup_link(hw, autoneg, TRUE); } +/* + * External PHY interrupts handler + */ +void +ixgbe_handle_phy(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + int error; + + error = hw->phy.ops.handle_lasi(hw); + if (error == IXGBE_ERR_OVERTEMP) + printf("%s: CRITICAL: EXTERNAL PHY OVER TEMP!! " + " PHY will downshift to lower power state!\n", + sc->dev.dv_xname); + else if (error) + printf("%s: Error handling LASI interrupt: %d\n", + sc->dev.dv_xname, error); + +} + /********************************************************************** * * Update the board statistics counters. * **********************************************************************/ diff --git sys/dev/pci/ixgbe.c sys/dev/pci/ixgbe.c index 6304f04..14325aa 100644 --- sys/dev/pci/ixgbe.c +++ sys/dev/pci/ixgbe.c @@ -654,11 +654,12 @@ int32_t ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, uint8_t *mac_addr) void ixgbe_set_pci_config_data_generic(struct ixgbe_hw *hw, uint16_t link_status) { struct ixgbe_mac_info *mac = &hw->mac; - hw->bus.type = ixgbe_bus_type_pci_express; + if (hw->bus.type == ixgbe_bus_type_unknown) + hw->bus.type = ixgbe_bus_type_pci_express; switch (link_status & IXGBE_PCI_LINK_WIDTH) { case IXGBE_PCI_LINK_WIDTH_1: hw->bus.width = ixgbe_bus_width_pcie_x1; break; @@ -2285,14 +2286,15 @@ int32_t ixgbe_fc_enable_generic(struct ixgbe_hw *hw) } else { IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0); /* * In order to prevent Tx hangs when the internal Tx * switch is enabled we must set the high water mark - * to the maximum FCRTH value. This allows the Tx - * switch to function even under heavy Rx workloads. + * to the Rx packet buffer size - 24KB. This allows + * the Tx switch to function even under heavy Rx + * workloads. */ - fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32; + fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 24576; } IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), fcrth); } @@ -3567,11 +3569,12 @@ int32_t ixgbe_host_interface_command(struct ixgbe_hw *hw, uint32_t *buffer, * when a reset occurs. This function prevents this by flushing the PCIe * buffers on the system. **/ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw) { - uint32_t gcr_ext, hlreg0; + uint32_t gcr_ext, hlreg0, i, poll; + uint16_t value; /* * If double reset is not requested then all transactions should * already be clear and as such there is no work to do */ @@ -3584,10 +3587,27 @@ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw) * has already been cleared. */ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0 | IXGBE_HLREG0_LPBK); + /* Wait for a last completion before clearing buffers */ + IXGBE_WRITE_FLUSH(hw); + msec_delay(3); + + /* + * Before proceeding, make sure that the PCIe block does not have + * transactions pending. + */ + poll = ixgbe_pcie_timeout_poll(hw); + for (i = 0; i < poll; i++) { + usec_delay(100); + value = IXGBE_READ_PCIE_WORD(hw, IXGBE_PCI_DEVICE_STATUS); + if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING)) + goto out; + } + +out: /* initiate cleaning flow for buffers in the PCIe transaction layer */ gcr_ext = IXGBE_READ_REG(hw, IXGBE_GCR_EXT); IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext | IXGBE_GCR_EXT_BUFFERS_CLEAR); @@ -3933,10 +3953,16 @@ int32_t ixgbe_init_shared_code(struct ixgbe_hw *hw) status = ixgbe_init_ops_82599(hw); break; case ixgbe_mac_X540: status = ixgbe_init_ops_X540(hw); break; + case ixgbe_mac_X550: + status = ixgbe_init_ops_X550(hw); + break; + case ixgbe_mac_X550EM_x: + status = ixgbe_init_ops_X550EM(hw); + break; default: status = IXGBE_ERR_DEVICE_NOT_SUPPORTED; break; } hw->mac.max_link_up_time = IXGBE_LINK_UP_TIME; diff --git sys/dev/pci/ixgbe_phy.c sys/dev/pci/ixgbe_phy.c index 0787534..e6869a3 100644 --- sys/dev/pci/ixgbe_phy.c +++ sys/dev/pci/ixgbe_phy.c @@ -1002,31 +1002,19 @@ int32_t ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) **/ int32_t ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg) { - int32_t status = IXGBE_ERR_LINK_SETUP; - uint16_t speed_ability; + int32_t status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_get_copper_link_capabilities_generic"); - *speed = 0; *autoneg = TRUE; + if (!hw->phy.speeds_supported) + status = ixgbe_get_copper_speeds_supported(hw); - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - &speed_ability); - - if (status == IXGBE_SUCCESS) { - if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G) - *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G) - *speed |= IXGBE_LINK_SPEED_1GB_FULL; - if (speed_ability & IXGBE_MDIO_PHY_SPEED_100M) - *speed |= IXGBE_LINK_SPEED_100_FULL; - } - + *speed = hw->phy.speeds_supported; return status; } /** * ixgbe_check_phy_link_tnx - Determine link and speed status @@ -1444,11 +1432,11 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.sfp_type = ixgbe_sfp_type_lr; else if (comp_codes_10g & IXGBE_SFF_DA_BAD_HP_CABLE) hw->phy.sfp_type = ixgbe_sfp_type_da_cu; else hw->phy.sfp_type = ixgbe_sfp_type_unknown; - } else if (hw->mac.type == ixgbe_mac_82599EB) { + } else { if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { if (hw->bus.lan_id == 0) hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; else diff --git sys/dev/pci/ixgbe_type.h sys/dev/pci/ixgbe_type.h index 2fd32eb..3eedb78 100644 --- sys/dev/pci/ixgbe_type.h +++ sys/dev/pci/ixgbe_type.h @@ -3479,10 +3479,11 @@ struct ixgbe_phy_operations { void (*i2c_bus_clear)(struct ixgbe_hw *); int32_t (*read_i2c_combined)(struct ixgbe_hw *, uint8_t addr, uint16_t reg, uint16_t *val); int32_t (*write_i2c_combined)(struct ixgbe_hw *, uint8_t addr, uint16_t reg, uint16_t val); int32_t (*check_overtemp)(struct ixgbe_hw *); int32_t (*set_phy_power)(struct ixgbe_hw *, bool on); + int32_t (*handle_lasi)(struct ixgbe_hw *hw); int32_t (*read_i2c_combined_unlocked)(struct ixgbe_hw *, uint8_t addr, uint16_t reg, uint16_t *value); int32_t (*write_i2c_combined_unlocked)(struct ixgbe_hw *, uint8_t addr, uint16_t reg, uint16_t value); int32_t (*read_i2c_byte_unlocked)(struct ixgbe_hw *, uint8_t offset, uint8_t addr,