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.

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..f6d23d6 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
@@ -1566,27 +1620,13 @@ 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);
                        ixgbe_handle_msf(sc);
                } else
@@ -1602,11 +1642,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 +2228,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 +2407,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 +2548,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 +2968,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 +3103,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 +3159,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 +3193,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 +3220,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 3eb1718..32aa46d 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 30039fb..c313df1 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 b15c838..f19d952 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,

Reply via email to