提交 d0203361 编写于 作者: W Weiwei 提交者: Xie XiuQi

net: hns3: add hns3 cae drivers to kernel

driver inclusion
category: bugfix
bugzilla: NA
CVE: NA

add hns3 cae drivers to kernel.
Signed-off-by: NWeiwei <dengweiwei@huawei.com>
Reviewed-by: Ngaoxun <gaoxun3@huawei.com>
Reviewed-by: NShengzui You <youshengzui@huawei.com>
Reviewed-by: NZhaohui Zhong <zhongzhaohui@huawei.com>
Reviewed-by: NYongxin Li <liyongxin1@huawei.com>
Tested-by: Junxin Chen <chenjunxin1@huawei.com>i
Reviewed-by: NYunsheng Lin <linyunsheng@huawei.com>
Acked-by: NHanjun Guo <guohanjun@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 b4535f93
......@@ -123,6 +123,16 @@ config HNS3_ENET
family of SoCs. This module depends upon HNAE3 driver to access the HNAE3
devices and their associated operations.
config HNS3_CAE
tristate "Hisilicon HNS3 configuration & analysis & enhancement Support"
default m
depends on HNS3_HCLGE && HNS3_ENET
help
This selects the Configuration, Analysis and Enhancement Support for HNS3 Driver
(e.g. SFP management, self-adaptive port speed and DFX). It is supposed to
support upcoming User Mode Tool (i.e. hiarmtool) developed by Huawei.
This module depends upon HNS3_HCLGE and HNS3 driver.
endif #HNS3
endif # NET_VENDOR_HISILICON
......@@ -2,14 +2,85 @@
#
# Makefile for the HISILICON network device drivers.
#
ccflags-y += -I$(srctree)/$(src)
obj-$(CONFIG_HNS3) += hns3pf/
obj-$(CONFIG_HNS3) += hns3vf/
# Add security options
ccflags-y += -fstack-protector-strong
ccflags-y += -Wl,-z,relro,-z,now
ccflags-y += -Wl,-z,noexecstack
ccflags-y += -D_FORTIFY_SOURCE=2 -O2
ccflags-y += -fvisibility=hidden
ccflags-y += -Wformat=2 -Wfloat-equal
ccflags-y += -fsigned-char
ccflags-y += -DCONFIG_IT_VALIDATION
ccflags-y += -DCONFIG_HNS3_TEST
ccflags-y += -DCONFIG_EXT_TEST
PWD = $(srctree)/drivers/net/ethernet/hisilicon/hns3
#add include path
ccflags-y += -I$(PWD) \
-I$(PWD)/hns3pf \
-I$(PWD)/hns-customer \
-I$(PWD)/hns-customer/hns3pf \
-I$(PWD)/hns3vf \
-I$(PWD)/hns3_cae
obj-$(CONFIG_HNS3_HCLGE) += hclge.o
hclge-objs = hns3pf/hclge_main.o \
hns3pf/hclge_cmd.o \
hns3pf/hclge_mdio.o \
hns3pf/hclge_debugfs.o \
hns3pf/hclge_tm.o \
hns3pf/hclge_mbx.o \
hns3pf/hclge_err.o
hclge-objs += hns-customer/hns3pf/hclge_main_it.o \
hns-customer/hns3pf/hclge_cmd_it.o \
hns-customer/hns3pf/hclge_ext.o \
hns-customer/hns3pf/hclge_test.o
hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o
#### compile hnae3.ko
obj-$(CONFIG_HNS3) += hnae3.o
obj-$(CONFIG_HNS3_ENET) += hns3.o
hns3-objs = hns3_enet.o hns3_ethtool.o hns3_debugfs.o
hns3-objs += hns-customer/hns3_enet_it.o hns-customer/hns3_ext.o
hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o
#### compile hclgevf.ko
obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o
hclgevf-objs := hns3vf/hclgevf_main.o hns3vf/hclgevf_cmd.o hns3vf/hclgevf_mbx.o
#### compile hns3_cae.ko
#add rally code
HNS3_CAE_OBJS_PRIM = hns3_cae/hns3_cae_init.o \
hns3_cae/hns3_nictool.o \
hns3_cae/hns3_priv_common_test.o \
hns3_cae/hns3_priv_dcb.o \
hns3_cae/hns3_priv_lamp.o \
hns3_cae/hns3_priv_mactbl.o \
hns3_cae/hns3_priv_m7_cmd.o
#add test code
HNS3_CAE_OBJS_EXT = hns3_cae/hns3_priv_dfx.o \
hns3_cae/hns3_priv_ext.o \
hns3_cae/hns3_priv_fd.o \
hns3_cae/hns3_priv_hilink_param.o \
hns3_cae/hns3_priv_irq.o \
hns3_cae/hns3_priv_mac.o \
hns3_cae/hns3_priv_phy.o \
hns3_cae/hns3_priv_pkt.o \
hns3_cae/hns3_priv_port.o \
hns3_cae/hns3_priv_promisc.o \
hns3_cae/hns3_priv_qinfo.o \
hns3_cae/hns3_priv_qos.o \
hns3_cae/hns3_priv_qres.o \
hns3_cae/hns3_priv_rss.o \
hns3_cae/hns3_priv_stat.o \
hns3_cae/hns3_priv_tm.o \
hns3_cae/hns3_priv_vlan.o \
hns3_cae/hns3_priv_xsfp.o
obj-$(CONFIG_HNS3_CAE) += hns3_cae.o
hns3_cae-objs := $(HNS3_CAE_OBJS_PRIM) $(HNS3_CAE_OBJS_EXT)
......@@ -8,75 +8,22 @@
#include <linux/module.h>
#include <linux/pci.h>
#include "../hnae3.h"
#include "hnae3.h"
#include "hns3_enet_it.h"
#include "hns3pf/hclge_main_it.h"
#include "../hns3_enet.h"
#include "hns3_enet.h"
extern const char hns3_driver_string[];
extern const char hns3_copyright[];
#ifdef CONFIG_IT_VALIDATION
#define HNAE_DRIVER_VERSION "B075"
#define HNAE_DRIVER_VERSION_MAX_LEN 8
#define HNAE_DRIVER_VERSION "1.8.10.0"
#ifdef CONFIG_HNS3_X86
#define HNAE3_DEV_ID_X86_25_GE 0xA125
#endif
extern struct ethtool_ops hns3vf_ethtool_ops;
extern struct ethtool_ops hns3_ethtool_ops;
extern struct net_device_ops hns3_nic_netdev_ops;
extern const struct hnae3_client_ops client_ops;
extern struct hnae3_client client;
extern struct pci_driver hns3_driver;
extern const char hns3_driver_name[];
extern struct pci_error_handlers hns3_err_handler;
extern int hns3_set_link_ksettings_it(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd);
/* hns3_pci_tbl - PCI Device ID Table
*
* Last entry must be all 0s
*
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
const struct pci_device_id hns3_pci_tbl_it[] = {
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_GE), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA),
HNAE3_DEV_SUPPORT_ROCE_DCB_BITS},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA_MACSEC),
HNAE3_DEV_SUPPORT_ROCE_DCB_BITS},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA),
HNAE3_DEV_SUPPORT_ROCE_DCB_BITS},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA_MACSEC),
HNAE3_DEV_SUPPORT_ROCE_DCB_BITS},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC),
HNAE3_DEV_SUPPORT_ROCE_DCB_BITS},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_VF), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_DCB_PFC_VF),
HNAE3_DEV_SUPPORT_ROCE_DCB_BITS},
#ifdef CONFIG_HNS3_X86
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_X86_25_GE), 0},
#endif
/* required last entry */
{0, }
};
MODULE_DEVICE_TABLE(pci, hns3_pci_tbl_it);
#ifdef CONFIG_EXT_TEST
void hns3_nic_net_timeout_it(struct net_device *ndev)
{
if (!hns3_get_tx_timeo_queue_info(ndev))
return;
nic_call_event(ndev, HNAE3_FUNC_RESET_CUSTOM);
}
#endif
int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
......@@ -84,7 +31,6 @@ int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd)
case (SIOCDEVPRIVATE + 4):
if (hns3_ioctl)
return hns3_ioctl(netdev, ifr->ifr_data);
pr_err("open nic_test failed");
return -EINVAL;
default:
return -EINVAL;
......@@ -93,8 +39,7 @@ int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd)
#if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE)
u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb,
void *accel_priv,
select_queue_fallback_t fallback)
void *accel_priv, select_queue_fallback_t fallback)
#else
u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb,
struct net_device *accel_priv,
......@@ -115,25 +60,15 @@ u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb,
static int __init hns3_init_module_it(void)
{
struct ethtool_ops *loc_ethtool_ops;
struct net_device_ops *ndev_ops;
int ret;
#ifdef CONFIG_EXT_TEST
struct pci_error_handlers *err_handlers;
err_handlers = (struct pci_error_handlers *)&hns3_err_handler;
err_handlers->slot_reset = NULL;
#endif
pr_info("%s: %s - version\n", hns3_driver_name, hns3_driver_string);
pr_info("%s: %s\n", hns3_driver_name, hns3_copyright);
strncpy(hns3_driver_version, HNAE_DRIVER_VERSION,
HNAE_DRIVER_VERSION_MAX_LEN);
sizeof(HNAE_DRIVER_VERSION));
loc_ethtool_ops = (struct ethtool_ops *)&hns3_ethtool_ops;
loc_ethtool_ops->set_link_ksettings = hns3_set_link_ksettings_it;
client.type = HNAE3_CLIENT_KNIC;
snprintf(client.name, HNAE3_CLIENT_NAME_LENGTH - 1, "%s",
hns3_driver_name);
......@@ -141,9 +76,6 @@ static int __init hns3_init_module_it(void)
client.ops = &client_ops;
ndev_ops = (struct net_device_ops *)&hns3_nic_netdev_ops;
ndev_ops->ndo_do_ioctl = hns3_nic_do_ioctl_it;
#ifdef CONFIG_EXT_TEST
ndev_ops->ndo_tx_timeout = hns3_nic_net_timeout_it;
#endif
ndev_ops->ndo_select_queue = hns3_nic_select_queue_it;
INIT_LIST_HEAD(&client.node);
......@@ -153,7 +85,6 @@ static int __init hns3_init_module_it(void)
if (ret)
goto err_reg_client;
hns3_driver.id_table = hns3_pci_tbl_it;
ret = pci_register_driver(&hns3_driver);
if (ret)
goto err_reg_driver;
......@@ -166,5 +97,6 @@ static int __init hns3_init_module_it(void)
hns3_dbg_unregister_debugfs();
return ret;
}
module_init(hns3_init_module_it);
#endif
......@@ -7,8 +7,6 @@
typedef int (*hns3_priv_func)(struct net_device *, void *);
hns3_priv_func hns3_ioctl;
#define VERSION_NUMBER "$FULL_VERSION"
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#else
......
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/etherdevice.h>
#include <linux/string.h>
#include <linux/phy.h>
#include "../hns3_enet.h"
static int hns3_check_ksettings_para(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = priv->ae_handle;
u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN;
u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN;
u8 autoneg = 0;
u32 speed = 0;
u8 duplex = 0;
u32 check_flag;
/* Verify the settings we care about. */
if (cmd->base.autoneg != AUTONEG_ENABLE &&
cmd->base.autoneg != AUTONEG_DISABLE)
return -EINVAL;
if (h->ae_algo->ops->get_media_type)
h->ae_algo->ops->get_media_type(h, &media_type, &module_type);
if (h->ae_algo->ops->get_ksettings_an_result)
h->ae_algo->ops->get_ksettings_an_result(h, &autoneg, &speed,
&duplex);
if (cmd->base.autoneg == autoneg &&
cmd->base.speed == speed &&
cmd->base.duplex == duplex)
return 0;
if (media_type == HNAE3_MEDIA_TYPE_COPPER) {
check_flag = (cmd->base.speed != SPEED_10 &&
cmd->base.speed != SPEED_100 &&
cmd->base.speed != SPEED_1000);
if (check_flag)
return -EINVAL;
} else {
check_flag = (cmd->base.speed != SPEED_1000 &&
cmd->base.speed != SPEED_10000 &&
cmd->base.speed != SPEED_25000 &&
cmd->base.speed != SPEED_40000 &&
cmd->base.speed != SPEED_50000 &&
cmd->base.speed != SPEED_100000);
if (check_flag)
return -EINVAL;
}
check_flag = (cmd->base.duplex != DUPLEX_HALF &&
cmd->base.duplex != DUPLEX_FULL);
if (check_flag)
return -EINVAL;
return 0;
}
int hns3_set_link_ksettings_it(struct net_device *netdev,
const struct ethtool_link_ksettings *cmd)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = priv->ae_handle;
int ret = 0;
if (!h->ae_algo || !h->ae_algo->ops)
return -ESRCH;
ret = hns3_check_ksettings_para(netdev, cmd);
if (ret)
return ret;
netdev_info(netdev, "set link setting autoneg = %d, speed = %d, duplex = %d\n",
cmd->base.autoneg, cmd->base.speed, cmd->base.duplex);
if (netdev->phydev)
return phy_ethtool_ksettings_set(netdev->phydev, cmd);
if (h->ae_algo->ops->set_autoneg)
h->ae_algo->ops->set_autoneg(h, cmd->base.autoneg);
if (h->ae_algo->ops->cfg_mac_speed_dup_h)
h->ae_algo->ops->cfg_mac_speed_dup_h(h,
cmd->base.speed, cmd->base.duplex);
return 0;
}
EXPORT_SYMBOL(hns3_set_link_ksettings_it);
......@@ -38,21 +38,28 @@ int nic_netdev_match_check(struct net_device *netdev)
EXPORT_SYMBOL(nic_netdev_match_check);
void nic_chip_recover_handler(struct net_device *netdev,
enum hnae3_reset_type_custom event_t)
enum hnae3_event_type_custom event_t)
{
struct hnae3_ae_dev *ae_dev;
struct hns3_nic_priv *priv;
struct hnae3_handle *h;
if (nic_netdev_match_check(netdev))
return;
priv = netdev_priv(netdev);
h = priv->ae_handle;
ae_dev = pci_get_drvdata(h->pdev);
dev_info(&netdev->dev, "reset type is %d!!\n", event_t);
if (event_t == HNAE3_PPU_POISON_CUSTOM)
event_t = HNAE3_FUNC_RESET_CUSTOM;
if (event_t != HNAE3_FUNC_RESET_CUSTOM &&
event_t != HNAE3_GLOBAL_RESET_CUSTOM &&
event_t != HNAE3_IMP_RESET_CUSTOM) {
dev_err(&netdev->dev, "reset type err!!\n");
return;
}
if (ae_dev->ops->reset_event)
ae_dev->ops->reset_event(h->pdev, NULL);
h = hns3_get_handle(netdev);
if (h->ae_algo->ops->priv_ops)
h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_RESET, &event_t, 0);
}
EXPORT_SYMBOL(nic_chip_recover_handler);
......@@ -70,7 +77,10 @@ int nic_clean_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats)
priv = netdev_priv(ndev);
h = hns3_get_handle(ndev);
kinfo = &h->kinfo;
hclge_clean_stats64(h);
if (h->ae_algo->ops->priv_ops)
h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_CLEAN_STATS64, stats,
0);
for (i = 0; i < kinfo->num_tqps; i++) {
ring = priv->ring_data[i].ring;
......@@ -95,66 +105,96 @@ int nic_get_chipid(struct net_device *ndev, u32 *chip_id)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_get_chipid(h, chip_id);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_CHIPID,
chip_id, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_chipid);
int nic_get_sfpinfo(struct net_device *ndev, u8 *buff, u16 size, u16 *outlen)
int nic_get_mac_id(struct net_device *ndev, u32 *mac_id)
{
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
if (!buff || !outlen)
if (!mac_id)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_get_sfpinfo(h, buff, 0, size, outlen);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_MAC_ID,
mac_id, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_sfpinfo);
EXPORT_SYMBOL(nic_get_mac_id);
int nic_get_sfp_present(struct net_device *ndev, u32 *present)
int nic_get_sfpinfo(struct net_device *ndev, u8 *buff, u16 size, u16 *outlen)
{
struct hns3_sfp_info_para para;
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
if (!present)
if (!buff || !outlen)
return -EINVAL;
para.buff = buff;
para.outlen = outlen;
para.offset = 0;
para.size = size;
h = hns3_get_handle(ndev);
return hclge_get_sfp_present(h, present);
if (h->ae_algo->ops->priv_ops) {
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_SFPINFO,
&para, 0);
} else {
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL(nic_get_sfp_present);
EXPORT_SYMBOL(nic_get_sfpinfo);
int nic_set_sfp_state(struct net_device *ndev, bool en)
int nic_get_sfp_present(struct net_device *ndev, int *present)
{
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
if (!present)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_set_sfp_state(h, en);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_PRESENT,
present, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_set_sfp_state);
EXPORT_SYMBOL(nic_get_sfp_present);
int nic_get_sfp_speed(struct net_device *ndev, u32 *speed)
int nic_set_sfp_state(struct net_device *ndev, bool en)
{
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
if (!speed)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_ext_get_sfp_speed(h, speed);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_SET_SFP_STATE,
&en, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_sfp_speed);
EXPORT_SYMBOL(nic_set_sfp_state);
int nic_get_chip_num(struct net_device *ndev, u32 *chip_num)
{
......@@ -167,7 +207,11 @@ int nic_get_chip_num(struct net_device *ndev, u32 *chip_num)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_get_chip_num(h, chip_num);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_CHIP_NUM,
chip_num, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_chip_num);
......@@ -182,19 +226,30 @@ int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_get_port_num(h, port_num);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_PORT_NUM,
port_num, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_port_num_per_chip);
int nic_set_led(struct net_device *ndev, int type, int status)
{
struct hns3_led_state_para para;
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
para.status = status;
para.type = type;
h = hns3_get_handle(ndev);
return hclge_set_led(h, type, status);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_SET_LED, &para,
0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_set_led);
......@@ -209,7 +264,11 @@ int nic_get_led_signal(struct net_device *ndev, struct hns3_lamp_signal *signal)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_get_led_signal(h, signal);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_LED_SIGNAL,
signal, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_led_signal);
......@@ -221,7 +280,11 @@ int nic_disable_net_lane(struct net_device *ndev)
return -ENODEV;
h = hns3_get_handle(ndev);
return hclge_disable_net_lane(h);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_DISABLE_LANE,
NULL, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_disable_net_lane);
......@@ -236,7 +299,12 @@ int nic_get_net_lane_status(struct net_device *ndev, u32 *status)
return -EINVAL;
h = hns3_get_handle(ndev);
return hclge_get_net_lane_status(h, status);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h,
HNS3_EXT_OPC_GET_LANE_STATUS,
status, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_net_lane_status);
......@@ -250,7 +318,11 @@ int nic_set_mac_state(struct net_device *ndev, int enable)
h = hns3_get_handle(ndev);
en = !!enable;
return hclge_set_mac_state(h, en);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_SET_MAC_STATE,
&en, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_set_mac_state);
......@@ -271,7 +343,8 @@ int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask)
priv = netdev_priv(netdev);
if (test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) {
dev_err(&netdev->dev, "ethernet is down, not support cpu affinity set\n");
dev_err(&netdev->dev,
"ethernet is down, not support cpu affinity set\n");
return -EOPNOTSUPP;
}
......@@ -284,16 +357,16 @@ int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask)
ret = irq_set_affinity_hint(tqp_vector->vector_irq, NULL);
if (ret) {
dev_err(&netdev->dev, "reset affinity hint fail, ret = %d\n",
ret);
dev_err(&netdev->dev,
"reset affinity hint fail, ret = %d\n", ret);
return ret;
}
ret = irq_set_affinity_hint(tqp_vector->vector_irq,
&tqp_vector->affinity_mask);
if (ret) {
dev_err(&netdev->dev, "set affinity hint fail, ret = %d\n",
ret);
dev_err(&netdev->dev,
"set affinity hint fail, ret = %d\n", ret);
return ret;
}
}
......@@ -308,12 +381,151 @@ EXPORT_SYMBOL(nic_set_cpu_affinity);
int nic_disable_clock(struct net_device *ndev)
{
struct hnae3_handle *h;
u32 en;
if (nic_netdev_match_check(ndev))
return -ENODEV;
en = 0;
h = hns3_get_handle(ndev);
return hclge_config_nic_clock(h, 0);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_CONFIG_CLOCK,
&en, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_disable_clock);
int nic_set_pfc_storm_para(struct net_device *ndev, int dir, int enable,
int period_ms, int times, int recovery_period_ms)
{
struct hns3_pfc_storm_para para;
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
para.dir = dir;
para.enable = enable;
para.period_ms = period_ms;
para.times = times;
para.recovery_period_ms = recovery_period_ms;
h = hns3_get_handle(ndev);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h,
HNS3_EXT_OPC_SET_PFC_STORM_PARA,
&para, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_set_pfc_storm_para);
int nic_get_pfc_storm_para(struct net_device *ndev, int dir, int *enable,
int *period_ms, int *times, int *recovery_period_ms)
{
struct hns3_pfc_storm_para para;
struct hnae3_handle *h;
int ret;
if (nic_netdev_match_check(ndev))
return -ENODEV;
if (!enable || !period_ms || !times || !recovery_period_ms) {
pr_err("get pfc storm para failed because invalid input param.\n");
return -EINVAL;
}
h = hns3_get_handle(ndev);
if (h->ae_algo->ops->priv_ops) {
para.dir = dir;
ret = h->ae_algo->ops->priv_ops(h,
HNS3_EXT_OPC_GET_PFC_STORM_PARA,
&para, 0);
if (!ret) {
*enable = para.enable;
*period_ms = para.period_ms;
*times = para.times;
*recovery_period_ms = para.recovery_period_ms;
return 0;
} else {
return ret;
}
} else {
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL(nic_get_pfc_storm_para);
int nic_get_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 *data)
{
struct hns3_phy_para para;
struct hnae3_handle *h;
int ret;
if (nic_netdev_match_check(ndev))
return -ENODEV;
para.page_select_addr = page_select_addr;
para.page = page;
para.reg_addr = reg_addr;
h = hns3_get_handle(ndev);
if (h->ae_algo->ops->priv_ops) {
ret = h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_PHY_REG,
&para, 0);
if (!ret) {
*data = para.data;
return 0;
} else {
return ret;
}
} else {
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL(nic_get_phy_reg);
int nic_set_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 data)
{
struct hns3_phy_para para;
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
para.page_select_addr = page_select_addr;
para.page = page;
para.reg_addr = reg_addr;
para.data = data;
h = hns3_get_handle(ndev);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_SET_PHY_REG,
&para, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_set_phy_reg);
int nic_get_hilink_ref_los(struct net_device *ndev, u32 *status)
{
struct hnae3_handle *h;
if (nic_netdev_match_check(ndev))
return -ENODEV;
if (!status)
return -EINVAL;
h = hns3_get_handle(ndev);
if (h->ae_algo->ops->priv_ops)
return h->ae_algo->ops->priv_ops(h,
HNS3_EXT_OPC_GET_HILINK_REF_LOS,
status, 0);
else
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(nic_get_hilink_ref_los);
......@@ -4,32 +4,91 @@
#ifndef __HNS3_EXT_H
#define __HNS3_EXT_H
#include <linux/types.h>
#include "../hns3_enet.h"
#include "hns3pf/hclge_ext.h"
#include "hns3pf/hclge_main_it.h"
/**
* nic_chip_recover_handler - reset net device by port id
* @netdev: net device
* @hnae3_reset_type: nic device event type
*/
void nic_chip_recover_handler(struct net_device *netdev,
enum hnae3_reset_type_custom event_t);
#include "hns3_enet.h"
#include "hnae3.h"
#include "hclge_main_it.h"
enum hns3_ext_op_code {
HNS3_EXT_OPC_CLEAN_STATS64 = 0,
HNS3_EXT_OPC_GET_CHIPID,
HNS3_EXT_OPC_GET_SFPINFO,
HNS3_EXT_OPC_SET_SFP_STATE,
HNS3_EXT_OPC_GET_CHIP_NUM,
HNS3_EXT_OPC_GET_PORT_NUM,
HNS3_EXT_OPC_SET_LED,
HNS3_EXT_OPC_GET_PRESENT,
HNS3_EXT_OPC_DISABLE_LANE,
HNS3_EXT_OPC_GET_LANE_STATUS,
HNS3_EXT_OPC_GET_LED_SIGNAL,
HNS3_EXT_OPC_SET_MAC_STATE,
HNS3_EXT_OPC_CONFIG_CLOCK,
HNS3_EXT_OPC_GET_PFC_STORM_PARA,
HNS3_EXT_OPC_SET_PFC_STORM_PARA,
HNS3_EXT_OPC_GET_PHY_REG,
HNS3_EXT_OPC_SET_PHY_REG,
HNS3_EXT_OPC_GET_MAC_ID,
HNS3_EXT_OPC_OPT_MAC_TABLE,
HNS3_EXT_OPC_RESET,
HNS3_EXT_OPC_GET_HILINK_REF_LOS,
};
struct hns3_sfp_info_para {
u8 *buff;
u16 offset;
u16 size;
u16 *outlen;
};
struct hns3_led_state_para {
u32 type;
u32 status;
};
struct hns3_pfc_storm_para {
u32 dir;
u32 enable;
u32 period_ms;
u32 times;
u32 recovery_period_ms;
};
struct hns3_phy_para {
u32 page_select_addr;
u32 reg_addr;
u16 page;
u16 data;
};
struct hns3_lamp_signal {
u8 error;
u8 locate;
u8 activity;
};
int nic_get_chipid(struct net_device *ndev, u32 *chip_id);
int nic_netdev_match_check(struct net_device *netdev);
int nic_get_sfpinfo(struct net_device *ndev, u8 *buff, u16 size, u16 *outlen);
int nic_get_sfp_present(struct net_device *ndev, int *present);
int nic_set_sfp_state(struct net_device *ndev, bool en);
int nic_clean_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats);
int nic_get_sfpinfo(struct net_device *netdev, u8 *buff, u16 size, u16 *outlen);
int nic_set_sfp_state(struct net_device *netdev, bool en);
int nic_get_sfp_id(struct net_device *netdev, u32 *sfp_id);
int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num);
int nic_get_chip_num(struct net_device *ndev, u32 *chip_num);
int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num);
int nic_set_led(struct net_device *ndev, int type, int status);
int nic_disable_net_lane(struct net_device *ndev);
int nic_get_net_lane_status(struct net_device *ndev, u32 *status);
int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask);
int nic_get_led_signal(struct net_device *ndev,
struct hns3_lamp_signal *signal);
int nic_set_mac_state(struct net_device *ndev, int enable);
int nic_disable_clock(struct net_device *ndev);
int nic_set_pfc_storm_para(struct net_device *ndev, int dir, int enable,
int period_ms, int times, int recovery_period_ms);
int nic_get_pfc_storm_para(struct net_device *ndev, int dir, int *enable,
int *period_ms, int *times, int *recovery_period_ms);
int nic_get_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 *data);
int nic_set_phy_reg(struct net_device *ndev, u32 page_select_addr,
u16 page, u32 reg_addr, u16 data);
int nic_get_mac_id(struct net_device *ndev, u32 *mac_id);
int nic_get_hilink_ref_los(struct net_device *ndev, u32 *status);
#endif
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "../../hns3pf/hclge_cmd.h"
#include "../../hnae3.h"
#include "../../hns3pf/hclge_main.h"
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#ifdef CONFIG_HNS3_TEST
#include "hclge_test.h"
......@@ -12,4 +12,3 @@ EXPORT_SYMBOL(hclge_cmd_reuse_desc);
EXPORT_SYMBOL(hclge_cmd_setup_basic_desc);
EXPORT_SYMBOL(hclge_cmd_send);
#endif
......@@ -15,12 +15,16 @@
#include <net/gre.h>
#include <net/pkt_cls.h>
#include <net/vxlan.h>
#include "../../hns3pf/hclge_main.h"
#include "../../hnae3.h"
#include "../../hns3pf/hclge_cmd.h"
#include "hclge_main.h"
#include "hnae3.h"
#include "hclge_cmd.h"
#include "hclge_ext.h"
void hclge_clean_stats64(struct hnae3_handle *handle)
#define BD0_DATA_LEN 20
#define BD1_DATA_LEN 24
int hclge_clean_stats64(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hnae3_knic_private_info *kinfo;
struct hclge_vport *vport;
......@@ -37,17 +41,20 @@ void hclge_clean_stats64(struct hnae3_handle *handle)
memset(&tqp->tqp_stats, 0, sizeof(struct hlcge_tqp_stats));
}
memset(&hdev->hw_stats.mac_stats, 0, sizeof(struct hclge_mac_stats));
return 0;
}
EXPORT_SYMBOL(hclge_clean_stats64);
int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id)
int hclge_get_chipid(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_chip_id_cmd *resp = NULL;
struct hclge_desc desc;
u32 *chip_id;
int ret;
chip_id = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHIP_ID_GET, true);
resp = (struct hclge_chip_id_cmd *)(desc.data);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
......@@ -58,34 +65,27 @@ int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id)
*chip_id = resp->chip_id;
return 0;
}
EXPORT_SYMBOL(hclge_get_chipid);
int hclge_get_commit_id(struct hnae3_handle *handle, u8 *commit_id,
u32 *ncl_version)
int hclge_get_mac_id(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_commit_id_cmd *resp = NULL;
struct hclge_desc desc;
int ret, i;
u32 *mac_id;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_COMMIT_ID_GET, true);
resp = (struct hclge_commit_id_cmd *)(desc.data);
mac_id = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHIP_ID_GET, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "get commit id failed %d\n", ret);
dev_err(&hdev->pdev->dev, "get mac id failed, ret = %d\n", ret);
return ret;
}
for (i = 0; i < 8; i++)
commit_id[i] = resp->commit_id[i];
commit_id[8] = '\0';
*ncl_version = resp->ncl_version;
*mac_id = desc.data[1];
return 0;
}
EXPORT_SYMBOL(hclge_get_commit_id);
static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
u16 offset, u16 size, u16 *outlen)
......@@ -95,8 +95,13 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
struct hclge_dev *hdev = vport->back;
struct hclge_sfp_info *resp = NULL;
int ret;
int i;
int j;
u32 i;
u32 j;
u32 temp_len;
u32 data_len;
u8 *temp_data;
memset(desc, 0x0, sizeof(desc));
for (i = 0; i < HCLGE_SFP_INFO_LEN; i++) {
hclge_cmd_setup_basic_desc(&desc[i],
......@@ -112,8 +117,7 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_SFP_INFO_LEN);
if (ret) {
dev_err(&hdev->pdev->dev,
"get spf information cmd failed %d\n",
ret);
"get spf information cmd failed %d\n", ret);
return ret;
}
......@@ -121,51 +125,60 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
resp = (struct hclge_sfp_info *)desc[i].data;
if (i == 0) {
*outlen = (resp[i].sfpinfo[0] >> 16) & 0xFFFF;
for (j = 1; j < 6; j++) {
*(u32 *)buff = resp->sfpinfo[j];
buff = buff + sizeof(u32);
}
temp_len = *outlen;
data_len =
(temp_len > BD0_DATA_LEN) ? BD0_DATA_LEN : temp_len;
temp_data = (u8 *)&resp->sfpinfo[1];
} else {
for (j = 0; j < 6; j++) {
*(u32 *)buff = resp->sfpinfo[j];
buff = buff + sizeof(u32);
}
data_len =
(temp_len > BD1_DATA_LEN) ? BD1_DATA_LEN : temp_len;
temp_data = (u8 *)&resp->sfpinfo[0];
}
for (j = 0; j < data_len; j++)
*buff++ = *temp_data++;
temp_len -= data_len;
if (temp_len == 0)
break;
}
return 0;
}
int hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, u16 offset,
u16 size, u16 *outlen)
int hclge_get_sfpinfo(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_sfp_info_para *para;
u16 tmp_size;
u8 *tmp_buff;
u16 tmp_outlen;
int ret;
para = (struct hclge_sfp_info_para *)data;
tmp_buff = para->buff;
tmp_buff = buff;
while (size) {
while (para->size) {
WARN_ON_ONCE(!tmp_buff);
if (size > HCLGE_SFP_INFO_SIZE)
if (para->size > HCLGE_SFP_INFO_SIZE)
tmp_size = HCLGE_SFP_INFO_SIZE;
else
tmp_size = size;
ret = _hclge_get_sfpinfo(handle, tmp_buff, offset, tmp_size,
&tmp_outlen);
tmp_size = para->size;
ret = _hclge_get_sfpinfo(handle, tmp_buff, para->offset,
tmp_size, &tmp_outlen);
if (ret)
return ret;
offset += tmp_size;
size -= tmp_size;
para->offset += tmp_size;
para->size -= tmp_size;
tmp_buff += tmp_size;
*outlen += tmp_outlen;
*para->outlen += tmp_outlen;
if (tmp_size != tmp_outlen)
break;
}
return 0;
}
EXPORT_SYMBOL(hclge_get_sfpinfo);
int hclge_set_sfp_state(struct hnae3_handle *handle, bool en)
int hclge_set_sfp_state(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_sfp_enable_cmd *req = NULL;
......@@ -175,7 +188,7 @@ int hclge_set_sfp_state(struct hnae3_handle *handle, bool en)
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_SET_STATUS, false);
req = (struct hclge_sfp_enable_cmd *)desc.data;
req->set_sfp_enable_flag = en;
req->set_sfp_enable_flag = *(bool *)data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
......@@ -184,12 +197,13 @@ int hclge_set_sfp_state(struct hnae3_handle *handle, bool en)
return ret;
}
EXPORT_SYMBOL(hclge_set_sfp_state);
int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num)
int hclge_get_chip_num(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
u32 *chip_num = (u32 *)data;
struct hclge_desc desc;
int ret;
......@@ -202,40 +216,17 @@ int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num)
*chip_num = desc.data[0];
return 0;
}
EXPORT_SYMBOL(hclge_get_chip_num);
int hclge_ext_get_sfp_speed(struct hnae3_handle *handle, u32 *speed)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
int ret = 0;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_INFO, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret == -EOPNOTSUPP) {
dev_warn(&hdev->pdev->dev,
"IMP do not support get SFP speed %d\n", ret);
return ret;
} else if (ret) {
dev_err(&hdev->pdev->dev, "get sfp speed failed %d\n", ret);
return ret;
}
*speed = desc.data[0];
return 0;
}
EXPORT_SYMBOL(hclge_ext_get_sfp_speed);
int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num)
int hclge_get_port_num(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
u32 *port_num;
int ret;
port_num = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_PORT_NUM, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
......@@ -245,18 +236,20 @@ int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num)
*port_num = desc.data[0];
return 0;
}
EXPORT_SYMBOL(hclge_get_port_num);
int hclge_set_led(struct hnae3_handle *handle, u32 type, u32 status)
int hclge_set_led(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_led_state *para;
struct hclge_desc desc;
int ret;
para = (struct hclge_led_state *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, false);
desc.data[0] = type;
desc.data[1] = status;
desc.data[0] = para->type;
desc.data[1] = para->status;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "get set led failed %d\n", ret);
......@@ -265,16 +258,17 @@ int hclge_set_led(struct hnae3_handle *handle, u32 type, u32 status)
return 0;
}
EXPORT_SYMBOL(hclge_set_led);
int hclge_get_led_signal(struct hnae3_handle *handle,
struct hns3_lamp_signal *signal)
int hclge_get_led_signal(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_lamp_signal *signal;
struct hclge_desc desc;
int ret;
signal = (struct hclge_lamp_signal *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
......@@ -289,16 +283,18 @@ int hclge_get_led_signal(struct hnae3_handle *handle,
return 0;
}
EXPORT_SYMBOL(hclge_get_led_signal);
int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present)
int hclge_get_sfp_present(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_sfp_present_cmd *resp = NULL;
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
u32 *present;
int ret = 0;
present = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_GET_PRESENT, true);
resp = (struct hclge_sfp_present_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
......@@ -310,9 +306,9 @@ int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present)
*present = resp->sfp_present;
return 0;
}
EXPORT_SYMBOL(hclge_get_sfp_present);
int hclge_disable_net_lane(struct hnae3_handle *handle)
int hclge_disable_net_lane(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
......@@ -328,15 +324,17 @@ int hclge_disable_net_lane(struct hnae3_handle *handle)
}
return 0;
}
EXPORT_SYMBOL(hclge_disable_net_lane);
int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status)
int hclge_get_net_lane_status(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
u32 *status;
int ret = 0;
status = (u32 *)data;
desc.data[0] = 0;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DISABLE_NET_LANE, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
......@@ -347,18 +345,34 @@ int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status)
*status = desc.data[0];
return 0;
}
EXPORT_SYMBOL(hclge_get_net_lane_status);
int hclge_set_mac_state(struct hnae3_handle *handle, bool enable)
void hclge_set_phy_state(struct hnae3_handle *handle, bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct phy_device *phydev = hdev->hw.mac.phydev;
if (!phydev)
return;
if (enable)
phy_start(phydev);
else
phy_stop(phydev);
}
int hclge_set_mac_state(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_config_mac_mode_cmd *req;
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
struct hclge_config_mac_mode_cmd *req =
(struct hclge_config_mac_mode_cmd *)desc.data;
u32 loop_en = 0;
int ret = 0;
bool enable;
int ret;
enable = *(bool *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, false);
hnae3_set_bit(loop_en, HCLGE_MAC_TX_EN_B, enable);
hnae3_set_bit(loop_en, HCLGE_MAC_RX_EN_B, enable);
......@@ -374,21 +388,23 @@ int hclge_set_mac_state(struct hnae3_handle *handle, bool enable)
hnae3_set_bit(loop_en, HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B, enable);
hnae3_set_bit(loop_en, HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B, enable);
hnae3_set_bit(loop_en, HCLGE_MAC_TX_UNDER_MIN_ERR_B, enable);
req = (struct hclge_config_mac_mode_cmd *)desc.data;
req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
"set mac state %x fail, ret =%d.\n", enable, ret);
"set mac state %x fail, ret = %d.\n", enable, ret);
hclge_set_phy_state(handle, enable);
return ret;
}
EXPORT_SYMBOL(hclge_set_mac_state);
int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable)
int hclge_config_nic_clock(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
u32 nic_clock_en = enable;
u32 nic_clock_en = *(u32 *)data;
struct hclge_desc desc;
int ret = 0;
......@@ -402,4 +418,405 @@ int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable)
nic_clock_en, ret);
return ret;
}
EXPORT_SYMBOL(hclge_config_nic_clock);
int hclge_set_pfc_storm_para(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_pfc_storm_para *para;
struct hclge_desc desc;
int ret = 0;
para = (struct hclge_pfc_storm_para *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA,
false);
desc.data[0] = para->dir;
desc.data[1] = para->enable;
desc.data[2] = para->period_ms;
desc.data[3] = para->times;
desc.data[4] = para->recovery_period_ms;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "set pfc storm para failed %d\n",
ret);
return ret;
}
return 0;
}
int hclge_get_pfc_storm_para(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_pfc_storm_para *para;
struct hclge_desc desc;
int ret = 0;
para = (struct hclge_pfc_storm_para *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA, true);
desc.data[0] = para->dir;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "get pfc storm para failed %d\n",
ret);
return ret;
}
para->enable = desc.data[1];
para->period_ms = desc.data[2];
para->times = desc.data[3];
para->recovery_period_ms = desc.data[4];
return 0;
}
enum hclge_phy_op_code {
PHY_OP_READ,
PHY_OP_WRITE,
PHY_OP_MAX,
};
static int hclge_phy_need_page_select(struct hclge_dev *hdev,
enum hclge_phy_op_code opt_type,
struct hclge_phy_para *para,
u16 *cur_page)
{
struct hclge_mac *mac = &hdev->hw.mac;
struct mii_bus *mdio_bus = mac->mdio_bus;
u32 phyid = mac->phy_addr;
int ret;
/* no need to change page when page param is 0 */
if (opt_type != PHY_OP_READ || para->page != 0) {
ret = mdio_bus->read(mdio_bus, phyid, para->page_select_addr);
if (ret < 0) {
dev_err(&hdev->pdev->dev,
"record current phy %d reg page failed.\n",
phyid);
return ret;
}
*cur_page = ret;
if (para->page != *cur_page)
return 1;
else
return 0;
}
return 0;
}
static int hclge_check_phy_opt_pare(struct hclge_dev *hdev,
struct mii_bus *mdio_bus,
struct phy_device *phydev,
enum hclge_phy_op_code opt_type)
{
if (!phydev) {
dev_err(&hdev->pdev->dev, "this net dev has no phy.\n");
return -EINVAL;
}
if (!mdio_bus) {
dev_err(&hdev->pdev->dev, "this net dev has no mdio bus.\n");
return -EINVAL;
}
if (opt_type >= PHY_OP_MAX) {
dev_err(&hdev->pdev->dev, "unsupported phy operate type %d.",
opt_type);
return -EINVAL;
}
return 0;
}
static int hclge_phy_reg_opt(struct hnae3_handle *handle, void *data,
enum hclge_phy_op_code opt_type)
{
struct hclge_phy_para *para = (struct hclge_phy_para *)data;
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_mac *mac = &hdev->hw.mac;
struct mii_bus *mdio_bus = mac->mdio_bus;
u32 phyid = mac->phy_addr;
int need_page_select;
int op_ret, ret;
u16 cur_page;
ret = hclge_check_phy_opt_pare(hdev, mdio_bus, mac->phydev, opt_type);
if (ret < 0)
return ret;
/* operate flow:
* 1 record current page address
* 2 jump to operated page
* 3 operate register(read or write)
* 4 come back to the page recorded in the first step.
*/
mutex_lock(&mdio_bus->mdio_lock);
/* check if page select is needed and record current page address */
ret = hclge_phy_need_page_select(hdev, opt_type, para, &cur_page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
need_page_select = ret;
/* jump to operated page */
if (need_page_select) {
ret = mdio_bus->write(mdio_bus, phyid, para->page_select_addr,
para->page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
dev_err(&hdev->pdev->dev,
"change phy %d page %d to page %d failed.\n",
phyid, cur_page, para->page);
return ret;
}
}
/* operate register(read or write) */
if (opt_type == PHY_OP_READ) {
op_ret = mdio_bus->read(mdio_bus, phyid, para->reg_addr);
if (op_ret < 0) {
dev_err(&hdev->pdev->dev,
"read phy %d page %d reg %d failed.\n",
phyid, para->page, para->reg_addr);
} else {
para->data = (u16)op_ret;
op_ret = 0;
}
} else {
op_ret = mdio_bus->write(mdio_bus, phyid, para->reg_addr,
para->data);
if (op_ret < 0) {
dev_err(&hdev->pdev->dev,
"write phy %d page %d reg %d failed.\n",
phyid, para->page, para->reg_addr);
}
}
/* come back to the page recorded in the first step. */
if (need_page_select) {
ret = mdio_bus->write(mdio_bus, phyid, para->page_select_addr,
cur_page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
dev_err(&hdev->pdev->dev,
"restore phy %d reg page %u failed.\n",
phyid, cur_page);
return ret;
}
}
mutex_unlock(&mdio_bus->mdio_lock);
return op_ret;
}
static int hclge_get_phy_reg(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
return hclge_phy_reg_opt(handle, data, PHY_OP_READ);
}
static int hclge_set_phy_reg(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
return hclge_phy_reg_opt(handle, data, PHY_OP_WRITE);
}
static int hclge_opt_lookup_mac_tbl(struct hclge_vport *vport,
unsigned char *addr)
{
u32 high_val;
u32 low_val = addr[4] | (addr[5] << 8);
struct hclge_mac_vlan_tbl_entry_cmd req = {0};
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
u8 resp_code;
u16 retval;
int ret;
high_val = addr[2] << 16 | (addr[3] << 24) | (addr[0]) | (addr[1] << 8);
hnae3_set_bit(req.flags, HCLGE_MAC_VLAN_BIT0_EN_B, 1);
req.mac_addr_hi32 = cpu_to_le32(high_val);
req.mac_addr_lo16 = cpu_to_le16(low_val & 0xffff);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ADD, true);
memcpy(desc.data, &req, sizeof(struct hclge_mac_vlan_tbl_entry_cmd));
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"lookup mac addr failed for cmd_send, ret = %d.\n",
ret);
return ret;
}
resp_code = (le32_to_cpu(desc.data[0]) >> 8) & 0xff;
retval = le16_to_cpu(desc.retval);
if (retval) {
dev_err(&hdev->pdev->dev,
"cmdq execute failed for %s, retval = %d.\n",
__func__, retval);
return -EIO;
}
if (!resp_code) {
return 0;
} else if (resp_code == 1) {
dev_dbg(&hdev->pdev->dev, "lookup mac addr failed for miss.\n");
return -ENOENT;
}
dev_err(&hdev->pdev->dev,
"lookup mac addr failed for undefined, code = %d.\n",
resp_code);
return -EIO;
}
static int hclge_opt_mac_table(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_mac_table_para *info = (struct hclge_mac_table_para *)data;
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev;
int ret;
if (!info || !vport)
return -EIO;
hdev = vport->back;
switch (info->op_cmd) {
case HCLGE_OPT_TABLE_LOOKUP:
ret = hclge_opt_lookup_mac_tbl(vport, info->mac_addr);
if (ret == -ENOENT) {
return ret;
} else if (ret) {
dev_err(&hdev->pdev->dev,
"ext lookup uc mac address(%pM) fail, ret = %d.\n",
info->mac_addr, ret);
return -EIO;
}
break;
case HCLGE_OPT_TABLE_ADD:
ret = hclge_add_uc_addr_common(vport, info->mac_addr);
if (ret == -ENOSPC) {
return ret;
} else if (ret) {
dev_err(&hdev->pdev->dev,
"ext add uc mac address(%pM) fail, ret = %d.\n",
info->mac_addr, ret);
return -EIO;
}
break;
case HCLGE_OPT_TABLE_DEL:
ret = hclge_rm_uc_addr_common(vport, info->mac_addr);
if (ret == -ENOENT) {
return ret;
} else if (ret) {
dev_warn(&hdev->pdev->dev,
"ext remove uc mac address(%pM) fail, ret = %d.\n",
info->mac_addr, ret);
return -EIO;
}
break;
default:
dev_err(&hdev->pdev->dev, "ext opcode error.\n");
return -EIO;
}
return ret;
}
void hclge_reset_task_schedule_it(struct hclge_dev *hdev)
{
if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
!test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
queue_work_on(cpumask_first(&hdev->affinity_mask), system_wq,
&hdev->rst_service_task);
}
int hclge_set_reset_task(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
u32 *reset_level = (u32 *)data;
dev_warn(&hdev->pdev->dev, "reset level is %d\n", *reset_level);
/* request reset & schedule reset task */
set_bit(*reset_level, &hdev->reset_request);
hclge_reset_task_schedule_it(hdev);
return 0;
}
static int hclge_get_hilink_ref_los(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
u32 *hilink_ref_los_status;
int ret;
hilink_ref_los_status = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_GET_HILINK_REF_LOS,
true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"get hilink ref los failed, ret = %d\n", ret);
return ret;
}
*hilink_ref_los_status = desc.data[0];
return 0;
}
static struct hclge_ext_func hclge_ext_func_arr[] = {
{HCLGE_EXT_OPC_CLEAN_STATS64, hclge_clean_stats64},
{HCLGE_EXT_OPC_GET_CHIPID, hclge_get_chipid},
{HCLGE_EXT_OPC_GET_SFPINFO, hclge_get_sfpinfo},
{HCLGE_EXT_OPC_SET_SFP_STATE, hclge_set_sfp_state},
{HCLGE_EXT_OPC_GET_CHIP_NUM, hclge_get_chip_num},
{HCLGE_EXT_OPC_GET_PORT_NUM, hclge_get_port_num},
{HCLGE_EXT_OPC_SET_LED, hclge_set_led},
{HCLGE_EXT_OPC_GET_PRESENT, hclge_get_sfp_present},
{HCLGE_EXT_OPC_DISABLE_LANE, hclge_disable_net_lane},
{HCLGE_EXT_OPC_GET_LANE_STATUS, hclge_get_net_lane_status},
{HCLGE_EXT_OPC_GET_LED_SIGNAL, hclge_get_led_signal},
{HCLGE_EXT_OPC_SET_MAC_STATE, hclge_set_mac_state},
{HCLGE_EXT_OPC_CONFIG_CLOCK, hclge_config_nic_clock},
{HCLGE_EXT_OPC_GET_PFC_STORM_PARA, hclge_get_pfc_storm_para},
{HCLGE_EXT_OPC_SET_PFC_STORM_PARA, hclge_set_pfc_storm_para},
{HCLGE_EXT_OPC_GET_PHY_REG, hclge_get_phy_reg},
{HCLGE_EXT_OPC_SET_PHY_REG, hclge_set_phy_reg},
{HCLGE_EXT_OPC_GET_MAC_ID, hclge_get_mac_id},
{HCLGE_EXT_OPC_OPT_MAC_TABLE, hclge_opt_mac_table},
{HCLGE_EXT_OPC_RESET, hclge_set_reset_task},
{HCLGE_EXT_OPC_GET_HILINK_REF_LOS, hclge_get_hilink_ref_los},
};
int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode,
void *data, int length)
{
struct hclge_vport *vport = hclge_get_vport(handle);
int cmd_num = ARRAY_SIZE(hclge_ext_func_arr);
struct hclge_dev *hdev = vport->back;
if (opcode >= cmd_num) {
dev_err(&hdev->pdev->dev, "not support opcode %d.\n", opcode);
return -EOPNOTSUPP;
}
if (opcode != hclge_ext_func_arr[opcode].opcode) {
dev_err(&hdev->pdev->dev, "opcode %d is not equals %d.\n",
opcode, hclge_ext_func_arr[opcode].opcode);
return -EINVAL;
}
return hclge_ext_func_arr[opcode].priv_ops(handle, opcode, data,
length);
}
......@@ -4,7 +4,7 @@
#ifndef __HCLGE_EXT_H
#define __HCLGE_EXT_H
#include <linux/types.h>
#include "../../hnae3.h"
#include "hnae3.h"
#define HCLGE_SFP_INFO_LEN 6
#define HCLGE_SFP_INFO_SIZE 140
......@@ -16,16 +16,37 @@ struct hclge_chip_id_cmd {
u32 rsv[5];
};
struct hclge_commit_id_cmd {
u8 commit_id[8];
u32 ncl_version;
u32 rsv[3];
struct hclge_sfp_info_para {
u8 *buff;
u16 offset;
u16 size;
u16 *outlen;
};
struct hclge_sfp_info {
u32 sfpinfo[6];
};
struct hclge_led_state {
u32 type;
u32 status;
};
struct hclge_pfc_storm_para {
u32 dir;
u32 enable;
u32 period_ms;
u32 times;
u32 recovery_period_ms;
};
struct hclge_phy_para {
u32 page_select_addr;
u32 reg_addr;
u16 page;
u16 data;
};
struct hclge_sfp_enable_cmd {
u32 set_sfp_enable_flag;
u32 rsv[5];
......@@ -36,12 +57,53 @@ struct hclge_sfp_present_cmd {
u32 rsv[5];
};
struct hns3_lamp_signal {
struct hclge_lamp_signal {
u8 error;
u8 locate;
u8 activity;
};
struct hclge_mac_table_para {
u8 op_cmd;
u8 mac_addr[ETH_ALEN];
};
enum hclge_ext_op_code {
HCLGE_EXT_OPC_CLEAN_STATS64 = 0,
HCLGE_EXT_OPC_GET_CHIPID,
HCLGE_EXT_OPC_GET_SFPINFO,
HCLGE_EXT_OPC_SET_SFP_STATE,
HCLGE_EXT_OPC_GET_CHIP_NUM,
HCLGE_EXT_OPC_GET_PORT_NUM,
HCLGE_EXT_OPC_SET_LED,
HCLGE_EXT_OPC_GET_PRESENT,
HCLGE_EXT_OPC_DISABLE_LANE,
HCLGE_EXT_OPC_GET_LANE_STATUS,
HCLGE_EXT_OPC_GET_LED_SIGNAL,
HCLGE_EXT_OPC_SET_MAC_STATE,
HCLGE_EXT_OPC_CONFIG_CLOCK,
HCLGE_EXT_OPC_GET_PFC_STORM_PARA,
HCLGE_EXT_OPC_SET_PFC_STORM_PARA,
HCLGE_EXT_OPC_GET_PHY_REG,
HCLGE_EXT_OPC_SET_PHY_REG,
HCLGE_EXT_OPC_GET_MAC_ID,
HCLGE_EXT_OPC_OPT_MAC_TABLE,
HCLGE_EXT_OPC_RESET,
HCLGE_EXT_OPC_GET_HILINK_REF_LOS,
};
enum hclge_opt_table_code {
HCLGE_OPT_TABLE_LOOKUP,
HCLGE_OPT_TABLE_ADD,
HCLGE_OPT_TABLE_DEL,
};
struct hclge_ext_func {
int opcode;
int (*priv_ops)(struct hnae3_handle *handle, int opcode,
void *data, int length);
};
enum hclge_ext_opcode_type {
/* misc command */
HCLGE_OPC_CHIP_ID_GET = 0x7003,
......@@ -50,30 +112,15 @@ enum hclge_ext_opcode_type {
HCLGE_OPC_GET_PORT_NUM = 0x7006,
HCLGE_OPC_SET_LED = 0x7007,
HCLGE_OPC_DISABLE_NET_LANE = 0x7008,
/*SFP command*/
HCLGE_OPC_CFG_PAUSE_STORM_PARA = 0x7019,
HCLGE_OPC_CFG_GET_HILINK_REF_LOS = 0x701B,
/*SFP command */
HCLGE_OPC_SFP_GET_INFO = 0x7100,
HCLGE_OPC_SFP_GET_PRESENT = 0x7101,
HCLGE_OPC_SFP_SET_STATUS = 0x7102,
};
void hclge_clean_stats64(struct hnae3_handle *handle);
int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id);
int hclge_get_commit_id(struct hnae3_handle *handle, u8 *commit_id,
u32 *ncl_version);
int hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, u16 offset,
u16 size, u16 *outlen);
int hclge_set_sfp_state(struct hnae3_handle *handle, bool en);
int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num);
int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num);
int hclge_set_led(struct hnae3_handle *handle, u32 type, u32 status);
int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present);
int hclge_disable_net_lane(struct hnae3_handle *handle);
int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status);
int hclge_ext_get_sfp_speed(struct hnae3_handle *handle, u32 *speed);
int hclge_get_led_signal(struct hnae3_handle *handle,
struct hns3_lamp_signal *signal);
int hclge_set_mac_state(struct hnae3_handle *handle, bool enable);
int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable);
int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode,
void *data, int length);
void hclge_reset_task_schedule_it(struct hclge_dev *hdev);
#endif
......@@ -13,20 +13,17 @@
#include <linux/platform_device.h>
#include <linux/if_vlan.h>
#include <net/rtnetlink.h>
#include "../../kcompat.h"
#include "../../hns3pf/hclge_cmd.h"
#include "../../hns3pf/hclge_main.h"
#include "../../hnae3.h"
#include "kcompat.h"
#include "hclge_cmd.h"
#include "hclge_main.h"
#include "hnae3.h"
#include "hclge_ext.h"
#include "hclge_main_it.h"
#include "../../hns3pf/hclge_err.h"
#ifdef CONFIG_HNS3_TEST
#include "hclge_test.h"
#endif
#ifdef CONFIG_EXT_TEST
#define HCLGE_RESET_MAX_FAIL_CNT 1
static nic_event_fn_t nic_event_call;
......@@ -53,90 +50,125 @@ int nic_unregister_event(void)
EXPORT_SYMBOL(nic_unregister_event);
void nic_call_event(struct net_device *netdev,
enum hnae3_reset_type_custom event_t)
enum hnae3_event_type_custom event_t)
{
if (nic_event_call)
if (nic_event_call) {
nic_event_call(netdev, event_t);
netdev_info(netdev, "report reset event %d\n", event_t);
netdev_info(netdev, "report event %d\n", event_t);
}
}
EXPORT_SYMBOL(nic_call_event);
bool hclge_reset_done_it(struct hnae3_handle *handle, bool done)
void hclge_handle_imp_error_it(struct hnae3_handle *handle)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct net_device *netdev;
u32 reg_val;
netdev = hdev->vport[0].nic.netdev;
if (done) {
dev_info(&hdev->pdev->dev, "Report Reset DONE!\n");
nic_call_event(netdev, HNAE3_RESET_DONE_CUSTOM);
if (test_and_clear_bit(HCLGE_IMP_RD_POISON, &hdev->imp_err_state)) {
dev_err(&hdev->pdev->dev, "Detected IMP RD poison!\n");
if (nic_event_call)
nic_call_event(netdev, HNAE3_IMP_RD_POISON_CUSTOM);
reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG) &
~BIT(HCLGE_VECTOR0_IMP_RD_POISON_B);
hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val);
}
if (hdev->reset_fail_cnt >= HCLGE_RESET_MAX_FAIL_CNT) {
dev_err(&hdev->pdev->dev, "Report Reset fail!\n");
nic_call_event(netdev, HNAE3_PORT_FAULT);
if (test_and_clear_bit(HCLGE_IMP_CMDQ_ERROR, &hdev->imp_err_state)) {
dev_err(&hdev->pdev->dev, "Detected CMDQ ECC error!\n");
if (nic_event_call)
nic_call_event(netdev, HNAE3_IMP_RESET_CUSTOM);
reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG) &
~BIT(HCLGE_VECTOR0_IMP_CMDQ_ERR_B);
hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val);
}
return done;
}
pci_ers_result_t hclge_handle_hw_ras_error_it(struct hnae3_ae_dev *ae_dev)
void hclge_reset_event_it(struct pci_dev *pdev, struct hnae3_handle *handle)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
struct hclge_dev *hdev = ae_dev->priv;
struct device *dev = &hdev->pdev->dev;
enum hnae3_reset_type_custom reset_type;
struct net_device *netdev;
u32 status;
netdev = hdev->vport[0].nic.netdev;
status = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG);
/* We might end up getting called broadly because of 2 below cases:
* 1. Recoverable error was conveyed through APEI and only way to bring
* normalcy is to reset.
* 2. A new reset request from the stack due to timeout
*
* For the first case,error event might not have ae handle available.
* check if this is a new reset request and we are not here just because
* last reset attempt did not succeed and watchdog hit us again. We will
* know this if last reset request did not occur very recently (watchdog
* timer = 5*HZ, let us check after sufficiently large time, say 4*5*Hz)
* In case of new request we reset the "reset level" to PF reset.
* And if it is a repeat reset request of the most recent one then we
* want to make sure we throttle the reset request. Therefore, we will
* not allow it again before 12*HZ times.
*/
if (time_before(jiffies, (hdev->last_reset_time +
HCLGE_RESET_INTERVAL)))
return;
else if (hdev->default_reset_request)
hdev->reset_level =
hclge_get_reset_level(ae_dev, &hdev->default_reset_request);
else if (time_after(jiffies, (hdev->last_reset_time + 4 * 5 * HZ)))
hdev->reset_level = HNAE3_FUNC_RESET;
dev_info(&hdev->pdev->dev, "received reset event , reset type is %d",
hdev->reset_level);
if (hdev->ppu_poison_ras_err && nic_event_call) {
nic_call_event(netdev, HNAE3_PPU_POISON_CUSTOM);
hdev->ppu_poison_ras_err = false;
}
if (status & HCLGE_RAS_REG_NFE_MASK ||
status & HCLGE_RAS_REG_ROCEE_ERR_MASK)
ae_dev->hw_err_reset_req = 0;
if (nic_event_call) {
nic_call_event(netdev, hdev->reset_level);
} else {
/* request reset & schedule reset task */
set_bit(hdev->reset_level, &hdev->reset_request);
hclge_reset_task_schedule_it(hdev);
}
}
/* Handling Non-fatal HNS RAS errors */
if (status & HCLGE_RAS_REG_NFE_MASK) {
dev_warn(dev,
"HNS Non-Fatal RAS error(status=0x%x) identified\n",
status);
hclge_handle_all_ras_errors(hdev);
bool hclge_reset_done_it(struct hnae3_handle *handle, bool done)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct net_device *netdev;
reset_type = ae_dev->ops->set_default_reset_request(ae_dev,
&ae_dev->hw_err_reset_req);
netdev = hdev->vport[0].nic.netdev;
if (reset_type != HNAE3_NONE_RESET_CUSTOM)
nic_call_event(netdev, reset_type);
} else {
if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) ||
hdev->pdev->revision < 0x21) {
ae_dev->override_pci_need_reset = 1;
return PCI_ERS_RESULT_RECOVERED;
}
if (done) {
dev_info(&hdev->pdev->dev, "Report Reset DONE!\n");
if (nic_event_call)
nic_call_event(netdev, HNAE3_RESET_DONE_CUSTOM);
}
if (status & HCLGE_RAS_REG_ROCEE_ERR_MASK) {
dev_warn(dev, "ROCEE uncorrected RAS error identified\n");
hclge_handle_rocee_ras_error(ae_dev);
if (hdev->reset_fail_cnt >= HCLGE_RESET_MAX_FAIL_CNT) {
dev_err(&hdev->pdev->dev, "Report Reset fail!\n");
if (nic_event_call) {
if (hdev->reset_type == HNAE3_FUNC_RESET)
nic_call_event(netdev,
HNAE3_FUNC_RESET_FAIL_CUSTOM);
else if (hdev->reset_type == HNAE3_GLOBAL_RESET)
nic_call_event(netdev,
HNAE3_GLOBAL_RESET_FAIL_CUSTOM);
else if (hdev->reset_type == HNAE3_IMP_RESET)
nic_call_event(netdev,
HNAE3_IMP_RESET_FAIL_CUSTOM);
}
if ((status & HCLGE_RAS_REG_NFE_MASK ||
status & HCLGE_RAS_REG_ROCEE_ERR_MASK) &&
ae_dev->hw_err_reset_req) {
ae_dev->override_pci_need_reset = 0;
return PCI_ERS_RESULT_NEED_RESET;
}
ae_dev->override_pci_need_reset = 1;
return PCI_ERS_RESULT_RECOVERED;
return done;
}
#endif
#ifdef CONFIG_IT_VALIDATION
#define HCLGE_NAME_IT "hclge"
......@@ -145,39 +177,21 @@ EXPORT_SYMBOL(hclge_get_vport);
EXPORT_SYMBOL(hclge_cmd_set_promisc_mode);
EXPORT_SYMBOL(hclge_promisc_param_init);
struct pci_device_id ae_algo_pci_tbl_it[] = {
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_GE), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA_MACSEC), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA_MACSEC), 0},
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), 0},
#ifdef CONFIG_HNS3_X86
{PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_X86_25_GE), 0},
#endif
/* required last entry */
{0, }
};
int hclge_init_it(void)
{
pr_info("%s is initializing\n", HCLGE_NAME_IT);
#ifdef CONFIG_HNS3_TEST
hclge_ops.send_cmdq = hclge_send_cmdq;
hclge_ops.priv_ops = hclge_ext_ops_handle;
#endif
#ifdef CONFIG_EXT_TEST
hclge_ops.handle_hw_ras_error = hclge_handle_hw_ras_error_it;
hclge_ops.reset_event = hclge_reset_event_it;
hclge_ops.reset_done = hclge_reset_done_it;
#endif
ae_algo.pdev_id_table = ae_algo_pci_tbl_it;
hclge_ops.handle_imp_error = hclge_handle_imp_error_it;
hnae3_register_ae_algo(&ae_algo);
return 0;
}
module_init(hclge_init_it);
#endif
......@@ -7,7 +7,7 @@
extern struct hnae3_ae_algo ae_algo;
extern struct hnae3_ae_ops hclge_ops;
enum hnae3_reset_type_custom {
enum hnae3_event_type_custom {
HNAE3_VF_RESET_CUSTOM,
HNAE3_VF_FUNC_RESET_CUSTOM,
HNAE3_VF_PF_FUNC_RESET_CUSTOM,
......@@ -20,17 +20,20 @@ enum hnae3_reset_type_custom {
HNAE3_NONE_RESET_CUSTOM,
HNAE3_PORT_FAULT,
HNAE3_RESET_DONE_CUSTOM,
HNAE3_FUNC_RESET_FAIL_CUSTOM,
HNAE3_GLOBAL_RESET_FAIL_CUSTOM,
HNAE3_IMP_RESET_FAIL_CUSTOM,
HNAE3_PPU_POISON_CUSTOM,
HNAE3_IMP_RD_POISON_CUSTOM,
};
#ifdef CONFIG_EXT_TEST
/**
* nic_event_fn_t - nic event handler prototype
* @netdev: net device
* @hnae3_reset_type_custom: nic device event type
* @hnae3_event_type_custom: nic device event type
*/
typedef void (*nic_event_fn_t) (struct net_device *netdev,
enum hnae3_reset_type_custom);
enum hnae3_event_type_custom);
/**
* nic_register_event - register for nic event listening
......@@ -46,7 +49,5 @@ int nic_register_event(nic_event_fn_t event_call);
int nic_unregister_event(void);
void nic_call_event(struct net_device *netdev,
enum hnae3_reset_type_custom event_t);
#endif
enum hnae3_event_type_custom event_t);
#endif
......@@ -4,8 +4,8 @@
#ifndef __HCLGE_TEST_H
#define __HCLGE_TEST_H
#include "../../hns3pf/hclge_cmd.h"
#include "../../hns3pf/hclge_main.h"
#include "hclge_cmd.h"
#include "hclge_main.h"
int hclge_send_cmdq(struct hnae3_handle *handle, void *data, int num);
......
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include "hnae3.h"
#include "hns3_enet.h"
#include "hns3_enet_it.h"
#ifdef CONFIG_HNS3_TEST
#include "hns3_nictool.h"
#endif
static int __init hns3_cae_init(void)
{
#ifdef CONFIG_HNS3_TEST
int ret;
pr_err("%s enter!\n", __func__);
ret = nictool_k_init();
if (ret)
return ret;
#endif
return 0;
}
static void __exit hns3_cae_exit(void)
{
#ifdef CONFIG_HNS3_TEST
pr_err("%s exit!\n", __func__);
nictool_k_uninit();
#endif
}
module_init(hns3_cae_init);
module_exit(hns3_cae_exit);
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <net/sock.h>
#include <net/rtnetlink.h>
#include "hns3_enet.h"
#include "hclge_cmd.h"
#include "hclge_main.h"
#include "hns3_nictool.h"
#include "hns3_priv_tm.h"
#include "hns3_priv_dcb.h"
#include "hns3_priv_pkt.h"
#include "hns3_priv_mac.h"
#include "hns3_priv_dfx.h"
#include "hns3_priv_vlan.h"
#include "hns3_priv_phy.h"
#include "hns3_priv_qos.h"
#include "hns3_priv_qinfo.h"
#include "hns3_priv_promisc.h"
#include "hns3_priv_fd.h"
#include "hns3_priv_rss.h"
#include "hns3_priv_common_test.h"
#include "hns3_priv_m7_cmd.h"
#include "hns3_priv_qres.h"
#include "hns3_priv_stat.h"
#include "hns3_priv_irq.h"
#include "hns3_priv_lamp.h"
#include "hns3_priv_ext.h"
#include "hns3_priv_xsfp.h"
#include "hns3_priv_port.h"
#include "hns3_priv_hilink_param.h"
#include "hns3_priv_mactbl.h"
#include "kcompat.h"
#define HCLGE_CHS_OUT_L3_B 0
#define HCLGE_CHS_OUT_UDP_B 1
#define HCLGE_CHS_INNER_L3_B 0
#define HCLGE_CHS_INNER_TCP_B 1
#define HCLGE_CHS_INNER_UDP_B 2
#define HCLGE_CHS_INNER_SCTP_B 3
#define HCLGE_OPC_CHECKSUM_CHECK_EN 0x0601
#define SCC_TEMP_LOW_ADDR 0x31000000
#define SCC_TEMP_HIGH_ADDR 0x1
/* misc command */
#define HCLGE_OPC_CHIP_ID_GET 0x7003
#define HCLGE_OPC_IMP_COMMIT_ID_GET 0x7004
#define HCLGE_OPC_GET_CHIP_NUM 0x7005
#define HCLGE_OPC_GET_PORT_NUM 0x7006
/* SFP command */
#define HCLGE_OPC_SFP_GET_INFO 0x7100
#define HCLGE_OPC_SFP_GET_PRESENT 0x7101
#define HCLGE_OPC_SFP_SET_STATUS 0x7102
/* DCQCN command */
#define HCLGE_OPC_DCQCN_TEMPLATE_CFG 0x7014
#define HCLGE_OPC_DCQCN_GET_MSG_CNT 0x7017
#define HNAE_DRIVER_VERSION "1.8.10.0"
struct hclge_chs_param {
u8 outer_en;
u8 inner_en;
u8 rsv[22];
};
struct tx_timeout_param {
u16 wr_flag;
u16 tx_timeout_size;
};
struct reset_param {
u32 reset_level;
};
static dev_t g_dev_id = {0};
struct class *g_nictool_class;
struct cdev g_nictool_cdev;
static const char hns3_driver_name[] = "hns3";
int g_nictool_init_flag;
int g_nictool_ref_cnt;
typedef int (*driv_module) (struct hns3_nic_priv *nic_dev, void *buf_in,
u16 in_size, void *buf_out, u16 *out_size);
struct drv_module_handle {
enum driver_cmd_type driv_cmd_name;
driv_module driv_func;
};
static void free_buff_in(void *buf_in)
{
if (!buf_in)
return;
kfree(buf_in);
}
static int alloc_buff_in(struct msg_module *nt_msg, u32 in_size, void **buf_in)
{
void *msg_buf;
if (!in_size)
return 0;
msg_buf = kzalloc((unsigned long)in_size, GFP_KERNEL);
*buf_in = msg_buf;
if (ZERO_OR_NULL_PTR(*buf_in)) {
pr_err("alloc buf_in failed\n");
return -ENOMEM;
}
if (copy_from_user(msg_buf, nt_msg->in_buff, (unsigned long)in_size)) {
pr_err("Copy from user failed in %s function\n", __func__);
kfree(msg_buf);
return -EFAULT;
}
return 0;
}
static void free_buff_out(void *buf_out)
{
if (!buf_out)
return;
kfree(buf_out);
}
static int alloc_buff_out(u32 out_size, void **buf_out)
{
if (!out_size)
return 0;
*buf_out = kzalloc((unsigned long)out_size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR(*buf_out)) {
pr_err("alloc buf_out failed\n");
return -ENOMEM;
}
return 0;
}
static int copy_buf_out_to_user(struct msg_module *nt_msg, u32 out_size,
void **buf_out)
{
int ret = 0;
void *msg_out = buf_out;
if (copy_to_user(nt_msg->out_buf, msg_out, out_size))
ret = -EFAULT;
return ret;
}
static int nictool_netdev_match_check(struct net_device *netdev)
{
struct ethtool_drvinfo drv_info;
if (netdev->ethtool_ops->get_drvinfo)
netdev->ethtool_ops->get_drvinfo(netdev, &drv_info);
if (!strncmp(drv_info.driver, hns3_driver_name,
strlen(hns3_driver_name)))
return 0;
netdev_err(netdev, "match hns3 driver name(%s) failed\n",
drv_info.driver);
return -1;
}
#if (KERNEL_VERSION(4, 16, 0) < LINUX_VERSION_CODE)
static int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
{
mm_segment_t oldfs = get_fs();
int err;
set_fs(KERNEL_DS);
err = sock->ops->ioctl(sock, cmd, arg);
set_fs(oldfs);
return err;
}
#endif
static struct net_device *get_netdev_by_ifname(char *ifname)
{
struct socket *temp_sock = NULL;
struct net_device *netdev = NULL;
struct ifreq ifr;
int err;
err = sock_create(PF_INET, SOCK_DGRAM, 0, &temp_sock);
if (err < 0) {
pr_err("fail to enter sock_create, err = %d\n", err);
return NULL;
}
strncpy(ifr.ifr_ifrn.ifrn_name, ifname, (unsigned long)IFNAMSIZ);
kernel_sock_ioctl(temp_sock, SIOCSIFNAME, (unsigned long)&ifr);
netdev = dev_get_by_name(sock_net(temp_sock->sk), ifname);
if (!netdev)
goto out;
dev_put(netdev);
out:
sock_release(temp_sock);
return netdev;
}
static int nictool_k_get_netdev_by_ifname(char *ifname,
struct hns3_nic_priv **nic_dev)
{
struct net_device *netdev = NULL;
netdev = get_netdev_by_ifname(ifname);
if (!netdev) {
pr_err("not find the netdevice(%s)!\n", ifname);
return -EFAULT;
}
if (nictool_netdev_match_check(netdev)) {
netdev_err(netdev, "netdevice is not hns device.\n");
return -EFAULT;
}
*nic_dev = (struct hns3_nic_priv *)netdev_priv(netdev);
if (!(*nic_dev)) {
netdev_err(netdev, "no private data\n");
return -EFAULT;
}
return 0;
}
int hns3_test_chs_set(struct hclge_dev *hdev, u8 chs_type, u8 enable)
{
struct hclge_desc desc;
enum hclge_cmd_status status;
struct hclge_chs_param *recv;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHECKSUM_CHECK_EN, true);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
pr_err("chs get cmd send failed!\n");
return status;
}
recv = (struct hclge_chs_param *)desc.data;
switch (chs_type) {
case CKS_OUTER_L3_EN:
hnae3_set_bit(recv->outer_en, HCLGE_CHS_OUT_L3_B, enable);
break;
case CKS_OUTER_UDP_EN:
hnae3_set_bit(recv->outer_en, HCLGE_CHS_OUT_UDP_B, enable);
break;
case CKS_INNER_L3_EN:
hnae3_set_bit(recv->inner_en, HCLGE_CHS_INNER_L3_B, enable);
break;
case CKS_INNER_TCP_EN:
hnae3_set_bit(recv->inner_en, HCLGE_CHS_INNER_TCP_B, enable);
break;
case CKS_INNER_UDP_EN:
hnae3_set_bit(recv->inner_en, HCLGE_CHS_INNER_UDP_B, enable);
break;
case CKS_INNER_SCTP_EN:
hnae3_set_bit(recv->inner_en, HCLGE_CHS_INNER_SCTP_B, enable);
break;
default:
break;
}
hclge_cmd_reuse_desc(&desc, false);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
return status;
}
int hns3_test_chs_get(struct hclge_dev *hdev, u8 chs_type, u8 *enable)
{
struct hclge_chs_param *recv;
enum hclge_cmd_status status;
struct hclge_desc desc;
u8 inner_sctp_en;
u8 inner_tcp_en;
u8 inner_udp_en;
u8 outer_udp_en;
u8 outer_l3_en;
u8 inner_l3_en;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHECKSUM_CHECK_EN, true);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
pr_err("chs get cmd send failed!\n");
return status;
}
recv = (struct hclge_chs_param *)desc.data;
outer_l3_en = hnae3_get_bit(recv->outer_en, HCLGE_CHS_OUT_L3_B);
outer_udp_en = hnae3_get_bit(recv->outer_en, HCLGE_CHS_OUT_UDP_B);
inner_l3_en = hnae3_get_bit(recv->inner_en, HCLGE_CHS_INNER_L3_B);
inner_tcp_en = hnae3_get_bit(recv->inner_en, HCLGE_CHS_INNER_TCP_B);
inner_udp_en = hnae3_get_bit(recv->inner_en, HCLGE_CHS_INNER_UDP_B);
inner_sctp_en = hnae3_get_bit(recv->inner_en, HCLGE_CHS_INNER_SCTP_B);
switch (chs_type) {
case CKS_OUTER_L3_EN:
*enable = outer_l3_en;
break;
case CKS_OUTER_UDP_EN:
*enable = outer_udp_en;
break;
case CKS_INNER_L3_EN:
*enable = inner_l3_en;
break;
case CKS_INNER_TCP_EN:
*enable = inner_tcp_en;
break;
case CKS_INNER_UDP_EN:
*enable = inner_udp_en;
break;
case CKS_INNER_SCTP_EN:
*enable = inner_sctp_en;
break;
default:
break;
}
return status;
}
int hns3_test_chs_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct hns3_chs_param *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u8 *out_info;
u8 is_set;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct hns3_chs_param *)buf_in;
out_info = (u8 *)buf_out;
is_set = in_info->is_set;
if (in_info->type >= CKS_MAX) {
pr_err("chs type is %d, param err!\n", in_info->type);
return -1;
}
if (in_info->is_enable != 0 && in_info->is_enable != 1) {
pr_err("chs enable is %d, param err!\n", in_info->is_enable);
return -1;
}
if (is_set) {
if (hns3_test_chs_set(hdev, in_info->type,
in_info->is_enable)) {
pr_err("set chs type(%d) enable failed!\n",
in_info->type);
return -1;
}
} else {
if (hns3_test_chs_get(hdev, in_info->type, out_info)) {
pr_err("get chs type(%d) enable failed!\n",
in_info->type);
return -1;
}
pr_err("chs type(%d) enable status is %d\n",
in_info->type, *out_info);
}
return 0;
}
int hns_test_get_commit_id(struct hnae3_handle *handle, u8 *commit_id,
u32 *ncl_version)
{
#define COMMIT_ID_LEN 8
struct hclge_vport *vport = hclge_get_vport(handle);
struct hns3_test_commit_id_param *resp;
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
int ret, i;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_COMMIT_ID_GET, true);
resp = (struct hns3_test_commit_id_param *)(desc.data);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "get commit id failed %d\n", ret);
return ret;
}
for (i = 0; i < COMMIT_ID_LEN; i++)
commit_id[i] = resp->commit_id[i];
commit_id[COMMIT_ID_LEN] = '\0';
*ncl_version = resp->ncl_version;
return 0;
}
static int get_fw_ver(struct hns3_nic_priv *nic_dev, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct firmware_ver_param *out_buf;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u32 fw_ver;
handle = nic_dev->ae_handle;
vport = container_of(handle, struct hclge_vport, nic);
hdev = vport->back;
out_buf = (struct firmware_ver_param *)buf_out;
if (!handle)
return -EFAULT;
if (!hdev)
return -EFAULT;
if (hns_test_get_commit_id(handle, out_buf->commit_id,
&out_buf->ncl_version))
return -EFAULT;
fw_ver = hdev->fw_version;
out_buf->imp_ver = fw_ver;
if (!fw_ver)
return -EFAULT;
return 0;
}
static int get_driver_ver(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
if (!buf_out)
return -ENOMEM;
strncpy(buf_out, HNAE_DRIVER_VERSION, sizeof(HNAE_DRIVER_VERSION));
*out_size = sizeof(HNAE_DRIVER_VERSION);
return 0;
}
int hns3_test_clean_stats(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
struct hnae3_knic_private_info *kinfo;
struct hnae3_handle *handle;
struct hns3_enet_ring *ring;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_tqp *tqp;
int i;
handle = net_priv->ae_handle;
kinfo = &handle->kinfo;
vport = container_of(handle, struct hclge_vport, nic);
hdev = vport->back;
for (i = 0; i < kinfo->num_tqps; i++) {
tqp = container_of(kinfo->tqp[i], struct hclge_tqp, q);
memset(&tqp->tqp_stats, 0, sizeof(struct hlcge_tqp_stats));
ring = net_priv->ring_data[i].ring;
memset(&ring->stats, 0, sizeof(struct ring_stats));
ring = net_priv->ring_data[i + kinfo->num_tqps].ring;
memset(&ring->stats, 0, sizeof(struct ring_stats));
}
memset(&hdev->hw_stats.mac_stats, 0, sizeof(struct hclge_mac_stats));
memset(&netdev->stats, 0, sizeof(struct net_device_stats));
return 0;
}
int hns3_nic_reset(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct hnae3_handle *h = net_priv->ae_handle;
struct reset_param *reset_info;
enum hnae3_reset_type rst_type;
struct hclge_vport *vport;
struct hclge_dev *hdev;
vport = container_of(h, struct hclge_vport, nic);
hdev = vport->back;
reset_info = (struct reset_param *)buf_in;
rst_type = HNAE3_NONE_RESET;
if (test_bit(HCLGE_STATE_REMOVING, &hdev->state)) {
dev_info(&hdev->pdev->dev, "driver already uninit!\n");
return 0;
}
if (time_before(jiffies, (hdev->last_reset_time + 12 * HZ)))
return 0;
if (reset_info->reset_level == HNAE3_FUNC_RESET)
rst_type = HNAE3_FUNC_RESET;
else if (reset_info->reset_level == HNAE3_GLOBAL_RESET)
rst_type = HNAE3_GLOBAL_RESET;
hdev->reset_level = rst_type;
dev_info(&hdev->pdev->dev,
"user received reset event, reset type is %d\n",
hdev->reset_level);
/* request reset & schedule reset task */
set_bit(hdev->reset_level, &hdev->reset_request);
if (!test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state))
schedule_work(&hdev->rst_service_task);
return 0;
}
int hns3_nic_timeout_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
struct tx_timeout_param *in_info;
struct tx_timeout_param *out_info;
in_info = (struct tx_timeout_param *)buf_in;
out_info = (struct tx_timeout_param *)buf_out;
if (in_info->wr_flag)
netdev->watchdog_timeo = (in_info->tx_timeout_size) * HZ;
else
out_info->tx_timeout_size = (netdev->watchdog_timeo) / HZ;
return 0;
}
int hns3_gro_age_handle(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hnae3_handle *h = net_priv->ae_handle;
struct hclge_gro_age_config_cmd *req;
struct hclge_desc desc;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct gro_param *param;
int ret;
vport = container_of(h, struct hclge_vport, nic);
param = (struct gro_param *)buf_in;
hdev = vport->back;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GRO_AGE_CFG,
param->is_read ? true : false);
req = (struct hclge_gro_age_config_cmd *)desc.data;
if (!param->is_read)
req->ppu_gro_age_cnt = param->age_cnt;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "gro age config fail, ret = %d\n",
ret);
return ret;
}
if (param->is_read) {
memcpy(buf_out, &req->ppu_gro_age_cnt,
sizeof(req->ppu_gro_age_cnt));
*out_size = sizeof(req->ppu_gro_age_cnt);
}
return 0;
}
static int hns3_dcqcn_rw(struct hns3_nic_priv *net_priv,
u32 offset, u32 *data, u32 rw_type)
{
struct hnae3_handle *h = net_priv->ae_handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
int ret;
if (!data)
return -EFAULT;
vport = container_of(h, struct hclge_vport, nic);
hdev = vport->back;
if (rw_type == DEVMEM_CFG_READ) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DCQCN_TEMPLATE_CFG,
true);
} else {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DCQCN_TEMPLATE_CFG,
false);
desc.data[2] = *data;
}
desc.data[0] = SCC_TEMP_LOW_ADDR + offset;
desc.data[1] = SCC_TEMP_HIGH_ADDR;
desc.data[4] = 32;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "disable net lane failed %d\n", ret);
return ret;
}
if (rw_type == DEVMEM_CFG_READ)
*data = desc.data[2];
return 0;
}
int hns3_nic_dcqcn(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct hnae3_handle *h = net_priv->ae_handle;
struct hclge_vport *vport = container_of(h, struct hclge_vport, nic);
struct cfg_dcqcn_param *parm_out = buf_out;
struct cfg_dcqcn_param *parm_in = buf_in;
struct cfg_dcqcn_param tempbuffer = {0};
struct hclge_dev *hdev = vport->back;
u32 tempoutbuff;
u32 offset;
int ret;
if (!hnae3_dev_roce_supported(hdev)) {
dev_err(&hdev->pdev->dev, "This device is not support RoCE!\n");
return -EINVAL;
}
tempoutbuff = 0;
if (parm_in->device_number > 0xff) {
dev_err(&hdev->pdev->dev,
"parm_in->device_number=0x%x, max value is 0xff.\n",
parm_in->device_number);
return -ENXIO;
}
offset = 0x10 * parm_in->device_number + 0x6000;
ret = hns3_dcqcn_rw(net_priv, offset, (u32 *)&tempoutbuff,
DEVMEM_CFG_READ);
if (ret) {
dev_err(&hdev->pdev->dev,
"read dcqcn cfg 0~31 bit failed 0x%x\n", ret);
return ret;
}
tempbuffer.ai = (tempoutbuff & 0xffff);
tempbuffer.f = ((tempoutbuff >> 16) & 0xff);
tempbuffer.tkp = (tempoutbuff >> 24);
offset = offset + 0x4;
ret = hns3_dcqcn_rw(net_priv, offset, (u32 *)&tempoutbuff,
DEVMEM_CFG_READ);
if (ret) {
dev_err(&hdev->pdev->dev,
"read dcqcn cfg 32~63 bit failed ret = 0x%x\n", ret);
return ret;
}
tempbuffer.tmp = (tempoutbuff & 0xffff);
tempbuffer.alp = (tempoutbuff >> 16);
offset = offset + 0x4;
ret = hns3_dcqcn_rw(net_priv, offset, (u32 *)&tempoutbuff,
DEVMEM_CFG_READ);
if (ret) {
dev_err(&hdev->pdev->dev,
"read dcqcn cfg 64~95 bit failed ret = 0x%x\n", ret);
return ret;
}
tempbuffer.max_speed = tempoutbuff;
offset = offset + 0x4;
ret = hns3_dcqcn_rw(net_priv, offset, (u32 *)&tempoutbuff,
DEVMEM_CFG_READ);
if (ret) {
dev_err(&hdev->pdev->dev,
"read dcqcn cfg 96~127 bit failed ret = 0x%x\n", ret);
return ret;
}
tempbuffer.g = (tempoutbuff & 0xff);
tempbuffer.al = ((tempoutbuff >> 8) & 0xff);
tempbuffer.cnp_time = ((tempoutbuff >> 16) & 0xff);
tempbuffer.alp_shift = ((tempoutbuff >> 24) & 0xff);
if (parm_in->is_get == HINICADM_DCQCN_WRITE_CFG_MODE) {
if ((parm_in->dcqcn_parm_opcode & 0x1) == 1)
tempbuffer.ai = parm_in->ai;
if ((parm_in->dcqcn_parm_opcode & 0x2) == 0x2)
tempbuffer.f = parm_in->f;
if ((parm_in->dcqcn_parm_opcode & 0x4) == 0x4)
tempbuffer.tkp = parm_in->tkp;
if ((parm_in->dcqcn_parm_opcode & 0x8) == 0x8)
tempbuffer.tmp = parm_in->tmp;
if ((parm_in->dcqcn_parm_opcode & 0x10) == 0x10)
tempbuffer.alp = parm_in->alp;
if ((parm_in->dcqcn_parm_opcode & 0x20) == 0x20)
tempbuffer.g = parm_in->g;
if ((parm_in->dcqcn_parm_opcode & 0x40) == 0x40)
tempbuffer.al = parm_in->al;
if ((parm_in->dcqcn_parm_opcode & 0x80) == 0x80)
tempbuffer.max_speed = parm_in->max_speed;
if ((parm_in->dcqcn_parm_opcode & 0x100) == 0x100)
tempbuffer.cnp_time = parm_in->cnp_time;
if ((parm_in->dcqcn_parm_opcode & 0x200) == 0x200)
tempbuffer.alp_shift = parm_in->alp_shift;
ret = hns3_dcqcn_rw(net_priv,
0x10 * parm_in->device_number + 0x6000,
(u32 *)&tempbuffer.ai, DEVMEM_CFG_WRITE);
if (ret) {
dev_err(&hdev->pdev->dev,
"write dcqcn cfg 0~31 bit failed ret = 0x%x\n",
ret);
return ret;
}
ret = hns3_dcqcn_rw(net_priv,
0x10 * parm_in->device_number + 0x6004,
(u32 *)&tempbuffer.tmp, DEVMEM_CFG_WRITE);
if (ret) {
dev_err(&hdev->pdev->dev,
"write dcqcn cfg 32~63 bit failed ret = 0x%x\n",
ret);
return ret;
}
ret = hns3_dcqcn_rw(net_priv,
0x10 * parm_in->device_number + 0x6008,
(u32 *)&tempbuffer.max_speed,
DEVMEM_CFG_WRITE);
if (ret) {
dev_err(&hdev->pdev->dev,
"write dcqcn cfg 64~95 bit failed ret = 0x%x\n",
ret);
return ret;
}
ret = hns3_dcqcn_rw(net_priv,
0x10 * parm_in->device_number + 0x600c,
(u32 *)&tempbuffer.g, DEVMEM_CFG_WRITE);
if (ret) {
dev_err(&hdev->pdev->dev,
"write dcqcn cfg 96~127 bit failed ret = 0x%x\n",
ret);
return ret;
}
} else if (parm_in->is_get == HINICADM_DCQCN_READ_CFG_MODE) {
parm_out->ai = tempbuffer.ai;
parm_out->f = tempbuffer.f;
parm_out->tkp = tempbuffer.tkp;
parm_out->tmp = tempbuffer.tmp;
parm_out->alp = tempbuffer.alp;
parm_out->max_speed = tempbuffer.max_speed;
parm_out->g = tempbuffer.g;
parm_out->al = tempbuffer.al;
parm_out->cnp_time = tempbuffer.cnp_time;
parm_out->alp_shift = tempbuffer.alp_shift;
} else {
dev_err(&hdev->pdev->dev,
"parm->is_get = 0x%x parm is error type\n",
parm_in->is_get);
}
return 0;
}
int hns3_dcqcn_get_msg_cnt(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hnae3_handle *h = net_priv->ae_handle;
struct hclge_vport *vport = container_of(h, struct hclge_vport, nic);
struct dcqcn_statistic_param *statistic_parm_out = buf_out;
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DCQCN_GET_MSG_CNT, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "disable net lane failed %d\n", ret);
return ret;
}
statistic_parm_out->dcqcn_rx_cnt = desc.data[0];
statistic_parm_out->dcqcn_tx_cnt = desc.data[2];
statistic_parm_out->dcqcn_db_cnt = desc.data[4];
return 0;
}
struct drv_module_handle driv_module_cmd_handle[] = {
{FW_VER, get_fw_ver},
{DRIVER_VER, get_driver_ver},
{CHECKSUM_CFG, hns3_test_chs_cfg},
{TM_QUEUE_CFG, hns3_test_queue_cfg},
{TM_QSET_CFG, hns3_test_qs_cfg},
{TM_PRI_CFG, hns3_test_pri_cfg},
{TM_PG_CFG, hns3_test_pg_cfg},
{TM_PORT_CFG, hns3_test_port_cfg},
{TM_ETS_CFG, hns3_test_ets_cfg},
{DCB_MODE_CFG, hns3_test_dcb_cfg},
{ETS_MODE_CFG, hns3_test_dcb_ets_cfg},
{PFC_MODE_CFG, hns3_test_dcb_pfc_cfg},
{MAC_LOOP_CFG, hns3_test_mac_loop_cfg},
{DFX_INFO_CMD, hns3_test_get_dfx_info},
{DFX_READ_CMD, hns3_test_read_dfx_info},
{SEND_PKT, hns3_test_send_pkt},
{RX_PRIV_BUFF_WL_CFG, hns3_test_rx_priv_buff_wl_cfg},
{RX_COMMON_THRD_CFG, hns3_test_common_thrd_cfg},
{RX_COMMON_WL_CFG, hns3_test_common_wl_cfg},
{SHOW_RX_PRIV_WL, hns3_test_show_rx_priv_wl},
{SHOW_RX_COMM_THRES, hns3_test_show_comm_thres},
{QCN_EN_CFG, hns3_test_qcn_cfg},
{RX_BUFF_CFG, hns3_test_rx_buff_cfg},
{TX_BUFF_CFG, hns3_test_tx_buff_cfg},
{RESET_CFG, hns3_nic_reset},
{TIMEOUT_CFG, hns3_nic_timeout_cfg},
{PROMISC_MODE_CFG, hns3_promisc_mode_cfg},
{QINFO_CFG, hns3_test_qinfo_cfg},
{PHY_REGISTER_CFG, hns3_test_phy_register_cfg},
{MACTABLE_CFG, hns3_test_opt_mactbl},
{CLEAN_STATS, hns3_test_clean_stats},
{FD_CFG, hns3_test_fd_cfg},
{RSS_GENERIC_CFG, hns3_test_rss_cfg},
{REG_CFG, hns3_test_reg_cfg},
{COM_REG_CFG, hns3_reg_cfg},
{GRO_CFG, hns3_gro_age_handle},
{M7_CMD_MODE_CFG, hns3_m7_cmd_handle},
{QRES_CFG, hns3_test_qres_cfg},
{STAT_CFG, hns3_stat_mode_cfg},
{IRQ_CFG, hns3_irq_lli_cfg},
{VLAN_UPMAPPING, hns3_test_upmapping_cfg},
{LAMP_CFG, hns3_lamp_cfg},
{EXTERN_INTERFACE_CFG, hns3_ext_interface_test},
{XSFP_CFG, hns3_xsfp_cfg},
{SHOW_PORT_INFO, hns3_get_port_info},
{SHOW_HILINK_PARAM, hns3_get_hilink_param},
{DCQCN_PARM_CFG, hns3_nic_dcqcn},
{DCQCN_GET_MSG_CNT_CMD, hns3_dcqcn_get_msg_cnt}
};
static int send_to_driver(struct hns3_nic_priv *nic_dev,
struct msg_module *nt_msg,
void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
u32 num_cmds = ARRAY_SIZE(driv_module_cmd_handle);
enum driver_cmd_type cmd_type =
(enum driver_cmd_type)(nt_msg->msg_formate);
driv_module fn;
int err = 0;
u32 index;
for (index = 0; index < num_cmds; index++) {
if (cmd_type == driv_module_cmd_handle[index].driv_cmd_name) {
fn = driv_module_cmd_handle[index].driv_func;
err = fn(nic_dev, buf_in, (u16)in_size, buf_out,
(u16 *)out_size);
break;
}
}
return err;
}
static long nictool_k_unlocked_ioctl(struct file *pfile, unsigned int cmd,
unsigned long arg)
{
struct hns3_nic_priv *nic_dev = NULL;
struct msg_module nt_msg;
void *buf_out = NULL;
void *buf_in = NULL;
u32 out_size_expect;
u32 out_size = 0;
u32 in_size;
int cmd_raw;
int ret;
memset(&nt_msg, 0, sizeof(nt_msg));
if (copy_from_user(&nt_msg, (void *)arg, sizeof(nt_msg))) {
pr_err("copy from user failed in unlocked_ioctl function\n");
return -EFAULT;
}
cmd_raw = nt_msg.module;
out_size_expect = nt_msg.len_info.out_buff_len;
in_size = nt_msg.len_info.in_buff_len;
ret = nictool_k_get_netdev_by_ifname(nt_msg.device_name, &nic_dev);
if (ret) {
pr_err("can not get the netdevice correctly\n");
return -EINVAL;
}
if (nic_dev->ae_handle->flags & HNAE3_SUPPORT_VF) {
pr_err("VF is not supported.\n");
return -EINVAL;
}
ret = alloc_buff_in(&nt_msg, in_size, &buf_in);
if (ret) {
pr_err("alloc in buffer failed\n");
return -EFAULT;
}
ret = alloc_buff_out(out_size_expect, &buf_out);
if (ret) {
pr_err("alloc out buffer failed\n");
goto out_free_buf_in;
}
switch (cmd_raw) {
case SEND_TO_DRIVER:
ret = send_to_driver(nic_dev, &nt_msg, buf_in, in_size, buf_out,
&out_size);
if (ret) {
pr_err("send buffer to driver failed, ret = %d\n", ret);
goto out_free_buf_out;
}
break;
default:
pr_err("module err!\n");
ret = -EINVAL;
goto out_free_buf_out;
}
ret = copy_buf_out_to_user(&nt_msg, out_size_expect, buf_out);
if (ret)
pr_err("copy buf to user failed\n");
out_free_buf_out:
free_buff_out(buf_out);
out_free_buf_in:
free_buff_in(buf_in);
return (long)ret;
}
static int nictool_k_open(struct inode *pnode, struct file *pfile)
{
return 0;
}
static ssize_t nictool_k_read(struct file *pfile, char __user *ubuf,
size_t size, loff_t *ppos)
{
pr_info("%s read *ppos:%lld size = %d\n", __func__, *ppos, (int)size);
return 0;
}
static ssize_t nictool_k_write(struct file *pfile, const char __user *ubuf,
size_t size, loff_t *ppos)
{
pr_info("%s write *ppos:%lld size = %d\n", __func__, *ppos, (int)size);
return 0;
}
int nictool_k_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
if (ret)
return -EIO;
return 0;
}
static const struct file_operations fifo_operations = {
.owner = THIS_MODULE,
.open = nictool_k_open,
.read = nictool_k_read,
.write = nictool_k_write,
.unlocked_ioctl = nictool_k_unlocked_ioctl,
.mmap = nictool_k_mmap,
};
int if_nictool_exist(void)
{
struct file *fp = NULL;
int exist = 0;
fp = filp_open("/dev/nic_dev", O_RDONLY, 0);
if (IS_ERR(fp)) {
exist = 0;
} else {
(void)filp_close(fp, NULL);
exist = 1;
}
return exist;
}
int nictool_k_init(void)
{
int ret;
struct device *pdevice;
if (g_nictool_init_flag) {
g_nictool_ref_cnt++;
return 0;
}
if (if_nictool_exist()) {
pr_info("dev/nic_dev is existed!\n");
return 0;
}
ret = alloc_chrdev_region(&g_dev_id, 0, 1, "nic_dev");
if (ret < 0) {
pr_err("alloc_chrdev_region fail, ret = %d.\n", ret);
return ret;
}
g_nictool_class = class_create(THIS_MODULE, "nic_class");
if (IS_ERR(g_nictool_class)) {
pr_err("class create fail.\n");
ret = -EFAULT;
goto class_create_err;
}
cdev_init(&g_nictool_cdev, &fifo_operations);
ret = cdev_add(&g_nictool_cdev, g_dev_id, 1);
if (ret < 0) {
pr_err("cdev_add fail, ret = %d.\n", ret);
goto cdev_add_err;
}
pdevice = device_create(g_nictool_class, NULL, g_dev_id, NULL,
"nic_dev");
if (IS_ERR(pdevice)) {
pr_err("device_create fail.\n");
goto device_create_err;
}
g_nictool_init_flag = 1;
g_nictool_ref_cnt = 1;
pr_info("register nictool_dev to system, ok!\n");
return 0;
device_create_err:
cdev_del(&g_nictool_cdev);
cdev_add_err:
class_destroy(g_nictool_class);
class_create_err:
g_nictool_class = NULL;
unregister_chrdev_region(g_dev_id, 1);
return ret;
}
void nictool_k_uninit(void)
{
if (g_nictool_init_flag) {
if ((--g_nictool_ref_cnt))
return;
}
if (!g_nictool_class || IS_ERR(g_nictool_class))
return;
cdev_del(&g_nictool_cdev);
device_destroy(g_nictool_class, g_dev_id);
class_destroy(g_nictool_class);
g_nictool_class = NULL;
unregister_chrdev_region(g_dev_id, 1);
pr_info("unregister nictool_dev ok!\n");
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef HNS3_NICTOOL_H_
#define HNS3_NICTOOL_H_
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
/* completion overtime in (unit of) jiffies */
#define UP_COMP_TIME_OUT_VAL 10000U
#define UCODE_COMP_TIME_OUT_VAL 0xFF00000
#define NIC_TOOL_MAGIC 'x'
enum module_name {
SEND_TO_DRIVER = 1,
};
enum driver_cmd_type {
FW_VER = 1,
DRIVER_VER,
CHECKSUM_CFG,
RX_CS_STATISTICS_INFO,
CLEAN_STASTICS,
MAX_TSO_SIZE,
FUNC_TYPE,
TM_QUEUE_CFG = 100,
TM_QSET_CFG,
TM_PRI_CFG,
TM_PG_CFG,
TM_PORT_CFG,
TM_ETS_CFG,
DCB_MODE_CFG = 150,
ETS_MODE_CFG,
PFC_MODE_CFG,
MAC_LOOP_CFG = 200,
DFX_INFO_CMD = 250,
DFX_READ_CMD = 251,
SEND_PKT = 300,
RECV_PKT,
RX_PRIV_BUFF_WL_CFG = 400,
RX_COMMON_THRD_CFG,
RX_COMMON_WL_CFG,
MAC_PAUSE_EN_CFG,
PFC_PAUSE_EN_CFG,
MAC_PAUSE_PARAM_CFG,
SHOW_PAUSE_CFG,
SHOW_PRI_MAP_CFG,
SHOW_RX_PRIV_WL,
SHOW_RX_COMM_THRES,
TX_BUFF_CFG,
RX_BUFF_CFG,
SHOW_TX_QUEUE_TO_TC,
L2_PFC_CFG,
QCN_EN_CFG,
RESET_CFG = 500,
RAS_RESET_CFG = 501,
TIMEOUT_CFG = 550,
CLEAN_STATS = 600,
PROMISC_MODE_CFG = 700,
QINFO_CFG = 800,
MACTABLE_CFG = 900,
PHY_REGISTER_CFG = 1000,
FD_CFG,
RSS_GENERIC_CFG,
REG_CFG,
COM_REG_CFG,
GRO_CFG,
LAMP_CFG,
M7_CMD_MODE_CFG, /* M7 cmd */
QRES_CFG = 1100,
STAT_CFG,
IRQ_CFG,
VLAN_UPMAPPING = 1200,
EXTERN_INTERFACE_CFG = 1300, /* extern interface test */
XSFP_CFG = 1400,
SHOW_PORT_INFO,
SHOW_HILINK_PARAM,
DCQCN_PARM_CFG = 1500,
DCQCN_GET_MSG_CNT_CMD = 1600
};
#define API_CMD (0x1)
#define API_CHAIN (0x2)
struct msg_module {
char device_name[IFNAMSIZ];
unsigned int module;
u32 msg_formate; /* cmd type for driver */
struct {
u32 in_buff_len;
u32 out_buff_len;
} len_info;
u32 res;
void *in_buff;
void *out_buf;
};
#define OUTER_L3_CHECK_EN 0x1
#define OUTER_UDP_CHECK_EN 0x1
#define INNER_L3_CHECK_EN 0x1
#define INNER_TCP_CHECK_EN 0x1
#define INNER_UDP_CHECK_EN 0x1
#define INNER_SCTP_CHECK_EN 0x1
enum {
DCQCN_MASK_AI = 0x0,
DCQCN_MASK_F,
DCQCN_MASK_TKP,
DCQCN_MASK_TMP,
DCQCN_MASK_ALP,
DCQCN_MASK_G,
DCQCN_MASK_AL,
DCQCN_MASK_MAX_SPEED,
DCQCN_MASK_CNP_TIME,
DCQCN_MASK_ALP_SHIFT,
};
#define HINICADM_DCQCN_READ_CFG_MODE 30
#define HINICADM_DCQCN_WRITE_CFG_MODE 31
enum {
CKS_OUTER_L3_EN = 0,
CKS_OUTER_UDP_EN,
CKS_INNER_L3_EN,
CKS_INNER_TCP_EN,
CKS_INNER_UDP_EN,
CKS_INNER_SCTP_EN,
CKS_MAX,
};
int nictool_k_init(void);
void nictool_k_uninit(void);
struct hns3_chs_param {
u8 is_set;
u8 type;
u8 is_enable;
};
struct hns3_test_commit_id_param {
u8 commit_id[8];
u32 ncl_version;
u32 rsv[3];
};
struct firmware_ver_param {
u32 imp_ver;
u8 commit_id[9];
u8 rsv[3];
u32 ncl_version;
};
#define HCLGE_OPC_GRO_AGE_CFG 0x0c11
struct hclge_gro_age_config_cmd {
u32 ppu_gro_age_cnt;
u8 rsv[20];
};
struct gro_param {
u8 is_read;
u32 age_cnt;
};
struct cfg_dcqcn_param {
u16 ai;
u8 f;
u8 tkp;
u16 tmp;
u16 alp;
u32 max_speed;
u8 g;
u8 al;
u8 cnp_time;
u8 alp_shift;
u16 dcqcn_parm_opcode;
u16 is_get;
u32 device_number;
};
struct dcqcn_statistic_param {
u32 dcqcn_rx_cnt;
u32 dcqcn_tx_cnt;
u32 dcqcn_db_cnt;
u32 dcqcn_statistic_enable;
};
enum DEVMEM_RW_TYPE {
DEVMEM_CFG_WRITE = 0,
DEVMEM_CFG_READ,
};
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy_fixed.h>
#include <linux/platform_device.h>
#include "hclge_cmd.h"
#include "hclge_main.h"
#include "hnae3.h"
#include "hns3_enet.h"
#include "hns3_priv_common_test.h"
static int hns3_test_write_reg_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct reg_param *in_buf = (struct reg_param *)buf_in;
enum hclge_cmd_status status;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
if (in_buf->bits_width == 64) {
hclge_cmd_setup_basic_desc(&desc, CMDQ_64_COM_CMD_OPCODE,
false);
desc.data[0] = in_buf->addr;
desc.data[1] = in_buf->data[0];
} else {
hclge_cmd_setup_basic_desc(&desc, CMDQ_32_COM_CMD_OPCODE,
false);
desc.data[0] = in_buf->addr;
desc.data[2] = in_buf->data[0];
}
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev, "%s fail, status is %d.\n", __func__,
status);
return status;
}
return 0;
}
static int hns3_test_read_reg_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct reg_ret_param *out_buf = (struct reg_ret_param *)buf_out;
struct reg_param *in_buf = (struct reg_param *)buf_in;
struct hnae3_handle *handle = net_priv->ae_handle;
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
enum hclge_cmd_status status;
struct hclge_desc desc;
if (in_buf->bits_width == 64)
hclge_cmd_setup_basic_desc(&desc, CMDQ_64_COM_CMD_OPCODE, true);
else
hclge_cmd_setup_basic_desc(&desc, CMDQ_32_COM_CMD_OPCODE, true);
desc.data[0] = in_buf->addr;
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev, "%s fail, status is %d.\n", __func__,
status);
return status;
}
out_buf->value[0] = desc.data[0];
if (in_buf->bits_width == 64)
out_buf->value[1] = desc.data[1];
return 0;
}
int hns3_test_reg_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct reg_param *mode_param = (struct reg_param *)buf_in;
int ret;
if (!mode_param) {
pr_err("%s error: mode_param NULL.\n", __func__);
return -EINVAL;
}
if (mode_param->is_read == 1)
ret = hns3_test_read_reg_cfg(net_priv, buf_in, in_size,
buf_out, out_size);
else
ret = hns3_test_write_reg_cfg(net_priv, buf_in, in_size,
buf_out, out_size);
return ret;
}
static int hns3_reg_read_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct com_reg_param *out_buf = (struct com_reg_param *)buf_out;
struct com_reg_param *in_buf = (struct com_reg_param *)buf_in;
struct hnae3_handle *handle = net_priv->ae_handle;
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
enum hclge_cmd_status status;
struct hclge_desc desc;
int i;
hclge_cmd_setup_basic_desc(&desc, in_buf->fw_dw_opcode,
in_buf->is_read);
for (i = 0; i < 6; i++)
desc.data[i] = in_buf->reg_desc.data[i];
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev, "%s, status is %d.\n", __func__,
status);
return status;
}
for (i = 0; i < 6; i++)
out_buf->reg_desc.data[i] = desc.data[i];
return 0;
}
static int hns3_reg_write_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
enum hclge_cmd_status status;
struct com_reg_param *in_buf = (struct com_reg_param *)buf_in;
int i;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
hclge_cmd_setup_basic_desc(&desc, in_buf->fw_dw_opcode,
in_buf->is_read);
for (i = 0; i < 6; i++)
desc.data[i] = in_buf->reg_desc.data[i];
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev, "%s, status is %d.\n", __func__,
status);
return status;
}
return 0;
}
int hns3_reg_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
int ret = 0;
struct com_reg_param *param;
param = (struct com_reg_param *)buf_in;
if (!param) {
pr_err("%s error: param NULL.\n", __func__);
return -EINVAL;
}
if (param->is_read == 1)
ret = hns3_reg_read_cfg(net_priv, buf_in, in_size, buf_out,
out_size);
else
ret = hns3_reg_write_cfg(net_priv, buf_in, in_size, buf_out,
out_size);
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_COMMON_TEST_H
#define __HNS3_PRIV_COMMON_TEST_H
#define REG_RDATA_NUM 2
#define CMDQ_32_COM_CMD_OPCODE 0xfffd
#define CMDQ_64_COM_CMD_OPCODE 0xffff
struct reg_param {
u32 addr;
u32 data[REG_RDATA_NUM];
u8 bits_width;
u8 is_read;
};
struct reg_ret_param {
u32 value[REG_RDATA_NUM];
};
struct cmd_desc {
u16 opcode;
u16 flag;
u16 retval;
u16 rsv;
u32 data[6];
};
struct com_reg_param {
struct cmd_desc reg_desc;
u32 fw_dw_opcode;
u32 is_read;
};
int hns3_test_reg_cfg(struct hns3_nic_priv *net_priv, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_reg_cfg(struct hns3_nic_priv *net_priv, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kthread.h>
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hclge_tm.h"
#include "hclge_cmd.h"
#include "hns3_priv_dcb.h"
struct nictool_dcb_info dcb_all_info[20];
u8 curr_dev_index;
u8 max_index;
static void check_and_set_curr_dev(struct hns3_nic_priv *net_priv)
{
int flag = false;
int i;
for (i = 0; i < max_index; i++) {
if (dcb_all_info[i].net_priv != net_priv)
continue;
flag = true;
curr_dev_index = i;
}
if (!flag) {
max_index++;
curr_dev_index = max_index - 1;
dcb_all_info[curr_dev_index].net_priv = net_priv;
}
}
int hns3_test_dcb_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct nictool_dcb_cfg_param *in_info;
struct nictool_dcb_cfg_param *out_info;
in_info = (struct nictool_dcb_cfg_param *)buf_in;
out_info = (struct nictool_dcb_cfg_param *)buf_out;
check_and_set_curr_dev(net_priv);
if (!in_info) {
pr_err("in_info should not be NULL in %s funciton\n", __func__);
return -1;
}
if (in_info->is_read) {
out_info->dcb_en =
dcb_all_info[curr_dev_index].dcb_cfg_info.dcb_en;
} else {
if (in_info->cfg_flag & NICTOOL_DCB_DCB_CFG_FLAG)
dcb_all_info[curr_dev_index].dcb_cfg_info.dcb_en =
in_info->dcb_en;
}
return 0;
}
static int hns3_test_cfg_pfc_en(u8 is_read, struct hclge_dev *hdev,
struct nictool_pfc_cfg_param *info)
{
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, NICTOOL_OPC_CFG_PFC_PAUSE_EN, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
pr_err("read pfc enable status fail!ret = %d\n", ret);
return ret;
}
if (is_read) {
info->prien = ((desc.data[0] & 0xff00) >> 8);
info->pfc_en = ((desc.data[0] & 0x3) == 0x3);
} else {
hclge_cmd_reuse_desc(&desc, false);
if (info->cfg_flag & NICTOOL_PFC_EN_CFG_FLAG) {
desc.data[0] = (desc.data[0] & (~0x3)) |
(info->pfc_en << 0) |
(info->pfc_en << 1);
dcb_all_info[curr_dev_index].pfc_cfg_info.pfc_en =
info->pfc_en;
}
if (info->cfg_flag & NICTOOL_PFC_PRIEN_CFG_FLAG) {
desc.data[0] = (desc.data[0] & (~0xff00)) |
(info->prien << 8);
dcb_all_info[curr_dev_index].pfc_cfg_info.prien =
info->prien;
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
pr_err("set pfc cmd return fail!ret = %d\n", ret);
return ret;
}
}
return ret;
}
static int hns3_test_cfg_pause_param(struct hclge_dev *hdev,
struct nictool_pfc_cfg_param *info,
u8 is_read)
{
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, NICTOOL_OPC_CFG_PAUSE_PARAM, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
pr_err("pause param cfg cmd send fail\n");
return ret;
}
if (is_read) {
info->pause_time = desc.data[2] & 0xffff;
info->pause_gap = (desc.data[1] & 0xff0000) >> 16;
return 0;
}
if (info->cfg_flag & NICTOOL_PFC_TIME_CFG_FLAG)
desc.data[2] = (desc.data[2] & (~0xffff)) | info->pause_time;
if (info->cfg_flag & NICTOOL_PFC_GAP_CFG_FLAG)
desc.data[1] = (desc.data[1] & (~0xff0000)) |
(info->pause_gap << 16);
hclge_cmd_reuse_desc(&desc, false);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"mac pause param cfg fail, ret = %d.\n", ret);
return ret;
}
return 0;
}
int hns3_test_dcb_pfc_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct nictool_pfc_cfg_param *out_info;
struct nictool_pfc_cfg_param *in_info;
struct net_device *ndev;
struct hclge_vport *vport;
struct hnae3_handle *h;
struct hclge_dev *hdev;
int ret;
check_and_set_curr_dev(net_priv);
h = net_priv->ae_handle;
vport = hclge_get_vport(h);
ndev = h->netdev;
hdev = vport->back;
in_info = (struct nictool_pfc_cfg_param *)buf_in;
out_info = (struct nictool_pfc_cfg_param *)buf_out;
if (!in_info) {
pr_err("in_info should not be NULL in %s function\n", __func__);
return -1;
}
if (!in_info->is_read &&
!dcb_all_info[curr_dev_index].dcb_cfg_info.dcb_en) {
pr_err("please enable dcb cfg first!\n");
return -1;
}
if (!hnae3_dev_dcb_supported(hdev) || vport->vport_id != 0) {
pr_err("this device doesn't support dcb!\n");
return -1;
}
if (in_info->is_read) {
ret = hns3_test_cfg_pfc_en(in_info->is_read, hdev, out_info);
if (ret)
return ret;
ret = hns3_test_cfg_pause_param(hdev, out_info, true);
if (ret)
return ret;
} else {
struct ieee_pfc pfc = {0};
if (in_info->cfg_flag & NICTOOL_PFC_PRIEN_CFG_FLAG) {
pfc.pfc_en = in_info->prien;
dcb_all_info[curr_dev_index].pfc_cfg_info.prien =
in_info->prien;
if (ndev->dcbnl_ops->ieee_setpfc) {
rtnl_lock();
ret = ndev->dcbnl_ops->ieee_setpfc(ndev, &pfc);
rtnl_unlock();
if (ret)
return ret;
}
}
if ((in_info->cfg_flag & NICTOOL_PFC_TIME_CFG_FLAG) ||
(in_info->cfg_flag & NICTOOL_PFC_GAP_CFG_FLAG)) {
ret = hns3_test_cfg_pause_param(hdev, in_info, false);
if (ret)
return ret;
}
}
return 0;
}
static void hns3_test_disable_ets_cfg(struct hclge_dev *hdev,
struct ieee_ets *ets)
{
u8 percent = 0;
int i;
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++) {
ets->prio_tc[i] = hdev->tm_info.prio_tc[i];
ets->tc_tsa[i] = IEEE_8021QAZ_TSA_ETS;
dcb_all_info[curr_dev_index].ets_cfg_info.schedule[i] = 0;
}
for (i = 0; i < hdev->tm_info.num_tc; i++) {
ets->tc_tx_bw[i] = 100 / hdev->tm_info.num_tc;
dcb_all_info[curr_dev_index].ets_cfg_info.bw[i] =
ets->tc_tx_bw[i];
percent += ets->tc_tx_bw[i];
}
if (percent != 100) {
ets->tc_tx_bw[i - 1] += (100 - percent);
dcb_all_info[curr_dev_index].ets_cfg_info.bw[i - 1] =
ets->tc_tx_bw[i - 1];
}
}
static void hns3_test_enable_ets_cfg(struct hclge_dev *hdev,
struct ieee_ets *ets,
struct nictool_ets_cfg_param *info)
{
int i;
if (info->cfg_flag & NICTOOL_ETS_UP2TC_CFG_FLAG) {
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++) {
ets->prio_tc[i] = info->up2tc[i];
dcb_all_info[curr_dev_index].ets_cfg_info.up2tc[i] =
info->up2tc[i];
}
} else {
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++)
ets->prio_tc[i] = hdev->tm_info.prio_tc[i];
}
if (info->cfg_flag & NICTOOL_ETS_BANDWIDTH_CFG_FLAG) {
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++) {
ets->tc_tx_bw[i] = info->bw[i];
dcb_all_info[curr_dev_index].ets_cfg_info.bw[i] =
info->bw[i];
}
} else {
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++)
ets->tc_tx_bw[i] = hdev->tm_info.pg_info[0].tc_dwrr[i];
}
if (info->cfg_flag & NICTOOL_ETS_SCHEDULE_CFG_FLAG) {
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++) {
ets->tc_tsa[i] = info->schedule[i] ?
IEEE_8021QAZ_TSA_STRICT : IEEE_8021QAZ_TSA_ETS;
dcb_all_info[curr_dev_index].ets_cfg_info.schedule[i] =
info->schedule[i];
}
} else {
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++)
ets->tc_tsa[i] = hdev->tm_info.tc_info[i].tc_sch_mode ?
IEEE_8021QAZ_TSA_ETS : IEEE_8021QAZ_TSA_STRICT;
}
}
int hns3_test_dcb_ets_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct nictool_ets_cfg_param *out_info;
struct nictool_ets_cfg_param *in_info;
struct hclge_vport *vport;
struct net_device *ndev;
struct hclge_dev *hdev;
struct hclge_desc desc;
struct hnae3_handle *h;
int ret;
int i;
check_and_set_curr_dev(net_priv);
h = net_priv->ae_handle;
vport = hclge_get_vport(h);
ndev = h->netdev;
hdev = vport->back;
in_info = (struct nictool_ets_cfg_param *)buf_in;
out_info = (struct nictool_ets_cfg_param *)buf_out;
if (!in_info) {
pr_err("in_info should not be NULL in %s function\n", __func__);
return -1;
}
if (!in_info->is_read &&
!dcb_all_info[curr_dev_index].dcb_cfg_info.dcb_en) {
pr_err("please enable dcb cfg first!\n");
return -1;
}
if (!hnae3_dev_dcb_supported(hdev) || vport->vport_id != 0) {
pr_err("this device doesn't support dcb!\n");
return -1;
}
if (in_info->is_read) {
hclge_cmd_setup_basic_desc(&desc,
NICTOOL_OPC_PRI_TO_TC_MAPPING, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
pr_err("read up2tc mapping fail!\n");
return ret;
}
out_info->ets_en =
dcb_all_info[curr_dev_index].ets_cfg_info.ets_en;
for (i = 0; i < NICTOOL_ETS_MAC_TC_NUM; i++) {
out_info->up2tc[i] =
(desc.data[0] & (0xf << (4 * i))) >> (4 * i);
dcb_all_info[curr_dev_index].ets_cfg_info.up2tc[i] =
out_info->up2tc[i];
out_info->bw[i] = hdev->tm_info.pg_info[0].tc_dwrr[i];
dcb_all_info[curr_dev_index].ets_cfg_info.bw[i] =
hdev->tm_info.pg_info[0].tc_dwrr[i];
out_info->schedule[i] =
!hdev->tm_info.tc_info[i].tc_sch_mode;
dcb_all_info[curr_dev_index].ets_cfg_info.schedule[i] =
!hdev->tm_info.tc_info[i].tc_sch_mode;
}
} else {
struct ieee_ets ets = {0};
if (in_info->cfg_flag & NICTOOL_ETS_EN_CFG_FLAG)
dcb_all_info[curr_dev_index].ets_cfg_info.ets_en =
in_info->ets_en;
if (!dcb_all_info[curr_dev_index].ets_cfg_info.ets_en)
hns3_test_disable_ets_cfg(hdev, &ets);
else
hns3_test_enable_ets_cfg(hdev, &ets, in_info);
if (ndev->dcbnl_ops->ieee_setets) {
rtnl_lock();
ret = ndev->dcbnl_ops->ieee_setets(ndev, &ets);
rtnl_unlock();
if (ret)
return ret;
}
out_info->cfg_flag = in_info->cfg_flag;
out_info->is_read = in_info->is_read;
out_info->ets_en =
dcb_all_info[curr_dev_index].ets_cfg_info.ets_en;
}
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_DCB_H__
#define __HNS3_PRIV_DCB_H__
struct nictool_pfc_cfg_param {
u8 is_read;
u8 cfg_flag;
u8 pfc_en;
u8 prien;
u16 pause_time;
u8 pause_gap;
};
struct nictool_dcb_cfg_param {
u8 is_read;
u8 cfg_flag;
u8 dcb_en;
};
struct nictool_ets_cfg_param {
u8 is_read;
u8 cfg_flag;
u8 ets_en;
u8 up2tc[8];
u8 bw[8];
u8 schedule[8];
};
struct nictool_dcb_info {
struct hns3_nic_priv *net_priv;
struct nictool_pfc_cfg_param pfc_cfg_info;
struct nictool_dcb_cfg_param dcb_cfg_info;
struct nictool_ets_cfg_param ets_cfg_info;
};
#define NICTOOL_OPC_CFG_MAC_PAUSE_EN 0x0701
#define NICTOOL_OPC_CFG_PFC_PAUSE_EN 0x0702
#define NICTOOL_OPC_CFG_PAUSE_PARAM 0x0703
#define NICTOOL_OPC_PRI_TO_TC_MAPPING 0x0709
#define NICTOOL_OPC_TM_PRI_WEIGHT 0x080b
#define NICTOOL_DCB_DCB_CFG_FLAG 0x1
#define NICTOOL_ETS_EN_CFG_FLAG 0x1
#define NICTOOL_ETS_UP2TC_CFG_FLAG 0x2
#define NICTOOL_ETS_BANDWIDTH_CFG_FLAG 0x4
#define NICTOOL_ETS_SCHEDULE_CFG_FLAG 0x8
#define NICTOOL_ETS_MAC_TC_NUM 8
#define NICTOOL_PFC_EN_CFG_FLAG 0x1
#define NICTOOL_PFC_PRIEN_CFG_FLAG 0x2
#define NICTOOL_PFC_TIME_CFG_FLAG 0x4
#define NICTOOL_PFC_GAP_CFG_FLAG 0x8
#define NICTOOL_PFC_MAC_PRI 8
int hns3_test_dcb_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
int hns3_test_dcb_ets_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_dcb_pfc_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/phy_fixed.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_dfx.h"
static int hns3_test_operate_nic_regs(struct hclge_dev *hdev,
struct hns3_test_reg_param *info)
{
struct hclge_desc desc;
int ret;
if (info->is_read) {
hclge_cmd_setup_basic_desc(&desc, OPC_WRITE_READ_REG_CMD, true);
desc.data[0] = (u32)(info->addr & 0xffffffff);
desc.data[1] = (u32)(info->addr >> 32);
desc.data[4] = (u32)info->bit_width;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"read addr 0x%llx failed! ret = %d.\n",
info->addr, ret);
return ret;
}
info->value = (u64)desc.data[2] | ((u64)desc.data[3] << 32);
} else {
hclge_cmd_setup_basic_desc(&desc, OPC_WRITE_READ_REG_CMD,
false);
desc.data[0] = (u32)(info->addr & 0xffffffff);
desc.data[1] = (u32)(info->addr >> 32);
desc.data[2] = (u32)(info->value & 0xffffffff);
desc.data[3] = (u32)(info->value >> 32);
desc.data[4] = (u32)info->bit_width;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"write addr 0x%llx value 0x%llx failed! ret = %d.\n",
info->addr, info->value, ret);
return ret;
}
}
return 0;
}
static int hns3_test_get_chip_and_mac_id(struct hnae3_handle *handle,
u32 *chip_id, u32 *mac_id)
{
#define HNS3_TEST_GET_CHIP_MAC_ID_CMD 0x7003
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HNS3_TEST_GET_CHIP_MAC_ID_CMD, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "get chip id and mac id failed %d\n",
ret);
return ret;
}
*chip_id = desc.data[0];
*mac_id = desc.data[1];
return 0;
}
int hns3_test_get_dfx_info(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
#define HNS3_TEST_MAC_MODE_ADDR 0x130000000U
#define HNS3_TEST_MAC_MAP_ADDR 0x130000008U
struct hns3_test_dfx_param *out_info;
struct hns3_test_reg_param reg_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u32 chip_id;
u32 mac_id;
int ret;
int i;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
out_info = (struct hns3_test_dfx_param *)buf_out;
ret = hns3_test_get_chip_and_mac_id(handle, &chip_id, &mac_id);
if (ret)
return ret;
out_info->chip_id = (u8)chip_id;
out_info->mac_id = (u8)mac_id;
out_info->func_id = (u8)hdev->pdev->devfn;
out_info->is_cs_board =
(handle->pdev->revision > HNAE3_REVISION_ID_20) ? true : false;
reg_info.addr = HNS3_TEST_MAC_MODE_ADDR;
reg_info.bit_width = 32;
reg_info.is_read = true;
ret = hns3_test_operate_nic_regs(hdev, &reg_info);
if (ret) {
pr_err("read chip%d's work mode failed!\n", chip_id);
return ret;
}
out_info->work_mode = reg_info.value;
reg_info.addr = HNS3_TEST_MAC_MAP_ADDR;
reg_info.bit_width = 64;
reg_info.is_read = true;
ret = hns3_test_operate_nic_regs(hdev, &reg_info);
if (ret) {
pr_err("read mac's map info failed!\n");
return ret;
}
for (i = 0; i < HNS3_TEST_MAX_MAC_NUMBER; i++)
out_info->mac_used |= ((reg_info.value >> (i * 8)) & 0xff);
return 0;
}
int hns3_test_read_dfx_info(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hns3_test_reg_param *out_info;
struct hns3_test_reg_param *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
int ret;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct hns3_test_reg_param *)buf_in;
out_info = (struct hns3_test_reg_param *)buf_out;
if (in_info->is_read) {
out_info->addr = in_info->addr;
out_info->is_read = true;
out_info->bit_width = in_info->bit_width;
ret = hns3_test_operate_nic_regs(hdev, out_info);
if (ret)
return ret;
} else {
ret = hns3_test_operate_nic_regs(hdev, in_info);
if (ret)
return ret;
}
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_DFX_H
#define __HNS3_PRIV_DFX_H
#define OPC_WRITE_READ_REG_CMD 0x7014
struct hns3_test_reg_param {
u8 is_read;
u8 bit_width;
u64 value;
u64 addr;
};
struct hns3_test_dfx_param {
u8 is_cs_board;
u8 work_mode;
u8 mac_used;
u8 chip_id;
u8 mac_id;
u8 func_id;
};
#define HNS3_READ_INFO_FLAG 0x1
#define HNS3_READ_REGS_FLAG 0x2
#define HNS3_TEST_MAX_MAC_NUMBER 0x8
int hns3_test_get_dfx_info(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_read_dfx_info(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hns3_priv_ext.h"
#include "hns3_ext.h"
static int hns3_ext_test_disable_netclk(struct hns3_nic_priv *net_priv)
{
struct net_device *netdev = net_priv->netdev;
return nic_disable_clock(netdev);
}
static int hns3_get_cpu_affinity(struct hns3_nic_priv *priv)
{
struct hns3_enet_tqp_vector *tqp_vector;
struct hnae3_handle *h;
int i;
if (!priv) {
pr_err("invalid input param when get cpu affinity\n");
return -EINVAL;
}
h = priv->ae_handle;
if (nic_netdev_match_check(priv->netdev))
return -ENODEV;
pr_info("%s : %d irq total.\n", h->pdev->driver->name,
priv->vector_num);
for (i = 0; i < priv->vector_num; i++) {
tqp_vector = &priv->tqp_vector[i];
if (tqp_vector->irq_init_flag != HNS3_VECTOR_INITED)
continue;
pr_err("irq %d ==> cpu affinity: %*pb\n",
tqp_vector->vector_irq,
cpumask_pr_args(&tqp_vector->affinity_mask));
}
return 0;
}
static int hns3_ext_test_affi(struct hns3_nic_priv *net_priv, void *in)
{
struct hns3_cpumask_param *cpumask_param;
cpumask_var_t cpumask_new;
int ret;
cpumask_param = (struct hns3_cpumask_param *)in;
if (cpumask_param->affi_exec_flag != HNS3_AFFI_GET_BIT) {
if (!alloc_cpumask_var(&cpumask_new, GFP_KERNEL))
return -ENOMEM;
ret = cpumask_parse(cpumask_param->mask, cpumask_new);
if (ret) {
pr_err("parse cpu affinity from user fail, ret = %d\n",
ret);
return ret;
}
ret = nic_set_cpu_affinity(net_priv->netdev, cpumask_new);
if (ret) {
pr_err("set cpu affinity fail, ret = %d\n", ret);
return ret;
}
} else {
ret = hns3_get_cpu_affinity(net_priv);
if (ret) {
pr_err("get cpu affinity fail, ret = %d\n", ret);
return ret;
}
}
return ret;
}
static int hns3_ext_test_get_chipid(struct hns3_nic_priv *net_priv,
void *out, u16 *out_size)
{
u32 chip_id;
int ret;
struct net_device *netdev = net_priv->netdev;
ret = nic_get_chipid(netdev, &chip_id);
if (!ret) {
*(u32 *)out = chip_id;
*out_size = sizeof(chip_id);
}
return ret;
}
static int hns3_ext_test_match_check(struct hns3_nic_priv *net_priv)
{
struct net_device *netdev = net_priv->netdev;
return nic_netdev_match_check(netdev);
}
static int hns3_ext_test_set_led(struct hns3_nic_priv *net_priv, void *in)
{
struct hns3_led_state_para *para = (struct hns3_led_state_para *)in;
struct net_device *netdev = net_priv->netdev;
return nic_set_led(netdev, para->type, para->status);
}
static int hns3_ext_test_get_sfp_info(struct hns3_nic_priv *net_priv, void *in,
void *out, u16 *out_size)
{
struct hns3_priv_sfp_info_para *para_in =
(struct hns3_priv_sfp_info_para *)in;
struct hns3_priv_sfp_info_para *para_out =
(struct hns3_priv_sfp_info_para *)out;
struct net_device *netdev = net_priv->netdev;
int ret;
ret = nic_get_sfpinfo(netdev, para_out->buff, para_in->size,
&para_out->outlen);
if (!ret)
*out_size = para_out->outlen;
return ret;
}
static int hns3_ext_test_get_sfp_present(struct hns3_nic_priv *net_priv,
void *out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
u32 present;
int ret;
ret = nic_get_sfp_present(netdev, &present);
if (!ret) {
*(u32 *)out = present;
*out_size = sizeof(present);
}
return ret;
}
static int hns3_ext_test_set_sfp_state(struct hns3_nic_priv *net_priv, void *in)
{
struct net_device *netdev = net_priv->netdev;
bool en = *(bool *)in;
return nic_set_sfp_state(netdev, en);
}
static int hns3_ext_test_clean_stats64(struct hns3_nic_priv *net_priv)
{
struct net_device *netdev = net_priv->netdev;
return nic_clean_stats64(netdev, NULL);
}
static int hns3_ext_test_get_chip_num(struct hns3_nic_priv *net_priv,
void *out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
u32 chip_num;
int ret;
ret = nic_get_chip_num(netdev, &chip_num);
if (!ret) {
*(u32 *)out = chip_num;
*out_size = sizeof(chip_num);
}
return ret;
}
static int hns3_ext_test_get_port_num(struct hns3_nic_priv *net_priv,
void *out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
u32 port_num;
int ret;
ret = nic_get_port_num_per_chip(netdev, &port_num);
if (!ret) {
*(u32 *)out = port_num;
*out_size = sizeof(port_num);
}
return ret;
}
static int hns3_ext_test_disable_net_lane(struct hns3_nic_priv *net_priv)
{
struct net_device *netdev = net_priv->netdev;
return nic_disable_net_lane(netdev);
}
static int hns3_ext_test_get_lane_status(struct hns3_nic_priv *net_priv,
void *out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
u32 lane_status;
int ret;
ret = nic_get_net_lane_status(netdev, &lane_status);
if (!ret) {
*(u32 *)out = lane_status;
*out_size = lane_status;
}
return ret;
}
static int hns3_ext_test_set_mac_state(struct hns3_nic_priv *net_priv, void *in)
{
struct net_device *netdev = net_priv->netdev;
int enable = *(int *)in;
return nic_set_mac_state(netdev, enable);
}
static int hns3_ext_test_set_pfc_storm_para(struct hns3_nic_priv *net_priv,
void *in)
{
struct hns3_pfc_storm_para *para = (struct hns3_pfc_storm_para *)in;
struct net_device *netdev = net_priv->netdev;
return nic_set_pfc_storm_para(netdev, para->dir, para->enable,
para->period_ms, para->times,
para->recovery_period_ms);
}
static int hns3_ext_test_get_pfc_storm_para(struct hns3_nic_priv *net_priv,
void *in, void *out, u16 *out_size)
{
struct hns3_pfc_storm_para *para_in = (struct hns3_pfc_storm_para *)in;
struct net_device *netdev = net_priv->netdev;
struct hns3_pfc_storm_para *para_out =
(struct hns3_pfc_storm_para *)out;
u32 recovery_period_ms;
u32 period_ms;
u32 enable;
u32 times;
u32 dir;
int ret;
dir = para_in->dir;
ret = nic_get_pfc_storm_para(netdev, dir, &enable, &period_ms,
&times, &recovery_period_ms);
if (!ret) {
para_out->dir = dir;
para_out->enable = enable;
para_out->period_ms = period_ms;
para_out->times = times;
para_out->recovery_period_ms = recovery_period_ms;
*out_size = sizeof(struct hns3_pfc_storm_para);
}
return ret;
}
static int hns3_ext_test_get_phy_reg(struct hns3_nic_priv *net_priv, void *in,
void *out, u16 *out_size)
{
struct hns3_phy_para *para_out = (struct hns3_phy_para *)out;
struct hns3_phy_para *para_in = (struct hns3_phy_para *)in;
u32 page_select_addr = para_in->page_select_addr;
struct net_device *netdev = net_priv->netdev;
u32 reg_addr = para_in->reg_addr;
u16 page = para_in->page;
u16 data;
int ret;
ret = nic_get_phy_reg(netdev, page_select_addr, page, reg_addr, &data);
if (!ret) {
para_out->page = page;
para_out->reg_addr = reg_addr;
para_out->data = data;
*out_size = sizeof(struct hns3_phy_para);
}
return ret;
}
static int hns3_ext_test_set_phy_reg(struct hns3_nic_priv *net_priv, void *in)
{
struct hns3_phy_para *para = (struct hns3_phy_para *)in;
struct net_device *netdev = net_priv->netdev;
return nic_set_phy_reg(netdev, para->page_select_addr,
para->page, para->reg_addr, para->data);
}
static int hns3_ext_test_get_macid(struct hns3_nic_priv *net_priv,
void *out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
u32 mac_id;
int ret;
ret = nic_get_mac_id(netdev, &mac_id);
if (!ret) {
*(u32 *)out = mac_id;
*out_size = sizeof(mac_id);
}
return ret;
}
static int hns3_ext_test_get_hilink_ref_los(struct hns3_nic_priv *net_priv,
void *out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
u32 status;
int ret;
ret = nic_get_hilink_ref_los(netdev, &status);
if (!ret) {
*(u32 *)out = status;
*out_size = sizeof(status);
}
return ret;
}
int hns3_ext_interface_test(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct cmd_ext_driver_param *ext_param_in;
struct cmd_ext_driver_param *ext_param_out;
void *in;
void *out;
int ret;
ext_param_in = (struct cmd_ext_driver_param *)buf_in;
ext_param_out = (struct cmd_ext_driver_param *)buf_out;
in = ext_param_in->buf;
out = ext_param_out->buf;
switch (ext_param_in->op_code) {
case EXT_AFFI_MASK:
ret = hns3_ext_test_affi(net_priv, in);
break;
case EXT_DISABLE_NET_CLK:
ret = hns3_ext_test_disable_netclk(net_priv);
break;
case EXT_GET_CHIP_ID:
ret = hns3_ext_test_get_chipid(net_priv, out, out_size);
break;
case EXT_NET_MATCH_CHECK:
ret = hns3_ext_test_match_check(net_priv);
break;
case EXT_SET_LED:
ret = hns3_ext_test_set_led(net_priv, in);
break;
case EXT_GET_SFP_INFO:
ret = hns3_ext_test_get_sfp_info(net_priv, in, out, out_size);
break;
case EXT_GET_SFP_PRESENT:
ret = hns3_ext_test_get_sfp_present(net_priv, out, out_size);
break;
case EXT_SET_SFP_STATE:
ret = hns3_ext_test_set_sfp_state(net_priv, in);
break;
case EXT_CLEAN_STATS64:
ret = hns3_ext_test_clean_stats64(net_priv);
break;
case EXT_GET_CHIP_NUM:
ret = hns3_ext_test_get_chip_num(net_priv, out, out_size);
break;
case EXT_GET_PORT_NUM:
ret = hns3_ext_test_get_port_num(net_priv, out, out_size);
break;
case EXT_DISABLE_NET_LANE:
ret = hns3_ext_test_disable_net_lane(net_priv);
break;
case EXT_GET_LANE_STATUS:
ret = hns3_ext_test_get_lane_status(net_priv, out, out_size);
break;
case EXT_SET_MAC_STATE:
ret = hns3_ext_test_set_mac_state(net_priv, in);
break;
case EXT_SET_PFC_STORM_PARA:
ret = hns3_ext_test_set_pfc_storm_para(net_priv, in);
break;
case EXT_GET_PFC_STORM_PARA:
ret = hns3_ext_test_get_pfc_storm_para(net_priv, in,
out, out_size);
break;
case EXT_GET_PHY_REG:
ret = hns3_ext_test_get_phy_reg(net_priv, in, out, out_size);
break;
case EXT_SET_PHY_REG:
ret = hns3_ext_test_set_phy_reg(net_priv, in);
break;
case EXT_GET_MAC_ID:
ret = hns3_ext_test_get_macid(net_priv, out, out_size);
break;
case EXT_GET_HILINK_REF_LOS:
ret = hns3_ext_test_get_hilink_ref_los(net_priv, out, out_size);
break;
default:
ret = -EFAULT;
}
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_EXT_H
#define __HNS3_PRIV_EXT_H
#include "hnae3.h"
#include "hns3_enet.h"
#define HNS3_AFFI_SET_BIT BIT(0)
#define HNS3_AFFI_GET_BIT BIT(1)
#define HNS3_AFFI_MAX_LEN 34
enum ext_op_code {
EXT_AFFI_MASK = 0,
EXT_DISABLE_NET_CLK,
EXT_GET_CHIP_ID,
EXT_NET_MATCH_CHECK,
EXT_SET_LED,
EXT_GET_SFP_INFO,
EXT_GET_SFP_PRESENT,
EXT_SET_SFP_STATE,
EXT_CLEAN_STATS64,
EXT_GET_CHIP_NUM,
EXT_GET_PORT_NUM,
EXT_DISABLE_NET_LANE,
EXT_GET_LANE_STATUS,
EXT_SET_MAC_STATE,
EXT_SET_PFC_STORM_PARA,
EXT_GET_PFC_STORM_PARA,
EXT_GET_PHY_REG,
EXT_SET_PHY_REG,
EXT_GET_MAC_ID,
EXT_GET_HILINK_REF_LOS,
};
struct hns3_cpumask_param {
u32 affi_exec_flag;
char mask[HNS3_AFFI_MAX_LEN];
};
struct hns3_priv_sfp_info_para {
u8 buff[768];
u16 offset;
u16 size;
u16 outlen;
};
struct cmd_ext_driver_param {
u32 op_code;
u32 judge_class;
u8 buf[1024];
};
int hns3_ext_interface_test(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/phy_fixed.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_fd.h"
int hclge_test_send_generic_cmd(struct hclge_dev *hdev, u8 *buf_in,
u16 in_size, u8 *buf_out, u16 *out_size)
{
struct fd_param *param = (struct fd_param *)buf_in;
struct hclge_get_fd_mode_cmd *mode_cfg;
struct hclge_get_fd_mode_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_MODE_CTRL,
param->is_read ? true : false);
req = (struct hclge_get_fd_mode_cmd *)desc.data;
if (!param->is_read) {
mode_cfg = (struct hclge_get_fd_mode_cmd *)param->data;
req->mode = mode_cfg->mode;
req->enable = mode_cfg->enable;
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "set fd mode fail, ret = %d\n", ret);
return ret;
}
if (param->is_read) {
mode_cfg = (struct hclge_get_fd_mode_cmd *)buf_out;
mode_cfg->mode = req->mode;
mode_cfg->enable = req->enable;
*out_size = sizeof(struct hclge_get_fd_mode_cmd);
}
return 0;
}
int hclge_test_send_allocate_cmd(struct hclge_dev *hdev, u8 *buf_in,
u16 in_size, u8 *buf_out, u16 *out_size)
{
struct hclge_get_fd_allocation_cmd *allocation_cfg;
struct hclge_get_fd_allocation_cmd *req;
struct hclge_desc desc;
int ret;
allocation_cfg = (struct hclge_get_fd_allocation_cmd *)buf_out;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_GET_ALLOCATION, true);
req = (struct hclge_get_fd_allocation_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"query fd allocation fail, ret = %d\n",
ret);
return ret;
}
allocation_cfg->stage1_entry_num = req->stage1_entry_num;
allocation_cfg->stage2_entry_num = req->stage2_entry_num;
allocation_cfg->stage1_counter_num = req->stage1_counter_num;
allocation_cfg->stage2_counter_num = req->stage2_counter_num;
*out_size = sizeof(struct hclge_get_fd_allocation_cmd);
return 0;
}
int hclge_test_send_key_cfg_cmd(struct hclge_dev *hdev, u8 *buf_in,
u16 in_size, u8 *buf_out, u16 *out_size)
{
struct fd_param *param = (struct fd_param *)buf_in;
struct hclge_set_fd_key_config_cmd *key_cfg_data;
struct hclge_set_fd_key_config_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_KEY_CONFIG,
param->is_read ? true : false);
req = (struct hclge_set_fd_key_config_cmd *)desc.data;
req->stage = param->stage;
if (!param->is_read) {
key_cfg_data =
(struct hclge_set_fd_key_config_cmd *)param->data;
req->key_select = key_cfg_data->key_select;
req->inner_sipv6_word_en = key_cfg_data->inner_sipv6_word_en;
req->inner_dipv6_word_en = key_cfg_data->inner_dipv6_word_en;
req->outer_sipv6_word_en = key_cfg_data->outer_sipv6_word_en;
req->outer_dipv6_word_en = key_cfg_data->outer_dipv6_word_en;
req->tuple_mask = key_cfg_data->tuple_mask;
req->meta_data_mask = key_cfg_data->meta_data_mask;
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "set fd key fail, ret = %d\n", ret);
return ret;
}
if (param->is_read) {
key_cfg_data = (struct hclge_set_fd_key_config_cmd *)buf_out;
key_cfg_data->key_select = req->key_select;
key_cfg_data->inner_sipv6_word_en = req->inner_sipv6_word_en;
key_cfg_data->inner_dipv6_word_en = req->inner_dipv6_word_en;
key_cfg_data->outer_sipv6_word_en = req->outer_sipv6_word_en;
key_cfg_data->outer_dipv6_word_en = req->outer_dipv6_word_en;
key_cfg_data->tuple_mask = req->tuple_mask;
key_cfg_data->meta_data_mask = req->meta_data_mask;
*out_size = sizeof(struct hclge_set_fd_key_config_cmd);
}
return 0;
}
int hclge_test_send_tcam_op_cmd(struct hclge_dev *hdev, u8 *buf_in,
u16 in_size, u8 *buf_out, u16 *out_size)
{
struct fd_param *param = (struct fd_param *)buf_in;
struct hclge_fd_tcam_config_1_cmd *req1;
struct hclge_fd_tcam_config_2_cmd *req2;
struct hclge_fd_tcam_config_3_cmd *req3;
struct hclge_fd_tcam_data *tcam_data;
struct hclge_desc desc[3];
u8 *buf;
int ret;
hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_FD_TCAM_OP,
param->is_read ? true : false);
desc[0].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_FD_TCAM_OP,
param->is_read ? true : false);
desc[1].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
hclge_cmd_setup_basic_desc(&desc[2], HCLGE_OPC_FD_TCAM_OP,
param->is_read ? true : false);
req1 = (struct hclge_fd_tcam_config_1_cmd *)desc[0].data;
req2 = (struct hclge_fd_tcam_config_2_cmd *)desc[1].data;
req3 = (struct hclge_fd_tcam_config_3_cmd *)desc[2].data;
req1->stage = param->stage;
req1->xy_sel = param->xy_sel;
req1->index = param->idx;
if (!param->is_read) {
req1->entry_vld = param->entry_vld;
tcam_data = (struct hclge_fd_tcam_data *)param->data;
buf = tcam_data->tcam_data;
memcpy(req1->tcam_data, buf, sizeof(req1->tcam_data));
buf += sizeof(req1->tcam_data);
memcpy(req2->tcam_data, buf, sizeof(req2->tcam_data));
buf += sizeof(req2->tcam_data);
memcpy(req3->tcam_data, buf, sizeof(req3->tcam_data));
}
ret = hclge_cmd_send(&hdev->hw, desc, 3);
if (ret) {
dev_err(&hdev->pdev->dev,
"config tcam key fail, ret = %d\n", ret);
return ret;
}
if (param->is_read) {
tcam_data = (struct hclge_fd_tcam_data *)buf_out;
tcam_data->vld = req1->entry_vld;
buf = tcam_data->tcam_data;
memcpy(buf, req1->tcam_data, sizeof(req1->tcam_data));
buf += sizeof(req1->tcam_data);
memcpy(buf, req2->tcam_data, sizeof(req2->tcam_data));
buf += sizeof(req2->tcam_data);
memcpy(buf, req3->tcam_data, sizeof(req3->tcam_data));
*out_size = sizeof(struct hclge_fd_tcam_data);
}
return 0;
}
int hclge_test_send_ad_op_cmd(struct hclge_dev *hdev, u8 *buf_in,
u16 in_size, u8 *buf_out, u16 *out_size)
{
struct fd_param *param = (struct fd_param *)buf_in;
struct hclge_fd_ad_config_cmd *ad_data;
struct hclge_fd_ad_config_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_AD_OP,
param->is_read ? true : false);
req = (struct hclge_fd_ad_config_cmd *)desc.data;
req->stage = param->stage;
req->index = param->idx;
if (!param->is_read) {
ad_data = (struct hclge_fd_ad_config_cmd *)param->data;
memcpy(&req->ad_data, &ad_data->ad_data, sizeof(req->ad_data));
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "fd ad config fail, ret = %d\n", ret);
return ret;
}
if (param->is_read) {
ad_data = (struct hclge_fd_ad_config_cmd *)buf_out;
memcpy(&ad_data->ad_data, &req->ad_data, sizeof(req->ad_data));
*out_size = sizeof(struct hclge_fd_ad_config_cmd);
}
return 0;
}
int hclge_test_send_cnt_op_cmd(struct hclge_dev *hdev, u8 *buf_in,
u16 in_size, u8 *buf_out, u16 *out_size)
{
struct fd_param *param = (struct fd_param *)buf_in;
struct hclge_fd_cnt_op_cmd *cnt_data;
struct hclge_fd_cnt_op_cmd *req;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_CNT_OP, true);
req = (struct hclge_fd_cnt_op_cmd *)desc.data;
req->stage = param->stage;
req->cnt_idx = param->idx;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "read fd cnt fail, ret = %d\n", ret);
return ret;
}
cnt_data = (struct hclge_fd_cnt_op_cmd *)buf_out;
memcpy(&cnt_data->cnt_value, &req->cnt_value, sizeof(req->cnt_value));
*out_size = sizeof(struct hclge_fd_cnt_op_cmd);
return 0;
}
int hns3_test_fd_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct hnae3_handle *handle = net_priv->ae_handle;
struct hclge_vport *vport = hclge_get_vport(handle);
struct fd_param *param = (struct fd_param *)buf_in;
struct hclge_dev *hdev = vport->back;
int ret = -1;
if (!hnae3_dev_fd_supported(hdev))
return -EOPNOTSUPP;
if (param->op == HCLGE_OPC_FD_MODE_CTRL) {
ret = hclge_test_send_generic_cmd(hdev, buf_in, in_size,
buf_out, out_size);
}
if (param->op == HCLGE_OPC_FD_GET_ALLOCATION) {
ret = hclge_test_send_allocate_cmd(hdev, buf_in, in_size,
buf_out, out_size);
}
if (param->op == HCLGE_OPC_FD_KEY_CONFIG) {
ret = hclge_test_send_key_cfg_cmd(hdev, buf_in, in_size,
buf_out, out_size);
}
if (param->op == HCLGE_OPC_FD_TCAM_OP) {
ret = hclge_test_send_tcam_op_cmd(hdev, buf_in, in_size,
buf_out, out_size);
}
if (param->op == HCLGE_OPC_FD_AD_OP) {
ret = hclge_test_send_ad_op_cmd(hdev, buf_in, in_size,
buf_out, out_size);
}
if (param->op == HCLGE_OPC_FD_CNT_OP) {
ret = hclge_test_send_cnt_op_cmd(hdev, buf_in, in_size,
buf_out, out_size);
}
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_FD_H__
#define __HNS3_PRIV_FD_H__
#define HCLGE_OPC_FD_CNT_OP 0x1205
struct fd_param {
u8 is_read;
u8 stage;
u16 op;
u8 xy_sel;
__le32 idx;
u8 entry_vld;
u8 data[128];
};
struct hclge_fd_cnt_op_cmd {
u8 stage;
u8 rsv1[3];
__le16 cnt_idx;
u8 rsv2[2];
__le64 cnt_value;
u8 rsv3[8];
};
struct hclge_fd_tcam_data {
u8 vld;
u8 tcam_data[52];
};
int hns3_test_fd_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include <linux/kernel.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_hilink_param.h"
#define HILINK_PARAM_CMD_BD_LEN 10UL
#define HILINK_PARAM_SINGLE_PORT_LANE_NUM 4
static void copy_data_from_cmd(u8 *dest, u32 dest_len, u8 *src, u32 src_len)
{
u32 cpy_len;
cpy_len = dest_len >= src_len ? src_len : dest_len;
memcpy(dest, src, cpy_len);
}
static int hns3_get_hilink_ctle(struct hclge_dev *hdev,
u32 lane_start, u32 lane_len,
struct hns3_hilink_param *hns3_param_out)
{
struct hclge_desc ctle_desc[HILINK_LANE_MAX_NUM] = {0};
u8 *ctle_data;
u32 bd_num;
int ret;
u32 i;
for (i = 0; i < HILINK_PARAM_CMD_BD_LEN; i++) {
hclge_cmd_setup_basic_desc(&ctle_desc[i],
HCLGE_OPC_DUMP_CTLE_PARAM, true);
if (i == 0)
ctle_desc[0].data[0] = lane_start | (lane_len << 4);
if (i < HILINK_PARAM_CMD_BD_LEN - 1)
ctle_desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
ctle_desc[i].flag &=
~(cpu_to_le16(HCLGE_CMD_FLAG_NEXT));
}
ret = hclge_cmd_send(&hdev->hw, ctle_desc, HILINK_PARAM_CMD_BD_LEN);
if (ret) {
dev_err(&hdev->pdev->dev, "get hilink param cmd failed %d\n",
ret);
return ret;
}
hns3_param_out->lane_start = ctle_desc[0].data[0] & 0xF;
hns3_param_out->lane_len = (ctle_desc[0].data[0] >> 4) & 0xF;
if (hns3_param_out->lane_len > HILINK_LANE_MAX_NUM)
hns3_param_out->lane_len = HILINK_LANE_MAX_NUM;
bd_num = min_t(u32, hns3_param_out->lane_len, HILINK_PARAM_CMD_BD_LEN);
for (i = 0; i < bd_num; i++) {
ctle_data = (u8 *)&ctle_desc[i].data[0];
if (i == 0) {
ctle_data = ctle_data + 1;
copy_data_from_cmd((u8 *)&hns3_param_out->ctle_param[i],
sizeof(struct hns3_ctle_data),
ctle_data, 23);
} else {
copy_data_from_cmd((u8 *)&hns3_param_out->ctle_param[i],
sizeof(struct hns3_ctle_data),
ctle_data, 24);
}
}
return ret;
}
static int hns3_get_hilink_dfe(struct hclge_dev *hdev,
u32 lane_start, u32 lane_len,
struct hns3_hilink_param *hns3_param_out)
{
struct hclge_desc dfe_desc[HILINK_LANE_MAX_NUM] = {0};
u8 *dfe_data;
u32 bd_num;
int ret;
u32 i;
for (i = 0; i < HILINK_PARAM_CMD_BD_LEN; i++) {
hclge_cmd_setup_basic_desc(&dfe_desc[i],
HCLGE_OPC_DUMP_DFE_PARAM, true);
if (i == 0)
dfe_desc[0].data[0] = lane_start | (lane_len << 4);
if (i < HILINK_PARAM_CMD_BD_LEN - 1)
dfe_desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
dfe_desc[i].flag &= ~(cpu_to_le16(HCLGE_CMD_FLAG_NEXT));
}
ret = hclge_cmd_send(&hdev->hw, dfe_desc, HILINK_PARAM_CMD_BD_LEN);
if (ret) {
dev_err(&hdev->pdev->dev, "get hilink param cmd failed %d\n",
ret);
return ret;
}
bd_num = min_t(u32, hns3_param_out->lane_len, HILINK_PARAM_CMD_BD_LEN);
for (i = 0; i < bd_num; i++) {
dfe_data = (u8 *)&dfe_desc[i].data[0];
if (i == 0) {
dfe_data = dfe_data + 1;
copy_data_from_cmd((u8 *)&hns3_param_out->dfe_param[i],
sizeof(struct hns3_dfe_data),
dfe_data, 23);
} else {
copy_data_from_cmd((u8 *)&hns3_param_out->dfe_param[i],
sizeof(struct hns3_dfe_data),
dfe_data, 24);
}
}
return ret;
}
static int hns3_get_hilink_ffe(struct hclge_dev *hdev,
u32 lane_start, u32 lane_len,
struct hns3_hilink_param *hns3_param_out)
{
struct hclge_desc ffe_desc[HILINK_LANE_MAX_NUM] = {0};
u8 *ffe_data;
u32 bd_num;
int ret;
u32 i;
for (i = 0; i < HILINK_PARAM_CMD_BD_LEN; i++) {
hclge_cmd_setup_basic_desc(&ffe_desc[i],
HCLGE_OPC_DUMP_FFE_PARAM, true);
if (i == 0)
ffe_desc[0].data[0] = lane_start | (lane_len << 4);
if (i < HILINK_PARAM_CMD_BD_LEN - 1)
ffe_desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
ffe_desc[i].flag &= ~(cpu_to_le16(HCLGE_CMD_FLAG_NEXT));
}
ret = hclge_cmd_send(&hdev->hw, ffe_desc, HILINK_PARAM_CMD_BD_LEN);
if (ret) {
dev_err(&hdev->pdev->dev, "get hilink param cmd failed %d\n",
ret);
return ret;
}
bd_num = min_t(u32, hns3_param_out->lane_len, HILINK_PARAM_CMD_BD_LEN);
for (i = 0; i < bd_num; i++) {
ffe_data = (u8 *)&ffe_desc[i].data[0];
if (i == 0) {
ffe_data = ffe_data + 1;
copy_data_from_cmd((u8 *)&hns3_param_out->ffe_param[i],
sizeof(struct hns3_ffe_data),
ffe_data, 23);
} else {
copy_data_from_cmd((u8 *)&hns3_param_out->ffe_param[i],
sizeof(struct hns3_ffe_data),
ffe_data, 24);
}
}
return ret;
}
int hns3_get_hilink_param(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hnae3_handle *handle = hns3_get_handle(net_priv->netdev);
struct hclge_vport *vport = hclge_get_vport(handle);
struct hns3_hilink_param *hns3_param_out;
struct hns3_hilink_param *hns3_param_in;
struct hclge_dev *hdev = vport->back;
int ret;
if (!buf_in)
return -ENODEV;
hns3_param_in = (struct hns3_hilink_param *)buf_in;
hns3_param_out = (struct hns3_hilink_param *)buf_out;
memset(hns3_param_out->ctle_param, 0x0,
sizeof(hns3_param_out->ctle_param));
memset(hns3_param_out->dfe_param, 0x0,
sizeof(hns3_param_out->dfe_param));
memset(hns3_param_out->ffe_param, 0x0,
sizeof(hns3_param_out->ffe_param));
ret = hns3_get_hilink_ctle(hdev, hns3_param_in->lane_start,
hns3_param_in->lane_len, hns3_param_out);
if (ret) {
dev_err(&hdev->pdev->dev, "get hilink ctle cmd failed %d\n",
ret);
return ret;
}
ret = hns3_get_hilink_dfe(hdev, hns3_param_in->lane_start,
hns3_param_in->lane_len, hns3_param_out);
if (ret) {
dev_err(&hdev->pdev->dev, "get hilink dfe cmd failed %d\n",
ret);
return ret;
}
ret = hns3_get_hilink_ffe(hdev, hns3_param_in->lane_start,
hns3_param_in->lane_len, hns3_param_out);
if (ret) {
dev_err(&hdev->pdev->dev, "get hilink ffe cmd failed %d\n",
ret);
return ret;
}
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_HILINK_PARAM_H__
#define __HNS3_PRIV_HILINK_PARAM_H__
#define HILINK_LANE_MAX_NUM 10
#define HCLGE_OPC_DUMP_CTLE_PARAM 0x0382
#define HCLGE_OPC_DUMP_DFE_PARAM 0x0383
#define HCLGE_OPC_DUMP_FFE_PARAM 0x0384
struct hns3_ctle_data {
u8 ctlebst[3];
u8 ctlecmband[3];
u8 ctlermband[3];
u8 ctleza[3];
u8 ctlesqh[3];
u8 ctleactgn[3];
u8 ctlepassgn;
u8 ctlerefsel;
u8 ctleibiastune;
u8 alos;
u8 lpbk;
};
struct hns3_dfe_data {
u8 dfefxtap[10]; /* DFE Fix Tap */
u8 floatingtap[6]; /* DFE Floating Taps */
};
struct hns3_ffe_data {
u8 pre2;
u8 pre1;
u8 main;
u8 post1;
u8 post2;
};
struct hns3_hilink_param {
u32 lane_start;
u32 lane_len;
struct hns3_ctle_data ctle_param[HILINK_LANE_MAX_NUM];
struct hns3_dfe_data dfe_param[HILINK_LANE_MAX_NUM];
struct hns3_ffe_data ffe_param[HILINK_LANE_MAX_NUM];
};
int hns3_get_hilink_param(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kthread.h>
#include "hclge_cmd.h"
#include "hclge_main.h"
#include "hnae3.h"
#include "hns3_enet.h"
#include "hns3_priv_irq.h"
struct hns3_irq_lli_param {
int is_get;
u8 computer_cpus;
u16 tqp_nums;
};
int hns3_irq_lli_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct hns3_irq_lli_param *in_info, *out_info;
struct hnae3_handle *handle;
int is_get;
handle = net_priv->ae_handle;
in_info = (struct hns3_irq_lli_param *)buf_in;
out_info = (struct hns3_irq_lli_param *)buf_out;
is_get = in_info->is_get;
if (is_get) {
out_info->computer_cpus = net_priv->vector_num;
out_info->tqp_nums = handle->kinfo.num_tqps;
}
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_IRQ_H__
#define __HNS3_PRIV_IRQ_H__
int hns3_irq_lli_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_lamp.h"
int hns3_lamp_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct net_device *netdev = net_priv->netdev;
struct hns3_lamp_signal *signal;
struct hns3_lamp_param *param;
int ret = -1;
if (!buf_in || !buf_out)
return -ENODEV;
param = (struct hns3_lamp_param *)buf_in;
signal = (struct hns3_lamp_signal *)buf_out;
if (param->op_type == LAMP_OP_GET_SGPIO)
ret = nic_get_led_signal(netdev, signal);
else if (param->op_type == LAMP_OP_SET_TYPE)
ret = nic_set_led(netdev, param->type, param->status);
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_LAMP_H__
#define __HNS3_PRIV_LAMP_H__
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
enum hns3_lamp_spgio_e {
LAMP_OP_GET_SGPIO = 0,
LAMP_OP_SET_TYPE,
LAMP_OP_UNKNOWN
};
struct hns3_lamp_param {
u32 op_type;
u32 type;
u32 status;
};
struct hns3_lamp_signal {
u8 error;
u8 locate;
u8 activity;
};
int hns3_lamp_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int nic_get_led_signal(struct net_device *ndev,
struct hns3_lamp_signal *signal);
int nic_set_led(struct net_device *ndev, int type, int status);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/kernel.h>
#include "hns3_priv_m7_cmd.h"
int hns3_m7_cmd_handle(struct hns3_nic_priv *nic_dev, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct m7_cmd_para *cmd_para = (struct m7_cmd_para *)buf_in;
struct hnae3_handle *handle = nic_dev->ae_handle;
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
enum hclge_cmd_status status;
struct hclge_desc *desc;
int bd_size;
bd_size = sizeof(struct hclge_desc) * cmd_para->bd_count;
desc = kzalloc(bd_size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR(desc)) {
pr_err("desc kzalloc failed in m7_cmd_handle function\n");
return -ENOMEM;
}
if (copy_from_user((void *)desc, cmd_para->bd_data, bd_size)) {
pr_err("copy from user failed in m7_cmd_handle function\n");
kfree(desc);
return -EFAULT;
}
status = hclge_cmd_send(&hdev->hw, desc, cmd_para->bd_count);
if (status) {
dev_err(&hdev->pdev->dev,
"generic cmd send fail, status is %d.\n", status);
kfree(desc);
return status;
}
if (desc->flag & HCLGE_CMD_FLAG_WR) {
memcpy(buf_out, desc, bd_size);
*out_size = (u16)bd_size;
}
kfree(desc);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_M7_CMD_H__
#define __HNS3_PRIV_M7_CMD_H__
#include "hclge_main.h"
#include "hclge_cmd.h"
#include "hns3_enet.h"
struct m7_cmd_para {
u32 bd_count;
u32 bd_type;
void *bd_data;
};
int hns3_m7_cmd_handle(struct hns3_nic_priv *nic_dev, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kthread.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_mac.h"
int hns3_test_mac_loop_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct nictool_cfg_serdes_mode_cmd *req1;
struct nictool_cfg_mac_mode_cmd *req2;
struct nictool_loop_param *out_info;
struct nictool_loop_param *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
int ret;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_loop_param *)buf_in;
out_info = (struct nictool_loop_param *)buf_out;
req1 = (struct nictool_cfg_serdes_mode_cmd *)&desc.data[0];
req2 = (struct nictool_cfg_mac_mode_cmd *)&desc.data[0];
if (in_info->is_read) {
hclge_cmd_setup_basic_desc(&desc,
HCLGE_OPC_CONFIG_MAC_MODE, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"mac loopback read fail, ret = %d.\n", ret);
return -EIO;
}
out_info->tx2rx_loop_en =
hnae3_get_bit(req2->txrx_pad_fcs_loop_en,
HCLGE_MAC_APP_LP_B);
out_info->rx2tx_loop_en =
hnae3_get_bit(req2->txrx_pad_fcs_loop_en,
HCLGE_MAC_LINE_LP_B);
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK,
true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"serdes loopback read fail, ret = %d.\n", ret);
return -EIO;
}
out_info->serial_tx2rx_loop_en =
hnae3_get_bit(req1->loop_en, SERDES_SERIAL_INNER_LOOP_B);
out_info->parallel_rx2tx_loop_en =
hnae3_get_bit(req1->loop_en, SERDES_PARALLEL_OUTER_LOOP_B);
out_info->parallel_tx2rx_loop_en =
hnae3_get_bit(req1->loop_en, SERDES_PARALLEL_INNER_LOOP_B);
} else {
if (in_info->tx2rx_loop_en < MAINTAIN_LOOP_MODE ||
in_info->rx2tx_loop_en < MAINTAIN_LOOP_MODE) {
hclge_cmd_setup_basic_desc(&desc,
HCLGE_OPC_CONFIG_MAC_MODE,
true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"mac loopback set fail, ret = %d.\n",
ret);
return -EIO;
}
/* 0: off, 1:on, >=2: not set. */
if (in_info->tx2rx_loop_en < MAINTAIN_LOOP_MODE)
hnae3_set_bit(req2->txrx_pad_fcs_loop_en,
HCLGE_MAC_APP_LP_B,
in_info->tx2rx_loop_en);
/* 0: off, 1:on, >=2: not set. */
if (in_info->rx2tx_loop_en < MAINTAIN_LOOP_MODE)
hnae3_set_bit(req2->txrx_pad_fcs_loop_en,
HCLGE_MAC_LINE_LP_B,
in_info->rx2tx_loop_en);
hclge_cmd_reuse_desc(&desc, false);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"mac loopback set fail, ret = %d.\n",
ret);
return -EIO;
}
} else {
hclge_cmd_setup_basic_desc(&desc,
HCLGE_OPC_SERDES_LOOPBACK,
true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"mac loopback set fail, ret = %d.\n",
ret);
return -EIO;
}
/* 0: off, 1:on, >=2: not set. */
if (in_info->serial_tx2rx_loop_en <
MAINTAIN_LOOP_MODE) {
hnae3_set_bit(req1->loop_en,
SERDES_SERIAL_INNER_LOOP_B,
in_info->serial_tx2rx_loop_en);
hnae3_set_bit(req1->loop_valid,
SERDES_SERIAL_INNER_LOOP_B, true);
}
/* 0: off, 1:on, >=2: not set. */
if (in_info->parallel_rx2tx_loop_en <
MAINTAIN_LOOP_MODE) {
hnae3_set_bit(req1->loop_en,
SERDES_PARALLEL_OUTER_LOOP_B,
in_info->parallel_rx2tx_loop_en);
hnae3_set_bit(req1->loop_valid,
SERDES_PARALLEL_OUTER_LOOP_B,
true);
}
/* 0: off, 1:on, >=2: not set. */
if (in_info->parallel_tx2rx_loop_en <
MAINTAIN_LOOP_MODE) {
hnae3_set_bit(req1->loop_en,
SERDES_PARALLEL_INNER_LOOP_B,
in_info->parallel_tx2rx_loop_en);
hnae3_set_bit(req1->loop_valid,
SERDES_PARALLEL_INNER_LOOP_B,
true);
}
hclge_cmd_reuse_desc(&desc, false);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"serdes loopback set fail, ret = %d.\n",
ret);
return -EIO;
}
}
}
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_MAC_H__
#define __HNS3_PRIV_MAC_H__
#define SERDES_SERIAL_INNER_LOOP_B 0x0
#define SERDES_PARALLEL_OUTER_LOOP_B 0x1
#define SERDES_PARALLEL_INNER_LOOP_B 0x2
#define MAINTAIN_LOOP_MODE 0x2
struct nictool_loop_param {
u8 tx2rx_loop_en; /* 0: off, 1:on, >=2: not set. */
u8 rx2tx_loop_en; /* 0: off, 1:on, >=2: not set. */
u8 serial_tx2rx_loop_en; /* 0: off, 1:on, >=2: not set. */
u8 parallel_rx2tx_loop_en; /* 0: off, 1:on, >=2: not set. */
u8 parallel_tx2rx_loop_en; /* 0: off, 1:on, >=2: not set. */
u8 is_read;
};
struct nictool_cfg_mac_mode_cmd {
u32 txrx_pad_fcs_loop_en;
u8 rsv[20];
};
struct nictool_cfg_serdes_mode_cmd {
u8 loop_valid;
u8 loop_en;
u8 loop_status;
u8 rsv[21];
};
int hns3_test_mac_loop_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/phy_fixed.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_ext.h"
#include "hns3_priv_mactbl.h"
int hns3_test_opt_mactbl(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hns3_mac_tbl_para *out = (struct hns3_mac_tbl_para *)buf_out;
struct hns3_mac_tbl_para *in = (struct hns3_mac_tbl_para *)buf_in;
struct net_device *netdev = net_priv->netdev;
struct hnae3_handle *h;
int ret;
h = hns3_get_handle(netdev);
if (!h->ae_algo->ops->priv_ops)
return -EOPNOTSUPP;
out->op_cmd = in->op_cmd;
memcpy(out->mac_addr, in->mac_addr, sizeof(in->mac_addr));
ret = h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_OPT_MAC_TABLE, in, 0);
if (!ret) {
out->result = HNS3_MACTBL_RESULT_SUCCESS;
return 0;
} else if (ret == -ENOENT) {
out->result = HNS3_MACTBL_RESULT_NOEXIST;
return 0;
}
out->result = HNS3_MACTBL_RESULT_FAIL;
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_MACTBL_H__
#define __HNS3_PRIV_MACTBL_H__
enum hns3_mac_table_code {
HNS3_MACTBL_OPT_TABLE_LOOKUP,
HNS3_MACTBL_OPT_TABLE_ADD,
HNS3_MACTBL_OPT_TABLE_DEL,
};
enum hns3_mac_result_code {
HNS3_MACTBL_RESULT_SUCCESS,
HNS3_MACTBL_RESULT_FAIL,
HNS3_MACTBL_RESULT_NOEXIST,
HNS3_MACTBL_RESULT_NOSPACE
};
struct hns3_mac_tbl_para {
u8 op_cmd;
u8 mac_addr[6];
u8 result;
};
int hns3_test_opt_mactbl(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/phy_fixed.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_phy.h"
#define HNS3_PHY_MAX_REG_NUM 0xFFFF
#define HNS3_PHY_READ 0
#define HNS3_PHY_WRITE 1
static int hns3_test_get_reg(struct mii_bus *mdio_bus, u32 phy_id,
u16 page_select_addr, u16 page, u32 addr,
u16 *data)
{
u16 cur_page;
int ret;
if (addr > HNS3_PHY_MAX_REG_NUM) {
pr_err("invalid phy %d page or reg.\n", phy_id);
return -EPERM;
}
mutex_lock(&mdio_bus->mdio_lock);
ret = mdio_bus->read(mdio_bus, phy_id, page_select_addr);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
pr_err("record current phy %d reg page failed.\n", phy_id);
return ret;
}
cur_page = ret;
if (page == cur_page) {
ret = mdio_bus->read(mdio_bus, phy_id, addr);
mutex_unlock(&mdio_bus->mdio_lock);
if (ret >= 0) {
*data = ret;
return 0;
}
return ret;
}
ret = mdio_bus->write(mdio_bus, phy_id, page_select_addr, page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
pr_err("change phy %d reg page %d to %d failed.\n", phy_id,
cur_page, page);
return ret;
}
ret = mdio_bus->read(mdio_bus, phy_id, addr);
if (ret < 0) {
pr_err("read phy %d reg(%u-%u) failed.\n", phy_id, page, addr);
if (mdio_bus->write(mdio_bus, phy_id, page_select_addr,
cur_page) < 0)
pr_err("restore phy %d reg page %d failed after error read.\n",
phy_id, cur_page);
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
*data = ret;
ret = mdio_bus->write(mdio_bus, phy_id, page_select_addr, cur_page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
pr_err("restore phy %d reg page %u failed.\n", phy_id,
cur_page);
return ret;
}
mutex_unlock(&mdio_bus->mdio_lock);
return 0;
}
static int hns3_test_set_reg(struct mii_bus *mdio_bus, u32 phy_id,
u16 page_select_addr, u16 page, u32 addr, u16 data)
{
u16 cur_page;
int ret;
if (addr > HNS3_PHY_MAX_REG_NUM) {
pr_err("invalid phy %d page reg or val.\n", phy_id);
return -EPERM;
}
mutex_lock(&mdio_bus->mdio_lock);
ret = mdio_bus->read(mdio_bus, phy_id, page_select_addr);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
pr_err("record current phy %d reg page failed.\n", phy_id);
return ret;
}
cur_page = ret;
if (page == cur_page) {
ret = mdio_bus->write(mdio_bus, phy_id, addr, data);
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
ret = mdio_bus->write(mdio_bus, phy_id, page_select_addr, page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
pr_err("change phy %d reg page %d to %d failed.\n", phy_id,
cur_page, page);
return ret;
}
ret = mdio_bus->write(mdio_bus, phy_id, addr, data);
if (ret < 0) {
pr_err("write phy %d reg(%d-%d) failed.\n", phy_id, page, addr);
if (mdio_bus->write(mdio_bus, phy_id, page_select_addr,
cur_page) < 0)
pr_err("restore phy %d reg page %d failed after error write\n",
phy_id, cur_page);
mutex_unlock(&mdio_bus->mdio_lock);
return ret;
}
ret = mdio_bus->write(mdio_bus, phy_id, page_select_addr, cur_page);
if (ret < 0) {
mutex_unlock(&mdio_bus->mdio_lock);
pr_err("change phy %d reg page %d to %d failed.\n", phy_id,
page, cur_page);
return ret;
}
mutex_unlock(&mdio_bus->mdio_lock);
return 0;
}
int hns3_test_phy_register_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct phy_reg_param *param;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct mii_bus *mdio_bus;
struct hclge_dev *hdev;
struct hclge_mac *mac;
u16 data = 0;
u32 phyid;
int ret;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
mac = &hdev->hw.mac;
if (!mac->phydev) {
pr_err("this net dev has no phy.\n");
return -EINVAL;
}
phyid = mac->phy_addr;
mdio_bus = mac->mdio_bus;
param = (struct phy_reg_param *)buf_in;
if (param->operate == HNS3_PHY_READ) {
ret = hns3_test_get_reg(mdio_bus, phyid,
param->page_select_addr,
param->page, param->addr, &data);
if (ret == 0) {
*out_size = sizeof(data);
memcpy(buf_out, &data, (int)sizeof(data));
}
} else if (param->operate == HNS3_PHY_WRITE) {
ret = hns3_test_set_reg(mdio_bus, phyid,
param->page_select_addr,
param->page, param->addr,
param->data);
} else {
pr_err("%s:operate is invalid.\n", __func__);
return -1;
}
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_PHY_H__
#define __HNS3_PRIV_PHY_H__
struct phy_reg_param {
u16 operate;
u16 page_select_addr;
u16 page;
u32 addr;
u16 data;
};
int hns3_test_phy_register_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/inetdevice.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_net.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kthread.h>
#include "hns3_enet.h"
#include "hns3_priv_pkt.h"
#define DEFAULT_PAGE_SIZE 4096
#define DEFAULT_TCP_MSS 1460
#define DEFAULT_MIN_PKT_LEN 60
#define NEXTHDR_HOP 0
u8 pkt_head_table[NICTOOL_PKT_TYPE_MAX][128] = {
/* ARP */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0x08, 0x06, 0x00, 0x01,
0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0x01, 0x01, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* TCP */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0x08, 0x00, 0x45, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0xfd,
0xe4, 0x33, 0xc0, 0xa8, 0x0a, 0x0a, 0xc0, 0xa8,
0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* TCP_DSCP */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0x08, 0x00, 0x45, 0x00,
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0xfd,
0xe4, 0x33, 0xc0, 0xa8, 0x0a, 0x0a, 0xc0, 0xa8,
0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* PAUSE */
{
0x01, 0x80, 0xc2, 0x00, 0x00, 0x01, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x06, 0x88, 0x08, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* PAUSE_ERR */
{
0x01, 0x80, 0xc2, 0x00, 0x00, 0x01, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x06, 0x88, 0x08, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* PFC */
{
0x01, 0x80, 0xc2, 0x00, 0x00, 0x01, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x06, 0x88, 0x08, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* PFC_ERR */
{
0x01, 0x80, 0xc2, 0x00, 0x00, 0x01, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x06, 0x88, 0x08, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* IPV4 */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x02, 0x08, 0x00, 0x45, 0x00,
0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x40, 0xfd,
0x75, 0x8b, 0xc0, 0xa8, 0x0a, 0x0a, 0xc0, 0xa8,
0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
/* IPV4_LOOSE_OPTION */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x03, 0x08, 0x00,
0x46, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00,
0x40, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x0b,
0xc0, 0xa8, 0x0a, 0x0a,
0x83, 0x00, 0x04, 0x00,
0x00, 0x64, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x19, 0x09, 0x00, 0x00
},
/* IPV4_TRACEROUTE_OPTION */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x03, 0x08, 0x00,
0x48, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00,
0x40, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x0b,
0xc0, 0xa8, 0x0a, 0x0a,
0x52, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x01,
0x00, 0x64, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x19, 0x09, 0x00, 0x00
},
/* IPV6 */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x02, 0x86, 0xdd, 0x60, 0x00,
0x00, 0x00, 0x05, 0xdc, 0x3b, 0xff, 0xfe, 0xc0,
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00,
0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x0b, 0xfe, 0xc0,
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00,
0x00, 0x00, 0xc0, 0x55, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
},
/* ipv6_extension_routing */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x03, 0x86, 0xdd,
0x60, 0x00, 0x00, 0x00, 0x05, 0xdc, 0x2b, 0xff,
0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x02, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x0b,
0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x02, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x0a, 0x0a,
0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x21,
0x16, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x22,
0x00, 0x64, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x15, 0x99, 0x00, 0x00
},
/* IPV4+SCTP */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x02, 0x08, 0x00,
0x45, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00,
0x40, 0x84, 0x00, 0x00, 0x80, 0x05, 0x7a, 0xb5,
0x80, 0x05, 0x7a, 0xab,
0x00, 0x64, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04,
},
/* IPV6+SCTP */
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa,
0xbb, 0xcc, 0xdd, 0x02, 0x86, 0xdd,
0x60, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x84, 0xff,
0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x02, 0x00, 0x00, 0x00, 0x80, 0x05, 0x7a, 0xb5,
0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x02, 0x00, 0x00, 0x00, 0x80, 0x05, 0x7a, 0xab,
0x00, 0x64, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04,
},
};
#define MAX_KTHREAD_NUM 16
struct kthread_info {
int tid;
struct task_struct *task;
int stop;
struct hns3_nic_priv *net_priv;
struct nictool_pkt_cfg_info *in_info;
struct nictool_pkt_result_info *out_info;
};
struct kthread_info *kthread_table[MAX_KTHREAD_NUM] = {0};
/* This mutexes are created for packets send */
struct mutex pkt_mutex[MAX_KTHREAD_NUM];
int is_send_thread(int tid)
{
return (tid % 2 == 0);
}
int __get_tid(int queue_id, int is_send)
{
if (is_send)
return (queue_id * 2) % MAX_KTHREAD_NUM;
else
return (queue_id * 2 + 1) % MAX_KTHREAD_NUM;
}
static struct sk_buff *__hns_assemble_skb(struct net_device *ndev,
const void *data, int length,
int queue_id, int mss)
{
struct sk_buff *skb;
struct page *p;
void *buff;
int bnum = 0;
int protocol;
int proc_length;
const char *head_data = (const char *)data;
const struct ethhdr *ethhead = (const struct ethhdr *)data;
struct ipv6hdr *ip6_hdr;
/* allocate test skb */
skb = alloc_skb(256, GFP_KERNEL);
if (!skb)
return NULL;
skb->protocol = ethhead->h_proto;
skb->queue_mapping = queue_id;
skb->dev = ndev;
skb_reset_mac_header(skb);
if (length <= 256) {
skb_put(skb, length);
memcpy(&skb->data[0], head_data, length);
} else {
skb_put(skb, 256);
memcpy(&skb->data[0], head_data, 256);
proc_length = length - 256;
while (proc_length > DEFAULT_PAGE_SIZE) {
p = dev_alloc_pages(get_order(DEFAULT_PAGE_SIZE));
if (!p) {
dev_kfree_skb_any(skb);
return NULL;
}
buff = page_address(p);
memcpy(buff, head_data + length - proc_length,
DEFAULT_PAGE_SIZE);
skb_add_rx_frag(skb, bnum, p, 0, DEFAULT_PAGE_SIZE,
DEFAULT_PAGE_SIZE);
proc_length -= DEFAULT_PAGE_SIZE;
bnum++;
}
p = dev_alloc_pages(get_order(DEFAULT_PAGE_SIZE));
if (!p) {
dev_kfree_skb_any(skb);
return NULL;
}
buff = page_address(p);
memcpy(buff, head_data + length - proc_length, proc_length);
skb_add_rx_frag(skb, bnum, p, 0, proc_length,
DEFAULT_PAGE_SIZE);
}
skb->network_header = ETH_HLEN;
if (skb->protocol == htons(ETH_P_8021Q)) {
skb->network_header += VLAN_HLEN;
protocol = vlan_get_protocol(skb);
} else {
protocol = skb->protocol;
}
if (protocol == htons(ETH_P_IP))
skb->transport_header =
skb->network_header + ip_hdr(skb)->ihl * 4;
if (protocol == htons(ETH_P_IPV6)) {
ip6_hdr = (struct ipv6hdr *)skb_network_header(skb);
skb->transport_header =
skb->network_header + sizeof(struct ipv6hdr);
if (ip6_hdr->nexthdr == NEXTHDR_HOP)
skb->transport_header +=
(skb_transport_header(skb)[1] + 1) << 3;
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
}
skb_shinfo(skb)->gso_size = mss;
return skb;
}
void nictool_pkt_type_deal(u8 *payload, struct nictool_pkt_cfg_info *in_info,
struct in_ifaddr *ifa_list,
u8 *pkt_payload, u32 head_len)
{
int i;
memcpy(payload, in_info->dst_mac, 6); /* DST_MAC */
payload[16] = in_info->pkt_len / 256;
payload[17] = in_info->pkt_len % 256;
memcpy(payload + 24, &in_info->pkt_checksum, 2); /* checksum */
if (ifa_list)
memcpy(payload + 26, &ifa_list->ifa_address, 4); /* SRC_IP */
memcpy(payload + 30, in_info->dst_ip, 4); /* DST_IP */
if (in_info->pkt_payload_flag == 1) {
for (i = 0; i < in_info->pkt_len; i++)
pkt_payload[i] = 0xff;
memcpy(payload + head_len, pkt_payload,
in_info->pkt_len - head_len); /* payload */
} else {
for (i = 0; i < in_info->pkt_len; i++)
pkt_payload[i] = 0x0;
memcpy(payload + head_len, pkt_payload,
in_info->pkt_len - head_len); /* payload */
}
}
void __fill_the_pkt_head(struct net_device *netdev, u8 *payload,
struct nictool_pkt_cfg_info *in_info)
{
struct in_ifaddr *ifa_list;
u8 *pkt_payload;
u32 vlan_tag;
size_t count;
int i;
pkt_payload = kzalloc((in_info->pkt_len) * sizeof(u8), GFP_KERNEL);
if (ZERO_OR_NULL_PTR(pkt_payload))
return;
count = in_info->pkt_len > 128 ? 128 : in_info->pkt_len;
memcpy(payload, pkt_head_table[in_info->type], count);
memcpy(payload + 6, netdev->dev_addr, ETH_ALEN);
ifa_list = (struct in_ifaddr *)netdev->ip_ptr->ifa_list;
switch (in_info->type) {
case NICTOOL_PKT_TYPE_ARP:
memcpy(payload + 22, netdev->dev_addr, ETH_ALEN);
if (ifa_list)
memcpy(payload + 28, &ifa_list->ifa_address,
4); /* SRC_IP */
memcpy(payload + 32, in_info->dst_mac, ETH_ALEN);
memcpy(payload + 38, in_info->dst_ip, 4);
break;
case NICTOOL_PKT_TYPE_TCP:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
payload[16] = in_info->pkt_len / 256;
payload[17] = in_info->pkt_len % 256;
if (ifa_list)
memcpy(payload + 26, &ifa_list->ifa_address, 4);
memcpy(payload + 30, in_info->dst_ip, 4);
break;
case NICTOOL_PKT_TYPE_TCP_DSCP:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
payload[15] = (in_info->dscp << 2);
payload[16] = in_info->pkt_len / 256;
payload[17] = in_info->pkt_len % 256;
if (ifa_list)
memcpy(payload + 26, &ifa_list->ifa_address,
4); /* SRC_IP */
memcpy(payload + 30, in_info->dst_ip, 4);
break;
case NICTOOL_PKT_TYPE_PAUSE:
memcpy(payload + 16, &in_info->pause_time, 2);
break;
case NICTOOL_PKT_TYPE_PAUSE_ERR:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
memcpy(payload + 12, &in_info->eth_type, 2);
memcpy(payload + 14, &in_info->pause_code, 2);
memcpy(payload + 16, &in_info->pause_time, 2);
break;
case NICTOOL_PKT_TYPE_PFC:
payload[17] = in_info->priority;
for (i = 0; i < 8; i++) {
if ((in_info->priority >> i) & 0x01)
memcpy(payload + 18 + i * 2,
&in_info->pause_time, 2);
}
break;
case NICTOOL_PKT_TYPE_PFC_ERR:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
memcpy(payload + 12, &in_info->eth_type, 2);
memcpy(payload + 14, &in_info->pause_code, 2);
payload[17] = in_info->priority;
for (i = 0; i < 8; i++) {
if ((in_info->priority >> i) & 0x01)
memcpy(payload + 18 + i * 2,
&in_info->pause_time, 2);
}
break;
case NICTOOL_PKT_TYPE_IPV4:
nictool_pkt_type_deal(payload, in_info, ifa_list, pkt_payload,
34);
break;
case NICTOOL_PKT_TYPE_IPV4_LOOSESRCROUTE_OPTION:
nictool_pkt_type_deal(payload, in_info, ifa_list, pkt_payload,
58);
break;
case NICTOOL_PKT_TYPE_IPV4_TRACEROUTE_OPTION:
nictool_pkt_type_deal(payload, in_info, ifa_list, pkt_payload,
66);
break;
case NICTOOL_PKT_TYPE_IPV6:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
memcpy(payload + 22, in_info->pkt_inet6_addr, 16);
if (in_info->pkt_payload_flag == 1) {
for (i = 0; i < in_info->pkt_len; i++)
pkt_payload[i] = 0xff;
memcpy(payload + 54, pkt_payload,
in_info->pkt_len - 54); /* payload */
} else {
for (i = 0; i < in_info->pkt_len; i++)
pkt_payload[i] = 0x0;
memcpy(payload + 54, pkt_payload,
in_info->pkt_len - 54); /* payload */
}
break;
case NICTOOL_PKT_TYPE_IPV6_EXTENSION_ROUTING:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
memcpy(payload + 22, in_info->pkt_inet6_addr, 16);
if (in_info->pkt_payload_flag == 1) {
for (i = 0; i < in_info->pkt_len; i++)
pkt_payload[i] = 0xff;
memcpy(payload + 114, pkt_payload,
in_info->pkt_len - 114); /* payload */
} else {
for (i = 0; i < in_info->pkt_len; i++)
pkt_payload[i] = 0x0;
memcpy(payload + 114, pkt_payload,
in_info->pkt_len - 114); /* payload */
}
break;
case NICTOOL_PKT_TYPE_SCTP4:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
if (ifa_list)
memcpy(payload + 26, &ifa_list->ifa_address,
4); /* SRC_IP */
memcpy(payload + 30, in_info->dst_ip, 4);
memcpy(payload + 42, &in_info->pkt_checksum_sctp,
4); /* checksum */
break;
case NICTOOL_PKT_TYPE_SCTP6:
memcpy(payload, in_info->dst_mac, ETH_ALEN);
memcpy(payload + 22, in_info->pkt_inet6_addr, 16);
memcpy(payload + 62, &in_info->pkt_checksum_sctp,
4); /* checksum */
break;
default:
break;
}
if (in_info->vlan_tag) {
memmove(payload + 16, payload + 12, 48);
vlan_tag = htonl(in_info->vlan_tag);
memcpy(payload + 12, &vlan_tag, sizeof(vlan_tag));
}
kfree(pkt_payload);
}
#define MAX_PKTS_NUM_ONCE 50
static int __hns3_test_change_send_queue(int cur_queue,
struct nictool_pkt_cfg_info *in_info,
u8 *payload)
{
int queue_id = cur_queue;
queue_id++;
if (queue_id >= in_info->queue_id + in_info->multi_queue)
queue_id = in_info->queue_id;
/* use last ip for different queue */
if (in_info->multi_queue > 1)
payload[33] = queue_id % 255;
return queue_id;
}
int __hns3_test_send_pkt(struct hns3_nic_priv *net_priv,
struct nictool_pkt_cfg_info *in_info,
struct nictool_pkt_result_info *out_info)
{
struct hnae3_handle *handle;
struct sk_buff *skb;
int pkt_len;
u8 *payload;
int ret = 0;
int i;
int change_flag;
int total_len;
int tid;
int queue_id = in_info->queue_id;
struct net_device *netdev = net_priv->netdev;
handle = net_priv->ae_handle;
if (queue_id > handle->kinfo.num_tqps ||
queue_id + in_info->multi_queue - 1 > handle->kinfo.num_tqps) {
pr_err("%s,%d:queue(%d) or multi_queue(%d) is invalid\n",
__func__, __LINE__,
in_info->queue_id, in_info->multi_queue);
return -EINVAL;
}
pkt_len = in_info->pkt_len;
payload = kzalloc(pkt_len, GFP_KERNEL);
if (ZERO_OR_NULL_PTR(payload))
return -ENOMEM;
__fill_the_pkt_head(netdev, payload, in_info);
tid = __get_tid(queue_id, 1);
total_len = 0;
change_flag = MAX_PKTS_NUM_ONCE;
for (i = 0; i < in_info->num; i++) {
skb_again:
if (in_info->multi_queue > 1) {
change_flag--;
if (change_flag <= 0) {
change_flag = MAX_PKTS_NUM_ONCE;
queue_id =
__hns3_test_change_send_queue(queue_id,
in_info,
payload);
}
}
skb = __hns_assemble_skb(netdev, payload, pkt_len,
queue_id, in_info->mss);
if (!skb) {
ret = -1;
goto out;
}
send_again:
if (in_info->new_thread && kthread_table[tid]) {
if (kthread_table[tid]->stop) {
dev_kfree_skb_any(skb);
break;
}
}
ret = netdev->netdev_ops->ndo_start_xmit(skb, netdev);
if (ret == NETDEV_TX_BUSY) {
if (in_info->multi_queue > 1) {
dev_kfree_skb_any(skb);
change_flag = 0;
goto skb_again;
}
if (in_info->wait_all_finish) {
schedule();
goto send_again;
}
dev_kfree_skb_any(skb);
break;
}
total_len += pkt_len;
}
out_info->num = i;
out_info->total_len = total_len;
out:
kfree(payload);
return ret;
}
void hns3_test_pkt_init(void)
{
int i;
for (i = 0; i < MAX_KTHREAD_NUM; i++)
mutex_init(&pkt_mutex[i]);
}
void hns3_test_pkt_destroy(void)
{
int i;
for (i = 0; i < MAX_KTHREAD_NUM; i++)
mutex_destroy(&pkt_mutex[i]);
}
int __hns3_test_new_task(void *arg)
{
struct kthread_info *info = (struct kthread_info *)arg;
int tid = info->tid;
if (is_send_thread(tid)) {
__hns3_test_send_pkt(info->net_priv,
info->in_info, info->out_info);
pr_err("send pkt %d, the total len = %d\n",
info->out_info->num, info->out_info->total_len);
}
mutex_lock(&pkt_mutex[tid]);
kfree(info->in_info);
kfree(info->out_info);
kfree(info);
kthread_table[tid] = NULL;
mutex_unlock(&pkt_mutex[tid]);
return 0;
}
int hns3_test_create_new_thread(int tid,
struct hns3_nic_priv *net_priv,
struct nictool_pkt_cfg_info *in_info,
struct nictool_pkt_result_info *out_info)
{
char name[] = "hns3_test_pkt00";
int ret;
if (kthread_table[tid]) {
pr_err("%s,%d:the thread[%d] is busy!\n", __func__, __LINE__,
tid);
return -EINVAL;
}
kthread_table[tid] = kzalloc(sizeof(*kthread_table[0]), GFP_KERNEL);
if (ZERO_OR_NULL_PTR(kthread_table[tid])) {
pr_err("%s,%d:thread[%d] mem alloc failed\n", __func__,
__LINE__, tid);
return -ENOMEM;
}
kthread_table[tid]->tid = tid;
kthread_table[tid]->net_priv = net_priv;
kthread_table[tid]->in_info = kzalloc(sizeof(*in_info), GFP_KERNEL);
if (ZERO_OR_NULL_PTR(kthread_table[tid]->in_info)) {
pr_err("%s,%d:thread[%d] in info alloc failed\n", __func__,
__LINE__, tid);
ret = -ENOMEM;
goto err_in_info_alloc;
}
kthread_table[tid]->out_info = kzalloc(sizeof(*out_info), GFP_KERNEL);
if (ZERO_OR_NULL_PTR(kthread_table[tid]->out_info)) {
pr_err("%s,%d:thread[%d] out info alloc failed\n", __func__,
__LINE__, tid);
ret = -ENOMEM;
goto err_out_info_alloc;
}
memcpy(kthread_table[tid]->in_info, in_info, sizeof(*in_info));
name[13] = tid / 10 + '0';
name[14] = tid % 10 + '0';
kthread_table[tid]->task =
kthread_run(__hns3_test_new_task, kthread_table[tid], "%s", name);
if (IS_ERR(kthread_table[tid]->task)) {
pr_err("%s,%d:thread[%d] alloc failed\n", __func__, __LINE__,
tid);
ret = -EAGAIN;
goto err_kthread_alloc;
}
return 0;
err_kthread_alloc:
kfree(kthread_table[tid]->out_info);
err_out_info_alloc:
kfree(kthread_table[tid]->in_info);
err_in_info_alloc:
kfree(kthread_table[tid]);
kthread_table[tid] = NULL;
return ret;
}
void hns3_test_stop_new_thread(int tid)
{
mutex_lock(&pkt_mutex[tid]);
if (kthread_table[tid])
kthread_table[tid]->stop = 1;
mutex_unlock(&pkt_mutex[tid]);
}
int hns3_test_send_pkt(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct nictool_pkt_result_info *out_info;
struct nictool_pkt_cfg_info *in_info;
struct hnae3_handle *handle;
int queue_id;
int tid;
in_info = (struct nictool_pkt_cfg_info *)buf_in;
out_info = (struct nictool_pkt_result_info *)buf_out;
handle = net_priv->ae_handle;
queue_id = in_info->queue_id;
*out_size = sizeof(*out_info);
if (queue_id > handle->kinfo.num_tqps) {
pr_err("%s,%d:queue(%d) is invalid\n", __func__, __LINE__,
in_info->queue_id);
return -EINVAL;
}
memset(out_info, 0, sizeof(*out_info));
tid = __get_tid(in_info->queue_id, 1);
if (in_info->stop_thread) {
hns3_test_stop_new_thread(tid);
return 0;
}
if (in_info->new_thread)
return hns3_test_create_new_thread(tid, net_priv, in_info,
out_info);
return __hns3_test_send_pkt(net_priv, in_info, out_info);
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_PKT_H__
#define __HNS3_PRIV_PKT_H__
enum PKT_TYPE {
NICTOOL_PKT_TYPE_ARP = 0,
NICTOOL_PKT_TYPE_TCP,
NICTOOL_PKT_TYPE_TCP_DSCP,
NICTOOL_PKT_TYPE_PAUSE,
NICTOOL_PKT_TYPE_PAUSE_ERR,
NICTOOL_PKT_TYPE_PFC,
NICTOOL_PKT_TYPE_PFC_ERR,
NICTOOL_PKT_TYPE_IPV4,
NICTOOL_PKT_TYPE_IPV4_LOOSESRCROUTE_OPTION,
NICTOOL_PKT_TYPE_IPV4_TRACEROUTE_OPTION,
NICTOOL_PKT_TYPE_IPV6,
NICTOOL_PKT_TYPE_IPV6_EXTENSION_ROUTING,
NICTOOL_PKT_TYPE_SCTP4,
NICTOOL_PKT_TYPE_SCTP6,
NICTOOL_PKT_TYPE_MAX,
};
struct nictool_pkt_cfg_info {
int queue_id;
int type;
int pkt_len;
int num;
int mss;
int new_thread;
int stop_thread;
int wait_all_finish;
u32 vlan_tag;
u16 pause_time;
u16 eth_type;
u16 pause_code;
u8 priority;
u8 dscp;
u8 dst_mac[6];
u8 dst_ip[4];
int multi_queue;
int pkt_payload_flag;
u16 pkt_checksum;
u32 pkt_checksum_sctp;
u16 pkt_inet6_addr[10];
};
struct nictool_pkt_result_info {
int total_len;
int num;
};
int hns3_test_send_pkt(struct hns3_nic_priv *net_priv, void *buf_in,
u16 in_size, void *buf_out, u16 *out_size);
void hns3_test_pkt_init(void);
void hns3_test_pkt_destroy(void);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_port.h"
#define HCLGE_CMD_DATA_BYTE_LEN 24
#define BD_NUM_5 5
#define BD_NUM_6 6
#define BD_NUM_7 7
int hns3_get_port_info(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct hclge_port_info *get_port_info_out;
struct hclge_desc desc = {0};
struct hclge_desc *port_desc;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
__le32 *desc_data;
u8 *dest_data;
u8 *tmp_buff;
u32 bd_num;
int ret;
u32 i;
if (!buf_in || !buf_out)
return -ENODEV;
get_port_info_out = (struct hclge_port_info *)buf_out;
handle = hns3_get_handle(net_priv->netdev);
vport = hclge_get_vport(handle);
hdev = vport->back;
get_port_info_out->gpio_insert = 0;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_PORTINFO_BD_NUM,
true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"hclge get port info BD num failed %d\n", ret);
return ret;
}
desc_data = (__le32 *)(&desc.data[0]);
bd_num = le32_to_cpu(*desc_data);
port_desc = kcalloc(bd_num, sizeof(struct hclge_desc), GFP_KERNEL);
if (ZERO_OR_NULL_PTR(port_desc))
return -ENOMEM;
for (i = 0; i < bd_num; i++) {
hclge_cmd_setup_basic_desc(&port_desc[i],
HCLGE_OPC_DUMP_PORT_INFO, true);
if (i < bd_num - 1)
port_desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
port_desc[i].flag &=
~(cpu_to_le16(HCLGE_CMD_FLAG_NEXT));
}
ret = hclge_cmd_send(&hdev->hw, port_desc, bd_num);
if (ret) {
dev_err(&hdev->pdev->dev,
"get port information cmd failed %d\n", ret);
kfree(port_desc);
return ret;
}
dest_data = (u8 *)get_port_info_out;
/* first BD (24 Bytes) */
for (i = 0; i < bd_num; i++) {
tmp_buff = (u8 *)&port_desc[i].data[0];
if (i == BD_NUM_5) {
get_port_info_out->his_link_machine_state =
port_desc[i].data[0];
get_port_info_out->his_machine_state_length =
port_desc[i].data[1] & 0xFF;
memcpy(get_port_info_out->his_machine_state_data,
tmp_buff + 5, 19);
} else if (i == BD_NUM_6) {
get_port_info_out->cur_link_machine_state =
port_desc[i].data[0];
get_port_info_out->cur_machine_state_length =
port_desc[i].data[1] & 0xFF;
memcpy(get_port_info_out->cur_machine_state_data,
tmp_buff + 5, 19);
} else {
if (i == BD_NUM_7)
dest_data =
(u8 *)&get_port_info_out->param_info;
memcpy(dest_data, tmp_buff, HCLGE_CMD_DATA_BYTE_LEN);
if (i != (bd_num - 1))
dest_data = dest_data + HCLGE_CMD_DATA_BYTE_LEN;
}
}
kfree(port_desc);
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_PORT_H__
#define __HNS3_PRIV_PORT_H__
#define HCLGE_OPC_QUERY_PORTINFO_BD_NUM 0x0380
#define HCLGE_OPC_DUMP_PORT_INFO 0x0381
struct port_cfg {
u8 an;
u8 fec;
u16 speed;
};
struct port_param_info {
/* BD7:24 byte */
u8 chip_id;
u8 lane_id;
u8 lane_num;
u8 rsvd1;
struct port_cfg default_cfg;
struct port_cfg bios_cfg;
struct port_cfg user_cfg;
struct port_cfg final_cfg;
u8 adapt_default_en;
u8 adapt_cur_en;
u8 adapt_speed;
u8 rsvd2;
};
struct hclge_port_info {
/* BD0:24 Byte */
u8 vendor_name[16];
u32 port_type;
u32 port_sub_type;
/* BD1:24 Byte */
u32 cable_length;
u8 cable_temp;
u8 max_speed;
u8 sfp_type;
u8 rsvd2;
u32 power[4];
/* BD2:24 Byte */
u8 an_state;
u8 fec;
u16 speed;
u8 gpio_insert;
u8 alos;
u8 rx_los;
u8 pma_ctrl;
u32 pma_fifo_reg;
u32 pma_signal_ok_reg;
u32 pcs_64_66b_reg;
u32 rf_lf;
/* BD3 - BD4:24*2 Byte */
u8 pcs_link;
u8 pcs_mac_link;
u8 tx_enable;
u8 rx_enable;
u32 pcs_err_cnt;
u8 eq_data[38];
u8 rsvd5[2];
/* BD5-BD6 */
u32 his_link_machine_state;
u32 cur_link_machine_state;
u8 his_machine_state_data[128];
u8 cur_machine_state_data[128];
u8 his_machine_state_length;
u8 cur_machine_state_length;
struct port_param_info param_info;
u8 rsvd6[488];
};
struct hclge_lsport_info {
u32 portinfo[6];
};
int hns3_get_port_info(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hns3_priv_promisc.h"
int hns3_read_promisc_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_promisc_cfg_cmd *req;
enum hclge_cmd_status status;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
u8 *out_buf = (u8 *)buf_out;
u8 enable;
handle = nic_dev->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
req = (struct hclge_promisc_cfg_cmd *)desc.data;
req->vf_id = vport->vport_id;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PROMISC_MODE, true);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
req = (struct hclge_promisc_cfg_cmd *)desc.data;
if (status) {
dev_err(&hdev->pdev->dev,
"Get promisc mode fail, status is %d.\n", status);
return status;
}
enable = req->flag >> HCLGE_PROMISC_EN_B;
*out_buf = enable;
return 0;
}
int hns3_set_promisc_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct promisc_mode_param *mode_param;
struct hclge_promisc_cfg_cmd *req;
struct hclge_promisc_param param;
enum hclge_cmd_status status;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
bool en_uc;
bool en_mc;
bool en_bc;
u8 enable;
handle = nic_dev->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
req = (struct hclge_promisc_cfg_cmd *)desc.data;
req->vf_id = vport->vport_id;
mode_param = (struct promisc_mode_param *)buf_in;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PROMISC_MODE, true);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
req = (struct hclge_promisc_cfg_cmd *)desc.data;
if (status) {
dev_err(&hdev->pdev->dev,
"Get promisc mode fail, status is %d.\n", status);
return status;
}
enable = req->flag >> HCLGE_PROMISC_EN_B;
if (enable & HCLGE_PROMISC_EN_UC)
en_uc = 1;
else
en_uc = 0;
if (enable & HCLGE_PROMISC_EN_MC)
en_mc = 1;
else
en_mc = 0;
if (enable & HCLGE_PROMISC_EN_BC)
en_bc = 1;
else
en_bc = 0;
switch (mode_param->type) {
case HNS3_UNICAST:
en_uc = mode_param->uc;
break;
case HNS3_MULTICAST:
en_mc = mode_param->mc;
break;
case HNS3_BROADCAST:
en_bc = mode_param->bc;
break;
default:
return -1;
}
hclge_promisc_param_init(&param, en_uc, en_mc, en_bc, vport->vport_id);
return hclge_cmd_set_promisc_mode(hdev, &param);
}
int hns3_promisc_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
int ret;
struct promisc_mode_param *mode_param;
mode_param = (struct promisc_mode_param *)buf_in;
if (mode_param->is_read == 1)
ret = hns3_read_promisc_mode_cfg(nic_dev, buf_in, in_size,
buf_out, out_size);
else
ret = hns3_set_promisc_mode_cfg(nic_dev, buf_in, in_size,
buf_out, out_size);
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_PROMISC_H__
#define __HNS3_PRIV_PROMISC_H__
#include "hclge_main.h"
#include "hclge_cmd.h"
#include "hns3_enet.h"
enum promisc_mode {
HNS3_UNICAST = 0,
HNS3_MULTICAST,
HNS3_BROADCAST,
};
struct promisc_mode_param {
u8 uc;
u8 mc;
u8 bc;
u8 is_read;
u8 type;
};
int hns3_promisc_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hns3_priv_qinfo.h"
int hns3_get_q_rx_fbd(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
int tqps_num;
tqps_num = net_priv->ae_handle->kinfo.num_tqps;
ring = net_priv->ring_data[ring_id + tqps_num].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_FBDNUM_REG);
return num;
}
int hns3_get_q_rx_ebd(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
int tqps_num;
tqps_num = net_priv->ae_handle->kinfo.num_tqps;
ring = net_priv->ring_data[ring_id + tqps_num].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_EBDNUM_REG);
return num;
}
int hns3_get_q_tx_fbd(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
ring = net_priv->ring_data[ring_id].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_FBDNUM_REG);
return num;
}
int hns3_get_q_tx_ebd(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
ring = net_priv->ring_data[ring_id].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_EBDNUM_REG);
return num;
}
int hns3_get_q_rx_tail(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
int tqps_num;
tqps_num = net_priv->ae_handle->kinfo.num_tqps;
ring = net_priv->ring_data[ring_id + tqps_num].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG);
return num;
}
int hns3_get_q_rx_head(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
int tqps_num;
tqps_num = net_priv->ae_handle->kinfo.num_tqps;
ring = net_priv->ring_data[ring_id + tqps_num].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_HEAD_REG);
return num;
}
int hns3_get_q_tx_tail(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
ring = net_priv->ring_data[ring_id].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG);
return num;
}
int hns3_get_q_tx_head(struct hns3_nic_priv *net_priv, int ring_id)
{
struct hns3_enet_ring *ring;
int num;
ring = net_priv->ring_data[ring_id].ring;
num = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_HEAD_REG);
return num;
}
int hns3_test_qinfo_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct qinfo_param *out_info;
int tqps_num;
int ring_id;
int rx_head;
int rx_tail;
int rx_ebd;
int rx_fbd;
int tx_head;
int tx_tail;
int tx_ebd;
int tx_fbd;
tqps_num = net_priv->ae_handle->kinfo.num_tqps;
out_info = (struct qinfo_param *)buf_out;
ring_id = *((int *)buf_in);
if (ring_id > tqps_num || ring_id < 0) {
pr_err("please input valid qid\n");
return -1;
}
rx_head = hns3_get_q_rx_head(net_priv, ring_id);
rx_tail = hns3_get_q_rx_tail(net_priv, ring_id);
rx_ebd = hns3_get_q_rx_ebd(net_priv, ring_id);
rx_fbd = hns3_get_q_rx_fbd(net_priv, ring_id);
tx_head = hns3_get_q_tx_head(net_priv, ring_id);
tx_tail = hns3_get_q_tx_tail(net_priv, ring_id);
tx_ebd = hns3_get_q_tx_ebd(net_priv, ring_id);
tx_fbd = hns3_get_q_tx_fbd(net_priv, ring_id);
out_info->qid = ring_id;
out_info->rx_head = rx_head;
out_info->rx_tail = rx_tail;
out_info->rx_ebd = rx_ebd;
out_info->rx_fbd = rx_fbd;
out_info->tx_head = tx_head;
out_info->tx_tail = tx_tail;
out_info->tx_ebd = tx_ebd;
out_info->tx_fbd = tx_fbd;
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_QINFO_H__
#define __HNS3_PRIV_QINFO_H__
#include "hclge_main.h"
#include "hclge_cmd.h"
#include "hns3_enet.h"
#define HNS3_RING_RX_RING_EBDNUM_REG 0x00024
#ifndef HNS3_RING_TX_RING_EBDNUM_REG
#define HNS3_RING_TX_RING_EBDNUM_REG 0x00068
#endif
struct qinfo_param {
int qid;
int tx_head;
int tx_tail;
int tx_ebd;
int tx_fbd;
int rx_head;
int rx_tail;
int rx_ebd;
int rx_fbd;
};
int hns3_get_q_rx_fbd(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_get_q_rx_ebd(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_get_q_tx_fbd(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_get_q_tx_ebd(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_get_q_rx_tail(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_get_q_rx_head(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_get_q_tx_tail(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_get_q_tx_head(struct hns3_nic_priv *net_priv, int ring_id);
int hns3_test_qinfo_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hclge_main.h"
#include "hclge_cmd.h"
#include "hns3_enet.h"
#include "hns3_priv_qos.h"
struct hclge_dev *get_val_hdev(struct hns3_nic_priv *net_priv)
{
struct hnae3_handle *handle;
struct hclge_vport *vport;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
return vport->back;
}
int hns3_cmd_rx_priv_wl_config(struct hclge_dev *hdev, u16 tc,
u32 high, u32 low, u32 en)
{
struct hclge_rx_priv_wl_buf *req;
enum hclge_cmd_status status;
struct hclge_desc desc[2];
int idx;
int i;
int j;
for (i = 0; i < 2; i++) {
hclge_cmd_setup_basic_desc(&desc[i],
HCLGE_OPC_RX_PRIV_WL_ALLOC, false);
req = (struct hclge_rx_priv_wl_buf *)desc[i].data;
/* The first descriptor set the NEXT bit to 1 */
if (i == 0)
desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
desc[i].flag &= ~cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
for (j = 0; j < HCLGE_TC_NUM_ONE_DESC; j++) {
idx = i * HCLGE_TC_NUM_ONE_DESC + j;
if ((tc >> idx) & 0x01) {
req->tc_wl[j].high = cpu_to_le16(high);
req->tc_wl[j].high |=
cpu_to_le16(en << HCLGE_RX_PRIV_EN_B);
req->tc_wl[j].low = cpu_to_le16(low);
req->tc_wl[j].low |=
cpu_to_le16(en << HCLGE_RX_PRIV_EN_B);
}
}
}
/* Send 2 descriptor at one time */
status = hclge_cmd_send(&hdev->hw, desc, 2);
if (status) {
dev_err(&hdev->pdev->dev,
"Set rx private waterline fail, status %d\n", status);
return status;
}
return 0;
}
int hns3_test_rx_priv_buff_wl_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_dev *hdev = get_val_hdev(net_priv);
struct hns3_rx_priv_buff_wl_param *in_info;
if (!hnae3_dev_dcb_supported(hdev)) {
dev_err(&hdev->pdev->dev,
"This device is not support this cmd!\n");
return -EPERM;
}
in_info = (struct hns3_rx_priv_buff_wl_param *)buf_in;
pr_err("wl is_set param, tc_no = 0x%x, hight = 0x%x, low = 0x%x\n",
in_info->tc_no, in_info->high_wl, in_info->low_wl);
return hns3_cmd_rx_priv_wl_config(hdev, in_info->tc_no,
in_info->high_wl, in_info->low_wl, 1);
}
int hns3_cmd_common_thrd_config(struct hclge_dev *hdev, u16 tc,
u32 high, u32 low, u32 en)
{
struct hclge_rx_com_thrd *req;
enum hclge_cmd_status status;
struct hclge_desc desc[2];
int idx;
int i;
int j;
for (i = 0; i < 2; i++) {
hclge_cmd_setup_basic_desc(&desc[i],
HCLGE_OPC_RX_COM_THRD_ALLOC, false);
req = (struct hclge_rx_com_thrd *)desc[i].data;
if (i == 0)
desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
desc[i].flag &= ~cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
for (j = 0; j < HCLGE_TC_NUM_ONE_DESC; j++) {
idx = i * HCLGE_TC_NUM_ONE_DESC + j;
if ((tc >> idx) & 0x01) {
req->com_thrd[j].high = cpu_to_le16(high);
req->com_thrd[j].high |=
cpu_to_le16(en << HCLGE_RX_PRIV_EN_B);
req->com_thrd[j].low = cpu_to_le16(low);
req->com_thrd[j].low |=
cpu_to_le16(en << HCLGE_RX_PRIV_EN_B);
}
}
}
/* Send 2 descriptors at one time */
status = hclge_cmd_send(&hdev->hw, desc, 2);
if (status) {
dev_err(&hdev->pdev->dev,
"Set rx common threshold fail, status %d\n", status);
return status;
}
return 0;
}
int hns3_test_common_thrd_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_dev *hdev = get_val_hdev(net_priv);
struct hns3_rx_priv_buff_wl_param *in_info;
if (!hnae3_dev_dcb_supported(hdev)) {
dev_err(&hdev->pdev->dev,
"This device is not support this cmd!\n");
return -EPERM;
}
in_info = (struct hns3_rx_priv_buff_wl_param *)buf_in;
pr_info("common thrd is_set param, tc_no = 0x%x, hight = 0x%x, low = 0x%x\n",
in_info->tc_no, in_info->high_wl, in_info->low_wl);
return hns3_cmd_common_thrd_config(hdev, in_info->tc_no,
in_info->high_wl, in_info->low_wl,
1);
}
int hns3_cmd_common_wl_config(struct hclge_dev *hdev, u32 high, u32 low, u32 en)
{
enum hclge_cmd_status status;
struct hclge_desc desc;
struct hclge_rx_com_wl *req = (struct hclge_rx_com_wl *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_COM_WL_ALLOC, false);
req->com_wl.high = cpu_to_le16(high);
req->com_wl.high |= cpu_to_le16(en << HCLGE_RX_PRIV_EN_B);
req->com_wl.low = cpu_to_le16(low);
req->com_wl.low |= cpu_to_le16(en << HCLGE_RX_PRIV_EN_B);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev,
"Set rx common waterline fail, status %d\n", status);
return status;
}
return 0;
}
int hns3_test_common_wl_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hns3_rx_priv_buff_wl_param *out_info;
struct hns3_rx_priv_buff_wl_param *in_info;
enum hclge_cmd_status status;
struct hnae3_handle *handle;
struct hclge_rx_com_wl *req;
struct hclge_vport *vport;
struct hclge_desc desc;
struct hclge_dev *hdev;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
out_info = (struct hns3_rx_priv_buff_wl_param *)buf_out;
in_info = (struct hns3_rx_priv_buff_wl_param *)buf_in;
if (in_info->is_read == IS_WRITE) {
status = hns3_cmd_common_wl_config(hdev, in_info->high_wl,
in_info->low_wl, 1);
} else {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_COM_WL_ALLOC,
true);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status != 0) {
dev_err(&hdev->pdev->dev,
"get rx common waterline fail, status = %d\n",
status);
return status;
}
req = (struct hclge_rx_com_wl *)desc.data;
out_info->high_wl = req->com_wl.high;
out_info->low_wl = req->com_wl.low;
}
return status;
}
int hns3_test_rx_buff_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_rx_priv_buff_cmd *recv;
struct hns3_rx_buff_param *out_info;
struct hns3_rx_buff_param *in_info;
enum hclge_cmd_status status;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
int i;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
out_info = (struct hns3_rx_buff_param *)buf_out;
in_info = (struct hns3_rx_buff_param *)buf_in;
if (in_info->is_read == IS_READ) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_PRIV_BUFF_ALLOC,
true);
recv = (struct hclge_rx_priv_buff_cmd *)desc.data;
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
pr_err("rx buff get cmd send failed!\n");
return status;
}
for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
out_info->buff_size[i] = recv->buf_num[i];
out_info->share_buff = recv->shared_buf;
}
return 0;
}
int hns3_test_tx_buff_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_tx_buff_alloc_cmd *recv;
struct hns3_tx_buff_param *out_info;
struct hns3_tx_buff_param *in_info;
enum hclge_cmd_status status;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_desc desc;
struct hclge_dev *hdev;
int i;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
out_info = (struct hns3_tx_buff_param *)buf_out;
in_info = (struct hns3_tx_buff_param *)buf_in;
if (in_info->is_read == IS_READ) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TX_BUFF_ALLOC,
true);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
pr_err("tx buff get cmd send failed!\n");
return status;
}
recv = (struct hclge_tx_buff_alloc_cmd *)desc.data;
for (i = 0; i < HCLGE_MAX_TC_NUM; i++)
out_info->buff_size[i] = recv->tx_pkt_buff[i];
}
return 0;
}
int hns3_test_show_comm_thres(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_dev *hdev = get_val_hdev(net_priv);
struct hns3_total_priv_wl_param *out_info;
struct hclge_rx_com_thrd *req;
enum hclge_cmd_status status;
struct hclge_desc desc[2];
int idx;
int i;
int j;
out_info = (struct hns3_total_priv_wl_param *)buf_out;
for (i = 0; i < 2; i++) {
hclge_cmd_setup_basic_desc(&desc[i],
HCLGE_OPC_RX_COM_THRD_ALLOC, true);
if (i == 0)
desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
desc[i].flag &= ~cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
}
status = hclge_cmd_send(&hdev->hw, desc, 2);
if (status) {
dev_err(&hdev->pdev->dev,
"Get rx common threshold fail, status = %d\n", status);
return status;
}
for (i = 0; i < 2; i++) {
req = (struct hclge_rx_com_thrd *)desc[i].data;
for (j = 0; j < HCLGE_TC_NUM_ONE_DESC; j++) {
idx = i * HCLGE_TC_NUM_ONE_DESC + j;
out_info->priv_wl[idx].high = req->com_thrd[j].high;
out_info->priv_wl[idx].low = req->com_thrd[j].low;
}
}
return 0;
}
int hns3_test_show_rx_priv_wl(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_dev *hdev = get_val_hdev(net_priv);
struct hns3_total_priv_wl_param *out_info;
struct hclge_rx_priv_wl_buf *req;
enum hclge_cmd_status status;
struct hclge_desc desc[2];
int idx;
int i;
int j;
out_info = (struct hns3_total_priv_wl_param *)buf_out;
for (i = 0; i < 2; i++) {
hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_RX_PRIV_WL_ALLOC,
true);
if (i == 0)
desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
desc[i].flag &= ~cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
}
status = hclge_cmd_send(&hdev->hw, desc, 2);
if (status) {
dev_err(&hdev->pdev->dev,
"Get rx private waterline fail, statu = %d\n", status);
return status;
}
for (i = 0; i < 2; i++) {
req = (struct hclge_rx_priv_wl_buf *)desc[i].data;
for (j = 0; j < HCLGE_TC_NUM_ONE_DESC; j++) {
idx = i * HCLGE_TC_NUM_ONE_DESC + j;
out_info->priv_wl[idx].high = req->tc_wl[j].high;
out_info->priv_wl[idx].low = req->tc_wl[j].low;
}
}
return 0;
}
int hns3_test_qcn_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
#define HCLGE_OPC_QCN_CFG 0x1A01
int qcn_bypass = *(int *)(buf_in);
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
u32 qcn_cfg;
int ret;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_CFG, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
return ret;
qcn_cfg = desc.data[0] & HNS3_QCN_SHAP_BYPASS_MASK;
hclge_cmd_reuse_desc(&desc, false);
desc.data[0] = (qcn_cfg | ((qcn_bypass << HNS3_QCN_SHAP_BYPASS_OFF) &
HNS3_QOS_QCN_BYPASS_MASK)) &
HNS3_QOS_QCN_MASK;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_QOS_H__
#define __HNS3_PRIV_QOS_H__
#include "hns3_priv_tm.h"
struct hns3_rx_priv_buff_wl_param {
u32 tc_no;
u32 high_wl;
u32 low_wl;
u8 is_read;
};
struct hns3_tx_buff_param {
u16 buff_size[MAX_TC_NUM];
u8 is_read;
};
struct hns3_rx_buff_param {
u16 buff_size[MAX_TC_NUM];
u16 share_buff;
u8 is_read;
};
struct hns3_rx_priv_wl {
u16 high;
u16 low;
};
struct hns3_total_priv_wl_param {
struct hns3_rx_priv_wl priv_wl[MAX_TC_NUM];
};
enum opt_type {
IS_READ = 1,
IS_WRITE,
};
#define HNS3_QOS_QCN_MASK 0xF0000
#define HNS3_QCN_SHAP_BYPASS_MASK 0xCFFFF
#define HNS3_QOS_QCN_BYPASS_MASK 0x20000
#define HNS3_QCN_SHAP_BYPASS_OFF 17
int hns3_test_rx_priv_buff_wl_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_common_thrd_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_common_wl_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_tx_buff_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_rx_buff_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_show_rx_priv_wl(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_show_comm_thres(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_qcn_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hns3_priv_qres.h"
int hns3_get_qres_rx_value(struct hns3_nic_priv *net_priv, int ring_id,
enum param_type type)
{
struct hns3_enet_ring *ring;
int tqps_num;
int num;
tqps_num = net_priv->ae_handle->kinfo.num_tqps;
ring = net_priv->ring_data[ring_id + tqps_num].ring;
switch (type) {
case RX_HEAD_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_RX_RING_HEAD_REG);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case RX_TAIL_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_RX_RING_TAIL_REG);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case RX_EBD_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_RX_RING_EBDNUM_REG_ADRR);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case RX_FBD_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_RX_RING_FBDNUM_REG);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case RX_SOFTWARE_HEAD_TYPE:
num = ring->next_to_use;
break;
case RX_SOFTWARE_TAIL_TYPE:
num = ring->next_to_clean;
break;
default:
pr_err("please input valid param type!\n");
return -1;
}
return num;
}
int hns3_get_qres_tx_value(struct hns3_nic_priv *net_priv, int ring_id,
enum param_type type)
{
struct hns3_enet_ring *ring;
int num;
ring = net_priv->ring_data[ring_id].ring;
switch (type) {
case TX_HEAD_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_TX_RING_HEAD_REG);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case TX_TAIL_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_TX_RING_TAIL_REG);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case TX_EBD_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_TX_RING_EBDNUM_REG_ADRR);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case TX_FBD_TYPE:
num = readl_relaxed(ring->tqp->io_base +
HNS3_RING_TX_RING_FBDNUM_REG);
/* Make sure num taken effect before other data is touched */
rmb();
break;
case TX_SOFTWARE_HEAD_TYPE:
num = ring->next_to_use;
break;
case TX_SOFTWARE_TAIL_TYPE:
num = ring->next_to_clean;
break;
default:
pr_err("please input valid param type!\n");
return -1;
}
return num;
}
int hns3_test_qres_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct qres_bufin_param *qres_in_param;
struct hns3_enet_ring *ring;
struct qres_param *out_info;
int bd_index;
int tqps_num;
int ring_id;
tqps_num = net_priv->ae_handle->kinfo.num_tqps;
out_info = (struct qres_param *)buf_out;
qres_in_param = (struct qres_bufin_param *)buf_in;
ring_id = qres_in_param->queue_id;
bd_index = qres_in_param->BD_id;
out_info->num_tqps = tqps_num;
if (ring_id >= tqps_num || ring_id < 0) {
pr_err("please input valid qid\n");
return -1;
}
if (qres_in_param->mtype == MTYPE_QUEUE_INFO) {
out_info->qid = ring_id;
out_info->rx_head = hns3_get_qres_rx_value(net_priv, ring_id,
RX_HEAD_TYPE);
out_info->rx_tail = hns3_get_qres_rx_value(net_priv, ring_id,
RX_TAIL_TYPE);
out_info->rx_ebd = hns3_get_qres_rx_value(net_priv, ring_id,
RX_EBD_TYPE);
out_info->rx_fbd = hns3_get_qres_rx_value(net_priv, ring_id,
RX_FBD_TYPE);
out_info->rx_software_head =
hns3_get_qres_rx_value(net_priv, ring_id,
RX_SOFTWARE_HEAD_TYPE);
out_info->rx_software_tail =
hns3_get_qres_rx_value(net_priv, ring_id,
RX_SOFTWARE_TAIL_TYPE);
/* tx info */
out_info->tx_head = hns3_get_qres_tx_value(net_priv, ring_id,
TX_HEAD_TYPE);
out_info->tx_tail = hns3_get_qres_tx_value(net_priv, ring_id,
TX_TAIL_TYPE);
out_info->tx_ebd = hns3_get_qres_tx_value(net_priv, ring_id,
TX_EBD_TYPE);
out_info->tx_fbd = hns3_get_qres_tx_value(net_priv, ring_id,
TX_FBD_TYPE);
out_info->tx_software_head =
hns3_get_qres_tx_value(net_priv, ring_id,
TX_SOFTWARE_HEAD_TYPE);
out_info->tx_software_tail =
hns3_get_qres_tx_value(net_priv, ring_id,
TX_SOFTWARE_TAIL_TYPE);
} else if (qres_in_param->mtype == MTYPE_BD_INFO) {
if (qres_in_param->queue_type == TYPE_TX) {
ring = net_priv->ring_data[ring_id].ring;
if (bd_index >= ring->desc_num || bd_index < 0) {
out_info->num_bd = ring->desc_num;
pr_err("please input valid TX BD_id\n");
return -1;
}
out_info->desc = ring->desc[bd_index];
} else if (qres_in_param->queue_type == TYPE_RX) {
ring = net_priv->ring_data[ring_id + tqps_num].ring;
if (bd_index >= ring->desc_num || bd_index < 0) {
out_info->num_bd = ring->desc_num;
pr_err("please input valid RX BD_id\n");
return -1;
}
out_info->desc = ring->desc[bd_index];
}
}
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_QRES_H__
#define __HNS3_PRIV_QRES_H__
#include "hclge_main.h"
#include "hclge_cmd.h"
#include "hns3_enet.h"
#define HNS3_RING_RX_RING_EBDNUM_REG_ADRR 0x00008
#define HNS3_RING_TX_RING_EBDNUM_REG_ADRR 0x00068
struct qres_param {
int qid;
int tx_head;
int tx_tail;
int tx_ebd;
int tx_fbd;
int tx_software_head; /* next_to_use */
int tx_software_tail; /* next_to_clean */
int rx_head;
int rx_tail;
int rx_ebd;
int rx_fbd;
int rx_software_head;
int rx_software_tail;
int num_tqps;
int num_bd;
struct hns3_desc desc; /* dma map address space */
};
enum param_type {
TX_HEAD_TYPE,
TX_TAIL_TYPE,
TX_EBD_TYPE,
TX_FBD_TYPE,
TX_SOFTWARE_TAIL_TYPE,
TX_SOFTWARE_HEAD_TYPE,
RX_HEAD_TYPE,
RX_TAIL_TYPE,
RX_EBD_TYPE,
RX_FBD_TYPE,
RX_SOFTWARE_TAIL_TYPE,
RX_SOFTWARE_HEAD_TYPE,
};
struct qres_bufin_param {
int BD_id;
int queue_type;
int mtype;
int queue_id;
};
enum qres_main_type {
MTYPE_NULL,
MTYPE_BD_INFO,
MTYPE_QUEUE_INFO,
};
enum qres_queue_type {
TYPE_NULL,
TYPE_RX,
TYPE_TX,
};
int hns3_test_qres_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#ifdef CONFIG_HNS3_TEST
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/phy_fixed.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_rss.h"
#define HASH_ALG_MASK 0XFC
static int hclge_set_rss_algo_key(struct hclge_dev *hdev,
const u8 hfunc, const u8 *key)
{
struct hclge_rss_config_cmd *req;
enum hclge_cmd_status status;
struct hclge_desc desc;
int key_offset;
int key_size;
req = (struct hclge_rss_config_cmd *)desc.data;
for (key_offset = 0; key_offset < 3; key_offset++) {
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_GENERIC_CONFIG,
false);
req->hash_config |= (hfunc & HCLGE_RSS_HASH_ALGO_MASK);
req->hash_config |= (key_offset << HCLGE_RSS_HASH_KEY_OFFSET_B);
if (key_offset == 2)
key_size =
HCLGE_RSS_KEY_SIZE - HCLGE_RSS_HASH_KEY_NUM * 2;
else
key_size = HCLGE_RSS_HASH_KEY_NUM;
memcpy(req->hash_key,
key + key_offset * HCLGE_RSS_HASH_KEY_NUM, key_size);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev,
"Configure RSS algo fail, status = %d\n",
status);
return -EINVAL;
}
}
return 0;
}
static int hns3_test_set_rss_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_rss_config_cmd *in_info;
enum hclge_cmd_status status;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u8 hash_config;
u8 *key;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
key = vport->rss_hash_key;
in_info = (struct hclge_rss_config_cmd *)buf_in;
hash_config =
((u8)(vport->rss_algo) & (HASH_ALG_MASK)) | in_info->hash_config;
status = hclge_set_rss_algo_key(hdev, hash_config, key);
if (status) {
dev_err(&hdev->pdev->dev,
"hclge_set_rss_algo_key, status = %d\n", status);
return -EINVAL;
}
vport->rss_algo = hash_config;
return 0;
}
static int hns3_test_get_rss_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hclge_rss_config_cmd *req;
enum hclge_cmd_status status;
u8 *out_buf = (u8 *)buf_out;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_GENERIC_CONFIG, true);
status = hclge_cmd_send(&hdev->hw, &desc, 1);
if (status) {
dev_err(&hdev->pdev->dev, "%s fail, status is %d.\n",
__func__, status);
return status;
}
req = (struct hclge_rss_config_cmd *)desc.data;
*out_buf = req->hash_config;
return 0;
}
int hns3_test_rss_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct rss_config *mode_param;
int ret;
mode_param = (struct rss_config *)buf_in;
if (!mode_param) {
pr_err("%s error: mode_param NULL.\n", __func__);
return -EINVAL;
}
if (mode_param->is_read == 1)
ret = hns3_test_get_rss_cfg(net_priv, buf_in, in_size, buf_out,
out_size);
else
ret = hns3_test_set_rss_cfg(net_priv, buf_in, in_size, buf_out,
out_size);
return ret;
}
#endif
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_RSS_H
#define __HNS3_PRIV_RSS_H
#define RSS_HASH_KEY_NUM 40
struct rss_config {
u8 hash_config;
u8 rsv[7];
u8 hash_key[RSS_HASH_KEY_NUM];
u8 is_read;
};
int hns3_test_rss_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include "hns3_priv_stat.h"
const struct ring_stats_name hns3_ring_stats_name[] = {
{"io_err_cnt", IO_ERR_CNT},
{"sw_err_cnt", SW_ERR_CNT},
{"seg_pkt_cnt", SEG_PKT_CNT},
{"tx_pkts", TX_PKTS},
{"tx_bytes", TX_BYTES},
{"tx_err_cnt", TX_ERR_CNT},
{"restart_queue", RESTART_QUEUE},
{"tx_busy", TX_BUSY},
{"rx_pkts", RX_PKTS},
{"rx_bytes", RX_BYTES},
{"rx_err_cnt", RX_ERR_CNT},
{"reuse_pg_cnt", REUSE_PG_CNT},
{"err_pkt_len", ERR_PKT_LEN},
{"err_bd_num", ERR_BD_NUM},
{"l2_err", L2_ERR},
{"l3l4_csum_err", L3L4_CSUM_ERR},
{"rx_multicast", RX_MULTICAST},
};
static int hns3_get_stat_val(struct ring_stats *r_stats, char val_name[],
u64 **val)
{
u32 stats_name_id = 0;
u32 i;
if (!r_stats || !val_name || !val) {
pr_info("%s param is null.\n", __func__);
return HCLGE_ERR_CSQ_ERROR;
}
*val = NULL;
for (i = 0; i < ARRAY_SIZE(hns3_ring_stats_name); i++) {
if (!strcmp(val_name, hns3_ring_stats_name[i].stats_name)) {
stats_name_id = hns3_ring_stats_name[i].stats_namd_id;
break;
}
}
switch (stats_name_id) {
case IO_ERR_CNT:
*val = &r_stats->io_err_cnt;
break;
case SW_ERR_CNT:
*val = &r_stats->sw_err_cnt;
break;
case SEG_PKT_CNT:
*val = &r_stats->seg_pkt_cnt;
break;
case TX_PKTS:
*val = &r_stats->tx_pkts;
break;
case TX_BYTES:
*val = &r_stats->tx_bytes;
break;
case TX_ERR_CNT:
*val = &r_stats->tx_err_cnt;
break;
case RESTART_QUEUE:
*val = &r_stats->restart_queue;
break;
case TX_BUSY:
*val = &r_stats->tx_busy;
break;
case RX_PKTS:
*val = &r_stats->rx_pkts;
break;
case RX_BYTES:
*val = &r_stats->rx_bytes;
break;
case RX_ERR_CNT:
*val = &r_stats->rx_err_cnt;
break;
case REUSE_PG_CNT:
*val = &r_stats->reuse_pg_cnt;
break;
case ERR_PKT_LEN:
*val = &r_stats->err_pkt_len;
break;
case ERR_BD_NUM:
*val = &r_stats->err_bd_num;
break;
case L2_ERR:
*val = &r_stats->l2_err;
break;
case L3L4_CSUM_ERR:
*val = &r_stats->l3l4_csum_err;
break;
case RX_MULTICAST:
*val = &r_stats->rx_multicast;
break;
default:
pr_info("val name [%s] is not existed.\n", val_name);
return HCLGE_ERR_CSQ_ERROR;
}
return HCLGE_STATUS_SUCCESS;
}
int hns3_read_stat_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct stat_sw_mode_param *stat_sw_param;
struct hnae3_knic_private_info *kinfo;
u64 *ret_data = (u64 *)buf_out;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u64 *val = NULL;
u32 ring_idx;
int ret;
handle = nic_dev->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
kinfo = &handle->kinfo;
stat_sw_param = (struct stat_sw_mode_param *)buf_in;
if (!buf_out || !out_size) {
dev_err(&hdev->pdev->dev, "Get stat buf out is null.\n");
return HCLGE_ERR_CSQ_ERROR;
}
ring_idx = stat_sw_param->ring_idx;
if (ring_idx >= kinfo->num_tqps) {
dev_err(&hdev->pdev->dev,
"Get stat ring_idx[%d] >= num_tqps[%d].\n", ring_idx,
kinfo->num_tqps);
return HCLGE_ERR_CSQ_ERROR;
}
if (stat_sw_param->is_rx)
ring_idx += kinfo->num_tqps;
ret = hns3_get_stat_val(&nic_dev->ring_data[ring_idx].ring->stats,
stat_sw_param->val_name, &val);
if (ret || !val) {
pr_info("get stat val name [%s] error.\n",
stat_sw_param->val_name);
return HCLGE_ERR_CSQ_ERROR;
}
*ret_data = le64_to_cpu(*val);
*out_size = sizeof(u64);
return HCLGE_STATUS_SUCCESS;
}
int hns3_set_stat_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct stat_sw_mode_param *stat_sw_param;
struct hnae3_knic_private_info *kinfo;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u64 *val = NULL;
u32 ring_idx;
int ret;
handle = nic_dev->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
kinfo = &handle->kinfo;
stat_sw_param = (struct stat_sw_mode_param *)buf_in;
if (!buf_in) {
dev_err(&hdev->pdev->dev, "Set stat buf in is null.\n");
return HCLGE_ERR_CSQ_ERROR;
}
ring_idx = stat_sw_param->ring_idx;
if (ring_idx >= kinfo->num_tqps) {
dev_err(&hdev->pdev->dev,
"Set stat ring_idx[%d] >= num_tqps[%d].\n", ring_idx,
kinfo->num_tqps);
return HCLGE_ERR_CSQ_ERROR;
}
if (stat_sw_param->is_rx)
ring_idx += kinfo->num_tqps;
ret = hns3_get_stat_val(&nic_dev->ring_data[ring_idx].ring->stats,
stat_sw_param->val_name, &val);
if (ret || !val) {
pr_info("Set stat val name [%s] error.\n",
stat_sw_param->val_name);
return HCLGE_ERR_CSQ_ERROR;
}
*val = cpu_to_le64(stat_sw_param->data);
return HCLGE_STATUS_SUCCESS;
}
int hns3_stat_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct stat_sw_mode_param *mode_param;
int ret = 0;
mode_param = (struct stat_sw_mode_param *)buf_in;
if (mode_param->is_read == 1)
ret = hns3_read_stat_mode_cfg(nic_dev, buf_in, in_size, buf_out,
out_size);
else
ret = hns3_set_stat_mode_cfg(nic_dev, buf_in, in_size, buf_out,
out_size);
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_STAT_H__
#define __HNS3_PRIV_STAT_H__
#include "hclge_main.h"
#include "hclge_cmd.h"
#include "hns3_enet.h"
struct stat_sw_mode_param {
u64 data;
u32 ring_idx;
u8 val_name[24];
u8 is_read;
u8 is_rx;
};
enum stats_name_type {
IO_ERR_CNT = 1,
SW_ERR_CNT,
SEG_PKT_CNT,
TX_PKTS,
TX_BYTES,
TX_ERR_CNT,
RESTART_QUEUE,
TX_BUSY,
RX_PKTS,
RX_BYTES,
RX_ERR_CNT,
REUSE_PG_CNT,
ERR_PKT_LEN,
ERR_BD_NUM,
L2_ERR,
L3L4_CSUM_ERR,
RX_MULTICAST,
};
struct ring_stats_name {
u8 stats_name[24];
u32 stats_namd_id;
};
int hns3_stat_mode_cfg(struct hns3_nic_priv *nic_dev,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kthread.h>
#include "hnae3.h"
#include "hclge_main.h"
#include "hclge_tm.h"
#include "hclge_cmd.h"
#include "hns3_priv_tm.h"
static int hns3_test_tm_schd_mode_set(struct hclge_dev *hdev,
enum hclge_opcode_type opcode,
u8 mode, u16 id)
{
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, opcode, false);
if (mode == HCLGE_SCH_MODE_DWRR)
desc.data[1] = 1;
else
desc.data[1] = 0;
desc.data[0] = cpu_to_le32(id);
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
static int hns3_test_tm_schd_mode_get(struct hclge_dev *hdev,
enum hclge_opcode_type opcode,
u8 *mode, u16 id)
{
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, opcode, true);
desc.data[0] = cpu_to_le32(id);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*mode = desc.data[1];
return ret;
}
int hns3_test_tm_q_to_qs_set(struct hclge_dev *hdev, u16 q_id, u16 qs_id)
{
struct hclge_nq_to_qs_link_cmd *map;
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_NQ_TO_QS_LINK, false);
map = (struct hclge_nq_to_qs_link_cmd *)desc.data;
map->nq_id = cpu_to_le16(q_id);
map->qset_id = cpu_to_le16(qs_id | HCLGE_TM_Q_QS_LINK_VLD_MSK);
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_q_to_qs_get(struct hclge_dev *hdev, u16 q_id, u16 *qs_id)
{
struct hclge_nq_to_qs_link_cmd *map;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_NQ_TO_QS_LINK, true);
map = (struct hclge_nq_to_qs_link_cmd *)desc.data;
map->nq_id = cpu_to_le16(q_id);
map->qset_id = cpu_to_le16(*qs_id | HCLGE_TM_Q_QS_LINK_VLD_MSK);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*qs_id = map->qset_id & HNS3_TEST_QS_ID_MSK;
return ret;
}
int hns3_test_tm_qs_to_pri_set(struct hclge_dev *hdev, u16 qs_id, u8 pri)
{
struct hclge_qs_to_pri_link_cmd *map;
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_TO_PRI_LINK, false);
map = (struct hclge_qs_to_pri_link_cmd *)desc.data;
map->qs_id = cpu_to_le16(qs_id);
map->priority = pri;
map->link_vld = HCLGE_TM_QS_PRI_LINK_VLD_MSK;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_qs_to_pri_get(struct hclge_dev *hdev, u16 qs_id, u8 *pri)
{
struct hclge_qs_to_pri_link_cmd *map;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_TO_PRI_LINK, true);
map = (struct hclge_qs_to_pri_link_cmd *)desc.data;
map->qs_id = cpu_to_le16(qs_id);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*pri = map->priority;
return ret;
}
int hns3_test_tm_qs_weight_set(struct hclge_dev *hdev, u16 qs_id, u8 dwrr)
{
struct hclge_qs_weight_cmd *weight;
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_WEIGHT, false);
weight = (struct hclge_qs_weight_cmd *)desc.data;
weight->qs_id = cpu_to_le16(qs_id);
weight->dwrr = dwrr;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_qs_weight_get(struct hclge_dev *hdev, u16 qs_id, u8 *dwrr)
{
struct hclge_qs_weight_cmd *weight;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_QS_WEIGHT, true);
weight = (struct hclge_qs_weight_cmd *)desc.data;
weight->qs_id = cpu_to_le16(qs_id);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*dwrr = weight->dwrr;
return ret;
}
int hns3_test_tm_pri_weight_set(struct hclge_dev *hdev, u8 pri_id, u8 dwrr)
{
struct hclge_priority_weight_cmd *weight;
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PRI_WEIGHT, false);
weight = (struct hclge_priority_weight_cmd *)desc.data;
weight->pri_id = pri_id;
weight->dwrr = dwrr;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_pri_weight_get(struct hclge_dev *hdev, u8 pri_id, u8 *dwrr)
{
struct hclge_priority_weight_cmd *weight;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PRI_WEIGHT, true);
weight = (struct hclge_priority_weight_cmd *)desc.data;
weight->pri_id = pri_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*dwrr = weight->dwrr;
return ret;
}
int hns3_test_tm_pri_pg_bitmap_set(struct hclge_dev *hdev, u8 pg_id, u8 bitmap)
{
struct hclge_pg_to_pri_link_cmd *map;
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_TO_PRI_LINK, false);
map = (struct hclge_pg_to_pri_link_cmd *)desc.data;
map->pg_id = cpu_to_le16(pg_id);
map->pri_bit_map = bitmap;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_pri_pg_bitmap_get(struct hclge_dev *hdev, u8 pg_id,
u8 *bitmap)
{
struct hclge_pg_to_pri_link_cmd *map;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_TO_PRI_LINK, true);
map = (struct hclge_pg_to_pri_link_cmd *)desc.data;
map->pg_id = cpu_to_le16(pg_id);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
return ret;
*bitmap = map->pri_bit_map;
return 0;
}
int hns3_test_tm_qs_bp_bitmap_set(struct hclge_dev *hdev, u8 tc, u8 gp_id,
u32 map)
{
struct hclge_bp_to_qs_map_cmd *bp_to_qs_map_cmd;
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_BP_TO_QSET_MAPPING,
false);
bp_to_qs_map_cmd = (struct hclge_bp_to_qs_map_cmd *)desc.data;
bp_to_qs_map_cmd->tc_id = tc;
bp_to_qs_map_cmd->qs_group_id = gp_id;
/* Qset and tc is one by one mapping */
bp_to_qs_map_cmd->qs_bit_map = map;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_qs_bp_bitmap_get(struct hclge_dev *hdev, u8 tc, u8 gp_id,
u32 *map)
{
struct hclge_bp_to_qs_map_cmd *bp_to_qs_map_cmd;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_BP_TO_QSET_MAPPING,
true);
bp_to_qs_map_cmd = (struct hclge_bp_to_qs_map_cmd *)desc.data;
bp_to_qs_map_cmd->tc_id = tc;
bp_to_qs_map_cmd->qs_group_id = gp_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
return ret;
*map = bp_to_qs_map_cmd->qs_bit_map;
return 0;
}
int hns3_test_tm_pri_shapping_set(struct hclge_dev *hdev,
enum hclge_shap_bucket bucket, u8 pri_id,
u32 shaper)
{
struct hclge_pri_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
opcode = bucket == HCLGE_TM_SHAP_P_BUCKET ?
HCLGE_OPC_TM_PRI_P_SHAPPING : HCLGE_OPC_TM_PRI_C_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, false);
shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data;
shap_cfg_cmd->pri_id = pri_id;
shap_cfg_cmd->pri_shapping_para = shaper;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_pri_shapping_get(struct hclge_dev *hdev,
enum hclge_shap_bucket bucket, u8 pri_id,
u32 *shaper)
{
struct hclge_pri_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
int ret;
opcode = bucket == HCLGE_TM_SHAP_P_BUCKET ?
HCLGE_OPC_TM_PRI_P_SHAPPING : HCLGE_OPC_TM_PRI_C_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, true);
shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data;
shap_cfg_cmd->pri_id = pri_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
*shaper = shap_cfg_cmd->pri_shapping_para;
return ret;
}
int hns3_test_tm_pg_weight_set(struct hclge_dev *hdev, u8 pg_id, u8 dwrr)
{
struct hclge_pg_weight_cmd *weight;
struct hclge_desc desc;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_WEIGHT, false);
weight = (struct hclge_pg_weight_cmd *)desc.data;
weight->pg_id = pg_id;
weight->dwrr = dwrr;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_pg_weight_get(struct hclge_dev *hdev, u8 pg_id, u8 *dwrr)
{
struct hclge_pg_weight_cmd *weight;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_PG_WEIGHT, true);
weight = (struct hclge_pg_weight_cmd *)desc.data;
weight->pg_id = pg_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*dwrr = weight->dwrr;
return ret;
}
int hns3_test_tm_pg_shapping_set(struct hclge_dev *hdev,
enum hclge_shap_bucket bucket, u8 pg_id,
u32 shaper)
{
struct hclge_pg_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
opcode = bucket == HCLGE_TM_SHAP_P_BUCKET ? HCLGE_OPC_TM_PG_P_SHAPPING :
HCLGE_OPC_TM_PG_C_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, false);
shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
shap_cfg_cmd->pg_id = pg_id;
shap_cfg_cmd->pg_shapping_para = shaper;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_pg_shapping_get(struct hclge_dev *hdev,
enum hclge_shap_bucket bucket, u8 pg_id,
u32 *shaper)
{
struct hclge_pg_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
int ret;
opcode = bucket == HCLGE_TM_SHAP_P_BUCKET ? HCLGE_OPC_TM_PG_P_SHAPPING :
HCLGE_OPC_TM_PG_C_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, true);
shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data;
shap_cfg_cmd->pg_id = pg_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*shaper = shap_cfg_cmd->pg_shapping_para;
return ret;
}
int hns3_test_tm_port_shapping_set(struct hclge_dev *hdev, u32 shaper)
{
struct hclge_port_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
opcode = HCLGE_OPC_TM_PORT_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, false);
shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data;
shap_cfg_cmd->port_shapping_para = shaper;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
int hns3_test_tm_port_shapping_get(struct hclge_dev *hdev, u32 *shaper)
{
struct hclge_port_shapping_cmd *shap_cfg_cmd;
enum hclge_opcode_type opcode;
struct hclge_desc desc;
int ret;
opcode = HCLGE_OPC_TM_PORT_SHAPPING;
hclge_cmd_setup_basic_desc(&desc, opcode, true);
shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret)
*shaper = shap_cfg_cmd->port_shapping_para;
return ret;
}
static int hns3_test_tm_ets_tc_dwrr_set(struct hclge_dev *hdev, u8 *weight)
{
#define DEFAULT_TC_WEIGHT 1
#define DEFAULT_TC_OFFSET 14
struct nictool_ets_tc_weight_cmd *ets_weight;
struct hclge_desc desc;
int i;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ETS_TC_WEIGHT, false);
ets_weight = (struct nictool_ets_tc_weight_cmd *)desc.data;
for (i = 0; i < MAX_TC_NUM; i++)
ets_weight->tc_weight[i] = weight[i];
ets_weight->weight_offset = DEFAULT_TC_OFFSET;
return hclge_cmd_send(&hdev->hw, &desc, 1);
}
static int hns3_test_tm_ets_tc_dwrr_get(struct hclge_dev *hdev, u8 *weight)
{
struct nictool_ets_tc_weight_cmd *ets_weight;
struct hclge_desc desc;
int ret, i;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ETS_TC_WEIGHT, true);
ets_weight = (struct nictool_ets_tc_weight_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (!ret) {
for (i = 0; i < MAX_TC_NUM; i++)
weight[i] = ets_weight->tc_weight[i];
}
return ret;
}
static int hns3_test_tm_operate_nic_regs(struct hclge_dev *hdev,
u64 addr, u64 *value, u8 is_read)
{
#define HNS3_WRITE_READ_REG_CMD 0x7014
struct hclge_desc desc;
int ret;
if (is_read) {
hclge_cmd_setup_basic_desc(&desc, HNS3_WRITE_READ_REG_CMD,
true);
desc.data[0] = (u32)(addr & 0xffffffff);
desc.data[1] = (u32)(addr >> 32);
desc.data[4] = 32;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"read addr 0x%llx failed! ret = %d.\n",
addr, ret);
return ret;
}
*value = (u64)desc.data[2] | ((u64)desc.data[3] << 32);
} else {
hclge_cmd_setup_basic_desc(&desc, HNS3_WRITE_READ_REG_CMD,
false);
desc.data[0] = (u32)(addr & 0xffffffff);
desc.data[1] = (u32)(addr >> 32);
desc.data[2] = (u32)(*value & 0xffffffff);
desc.data[3] = (u32)(*value >> 32);
desc.data[4] = 32;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
" write addr 0x%llx value 0x%llx failed! ret = %d.\n",
addr, *value, ret);
return ret;
}
}
return 0;
}
int hns3_test_queue_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct nictool_queue_cfg_info *in_info;
struct nictool_queue_cfg_info *out_info;
struct hclge_dev *hdev;
int is_read;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_queue_cfg_info *)buf_in;
out_info = (struct nictool_queue_cfg_info *)buf_out;
is_read = in_info->is_read;
if (is_read) {
out_info->queue_id = in_info->queue_id;
if (hns3_test_tm_q_to_qs_get(hdev, in_info->queue_id,
&out_info->qs)) {
pr_err("%s,%d:get queue(%d) to qs failed!\n", __func__,
__LINE__, in_info->queue_id);
return -1;
}
} else {
if (hns3_test_tm_q_to_qs_set(hdev, in_info->queue_id,
in_info->qs)) {
pr_err("%s,%d:set queue(%d) to qs(%d) failed!\n",
__func__, __LINE__,
in_info->queue_id, in_info->qs);
return -1;
}
}
return 0;
}
static int hns3_test_qs_set_new_map(int tc, u32 map,
struct hclge_dev *hdev,
struct nictool_qs_cfg_info *in_info)
{
u32 bp_map = map;
u16 qs_id;
int gp_id;
int offset;
qs_id = in_info->qs_id;
gp_id = qs_id / 32;
offset = qs_id % 32;
if (tc < MAX_TC_NUM) {
/* clear old bit */
bp_map &= ~BIT(offset);
if (hns3_test_tm_qs_bp_bitmap_set(hdev, tc, gp_id, bp_map)) {
pr_err("%s,%d:set qs(%d) bp map failed!\n", __func__,
__LINE__, qs_id);
return -1;
}
/* set new bit */
if (hns3_test_tm_qs_bp_bitmap_get
(hdev, in_info->tc, gp_id, &bp_map)) {
pr_err("%s,%d:get qs(%d) bp map failed!\n", __func__,
__LINE__, qs_id);
return -1;
}
bp_map |= BIT(offset);
if (hns3_test_tm_qs_bp_bitmap_set
(hdev, in_info->tc, gp_id, bp_map)) {
pr_err("%s,%d:set qs(%d) bp map failed!\n", __func__,
__LINE__, qs_id);
return -1;
}
}
return 0;
}
int hns3_test_qs_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct nictool_qs_cfg_info *out_info;
struct nictool_qs_cfg_info *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
int is_read;
int offset;
u32 bp_map;
u16 qs_id;
int gp_id;
int tc;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_qs_cfg_info *)buf_in;
out_info = (struct nictool_qs_cfg_info *)buf_out;
is_read = in_info->is_read;
qs_id = in_info->qs_id;
gp_id = qs_id / 32;
offset = qs_id % 32;
for (tc = 0; tc < MAX_TC_NUM; tc++) {
if (hns3_test_tm_qs_bp_bitmap_get(hdev, tc, gp_id, &bp_map)) {
pr_err("%s,%d:get qs(%d) bp map failed!\n", __func__,
__LINE__, qs_id);
return -1;
}
if (bp_map & BIT(offset))
break;
}
if (is_read) {
out_info->qs_id = qs_id;
out_info->tc = tc;
if (hns3_test_tm_qs_to_pri_get(hdev, qs_id, &out_info->pri)) {
pr_err("%s,%d:get qs(%d) to pri failed!\n", __func__,
__LINE__, qs_id);
return -1;
}
if (hns3_test_tm_schd_mode_get
(hdev, HCLGE_OPC_TM_QS_SCH_MODE_CFG, &out_info->mode,
qs_id)) {
pr_err("%s,%d:get qs(%d) mode failed!\n", __func__,
__LINE__, qs_id);
return -1;
}
if (hns3_test_tm_qs_weight_get(hdev, qs_id,
&out_info->weight)) {
pr_err("%s,%d:get qs(%d) weight failed!\n", __func__,
__LINE__, qs_id);
return -1;
}
} else {
if ((in_info->flag & HNS3_TM_QSET_MAPPING_FLAG) &&
hns3_test_tm_qs_to_pri_set(hdev, qs_id, in_info->pri)) {
pr_err("%s,%d:set qs(%d) to pri(%d) failed!\n",
__func__, __LINE__, qs_id, in_info->pri);
return -1;
}
if ((in_info->flag & HNS3_TM_QSET_MODE_CFG_FLAG) &&
hns3_test_tm_schd_mode_set(hdev,
HCLGE_OPC_TM_QS_SCH_MODE_CFG,
in_info->mode, qs_id)) {
pr_err("%s,%d:set qs(%d) mode(%d) failed!\n", __func__,
__LINE__, qs_id, in_info->mode);
return -1;
}
if ((in_info->flag & HNS3_TM_QSET_WEIGHT_CFG_FLAG) &&
hns3_test_tm_qs_weight_set(hdev, qs_id, in_info->weight)) {
pr_err("%s,%d:set qs(%d) weight(%d) failed!\n",
__func__, __LINE__, qs_id, in_info->weight);
return -1;
}
if ((in_info->flag & HNS3_TM_QSET_BP_CFG_FLAG) &&
hns3_test_qs_set_new_map(tc, bp_map, hdev, in_info)) {
pr_err("%s,%d:set qset %d bp cfg to tc %d failed!\n",
__func__, __LINE__, qs_id, in_info->tc);
return -1;
}
}
return 0;
}
static int hns3_test_pri_pg_set_map(struct hclge_dev *hdev,
int cur_pg, u8 map,
struct nictool_pri_cfg_info *in_info)
{
u8 bitmap = map;
u16 pri_id = in_info->pri_id;
/* clear old map */
if (in_info->pg != cur_pg) {
bitmap &= ~BIT(pri_id);
if (hns3_test_tm_pri_pg_bitmap_set(hdev, cur_pg, bitmap)) {
pr_err("%s,%d:set pg(%d) pri_map failed!\n", __func__,
__LINE__, cur_pg);
return -1;
}
bitmap = 0;
if (hns3_test_tm_pri_pg_bitmap_get(hdev, in_info->pg,
&bitmap)) {
pr_err("%s,%d:get pg(%d) pri_map failed!\n", __func__,
__LINE__, in_info->pg);
return -1;
}
}
/* set new map */
bitmap |= BIT(pri_id);
if (hns3_test_tm_pri_pg_bitmap_set(hdev, in_info->pg, bitmap)) {
pr_err("%s,%d:set pg(%d) pri_map failed!\n", __func__, __LINE__,
in_info->pg);
return -1;
}
return 0;
}
int hns3_test_pri_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct nictool_pri_cfg_info *out_info;
struct nictool_pri_cfg_info *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
int is_read;
u16 pri_id;
int cur_pg;
u8 bitmap;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_pri_cfg_info *)buf_in;
out_info = (struct nictool_pri_cfg_info *)buf_out;
is_read = in_info->is_read;
pri_id = in_info->pri_id;
for (cur_pg = 0; cur_pg < MAX_PG_NUM; cur_pg++) {
bitmap = 0;
if (hns3_test_tm_pri_pg_bitmap_get(hdev, cur_pg, &bitmap)) {
pr_err("%s,%d:get pg(%d) pri_map failed!\n", __func__,
__LINE__, cur_pg);
return -1;
}
if (bitmap & BIT(pri_id))
break;
}
if (cur_pg == MAX_PG_NUM) {
pr_err("%s,%d:find pri(%d) to pg failed!\n", __func__, __LINE__,
pri_id);
return -1;
}
if (is_read) {
out_info->pri_id = pri_id;
out_info->pg = cur_pg;
if (hns3_test_tm_pri_shapping_get(hdev, HCLGE_TM_SHAP_C_BUCKET,
pri_id,
&out_info->c_shaping)) {
pr_err("%s,%d:get pri(%d) c shaping failed!\n",
__func__, __LINE__, pri_id);
return -1;
}
if (hns3_test_tm_pri_shapping_get(hdev, HCLGE_TM_SHAP_P_BUCKET,
pri_id,
&out_info->p_shaping)) {
pr_err("%s,%d:get pri(%d) p shaping failed!\n",
__func__, __LINE__, pri_id);
return -1;
}
if (hns3_test_tm_schd_mode_get
(hdev, HCLGE_OPC_TM_PRI_SCH_MODE_CFG, &out_info->mode,
pri_id)) {
pr_err("%s,%d:get pri(%d) mode failed!\n", __func__,
__LINE__, pri_id);
return -1;
}
if (hns3_test_tm_pri_weight_get
(hdev, pri_id, &out_info->weight)) {
pr_err("%s,%d:set pri(%d) weight failed!\n", __func__,
__LINE__, pri_id);
return -1;
}
} else {
if ((in_info->flag & HNS3_TM_PRI_MAPPING_FLAG) &&
hns3_test_pri_pg_set_map(hdev, cur_pg, bitmap, in_info)) {
pr_err("%s,%d:set pri(%d) mapping to pg(%d) failed!\n",
__func__, __LINE__, pri_id, in_info->pg);
return -1;
}
if ((in_info->flag & HNS3_TM_PRI_CSHAP_CFG_FLAG) &&
hns3_test_tm_pri_shapping_set(hdev, HCLGE_TM_SHAP_C_BUCKET,
pri_id, in_info->c_shaping)) {
pr_err("%s,%d:set pri(%d) c shaping(%u)) failed!\n",
__func__, __LINE__, pri_id, in_info->c_shaping);
return -1;
}
if ((in_info->flag & HNS3_TM_PRI_PSHAP_CFG_FLAG) &&
hns3_test_tm_pri_shapping_set(hdev, HCLGE_TM_SHAP_P_BUCKET,
pri_id, in_info->p_shaping)) {
pr_err("%s,%d:set pri(%d) p shaping(%u) failed!\n",
__func__, __LINE__, pri_id, in_info->p_shaping);
return -1;
}
if ((in_info->flag & HNS3_TM_PRI_MODE_CFG_FLAG) &&
hns3_test_tm_schd_mode_set(hdev,
HCLGE_OPC_TM_PRI_SCH_MODE_CFG,
in_info->mode, pri_id)) {
pr_err("%s,%d:set pri(%d) mode(%d) failed!\n", __func__,
__LINE__, pri_id, in_info->mode);
return -1;
}
if ((in_info->flag & HNS3_TM_PRI_WEIGHT_CFG_FLAG) &&
hns3_test_tm_pri_weight_set(hdev, pri_id,
in_info->weight)) {
pr_err("%s,%d:set pri(%d) weight(%d) failed!\n",
__func__, __LINE__, pri_id, in_info->weight);
return -1;
}
}
return 0;
}
int hns3_test_pg_cfg(struct hns3_nic_priv *net_priv, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct nictool_pg_cfg_info *out_info;
struct nictool_pg_cfg_info *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
int is_read;
u16 pg_id;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_pg_cfg_info *)buf_in;
out_info = (struct nictool_pg_cfg_info *)buf_out;
is_read = in_info->is_read;
pg_id = in_info->pg_id;
if (is_read) {
out_info->pg_id = pg_id;
if (hns3_test_tm_pg_shapping_get(hdev, HCLGE_TM_SHAP_C_BUCKET,
pg_id,
&out_info->c_shaping)) {
pr_err("%s,%d:get pg(%d) c shaping failed!\n", __func__,
__LINE__, pg_id);
return -1;
}
if (hns3_test_tm_pg_shapping_get(hdev, HCLGE_TM_SHAP_P_BUCKET,
pg_id,
&out_info->p_shaping)) {
pr_err("%s,%d:get pg(%d) p shaping failed!\n", __func__,
__LINE__, pg_id);
return -1;
}
if (hns3_test_tm_schd_mode_get
(hdev, HCLGE_OPC_TM_PG_SCH_MODE_CFG, &out_info->mode,
pg_id)) {
pr_err("%s,%d:get pg(%d) mode failed!\n", __func__,
__LINE__, pg_id);
return -1;
}
if (hns3_test_tm_pg_weight_get(hdev, pg_id,
&out_info->weight)) {
pr_err("%s,%d:set pg(%d) weight failed!\n", __func__,
__LINE__, pg_id);
return -1;
}
} else {
if ((in_info->flag & HNS3_TM_PG_CSHAP_CFG_FLAG) &&
hns3_test_tm_pg_shapping_set(hdev, HCLGE_TM_SHAP_C_BUCKET,
pg_id, in_info->c_shaping)) {
pr_err("%s,%d:set pg(%d) c shaping(%u) failed!\n",
__func__, __LINE__, pg_id, in_info->c_shaping);
return -1;
}
if ((in_info->flag & HNS3_TM_PG_PSHAP_CFG_FLAG) &&
hns3_test_tm_pg_shapping_set(hdev, HCLGE_TM_SHAP_P_BUCKET,
pg_id, in_info->p_shaping)) {
pr_err("%s,%d:set pg(%d) p shaping(%u) failed!\n",
__func__, __LINE__, pg_id, in_info->p_shaping);
return -1;
}
if ((in_info->flag & HNS3_TM_PG_MODE_CFG_FLAG) &&
hns3_test_tm_schd_mode_set(hdev,
HCLGE_OPC_TM_PG_SCH_MODE_CFG,
in_info->mode, pg_id)) {
pr_err("%s,%d:set pg(%d) mode(%d) failed!\n", __func__,
__LINE__, pg_id, in_info->mode);
return -1;
}
if ((in_info->flag & HNS3_TM_PG_WEIGHT_CFG_FLAG) &&
hns3_test_tm_pg_weight_set(hdev, pg_id, in_info->weight)) {
pr_err("%s,%d:set pg(%d) weight(%d) failed!\n",
__func__, __LINE__, pg_id, in_info->weight);
return -1;
}
}
return 0;
}
int hns3_test_port_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
struct nictool_port_cfg_info *out_info;
struct nictool_port_cfg_info *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u16 port_id;
int is_read;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_port_cfg_info *)buf_in;
out_info = (struct nictool_port_cfg_info *)buf_out;
is_read = in_info->is_read;
port_id = in_info->port_id;
if (is_read) {
out_info->port_id = port_id;
if (hns3_test_tm_port_shapping_get(hdev, &out_info->shaping)) {
pr_err("%s,%d:get port p shaping failed!\n", __func__,
__LINE__);
return -1;
}
} else {
if ((in_info->flag & HNS3_TM_PORT_PSHAP_CFG_FLAG) &&
hns3_test_tm_port_shapping_set(hdev, in_info->shaping)) {
pr_err("%s,%d:set port p shaping(%u) failed!\n",
__func__, __LINE__, in_info->shaping);
return -1;
}
}
return 0;
}
int hns3_test_ets_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size)
{
#define HNS3_TM_ETS_PORT_SHAPING 0x130820850
struct nictool_ets_cfg_info *out_info;
struct nictool_ets_cfg_info *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
u8 weight[8];
int is_read;
u16 tc_id;
u8 mac_id;
u64 value;
u64 addr;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_ets_cfg_info *)buf_in;
out_info = (struct nictool_ets_cfg_info *)buf_out;
is_read = in_info->is_read;
tc_id = in_info->tc_id;
mac_id = in_info->mac_id;
addr = (u64)HNS3_TM_ETS_PORT_SHAPING + ((u64)mac_id << 20);
out_info->tc_id = tc_id;
out_info->mac_id = mac_id;
if (is_read) {
if (hns3_test_tm_ets_tc_dwrr_get(hdev, weight)) {
pr_err("%s,%d:get ets tc dwrr failed!\n", __func__,
__LINE__);
return -1;
}
out_info->weight = weight[tc_id];
if (hns3_test_tm_operate_nic_regs(hdev, addr, &value,
is_read)) {
pr_err("%s,%d:get ets port shaper failed!\n", __func__,
__LINE__);
return -1;
}
out_info->shaping = (u32)value;
} else {
if (hns3_test_tm_ets_tc_dwrr_get(hdev, weight)) {
pr_err("%s,%d:get ets tc dwrr failed!\n", __func__,
__LINE__);
return -1;
}
weight[tc_id] = in_info->weight;
if ((in_info->flag & HNS3_TM_ETS_TC_CFG_FLAG) &&
hns3_test_tm_ets_tc_dwrr_set(hdev, weight)) {
pr_err("%s,%d:set ets tc dwrr failed!\n", __func__,
__LINE__);
return -1;
}
value = (u64)in_info->shaping;
if ((in_info->flag & HNS3_TM_ETS_PSHAP_CFG_FLAG) &&
hns3_test_tm_operate_nic_regs(hdev, addr, &value,
is_read)) {
pr_err("%s,%d:set ets port shaping(%u) failed!\n",
__func__, __LINE__, in_info->shaping);
return -1;
}
}
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_TM_H__
#define __HNS3_PRIV_TM_H__
#include "hns3_enet.h"
#define MAX_QUEUE_NUM 16
#define MAX_PG_NUM 4
#define MAX_TC_NUM 8
#define HNS3_TEST_QS_ID_MSK (BIT(10) - 1)
#define HCLGE_OPC_TM_PORT_SCH_MODE_CFG 0x0811
#define HNS3_TM_QSET_MAPPING_FLAG 0x01
#define HNS3_TM_QSET_MODE_CFG_FLAG 0x02
#define HNS3_TM_QSET_WEIGHT_CFG_FLAG 0x04
#define HNS3_TM_QSET_BP_CFG_FLAG 0x08
#define HNS3_TM_PRI_MAPPING_FLAG 0x01
#define HNS3_TM_PRI_MODE_CFG_FLAG 0x02
#define HNS3_TM_PRI_WEIGHT_CFG_FLAG 0x04
#define HNS3_TM_PRI_CSHAP_CFG_FLAG 0x08
#define HNS3_TM_PRI_PSHAP_CFG_FLAG 0x10
#define HNS3_TM_PG_MODE_CFG_FLAG 0x01
#define HNS3_TM_PG_WEIGHT_CFG_FLAG 0x02
#define HNS3_TM_PG_CSHAP_CFG_FLAG 0x04
#define HNS3_TM_PG_PSHAP_CFG_FLAG 0x08
#define HNS3_TM_PORT_MODE_CFG_FLAG 0x01
#define HNS3_TM_PORT_WEIGHT_CFG_FLAG 0x02
#define HNS3_TM_PORT_PSHAP_CFG_FLAG 0x04
#define HNS3_TM_ETS_PSHAP_CFG_FLAG 0x01
#define HNS3_TM_ETS_TC_CFG_FLAG 0x02
struct nictool_ets_tc_weight_cmd {
u8 tc_weight[MAX_TC_NUM];
u8 weight_offset;
u8 rsvd[15];
};
struct nictool_queue_cfg_info {
int is_read;
u16 queue_id;
u16 qs;
};
struct nictool_qs_cfg_info {
int is_read;
u16 qs_id;
u8 pri;
u8 mode;
u8 weight;
u8 tc;
u8 flag;
};
struct nictool_pri_cfg_info {
int is_read;
u16 pri_id;
u8 pg;
u32 c_shaping;
u32 p_shaping;
u8 mode;
u8 weight;
u8 flag;
};
struct nictool_pg_cfg_info {
int is_read;
u16 pg_id;
u32 c_shaping;
u32 p_shaping;
u8 mode;
u8 weight;
u8 flag;
};
struct nictool_port_cfg_info {
int is_read;
u16 port_id;
u32 mode;
u32 shaping;
u8 weight;
u8 flag;
};
struct nictool_ets_cfg_info {
int is_read;
u16 tc_id;
u8 weight;
u32 shaping;
u8 mac_id;
u8 flag;
};
int hns3_test_queue_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_qs_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
int hns3_test_pri_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
int hns3_test_pg_cfg(struct hns3_nic_priv *net_priv, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_port_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
int hns3_test_ets_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size, void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/kthread.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_vlan.h"
int hns3_test_upmapping_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
#define HCLGE_OPC_VLANUP_MAPPING_VF_TX_CFG 0x0F10
#define HCLGE_OPC_VLANUP_MAPPING_PORT_TX_CFG 0x0F11
struct nictool_vlanup_param *out_info;
struct nictool_vlanup_param *in_info;
struct hnae3_handle *handle;
struct hclge_vport *vport;
struct hclge_dev *hdev;
struct hclge_desc desc;
int ret;
handle = net_priv->ae_handle;
vport = hclge_get_vport(handle);
hdev = vport->back;
in_info = (struct nictool_vlanup_param *)buf_in;
out_info = (struct nictool_vlanup_param *)buf_out;
if (in_info->is_read) {
if (!out_info)
return 0;
if (in_info->map_flag & NICTOOL_VLANUP_VF_CFG_FLAG) {
hclge_cmd_setup_basic_desc
(&desc, HCLGE_OPC_VLANUP_MAPPING_VF_TX_CFG, true);
if (in_info->pf_valid) {
desc.data[0] |= NICTOOL_PFVLD_MASK;
desc.data[0] |=
(in_info->pf_id & NICTOOL_PFID_MASK);
out_info->pf_id = in_info->pf_id;
}
desc.data[0] |=
((in_info->vf_id << 3) & NICTOOL_VFID_MASK);
desc.data[1] |= in_info->module & NICTOOL_MODULE_MASK;
out_info->vf_id = in_info->vf_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"vf up mapping read fail, ret = %d.\n",
ret);
return -EIO;
}
out_info->ti2oupm = desc.data[2];
out_info->tv2pupm = desc.data[4];
} else if (in_info->map_flag & NICTOOL_VLANUP_TC_CFG_FLAG) {
hclge_cmd_setup_basic_desc
(&desc, HCLGE_OPC_VLANUP_MAPPING_PORT_TX_CFG, true);
desc.data[0] |= in_info->tc_id & NICTOOL_TCID_MASK;
desc.data[1] |= in_info->module & NICTOOL_MODULE_MASK;
out_info->tc_id = in_info->tc_id;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"port up mapping read fail, ret = %d.\n",
ret);
return -EIO;
}
out_info->tp2nupm = desc.data[2];
out_info->tag_en = (desc.data[4] & NICTOOL_TAGEN_MASK) |
(((desc.data[4] >> 4) & NICTOOL_TAGEN_MASK) << 2);
}
out_info->module = in_info->module;
out_info->map_flag = in_info->map_flag;
} else {
if (in_info->map_flag & NICTOOL_VLANUP_VF_CFG_FLAG) {
hclge_cmd_setup_basic_desc
(&desc, HCLGE_OPC_VLANUP_MAPPING_VF_TX_CFG, true);
if (in_info->pf_valid) {
desc.data[0] |= NICTOOL_PFVLD_MASK;
desc.data[0] |=
(in_info->pf_id & NICTOOL_PFID_MASK);
}
desc.data[0] |=
((in_info->vf_id << 3) & NICTOOL_VFID_MASK);
desc.data[1] |= (in_info->module & NICTOOL_MODULE_MASK);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"vf up mapping set fail, ret = %d.\n",
ret);
return -EIO;
}
hclge_cmd_reuse_desc(&desc, false);
if (in_info->map_flag & NICTOOL_VLANUP_TI2OUPM_FLAG)
desc.data[2] = in_info->ti2oupm;
if (in_info->map_flag & NICTOOL_VLANUP_TV2PUPM_FLAG)
desc.data[4] = in_info->tv2pupm;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"vf up mapping set fail, ret = %d.\n",
ret);
return -EIO;
}
} else if (in_info->map_flag & NICTOOL_VLANUP_TC_CFG_FLAG) {
hclge_cmd_setup_basic_desc
(&desc, HCLGE_OPC_VLANUP_MAPPING_PORT_TX_CFG, true);
desc.data[0] = (in_info->tc_id & NICTOOL_TCID_MASK);
desc.data[1] = (in_info->module & NICTOOL_MODULE_MASK);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"port up mapping set fail, ret = %d.\n",
ret);
return -EIO;
}
hclge_cmd_reuse_desc(&desc, false);
if (in_info->map_flag & NICTOOL_VLANUP_TP2NUPM_FLAG)
desc.data[2] = in_info->tp2nupm;
if (in_info->map_flag & NICTOOL_VLANUP_CTRL_CFG_FLAG) {
desc.data[4] = (in_info->tag_en &
NICTOOL_TAGEN_MASK) |
(((in_info->tag_en >> 2) &
NICTOOL_TAGEN_MASK) << 4);
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"port up mapping set fail, ret = %d.\n",
ret);
return -EIO;
}
}
}
return 0;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_VLAN_H__
#define __HNS3_PRIV_VLAN_H__
#define NICTOOL_VLANUP_MODULE_FLAG 0x01
#define NICTOOL_VLANUP_PF_CFG_FLAG 0x02
#define NICTOOL_VLANUP_VF_CFG_FLAG 0x04
#define NICTOOL_VLANUP_TC_CFG_FLAG 0x08
#define NICTOOL_VLANUP_TI2OUPM_FLAG 0x10
#define NICTOOL_VLANUP_TV2PUPM_FLAG 0x20
#define NICTOOL_VLANUP_TP2NUPM_FLAG 0x40
#define NICTOOL_VLANUP_CTRL_CFG_FLAG 0x80
#define NICTOOL_TAGEN_MASK 0x3
#define NICTOOL_TCID_MASK 0x7
#define NICTOOL_PFID_MASK 0x7
#define NICTOOL_VFID_MASK 0x7F8
#define NICTOOL_PFVLD_MASK 0x1000
#define NICTOOL_MODULE_MASK 0x1
struct nictool_vlanup_param {
u8 is_read;
u32 ti2oupm;
u32 tv2pupm;
u32 tp2nupm;
u32 vf_id;
u32 map_flag;
u8 pf_valid;
u8 pf_id;
u8 tc_id;
u8 tag_en;
u8 module;
};
int hns3_test_upmapping_cfg(struct hns3_nic_priv *net_priv,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size);
#endif
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2016-2017 Hisilicon Limited.
#include <linux/module.h>
#include <linux/kernel.h>
#include "hclge_cmd.h"
#include "hnae3.h"
#include "hclge_main.h"
#include "hns3_enet.h"
#include "hns3_priv_xsfp.h"
#define BD0_DATA_LEN 20
#define BD1_DATA_LEN 24
static int hns3_get_sfp_present(struct hnae3_handle *handle, u32 *present)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_sfp_present_cmd *resp;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, XSFP_OPC_SFP_GET_PRESENT, true);
resp = (struct hclge_sfp_present_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev, "get spf present failed %d\n", ret);
return ret;
}
*present = resp->sfp_present;
return 0;
}
static int _hns3_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
u16 offset, u16 size, u16 *outlen)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_desc desc[HCLGE_SFP_INFO_LEN];
struct hclge_dev *hdev = vport->back;
struct hclge_sfp_info *resp = NULL;
u32 data_length;
u8 *temp_data;
u32 temp_len;
int ret;
u32 i;
u32 j;
memset(desc, 0x0, sizeof(desc));
for (i = 0; i < HCLGE_SFP_INFO_LEN; i++) {
hclge_cmd_setup_basic_desc(&desc[i], XSFP_OPC_SFP_GET_INFO,
true);
if (i == 0)
desc[0].data[0] = offset | (size << 16);
if (i < HCLGE_SFP_INFO_LEN - 1)
desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT);
else
desc[i].flag &= ~(cpu_to_le16(HCLGE_CMD_FLAG_NEXT));
}
ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_SFP_INFO_LEN);
if (ret) {
dev_err(&hdev->pdev->dev, "get spf information cmd failed %d\n",
ret);
return ret;
}
for (i = 0; i < HCLGE_SFP_INFO_LEN; i++) {
resp = (struct hclge_sfp_info *)desc[i].data;
if (i == 0) {
*outlen = (resp[i].sfpinfo[0] >> 16) & 0xFFFF;
temp_len = *outlen;
data_length =
(temp_len > BD0_DATA_LEN) ? BD0_DATA_LEN : temp_len;
temp_data = (u8 *)&resp->sfpinfo[1];
} else {
data_length =
(temp_len > BD1_DATA_LEN) ? BD1_DATA_LEN : temp_len;
temp_data = (u8 *)&resp->sfpinfo[0];
}
for (j = 0; j < data_length; j++)
*buff++ = *temp_data++;
temp_len -= data_length;
if (temp_len == 0)
break;
}
return 0;
}
static int hns3_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, u16 offset,
u16 size, u16 *outlen)
{
u16 tmp_size;
u8 *tmp_buff;
u16 tmp_outlen;
int ret;
tmp_buff = buff;
while (size) {
WARN_ON_ONCE(!tmp_buff);
if (size > HCLGE_SFP_INFO_SIZE)
tmp_size = HCLGE_SFP_INFO_SIZE;
else
tmp_size = size;
ret =
_hns3_get_sfpinfo(handle, tmp_buff, offset, tmp_size,
&tmp_outlen);
if (ret)
return ret;
offset += tmp_size;
size -= tmp_size;
tmp_buff += tmp_size;
*outlen += tmp_outlen;
if (tmp_size != tmp_outlen)
break;
}
return 0;
}
int hns3_set_sfp_state(struct hnae3_handle *handle, bool en)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_sfp_enable_cmd *req = NULL;
struct hclge_dev *hdev = vport->back;
struct hclge_desc desc;
int ret;
hclge_cmd_setup_basic_desc(&desc, XSFP_OPC_SFP_SET_STATUS, false);
req = (struct hclge_sfp_enable_cmd *)desc.data;
req->set_sfp_enable_flag = en;
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev, "set spf on/off cmd failed %d\n",
ret);
return ret;
}
int hns3_xsfp_cfg(struct hns3_nic_priv *net_priv, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hns3_xsfp_info *xsfp_info_out;
struct hnae3_handle *handle;
struct hns3_cfg_xsfp *param;
u32 sfp_present = 0;
int ret;
if (!buf_in || !buf_out)
return -ENODEV;
handle = hns3_get_handle(net_priv->netdev);
param = (struct hns3_cfg_xsfp *)buf_in;
xsfp_info_out = (struct hns3_xsfp_info *)buf_out;
ret = hns3_get_sfp_present(handle, &sfp_present);
if (ret) {
pr_err("nic_get_sfp_present error.\n");
xsfp_info_out->light_module_status = 0xff;
return 0;
}
xsfp_info_out->light_module_status = (u8)sfp_present;
if (sfp_present) {
if (param->cfg_optype == OPC_QUERY_XSFP_INFO) {
ret = hns3_get_sfpinfo(handle, xsfp_info_out->sfp_info,
0,
STD_XSFP_INFO_A0_SIZE +
STD_XSFP_INFO_A2_SIZE,
&xsfp_info_out->eeprom_len);
if (ret) {
pr_err("hns3_get_sfpinfo error.\n");
return ret;
}
} else if (param->cfg_optype == OPC_QUERY_ALL_XSFP_INFO) {
ret = hns3_get_sfpinfo(handle, xsfp_info_out->sfp_info,
0, STD_XSFP_INFO_MAX_SIZE,
&xsfp_info_out->eeprom_len);
if (ret) {
pr_err("hns3_get_sfpinfo error.\n");
return ret;
}
} else if (param->cfg_optype == OPC_CONFIG_XSFP_TX_STATUS) {
ret = hns3_set_sfp_state(handle, param->status);
if (ret) {
pr_err("nic_set_sfp_state error.\n");
return ret;
}
} else {
pr_err("%s error: unsupport optype:%u.\n",
__func__, param->cfg_optype);
ret = -EINVAL;
}
} else {
ret = 0;
}
return ret;
}
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2016-2019 Hisilicon Limited. */
#ifndef __HNS3_PRIV_XSFP_H__
#define __HNS3_PRIV_XSFP_H__
#define STD_XSFP_INFO_A0_SIZE 256
#define STD_XSFP_INFO_A2_SIZE 256
#define STD_XSFP_INFO_MAX_SIZE 640
#define HCLGE_SFP_INFO_LEN 6
#define HCLGE_SFP_INFO_SIZE 140
/* SFP command */
#define XSFP_OPC_SFP_GET_INFO 0x7100
#define XSFP_OPC_SFP_GET_PRESENT 0x7101
#define XSFP_OPC_SFP_SET_STATUS 0x7102
struct hclge_sfp_info {
u32 sfpinfo[6];
};
struct hclge_sfp_enable_cmd {
u32 set_sfp_enable_flag;
u32 rsv[5];
};
struct hclge_sfp_present_cmd {
u32 sfp_present;
u32 rsv[5];
};
enum hns3_xsfp_opcode_type {
OPC_QUERY_XSFP_INFO = 0,
OPC_QUERY_ALL_XSFP_INFO,
OPC_CONFIG_XSFP_TX_STATUS
};
struct hns3_cfg_xsfp {
u32 cfg_optype;
u8 status; /* 1: enable 0: disable */
};
struct hns3_xsfp_info {
u8 light_module_status;
u16 eeprom_len;
u8 sfp_info[STD_XSFP_INFO_MAX_SIZE + 1];
};
int hns3_xsfp_cfg(struct hns3_nic_priv *net_priv, void *buf_in,
u16 in_size, void *buf_out, u16 *out_size);
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册