OSDN Git Service

enetc: Enable TC offloading with mqprio
authorCamelia Groza <camelia.groza@nxp.com>
Mon, 27 May 2019 15:21:31 +0000 (18:21 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 29 May 2019 00:11:02 +0000 (17:11 -0700)
Add support to configure multiple prioritized TX traffic
classes with mqprio.

Configure one BD ring per TC for the moment, one netdev
queue per TC.

Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
Signed-off-by: Claudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/freescale/enetc/enetc.c
drivers/net/ethernet/freescale/enetc/enetc.h
drivers/net/ethernet/freescale/enetc/enetc_hw.h
drivers/net/ethernet/freescale/enetc/enetc_pf.c
drivers/net/ethernet/freescale/enetc/enetc_vf.c

index 79bbc86..2237094 100644 (file)
@@ -1427,6 +1427,62 @@ int enetc_close(struct net_device *ndev)
        return 0;
 }
 
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+                  void *type_data)
+{
+       struct enetc_ndev_priv *priv = netdev_priv(ndev);
+       struct tc_mqprio_qopt *mqprio = type_data;
+       struct enetc_bdr *tx_ring;
+       u8 num_tc;
+       int i;
+
+       if (type != TC_SETUP_QDISC_MQPRIO)
+               return -EOPNOTSUPP;
+
+       mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
+       num_tc = mqprio->num_tc;
+
+       if (!num_tc) {
+               netdev_reset_tc(ndev);
+               netif_set_real_num_tx_queues(ndev, priv->num_tx_rings);
+
+               /* Reset all ring priorities to 0 */
+               for (i = 0; i < priv->num_tx_rings; i++) {
+                       tx_ring = priv->tx_ring[i];
+                       enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, 0);
+               }
+
+               return 0;
+       }
+
+       /* Check if we have enough BD rings available to accommodate all TCs */
+       if (num_tc > priv->num_tx_rings) {
+               netdev_err(ndev, "Max %d traffic classes supported\n",
+                          priv->num_tx_rings);
+               return -EINVAL;
+       }
+
+       /* For the moment, we use only one BD ring per TC.
+        *
+        * Configure num_tc BD rings with increasing priorities.
+        */
+       for (i = 0; i < num_tc; i++) {
+               tx_ring = priv->tx_ring[i];
+               enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, i);
+       }
+
+       /* Reset the number of netdev queues based on the TC count */
+       netif_set_real_num_tx_queues(ndev, num_tc);
+
+       netdev_set_num_tc(ndev, num_tc);
+
+       /* Each TC is associated with one netdev queue */
+       for (i = 0; i < num_tc; i++)
+               netdev_set_tc_queue(ndev, i, 1, i);
+
+       return 0;
+}
+
 struct net_device_stats *enetc_get_stats(struct net_device *ndev)
 {
        struct enetc_ndev_priv *priv = netdev_priv(ndev);
index ea44326..541b4e2 100644 (file)
@@ -229,6 +229,9 @@ struct net_device_stats *enetc_get_stats(struct net_device *ndev);
 int enetc_set_features(struct net_device *ndev,
                       netdev_features_t features);
 int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd);
+int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+                  void *type_data);
+
 /* ethtool */
 void enetc_set_ethtool_ops(struct net_device *ndev);
 
index 6559cef..8827629 100644 (file)
@@ -127,7 +127,7 @@ enum enetc_bdr_type {TX, RX};
 #define ENETC_TBSR_BUSY        BIT(0)
 #define ENETC_TBMR_VIH BIT(9)
 #define ENETC_TBMR_PRIO_MASK           GENMASK(2, 0)
-#define ENETC_TBMR_PRIO_SET(val)       val
+#define ENETC_TBMR_SET_PRIO(val)       ((val) & ENETC_TBMR_PRIO_MASK)
 #define ENETC_TBMR_EN  BIT(31)
 #define ENETC_TBSR     0x4
 #define ENETC_TBBAR0   0x10
@@ -544,3 +544,13 @@ static inline void enetc_enable_txvlan(struct enetc_hw *hw, int si_idx,
        val = (val & ~ENETC_TBMR_VIH) | (en ? ENETC_TBMR_VIH : 0);
        enetc_txbdr_wr(hw, si_idx, ENETC_TBMR, val);
 }
+
+static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx,
+                                     int prio)
+{
+       u32 val = enetc_txbdr_rd(hw, bdr_idx, ENETC_TBMR);
+
+       val &= ~ENETC_TBMR_PRIO_MASK;
+       val |= ENETC_TBMR_SET_PRIO(prio);
+       enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val);
+}
index d78ec8d..258b3cb 100644 (file)
@@ -703,6 +703,7 @@ static const struct net_device_ops enetc_ndev_ops = {
        .ndo_set_vf_spoofchk    = enetc_pf_set_vf_spoofchk,
        .ndo_set_features       = enetc_pf_set_features,
        .ndo_do_ioctl           = enetc_ioctl,
+       .ndo_setup_tc           = enetc_setup_tc,
 };
 
 static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
index 17f7264..ebd21bf 100644 (file)
@@ -112,6 +112,7 @@ static const struct net_device_ops enetc_ndev_ops = {
        .ndo_set_mac_address    = enetc_vf_set_mac_addr,
        .ndo_set_features       = enetc_vf_set_features,
        .ndo_do_ioctl           = enetc_ioctl,
+       .ndo_setup_tc           = enetc_setup_tc,
 };
 
 static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,