net: hns3: Add mqprio hardware offload support in hns3 driver
authorYunsheng Lin <linyunsheng@huawei.com>
Tue, 17 Oct 2017 06:51:30 +0000 (14:51 +0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 19 Oct 2017 11:45:45 +0000 (12:45 +0100)
When using tc qdisc, dcb_ops->setup_tc is used to tell hclge_dcb
module to do the tm related setup. Only TC_MQPRIO_MODE_CHANNEL
offload mode is supported.

Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c

index 575f50df340c4d8957c9133de6248c6491c99a98..3acd8db0a794cbadd5045d43fafd5a06560d0852 100644 (file)
@@ -381,6 +381,7 @@ struct hnae3_dcb_ops {
        u8   (*setdcbx)(struct hnae3_handle *, u8);
 
        int (*map_update)(struct hnae3_handle *);
+       int (*setup_tc)(struct hnae3_handle *, u8, u8 *);
 };
 
 struct hnae3_ae_algo {
index 1b30a6f966d8210d2760b28586cecbf6ceadd7ea..5018d66331337647515dd15cc35d422d1f242780 100644 (file)
@@ -178,7 +178,8 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets)
        u8 num_tc = 0;
        int ret;
 
-       if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
+       if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
+           hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE)
                return -EINVAL;
 
        ret = hclge_ets_validate(hdev, ets, &num_tc, &map_changed);
@@ -228,7 +229,8 @@ static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
        struct hclge_dev *hdev = vport->back;
        u8 i, j, pfc_map, *prio_tc;
 
-       if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
+       if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
+           hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE)
                return -EINVAL;
 
        prio_tc = hdev->tm_info.prio_tc;
@@ -257,6 +259,9 @@ static u8 hclge_getdcbx(struct hnae3_handle *h)
        struct hclge_vport *vport = hclge_get_vport(h);
        struct hclge_dev *hdev = vport->back;
 
+       if (hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE)
+               return 0;
+
        return hdev->dcbx_cap;
 }
 
@@ -276,6 +281,43 @@ static u8 hclge_setdcbx(struct hnae3_handle *h, u8 mode)
        return 0;
 }
 
+/* Set up TC for hardware offloaded mqprio in channel mode */
+static int hclge_setup_tc(struct hnae3_handle *h, u8 tc, u8 *prio_tc)
+{
+       struct hclge_vport *vport = hclge_get_vport(h);
+       struct hclge_dev *hdev = vport->back;
+       int ret;
+
+       if (hdev->flag & HCLGE_FLAG_DCB_ENABLE)
+               return -EINVAL;
+
+       if (tc > hdev->tc_max) {
+               dev_err(&hdev->pdev->dev,
+                       "setup tc failed, tc(%u) > tc_max(%u)\n",
+                       tc, hdev->tc_max);
+               return -EINVAL;
+       }
+
+       hclge_tm_schd_info_update(hdev, tc);
+
+       ret = hclge_tm_prio_tc_info_update(hdev, prio_tc);
+       if (ret)
+               return ret;
+
+       ret = hclge_tm_init_hw(hdev);
+       if (ret)
+               return ret;
+
+       hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
+
+       if (tc > 1)
+               hdev->flag |= HCLGE_FLAG_MQPRIO_ENABLE;
+       else
+               hdev->flag &= ~HCLGE_FLAG_MQPRIO_ENABLE;
+
+       return 0;
+}
+
 static const struct hnae3_dcb_ops hns3_dcb_ops = {
        .ieee_getets    = hclge_ieee_getets,
        .ieee_setets    = hclge_ieee_setets,
@@ -284,6 +326,7 @@ static const struct hnae3_dcb_ops hns3_dcb_ops = {
        .getdcbx        = hclge_getdcbx,
        .setdcbx        = hclge_setdcbx,
        .map_update     = hclge_map_update,
+       .setup_tc       = hclge_setup_tc,
 };
 
 void hclge_dcb_ops_set(struct hclge_dev *hdev)
index a7c018c7b0eca66987cd9febe6b0941e90bb820d..bca4430bb7e7f1c5923dc03c72bf69c7599d6f37 100644 (file)
@@ -470,6 +470,7 @@ struct hclge_dev {
 #define HCLGE_FLAG_MAIN                0x00000004
 #define HCLGE_FLAG_DCB_CAPABLE 0x00000008
 #define HCLGE_FLAG_DCB_ENABLE  0x00000010
+#define HCLGE_FLAG_MQPRIO_ENABLE       0x00000020
        u32 flag;
 
        u32 pkt_buf_size; /* Total pf buf size for tx/rx */
index ba550c1b5b0135ae0b4d6816415cf6e15569f9f4..8fa4e658b27392c0c2cdd41ec35b45f92fc20356 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/sctp.h>
 #include <linux/vermagic.h>
 #include <net/gre.h>
+#include <net/pkt_cls.h>
 #include <net/vxlan.h>
 
 #include "hnae3.h"
@@ -1186,53 +1187,74 @@ static void hns3_nic_udp_tunnel_del(struct net_device *netdev,
        }
 }
 
-static int hns3_setup_tc(struct net_device *netdev, u8 tc)
+static int hns3_setup_tc(struct net_device *netdev, void *type_data)
 {
+       struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
        struct hnae3_handle *h = hns3_get_handle(netdev);
        struct hnae3_knic_private_info *kinfo = &h->kinfo;
+       u8 *prio_tc = mqprio_qopt->qopt.prio_tc_map;
+       u8 tc = mqprio_qopt->qopt.num_tc;
+       u16 mode = mqprio_qopt->mode;
+       u8 hw = mqprio_qopt->qopt.hw;
+       bool if_running;
        unsigned int i;
        int ret;
 
+       if (!((hw == TC_MQPRIO_HW_OFFLOAD_TCS &&
+              mode == TC_MQPRIO_MODE_CHANNEL) || (!hw && tc == 0)))
+               return -EOPNOTSUPP;
+
        if (tc > HNAE3_MAX_TC)
                return -EINVAL;
 
-       if (kinfo->num_tc == tc)
-               return 0;
-
        if (!netdev)
                return -EINVAL;
 
-       if (!tc) {
-               netdev_reset_tc(netdev);
-               return 0;
+       if_running = netif_running(netdev);
+       if (if_running) {
+               hns3_nic_net_stop(netdev);
+               msleep(100);
        }
 
-       /* Set num_tc for netdev */
-       ret = netdev_set_num_tc(netdev, tc);
+       ret = (kinfo->dcb_ops && kinfo->dcb_ops->setup_tc) ?
+               kinfo->dcb_ops->setup_tc(h, tc, prio_tc) : -EOPNOTSUPP;
        if (ret)
-               return ret;
+               goto out;
+
+       if (tc <= 1) {
+               netdev_reset_tc(netdev);
+       } else {
+               ret = netdev_set_num_tc(netdev, tc);
+               if (ret)
+                       goto out;
+
+               for (i = 0; i < HNAE3_MAX_TC; i++) {
+                       if (!kinfo->tc_info[i].enable)
+                               continue;
 
-       /* Set per TC queues for the VSI */
-       for (i = 0; i < HNAE3_MAX_TC; i++) {
-               if (kinfo->tc_info[i].enable)
                        netdev_set_tc_queue(netdev,
                                            kinfo->tc_info[i].tc,
                                            kinfo->tc_info[i].tqp_count,
                                            kinfo->tc_info[i].tqp_offset);
+               }
        }
 
-       return 0;
+       ret = hns3_nic_set_real_num_queue(netdev);
+
+out:
+       if (if_running)
+               hns3_nic_net_open(netdev);
+
+       return ret;
 }
 
 static int hns3_nic_setup_tc(struct net_device *dev, enum tc_setup_type type,
                             void *type_data)
 {
-       struct tc_mqprio_qopt *mqprio = type_data;
-
        if (type != TC_SETUP_MQPRIO)
                return -EOPNOTSUPP;
 
-       return hns3_setup_tc(dev, mqprio->num_tc);
+       return hns3_setup_tc(dev, type_data);
 }
 
 static int hns3_vlan_rx_add_vid(struct net_device *netdev,