ixgbe: DCB set PFC high and low water marks per data sheet specs
authorJohn Fastabend <john.r.fastabend@intel.com>
Wed, 17 Nov 2010 03:26:44 +0000 (19:26 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 17 Nov 2010 03:26:44 +0000 (19:26 -0800)
Currently the high and low water marks for PFC are being set
conservatively for jumbo frames. This means the RX buffers
are being underutilized in the default 1500 MTU. This patch
fixes this so that the water marks are set as described in
the data sheet considering the MTU size.

The equation used is,

RTT * 1.44 + MTU * 1.44 + MTU

Where RTT is the round trip time and MTU is the max frame size
in KB. To avoid floating point arithmetic FC_HIGH_WATER is
defined

((((RTT + MTU) * 144) + 99) / 100) + MTU

This changes how the hardware field fc.low_water and
fc.high_water are used. With this change they are no longer
storing the actual low water and high water markers but are
storing the required head room in the buffer. This simplifies
the logic and we do not need to account for the size of the
buffer when setting the thresholds.

Testing with iperf and 16 threads showed a slight uptick in
throughput over a single traffic class .1-.2Gbps and a reduction
in pause frames. Without the patch a 30 second run would show
~10-15 pause frames being transmitted with the patch ~2-5 are
seen. Test were run back to back with 82599.

Note RXPBSIZE is in KB and low and high water marks fields are
also in KB. However the FCRT* registers are 32B granularity and
right shifted 5 into the register,

(((rx_pbsize - water_mark) * 1024) / 32) << 5

is the most explicit conversion here we simplify

(rx_pbsize - water_mark) * 32 << 5 = (rx_pbsize - water_mark) << 10

This patch updates the PFC thresholds and legacy FC thresholds.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_dcb_82598.c
drivers/net/ixgbe/ixgbe_dcb_82599.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_type.h

index 018e143612b2a99ea9d50f82d51d8d0b88353891..4f98486d8c2cdd9f3d4d054767f5032c5c82b8ba 100644 (file)
 #define IXGBE_MIN_RXD                       64
 
 /* flow control */
-#define IXGBE_DEFAULT_FCRTL            0x10000
 #define IXGBE_MIN_FCRTL                           0x40
 #define IXGBE_MAX_FCRTL                        0x7FF80
-#define IXGBE_DEFAULT_FCRTH            0x20000
 #define IXGBE_MIN_FCRTH                          0x600
 #define IXGBE_MAX_FCRTH                        0x7FFF0
 #define IXGBE_DEFAULT_FCPAUSE           0xFFFF
index 9c02d6014cc43856fa405d8b0c0cc140aef63dde..25b20f93190a1307eb009614eba58d1beb743c9d 100644 (file)
@@ -357,6 +357,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
        u32 fctrl_reg;
        u32 rmcs_reg;
        u32 reg;
+       u32 rx_pba_size;
        u32 link_speed = 0;
        bool link_up;
 
@@ -459,16 +460,18 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
 
        /* Set up and enable Rx high/low water mark thresholds, enable XON. */
        if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
-               if (hw->fc.send_xon) {
-                       IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
-                                       (hw->fc.low_water | IXGBE_FCRTL_XONE));
-               } else {
-                       IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
-                                       hw->fc.low_water);
-               }
+               rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
+               rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
+
+               reg = (rx_pba_size - hw->fc.low_water) << 6;
+               if (hw->fc.send_xon)
+                       reg |= IXGBE_FCRTL_XONE;
+               IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num), reg);
+
+               reg = (rx_pba_size - hw->fc.high_water) << 10;
+               reg |= IXGBE_FCRTH_FCEN;
 
-               IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
-                               (hw->fc.high_water | IXGBE_FCRTH_FCEN));
+               IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num), reg);
        }
 
        /* Configure pause time (2 TCs per register) */
index e3eca13163891c7ba339b71c1b95768247c4542e..62aa2be199f15bf89c7be3bfa932424372e9cc82 100644 (file)
@@ -1595,6 +1595,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
        u32 mflcn_reg, fccfg_reg;
        u32 reg;
        u32 rx_pba_size;
+       u32 fcrtl, fcrth;
 
 #ifdef CONFIG_DCB
        if (hw->fc.requested_mode == ixgbe_fc_pfc)
@@ -1671,41 +1672,21 @@ 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);
 
-       reg = IXGBE_READ_REG(hw, IXGBE_MTQC);
-       /* Thresholds are different for link flow control when in DCB mode */
-       if (reg & IXGBE_MTQC_RT_ENA) {
-               rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
+       rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
+       rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
 
-               /* Always disable XON for LFC when in DCB mode */
-               reg = (rx_pba_size >> 5) & 0xFFE0;
-               IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), reg);
+       fcrth = (rx_pba_size - hw->fc.high_water) << 10;
+       fcrtl = (rx_pba_size - hw->fc.low_water) << 10;
 
