IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(reg_idx), srrctl);
 }
 
-static void ixgbe_setup_reta(struct ixgbe_adapter *adapter, const u32 *seed)
+/**
+ * Return a number of entries in the RSS indirection table
+ *
+ * @adapter: device handle
+ *
+ *  - 82598/82599/X540:     128
+ *  - X550(non-SRIOV mode): 512
+ *  - X550(SRIOV mode):     64
+ */
+static u32 ixgbe_rss_indir_tbl_entries(struct ixgbe_adapter *adapter)
+{
+       if (adapter->hw.mac.type < ixgbe_mac_X550)
+               return 128;
+       else if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
+               return 64;
+       else
+               return 512;
+}
+
+/**
+ * Write the RETA table to HW
+ *
+ * @adapter: device handle
+ *
+ * Write the RSS redirection table stored in adapter.rss_indir_tbl[] to HW.
+ */
+static void ixgbe_store_reta(struct ixgbe_adapter *adapter)
 {
+       u32 i, reta_entries = ixgbe_rss_indir_tbl_entries(adapter);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 reta = 0;
-       int i, j;
-       int reta_entries = 128;
-       u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
-       int indices_multi;
-
-       /*
-        * Program table for at least 2 queues w/ SR-IOV so that VFs can
-        * make full use of any rings they may have.  We will use the
-        * PSRTYPE register to control how many rings we use within the PF.
-        */
-       if ((adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) && (rss_i < 2))
-               rss_i = 2;
-
-       /* Fill out hash function seeds */
-       for (i = 0; i < 10; i++)
-               IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
+       u32 indices_multi;
+       u8 *indir_tbl = adapter->rss_indir_tbl;
 
        /* Fill out the redirection table as follows:
-        * 82598: 128 (8 bit wide) entries containing pair of 4 bit RSS indices
-        * 82599/X540: 128 (8 bit wide) entries containing 4 bit RSS index
-        * X550: 512 (8 bit wide) entries containing 6 bit RSS index
+        *  - 82598:      8 bit wide entries containing pair of 4 bit RSS
+        *    indices.
+        *  - 82599/X540: 8 bit wide entries containing 4 bit RSS index
+        *  - X550:       8 bit wide entries containing 6 bit RSS index
         */
        if (adapter->hw.mac.type == ixgbe_mac_82598EB)
                indices_multi = 0x11;
        else
                indices_multi = 0x1;
 
-       switch (adapter->hw.mac.type) {
-       case ixgbe_mac_X550:
-       case ixgbe_mac_X550EM_x:
-               if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
-                       reta_entries = 512;
-       default:
-               break;
-       }
-
-       /* Fill out redirection table */
-       for (i = 0, j = 0; i < reta_entries; i++, j++) {
-               if (j == rss_i)
-                       j = 0;
-               reta = (reta << 8) | (j * indices_multi);
+       /* Write redirection table to HW */
+       for (i = 0; i < reta_entries; i++) {
+               reta |= indices_multi * indir_tbl[i] << (i & 0x3) * 8;
                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;
                }
        }
 }
 
-static void ixgbe_setup_vfreta(struct ixgbe_adapter *adapter, const u32 *seed)
+/**
+ * Write the RETA table to HW (for x550 devices in SRIOV mode)
+ *
+ * @adapter: device handle
+ *
+ * Write the RSS redirection table stored in adapter.rss_indir_tbl[] to HW.
+ */
+static void ixgbe_store_vfreta(struct ixgbe_adapter *adapter)
 {
+       u32 i, reta_entries = ixgbe_rss_indir_tbl_entries(adapter);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 vfreta = 0;
+       unsigned int pf_pool = adapter->num_vfs;
+
+       /* Write redirection table to HW */
+       for (i = 0; i < reta_entries; i++) {
+               vfreta |= (u32)adapter->rss_indir_tbl[i] << (i & 0x3) * 8;
+               if ((i & 3) == 3) {
+                       IXGBE_WRITE_REG(hw, IXGBE_PFVFRETA(i >> 2, pf_pool),
+                                       vfreta);
+                       vfreta = 0;
+               }
+       }
+}
+
+static void ixgbe_setup_reta(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 i, j;
+       u32 reta_entries = ixgbe_rss_indir_tbl_entries(adapter);
+       u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
+
+       /* Program table for at least 2 queues w/ SR-IOV so that VFs can
+        * make full use of any rings they may have.  We will use the
+        * PSRTYPE register to control how many rings we use within the PF.
+        */
+       if ((adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) && (rss_i < 2))
+               rss_i = 2;
+
+       /* Fill out hash function seeds */
+       for (i = 0; i < 10; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), adapter->rss_key[i]);
+
+       /* Fill out redirection table */
+       memset(adapter->rss_indir_tbl, 0, sizeof(adapter->rss_indir_tbl));
+
+       for (i = 0, j = 0; i < reta_entries; i++, j++) {
+               if (j == rss_i)
+                       j = 0;
+
+               adapter->rss_indir_tbl[i] = j;
+       }
+
+       ixgbe_store_reta(adapter);
+}
+
+static void ixgbe_setup_vfreta(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
        u16 rss_i = adapter->ring_feature[RING_F_RSS].indices;
        unsigned int pf_pool = adapter->num_vfs;
        int i, j;
 
        /* Fill out hash function seeds */
        for (i = 0; i < 10; i++)
-               IXGBE_WRITE_REG(hw, IXGBE_PFVFRSSRK(i, pf_pool), seed[i]);
+               IXGBE_WRITE_REG(hw, IXGBE_PFVFRSSRK(i, pf_pool),
+                               adapter->rss_key[i]);
 
        /* Fill out the redirection table */
        for (i = 0, j = 0; i < 64; i++, j++) {
                if (j == rss_i)
                        j = 0;
-               vfreta = (vfreta << 8) | j;
-               if ((i & 3) == 3)
-                       IXGBE_WRITE_REG(hw, IXGBE_PFVFRETA(i >> 2, pf_pool),
-                                       vfreta);
+
+               adapter->rss_indir_tbl[i] = j;
        }
+
+       ixgbe_store_vfreta(adapter);
 }
 
 static void ixgbe_setup_mrqc(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        u32 mrqc = 0, rss_field = 0, vfmrqc = 0;
-       u32 rss_key[10];
        u32 rxcsum;
 
        /* Disable indicating checksum in descriptor, enables RSS hash */
        if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
                rss_field |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
 
-       netdev_rss_key_fill(rss_key, sizeof(rss_key));
+       netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
        if ((hw->mac.type >= ixgbe_mac_X550) &&
            (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) {
                unsigned int pf_pool = adapter->num_vfs;
                IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 
                /* Setup RSS through the VF registers */
-               ixgbe_setup_vfreta(adapter, rss_key);
+               ixgbe_setup_vfreta(adapter);
                vfmrqc = IXGBE_MRQC_RSSEN;
                vfmrqc |= rss_field;
                IXGBE_WRITE_REG(hw, IXGBE_PFVFMRQC(pf_pool), vfmrqc);
        } else {
-               ixgbe_setup_reta(adapter, rss_key);
+               ixgbe_setup_reta(adapter);
                mrqc |= rss_field;
                IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
        }