Commit 30d240df authored by Yunsheng Lin's avatar Yunsheng Lin Committed by David S. Miller

net: hns3: Add mqprio hardware offload support in hns3 driver

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: default avatarYunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 56fd2b2c
...@@ -381,6 +381,7 @@ struct hnae3_dcb_ops { ...@@ -381,6 +381,7 @@ struct hnae3_dcb_ops {
u8 (*setdcbx)(struct hnae3_handle *, u8); u8 (*setdcbx)(struct hnae3_handle *, u8);
int (*map_update)(struct hnae3_handle *); int (*map_update)(struct hnae3_handle *);
int (*setup_tc)(struct hnae3_handle *, u8, u8 *);
}; };
struct hnae3_ae_algo { struct hnae3_ae_algo {
......
...@@ -178,7 +178,8 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets) ...@@ -178,7 +178,8 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets)
u8 num_tc = 0; u8 num_tc = 0;
int ret; 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; return -EINVAL;
ret = hclge_ets_validate(hdev, ets, &num_tc, &map_changed); 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) ...@@ -228,7 +229,8 @@ static int hclge_ieee_setpfc(struct hnae3_handle *h, struct ieee_pfc *pfc)
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
u8 i, j, pfc_map, *prio_tc; 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; return -EINVAL;
prio_tc = hdev->tm_info.prio_tc; prio_tc = hdev->tm_info.prio_tc;
...@@ -257,6 +259,9 @@ static u8 hclge_getdcbx(struct hnae3_handle *h) ...@@ -257,6 +259,9 @@ static u8 hclge_getdcbx(struct hnae3_handle *h)
struct hclge_vport *vport = hclge_get_vport(h); struct hclge_vport *vport = hclge_get_vport(h);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
if (hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE)
return 0;
return hdev->dcbx_cap; return hdev->dcbx_cap;
} }
...@@ -276,6 +281,43 @@ static u8 hclge_setdcbx(struct hnae3_handle *h, u8 mode) ...@@ -276,6 +281,43 @@ static u8 hclge_setdcbx(struct hnae3_handle *h, u8 mode)
return 0; 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 = { static const struct hnae3_dcb_ops hns3_dcb_ops = {
.ieee_getets = hclge_ieee_getets, .ieee_getets = hclge_ieee_getets,
.ieee_setets = hclge_ieee_setets, .ieee_setets = hclge_ieee_setets,
...@@ -284,6 +326,7 @@ static const struct hnae3_dcb_ops hns3_dcb_ops = { ...@@ -284,6 +326,7 @@ static const struct hnae3_dcb_ops hns3_dcb_ops = {
.getdcbx = hclge_getdcbx, .getdcbx = hclge_getdcbx,
.setdcbx = hclge_setdcbx, .setdcbx = hclge_setdcbx,
.map_update = hclge_map_update, .map_update = hclge_map_update,
.setup_tc = hclge_setup_tc,
}; };
void hclge_dcb_ops_set(struct hclge_dev *hdev) void hclge_dcb_ops_set(struct hclge_dev *hdev)
......
...@@ -470,6 +470,7 @@ struct hclge_dev { ...@@ -470,6 +470,7 @@ struct hclge_dev {
#define HCLGE_FLAG_MAIN 0x00000004 #define HCLGE_FLAG_MAIN 0x00000004
#define HCLGE_FLAG_DCB_CAPABLE 0x00000008 #define HCLGE_FLAG_DCB_CAPABLE 0x00000008
#define HCLGE_FLAG_DCB_ENABLE 0x00000010 #define HCLGE_FLAG_DCB_ENABLE 0x00000010
#define HCLGE_FLAG_MQPRIO_ENABLE 0x00000020
u32 flag; u32 flag;
u32 pkt_buf_size; /* Total pf buf size for tx/rx */ u32 pkt_buf_size; /* Total pf buf size for tx/rx */
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/sctp.h> #include <linux/sctp.h>
#include <linux/vermagic.h> #include <linux/vermagic.h>
#include <net/gre.h> #include <net/gre.h>
#include <net/pkt_cls.h>
#include <net/vxlan.h> #include <net/vxlan.h>
#include "hnae3.h" #include "hnae3.h"
...@@ -1186,53 +1187,74 @@ static void hns3_nic_udp_tunnel_del(struct net_device *netdev, ...@@ -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_handle *h = hns3_get_handle(netdev);
struct hnae3_knic_private_info *kinfo = &h->kinfo; 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; unsigned int i;
int ret; int ret;
if (!((hw == TC_MQPRIO_HW_OFFLOAD_TCS &&
mode == TC_MQPRIO_MODE_CHANNEL) || (!hw && tc == 0)))
return -EOPNOTSUPP;
if (tc > HNAE3_MAX_TC) if (tc > HNAE3_MAX_TC)
return -EINVAL; return -EINVAL;
if (kinfo->num_tc == tc)
return 0;
if (!netdev) if (!netdev)
return -EINVAL; return -EINVAL;
if (!tc) { if_running = netif_running(netdev);
netdev_reset_tc(netdev); if (if_running) {
return 0; hns3_nic_net_stop(netdev);
msleep(100);
} }
/* Set num_tc for netdev */ ret = (kinfo->dcb_ops && kinfo->dcb_ops->setup_tc) ?
ret = netdev_set_num_tc(netdev, tc); kinfo->dcb_ops->setup_tc(h, tc, prio_tc) : -EOPNOTSUPP;
if (ret) 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, netdev_set_tc_queue(netdev,
kinfo->tc_info[i].tc, kinfo->tc_info[i].tc,
kinfo->tc_info[i].tqp_count, kinfo->tc_info[i].tqp_count,
kinfo->tc_info[i].tqp_offset); 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, static int hns3_nic_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data) void *type_data)
{ {
struct tc_mqprio_qopt *mqprio = type_data;
if (type != TC_SETUP_MQPRIO) if (type != TC_SETUP_MQPRIO)
return -EOPNOTSUPP; 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, static int hns3_vlan_rx_add_vid(struct net_device *netdev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment