fm10k/base: scale interrupt on PCIe link speed
authorWang Xiao W <xiao.w.wang@intel.com>
Thu, 10 Sep 2015 04:38:14 +0000 (12:38 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Wed, 7 Oct 2015 11:25:07 +0000 (13:25 +0200)
Red Rock Canyon's interrupt throttle timers are based on the PCIe link
speed. Because of this, the value being programmed into the ITR
registers must be scaled.

For the PF, this is as simple as reading the PCIe link speed and storing
the result. However, in the case of SR-IOV, the VF's interrupt throttle
timers are based on the link speed of the PF. However, the VF is unable
to get the link speed information from its configuration space, so the
PF must inform it of what scale to use.

Rather than passing this scale via mailbox message, we take advantage of
unused bits in the TDLEN register to pass the scale. It is the
responsibility of the PF to program this for the VF while setting up the
VF queues and the responsibility of the VF to get the information
accordingly. This is preferable because it allows the VF to set up the
interrupts properly during initialization and matches how the MAC
address is passed in the TDBAL/TDBAH registers.

A VF unload followed by a reload incorrectly left this value as 0.
If the VF driver blindly trusted this value it could cause a divide by
zero failure.
Fix this by having stop_hw_vf reset the ITR scale as the device goes
down, similar to the way we handle the MAC address.

To prevent divide-by-zero issues, ensure that we always have an ITR
scale. Default to Gen3 scaling if we don't know the speed. Also ensure
the VF checks the register value and ensures we use Gen3 if we are
provided a zero value.

Signed-off-by: Wang Xiao W <xiao.w.wang@intel.com>
drivers/net/fm10k/base/fm10k_pf.c
drivers/net/fm10k/base/fm10k_type.h
drivers/net/fm10k/base/fm10k_vf.c

index 663a28c..a9d280c 100644 (file)
@@ -169,19 +169,26 @@ STATIC s32 fm10k_init_hw_pf(struct fm10k_hw *hw)
                                FM10K_TPH_RXCTRL_HDR_WROEN);
        }
 
-       /* set max hold interval to align with 1.024 usec in all modes */
+       /* set max hold interval to align with 1.024 usec in all modes and
+        * store ITR scale
+        */
        switch (hw->bus.speed) {
        case fm10k_bus_speed_2500:
                dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1;
+               hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN1;
                break;
        case fm10k_bus_speed_5000:
                dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2;
+               hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN2;
                break;
        case fm10k_bus_speed_8000:
                dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3;
+               hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3;
                break;
        default:
                dma_ctrl = 0;
+               /* just in case, assume Gen3 ITR scale */
+               hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3;
                break;
        }
 
@@ -947,6 +954,12 @@ STATIC s32 fm10k_iov_assign_default_mac_vlan_pf(struct fm10k_hw *hw,
        FM10K_WRITE_REG(hw, FM10K_TDBAL(vf_q_idx), tdbal);
        FM10K_WRITE_REG(hw, FM10K_TDBAH(vf_q_idx), tdbah);
 
+       /* Provide the VF the ITR scale, using software-defined fields in TDLEN
+        * to pass the information during VF initialization
+        */
+       FM10K_WRITE_REG(hw, FM10K_TDLEN(vf_q_idx), hw->mac.itr_scale <<
+                                                  FM10K_TDLEN_ITR_SCALE_SHIFT);
+
 err_out:
        /* configure Queue control register */
        txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) &
@@ -1079,6 +1092,9 @@ STATIC s32 fm10k_iov_reset_resources_pf(struct fm10k_hw *hw,
        for (i = queues_per_pool; i--;) {
                FM10K_WRITE_REG(hw, FM10K_TDBAL(vf_q_idx + i), tdbal);
                FM10K_WRITE_REG(hw, FM10K_TDBAH(vf_q_idx + i), tdbah);
+               FM10K_WRITE_REG(hw, FM10K_TDLEN(vf_q_idx + i),
+                               hw->mac.itr_scale <<
+                               FM10K_TDLEN_ITR_SCALE_SHIFT);
                FM10K_WRITE_REG(hw, FM10K_TQMAP(qmap_idx + i), vf_q_idx + i);
                FM10K_WRITE_REG(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i);
        }
index e2ad65d..c3f1c63 100644 (file)
@@ -344,6 +344,11 @@ struct fm10k_hw;
 #define FM10K_TDBAL(_n)                ((0x40 * (_n)) + 0x8000)
 #define FM10K_TDBAH(_n)                ((0x40 * (_n)) + 0x8001)
 #define FM10K_TDLEN(_n)                ((0x40 * (_n)) + 0x8002)
+#define FM10K_TDLEN_ITR_SCALE_SHIFT            9
+#define FM10K_TDLEN_ITR_SCALE_MASK             0x00000E00
+#define FM10K_TDLEN_ITR_SCALE_GEN1             4
+#define FM10K_TDLEN_ITR_SCALE_GEN2             2
+#define FM10K_TDLEN_ITR_SCALE_GEN3             1
 #define FM10K_TPH_TXCTRL(_n)   ((0x40 * (_n)) + 0x8003)
 #define FM10K_TPH_TXCTRL_DESC_TPHEN            0x00000020
 #define FM10K_TPH_TXCTRL_DESC_RROEN            0x00000200
@@ -693,6 +698,7 @@ struct fm10k_mac_info {
        bool get_host_state;
        bool tx_ready;
        u32 dglort_map;
+       u8 itr_scale;
 };
 
 struct fm10k_swapi_table_info {
index 76be9ab..ba7c7c1 100644 (file)
@@ -41,7 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.
 STATIC s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
 {
        u8 *perm_addr = hw->mac.perm_addr;
-       u32 bal = 0, bah = 0;
+       u32 bal = 0, bah = 0, tdlen;
        s32 err;
        u16 i;
 
@@ -63,6 +63,9 @@ STATIC s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
                       ((u32)perm_addr[2]);
        }
 
+       /* restore default itr_scale for next VF initialization */
+       tdlen = hw->mac.itr_scale << FM10K_TDLEN_ITR_SCALE_SHIFT;
+
        /* The queues have already been disabled so we just need to
         * update their base address registers
         */
@@ -71,6 +74,7 @@ STATIC s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
                FM10K_WRITE_REG(hw, FM10K_TDBAH(i), bah);
                FM10K_WRITE_REG(hw, FM10K_RDBAL(i), bal);
                FM10K_WRITE_REG(hw, FM10K_RDBAH(i), bah);
+               FM10K_WRITE_REG(hw, FM10K_TDLEN(i), tdlen);
        }
 
        return FM10K_SUCCESS;
@@ -143,9 +147,16 @@ STATIC s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
        /* record maximum queue count */
        hw->mac.max_queues = i;
 
-       /* fetch default VLAN */
+       /* fetch default VLAN and ITR scale */
        hw->mac.default_vid = (FM10K_READ_REG(hw, FM10K_TXQCTL(0)) &
                               FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT;
+       hw->mac.itr_scale = (FM10K_READ_REG(hw, FM10K_TDLEN(0)) &
+                            FM10K_TDLEN_ITR_SCALE_MASK) >>
+                           FM10K_TDLEN_ITR_SCALE_SHIFT;
+
+       /* ensure a non-zero itr scale */
+       if (!hw->mac.itr_scale)
+               hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3;
 
        return FM10K_SUCCESS;
 }