On Fri, Nov 18, 2016 at 13:27 +0100, Mike Belopuhov wrote:
> 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).
> 

The remaining diff after the interrupt change was committed.  I have
kept KERNEL_LOCK/UNLOCK dance since those functions can run in
parallel with similar code triggered by ifconfig so better safe than
sorry.

I still need to go through changes in ixgbe_initialize_receive_units.
One thing that is obvious is that Intel driver calls RSS setup even
if one queue is configured which we haven't done before.  My and
others tests don't show any regression regarding this however.

"Wait for a last completion before clearing buffers" change in the
ixgbe_clear_tx_pending was committed upstream without any explanation
but "looks safe".

FCRTH related change also looks strange, needs to get checked against
documentation.

Ditto regarding changes regarding PHY power and ixgbe_handle_mod.
Hrvoje has already reported that X550 SFP doesn't seem to be able to
detect different SFP+ modules when replugged as opposed to X520.

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
@@ -351,20 +351,21 @@ file      dev/pci/ixgb_ee.c               ixgb
 file   dev/pci/ixgb_hw.c               ixgb
 
 # Intel 82598 10GbE
 device ix: ether, ifnet, ifmedia
 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
 file   dev/pci/if_xge.c                xge
 
 # NetXen NX2031/NX2035 10Gb Ethernet
 device nxe: ether, ifnet, ifmedia
 attach nxe at pci
diff --git sys/dev/pci/if_ix.c sys/dev/pci/if_ix.c
index 03e1e6e..5454dd4 100644
--- sys/dev/pci/if_ix.c
+++ sys/dev/pci/if_ix.c
@@ -64,24 +64,34 @@ const struct pci_matchid ixgbe_devices[] = {
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82598_DA_DUAL },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_KX4 },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_KX4_MEZZ },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_XAUI },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82599_COMBO_BP },
        { 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
  *********************************************************************/
 int    ixgbe_probe(struct device *, void *, void *);
 void   ixgbe_attach(struct device *, struct device *, void *);
 int    ixgbe_detach(struct device *, int);
 void   ixgbe_start(struct ifnet *);
 int    ixgbe_ioctl(struct ifnet *, u_long, caddr_t);
@@ -108,20 +118,21 @@ int       ixgbe_setup_transmit_ring(struct tx_ring *);
 void   ixgbe_initialize_transmit_units(struct ix_softc *);
 void   ixgbe_free_transmit_structures(struct ix_softc *);
 void   ixgbe_free_transmit_buffers(struct tx_ring *);
 
 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 *);
 void   ixgbe_update_stats_counters(struct ix_softc *);
 int    ixgbe_txeof(struct tx_ring *);
 int    ixgbe_rxeof(struct ix_queue *);
 void   ixgbe_rx_checksum(uint32_t, struct mbuf *, uint32_t);
 void   ixgbe_iff(struct ix_softc *);
@@ -272,20 +283,28 @@ ixgbe_attach(struct device *parent, struct device *self, 
void *aux)
        /* Detect and set physical type */
        ixgbe_setup_optics(sc);
 
        bcopy(sc->hw.mac.addr, sc->arpcom.ac_enaddr,
            IXGBE_ETH_LENGTH_OF_ADDRESS);
 
        error = ixgbe_allocate_legacy(sc);
        if (error)
                goto err_late;
 
+       /* Enable the optics for 82599 SFP+ fiber */
+       if (sc->hw.phy.multispeed_fiber && 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);
 
        /* Get the PCI-E bus info and determine LAN ID */
        hw->mac.ops.get_bus_info(hw);
 
        /* Set an initial default flow control value */
@@ -721,20 +740,24 @@ ixgbe_init(void *arg)
                        return;
                }
        }
 
        /* Setup interrupt moderation */
        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 */
        ixgbe_config_delay_values(sc);
 
        /* Initialize the FC settings */
        sc->hw.mac.ops.start_hw(&sc->hw);
 
        /* And now turn on interrupts */
