提交 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 ...@@ -123,6 +123,16 @@ config HNS3_ENET
family of SoCs. This module depends upon HNAE3 driver to access the HNAE3 family of SoCs. This module depends upon HNAE3 driver to access the HNAE3
devices and their associated operations. 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 #HNS3
endif # NET_VENDOR_HISILICON endif # NET_VENDOR_HISILICON
...@@ -2,14 +2,85 @@ ...@@ -2,14 +2,85 @@
# #
# Makefile for the HISILICON network device drivers. # Makefile for the HISILICON network device drivers.
# #
ccflags-y += -I$(srctree)/$(src)
obj-$(CONFIG_HNS3) += hns3pf/ # Add security options
obj-$(CONFIG_HNS3) += hns3vf/ 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) += hnae3.o
obj-$(CONFIG_HNS3_ENET) += hns3.o obj-$(CONFIG_HNS3_ENET) += hns3.o
hns3-objs = hns3_enet.o hns3_ethtool.o hns3_debugfs.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 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 @@ ...@@ -8,75 +8,22 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "../hnae3.h" #include "hnae3.h"
#include "hns3_enet_it.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_driver_string[];
extern const char hns3_copyright[]; extern const char hns3_copyright[];
#ifdef CONFIG_IT_VALIDATION #ifdef CONFIG_IT_VALIDATION
#define HNAE_DRIVER_VERSION "B075" #define HNAE_DRIVER_VERSION "1.8.10.0"
#define HNAE_DRIVER_VERSION_MAX_LEN 8
#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 struct net_device_ops hns3_nic_netdev_ops;
extern const struct hnae3_client_ops client_ops; extern const struct hnae3_client_ops client_ops;
extern struct hnae3_client client; extern struct hnae3_client client;
extern struct pci_driver hns3_driver; extern struct pci_driver hns3_driver;
extern const char hns3_driver_name[]; 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) 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) ...@@ -84,7 +31,6 @@ int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd)
case (SIOCDEVPRIVATE + 4): case (SIOCDEVPRIVATE + 4):
if (hns3_ioctl) if (hns3_ioctl)
return hns3_ioctl(netdev, ifr->ifr_data); return hns3_ioctl(netdev, ifr->ifr_data);
pr_err("open nic_test failed");
return -EINVAL; return -EINVAL;
default: default:
return -EINVAL; return -EINVAL;
...@@ -93,8 +39,7 @@ int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd) ...@@ -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) #if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE)
u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb, u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb,
void *accel_priv, void *accel_priv, select_queue_fallback_t fallback)
select_queue_fallback_t fallback)
#else #else
u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb, u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb,
struct net_device *accel_priv, struct net_device *accel_priv,
...@@ -115,25 +60,15 @@ u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb, ...@@ -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) static int __init hns3_init_module_it(void)
{ {
struct ethtool_ops *loc_ethtool_ops;
struct net_device_ops *ndev_ops; struct net_device_ops *ndev_ops;
int ret; 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 - version\n", hns3_driver_name, hns3_driver_string);
pr_info("%s: %s\n", hns3_driver_name, hns3_copyright); pr_info("%s: %s\n", hns3_driver_name, hns3_copyright);
strncpy(hns3_driver_version, HNAE_DRIVER_VERSION, 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; client.type = HNAE3_CLIENT_KNIC;
snprintf(client.name, HNAE3_CLIENT_NAME_LENGTH - 1, "%s", snprintf(client.name, HNAE3_CLIENT_NAME_LENGTH - 1, "%s",
hns3_driver_name); hns3_driver_name);
...@@ -141,9 +76,6 @@ static int __init hns3_init_module_it(void) ...@@ -141,9 +76,6 @@ static int __init hns3_init_module_it(void)
client.ops = &client_ops; client.ops = &client_ops;
ndev_ops = (struct net_device_ops *)&hns3_nic_netdev_ops; ndev_ops = (struct net_device_ops *)&hns3_nic_netdev_ops;
ndev_ops->ndo_do_ioctl = hns3_nic_do_ioctl_it; 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; ndev_ops->ndo_select_queue = hns3_nic_select_queue_it;
INIT_LIST_HEAD(&client.node); INIT_LIST_HEAD(&client.node);
...@@ -153,7 +85,6 @@ static int __init hns3_init_module_it(void) ...@@ -153,7 +85,6 @@ static int __init hns3_init_module_it(void)
if (ret) if (ret)
goto err_reg_client; goto err_reg_client;
hns3_driver.id_table = hns3_pci_tbl_it;
ret = pci_register_driver(&hns3_driver); ret = pci_register_driver(&hns3_driver);
if (ret) if (ret)
goto err_reg_driver; goto err_reg_driver;
...@@ -166,5 +97,6 @@ static int __init hns3_init_module_it(void) ...@@ -166,5 +97,6 @@ static int __init hns3_init_module_it(void)
hns3_dbg_unregister_debugfs(); hns3_dbg_unregister_debugfs();
return ret; return ret;
} }
module_init(hns3_init_module_it); module_init(hns3_init_module_it);
#endif #endif
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
typedef int (*hns3_priv_func)(struct net_device *, void *); typedef int (*hns3_priv_func)(struct net_device *, void *);
hns3_priv_func hns3_ioctl; hns3_priv_func hns3_ioctl;
#define VERSION_NUMBER "$FULL_VERSION"
#ifndef LINUX_VERSION_CODE #ifndef LINUX_VERSION_CODE
#include <linux/version.h> #include <linux/version.h>
#else #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) ...@@ -38,21 +38,28 @@ int nic_netdev_match_check(struct net_device *netdev)
EXPORT_SYMBOL(nic_netdev_match_check); EXPORT_SYMBOL(nic_netdev_match_check);
void nic_chip_recover_handler(struct net_device *netdev, 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; struct hnae3_handle *h;
if (nic_netdev_match_check(netdev)) if (nic_netdev_match_check(netdev))
return; return;
priv = netdev_priv(netdev); dev_info(&netdev->dev, "reset type is %d!!\n", event_t);
h = priv->ae_handle;
ae_dev = pci_get_drvdata(h->pdev); 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) h = hns3_get_handle(netdev);
ae_dev->ops->reset_event(h->pdev, NULL); 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); EXPORT_SYMBOL(nic_chip_recover_handler);
...@@ -70,7 +77,10 @@ int nic_clean_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats) ...@@ -70,7 +77,10 @@ int nic_clean_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats)
priv = netdev_priv(ndev); priv = netdev_priv(ndev);
h = hns3_get_handle(ndev); h = hns3_get_handle(ndev);
kinfo = &h->kinfo; 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++) { for (i = 0; i < kinfo->num_tqps; i++) {
ring = priv->ring_data[i].ring; ring = priv->ring_data[i].ring;
...@@ -95,66 +105,96 @@ int nic_get_chipid(struct net_device *ndev, u32 *chip_id) ...@@ -95,66 +105,96 @@ int nic_get_chipid(struct net_device *ndev, u32 *chip_id)
return -EINVAL; return -EINVAL;
h = hns3_get_handle(ndev); 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); 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; struct hnae3_handle *h;
if (nic_netdev_match_check(ndev)) if (nic_netdev_match_check(ndev))
return -ENODEV; return -ENODEV;
if (!buff || !outlen) if (!mac_id)
return -EINVAL; return -EINVAL;
h = hns3_get_handle(ndev); 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; struct hnae3_handle *h;
if (nic_netdev_match_check(ndev)) if (nic_netdev_match_check(ndev))
return -ENODEV; return -ENODEV;
if (!present) if (!buff || !outlen)
return -EINVAL; return -EINVAL;
para.buff = buff;
para.outlen = outlen;
para.offset = 0;
para.size = size;
h = hns3_get_handle(ndev); 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; struct hnae3_handle *h;
if (nic_netdev_match_check(ndev)) if (nic_netdev_match_check(ndev))
return -ENODEV; return -ENODEV;
if (!present)
return -EINVAL;
h = hns3_get_handle(ndev); 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; struct hnae3_handle *h;
if (nic_netdev_match_check(ndev)) if (nic_netdev_match_check(ndev))
return -ENODEV; return -ENODEV;
if (!speed)
return -EINVAL;
h = hns3_get_handle(ndev); 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) 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) ...@@ -167,7 +207,11 @@ int nic_get_chip_num(struct net_device *ndev, u32 *chip_num)
return -EINVAL; return -EINVAL;
h = hns3_get_handle(ndev); 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); EXPORT_SYMBOL(nic_get_chip_num);
...@@ -182,19 +226,30 @@ int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num) ...@@ -182,19 +226,30 @@ int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num)
return -EINVAL; return -EINVAL;
h = hns3_get_handle(ndev); 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); EXPORT_SYMBOL(nic_get_port_num_per_chip);
int nic_set_led(struct net_device *ndev, int type, int status) int nic_set_led(struct net_device *ndev, int type, int status)
{ {
struct hns3_led_state_para para;
struct hnae3_handle *h; struct hnae3_handle *h;
if (nic_netdev_match_check(ndev)) if (nic_netdev_match_check(ndev))
return -ENODEV; return -ENODEV;
para.status = status;
para.type = type;
h = hns3_get_handle(ndev); 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); EXPORT_SYMBOL(nic_set_led);
...@@ -209,7 +264,11 @@ int nic_get_led_signal(struct net_device *ndev, struct hns3_lamp_signal *signal) ...@@ -209,7 +264,11 @@ int nic_get_led_signal(struct net_device *ndev, struct hns3_lamp_signal *signal)
return -EINVAL; return -EINVAL;
h = hns3_get_handle(ndev); 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); EXPORT_SYMBOL(nic_get_led_signal);
...@@ -221,7 +280,11 @@ int nic_disable_net_lane(struct net_device *ndev) ...@@ -221,7 +280,11 @@ int nic_disable_net_lane(struct net_device *ndev)
return -ENODEV; return -ENODEV;
h = hns3_get_handle(ndev); 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); EXPORT_SYMBOL(nic_disable_net_lane);
...@@ -236,7 +299,12 @@ int nic_get_net_lane_status(struct net_device *ndev, u32 *status) ...@@ -236,7 +299,12 @@ int nic_get_net_lane_status(struct net_device *ndev, u32 *status)
return -EINVAL; return -EINVAL;
h = hns3_get_handle(ndev); 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); EXPORT_SYMBOL(nic_get_net_lane_status);
...@@ -250,7 +318,11 @@ int nic_set_mac_state(struct net_device *ndev, int enable) ...@@ -250,7 +318,11 @@ int nic_set_mac_state(struct net_device *ndev, int enable)
h = hns3_get_handle(ndev); h = hns3_get_handle(ndev);
en = !!enable; 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); EXPORT_SYMBOL(nic_set_mac_state);
...@@ -271,7 +343,8 @@ int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask) ...@@ -271,7 +343,8 @@ int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask)
priv = netdev_priv(netdev); priv = netdev_priv(netdev);
if (test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) { 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; return -EOPNOTSUPP;
} }
...@@ -284,16 +357,16 @@ int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask) ...@@ -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); ret = irq_set_affinity_hint(tqp_vector->vector_irq, NULL);
if (ret) { if (ret) {
dev_err(&netdev->dev, "reset affinity hint fail, ret = %d\n", dev_err(&netdev->dev,
ret); "reset affinity hint fail, ret = %d\n", ret);
return ret; return ret;
} }
ret = irq_set_affinity_hint(tqp_vector->vector_irq, ret = irq_set_affinity_hint(tqp_vector->vector_irq,
&tqp_vector->affinity_mask); &tqp_vector->affinity_mask);
if (ret) { if (ret) {
dev_err(&netdev->dev, "set affinity hint fail, ret = %d\n", dev_err(&netdev->dev,
ret); "set affinity hint fail, ret = %d\n", ret);
return ret; return ret;
} }
} }
...@@ -308,12 +381,151 @@ EXPORT_SYMBOL(nic_set_cpu_affinity); ...@@ -308,12 +381,151 @@ EXPORT_SYMBOL(nic_set_cpu_affinity);
int nic_disable_clock(struct net_device *ndev) int nic_disable_clock(struct net_device *ndev)
{ {
struct hnae3_handle *h; struct hnae3_handle *h;
u32 en;
if (nic_netdev_match_check(ndev)) if (nic_netdev_match_check(ndev))
return -ENODEV; return -ENODEV;
en = 0;
h = hns3_get_handle(ndev); 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); 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 @@ ...@@ -4,32 +4,91 @@
#ifndef __HNS3_EXT_H #ifndef __HNS3_EXT_H
#define __HNS3_EXT_H #define __HNS3_EXT_H
#include <linux/types.h> #include <linux/types.h>
#include "../hns3_enet.h" #include "hns3_enet.h"
#include "hns3pf/hclge_ext.h" #include "hnae3.h"
#include "hns3pf/hclge_main_it.h" #include "hclge_main_it.h"
/** enum hns3_ext_op_code {
* nic_chip_recover_handler - reset net device by port id HNS3_EXT_OPC_CLEAN_STATS64 = 0,
* @netdev: net device HNS3_EXT_OPC_GET_CHIPID,
* @hnae3_reset_type: nic device event type HNS3_EXT_OPC_GET_SFPINFO,
*/ HNS3_EXT_OPC_SET_SFP_STATE,
void nic_chip_recover_handler(struct net_device *netdev, HNS3_EXT_OPC_GET_CHIP_NUM,
enum hnae3_reset_type_custom event_t); 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_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, int nic_clean_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats); 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_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_set_led(struct net_device *ndev, int type, int status);
int nic_disable_net_lane(struct net_device *ndev); int nic_disable_net_lane(struct net_device *ndev);
int nic_get_net_lane_status(struct net_device *ndev, u32 *status); 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_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_set_mac_state(struct net_device *ndev, int enable);
int nic_disable_clock(struct net_device *ndev); 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 #endif
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2016-2017 Hisilicon Limited. // Copyright (c) 2016-2017 Hisilicon Limited.
#include "../../hns3pf/hclge_cmd.h" #include "hclge_cmd.h"
#include "../../hnae3.h" #include "hnae3.h"
#include "../../hns3pf/hclge_main.h" #include "hclge_main.h"
#ifdef CONFIG_HNS3_TEST #ifdef CONFIG_HNS3_TEST
#include "hclge_test.h" #include "hclge_test.h"
...@@ -12,4 +12,3 @@ EXPORT_SYMBOL(hclge_cmd_reuse_desc); ...@@ -12,4 +12,3 @@ EXPORT_SYMBOL(hclge_cmd_reuse_desc);
EXPORT_SYMBOL(hclge_cmd_setup_basic_desc); EXPORT_SYMBOL(hclge_cmd_setup_basic_desc);
EXPORT_SYMBOL(hclge_cmd_send); EXPORT_SYMBOL(hclge_cmd_send);
#endif #endif
...@@ -15,12 +15,16 @@ ...@@ -15,12 +15,16 @@
#include <net/gre.h> #include <net/gre.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/vxlan.h> #include <net/vxlan.h>
#include "../../hns3pf/hclge_main.h" #include "hclge_main.h"
#include "../../hnae3.h" #include "hnae3.h"
#include "../../hns3pf/hclge_cmd.h" #include "hclge_cmd.h"
#include "hclge_ext.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 hnae3_knic_private_info *kinfo;
struct hclge_vport *vport; struct hclge_vport *vport;
...@@ -37,17 +41,20 @@ void hclge_clean_stats64(struct hnae3_handle *handle) ...@@ -37,17 +41,20 @@ void hclge_clean_stats64(struct hnae3_handle *handle)
memset(&tqp->tqp_stats, 0, sizeof(struct hlcge_tqp_stats)); memset(&tqp->tqp_stats, 0, sizeof(struct hlcge_tqp_stats));
} }
memset(&hdev->hw_stats.mac_stats, 0, sizeof(struct hclge_mac_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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_chip_id_cmd *resp = NULL; struct hclge_chip_id_cmd *resp = NULL;
struct hclge_desc desc; struct hclge_desc desc;
u32 *chip_id;
int ret; int ret;
chip_id = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHIP_ID_GET, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHIP_ID_GET, true);
resp = (struct hclge_chip_id_cmd *)(desc.data); resp = (struct hclge_chip_id_cmd *)(desc.data);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
...@@ -58,34 +65,27 @@ int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id) ...@@ -58,34 +65,27 @@ int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id)
*chip_id = resp->chip_id; *chip_id = resp->chip_id;
return 0; return 0;
} }
EXPORT_SYMBOL(hclge_get_chipid);
int hclge_get_commit_id(struct hnae3_handle *handle, u8 *commit_id, int hclge_get_mac_id(struct hnae3_handle *handle, int opcode,
u32 *ncl_version) void *data, int length)
{ {
struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_commit_id_cmd *resp = NULL;
struct hclge_desc desc; 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); mac_id = (u32 *)data;
resp = (struct hclge_commit_id_cmd *)(desc.data); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHIP_ID_GET, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) { 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; return ret;
} }
for (i = 0; i < 8; i++) *mac_id = desc.data[1];
commit_id[i] = resp->commit_id[i];
commit_id[8] = '\0';
*ncl_version = resp->ncl_version;
return 0; return 0;
} }
EXPORT_SYMBOL(hclge_get_commit_id);
static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
u16 offset, u16 size, u16 *outlen) u16 offset, u16 size, u16 *outlen)
...@@ -95,8 +95,13 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, ...@@ -95,8 +95,13 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_sfp_info *resp = NULL; struct hclge_sfp_info *resp = NULL;
int ret; int ret;
int i; u32 i;
int j; 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++) { for (i = 0; i < HCLGE_SFP_INFO_LEN; i++) {
hclge_cmd_setup_basic_desc(&desc[i], hclge_cmd_setup_basic_desc(&desc[i],
...@@ -112,8 +117,7 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, ...@@ -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); ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_SFP_INFO_LEN);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"get spf information cmd failed %d\n", "get spf information cmd failed %d\n", ret);
ret);
return ret; return ret;
} }
...@@ -121,51 +125,60 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, ...@@ -121,51 +125,60 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff,
resp = (struct hclge_sfp_info *)desc[i].data; resp = (struct hclge_sfp_info *)desc[i].data;
if (i == 0) { if (i == 0) {
*outlen = (resp[i].sfpinfo[0] >> 16) & 0xFFFF; *outlen = (resp[i].sfpinfo[0] >> 16) & 0xFFFF;
for (j = 1; j < 6; j++) { temp_len = *outlen;
*(u32 *)buff = resp->sfpinfo[j]; data_len =
buff = buff + sizeof(u32); (temp_len > BD0_DATA_LEN) ? BD0_DATA_LEN : temp_len;
} temp_data = (u8 *)&resp->sfpinfo[1];
} else { } else {
for (j = 0; j < 6; j++) { data_len =
*(u32 *)buff = resp->sfpinfo[j]; (temp_len > BD1_DATA_LEN) ? BD1_DATA_LEN : temp_len;
buff = buff + sizeof(u32); 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; return 0;
} }
int hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, u16 offset, int hclge_get_sfpinfo(struct hnae3_handle *handle, int opcode,
u16 size, u16 *outlen) void *data, int length)
{ {
struct hclge_sfp_info_para *para;
u16 tmp_size; u16 tmp_size;
u8 *tmp_buff; u8 *tmp_buff;
u16 tmp_outlen; u16 tmp_outlen;
int ret; int ret;
para = (struct hclge_sfp_info_para *)data;
tmp_buff = para->buff;
tmp_buff = buff; while (para->size) {
while (size) {
WARN_ON_ONCE(!tmp_buff); WARN_ON_ONCE(!tmp_buff);
if (size > HCLGE_SFP_INFO_SIZE) if (para->size > HCLGE_SFP_INFO_SIZE)
tmp_size = HCLGE_SFP_INFO_SIZE; tmp_size = HCLGE_SFP_INFO_SIZE;
else else
tmp_size = size; tmp_size = para->size;
ret = _hclge_get_sfpinfo(handle, tmp_buff, offset, tmp_size, ret = _hclge_get_sfpinfo(handle, tmp_buff, para->offset,
&tmp_outlen); tmp_size, &tmp_outlen);
if (ret) if (ret)
return ret; return ret;
offset += tmp_size; para->offset += tmp_size;
size -= tmp_size; para->size -= tmp_size;
tmp_buff += tmp_size; tmp_buff += tmp_size;
*outlen += tmp_outlen; *para->outlen += tmp_outlen;
if (tmp_size != tmp_outlen) if (tmp_size != tmp_outlen)
break; break;
} }
return 0; 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_vport *vport = hclge_get_vport(handle);
struct hclge_sfp_enable_cmd *req = NULL; struct hclge_sfp_enable_cmd *req = NULL;
...@@ -175,7 +188,7 @@ int hclge_set_sfp_state(struct hnae3_handle *handle, bool en) ...@@ -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); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_SET_STATUS, false);
req = (struct hclge_sfp_enable_cmd *)desc.data; 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); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) if (ret)
...@@ -184,12 +197,13 @@ int hclge_set_sfp_state(struct hnae3_handle *handle, bool en) ...@@ -184,12 +197,13 @@ int hclge_set_sfp_state(struct hnae3_handle *handle, bool en)
return ret; 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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
u32 *chip_num = (u32 *)data;
struct hclge_desc desc; struct hclge_desc desc;
int ret; int ret;
...@@ -202,40 +216,17 @@ int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num) ...@@ -202,40 +216,17 @@ int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num)
*chip_num = desc.data[0]; *chip_num = desc.data[0];
return 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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_desc desc; struct hclge_desc desc;
u32 *port_num;
int ret; int ret;
port_num = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_PORT_NUM, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_PORT_NUM, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) { if (ret) {
...@@ -245,18 +236,20 @@ int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num) ...@@ -245,18 +236,20 @@ int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num)
*port_num = desc.data[0]; *port_num = desc.data[0];
return 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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_led_state *para;
struct hclge_desc desc; struct hclge_desc desc;
int ret; int ret;
para = (struct hclge_led_state *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, false); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, false);
desc.data[0] = type; desc.data[0] = para->type;
desc.data[1] = status; desc.data[1] = para->status;
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, "get set led failed %d\n", 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) ...@@ -265,16 +258,17 @@ int hclge_set_led(struct hnae3_handle *handle, u32 type, u32 status)
return 0; return 0;
} }
EXPORT_SYMBOL(hclge_set_led);
int hclge_get_led_signal(struct hnae3_handle *handle, int hclge_get_led_signal(struct hnae3_handle *handle, int opcode,
struct hns3_lamp_signal *signal) void *data, int length)
{ {
struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_lamp_signal *signal;
struct hclge_desc desc; struct hclge_desc desc;
int ret; int ret;
signal = (struct hclge_lamp_signal *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) { if (ret) {
...@@ -289,16 +283,18 @@ int hclge_get_led_signal(struct hnae3_handle *handle, ...@@ -289,16 +283,18 @@ int hclge_get_led_signal(struct hnae3_handle *handle,
return 0; 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_vport *vport = hclge_get_vport(handle);
struct hclge_sfp_present_cmd *resp = NULL; struct hclge_sfp_present_cmd *resp = NULL;
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_desc desc; struct hclge_desc desc;
u32 *present;
int ret = 0; int ret = 0;
present = (u32 *)data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_GET_PRESENT, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_GET_PRESENT, true);
resp = (struct hclge_sfp_present_cmd *)desc.data; resp = (struct hclge_sfp_present_cmd *)desc.data;
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
...@@ -310,9 +306,9 @@ int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present) ...@@ -310,9 +306,9 @@ int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present)
*present = resp->sfp_present; *present = resp->sfp_present;
return 0; 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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
...@@ -328,15 +324,17 @@ int hclge_disable_net_lane(struct hnae3_handle *handle) ...@@ -328,15 +324,17 @@ int hclge_disable_net_lane(struct hnae3_handle *handle)
} }
return 0; 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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_desc desc; struct hclge_desc desc;
u32 *status;
int ret = 0; int ret = 0;
status = (u32 *)data;
desc.data[0] = 0; desc.data[0] = 0;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DISABLE_NET_LANE, true); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DISABLE_NET_LANE, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
...@@ -347,18 +345,34 @@ int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status) ...@@ -347,18 +345,34 @@ int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status)
*status = desc.data[0]; *status = desc.data[0];
return 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_vport *vport = hclge_get_vport(handle);
struct hclge_config_mac_mode_cmd *req;
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_desc desc; struct hclge_desc desc;
struct hclge_config_mac_mode_cmd *req =
(struct hclge_config_mac_mode_cmd *)desc.data;
u32 loop_en = 0; 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); 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_TX_EN_B, enable);
hnae3_set_bit(loop_en, HCLGE_MAC_RX_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) ...@@ -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_TX_OVERSIZE_TRUNCATE_B, enable);
hnae3_set_bit(loop_en, HCLGE_MAC_RX_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); 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); req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en);
ret = hclge_cmd_send(&hdev->hw, &desc, 1); ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) if (ret)
dev_err(&hdev->pdev->dev, 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; 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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
u32 nic_clock_en = enable; u32 nic_clock_en = *(u32 *)data;
struct hclge_desc desc; struct hclge_desc desc;
int ret = 0; int ret = 0;
...@@ -402,4 +418,405 @@ int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable) ...@@ -402,4 +418,405 @@ int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable)
nic_clock_en, ret); nic_clock_en, ret);
return 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 @@ ...@@ -4,7 +4,7 @@
#ifndef __HCLGE_EXT_H #ifndef __HCLGE_EXT_H
#define __HCLGE_EXT_H #define __HCLGE_EXT_H
#include <linux/types.h> #include <linux/types.h>
#include "../../hnae3.h" #include "hnae3.h"
#define HCLGE_SFP_INFO_LEN 6 #define HCLGE_SFP_INFO_LEN 6
#define HCLGE_SFP_INFO_SIZE 140 #define HCLGE_SFP_INFO_SIZE 140
...@@ -16,16 +16,37 @@ struct hclge_chip_id_cmd { ...@@ -16,16 +16,37 @@ struct hclge_chip_id_cmd {
u32 rsv[5]; u32 rsv[5];
}; };
struct hclge_commit_id_cmd { struct hclge_sfp_info_para {
u8 commit_id[8]; u8 *buff;
u32 ncl_version; u16 offset;
u32 rsv[3]; u16 size;
u16 *outlen;
}; };
struct hclge_sfp_info { struct hclge_sfp_info {
u32 sfpinfo[6]; 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 { struct hclge_sfp_enable_cmd {
u32 set_sfp_enable_flag; u32 set_sfp_enable_flag;
u32 rsv[5]; u32 rsv[5];
...@@ -36,12 +57,53 @@ struct hclge_sfp_present_cmd { ...@@ -36,12 +57,53 @@ struct hclge_sfp_present_cmd {
u32 rsv[5]; u32 rsv[5];
}; };
struct hns3_lamp_signal { struct hclge_lamp_signal {
u8 error; u8 error;
u8 locate; u8 locate;
u8 activity; 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 { enum hclge_ext_opcode_type {
/* misc command */ /* misc command */
HCLGE_OPC_CHIP_ID_GET = 0x7003, HCLGE_OPC_CHIP_ID_GET = 0x7003,
...@@ -50,30 +112,15 @@ enum hclge_ext_opcode_type { ...@@ -50,30 +112,15 @@ enum hclge_ext_opcode_type {
HCLGE_OPC_GET_PORT_NUM = 0x7006, HCLGE_OPC_GET_PORT_NUM = 0x7006,
HCLGE_OPC_SET_LED = 0x7007, HCLGE_OPC_SET_LED = 0x7007,
HCLGE_OPC_DISABLE_NET_LANE = 0x7008, 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_INFO = 0x7100,
HCLGE_OPC_SFP_GET_PRESENT = 0x7101, HCLGE_OPC_SFP_GET_PRESENT = 0x7101,
HCLGE_OPC_SFP_SET_STATUS = 0x7102, HCLGE_OPC_SFP_SET_STATUS = 0x7102,
}; };
void hclge_clean_stats64(struct hnae3_handle *handle); int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode,
int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id); void *data, int length);
int hclge_get_commit_id(struct hnae3_handle *handle, u8 *commit_id, void hclge_reset_task_schedule_it(struct hclge_dev *hdev);
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);
#endif #endif
...@@ -13,20 +13,17 @@ ...@@ -13,20 +13,17 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include "../../kcompat.h" #include "kcompat.h"
#include "../../hns3pf/hclge_cmd.h" #include "hclge_cmd.h"
#include "../../hns3pf/hclge_main.h" #include "hclge_main.h"
#include "../../hnae3.h" #include "hnae3.h"
#include "hclge_ext.h" #include "hclge_ext.h"
#include "hclge_main_it.h" #include "hclge_main_it.h"
#include "../../hns3pf/hclge_err.h"
#ifdef CONFIG_HNS3_TEST #ifdef CONFIG_HNS3_TEST
#include "hclge_test.h" #include "hclge_test.h"
#endif #endif
#ifdef CONFIG_EXT_TEST
#define HCLGE_RESET_MAX_FAIL_CNT 1 #define HCLGE_RESET_MAX_FAIL_CNT 1
static nic_event_fn_t nic_event_call; static nic_event_fn_t nic_event_call;
...@@ -53,90 +50,125 @@ int nic_unregister_event(void) ...@@ -53,90 +50,125 @@ int nic_unregister_event(void)
EXPORT_SYMBOL(nic_unregister_event); EXPORT_SYMBOL(nic_unregister_event);
void nic_call_event(struct net_device *netdev, 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); nic_event_call(netdev, event_t);
netdev_info(netdev, "report event %d\n", event_t);
netdev_info(netdev, "report reset event %d\n", event_t); }
} }
EXPORT_SYMBOL(nic_call_event); 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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct net_device *netdev; struct net_device *netdev;
u32 reg_val;
netdev = hdev->vport[0].nic.netdev; netdev = hdev->vport[0].nic.netdev;
if (done) { if (test_and_clear_bit(HCLGE_IMP_RD_POISON, &hdev->imp_err_state)) {
dev_info(&hdev->pdev->dev, "Report Reset DONE!\n"); dev_err(&hdev->pdev->dev, "Detected IMP RD poison!\n");
nic_call_event(netdev, HNAE3_RESET_DONE_CUSTOM); 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) { if (test_and_clear_bit(HCLGE_IMP_CMDQ_ERROR, &hdev->imp_err_state)) {
dev_err(&hdev->pdev->dev, "Report Reset fail!\n"); dev_err(&hdev->pdev->dev, "Detected CMDQ ECC error!\n");
nic_call_event(netdev, HNAE3_PORT_FAULT); 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 hclge_dev *hdev = ae_dev->priv;
struct device *dev = &hdev->pdev->dev;
enum hnae3_reset_type_custom reset_type;
struct net_device *netdev; struct net_device *netdev;
u32 status;
netdev = hdev->vport[0].nic.netdev; 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 || if (nic_event_call) {
status & HCLGE_RAS_REG_ROCEE_ERR_MASK) nic_call_event(netdev, hdev->reset_level);
ae_dev->hw_err_reset_req = 0; } 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 */ bool hclge_reset_done_it(struct hnae3_handle *handle, bool done)
if (status & HCLGE_RAS_REG_NFE_MASK) { {
dev_warn(dev, struct hclge_vport *vport = hclge_get_vport(handle);
"HNS Non-Fatal RAS error(status=0x%x) identified\n", struct hclge_dev *hdev = vport->back;
status); struct net_device *netdev;
hclge_handle_all_ras_errors(hdev);
reset_type = ae_dev->ops->set_default_reset_request(ae_dev, netdev = hdev->vport[0].nic.netdev;
&ae_dev->hw_err_reset_req);
if (reset_type != HNAE3_NONE_RESET_CUSTOM) if (done) {
nic_call_event(netdev, reset_type); dev_info(&hdev->pdev->dev, "Report Reset DONE!\n");
} else { if (nic_event_call)
if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || nic_call_event(netdev, HNAE3_RESET_DONE_CUSTOM);
hdev->pdev->revision < 0x21) {
ae_dev->override_pci_need_reset = 1;
return PCI_ERS_RESULT_RECOVERED;
}
} }
if (status & HCLGE_RAS_REG_ROCEE_ERR_MASK) { if (hdev->reset_fail_cnt >= HCLGE_RESET_MAX_FAIL_CNT) {
dev_warn(dev, "ROCEE uncorrected RAS error identified\n"); dev_err(&hdev->pdev->dev, "Report Reset fail!\n");
hclge_handle_rocee_ras_error(ae_dev); 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 #ifdef CONFIG_IT_VALIDATION
#define HCLGE_NAME_IT "hclge" #define HCLGE_NAME_IT "hclge"
...@@ -145,39 +177,21 @@ EXPORT_SYMBOL(hclge_get_vport); ...@@ -145,39 +177,21 @@ EXPORT_SYMBOL(hclge_get_vport);
EXPORT_SYMBOL(hclge_cmd_set_promisc_mode); EXPORT_SYMBOL(hclge_cmd_set_promisc_mode);
EXPORT_SYMBOL(hclge_promisc_param_init); 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) int hclge_init_it(void)
{ {
pr_info("%s is initializing\n", HCLGE_NAME_IT); pr_info("%s is initializing\n", HCLGE_NAME_IT);
#ifdef CONFIG_HNS3_TEST #ifdef CONFIG_HNS3_TEST
hclge_ops.send_cmdq = hclge_send_cmdq; hclge_ops.send_cmdq = hclge_send_cmdq;
hclge_ops.priv_ops = hclge_ext_ops_handle;
#endif #endif
#ifdef CONFIG_EXT_TEST hclge_ops.reset_event = hclge_reset_event_it;
hclge_ops.handle_hw_ras_error = hclge_handle_hw_ras_error_it;
hclge_ops.reset_done = hclge_reset_done_it; hclge_ops.reset_done = hclge_reset_done_it;
#endif hclge_ops.handle_imp_error = hclge_handle_imp_error_it;
ae_algo.pdev_id_table = ae_algo_pci_tbl_it;
hnae3_register_ae_algo(&ae_algo); hnae3_register_ae_algo(&ae_algo);
return 0; return 0;
} }
module_init(hclge_init_it); module_init(hclge_init_it);
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
extern struct hnae3_ae_algo ae_algo; extern struct hnae3_ae_algo ae_algo;
extern struct hnae3_ae_ops hclge_ops; extern struct hnae3_ae_ops hclge_ops;
enum hnae3_reset_type_custom { enum hnae3_event_type_custom {
HNAE3_VF_RESET_CUSTOM, HNAE3_VF_RESET_CUSTOM,
HNAE3_VF_FUNC_RESET_CUSTOM, HNAE3_VF_FUNC_RESET_CUSTOM,
HNAE3_VF_PF_FUNC_RESET_CUSTOM, HNAE3_VF_PF_FUNC_RESET_CUSTOM,
...@@ -20,17 +20,20 @@ enum hnae3_reset_type_custom { ...@@ -20,17 +20,20 @@ enum hnae3_reset_type_custom {
HNAE3_NONE_RESET_CUSTOM, HNAE3_NONE_RESET_CUSTOM,
HNAE3_PORT_FAULT, HNAE3_PORT_FAULT,
HNAE3_RESET_DONE_CUSTOM, 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 * nic_event_fn_t - nic event handler prototype
* @netdev: net device * @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, 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 * nic_register_event - register for nic event listening
...@@ -46,7 +49,5 @@ int nic_register_event(nic_event_fn_t event_call); ...@@ -46,7 +49,5 @@ int nic_register_event(nic_event_fn_t event_call);
int nic_unregister_event(void); int nic_unregister_event(void);
void nic_call_event(struct net_device *netdev, void nic_call_event(struct net_device *netdev,
enum hnae3_reset_type_custom event_t); enum hnae3_event_type_custom event_t);
#endif
#endif #endif
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
#ifndef __HCLGE_TEST_H #ifndef __HCLGE_TEST_H
#define __HCLGE_TEST_H #define __HCLGE_TEST_H
#include "../../hns3pf/hclge_cmd.h" #include "hclge_cmd.h"
#include "../../hns3pf/hclge_main.h" #include "hclge_main.h"
int hclge_send_cmdq(struct hnae3_handle *handle, void *data, int num); 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.
先完成此消息的编辑!
想要评论请 注册