From e18683f8ef6ce08fd587e3e8537e2030bcfe0825 Mon Sep 17 00:00:00 2001 From: Wang Xiao W Date: Thu, 10 Sep 2015 12:38:14 +0800 Subject: [PATCH] fm10k/base: scale interrupt on PCIe link speed 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 --- drivers/net/fm10k/base/fm10k_pf.c | 18 +++++++++++++++++- drivers/net/fm10k/base/fm10k_type.h | 6 ++++++ drivers/net/fm10k/base/fm10k_vf.c | 15 +++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/net/fm10k/base/fm10k_pf.c b/drivers/net/fm10k/base/fm10k_pf.c index 663a28c819..a9d280c746 100644 --- a/drivers/net/fm10k/base/fm10k_pf.c +++ b/drivers/net/fm10k/base/fm10k_pf.c @@ -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); } diff --git a/drivers/net/fm10k/base/fm10k_type.h b/drivers/net/fm10k/base/fm10k_type.h index e2ad65d833..c3f1c63a75 100644 --- a/drivers/net/fm10k/base/fm10k_type.h +++ b/drivers/net/fm10k/base/fm10k_type.h @@ -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 { diff --git a/drivers/net/fm10k/base/fm10k_vf.c b/drivers/net/fm10k/base/fm10k_vf.c index 76be9ab3c0..ba7c7c1e56 100644 --- a/drivers/net/fm10k/base/fm10k_vf.c +++ b/drivers/net/fm10k/base/fm10k_vf.c @@ -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; } -- 2.20.1