@@ -2527,40 +2550,39 @@ fail:
 /*********************************************************************
  *
  *  Setup receive registers and features.
  *
  **********************************************************************/
 #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
 
 void
 ixgbe_initialize_receive_units(struct ix_softc *sc)
 {
-       struct  rx_ring *rxr = sc->rx_rings;
+       struct rx_ring  *rxr = sc->rx_rings;
        struct ixgbe_hw *hw = &sc->hw;
-       uint32_t        bufsz, rxctrl, fctrl, srrctl, rxcsum;
-       uint32_t        reta, mrqc = 0, hlreg;
-       uint32_t        random[10];
+       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(hw, IXGBE_FCTRL);
        fctrl |= IXGBE_FCTRL_BAM;
-       fctrl |= IXGBE_FCTRL_DPF;
-       fctrl |= IXGBE_FCTRL_PMCF;
+       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(hw, IXGBE_HLREG0);
        hlreg |= IXGBE_HLREG0_JUMBOEN;
        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++) {
@@ -2584,66 +2606,100 @@ ixgbe_initialize_receive_units(struct ix_softc *sc)
 
        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(hw, IXGBE_PSRTYPE(0), psrtype);
        }
 
        rxcsum = IXGBE_READ_REG(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);
-               }
-
-               /* 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(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.
  *
  **********************************************************************/
 void
 ixgbe_free_receive_structures(struct ix_softc *sc)
 {
        struct rx_ring *rxr;
        int             i;
@@ -3105,34 +3161,55 @@ ixgbe_configure_ivars(struct ix_softc *sc)
 #endif
 }
 
 /*
  * SFP module interrupts handler
  */
 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;
        }
        err = hw->mac.ops.setup_sfp(hw);
        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);
 }
 
 
 /*
  * MSF (multispeed fiber) interrupts handler
  */
diff --git sys/dev/pci/ixgbe.c sys/dev/pci/ixgbe.c
index 6304f04..c466b3f 100644
--- sys/dev/pci/ixgbe.c
+++ sys/dev/pci/ixgbe.c
@@ -2280,24 +2280,25 @@ int32_t ixgbe_fc_enable_generic(struct ixgbe_hw *hw)
                if ((hw->fc.current_mode & ixgbe_fc_tx_pause) &&
                    hw->fc.high_water[i]) {
                        fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE;
                        IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl);
                        fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN;
                } 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);
        }
 
        /* Configure pause time (2 TCs per register) */
        reg = hw->fc.pause_time * 0x00010001;
        for (i = 0; i < (IXGBE_DCB_MAX_TRAFFIC_CLASS / 2); i++)
                IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg);
 
@@ -3562,37 +3563,55 @@ int32_t ixgbe_host_interface_command(struct ixgbe_hw 
*hw, uint32_t *buffer,
 /**
  * ixgbe_clear_tx_pending - Clear pending TX work from the PCIe fifo
  * @hw: pointer to the hardware structure
  *
  * The 82599 and x540 MACs can experience issues if TX work is still pending
  * 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
         */
        if (!(hw->mac.flags & IXGBE_FLAGS_DOUBLE_RESET_REQUIRED))
                return;
 
        /*
         * Set loopback enable to prevent any transmits from being sent
         * should the link come up.  This assumes that the RXCTRL.RXEN bit
         * 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);
 
        /* Flush all writes and allow 20usec for all transactions to clear */
        IXGBE_WRITE_FLUSH(hw);
        usec_delay(20);
 
        /* restore previous register values */
@@ -3928,20 +3947,26 @@ int32_t ixgbe_init_shared_code(struct ixgbe_hw *hw)
        switch (hw->mac.type) {
        case ixgbe_mac_82598EB:
                status = ixgbe_init_ops_82598(hw);
                break;
        case ixgbe_mac_82599EB:
                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;
 
        return status;
 }
 
 /**

Reply via email to