-               reg = (rx_pba_size >> 2) & 0xFFE0;
-               if (hw->fc.current_mode & ixgbe_fc_tx_pause)
-                       reg |= IXGBE_FCRTH_FCEN;
-               IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), reg);
-       } else {
-               /*
-                * Set up and enable Rx high/low water mark thresholds,
-                * enable XON.
-                */
-               if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
-                       if (hw->fc.send_xon) {
-                               IXGBE_WRITE_REG(hw,
-                                             IXGBE_FCRTL_82599(packetbuf_num),
-                                             (hw->fc.low_water |
-                                             IXGBE_FCRTL_XONE));
-                       } else {
-                               IXGBE_WRITE_REG(hw,
-                                             IXGBE_FCRTL_82599(packetbuf_num),
-                                             hw->fc.low_water);
-                       }
-
-                       IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num),
-                                      (hw->fc.high_water | IXGBE_FCRTH_FCEN));
-               }
+       if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
+               fcrth |= IXGBE_FCRTH_FCEN;
+               if (hw->fc.send_xon)
+                       fcrtl |= IXGBE_FCRTL_XONE;
        }
 
+       IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num), fcrth);
+       IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), fcrtl);
+
        /* Configure pause time (2 TCs per register) */
        reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num / 2));
        if ((packetbuf_num & 1) == 0)
index 50288bcadc5985bac86d29e2ff12abd1777875bc..9a5e89c12e050281af83dbf2b143264fdf974fe3 100644 (file)
@@ -256,21 +256,17 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw,
         * for each traffic class.
         */
        for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-               if (dcb_config->rx_pba_cfg == pba_equal) {
-                       rx_pba_size = IXGBE_RXPBSIZE_64KB;
-               } else {
-                       rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB
-                                             : IXGBE_RXPBSIZE_48KB;
-               }
+               rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
+               rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
+               reg = (rx_pba_size - hw->fc.low_water) << 10;
 
-               reg = ((rx_pba_size >> 5) &  0xFFF0);
                if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
                    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
                        reg |= IXGBE_FCRTL_XONE;
 
                IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg);
 
-               reg = ((rx_pba_size >> 2) & 0xFFF0);
+               reg = (rx_pba_size - hw->fc.high_water) << 10;
                if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
                    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
                        reg |= IXGBE_FCRTH_FCEN;
index 05f224715073cf46e42e52db91a1b57fca226ddc..374e1f74d0f51c20bbfe6e245d8500f90a015dab 100644 (file)
@@ -251,19 +251,17 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
 
        /* Configure PFC Tx thresholds per TC */
        for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-               if (dcb_config->rx_pba_cfg == pba_equal)
-                       rx_pba_size = IXGBE_RXPBSIZE_64KB;
-               else
-                       rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB
-                                             : IXGBE_RXPBSIZE_48KB;
+               rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
+               rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
+
+               reg = (rx_pba_size - hw->fc.low_water) << 10;
 
-               reg = ((rx_pba_size >> 5) & 0xFFE0);
                if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full ||
                    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx)
                        reg |= IXGBE_FCRTL_XONE;
                IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg);
 
-               reg = ((rx_pba_size >> 2) & 0xFFE0);
+               reg = (rx_pba_size - hw->fc.high_water) << 10;
                if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full ||
                    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx)
                        reg |= IXGBE_FCRTH_FCEN;
index a137f9dbaacd7ee90e410bdf246acedbb38faa7c..f374207e14b407cbd69a32ad344c1e7d146687b4 100644 (file)
@@ -4854,6 +4854,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
        int j;
        struct tc_configuration *tc;
 #endif
+       int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
 
        /* PCI config space info */
 
@@ -4930,8 +4931,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
 #ifdef CONFIG_DCB
        adapter->last_lfc_mode = hw->fc.current_mode;
 #endif
-       hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
-       hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
+       hw->fc.high_water = FC_HIGH_WATER(max_frame);
+       hw->fc.low_water = FC_LOW_WATER(max_frame);
        hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
        hw->fc.send_xon = true;
        hw->fc.disable_fc_autoneg = false;
@@ -5193,6 +5194,7 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
 static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
        int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
 
        /* MTU < 68 is an error and causes problems on some kernels */
@@ -5203,6 +5205,9 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
        /* must set new MTU before calling down or up */
        netdev->mtu = new_mtu;
 
+       hw->fc.high_water = FC_HIGH_WATER(max_frame);
+       hw->fc.low_water = FC_LOW_WATER(max_frame);
+
        if (netif_running(netdev))
                ixgbe_reinit_locked(adapter);
 
index d3cc6ce7c973a3c71855588029e57ab7dcd82ef6..96dea7731e68abcb93733211b5a1fff8b61b9570 100644 (file)
@@ -2113,6 +2113,14 @@ typedef u32 ixgbe_physical_layer;
 #define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000
 #define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA 0x2000
 
+/* Flow Control Macros */
+#define PAUSE_RTT      8
+#define PAUSE_MTU(MTU) ((MTU + 1024 - 1) / 1024)
+
+#define FC_HIGH_WATER(MTU) ((((PAUSE_RTT + PAUSE_MTU(MTU)) * 144) + 99) / 100 +\
+                               PAUSE_MTU(MTU))
+#define FC_LOW_WATER(MTU)  (2 * (2 * PAUSE_MTU(MTU) + PAUSE_RTT))
+
 /* Software ATR hash keys */
 #define IXGBE_ATR_BUCKET_HASH_KEY    0xE214AD3D
 #define IXGBE_ATR_SIGNATURE_HASH_KEY 0x14364D17