From e5776620a7b7b2aacbc60ff1cdbeca6814ec8411 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Sat, 5 Apr 2014 02:35:52 +0000 Subject: [PATCH] ixgbe: convert low_water into an array Since fc.high_water is an array, we should treat low_water as an array also. This allows the algorithm to output different values for different TCs, and then we can distinguish between them. In addition, this patch changes one path that didn't honor the return value from ixgbe_setup_fc. Reported-by: Aaron Salter Signed-off-by: Jacob Keller Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ixgbe/ixgbe_82598.c | 27 ++++++++------ .../net/ethernet/intel/ixgbe/ixgbe_common.c | 35 ++++++++++++------- .../ethernet/intel/ixgbe/ixgbe_dcb_82598.c | 2 +- .../ethernet/intel/ixgbe/ixgbe_dcb_82599.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h | 2 -- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 22 ++++++++---- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 +- 7 files changed, 57 insertions(+), 35 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 4c78ea8946c1..1c52e4753480 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -337,19 +337,25 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) int i; bool link_up; - /* - * 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"); + /* Validate the water mark configuration */ + if (!hw->fc.pause_time) { ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; } + /* Low water mark of zero causes XOFF floods */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && + hw->fc.high_water[i]) { + if (!hw->fc.low_water[i] || + hw->fc.low_water[i] >= hw->fc.high_water[i]) { + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + } + } + /* * On 82598 having Rx FC on causes resets while doing 1G * so if it's on turn it off once we know link_speed. For @@ -432,12 +438,11 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg); IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg); - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; - /* 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]) { + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), fcrtl); IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), fcrth); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 24fba39e194e..6cc148b7c132 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -271,6 +271,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) **/ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) { + s32 ret_val; u32 ctrl_ext; /* Set the media type */ @@ -292,12 +293,15 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); /* Setup flow control */ - ixgbe_setup_fc(hw); + ret_val = ixgbe_setup_fc(hw); + if (!ret_val) + goto out; /* Clear adapter stopped flag */ hw->adapter_stopped = false; - return 0; +out: + return ret_val; } /** @@ -2106,19 +2110,25 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) u32 fcrtl, fcrth; int i; - /* - * 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"); + /* Validate the water mark configuration. */ + if (!hw->fc.pause_time) { ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; } + /* Low water mark of zero causes XOFF floods */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && + hw->fc.high_water[i]) { + if (!hw->fc.low_water[i] || + hw->fc.low_water[i] >= hw->fc.high_water[i]) { + hw_dbg(hw, "Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + } + } + /* Negotiate the fc mode to use */ ixgbe_fc_autoneg(hw); @@ -2181,12 +2191,11 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; - /* 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]) { + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); fcrth = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; } else { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c index 7a77f37a7cbc..d3ba63f9ad37 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c @@ -208,7 +208,6 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; /* Configure PFC Tx thresholds per TC */ for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { if (!(pfc_en & (1 << i))) { @@ -217,6 +216,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) continue; } + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), fcrtl); IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c index bdb99b3b0f30..3b932fe64ab6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c @@ -242,7 +242,6 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) max_tc = prio_tc[i]; } - fcrtl = (hw->fc.low_water << 10) | IXGBE_FCRTL_XONE; /* Configure PFC Tx thresholds per TC */ for (i = 0; i <= max_tc; i++) { @@ -257,6 +256,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *prio_tc) if (enabled) { reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); } else { reg = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h index b16cc786750d..0772b7730fce 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h @@ -81,9 +81,7 @@ struct ixgbe_fcoe { void *extra_ddp_buffer; dma_addr_t extra_ddp_buffer_dma; unsigned long mode; -#ifdef CONFIG_IXGBE_DCB u8 up; -#endif }; #endif /* _IXGBE_FCOE_H */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index c4c526b7f99f..147efec3e002 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -4100,8 +4100,8 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb) (tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) && (pb == ixgbe_fcoe_get_tc(adapter))) tc = IXGBE_FCOE_JUMBO_FRAME_SIZE; - #endif + /* Calculate delay value for device */ switch (hw->mac.type) { case ixgbe_mac_X540: @@ -4142,7 +4142,7 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb) * @adapter: board private structure to calculate for * @pb: packet buffer to calculate */ -static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter) +static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter, int pb) { struct ixgbe_hw *hw = &adapter->hw; struct net_device *dev = adapter->netdev; @@ -4152,6 +4152,14 @@ static int ixgbe_lpbthresh(struct ixgbe_adapter *adapter) /* Calculate max LAN frame size */ tc = dev->mtu + ETH_HLEN + ETH_FCS_LEN; +#ifdef IXGBE_FCOE + /* FCoE traffic class uses FCOE jumbo frames */ + if ((dev->features & NETIF_F_FCOE_MTU) && + (tc < IXGBE_FCOE_JUMBO_FRAME_SIZE) && + (pb == netdev_get_prio_tc_map(dev, adapter->fcoe.up))) + tc = IXGBE_FCOE_JUMBO_FRAME_SIZE; +#endif + /* Calculate delay value for device */ switch (hw->mac.type) { case ixgbe_mac_X540: @@ -4178,15 +4186,17 @@ static void ixgbe_pbthresh_setup(struct ixgbe_adapter *adapter) if (!num_tc) num_tc = 1; - hw->fc.low_water = ixgbe_lpbthresh(adapter); - for (i = 0; i < num_tc; i++) { hw->fc.high_water[i] = ixgbe_hpbthresh(adapter, i); + hw->fc.low_water[i] = ixgbe_lpbthresh(adapter, i); /* Low water marks must not be larger than high water marks */ - if (hw->fc.low_water > hw->fc.high_water[i]) - hw->fc.low_water = 0; + if (hw->fc.low_water[i] > hw->fc.high_water[i]) + hw->fc.low_water[i] = 0; } + + for (; i < MAX_TRAFFIC_CLASS; i++) + hw->fc.high_water[i] = 0; } static void ixgbe_configure_pb(struct ixgbe_adapter *adapter) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 8a6ff2423f07..551d6089a4d3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -2746,7 +2746,7 @@ struct ixgbe_bus_info { /* Flow control parameters */ struct ixgbe_fc_info { u32 high_water[MAX_TRAFFIC_CLASS]; /* Flow Control High-water */ - u32 low_water; /* Flow Control Low-water */ + u32 low_water[MAX_TRAFFIC_CLASS]; /* Flow Control Low-water */ u16 pause_time; /* Flow Control Pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */