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: Yunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Yunsheng Lin 2017-10-17 14:51:30 +08:00 коммит произвёл David S. Miller
Родитель 56fd2b2ca4
Коммит 30d240dfa2
4 изменённых файлов: 86 добавлений и 19 удалений

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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)

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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 = (kinfo->dcb_ops && kinfo->dcb_ops->setup_tc) ?
kinfo->dcb_ops->setup_tc(h, tc, prio_tc) : -EOPNOTSUPP;
if (ret)
goto out;
if (tc <= 1) {
netdev_reset_tc(netdev);
} else {
ret = netdev_set_num_tc(netdev, tc);
if (ret)
return ret;
goto out;
/* Set per TC queues for the VSI */
for (i = 0; i < HNAE3_MAX_TC; i++) {
if (kinfo->tc_info[i].enable)
if (!kinfo->tc_info[i].enable)
continue;
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,