diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 25152715396bc04eda5e9d793a608ff7ae546071..397ce4088b53feeaa42451a2493827dffd1ec75b 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -123,6 +123,16 @@ config HNS3_ENET family of SoCs. This module depends upon HNAE3 driver to access the HNAE3 devices and their associated operations. +config HNS3_CAE + tristate "Hisilicon HNS3 configuration & analysis & enhancement Support" + default m + depends on HNS3_HCLGE && HNS3_ENET + help + This selects the Configuration, Analysis and Enhancement Support for HNS3 Driver + (e.g. SFP management, self-adaptive port speed and DFX). It is supposed to + support upcoming User Mode Tool (i.e. hiarmtool) developed by Huawei. + This module depends upon HNS3_HCLGE and HNS3 driver. + endif #HNS3 endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index ee1b9f90f1c9fc930ce33f49c91af67101627253..feb9a31253ea4f5e873ff9eb66ae690ae142a35a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -2,14 +2,85 @@ # # Makefile for the HISILICON network device drivers. # -ccflags-y += -I$(srctree)/$(src) -obj-$(CONFIG_HNS3) += hns3pf/ -obj-$(CONFIG_HNS3) += hns3vf/ +# Add security options +ccflags-y += -fstack-protector-strong +ccflags-y += -Wl,-z,relro,-z,now +ccflags-y += -Wl,-z,noexecstack +ccflags-y += -D_FORTIFY_SOURCE=2 -O2 +ccflags-y += -fvisibility=hidden +ccflags-y += -Wformat=2 -Wfloat-equal +ccflags-y += -fsigned-char +ccflags-y += -DCONFIG_IT_VALIDATION +ccflags-y += -DCONFIG_HNS3_TEST +ccflags-y += -DCONFIG_EXT_TEST + +PWD = $(srctree)/drivers/net/ethernet/hisilicon/hns3 +#add include path +ccflags-y += -I$(PWD) \ + -I$(PWD)/hns3pf \ + -I$(PWD)/hns-customer \ + -I$(PWD)/hns-customer/hns3pf \ + -I$(PWD)/hns3vf \ + -I$(PWD)/hns3_cae + +obj-$(CONFIG_HNS3_HCLGE) += hclge.o +hclge-objs = hns3pf/hclge_main.o \ + hns3pf/hclge_cmd.o \ + hns3pf/hclge_mdio.o \ + hns3pf/hclge_debugfs.o \ + hns3pf/hclge_tm.o \ + hns3pf/hclge_mbx.o \ + hns3pf/hclge_err.o + +hclge-objs += hns-customer/hns3pf/hclge_main_it.o \ + hns-customer/hns3pf/hclge_cmd_it.o \ + hns-customer/hns3pf/hclge_ext.o \ + hns-customer/hns3pf/hclge_test.o + +hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o + +#### compile hnae3.ko obj-$(CONFIG_HNS3) += hnae3.o obj-$(CONFIG_HNS3_ENET) += hns3.o hns3-objs = hns3_enet.o hns3_ethtool.o hns3_debugfs.o +hns3-objs += hns-customer/hns3_enet_it.o hns-customer/hns3_ext.o hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o + +#### compile hclgevf.ko +obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o +hclgevf-objs := hns3vf/hclgevf_main.o hns3vf/hclgevf_cmd.o hns3vf/hclgevf_mbx.o + +#### compile hns3_cae.ko +#add rally code +HNS3_CAE_OBJS_PRIM = hns3_cae/hns3_cae_init.o \ + hns3_cae/hns3_nictool.o \ + hns3_cae/hns3_priv_common_test.o \ + hns3_cae/hns3_priv_dcb.o \ + hns3_cae/hns3_priv_lamp.o \ + hns3_cae/hns3_priv_mactbl.o \ + hns3_cae/hns3_priv_m7_cmd.o +#add test code +HNS3_CAE_OBJS_EXT = hns3_cae/hns3_priv_dfx.o \ + hns3_cae/hns3_priv_ext.o \ + hns3_cae/hns3_priv_fd.o \ + hns3_cae/hns3_priv_hilink_param.o \ + hns3_cae/hns3_priv_irq.o \ + hns3_cae/hns3_priv_mac.o \ + hns3_cae/hns3_priv_phy.o \ + hns3_cae/hns3_priv_pkt.o \ + hns3_cae/hns3_priv_port.o \ + hns3_cae/hns3_priv_promisc.o \ + hns3_cae/hns3_priv_qinfo.o \ + hns3_cae/hns3_priv_qos.o \ + hns3_cae/hns3_priv_qres.o \ + hns3_cae/hns3_priv_rss.o \ + hns3_cae/hns3_priv_stat.o \ + hns3_cae/hns3_priv_tm.o \ + hns3_cae/hns3_priv_vlan.o \ + hns3_cae/hns3_priv_xsfp.o +obj-$(CONFIG_HNS3_CAE) += hns3_cae.o +hns3_cae-objs := $(HNS3_CAE_OBJS_PRIM) $(HNS3_CAE_OBJS_EXT) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.c b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.c index 0305fcb26588f9951f8033f2d91074e5f15b7300..ef73145e67d958aa89cc53a1447aaf474a4f639a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.c @@ -8,75 +8,22 @@ #include #include -#include "../hnae3.h" +#include "hnae3.h" #include "hns3_enet_it.h" -#include "hns3pf/hclge_main_it.h" -#include "../hns3_enet.h" +#include "hns3_enet.h" extern const char hns3_driver_string[]; extern const char hns3_copyright[]; #ifdef CONFIG_IT_VALIDATION -#define HNAE_DRIVER_VERSION "B075" -#define HNAE_DRIVER_VERSION_MAX_LEN 8 +#define HNAE_DRIVER_VERSION "1.8.10.0" -#ifdef CONFIG_HNS3_X86 -#define HNAE3_DEV_ID_X86_25_GE 0xA125 -#endif - -extern struct ethtool_ops hns3vf_ethtool_ops; -extern struct ethtool_ops hns3_ethtool_ops; extern struct net_device_ops hns3_nic_netdev_ops; extern const struct hnae3_client_ops client_ops; extern struct hnae3_client client; extern struct pci_driver hns3_driver; extern const char hns3_driver_name[]; -extern struct pci_error_handlers hns3_err_handler; - -extern int hns3_set_link_ksettings_it(struct net_device *netdev, - const struct ethtool_link_ksettings *cmd); - -/* hns3_pci_tbl - PCI Device ID Table - * - * Last entry must be all 0s - * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, - * Class, Class Mask, private data (not used) } - */ -const struct pci_device_id hns3_pci_tbl_it[] = { - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_GE), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA), - HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA_MACSEC), - HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA), - HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA_MACSEC), - HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), - HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_VF), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_DCB_PFC_VF), - HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, -#ifdef CONFIG_HNS3_X86 - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_X86_25_GE), 0}, -#endif - /* required last entry */ - {0, } -}; -MODULE_DEVICE_TABLE(pci, hns3_pci_tbl_it); - -#ifdef CONFIG_EXT_TEST -void hns3_nic_net_timeout_it(struct net_device *ndev) -{ - if (!hns3_get_tx_timeo_queue_info(ndev)) - return; - - nic_call_event(ndev, HNAE3_FUNC_RESET_CUSTOM); -} -#endif int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd) { @@ -84,7 +31,6 @@ int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd) case (SIOCDEVPRIVATE + 4): if (hns3_ioctl) return hns3_ioctl(netdev, ifr->ifr_data); - pr_err("open nic_test failed"); return -EINVAL; default: return -EINVAL; @@ -93,8 +39,7 @@ int hns3_nic_do_ioctl_it(struct net_device *netdev, struct ifreq *ifr, int cmd) #if (KERNEL_VERSION(4, 19, 0) > LINUX_VERSION_CODE) u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb, - void *accel_priv, - select_queue_fallback_t fallback) + void *accel_priv, select_queue_fallback_t fallback) #else u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb, struct net_device *accel_priv, @@ -115,25 +60,15 @@ u16 hns3_nic_select_queue_it(struct net_device *ndev, struct sk_buff *skb, static int __init hns3_init_module_it(void) { - struct ethtool_ops *loc_ethtool_ops; struct net_device_ops *ndev_ops; int ret; -#ifdef CONFIG_EXT_TEST - struct pci_error_handlers *err_handlers; - - err_handlers = (struct pci_error_handlers *)&hns3_err_handler; - err_handlers->slot_reset = NULL; -#endif - pr_info("%s: %s - version\n", hns3_driver_name, hns3_driver_string); pr_info("%s: %s\n", hns3_driver_name, hns3_copyright); strncpy(hns3_driver_version, HNAE_DRIVER_VERSION, - HNAE_DRIVER_VERSION_MAX_LEN); + sizeof(HNAE_DRIVER_VERSION)); - loc_ethtool_ops = (struct ethtool_ops *)&hns3_ethtool_ops; - loc_ethtool_ops->set_link_ksettings = hns3_set_link_ksettings_it; client.type = HNAE3_CLIENT_KNIC; snprintf(client.name, HNAE3_CLIENT_NAME_LENGTH - 1, "%s", hns3_driver_name); @@ -141,9 +76,6 @@ static int __init hns3_init_module_it(void) client.ops = &client_ops; ndev_ops = (struct net_device_ops *)&hns3_nic_netdev_ops; ndev_ops->ndo_do_ioctl = hns3_nic_do_ioctl_it; -#ifdef CONFIG_EXT_TEST - ndev_ops->ndo_tx_timeout = hns3_nic_net_timeout_it; -#endif ndev_ops->ndo_select_queue = hns3_nic_select_queue_it; INIT_LIST_HEAD(&client.node); @@ -153,7 +85,6 @@ static int __init hns3_init_module_it(void) if (ret) goto err_reg_client; - hns3_driver.id_table = hns3_pci_tbl_it; ret = pci_register_driver(&hns3_driver); if (ret) goto err_reg_driver; @@ -166,5 +97,6 @@ static int __init hns3_init_module_it(void) hns3_dbg_unregister_debugfs(); return ret; } + module_init(hns3_init_module_it); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.h b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.h index 9ba52155f1d5a3fcf1f2fa4ffc8e7322186f99d7..59bfcbec81a275f936c4d0700d4009ae1a269575 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_enet_it.h @@ -7,8 +7,6 @@ typedef int (*hns3_priv_func)(struct net_device *, void *); hns3_priv_func hns3_ioctl; -#define VERSION_NUMBER "$FULL_VERSION" - #ifndef LINUX_VERSION_CODE #include #else diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ethtool_it.c b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ethtool_it.c deleted file mode 100644 index 074aa38b47fc7ad5dd081a7e42f48e6739465668..0000000000000000000000000000000000000000 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ethtool_it.c +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// Copyright (c) 2016-2017 Hisilicon Limited. - -#include -#include -#include -#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); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.c b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.c index 76161f1672dfbb0d1c9c6760a6c09985c89b76ec..5fc097088913f182293748bb6c4b26a459b00823 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.c @@ -38,21 +38,28 @@ int nic_netdev_match_check(struct net_device *netdev) EXPORT_SYMBOL(nic_netdev_match_check); void nic_chip_recover_handler(struct net_device *netdev, - enum hnae3_reset_type_custom event_t) + enum hnae3_event_type_custom event_t) { - struct hnae3_ae_dev *ae_dev; - struct hns3_nic_priv *priv; struct hnae3_handle *h; if (nic_netdev_match_check(netdev)) return; - priv = netdev_priv(netdev); - h = priv->ae_handle; - ae_dev = pci_get_drvdata(h->pdev); + dev_info(&netdev->dev, "reset type is %d!!\n", event_t); - if (ae_dev->ops->reset_event) - ae_dev->ops->reset_event(h->pdev, NULL); + 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; + } + + h = hns3_get_handle(netdev); + if (h->ae_algo->ops->priv_ops) + h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_RESET, &event_t, 0); } EXPORT_SYMBOL(nic_chip_recover_handler); @@ -70,7 +77,10 @@ int nic_clean_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats) priv = netdev_priv(ndev); h = hns3_get_handle(ndev); kinfo = &h->kinfo; - hclge_clean_stats64(h); + + if (h->ae_algo->ops->priv_ops) + h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_CLEAN_STATS64, stats, + 0); for (i = 0; i < kinfo->num_tqps; i++) { ring = priv->ring_data[i].ring; @@ -95,66 +105,96 @@ int nic_get_chipid(struct net_device *ndev, u32 *chip_id) return -EINVAL; h = hns3_get_handle(ndev); - return hclge_get_chipid(h, chip_id); + + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_CHIPID, + chip_id, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_get_chipid); -int nic_get_sfpinfo(struct net_device *ndev, u8 *buff, u16 size, u16 *outlen) +int nic_get_mac_id(struct net_device *ndev, u32 *mac_id) { struct hnae3_handle *h; if (nic_netdev_match_check(ndev)) return -ENODEV; - if (!buff || !outlen) + if (!mac_id) return -EINVAL; h = hns3_get_handle(ndev); - return hclge_get_sfpinfo(h, buff, 0, size, outlen); + + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_MAC_ID, + mac_id, 0); + else + return -EOPNOTSUPP; } -EXPORT_SYMBOL(nic_get_sfpinfo); +EXPORT_SYMBOL(nic_get_mac_id); -int nic_get_sfp_present(struct net_device *ndev, u32 *present) +int nic_get_sfpinfo(struct net_device *ndev, u8 *buff, u16 size, u16 *outlen) { + struct hns3_sfp_info_para para; struct hnae3_handle *h; if (nic_netdev_match_check(ndev)) return -ENODEV; - if (!present) + if (!buff || !outlen) return -EINVAL; + para.buff = buff; + para.outlen = outlen; + para.offset = 0; + para.size = size; h = hns3_get_handle(ndev); - return hclge_get_sfp_present(h, present); + + if (h->ae_algo->ops->priv_ops) { + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_SFPINFO, + ¶, 0); + } else { + return -EOPNOTSUPP; + } } -EXPORT_SYMBOL(nic_get_sfp_present); +EXPORT_SYMBOL(nic_get_sfpinfo); -int nic_set_sfp_state(struct net_device *ndev, bool en) +int nic_get_sfp_present(struct net_device *ndev, int *present) { struct hnae3_handle *h; if (nic_netdev_match_check(ndev)) return -ENODEV; + if (!present) + return -EINVAL; + h = hns3_get_handle(ndev); - return hclge_set_sfp_state(h, en); + + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_PRESENT, + present, 0); + else + return -EOPNOTSUPP; } -EXPORT_SYMBOL(nic_set_sfp_state); +EXPORT_SYMBOL(nic_get_sfp_present); -int nic_get_sfp_speed(struct net_device *ndev, u32 *speed) +int nic_set_sfp_state(struct net_device *ndev, bool en) { struct hnae3_handle *h; if (nic_netdev_match_check(ndev)) return -ENODEV; - if (!speed) - return -EINVAL; - h = hns3_get_handle(ndev); - return hclge_ext_get_sfp_speed(h, speed); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_SET_SFP_STATE, + &en, 0); + else + return -EOPNOTSUPP; } -EXPORT_SYMBOL(nic_get_sfp_speed); +EXPORT_SYMBOL(nic_set_sfp_state); int nic_get_chip_num(struct net_device *ndev, u32 *chip_num) { @@ -167,7 +207,11 @@ int nic_get_chip_num(struct net_device *ndev, u32 *chip_num) return -EINVAL; h = hns3_get_handle(ndev); - return hclge_get_chip_num(h, chip_num); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_CHIP_NUM, + chip_num, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_get_chip_num); @@ -182,19 +226,30 @@ int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num) return -EINVAL; h = hns3_get_handle(ndev); - return hclge_get_port_num(h, port_num); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_PORT_NUM, + port_num, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_get_port_num_per_chip); int nic_set_led(struct net_device *ndev, int type, int status) { + struct hns3_led_state_para para; struct hnae3_handle *h; if (nic_netdev_match_check(ndev)) return -ENODEV; + para.status = status; + para.type = type; h = hns3_get_handle(ndev); - return hclge_set_led(h, type, status); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_SET_LED, ¶, + 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_set_led); @@ -209,7 +264,11 @@ int nic_get_led_signal(struct net_device *ndev, struct hns3_lamp_signal *signal) return -EINVAL; h = hns3_get_handle(ndev); - return hclge_get_led_signal(h, signal); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_GET_LED_SIGNAL, + signal, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_get_led_signal); @@ -221,11 +280,15 @@ int nic_disable_net_lane(struct net_device *ndev) return -ENODEV; h = hns3_get_handle(ndev); - return hclge_disable_net_lane(h); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_DISABLE_LANE, + NULL, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_disable_net_lane); -int nic_get_net_lane_status(struct net_device *ndev, u32 *status) +int nic_get_net_lane_status(struct net_device *ndev, u32 *status) { struct hnae3_handle *h; @@ -236,11 +299,16 @@ int nic_get_net_lane_status(struct net_device *ndev, u32 *status) return -EINVAL; h = hns3_get_handle(ndev); - return hclge_get_net_lane_status(h, status); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, + HNS3_EXT_OPC_GET_LANE_STATUS, + status, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_get_net_lane_status); -int nic_set_mac_state(struct net_device *ndev, int enable) +int nic_set_mac_state(struct net_device *ndev, int enable) { struct hnae3_handle *h; bool en; @@ -250,7 +318,11 @@ int nic_set_mac_state(struct net_device *ndev, int enable) h = hns3_get_handle(ndev); en = !!enable; - return hclge_set_mac_state(h, en); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_SET_MAC_STATE, + &en, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_set_mac_state); @@ -271,7 +343,8 @@ int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask) priv = netdev_priv(netdev); if (test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) { - dev_err(&netdev->dev, "ethernet is down, not support cpu affinity set\n"); + dev_err(&netdev->dev, + "ethernet is down, not support cpu affinity set\n"); return -EOPNOTSUPP; } @@ -284,16 +357,16 @@ int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask) ret = irq_set_affinity_hint(tqp_vector->vector_irq, NULL); if (ret) { - dev_err(&netdev->dev, "reset affinity hint fail, ret = %d\n", - ret); + dev_err(&netdev->dev, + "reset affinity hint fail, ret = %d\n", ret); return ret; } ret = irq_set_affinity_hint(tqp_vector->vector_irq, &tqp_vector->affinity_mask); if (ret) { - dev_err(&netdev->dev, "set affinity hint fail, ret = %d\n", - ret); + dev_err(&netdev->dev, + "set affinity hint fail, ret = %d\n", ret); return ret; } } @@ -308,12 +381,151 @@ EXPORT_SYMBOL(nic_set_cpu_affinity); int nic_disable_clock(struct net_device *ndev) { struct hnae3_handle *h; - + u32 en; if (nic_netdev_match_check(ndev)) return -ENODEV; + en = 0; h = hns3_get_handle(ndev); - return hclge_config_nic_clock(h, 0); + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, HNS3_EXT_OPC_CONFIG_CLOCK, + &en, 0); + else + return -EOPNOTSUPP; } EXPORT_SYMBOL(nic_disable_clock); +int nic_set_pfc_storm_para(struct net_device *ndev, int dir, int enable, + int period_ms, int times, int recovery_period_ms) +{ + struct hns3_pfc_storm_para para; + struct hnae3_handle *h; + + if (nic_netdev_match_check(ndev)) + return -ENODEV; + + para.dir = dir; + para.enable = enable; + para.period_ms = period_ms; + para.times = times; + para.recovery_period_ms = recovery_period_ms; + h = hns3_get_handle(ndev); + + if (h->ae_algo->ops->priv_ops) + return h->ae_algo->ops->priv_ops(h, + HNS3_EXT_OPC_SET_PFC_STORM_PARA, + ¶, 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, + ¶, 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, + ¶, 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, + ¶, 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); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.h b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.h index 98ab12746273eb25799503fccd0d914fdfce178f..741912c10eaf4f121505236442917be04ffe0fa7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3_ext.h @@ -4,32 +4,91 @@ #ifndef __HNS3_EXT_H #define __HNS3_EXT_H #include -#include "../hns3_enet.h" -#include "hns3pf/hclge_ext.h" -#include "hns3pf/hclge_main_it.h" - -/** - * nic_chip_recover_handler - reset net device by port id - * @netdev: net device - * @hnae3_reset_type: nic device event type - */ -void nic_chip_recover_handler(struct net_device *netdev, - enum hnae3_reset_type_custom event_t); +#include "hns3_enet.h" +#include "hnae3.h" +#include "hclge_main_it.h" + +enum hns3_ext_op_code { + HNS3_EXT_OPC_CLEAN_STATS64 = 0, + HNS3_EXT_OPC_GET_CHIPID, + HNS3_EXT_OPC_GET_SFPINFO, + HNS3_EXT_OPC_SET_SFP_STATE, + HNS3_EXT_OPC_GET_CHIP_NUM, + HNS3_EXT_OPC_GET_PORT_NUM, + HNS3_EXT_OPC_SET_LED, + HNS3_EXT_OPC_GET_PRESENT, + HNS3_EXT_OPC_DISABLE_LANE, + HNS3_EXT_OPC_GET_LANE_STATUS, + HNS3_EXT_OPC_GET_LED_SIGNAL, + HNS3_EXT_OPC_SET_MAC_STATE, + HNS3_EXT_OPC_CONFIG_CLOCK, + HNS3_EXT_OPC_GET_PFC_STORM_PARA, + HNS3_EXT_OPC_SET_PFC_STORM_PARA, + HNS3_EXT_OPC_GET_PHY_REG, + HNS3_EXT_OPC_SET_PHY_REG, + HNS3_EXT_OPC_GET_MAC_ID, + HNS3_EXT_OPC_OPT_MAC_TABLE, + HNS3_EXT_OPC_RESET, + HNS3_EXT_OPC_GET_HILINK_REF_LOS, +}; + +struct hns3_sfp_info_para { + u8 *buff; + u16 offset; + u16 size; + u16 *outlen; +}; + +struct hns3_led_state_para { + u32 type; + u32 status; +}; + +struct hns3_pfc_storm_para { + u32 dir; + u32 enable; + u32 period_ms; + u32 times; + u32 recovery_period_ms; +}; + +struct hns3_phy_para { + u32 page_select_addr; + u32 reg_addr; + u16 page; + u16 data; +}; + +struct hns3_lamp_signal { + u8 error; + u8 locate; + u8 activity; +}; + +int nic_get_chipid(struct net_device *ndev, u32 *chip_id); int nic_netdev_match_check(struct net_device *netdev); +int nic_get_sfpinfo(struct net_device *ndev, u8 *buff, u16 size, u16 *outlen); +int nic_get_sfp_present(struct net_device *ndev, int *present); +int nic_set_sfp_state(struct net_device *ndev, bool en); int nic_clean_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats); -int nic_get_sfpinfo(struct net_device *netdev, u8 *buff, u16 size, u16 *outlen); -int nic_set_sfp_state(struct net_device *netdev, bool en); -int nic_get_sfp_id(struct net_device *netdev, u32 *sfp_id); -int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num); int nic_get_chip_num(struct net_device *ndev, u32 *chip_num); +int nic_get_port_num_per_chip(struct net_device *ndev, u32 *port_num); int nic_set_led(struct net_device *ndev, int type, int status); int nic_disable_net_lane(struct net_device *ndev); -int nic_get_net_lane_status(struct net_device *ndev, u32 *status); +int nic_get_net_lane_status(struct net_device *ndev, u32 *status); int nic_set_cpu_affinity(struct net_device *netdev, cpumask_t *affinity_mask); -int nic_get_led_signal(struct net_device *ndev, - struct hns3_lamp_signal *signal); -int nic_set_mac_state(struct net_device *ndev, int enable); +int nic_set_mac_state(struct net_device *ndev, int enable); int nic_disable_clock(struct net_device *ndev); +int nic_set_pfc_storm_para(struct net_device *ndev, int dir, int enable, + int period_ms, int times, int recovery_period_ms); +int nic_get_pfc_storm_para(struct net_device *ndev, int dir, int *enable, + int *period_ms, int *times, int *recovery_period_ms); +int nic_get_phy_reg(struct net_device *ndev, u32 page_select_addr, + u16 page, u32 reg_addr, u16 *data); +int nic_set_phy_reg(struct net_device *ndev, u32 page_select_addr, + u16 page, u32 reg_addr, u16 data); +int nic_get_mac_id(struct net_device *ndev, u32 *mac_id); +int nic_get_hilink_ref_los(struct net_device *ndev, u32 *status); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_cmd_it.c b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_cmd_it.c index e31f6f1a42dfbf7b5a8f73650a55ab754db436c3..910c4d6fbe050e4b28c8af87e4dad5235aa5d60d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_cmd_it.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_cmd_it.c @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2016-2017 Hisilicon Limited. -#include "../../hns3pf/hclge_cmd.h" -#include "../../hnae3.h" -#include "../../hns3pf/hclge_main.h" +#include "hclge_cmd.h" +#include "hnae3.h" +#include "hclge_main.h" #ifdef CONFIG_HNS3_TEST #include "hclge_test.h" @@ -12,4 +12,3 @@ EXPORT_SYMBOL(hclge_cmd_reuse_desc); EXPORT_SYMBOL(hclge_cmd_setup_basic_desc); EXPORT_SYMBOL(hclge_cmd_send); #endif - diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.c b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.c index f4c790952268496dee0fb15f11e956f2e5fe1d22..78940e9b88ac52b773fd649076f470f72007edb5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.c @@ -15,12 +15,16 @@ #include #include #include -#include "../../hns3pf/hclge_main.h" -#include "../../hnae3.h" -#include "../../hns3pf/hclge_cmd.h" +#include "hclge_main.h" +#include "hnae3.h" +#include "hclge_cmd.h" #include "hclge_ext.h" -void hclge_clean_stats64(struct hnae3_handle *handle) +#define BD0_DATA_LEN 20 +#define BD1_DATA_LEN 24 + +int hclge_clean_stats64(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hnae3_knic_private_info *kinfo; struct hclge_vport *vport; @@ -37,17 +41,20 @@ void hclge_clean_stats64(struct hnae3_handle *handle) memset(&tqp->tqp_stats, 0, sizeof(struct hlcge_tqp_stats)); } memset(&hdev->hw_stats.mac_stats, 0, sizeof(struct hclge_mac_stats)); + return 0; } -EXPORT_SYMBOL(hclge_clean_stats64); -int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id) +int hclge_get_chipid(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_chip_id_cmd *resp = NULL; struct hclge_desc desc; + u32 *chip_id; int ret; + chip_id = (u32 *)data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHIP_ID_GET, true); resp = (struct hclge_chip_id_cmd *)(desc.data); ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -58,34 +65,27 @@ int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id) *chip_id = resp->chip_id; return 0; } -EXPORT_SYMBOL(hclge_get_chipid); -int hclge_get_commit_id(struct hnae3_handle *handle, u8 *commit_id, - u32 *ncl_version) +int hclge_get_mac_id(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - struct hclge_commit_id_cmd *resp = NULL; struct hclge_desc desc; - int ret, i; + u32 *mac_id; + int ret; - hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_IMP_COMMIT_ID_GET, true); - resp = (struct hclge_commit_id_cmd *)(desc.data); + mac_id = (u32 *)data; + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CHIP_ID_GET, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { - dev_err(&hdev->pdev->dev, "get commit id failed %d\n", ret); + dev_err(&hdev->pdev->dev, "get mac id failed, ret = %d\n", ret); return ret; } - for (i = 0; i < 8; i++) - commit_id[i] = resp->commit_id[i]; - - commit_id[8] = '\0'; - *ncl_version = resp->ncl_version; - + *mac_id = desc.data[1]; return 0; } -EXPORT_SYMBOL(hclge_get_commit_id); static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, u16 offset, u16 size, u16 *outlen) @@ -95,8 +95,13 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, struct hclge_dev *hdev = vport->back; struct hclge_sfp_info *resp = NULL; int ret; - int i; - int j; + u32 i; + u32 j; + u32 temp_len; + u32 data_len; + u8 *temp_data; + + memset(desc, 0x0, sizeof(desc)); for (i = 0; i < HCLGE_SFP_INFO_LEN; i++) { hclge_cmd_setup_basic_desc(&desc[i], @@ -112,8 +117,7 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_SFP_INFO_LEN); if (ret) { dev_err(&hdev->pdev->dev, - "get spf information cmd failed %d\n", - ret); + "get spf information cmd failed %d\n", ret); return ret; } @@ -121,51 +125,60 @@ static int _hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, resp = (struct hclge_sfp_info *)desc[i].data; if (i == 0) { *outlen = (resp[i].sfpinfo[0] >> 16) & 0xFFFF; - for (j = 1; j < 6; j++) { - *(u32 *)buff = resp->sfpinfo[j]; - buff = buff + sizeof(u32); - } + temp_len = *outlen; + data_len = + (temp_len > BD0_DATA_LEN) ? BD0_DATA_LEN : temp_len; + temp_data = (u8 *)&resp->sfpinfo[1]; } else { - for (j = 0; j < 6; j++) { - *(u32 *)buff = resp->sfpinfo[j]; - buff = buff + sizeof(u32); - } + data_len = + (temp_len > BD1_DATA_LEN) ? BD1_DATA_LEN : temp_len; + temp_data = (u8 *)&resp->sfpinfo[0]; } + + for (j = 0; j < data_len; j++) + *buff++ = *temp_data++; + + temp_len -= data_len; + if (temp_len == 0) + break; } return 0; } -int hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, u16 offset, - u16 size, u16 *outlen) +int hclge_get_sfpinfo(struct hnae3_handle *handle, int opcode, + void *data, int length) { + struct hclge_sfp_info_para *para; u16 tmp_size; u8 *tmp_buff; u16 tmp_outlen; int ret; + para = (struct hclge_sfp_info_para *)data; + tmp_buff = para->buff; - tmp_buff = buff; - while (size) { + while (para->size) { WARN_ON_ONCE(!tmp_buff); - if (size > HCLGE_SFP_INFO_SIZE) + if (para->size > HCLGE_SFP_INFO_SIZE) tmp_size = HCLGE_SFP_INFO_SIZE; else - tmp_size = size; - ret = _hclge_get_sfpinfo(handle, tmp_buff, offset, tmp_size, - &tmp_outlen); + tmp_size = para->size; + ret = _hclge_get_sfpinfo(handle, tmp_buff, para->offset, + tmp_size, &tmp_outlen); if (ret) return ret; - offset += tmp_size; - size -= tmp_size; + para->offset += tmp_size; + para->size -= tmp_size; tmp_buff += tmp_size; - *outlen += tmp_outlen; + *para->outlen += tmp_outlen; if (tmp_size != tmp_outlen) break; } + return 0; } -EXPORT_SYMBOL(hclge_get_sfpinfo); -int hclge_set_sfp_state(struct hnae3_handle *handle, bool en) +int hclge_set_sfp_state(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_sfp_enable_cmd *req = NULL; @@ -175,7 +188,7 @@ int hclge_set_sfp_state(struct hnae3_handle *handle, bool en) hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_SET_STATUS, false); req = (struct hclge_sfp_enable_cmd *)desc.data; - req->set_sfp_enable_flag = en; + req->set_sfp_enable_flag = *(bool *)data; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) @@ -184,12 +197,13 @@ int hclge_set_sfp_state(struct hnae3_handle *handle, bool en) return ret; } -EXPORT_SYMBOL(hclge_set_sfp_state); -int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num) +int hclge_get_chip_num(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + u32 *chip_num = (u32 *)data; struct hclge_desc desc; int ret; @@ -202,40 +216,17 @@ int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num) *chip_num = desc.data[0]; return 0; } -EXPORT_SYMBOL(hclge_get_chip_num); - -int hclge_ext_get_sfp_speed(struct hnae3_handle *handle, u32 *speed) -{ - struct hclge_vport *vport = hclge_get_vport(handle); - struct hclge_dev *hdev = vport->back; - struct hclge_desc desc; - int ret = 0; - - hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_INFO, true); - - ret = hclge_cmd_send(&hdev->hw, &desc, 1); - if (ret == -EOPNOTSUPP) { - dev_warn(&hdev->pdev->dev, - "IMP do not support get SFP speed %d\n", ret); - return ret; - } else if (ret) { - dev_err(&hdev->pdev->dev, "get sfp speed failed %d\n", ret); - return ret; - } - - *speed = desc.data[0]; - - return 0; -} -EXPORT_SYMBOL(hclge_ext_get_sfp_speed); -int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num) +int hclge_get_port_num(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_desc desc; + u32 *port_num; int ret; + port_num = (u32 *)data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_PORT_NUM, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { @@ -245,18 +236,20 @@ int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num) *port_num = desc.data[0]; return 0; } -EXPORT_SYMBOL(hclge_get_port_num); -int hclge_set_led(struct hnae3_handle *handle, u32 type, u32 status) +int hclge_set_led(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + struct hclge_led_state *para; struct hclge_desc desc; int ret; + para = (struct hclge_led_state *)data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, false); - desc.data[0] = type; - desc.data[1] = status; + desc.data[0] = para->type; + desc.data[1] = para->status; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "get set led failed %d\n", ret); @@ -265,16 +258,17 @@ int hclge_set_led(struct hnae3_handle *handle, u32 type, u32 status) return 0; } -EXPORT_SYMBOL(hclge_set_led); -int hclge_get_led_signal(struct hnae3_handle *handle, - struct hns3_lamp_signal *signal) +int hclge_get_led_signal(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + struct hclge_lamp_signal *signal; struct hclge_desc desc; int ret; + signal = (struct hclge_lamp_signal *)data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_LED, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { @@ -289,16 +283,18 @@ int hclge_get_led_signal(struct hnae3_handle *handle, return 0; } -EXPORT_SYMBOL(hclge_get_led_signal); -int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present) +int hclge_get_sfp_present(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_sfp_present_cmd *resp = NULL; struct hclge_dev *hdev = vport->back; struct hclge_desc desc; + u32 *present; int ret = 0; + present = (u32 *)data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SFP_GET_PRESENT, true); resp = (struct hclge_sfp_present_cmd *)desc.data; ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -310,9 +306,9 @@ int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present) *present = resp->sfp_present; return 0; } -EXPORT_SYMBOL(hclge_get_sfp_present); -int hclge_disable_net_lane(struct hnae3_handle *handle) +int hclge_disable_net_lane(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; @@ -328,15 +324,17 @@ int hclge_disable_net_lane(struct hnae3_handle *handle) } return 0; } -EXPORT_SYMBOL(hclge_disable_net_lane); -int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status) +int hclge_get_net_lane_status(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_desc desc; + u32 *status; int ret = 0; + status = (u32 *)data; desc.data[0] = 0; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DISABLE_NET_LANE, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -347,18 +345,34 @@ int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status) *status = desc.data[0]; return 0; } -EXPORT_SYMBOL(hclge_get_net_lane_status); -int hclge_set_mac_state(struct hnae3_handle *handle, bool enable) +void hclge_set_phy_state(struct hnae3_handle *handle, bool enable) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct phy_device *phydev = hdev->hw.mac.phydev; + + if (!phydev) + return; + + if (enable) + phy_start(phydev); + else + phy_stop(phydev); +} + +int hclge_set_mac_state(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_config_mac_mode_cmd *req; struct hclge_dev *hdev = vport->back; struct hclge_desc desc; - struct hclge_config_mac_mode_cmd *req = - (struct hclge_config_mac_mode_cmd *)desc.data; u32 loop_en = 0; - int ret = 0; + bool enable; + int ret; + enable = *(bool *)data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, false); hnae3_set_bit(loop_en, HCLGE_MAC_TX_EN_B, enable); hnae3_set_bit(loop_en, HCLGE_MAC_RX_EN_B, enable); @@ -374,21 +388,23 @@ int hclge_set_mac_state(struct hnae3_handle *handle, bool enable) hnae3_set_bit(loop_en, HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B, enable); hnae3_set_bit(loop_en, HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B, enable); hnae3_set_bit(loop_en, HCLGE_MAC_TX_UNDER_MIN_ERR_B, enable); + req = (struct hclge_config_mac_mode_cmd *)desc.data; req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, - "set mac state %x fail, ret =%d.\n", enable, ret); + "set mac state %x fail, ret = %d.\n", enable, ret); + hclge_set_phy_state(handle, enable); return ret; } -EXPORT_SYMBOL(hclge_set_mac_state); -int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable) +int hclge_config_nic_clock(struct hnae3_handle *handle, int opcode, + void *data, int length) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - u32 nic_clock_en = enable; + u32 nic_clock_en = *(u32 *)data; struct hclge_desc desc; int ret = 0; @@ -402,4 +418,405 @@ int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable) nic_clock_en, ret); return ret; } -EXPORT_SYMBOL(hclge_config_nic_clock); + +int hclge_set_pfc_storm_para(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct hclge_pfc_storm_para *para; + struct hclge_desc desc; + int ret = 0; + + para = (struct hclge_pfc_storm_para *)data; + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA, + false); + desc.data[0] = para->dir; + desc.data[1] = para->enable; + desc.data[2] = para->period_ms; + desc.data[3] = para->times; + desc.data[4] = para->recovery_period_ms; + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, "set pfc storm para failed %d\n", + ret); + return ret; + } + return 0; +} + +int hclge_get_pfc_storm_para(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct hclge_pfc_storm_para *para; + struct hclge_desc desc; + int ret = 0; + + para = (struct hclge_pfc_storm_para *)data; + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA, true); + desc.data[0] = para->dir; + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, "get pfc storm para failed %d\n", + ret); + return ret; + } + para->enable = desc.data[1]; + para->period_ms = desc.data[2]; + para->times = desc.data[3]; + para->recovery_period_ms = desc.data[4]; + return 0; +} + +enum hclge_phy_op_code { + PHY_OP_READ, + PHY_OP_WRITE, + PHY_OP_MAX, +}; + +static int hclge_phy_need_page_select(struct hclge_dev *hdev, + enum hclge_phy_op_code opt_type, + struct hclge_phy_para *para, + u16 *cur_page) +{ + struct hclge_mac *mac = &hdev->hw.mac; + struct mii_bus *mdio_bus = mac->mdio_bus; + u32 phyid = mac->phy_addr; + int ret; + + /* no need to change page when page param is 0 */ + if (opt_type != PHY_OP_READ || para->page != 0) { + ret = mdio_bus->read(mdio_bus, phyid, para->page_select_addr); + if (ret < 0) { + dev_err(&hdev->pdev->dev, + "record current phy %d reg page failed.\n", + phyid); + return ret; + } + *cur_page = ret; + if (para->page != *cur_page) + return 1; + else + return 0; + } + + return 0; +} + +static int hclge_check_phy_opt_pare(struct hclge_dev *hdev, + struct mii_bus *mdio_bus, + struct phy_device *phydev, + enum hclge_phy_op_code opt_type) +{ + if (!phydev) { + dev_err(&hdev->pdev->dev, "this net dev has no phy.\n"); + return -EINVAL; + } + + if (!mdio_bus) { + dev_err(&hdev->pdev->dev, "this net dev has no mdio bus.\n"); + return -EINVAL; + } + + if (opt_type >= PHY_OP_MAX) { + dev_err(&hdev->pdev->dev, "unsupported phy operate type %d.", + opt_type); + return -EINVAL; + } + + return 0; +} + +static int hclge_phy_reg_opt(struct hnae3_handle *handle, void *data, + enum hclge_phy_op_code opt_type) +{ + struct hclge_phy_para *para = (struct hclge_phy_para *)data; + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct hclge_mac *mac = &hdev->hw.mac; + struct mii_bus *mdio_bus = mac->mdio_bus; + u32 phyid = mac->phy_addr; + int need_page_select; + int op_ret, ret; + u16 cur_page; + + ret = hclge_check_phy_opt_pare(hdev, mdio_bus, mac->phydev, opt_type); + if (ret < 0) + return ret; + + /* operate flow: + * 1 record current page address + * 2 jump to operated page + * 3 operate register(read or write) + * 4 come back to the page recorded in the first step. + */ + mutex_lock(&mdio_bus->mdio_lock); + + /* check if page select is needed and record current page address */ + ret = hclge_phy_need_page_select(hdev, opt_type, para, &cur_page); + if (ret < 0) { + mutex_unlock(&mdio_bus->mdio_lock); + return ret; + } + need_page_select = ret; + + /* jump to operated page */ + if (need_page_select) { + ret = mdio_bus->write(mdio_bus, phyid, para->page_select_addr, + para->page); + if (ret < 0) { + mutex_unlock(&mdio_bus->mdio_lock); + dev_err(&hdev->pdev->dev, + "change phy %d page %d to page %d failed.\n", + phyid, cur_page, para->page); + return ret; + } + } + + /* operate register(read or write) */ + if (opt_type == PHY_OP_READ) { + op_ret = mdio_bus->read(mdio_bus, phyid, para->reg_addr); + if (op_ret < 0) { + dev_err(&hdev->pdev->dev, + "read phy %d page %d reg %d failed.\n", + phyid, para->page, para->reg_addr); + } else { + para->data = (u16)op_ret; + op_ret = 0; + } + } else { + op_ret = mdio_bus->write(mdio_bus, phyid, para->reg_addr, + para->data); + if (op_ret < 0) { + dev_err(&hdev->pdev->dev, + "write phy %d page %d reg %d failed.\n", + phyid, para->page, para->reg_addr); + } + } + + /* come back to the page recorded in the first step. */ + if (need_page_select) { + ret = mdio_bus->write(mdio_bus, phyid, para->page_select_addr, + cur_page); + if (ret < 0) { + mutex_unlock(&mdio_bus->mdio_lock); + dev_err(&hdev->pdev->dev, + "restore phy %d reg page %u failed.\n", + phyid, cur_page); + return ret; + } + } + + mutex_unlock(&mdio_bus->mdio_lock); + + return op_ret; +} + +static int hclge_get_phy_reg(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + return hclge_phy_reg_opt(handle, data, PHY_OP_READ); +} + +static int hclge_set_phy_reg(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + return hclge_phy_reg_opt(handle, data, PHY_OP_WRITE); +} + +static int hclge_opt_lookup_mac_tbl(struct hclge_vport *vport, + unsigned char *addr) +{ + u32 high_val; + u32 low_val = addr[4] | (addr[5] << 8); + struct hclge_mac_vlan_tbl_entry_cmd req = {0}; + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc; + u8 resp_code; + u16 retval; + int ret; + + high_val = addr[2] << 16 | (addr[3] << 24) | (addr[0]) | (addr[1] << 8); + hnae3_set_bit(req.flags, HCLGE_MAC_VLAN_BIT0_EN_B, 1); + req.mac_addr_hi32 = cpu_to_le32(high_val); + req.mac_addr_lo16 = cpu_to_le16(low_val & 0xffff); + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ADD, true); + memcpy(desc.data, &req, sizeof(struct hclge_mac_vlan_tbl_entry_cmd)); + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "lookup mac addr failed for cmd_send, ret = %d.\n", + ret); + return ret; + } + + resp_code = (le32_to_cpu(desc.data[0]) >> 8) & 0xff; + retval = le16_to_cpu(desc.retval); + if (retval) { + dev_err(&hdev->pdev->dev, + "cmdq execute failed for %s, retval = %d.\n", + __func__, retval); + return -EIO; + } + + if (!resp_code) { + return 0; + } else if (resp_code == 1) { + dev_dbg(&hdev->pdev->dev, "lookup mac addr failed for miss.\n"); + return -ENOENT; + } + + dev_err(&hdev->pdev->dev, + "lookup mac addr failed for undefined, code = %d.\n", + resp_code); + return -EIO; +} + +static int hclge_opt_mac_table(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + struct hclge_mac_table_para *info = (struct hclge_mac_table_para *)data; + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev; + int ret; + + if (!info || !vport) + return -EIO; + + hdev = vport->back; + switch (info->op_cmd) { + case HCLGE_OPT_TABLE_LOOKUP: + ret = hclge_opt_lookup_mac_tbl(vport, info->mac_addr); + if (ret == -ENOENT) { + return ret; + } else if (ret) { + dev_err(&hdev->pdev->dev, + "ext lookup uc mac address(%pM) fail, ret = %d.\n", + info->mac_addr, ret); + return -EIO; + } + break; + case HCLGE_OPT_TABLE_ADD: + ret = hclge_add_uc_addr_common(vport, info->mac_addr); + if (ret == -ENOSPC) { + return ret; + } else if (ret) { + dev_err(&hdev->pdev->dev, + "ext add uc mac address(%pM) fail, ret = %d.\n", + info->mac_addr, ret); + return -EIO; + } + break; + case HCLGE_OPT_TABLE_DEL: + ret = hclge_rm_uc_addr_common(vport, info->mac_addr); + if (ret == -ENOENT) { + return ret; + } else if (ret) { + dev_warn(&hdev->pdev->dev, + "ext remove uc mac address(%pM) fail, ret = %d.\n", + info->mac_addr, ret); + return -EIO; + } + break; + default: + dev_err(&hdev->pdev->dev, "ext opcode error.\n"); + return -EIO; + } + + return ret; +} + +void hclge_reset_task_schedule_it(struct hclge_dev *hdev) +{ + if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) && + !test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state)) + queue_work_on(cpumask_first(&hdev->affinity_mask), system_wq, + &hdev->rst_service_task); +} + +int hclge_set_reset_task(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + u32 *reset_level = (u32 *)data; + + dev_warn(&hdev->pdev->dev, "reset level is %d\n", *reset_level); + + /* request reset & schedule reset task */ + set_bit(*reset_level, &hdev->reset_request); + hclge_reset_task_schedule_it(hdev); + return 0; +} + +static int hclge_get_hilink_ref_los(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc; + u32 *hilink_ref_los_status; + int ret; + + hilink_ref_los_status = (u32 *)data; + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_GET_HILINK_REF_LOS, + true); + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "get hilink ref los failed, ret = %d\n", ret); + return ret; + } + + *hilink_ref_los_status = desc.data[0]; + return 0; +} + +static struct hclge_ext_func hclge_ext_func_arr[] = { + {HCLGE_EXT_OPC_CLEAN_STATS64, hclge_clean_stats64}, + {HCLGE_EXT_OPC_GET_CHIPID, hclge_get_chipid}, + {HCLGE_EXT_OPC_GET_SFPINFO, hclge_get_sfpinfo}, + {HCLGE_EXT_OPC_SET_SFP_STATE, hclge_set_sfp_state}, + {HCLGE_EXT_OPC_GET_CHIP_NUM, hclge_get_chip_num}, + {HCLGE_EXT_OPC_GET_PORT_NUM, hclge_get_port_num}, + {HCLGE_EXT_OPC_SET_LED, hclge_set_led}, + {HCLGE_EXT_OPC_GET_PRESENT, hclge_get_sfp_present}, + {HCLGE_EXT_OPC_DISABLE_LANE, hclge_disable_net_lane}, + {HCLGE_EXT_OPC_GET_LANE_STATUS, hclge_get_net_lane_status}, + {HCLGE_EXT_OPC_GET_LED_SIGNAL, hclge_get_led_signal}, + {HCLGE_EXT_OPC_SET_MAC_STATE, hclge_set_mac_state}, + {HCLGE_EXT_OPC_CONFIG_CLOCK, hclge_config_nic_clock}, + {HCLGE_EXT_OPC_GET_PFC_STORM_PARA, hclge_get_pfc_storm_para}, + {HCLGE_EXT_OPC_SET_PFC_STORM_PARA, hclge_set_pfc_storm_para}, + {HCLGE_EXT_OPC_GET_PHY_REG, hclge_get_phy_reg}, + {HCLGE_EXT_OPC_SET_PHY_REG, hclge_set_phy_reg}, + {HCLGE_EXT_OPC_GET_MAC_ID, hclge_get_mac_id}, + {HCLGE_EXT_OPC_OPT_MAC_TABLE, hclge_opt_mac_table}, + {HCLGE_EXT_OPC_RESET, hclge_set_reset_task}, + {HCLGE_EXT_OPC_GET_HILINK_REF_LOS, hclge_get_hilink_ref_los}, +}; + +int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode, + void *data, int length) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + int cmd_num = ARRAY_SIZE(hclge_ext_func_arr); + struct hclge_dev *hdev = vport->back; + + if (opcode >= cmd_num) { + dev_err(&hdev->pdev->dev, "not support opcode %d.\n", opcode); + return -EOPNOTSUPP; + } + + if (opcode != hclge_ext_func_arr[opcode].opcode) { + dev_err(&hdev->pdev->dev, "opcode %d is not equals %d.\n", + opcode, hclge_ext_func_arr[opcode].opcode); + return -EINVAL; + } + + return hclge_ext_func_arr[opcode].priv_ops(handle, opcode, data, + length); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.h b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.h index 2049903980fa10183fe78980c89e67ac54c84b9b..8f34c2cff8d9c68cfb4da811b5f8d86558a04500 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_ext.h @@ -4,7 +4,7 @@ #ifndef __HCLGE_EXT_H #define __HCLGE_EXT_H #include -#include "../../hnae3.h" +#include "hnae3.h" #define HCLGE_SFP_INFO_LEN 6 #define HCLGE_SFP_INFO_SIZE 140 @@ -16,64 +16,111 @@ struct hclge_chip_id_cmd { u32 rsv[5]; }; -struct hclge_commit_id_cmd { - u8 commit_id[8]; - u32 ncl_version; - u32 rsv[3]; +struct hclge_sfp_info_para { + u8 *buff; + u16 offset; + u16 size; + u16 *outlen; }; struct hclge_sfp_info { u32 sfpinfo[6]; }; +struct hclge_led_state { + u32 type; + u32 status; +}; + +struct hclge_pfc_storm_para { + u32 dir; + u32 enable; + u32 period_ms; + u32 times; + u32 recovery_period_ms; +}; + +struct hclge_phy_para { + u32 page_select_addr; + u32 reg_addr; + u16 page; + u16 data; +}; + struct hclge_sfp_enable_cmd { - u32 set_sfp_enable_flag; - u32 rsv[5]; + u32 set_sfp_enable_flag; + u32 rsv[5]; }; struct hclge_sfp_present_cmd { - u32 sfp_present; - u32 rsv[5]; + u32 sfp_present; + u32 rsv[5]; }; -struct hns3_lamp_signal { +struct hclge_lamp_signal { u8 error; u8 locate; u8 activity; }; +struct hclge_mac_table_para { + u8 op_cmd; + u8 mac_addr[ETH_ALEN]; +}; + +enum hclge_ext_op_code { + HCLGE_EXT_OPC_CLEAN_STATS64 = 0, + HCLGE_EXT_OPC_GET_CHIPID, + HCLGE_EXT_OPC_GET_SFPINFO, + HCLGE_EXT_OPC_SET_SFP_STATE, + HCLGE_EXT_OPC_GET_CHIP_NUM, + HCLGE_EXT_OPC_GET_PORT_NUM, + HCLGE_EXT_OPC_SET_LED, + HCLGE_EXT_OPC_GET_PRESENT, + HCLGE_EXT_OPC_DISABLE_LANE, + HCLGE_EXT_OPC_GET_LANE_STATUS, + HCLGE_EXT_OPC_GET_LED_SIGNAL, + HCLGE_EXT_OPC_SET_MAC_STATE, + HCLGE_EXT_OPC_CONFIG_CLOCK, + HCLGE_EXT_OPC_GET_PFC_STORM_PARA, + HCLGE_EXT_OPC_SET_PFC_STORM_PARA, + HCLGE_EXT_OPC_GET_PHY_REG, + HCLGE_EXT_OPC_SET_PHY_REG, + HCLGE_EXT_OPC_GET_MAC_ID, + HCLGE_EXT_OPC_OPT_MAC_TABLE, + HCLGE_EXT_OPC_RESET, + HCLGE_EXT_OPC_GET_HILINK_REF_LOS, +}; + +enum hclge_opt_table_code { + HCLGE_OPT_TABLE_LOOKUP, + HCLGE_OPT_TABLE_ADD, + HCLGE_OPT_TABLE_DEL, +}; + +struct hclge_ext_func { + int opcode; + int (*priv_ops)(struct hnae3_handle *handle, int opcode, + void *data, int length); +}; + enum hclge_ext_opcode_type { /* misc command */ - HCLGE_OPC_CHIP_ID_GET = 0x7003, - HCLGE_OPC_IMP_COMMIT_ID_GET = 0x7004, - HCLGE_OPC_GET_CHIP_NUM = 0x7005, - HCLGE_OPC_GET_PORT_NUM = 0x7006, - HCLGE_OPC_SET_LED = 0x7007, - HCLGE_OPC_DISABLE_NET_LANE = 0x7008, - /*SFP command*/ - HCLGE_OPC_SFP_GET_INFO = 0x7100, - HCLGE_OPC_SFP_GET_PRESENT = 0x7101, - HCLGE_OPC_SFP_SET_STATUS = 0x7102, + HCLGE_OPC_CHIP_ID_GET = 0x7003, + HCLGE_OPC_IMP_COMMIT_ID_GET = 0x7004, + HCLGE_OPC_GET_CHIP_NUM = 0x7005, + HCLGE_OPC_GET_PORT_NUM = 0x7006, + HCLGE_OPC_SET_LED = 0x7007, + HCLGE_OPC_DISABLE_NET_LANE = 0x7008, + HCLGE_OPC_CFG_PAUSE_STORM_PARA = 0x7019, + HCLGE_OPC_CFG_GET_HILINK_REF_LOS = 0x701B, + /*SFP command */ + HCLGE_OPC_SFP_GET_INFO = 0x7100, + HCLGE_OPC_SFP_GET_PRESENT = 0x7101, + HCLGE_OPC_SFP_SET_STATUS = 0x7102, }; -void hclge_clean_stats64(struct hnae3_handle *handle); -int hclge_get_chipid(struct hnae3_handle *handle, u32 *chip_id); -int hclge_get_commit_id(struct hnae3_handle *handle, u8 *commit_id, - u32 *ncl_version); -int hclge_get_sfpinfo(struct hnae3_handle *handle, u8 *buff, u16 offset, - u16 size, u16 *outlen); -int hclge_set_sfp_state(struct hnae3_handle *handle, bool en); -int hclge_get_chip_num(struct hnae3_handle *handle, u32 *chip_num); -int hclge_get_port_num(struct hnae3_handle *handle, u32 *port_num); -int hclge_set_led(struct hnae3_handle *handle, u32 type, u32 status); -int hclge_get_sfp_present(struct hnae3_handle *handle, u32 *present); -int hclge_disable_net_lane(struct hnae3_handle *handle); -int hclge_get_net_lane_status(struct hnae3_handle *handle, u32 *status); -int hclge_ext_get_sfp_speed(struct hnae3_handle *handle, u32 *speed); -int hclge_get_led_signal(struct hnae3_handle *handle, - struct hns3_lamp_signal *signal); -int hclge_set_mac_state(struct hnae3_handle *handle, bool enable); -int hclge_config_nic_clock(struct hnae3_handle *handle, bool enable); - +int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode, + void *data, int length); +void hclge_reset_task_schedule_it(struct hclge_dev *hdev); #endif - diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.c b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.c index 46b95ac3cae0c74489f1632d425b90efe34d3b37..77d45c006d8fef0c3c748aa4fdee81f28f28fad9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.c @@ -13,20 +13,17 @@ #include #include #include -#include "../../kcompat.h" -#include "../../hns3pf/hclge_cmd.h" -#include "../../hns3pf/hclge_main.h" -#include "../../hnae3.h" +#include "kcompat.h" +#include "hclge_cmd.h" +#include "hclge_main.h" +#include "hnae3.h" #include "hclge_ext.h" #include "hclge_main_it.h" -#include "../../hns3pf/hclge_err.h" #ifdef CONFIG_HNS3_TEST #include "hclge_test.h" #endif -#ifdef CONFIG_EXT_TEST - #define HCLGE_RESET_MAX_FAIL_CNT 1 static nic_event_fn_t nic_event_call; @@ -53,90 +50,125 @@ int nic_unregister_event(void) EXPORT_SYMBOL(nic_unregister_event); void nic_call_event(struct net_device *netdev, - enum hnae3_reset_type_custom event_t) + enum hnae3_event_type_custom event_t) { - if (nic_event_call) + if (nic_event_call) { nic_event_call(netdev, event_t); - - netdev_info(netdev, "report reset event %d\n", event_t); + netdev_info(netdev, "report event %d\n", event_t); + } } EXPORT_SYMBOL(nic_call_event); -bool hclge_reset_done_it(struct hnae3_handle *handle, bool done) +void hclge_handle_imp_error_it(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct net_device *netdev; + u32 reg_val; netdev = hdev->vport[0].nic.netdev; - if (done) { - dev_info(&hdev->pdev->dev, "Report Reset DONE!\n"); - nic_call_event(netdev, HNAE3_RESET_DONE_CUSTOM); + if (test_and_clear_bit(HCLGE_IMP_RD_POISON, &hdev->imp_err_state)) { + dev_err(&hdev->pdev->dev, "Detected IMP RD poison!\n"); + if (nic_event_call) + nic_call_event(netdev, HNAE3_IMP_RD_POISON_CUSTOM); + reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG) & + ~BIT(HCLGE_VECTOR0_IMP_RD_POISON_B); + hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); } - if (hdev->reset_fail_cnt >= HCLGE_RESET_MAX_FAIL_CNT) { - dev_err(&hdev->pdev->dev, "Report Reset fail!\n"); - nic_call_event(netdev, HNAE3_PORT_FAULT); + if (test_and_clear_bit(HCLGE_IMP_CMDQ_ERROR, &hdev->imp_err_state)) { + dev_err(&hdev->pdev->dev, "Detected CMDQ ECC error!\n"); + if (nic_event_call) + nic_call_event(netdev, HNAE3_IMP_RESET_CUSTOM); + reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG) & + ~BIT(HCLGE_VECTOR0_IMP_CMDQ_ERR_B); + hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); } - return done; } -pci_ers_result_t hclge_handle_hw_ras_error_it(struct hnae3_ae_dev *ae_dev) +void hclge_reset_event_it(struct pci_dev *pdev, struct hnae3_handle *handle) { + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev); struct hclge_dev *hdev = ae_dev->priv; - struct device *dev = &hdev->pdev->dev; - enum hnae3_reset_type_custom reset_type; struct net_device *netdev; - u32 status; netdev = hdev->vport[0].nic.netdev; - status = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG); - - if (status & HCLGE_RAS_REG_NFE_MASK || - status & HCLGE_RAS_REG_ROCEE_ERR_MASK) - ae_dev->hw_err_reset_req = 0; - - /* Handling Non-fatal HNS RAS errors */ - if (status & HCLGE_RAS_REG_NFE_MASK) { - dev_warn(dev, - "HNS Non-Fatal RAS error(status=0x%x) identified\n", - status); - hclge_handle_all_ras_errors(hdev); - - reset_type = ae_dev->ops->set_default_reset_request(ae_dev, - &ae_dev->hw_err_reset_req); + /* 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 (reset_type != HNAE3_NONE_RESET_CUSTOM) - nic_call_event(netdev, reset_type); + if (nic_event_call) { + nic_call_event(netdev, hdev->reset_level); } else { - if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || - hdev->pdev->revision < 0x21) { - ae_dev->override_pci_need_reset = 1; - return PCI_ERS_RESULT_RECOVERED; - } + /* request reset & schedule reset task */ + set_bit(hdev->reset_level, &hdev->reset_request); + hclge_reset_task_schedule_it(hdev); } +} - if (status & HCLGE_RAS_REG_ROCEE_ERR_MASK) { - dev_warn(dev, "ROCEE uncorrected RAS error identified\n"); - hclge_handle_rocee_ras_error(ae_dev); +bool hclge_reset_done_it(struct hnae3_handle *handle, bool done) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + struct net_device *netdev; + + netdev = hdev->vport[0].nic.netdev; + + if (done) { + dev_info(&hdev->pdev->dev, "Report Reset DONE!\n"); + if (nic_event_call) + nic_call_event(netdev, HNAE3_RESET_DONE_CUSTOM); } - if ((status & HCLGE_RAS_REG_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; + if (hdev->reset_fail_cnt >= HCLGE_RESET_MAX_FAIL_CNT) { + dev_err(&hdev->pdev->dev, "Report Reset fail!\n"); + if (nic_event_call) { + if (hdev->reset_type == HNAE3_FUNC_RESET) + nic_call_event(netdev, + HNAE3_FUNC_RESET_FAIL_CUSTOM); + else if (hdev->reset_type == HNAE3_GLOBAL_RESET) + nic_call_event(netdev, + HNAE3_GLOBAL_RESET_FAIL_CUSTOM); + else if (hdev->reset_type == HNAE3_IMP_RESET) + nic_call_event(netdev, + HNAE3_IMP_RESET_FAIL_CUSTOM); + } } - ae_dev->override_pci_need_reset = 1; - return PCI_ERS_RESULT_RECOVERED; + return done; } -#endif - #ifdef CONFIG_IT_VALIDATION #define HCLGE_NAME_IT "hclge" @@ -145,39 +177,21 @@ EXPORT_SYMBOL(hclge_get_vport); EXPORT_SYMBOL(hclge_cmd_set_promisc_mode); EXPORT_SYMBOL(hclge_promisc_param_init); -struct pci_device_id ae_algo_pci_tbl_it[] = { - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_GE), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA_MACSEC), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA_MACSEC), 0}, - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), 0}, - -#ifdef CONFIG_HNS3_X86 - {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_X86_25_GE), 0}, -#endif - - /* required last entry */ - {0, } -}; - int hclge_init_it(void) { pr_info("%s is initializing\n", HCLGE_NAME_IT); #ifdef CONFIG_HNS3_TEST hclge_ops.send_cmdq = hclge_send_cmdq; + hclge_ops.priv_ops = hclge_ext_ops_handle; #endif -#ifdef CONFIG_EXT_TEST - hclge_ops.handle_hw_ras_error = hclge_handle_hw_ras_error_it; + hclge_ops.reset_event = hclge_reset_event_it; hclge_ops.reset_done = hclge_reset_done_it; -#endif - - ae_algo.pdev_id_table = ae_algo_pci_tbl_it; + hclge_ops.handle_imp_error = hclge_handle_imp_error_it; hnae3_register_ae_algo(&ae_algo); return 0; } + module_init(hclge_init_it); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.h b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.h index 48643ce615e2a36ef2999611431ae3d4b56cd5ca..e642ebef9db71f515ca799759ae38a616ba71c7d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_main_it.h @@ -7,7 +7,7 @@ extern struct hnae3_ae_algo ae_algo; extern struct hnae3_ae_ops hclge_ops; -enum hnae3_reset_type_custom { +enum hnae3_event_type_custom { HNAE3_VF_RESET_CUSTOM, HNAE3_VF_FUNC_RESET_CUSTOM, HNAE3_VF_PF_FUNC_RESET_CUSTOM, @@ -20,17 +20,20 @@ enum hnae3_reset_type_custom { HNAE3_NONE_RESET_CUSTOM, HNAE3_PORT_FAULT, HNAE3_RESET_DONE_CUSTOM, + HNAE3_FUNC_RESET_FAIL_CUSTOM, + HNAE3_GLOBAL_RESET_FAIL_CUSTOM, + HNAE3_IMP_RESET_FAIL_CUSTOM, + HNAE3_PPU_POISON_CUSTOM, + HNAE3_IMP_RD_POISON_CUSTOM, }; -#ifdef CONFIG_EXT_TEST - /** * nic_event_fn_t - nic event handler prototype * @netdev: net device - * @hnae3_reset_type_custom: nic device event type + * @hnae3_event_type_custom: nic device event type */ typedef void (*nic_event_fn_t) (struct net_device *netdev, - enum hnae3_reset_type_custom); + enum hnae3_event_type_custom); /** * nic_register_event - register for nic event listening @@ -46,7 +49,5 @@ int nic_register_event(nic_event_fn_t event_call); int nic_unregister_event(void); void nic_call_event(struct net_device *netdev, - enum hnae3_reset_type_custom event_t); -#endif - + enum hnae3_event_type_custom event_t); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_test.h b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_test.h index 2b63a611f3fabb08204b2eb6b5868d36c379dd67..63bb701aa51ef9bc6b740d461ad461a137f805ca 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_test.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns-customer/hns3pf/hclge_test.h @@ -4,8 +4,8 @@ #ifndef __HCLGE_TEST_H #define __HCLGE_TEST_H -#include "../../hns3pf/hclge_cmd.h" -#include "../../hns3pf/hclge_main.h" +#include "hclge_cmd.h" +#include "hclge_main.h" int hclge_send_cmdq(struct hnae3_handle *handle, void *data, int num); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c new file mode 100644 index 0000000000000000000000000000000000000000..e9172f78c6b4e4a5051546afe4bb13577b26e929 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_init.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include + +#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"); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_nictool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_nictool.c new file mode 100644 index 0000000000000000000000000000000000000000..48f32b3829d344adf9e263c1b6485c548c43d184 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_nictool.c @@ -0,0 +1,1092 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include +#include + +#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"); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_nictool.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_nictool.h new file mode 100644 index 0000000000000000000000000000000000000000..699848d6f874278b97a2e7a9d555601db9894dc0 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_nictool.h @@ -0,0 +1,207 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_common_test.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_common_test.c new file mode 100644 index 0000000000000000000000000000000000000000..4dabeb893e8e1cd198a1b62f8e78d3a7e0900748 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_common_test.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_common_test.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_common_test.h new file mode 100644 index 0000000000000000000000000000000000000000..49c7769cb66c09522b40de8862c76d1adf6ecb5e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_common_test.h @@ -0,0 +1,43 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dcb.c new file mode 100644 index 0000000000000000000000000000000000000000..4297e136f4ca38f61f3adbb1f18414ef2f120489 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dcb.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dcb.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dcb.h new file mode 100644 index 0000000000000000000000000000000000000000..743cf39f9a0197f47cc1492c929bf9d166fb1811 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dcb.h @@ -0,0 +1,68 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dfx.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dfx.c new file mode 100644 index 0000000000000000000000000000000000000000..0e28166d6bbed6ac68c4a96c22eea9b9fbdf861a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dfx.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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, ®_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, ®_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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dfx.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dfx.h new file mode 100644 index 0000000000000000000000000000000000000000..f9b211e954320c5219eccf7fe565d6d36fbcc049 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_dfx.h @@ -0,0 +1,37 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_ext.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_ext.c new file mode 100644 index 0000000000000000000000000000000000000000..f3f3fcc5859c7a6c5670557c40632bc526eb7579 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_ext.c @@ -0,0 +1,409 @@ +// 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, + ¶_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, + ×, &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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_ext.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_ext.h new file mode 100644 index 0000000000000000000000000000000000000000..eb04c2991e98cfbe8a63d28ea7c7c0dfa7ee0131 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_ext.h @@ -0,0 +1,60 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_fd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_fd.c new file mode 100644 index 0000000000000000000000000000000000000000..997a33c919ce5ce3ee3f3c58e748aaa7ccd52ace --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_fd.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_fd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_fd.h new file mode 100644 index 0000000000000000000000000000000000000000..7d80c906472a5a3053a7377906ebf878831196ab --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_fd.h @@ -0,0 +1,37 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_hilink_param.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_hilink_param.c new file mode 100644 index 0000000000000000000000000000000000000000..77d3ac50278f86af936a5b1e35c8d47bb0a00db8 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_hilink_param.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_hilink_param.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_hilink_param.h new file mode 100644 index 0000000000000000000000000000000000000000..e4d7a157e0510084446b01a2d281fb4296177e4a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_hilink_param.h @@ -0,0 +1,52 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_irq.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_irq.c new file mode 100644 index 0000000000000000000000000000000000000000..e4a04f2e3e2446a017db06718aa5e256d122721e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_irq.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_irq.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_irq.h new file mode 100644 index 0000000000000000000000000000000000000000..915d161bf3455bdc1adb7df4c451840e6ebedd17 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_irq.h @@ -0,0 +1,9 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_lamp.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_lamp.c new file mode 100644 index 0000000000000000000000000000000000000000..beee85f001b9c21fa00fa4f929214fc94f114bfb --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_lamp.c @@ -0,0 +1,30 @@ +// 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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_lamp.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_lamp.h new file mode 100644 index 0000000000000000000000000000000000000000..091ae86ad92556bbb8ef8af7131bb72f14b0100a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_lamp.h @@ -0,0 +1,36 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_m7_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_m7_cmd.c new file mode 100644 index 0000000000000000000000000000000000000000..ee7929ac27f02c890cae82821cf9dcad24c396b8 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_m7_cmd.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_m7_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_m7_cmd.h new file mode 100644 index 0000000000000000000000000000000000000000..5c21905f822a7ebd2de91c8e9a5ac3b55e403fbb --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_m7_cmd.h @@ -0,0 +1,19 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mac.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mac.c new file mode 100644 index 0000000000000000000000000000000000000000..22d6ecb7793e07f2d1f625f10bb628321476cac8 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mac.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mac.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mac.h new file mode 100644 index 0000000000000000000000000000000000000000..cbead1fb59aee642b9e48678609d91b5f2cb2cf1 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mac.h @@ -0,0 +1,38 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mactbl.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mactbl.c new file mode 100644 index 0000000000000000000000000000000000000000..34df4b281b2f4c2a54a99ad79ee98f96422a8217 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mactbl.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mactbl.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mactbl.h new file mode 100644 index 0000000000000000000000000000000000000000..88e5c6a6eae5ad9bcc9efa1e6a86bfc816c645eb --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_mactbl.h @@ -0,0 +1,30 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_phy.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_phy.c new file mode 100644 index 0000000000000000000000000000000000000000..d37791b1f9fdc646f4b0241bdc60bd564691290d --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_phy.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_phy.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_phy.h new file mode 100644 index 0000000000000000000000000000000000000000..c0ec2f8c0bdf7bcd8a5bc3b78e6e4d3868f2deb3 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_phy.h @@ -0,0 +1,19 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_pkt.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_pkt.c new file mode 100644 index 0000000000000000000000000000000000000000..38cd978e3483eb2caa332e2732bf055f1ae53d70 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_pkt.c @@ -0,0 +1,731 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_pkt.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_pkt.h new file mode 100644 index 0000000000000000000000000000000000000000..75aabb68eac3e1d0d3c1e5626f8d741606011afc --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_pkt.h @@ -0,0 +1,59 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_port.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_port.c new file mode 100644 index 0000000000000000000000000000000000000000..380ea418af8f05d4df3582f4049bce7004d49b9a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_port.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_port.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_port.h new file mode 100644 index 0000000000000000000000000000000000000000..a6eb84cb1938f80fa71235fe91478cc2a65fcd4a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_port.h @@ -0,0 +1,94 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_promisc.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_promisc.c new file mode 100644 index 0000000000000000000000000000000000000000..4bfb7110ce5a75389149a9e349528de5284669ee --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_promisc.c @@ -0,0 +1,121 @@ +// 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(¶m, en_uc, en_mc, en_bc, vport->vport_id); + + return hclge_cmd_set_promisc_mode(hdev, ¶m); +} + +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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_promisc.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_promisc.h new file mode 100644 index 0000000000000000000000000000000000000000..011740b0f8f370b968cf18b0090393a41a3cc790 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_promisc.h @@ -0,0 +1,28 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qinfo.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qinfo.c new file mode 100644 index 0000000000000000000000000000000000000000..9f70bc1b3aaa952bd1fd4111b327edd105f9c09b --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qinfo.c @@ -0,0 +1,144 @@ +// 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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qinfo.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qinfo.h new file mode 100644 index 0000000000000000000000000000000000000000..17cb508419ecb8bdee31b1b9c4ef118fb00d45c7 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qinfo.h @@ -0,0 +1,40 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qos.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qos.c new file mode 100644 index 0000000000000000000000000000000000000000..b434f93edd173aadfc8c86d550f15020c5c62330 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qos.c @@ -0,0 +1,398 @@ +// 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); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qos.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qos.h new file mode 100644 index 0000000000000000000000000000000000000000..610c19849dfc170c596a7355bcdb6da4f9ffe3ba --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qos.h @@ -0,0 +1,70 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qres.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qres.c new file mode 100644 index 0000000000000000000000000000000000000000..677f46b906e05186c9fde9dfe37940d01493dd2b --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qres.c @@ -0,0 +1,175 @@ +// 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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qres.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qres.h new file mode 100644 index 0000000000000000000000000000000000000000..d6cdb5e366f46adcca786afa8779b2d81aa32ad9 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_qres.h @@ -0,0 +1,71 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_rss.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_rss.c new file mode 100644 index 0000000000000000000000000000000000000000..f8d2e3e70dbe0bf1d8c5733b9e1de19214cb244d --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_rss.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#ifdef CONFIG_HNS3_TEST +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_rss.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_rss.h new file mode 100644 index 0000000000000000000000000000000000000000..c5ec57577185c633bf1727d2607fb087917f2eb8 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_rss.h @@ -0,0 +1,20 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_stat.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_stat.c new file mode 100644 index 0000000000000000000000000000000000000000..19437566cc669bcc824ae9b7857d8e74a78798cc --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_stat.c @@ -0,0 +1,218 @@ +// 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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_stat.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_stat.h new file mode 100644 index 0000000000000000000000000000000000000000..e6183e993a5eb40b0277f04b4cea10ff29315513 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_stat.h @@ -0,0 +1,47 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_tm.c new file mode 100644 index 0000000000000000000000000000000000000000..f4d18eebc827355f7352db7e72f640a63011682a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_tm.c @@ -0,0 +1,972 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_tm.h new file mode 100644 index 0000000000000000000000000000000000000000..1ea8c8e7e9004d031e9fd8b8be11fcb0eddd8d52 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_tm.h @@ -0,0 +1,114 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_vlan.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_vlan.c new file mode 100644 index 0000000000000000000000000000000000000000..6d8b574d68cc533947bb1787a232112b4825baef --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_vlan.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_vlan.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_vlan.h new file mode 100644 index 0000000000000000000000000000000000000000..3786fe855e8030074e110c6fad52237e08e0f86a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_vlan.h @@ -0,0 +1,41 @@ +/* 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_xsfp.c b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_xsfp.c new file mode 100644 index 0000000000000000000000000000000000000000..15884cd5a5f2c48570205ae1e4e81673cce52c73 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_xsfp.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include + +#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; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_xsfp.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_xsfp.h new file mode 100644 index 0000000000000000000000000000000000000000..2d85d990dea92d0908d304ec2f531f7f2b2678bc --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_priv_xsfp.h @@ -0,0 +1,51 @@ +/* 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