diff options
author | Alexander Duyck | 2012-04-19 19:48:48 +0200 |
---|---|---|
committer | Jeff Kirsher | 2012-05-04 12:25:24 +0200 |
commit | 041441d0f0d885619d48f8f7682825ace523cf59 (patch) | |
tree | c1ddc6cb296a46862093138aa1ada4c2cf8f0d0d /drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | |
parent | ixgbe: Reorder link flow control functions in ixgbe_common.c (diff) | |
download | kernel-qcow2-linux-041441d0f0d885619d48f8f7682825ace523cf59.tar.gz kernel-qcow2-linux-041441d0f0d885619d48f8f7682825ace523cf59.tar.xz kernel-qcow2-linux-041441d0f0d885619d48f8f7682825ace523cf59.zip |
ixgbe: Update link flow control to correctly handle multiple packet buffer DCB
This change updates the link flow control configuration so that we
correctly set the link flow control settings for DCB. Previously we would
have to call the fc_enable call 8 times, once for each packet buffer. If
we move that logic into the fc_enable call itself we can avoid multiple
unnecessary register writes.
This change also corrects an issue in which we were only shifting the water
marks for 82599 parts by 6 instead of 10. This was resulting in us only
using 1/16 of the packet buffer when flow control was enabled.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/ixgbe/ixgbe_common.c')
-rw-r--r-- | drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 164 |
1 files changed, 60 insertions, 104 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 3035f1938f5b..c7e51b85b8b6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -84,39 +84,12 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) * * Called at init time to set up flow control. **/ -static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) +static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) { s32 ret_val = 0; u32 reg = 0, reg_bp = 0; u16 reg_cu = 0; -#ifdef CONFIG_DCB - if (hw->fc.requested_mode == ixgbe_fc_pfc) { - hw->fc.current_mode = hw->fc.requested_mode; - goto out; - } - -#endif /* CONFIG_DCB */ - /* Validate the packetbuf configuration */ - if (packetbuf_num < 0 || packetbuf_num > 7) { - hw_dbg(hw, "Invalid packet buffer number [%d], expected range is 0-7\n", - packetbuf_num); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - - /* - * Validate the water mark configuration. Zero water marks are invalid - * because it causes the controller to just blast out fc packets. - */ - if (!hw->fc.low_water || - !hw->fc.high_water[packetbuf_num] || - !hw->fc.pause_time) { - hw_dbg(hw, "Invalid water mark configuration\n"); - ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; - goto out; - } - /* * Validate the requested mode. Strict IEEE mode does not allow * ixgbe_fc_rx_pause because it will cause us to fail at UNH. @@ -139,21 +112,18 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) * HW will be able to do fc autoneg once the cable is plugged in. If * we link at 10G, the 1G advertisement is harmless and vice versa. */ - switch (hw->phy.media_type) { case ixgbe_media_type_fiber: case ixgbe_media_type_backplane: reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); reg_bp = IXGBE_READ_REG(hw, IXGBE_AUTOC); break; - case ixgbe_media_type_copper: hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, ®_cu); break; - default: - ; + break; } /* @@ -164,9 +134,6 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) * 2: Tx flow control is enabled (we can send pause frames but * we do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. -#ifdef CONFIG_DCB - * 4: Priority Flow Control is enabled. -#endif * other: Invalid. */ switch (hw->fc.requested_mode) { @@ -179,51 +146,40 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) else if (hw->phy.media_type == ixgbe_media_type_copper) reg_cu &= ~(IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); break; - case ixgbe_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is - * disabled by software override. Since there really - * isn't a way to advertise that we are capable of RX - * Pause ONLY, we will advertise that we support both - * symmetric and asymmetric Rx PAUSE. Later, we will - * disable the adapter's ability to send PAUSE frames. - */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); - if (hw->phy.media_type == ixgbe_media_type_backplane) - reg_bp |= (IXGBE_AUTOC_SYM_PAUSE | - IXGBE_AUTOC_ASM_PAUSE); - else if (hw->phy.media_type == ixgbe_media_type_copper) - reg_cu |= (IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); - break; case ixgbe_fc_tx_pause: /* * Tx Flow control is enabled, and Rx Flow control is * disabled by software override. */ - reg |= (IXGBE_PCS1GANA_ASM_PAUSE); - reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE); + reg |= IXGBE_PCS1GANA_ASM_PAUSE; + reg &= ~IXGBE_PCS1GANA_SYM_PAUSE; if (hw->phy.media_type == ixgbe_media_type_backplane) { - reg_bp |= (IXGBE_AUTOC_ASM_PAUSE); - reg_bp &= ~(IXGBE_AUTOC_SYM_PAUSE); + reg_bp |= IXGBE_AUTOC_ASM_PAUSE; + reg_bp &= ~IXGBE_AUTOC_SYM_PAUSE; } else if (hw->phy.media_type == ixgbe_media_type_copper) { - reg_cu |= (IXGBE_TAF_ASM_PAUSE); - reg_cu &= ~(IXGBE_TAF_SYM_PAUSE); + reg_cu |= IXGBE_TAF_ASM_PAUSE; + reg_cu &= ~IXGBE_TAF_SYM_PAUSE; } break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE, as such we fall + * through to the fc_full statement. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ case ixgbe_fc_full: /* Flow control (both Rx and Tx) is enabled by SW override. */ - reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE); + reg |= IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE; if (hw->phy.media_type == ixgbe_media_type_backplane) - reg_bp |= (IXGBE_AUTOC_SYM_PAUSE | - IXGBE_AUTOC_ASM_PAUSE); + reg_bp |= IXGBE_AUTOC_SYM_PAUSE | + IXGBE_AUTOC_ASM_PAUSE; else if (hw->phy.media_type == ixgbe_media_type_copper) - reg_cu |= (IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE); - break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; + reg_cu |= IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE; break; -#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; @@ -298,7 +254,7 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); /* Setup flow control */ - ixgbe_setup_fc(hw, 0); + ixgbe_setup_fc(hw); /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -2126,28 +2082,36 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw) /** * ixgbe_fc_enable_generic - Enable flow control * @hw: pointer to hardware structure - * @packetbuf_num: packet buffer number (0-7) * * Enable flow control according to the current settings. **/ -s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) +s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) { s32 ret_val = 0; u32 mflcn_reg, fccfg_reg; u32 reg; u32 fcrtl, fcrth; + int i; -#ifdef CONFIG_DCB - if (hw->fc.requested_mode == ixgbe_fc_pfc) + /* + * Validate the water mark configuration for packet buffer 0. Zero + * water marks indicate that the packet buffer was not configured + * and the watermarks for packet buffer 0 should always be configured. + */ + if (!hw->fc.low_water || + !hw->fc.high_water[0] || + !hw->fc.pause_time) { + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; + } -#endif /* CONFIG_DCB */ /* Negotiate the fc mode to use */ ixgbe_fc_autoneg(hw); /* Disable any previous flow control settings */ mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); - mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE); + mflcn_reg &= ~(IXGBE_MFLCN_RPFCE_MASK | IXGBE_MFLCN_RFCE); fccfg_reg = IXGBE_READ_REG(hw, IXGBE_FCCFG); fccfg_reg &= ~(IXGBE_FCCFG_TFCE_802_3X | IXGBE_FCCFG_TFCE_PRIORITY); @@ -2160,9 +2124,6 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) * 2: Tx flow control is enabled (we can send pause frames but * we do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. -#ifdef CONFIG_DCB - * 4: Priority Flow Control is enabled. -#endif * other: Invalid. */ switch (hw->fc.current_mode) { @@ -2195,11 +2156,6 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) mflcn_reg |= IXGBE_MFLCN_RFCE; fccfg_reg |= IXGBE_FCCFG_TFCE_802_3X; break; -#ifdef CONFIG_DCB - case ixgbe_fc_pfc: - goto out; - break; -#endif /* CONFIG_DCB */ default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; @@ -2212,34 +2168,34 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num) IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); - fcrtl = hw->fc.low_water << 10; + fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; - if (hw->fc.current_mode & ixgbe_fc_tx_pause) { - fcrth = hw->fc.high_water[packetbuf_num] << 10; - fcrth |= IXGBE_FCRTH_FCEN; - if (hw->fc.send_xon) - fcrtl |= IXGBE_FCRTL_XONE; - } else { - /* - * If Tx flow control is disabled, set our high water mark - * to Rx FIFO size minus 32 in order prevent Tx switch - * loopback from stalling on DMA. - */ - fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num)) - 32; - } + /* Set up and enable Rx high/low water mark thresholds, enable XON. */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && + hw->fc.high_water[i]) { + 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. + */ + fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32; + } - IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), fcrth); - IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), fcrtl); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), fcrth); + } /* Configure pause time (2 TCs per register) */ - reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2)); - if ((packetbuf_num & 1) == 0) - reg = (reg & 0xFFFF0000) | hw->fc.pause_time; - else - reg = (reg & 0x0000FFFF) | (hw->fc.pause_time << 16); - IXGBE_WRITE_REG(hw, IXGBE_FCTTV(packetbuf_num / 2), reg); + reg = hw->fc.pause_time * 0x00010001; + for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); - IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1)); + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); out: return ret_val; |