Commit 20076fa1 authored by Jacob Keller's avatar Jacob Keller Committed by Jeff Kirsher

fm10k: Add support for ITR scaling based on PCIe link speed

The Intel Ethernet Switch FM10000 Host Interface interrupt throttle
timers are based on the PCIe link speed. Because of this, the value
being programmed into the ITR registers must be scaled accordingly.

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 pass this scale via mailbox message, 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.

Since we're modifying fm10k_type.h, we may as well also update the
copyright year.
Reported-by: default avatarMatthew Vick <matthew.vick@intel.com>
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Reviewed-by: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarKrishneil Singh <krishneil.k.singh@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 5680ea69
...@@ -150,19 +150,26 @@ static s32 fm10k_init_hw_pf(struct fm10k_hw *hw) ...@@ -150,19 +150,26 @@ static s32 fm10k_init_hw_pf(struct fm10k_hw *hw)
FM10K_TPH_RXCTRL_HDR_WROEN); 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) { switch (hw->bus.speed) {
case fm10k_bus_speed_2500: case fm10k_bus_speed_2500:
dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1; dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN1;
hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN1;
break; break;
case fm10k_bus_speed_5000: case fm10k_bus_speed_5000:
dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2; dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN2;
hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN2;
break; break;
case fm10k_bus_speed_8000: case fm10k_bus_speed_8000:
dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3; dma_ctrl = FM10K_DMA_CTRL_MAX_HOLD_1US_GEN3;
hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3;
break; break;
default: default:
dma_ctrl = 0; dma_ctrl = 0;
/* just in case, assume Gen3 ITR scale */
hw->mac.itr_scale = FM10K_TDLEN_ITR_SCALE_GEN3;
break; break;
} }
...@@ -903,6 +910,13 @@ static s32 fm10k_iov_assign_default_mac_vlan_pf(struct fm10k_hw *hw, ...@@ -903,6 +910,13 @@ 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_TDBAL(vf_q_idx), tdbal);
fm10k_write_reg(hw, FM10K_TDBAH(vf_q_idx), tdbah); 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. See definition of
* FM10K_TDLEN_ITR_SCALE_SHIFT for more details.
*/
fm10k_write_reg(hw, FM10K_TDLEN(vf_q_idx), hw->mac.itr_scale <<
FM10K_TDLEN_ITR_SCALE_SHIFT);
err_out: err_out:
/* configure Queue control register */ /* configure Queue control register */
txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) & txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) &
...@@ -1035,6 +1049,12 @@ static s32 fm10k_iov_reset_resources_pf(struct fm10k_hw *hw, ...@@ -1035,6 +1049,12 @@ static s32 fm10k_iov_reset_resources_pf(struct fm10k_hw *hw,
for (i = queues_per_pool; i--;) { for (i = queues_per_pool; i--;) {
fm10k_write_reg(hw, FM10K_TDBAL(vf_q_idx + i), tdbal); 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_TDBAH(vf_q_idx + i), tdbah);
/* See definition of FM10K_TDLEN_ITR_SCALE_SHIFT for an
* explanation of how TDLEN is used.
*/
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_TQMAP(qmap_idx + i), vf_q_idx + i);
fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i); fm10k_write_reg(hw, FM10K_RQMAP(qmap_idx + i), vf_q_idx + i);
} }
......
/* Intel Ethernet Switch Host Interface Driver /* Intel Ethernet Switch Host Interface Driver
* Copyright(c) 2013 - 2014 Intel Corporation. * Copyright(c) 2013 - 2015 Intel Corporation.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -272,6 +272,20 @@ struct fm10k_hw; ...@@ -272,6 +272,20 @@ struct fm10k_hw;
#define FM10K_TDBAL(_n) ((0x40 * (_n)) + 0x8000) #define FM10K_TDBAL(_n) ((0x40 * (_n)) + 0x8000)
#define FM10K_TDBAH(_n) ((0x40 * (_n)) + 0x8001) #define FM10K_TDBAH(_n) ((0x40 * (_n)) + 0x8001)
#define FM10K_TDLEN(_n) ((0x40 * (_n)) + 0x8002) #define FM10K_TDLEN(_n) ((0x40 * (_n)) + 0x8002)
/* When fist initialized, VFs need to know the Interrupt Throttle Rate (ITR)
* scale which is based on the PCIe speed but the speed information in the PCI
* configuration space may not be accurate. The PF already knows the ITR scale
* but there is no defined method to pass that information from the PF to the
* VF. This is accomplished during VF initialization by temporarily co-opting
* the yet-to-be-used TDLEN register to have the PF store the ITR shift for
* the VF to retrieve before the VF needs to use the TDLEN register for its
* intended purpose, i.e. before the Tx resources are allocated.
*/
#define FM10K_TDLEN_ITR_SCALE_SHIFT 9
#define FM10K_TDLEN_ITR_SCALE_MASK 0x00000E00
#define FM10K_TDLEN_ITR_SCALE_GEN1 2
#define FM10K_TDLEN_ITR_SCALE_GEN2 1
#define FM10K_TDLEN_ITR_SCALE_GEN3 0
#define FM10K_TPH_TXCTRL(_n) ((0x40 * (_n)) + 0x8003) #define FM10K_TPH_TXCTRL(_n) ((0x40 * (_n)) + 0x8003)
#define FM10K_TPH_TXCTRL_DESC_TPHEN 0x00000020 #define FM10K_TPH_TXCTRL_DESC_TPHEN 0x00000020
#define FM10K_TPH_TXCTRL_DESC_RROEN 0x00000200 #define FM10K_TPH_TXCTRL_DESC_RROEN 0x00000200
...@@ -560,6 +574,7 @@ struct fm10k_mac_info { ...@@ -560,6 +574,7 @@ struct fm10k_mac_info {
bool get_host_state; bool get_host_state;
bool tx_ready; bool tx_ready;
u32 dglort_map; u32 dglort_map;
u8 itr_scale;
}; };
struct fm10k_swapi_table_info { struct fm10k_swapi_table_info {
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw) static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
{ {
u8 *perm_addr = hw->mac.perm_addr; u8 *perm_addr = hw->mac.perm_addr;
u32 bal = 0, bah = 0; u32 bal = 0, bah = 0, tdlen;
s32 err; s32 err;
u16 i; u16 i;
...@@ -48,6 +48,9 @@ static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw) ...@@ -48,6 +48,9 @@ static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
((u32)perm_addr[2]); ((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 /* The queues have already been disabled so we just need to
* update their base address registers * update their base address registers
*/ */
...@@ -56,6 +59,12 @@ static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw) ...@@ -56,6 +59,12 @@ static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw)
fm10k_write_reg(hw, FM10K_TDBAH(i), bah); fm10k_write_reg(hw, FM10K_TDBAH(i), bah);
fm10k_write_reg(hw, FM10K_RDBAL(i), bal); fm10k_write_reg(hw, FM10K_RDBAL(i), bal);
fm10k_write_reg(hw, FM10K_RDBAH(i), bah); fm10k_write_reg(hw, FM10K_RDBAH(i), bah);
/* Restore ITR scale in software-defined mechanism in TDLEN
* for next VF initialization. See definition of
* FM10K_TDLEN_ITR_SCALE_SHIFT for more details on the use of
* TDLEN here.
*/
fm10k_write_reg(hw, FM10K_TDLEN(i), tdlen);
} }
return 0; return 0;
...@@ -131,9 +140,16 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw) ...@@ -131,9 +140,16 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
/* record maximum queue count */ /* record maximum queue count */
hw->mac.max_queues = i; 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)) & hw->mac.default_vid = (fm10k_read_reg(hw, FM10K_TXQCTL(0)) &
FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT; FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT;
/* Read the ITR scale from TDLEN. See the definition of
* FM10K_TDLEN_ITR_SCALE_SHIFT for more information about how TDLEN is
* used here.
*/
hw->mac.itr_scale = (fm10k_read_reg(hw, FM10K_TDLEN(0)) &
FM10K_TDLEN_ITR_SCALE_MASK) >>
FM10K_TDLEN_ITR_SCALE_SHIFT;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment