ixgbe: DCB, implement 802.1Qaz routines
authorJohn Fastabend <john.r.fastabend@intel.com>
Thu, 10 Feb 2011 14:40:01 +0000 (14:40 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 11 Feb 2011 16:47:15 +0000 (08:47 -0800)
Implements 802.1Qaz support for ixgbe driver. Additionally,
this adds IEEE_8021QAZ_TSA_{} defines to dcbnl.h this is to
avoid having to use cryptic numeric codes for the TSA type.

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_dcb.c
drivers/net/ixgbe/ixgbe_dcb.h
drivers/net/ixgbe/ixgbe_dcb_82598.c
drivers/net/ixgbe/ixgbe_dcb_nl.c
drivers/net/ixgbe/ixgbe_main.c
include/linux/dcbnl.h

index 3b8c924636171ac9078ff15b0d1c1f2c29b98dad..d04afdeee0353f22bdd9fecc8ef5ae8a41b2fd5d 100644 (file)
@@ -334,6 +334,10 @@ struct ixgbe_adapter {
        u16 bd_number;
        struct work_struct reset_task;
        struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
+
+       /* DCB parameters */
+       struct ieee_pfc *ixgbe_ieee_pfc;
+       struct ieee_ets *ixgbe_ieee_ets;
        struct ixgbe_dcb_config dcb_cfg;
        struct ixgbe_dcb_config temp_dcb_cfg;
        u8 dcb_set_bitmap;
index d9bb670ae2589e5071b2fe60f8fdfc462a6a94f7..13c962efbfc92a96047298573ed62d9dd707ac24 100644 (file)
 #include "ixgbe_dcb_82598.h"
 #include "ixgbe_dcb_82599.h"
 
+/**
+ * ixgbe_ieee_credits - This calculates the ieee traffic class
+ * credits from the configured bandwidth percentages. Credits
+ * are the smallest unit programable into the underlying
+ * hardware. The IEEE 802.1Qaz specification do not use bandwidth
+ * groups so this is much simplified from the CEE case.
+ */
+s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame)
+{
+       int min_percent = 100;
+       int min_credit, multiplier;
+       int i;
+
+       min_credit = ((max_frame / 2) + DCB_CREDIT_QUANTUM - 1) /
+                       DCB_CREDIT_QUANTUM;
+
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               if (bw[i] < min_percent && bw[i])
+                       min_percent = bw[i];
+       }
+
+       multiplier = (min_credit / min_percent) + 1;
+
+       /* Find out the hw credits for each TC */
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               int val = min(bw[i] * multiplier, MAX_CREDIT_REFILL);
+
+               if (val < min_credit)
+                       val = min_credit;
+               refill[i] = val;
+
+               max[i] = (bw[i] * MAX_CREDIT)/100;
+       }
+       return 0;
+}
+
 /**
  * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits
  * @ixgbe_dcb_config: Struct containing DCB settings.
@@ -236,3 +272,70 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
        return ret;
 }
 
+/* Helper routines to abstract HW specifics from DCB netlink ops */
+s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en)
+{
+       int ret = -EINVAL;
+
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB:
+               ret = ixgbe_dcb_config_pfc_82598(hw, pfc_en);
+               break;
+       case ixgbe_mac_82599EB:
+       case ixgbe_mac_X540:
+               ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en);
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw,
+                           u16 *refill, u16 *max, u8 *bwg_id, u8 *tsa)
+{
+       int i;
+       u8 prio_type[IEEE_8021QAZ_MAX_TCS];
+
+       /* Map TSA onto CEE prio type */
+       for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+               switch (tsa[i]) {
+               case IEEE_8021QAZ_TSA_STRICT:
+                       prio_type[i] = 2;
+                       break;
+               case IEEE_8021QAZ_TSA_ETS:
+                       prio_type[i] = 0;
+                       break;
+               default:
+                       /* Hardware only supports priority strict or
+                        * ETS transmission selection algorithms if
+                        * we receive some other value from dcbnl
+                        * throw an error
+                        */
+                       return -EINVAL;
+               }
+       }
+
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB:
+               ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max,
+                                                       prio_type);
+               ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max,
+                                                            bwg_id, prio_type);
+               ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max,
+                                                            bwg_id, prio_type);
+               break;
+       case ixgbe_mac_82599EB:
+       case ixgbe_mac_X540:
+               ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max,
+                                                 bwg_id, prio_type);
+               ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max,
+                                                      bwg_id, prio_type);
+               ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max,
+                                                      bwg_id, prio_type);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
index aa6cb5f9ebf47a302979979a04b6c888416c802a..4e4a641f3d53ca020ab61f50897d6d5b98f22218 100644 (file)
@@ -150,10 +150,14 @@ struct ixgbe_dcb_config {
 void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en);
 
 /* DCB credits calculation */
+s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame);
 s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *,
                                   struct ixgbe_dcb_config *, int, u8);
 
 /* DCB hw initialization */
+s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw,
+                           u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type);
+s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en);
 s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *);
 
 /* DCB definitions for credit calculation */
index d1288060cbd0b33f2fa1cc396755543861f11833..2965edcdac7bbd6c6631a4385f0db56689b327c6 100644 (file)
@@ -291,7 +291,7 @@ out:
  * Configure queue statistics registers, all queues belonging to same traffic
  * class uses a single set of queue statistics counters.
  */
-static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
+s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
 {
        u32 reg = 0;
        u8  i   = 0;
index 6ab1f1abaa01738def88eb84e6e9fa86dffd2a47..e75a3c91198d4bbd88172f17acccdcdd8d7c5c0f 100644 (file)
@@ -606,7 +606,98 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev,
        return rval;
 }
 
+static int ixgbe_dcbnl_ieee_getets(struct net_device *dev,
+                                  struct ieee_ets *ets)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(dev);
+       struct ieee_ets *my_ets = adapter->ixgbe_ieee_ets;
+
+       /* No IEEE PFC settings available */
+       if (!my_ets)
+               return -EINVAL;
+
+       ets->ets_cap = MAX_TRAFFIC_CLASS;
+       ets->cbs = my_ets->cbs;
+       memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
+       memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
+       memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
+       memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
+       return 0;
+}
+
+static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
+                                  struct ieee_ets *ets)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(dev);
+       __u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS];
+       int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
+       int err;
+       /* naively give each TC a bwg to map onto CEE hardware */
+       __u8 bwg_id[IEEE_8021QAZ_MAX_TCS] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+       if (!adapter->ixgbe_ieee_ets) {
+               adapter->ixgbe_ieee_ets = kmalloc(sizeof(struct ieee_ets),
+                                                 GFP_KERNEL);
+               if (!adapter->ixgbe_ieee_ets)
+                       return -ENOMEM;
+       }
+
+
+       memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets));
+
+       ixgbe_ieee_credits(ets->tc_tx_bw, refill, max, max_frame);
+       err = ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max,
+                                     bwg_id, ets->tc_tsa);
+       return err;
+}
+
+static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev,
+                                  struct ieee_pfc *pfc)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(dev);
+       struct ieee_pfc *my_pfc = adapter->ixgbe_ieee_pfc;
+       int i;
+
+       /* No IEEE PFC settings available */
+       if (!my_pfc)
+               return -EINVAL;
+
+       pfc->pfc_cap = MAX_TRAFFIC_CLASS;
+       pfc->pfc_en = my_pfc->pfc_en;
+       pfc->mbc = my_pfc->mbc;
+       pfc->delay = my_pfc->delay;
+
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               pfc->requests[i] = adapter->stats.pxoffrxc[i];
+               pfc->indications[i] = adapter->stats.pxofftxc[i];
+       }
+
+       return 0;
+}
+
+static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev,
+                                  struct ieee_pfc *pfc)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(dev);
+       int err;
+
+       if (!adapter->ixgbe_ieee_pfc) {
+               adapter->ixgbe_ieee_pfc = kmalloc(sizeof(struct ieee_pfc),
+                                                 GFP_KERNEL);
+               if (!adapter->ixgbe_ieee_pfc)
+                       return -ENOMEM;
+       }
+
+       memcpy(adapter->ixgbe_ieee_pfc, pfc, sizeof(*adapter->ixgbe_ieee_pfc));
+       err = ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en);
+       return err;
+}
+
 const struct dcbnl_rtnl_ops dcbnl_ops = {
+       .ieee_getets    = ixgbe_dcbnl_ieee_getets,
+       .ieee_setets    = ixgbe_dcbnl_ieee_setets,
+       .ieee_getpfc    = ixgbe_dcbnl_ieee_getpfc,
+       .ieee_setpfc    = ixgbe_dcbnl_ieee_setpfc,
        .getstate       = ixgbe_dcbnl_get_state,
        .setstate       = ixgbe_dcbnl_set_state,
        .getpermhwaddr  = ixgbe_dcbnl_get_perm_hw_addr,
index 1e4814875945e12f4fa0bb49f1f93ca4be38d1fc..c2e09b9cff464bef3accecd452f86d0912d42520 100644 (file)
@@ -5609,6 +5609,10 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
        }
 
        ixgbe_clear_interrupt_scheme(adapter);
+#ifdef CONFIG_DCB
+       kfree(adapter->ixgbe_ieee_pfc);
+       kfree(adapter->ixgbe_ieee_ets);
+#endif
 
 #ifdef CONFIG_PM
        retval = pci_save_state(pdev);
index 68cd248f6d3e20acba330fc7f9a92df1e3f278ab..cd8d518efa3b007163f3411ff06e54748e75cd0a 100644 (file)
 /* IEEE 802.1Qaz std supported values */
 #define IEEE_8021QAZ_MAX_TCS   8
 
+#define IEEE_8021QAZ_TSA_STRICT                0
+#define IEEE_8021QAZ_TSA_CB_SHABER     1
+#define IEEE_8021QAZ_TSA_ETS           2
+#define IEEE_8021QAZ_TSA_VENDOR                255
+
 /* This structure contains the IEEE 802.1Qaz ETS managed object
  *
  * @willing: willing bit in ETS configuratin TLV