From eb44201ee79cffdcf1b16759a54940dca047aae5 Mon Sep 17 00:00:00 2001 From: Junxin Chen Date: Tue, 31 May 2022 17:16:46 +0800 Subject: [PATCH 01/15] ubl: add CONFIG_UBL definition and UBL interface kernel inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ----------------------------------------------------------- This patch adds UB link interfaces to support it. UB is a new interconnection protocol that defines its own Layer 2 protocol. The format of a complete UB packet is as follows. UBL HDR includes UB LINK, CC and NPI. UB LINK replaces Ether header in packets. The UB Network header consists of CC, NPI, and traditional Network packet headers. |<-------- UBL HDR --------->| +--------------+------+------+---------+-----------+---------+ | UB LINK | CC | NPI | Network | TPH / TAH | Payload | +--------------+------+------+---------+-----------+---------+ |<----- UB Network ---->| - UB LINK: Format specified by the data link layer of the UB LINK. - CC: Congestion Control. - NPI: Network Partition Identifier. - Network: Traditinal L3 Header. At network layer, the UB Network Header is encapsulated. However, the packet type cannot be known by parsing packet from user, which leads to restrictions on the use of socket. This patch adds sw_ctype field to indicate the packet type. As shown in the following figure, the sw_ctype field will be add at the header of packet before entering the dirver. +----------+----+-----+---------+-----------+---------+ | sw_ctype | CC | NPI | Network | TPH / TAH | Payload | +----------+----+-----+---------+-----------+---------+ -sw_ctype: L3 Header type. When packets are sent to hardware, the sw_ctype field will be deleted and the original packet will be restored. +----+-----+---------+-----------+---------+ | CC | NPI | Network | TPH / TAH | Payload | +----+-----+---------+-----------+---------+ Signed-off-by: Junxin Chen Signed-off-by: Haiqing Fang --- arch/arm64/configs/openeuler_defconfig | 1 + drivers/net/Kconfig | 2 + drivers/net/Makefile | 1 + drivers/net/ub/Kconfig | 11 ++ drivers/net/ub/Makefile | 7 + drivers/net/ub/dev/Makefile | 7 + drivers/net/ub/dev/ubl.c | 169 +++++++++++++++++++++++++ drivers/net/ub/dev/ubl.h | 104 +++++++++++++++ include/uapi/linux/if_arp.h | 2 + include/uapi/linux/if_ether.h | 1 + 10 files changed, 305 insertions(+) create mode 100644 drivers/net/ub/Kconfig create mode 100644 drivers/net/ub/Makefile create mode 100644 drivers/net/ub/dev/Makefile create mode 100644 drivers/net/ub/dev/ubl.c create mode 100644 drivers/net/ub/dev/ubl.h diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index f055d8e93bc4..fab8a915eae0 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -2903,6 +2903,7 @@ CONFIG_NET_VENDOR_NEBULA_MATRIX=y CONFIG_M1600=m # CONFIG_FDDI is not set # CONFIG_HIPPI is not set +CONFIG_UBL=y # CONFIG_NET_SB1000 is not set CONFIG_PHYLIB=y CONFIG_SWPHY=y diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f20808024305..f3ac803d05c0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -444,6 +444,8 @@ source "drivers/net/fddi/Kconfig" source "drivers/net/hippi/Kconfig" +source "drivers/net/ub/Kconfig" + source "drivers/net/ipa/Kconfig" config NET_SB1000 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 72e18d505d1a..8aca829a3e87 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_WLAN) += wireless/ obj-$(CONFIG_WIMAX) += wimax/ obj-$(CONFIG_IEEE802154) += ieee802154/ +obj-$(CONFIG_UBL) += ub/ obj-$(CONFIG_VMXNET3) += vmxnet3/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o diff --git a/drivers/net/ub/Kconfig b/drivers/net/ub/Kconfig new file mode 100644 index 000000000000..d49376ec21ee --- /dev/null +++ b/drivers/net/ub/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# UBL configuration +# + +config UBL + default n + tristate "UB link support" + help + This enables UB link support. Say 'Y' or 'm' if your + device works in UB. diff --git a/drivers/net/ub/Makefile b/drivers/net/ub/Makefile new file mode 100644 index 000000000000..e9013cb9790f --- /dev/null +++ b/drivers/net/ub/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Makefile for the HISILICON network device drivers. +# + +#### compile ubl +obj-$(CONFIG_UBL) += dev/ diff --git a/drivers/net/ub/dev/Makefile b/drivers/net/ub/dev/Makefile new file mode 100644 index 000000000000..e93bfcca64ba --- /dev/null +++ b/drivers/net/ub/dev/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Makefile for the HISILICON network device drivers. +# + +#### compile ubl +obj-$(CONFIG_UBL) += ubl.o diff --git a/drivers/net/ub/dev/ubl.c b/drivers/net/ub/dev/ubl.c new file mode 100644 index 000000000000..f8d4bb86ff25 --- /dev/null +++ b/drivers/net/ub/dev/ubl.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * UBL An implementation of the UB protocol suite for the LINUX + * operating system. + * + * UB link device handling. + * + * Version: @(#)ubl.c 1.0.1 23/02/14 + * + */ + +#include +#include + +#include "ubl.h" + +static __be16 ubl_type_to_proto(u8 type) +{ + __be16 proto; + + switch (type) { + case UB_IPV4_CFG_TYPE: + proto = htons(ETH_P_IP); + break; + case UB_IPV6_CFG_TYPE: + proto = htons(ETH_P_IPV6); + break; + case UB_NOIP_CFG_TYPE: + default: + proto = htons(ETH_P_UB); + break; + } + + return proto; +} + +/** + * ubl_create_header - create the ubl header + * @skb: buffer to alter + * @dev: source device + * @type: ubl type field + * @daddr: not used in ubl + * @saddr: not used in ubl + * @len: packet length (<= skb->len) + * + */ +int ubl_create_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned int len) +{ + u8 ctype = UB_NOIP_CFG_TYPE; + int ret = -UBL_HLEN; + struct ublhdr *ubl; + + if (type == ETH_P_IP || type == ETH_P_IPV6) { + ubl = (struct ublhdr *)skb_push(skb, UBL_HLEN); + memset(ubl, 0, sizeof(struct ublhdr)); + ubl->h_npi = htonl(UB_DEFAULT_NPI); + ctype = (type == ETH_P_IP) ? UB_IPV4_CFG_TYPE : UB_IPV6_CFG_TYPE; + ret = UBL_HLEN; + } else if (type == ETH_P_UB) { + /* if type is ETH_P_UB, then do nothing. */ + ret = 0; + } + ubl_add_sw_ctype(skb, ctype); + + return ret; +} +EXPORT_SYMBOL(ubl_create_header); + +/** + * ubl_header_parse_protocol - parse packets protocol before send it to driver. + * @skb: buffer to alter + * + * parse packets based on packet data if skb->protocol is ETH_P_ALL or 0. + */ +static __be16 ubl_header_parse_protocol(const struct sk_buff *skb) +{ + return ubl_type_to_proto(skb->data[0]); +} + +const static struct header_ops ubl_header_ops ____cacheline_aligned = { + .create = ubl_create_header, + .parse_protocol = ubl_header_parse_protocol, +}; + +/** + * ubl_setup - setup ub link network device + * @dev: network device + * + * Fill in the fields of the device structure with ubl-generic values. + */ +void ubl_setup(struct net_device *dev) +{ + dev->header_ops = &ubl_header_ops; + dev->type = ARPHRD_UB; + dev->hard_header_len = UBL_HLEN; + dev->min_header_len = UBL_HLEN; + dev->mtu = UB_DATA_LEN; + dev->min_mtu = UB_MIN_MTU; + dev->max_mtu = UB_DATA_LEN; + dev->addr_len = UBL_ALEN; + dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; + dev->flags = (IFF_NOARP | IFF_POINTOPOINT); + dev->priv_flags |= IFF_TX_SKB_SHARING; +} +EXPORT_SYMBOL(ubl_setup); + +/** + * alloc_ubndev_mqs - Allocates and sets up an ub-n device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ubn device + * @txqs: The number of TX queues this device has. + * @rxqs: The number of RX queues this device has. + * + * Fill in the fields of the device structure with ubn-generic + * values. Basically does everything except registering the device. + * + * Constructs a new net device, complete with a private data area of + * size (sizeof_priv). A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_ubndev_mqs(int sizeof_priv, unsigned int txqs, + unsigned int rxqs) +{ + return alloc_netdev_mqs(sizeof_priv, "ubn%d", NET_NAME_UNKNOWN, + ubl_setup, txqs, rxqs); +} +EXPORT_SYMBOL(alloc_ubndev_mqs); + +/** + * ubl_type_trans - obtains skb->protocol and adds sw_ptype to the packet + * @skb: buffer to alter + * @dev: source device + * @type: packet type + * + * Obtains the packet type and translates it to skb->protocol and adds sw_ptype + * to the packet data. + */ +__be16 ubl_type_trans(struct sk_buff *skb, struct net_device *dev, u8 type) +{ + skb->dev = dev; + ubl_add_sw_ctype(skb, type); + skb_reset_mac_header(skb); + if (type == UB_IPV4_CFG_TYPE || type == UB_IPV6_CFG_TYPE) + skb_pull_inline(skb, UBL_HLEN + 1); + else if (type != UB_NOIP_CFG_TYPE) + net_warn_ratelimited("An unknown packet is received by %s, type is %u\n", + dev->name, type); + + return ubl_type_to_proto(type); +} +EXPORT_SYMBOL(ubl_type_trans); + +MODULE_AUTHOR("Huawei Tech. Co., Ltd."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("UB link level"); +MODULE_VERSION(UBL_MOD_VERSION); diff --git a/drivers/net/ub/dev/ubl.h b/drivers/net/ub/dev/ubl.h new file mode 100644 index 000000000000..02424918b01f --- /dev/null +++ b/drivers/net/ub/dev/ubl.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __LINUX_UBL_H +#define __LINUX_UBL_H + +#include +#include +#include +#include + +#define UBL_MOD_VERSION "1.0.0" + +#define UBL_HARD_HLEN 4 +#define UBL_HLEN 6 +#define UBL_ALEN 16 + +#define UBL_LCRC_LEN 2 +#define UBL_BCRC_LEN 4 +#define UBL_LINK_LEN 2 + +#define UB_DEFAULT_NPI 1 + +#define UB_MAX_BLOCK_NUM 16 +#define UB_FLIT_NUM_OF_BLOCK 32 +#define UB_BYTE_OF_FLIT 20 +#define UB_BYTE_OF_BLK (UB_BYTE_OF_FLIT * UB_FLIT_NUM_OF_BLOCK) + +#define UB_BLOCK_CRC_LEN (UBL_BCRC_LEN + UBL_LCRC_LEN) +#define UB_MAX_MTU_PER_BLK (UB_BYTE_OF_BLK - UBL_LINK_LEN - UB_BLOCK_CRC_LEN) +#define UB_DATA_LEN 1500 +#define UB_MAX_MTU ((UB_MAX_BLOCK_NUM * UB_MAX_MTU_PER_BLK) - \ + UBL_HLEN - UBL_HARD_HLEN + UBL_LINK_LEN) +#define UB_MIN_MTU 68 + +#define UB_IPV4_CFG_TYPE 3 +#define UB_IPV6_CFG_TYPE 4 +#define UB_NOIP_CFG_TYPE 5 +#define UB_UNKNOWN_CFG_TYPE 255 + +/** + * struct ublhdr - ub link header + * @h_cc: cc + * @h_npi: npi + */ +struct ublhdr { + __be16 h_cc; + __be32 h_npi; +} __packed; + +/** + * ubl_add_sw_ctype - add software packet type for skb->data + * @skb: buffer to alter + * @ctype: indicates the packet type + * + * The packet type cannot be known by parsing packe from user, + * which leads to restrictions on the use of socket. + * Add cs_type field to indicate the packet type. And sw_ctype + * exists only during software prcessing. + * +----------+----+-----+-----------+ + * | sw_ctype | CC | NPI | L3 Packet | + * +----------+----+-----+-----------+ + */ +static inline void ubl_add_sw_ctype(struct sk_buff *skb, u8 ctype) +{ + u8 *pkt_cfg = (u8 *)skb_push(skb, sizeof(u8)); + + *pkt_cfg = ctype; +} + +/** + * ubl_rmv_sw_ctype - delete software packet type for skb->data + * @skb: buffer to alter + * + * Before the packet is sent to the hardware, remove sw_ctype field + * and restore the original packet. + */ +static inline void ubl_rmv_sw_ctype(struct sk_buff *skb) +{ + skb_pull_inline(skb, sizeof(u8)); +} + +int ubl_create_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned int len); +void ubl_setup(struct net_device *dev); +__be16 ubl_type_trans(struct sk_buff *skb, struct net_device *dev, u8 type); +struct net_device *alloc_ubndev_mqs(int sizeof_priv, unsigned int txqs, + unsigned int rxqs); +#define alloc_ubndev_mq(sizeof_priv, count) \ + alloc_ubndev_mqs((sizeof_priv), (count), (count)) + +#endif diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h index c3cc5a9e5eaf..0ca98140376b 100644 --- a/include/uapi/linux/if_arp.h +++ b/include/uapi/linux/if_arp.h @@ -43,6 +43,8 @@ #define ARPHRD_EUI64 27 /* EUI-64 */ #define ARPHRD_INFINIBAND 32 /* InfiniBand */ +#define ARPHRD_UB 38 /* Unified bus */ + /* Dummy types for non ARP hardware */ #define ARPHRD_SLIP 256 #define ARPHRD_CSLIP 257 diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index d6de2b167448..7309563a2e47 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -150,6 +150,7 @@ #define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and * aggregation protocol */ +#define ETH_P_UB 0x0100 /* Network control packet of Unified Bus */ /* * This is an Ethernet frame header. -- Gitee From 631518bfeb74541b1165ab6efa43af69f9bedece Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Wed, 8 Feb 2023 11:24:56 +0800 Subject: [PATCH 02/15] UNIC: Support identify UBL device through device id driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ---------------------------------------------------------- The hns3 driver add the ability that support identifying device which is over UB Link through the new device id including physical device and virtual device. Signed-off-by: Fengyan Mu Signed-off-by: Junxin Chen --- arch/arm64/configs/openeuler_defconfig | 1 + drivers/net/ethernet/hisilicon/Kconfig | 10 ++++++++ drivers/net/ethernet/hisilicon/hns3/hnae3.h | 23 +++++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 18 +++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_enet.h | 3 +++ .../hisilicon/hns3/hns3pf/hclge_main.c | 4 ++++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 6 +++++ 7 files changed, 65 insertions(+) diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index fab8a915eae0..cd75e62e7537 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -2757,6 +2757,7 @@ CONFIG_HNS3_HCLGE=m CONFIG_HNS3_DCB=y CONFIG_HNS3_HCLGEVF=m CONFIG_HNS3_ENET=m +CONFIG_HNS3_UBL=y CONFIG_NET_VENDOR_HUAWEI=y CONFIG_HINIC=m CONFIG_HINIC3=m diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 2ba0e7bd3466..df684d97bc0c 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -139,6 +139,16 @@ config HNS3_ENET family of SoCs. This module depends upon HNAE3 driver to access the HNAE3 devices and their associated operations. +config HNS3_UBL + bool "Hisilicon HNS3 UB Link Device Support" + default n + depends on UBL + help + This selects the HNS UBL support which depends upon configuration UBL. + It is needed by Hisilicon Network Subsystem 3 to use the UB Link and + its associated operations. + Say N if using non-UB device and network. + endif #HNS3 endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 95c855bac7a0..62f588089911 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -58,6 +58,10 @@ #define HNAE3_DEV_ID_400G_ROH 0xA22D #define HNAE3_DEV_ID_VF 0xA22E #define HNAE3_DEV_ID_RDMA_DCB_PFC_VF 0xA22F +#define HNAE3_DEV_ID_UDMA_OVER_UBL 0xA260 +#define HNAE3_DEV_ID_RDMA_OVER_UBL 0xA262 +#define HNAE3_DEV_ID_UDMA_OVER_UBL_VF 0xA268 +#define HNAE3_DEV_ID_RDMA_OVER_UBL_VF 0xA26A #define HNAE3_CLASS_NAME_SIZE 16 @@ -68,10 +72,29 @@ #define HNAE3_UNIC_CLIENT_INITED_B 0x4 #define HNAE3_ROCE_CLIENT_INITED_B 0x5 #define HNAE3_ROH_CLIENT_INITED_B 0x6 +#define HNAE3_DEV_SUPPORT_UDMA_B 0x8 +#define HNAE3_DEV_SUPPORT_UBL_B 0x9 #define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) | \ BIT(HNAE3_DEV_SUPPORT_ROCE_B)) +#define HNAE3_DEV_SUPPORT_UDMA_OVER_UBL_DCB_BITS \ + (BIT(HNAE3_DEV_SUPPORT_DCB_B) | BIT(HNAE3_DEV_SUPPORT_UDMA_B) | \ + BIT(HNAE3_DEV_SUPPORT_UBL_B)) + +#define HNAE3_DEV_SUPPORT_ROCE_OVER_UBL_DCB_BITS \ + (BIT(HNAE3_DEV_SUPPORT_DCB_B) | BIT(HNAE3_DEV_SUPPORT_ROCE_B) | \ + BIT(HNAE3_DEV_SUPPORT_UBL_B)) + +#define HNAE3_DEV_SUPPORT_UDMA_DCB_BITS \ + (BIT(HNAE3_DEV_SUPPORT_DCB_B) | BIT(HNAE3_DEV_SUPPORT_UDMA_B)) + +#define hnae3_dev_udma_supported(ae_dev) \ + hnae3_get_bit((ae_dev)->flag, HNAE3_DEV_SUPPORT_UDMA_B) + +#define hnae3_dev_ubl_supported(ae_dev) \ + hnae3_get_bit((ae_dev)->flag, HNAE3_DEV_SUPPORT_UBL_B) + #define hnae3_dev_roh_supported(hdev) \ hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_ROH_CLIENT_INITED_B) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 4c7896f2c780..6d91702da6a7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -106,6 +106,16 @@ static const struct pci_device_id hns3_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_VF), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_DCB_PFC_VF), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, +#ifdef CONFIG_HNS3_UBL + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_OVER_UBL), + HNAE3_DEV_SUPPORT_UDMA_OVER_UBL_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_OVER_UBL), + HNAE3_DEV_SUPPORT_ROCE_OVER_UBL_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_OVER_UBL_VF), + HNAE3_DEV_SUPPORT_UDMA_OVER_UBL_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_OVER_UBL_VF), + HNAE3_DEV_SUPPORT_ROCE_OVER_UBL_DCB_BITS}, +#endif /* required last entry */ {0,} }; @@ -3296,9 +3306,17 @@ bool hns3_is_phys_func(struct pci_dev *pdev) case HNAE3_DEV_ID_200G_RDMA: case HNAE3_DEV_ID_200G_ROH: case HNAE3_DEV_ID_400G_ROH: +#ifdef CONFIG_HNS3_UBL + case HNAE3_DEV_ID_UDMA_OVER_UBL: + case HNAE3_DEV_ID_RDMA_OVER_UBL: +#endif return true; case HNAE3_DEV_ID_VF: case HNAE3_DEV_ID_RDMA_DCB_PFC_VF: +#ifdef CONFIG_HNS3_UBL + case HNAE3_DEV_ID_UDMA_OVER_UBL_VF: + case HNAE3_DEV_ID_RDMA_OVER_UBL_VF: +#endif return false; default: dev_warn(&pdev->dev, "un-recognized pci device-id %u", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 861979579c36..3cbf68cd7004 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -746,6 +746,9 @@ static inline unsigned int hns3_page_order(struct hns3_enet_ring *ring) return 0; } +#define hns3_ubl_supported(handle) \ + hnae3_dev_ubl_supported((struct hnae3_ae_dev *)pci_get_drvdata((handle)->pdev)) + #define hns3_page_size(_ring) (PAGE_SIZE << hns3_page_order(_ring)) /* iterator for handling rings in ring group */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 373af8118dd3..332024e319f4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -79,6 +79,10 @@ static const struct pci_device_id ae_algo_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_RDMA), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_ROH), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), 0}, +#ifdef CONFIG_HNS3_UBL + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_OVER_UBL), 0}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_OVER_UBL), 0}, +#endif /* required last entry */ {0, } }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 970354cebea4..9695c720177e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -28,6 +28,12 @@ static const struct pci_device_id ae_algovf_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_VF), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_DCB_PFC_VF), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, +#ifdef CONFIG_HNS3_UBL + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_OVER_UBL_VF), + HNAE3_DEV_SUPPORT_UDMA_OVER_UBL_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_OVER_UBL_VF), + HNAE3_DEV_SUPPORT_ROCE_OVER_UBL_DCB_BITS}, +#endif /* required last entry */ {0, } }; -- Gitee From b9e23b82d3bc6595b50b9a450a47a199fb9c1915 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Wed, 11 Oct 2023 11:36:44 +0800 Subject: [PATCH 03/15] UNIC: Support identify UBoE device through device id driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ---------------------------------------------------------- The hns3 driver add the ability that support identifying device which is UB device over ethernet through the new device id including physical device and virtual device. Signed-off-by: Fengyan Mu Signed-off-by: Junxin Chen --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 ++ drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 6 ++++++ drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 1 + drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 2 ++ 4 files changed, 11 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 62f588089911..9115b48efc1a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -59,8 +59,10 @@ #define HNAE3_DEV_ID_VF 0xA22E #define HNAE3_DEV_ID_RDMA_DCB_PFC_VF 0xA22F #define HNAE3_DEV_ID_UDMA_OVER_UBL 0xA260 +#define HNAE3_DEV_ID_UDMA 0xA261 #define HNAE3_DEV_ID_RDMA_OVER_UBL 0xA262 #define HNAE3_DEV_ID_UDMA_OVER_UBL_VF 0xA268 +#define HNAE3_DEV_ID_UDMA_VF 0xA269 #define HNAE3_DEV_ID_RDMA_OVER_UBL_VF 0xA26A #define HNAE3_CLASS_NAME_SIZE 16 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 6d91702da6a7..2b4ee25f891b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -103,9 +103,13 @@ static const struct pci_device_id hns3_pci_tbl[] = { HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA), + HNAE3_DEV_SUPPORT_UDMA_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_VF), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_DCB_PFC_VF), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_VF), + HNAE3_DEV_SUPPORT_UDMA_DCB_BITS}, #ifdef CONFIG_HNS3_UBL {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_OVER_UBL), HNAE3_DEV_SUPPORT_UDMA_OVER_UBL_DCB_BITS}, @@ -3310,6 +3314,7 @@ bool hns3_is_phys_func(struct pci_dev *pdev) case HNAE3_DEV_ID_UDMA_OVER_UBL: case HNAE3_DEV_ID_RDMA_OVER_UBL: #endif + case HNAE3_DEV_ID_UDMA: return true; case HNAE3_DEV_ID_VF: case HNAE3_DEV_ID_RDMA_DCB_PFC_VF: @@ -3317,6 +3322,7 @@ bool hns3_is_phys_func(struct pci_dev *pdev) case HNAE3_DEV_ID_UDMA_OVER_UBL_VF: case HNAE3_DEV_ID_RDMA_OVER_UBL_VF: #endif + case HNAE3_DEV_ID_UDMA_VF: return false; default: dev_warn(&pdev->dev, "un-recognized pci device-id %u", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 332024e319f4..ee11da881f5d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -79,6 +79,7 @@ static const struct pci_device_id ae_algo_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_RDMA), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_ROH), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), 0}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA), 0}, #ifdef CONFIG_HNS3_UBL {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_OVER_UBL), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_OVER_UBL), 0}, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 9695c720177e..de59c9150398 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -28,6 +28,8 @@ static const struct pci_device_id ae_algovf_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_VF), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_RDMA_DCB_PFC_VF), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_VF), + HNAE3_DEV_SUPPORT_UDMA_DCB_BITS}, #ifdef CONFIG_HNS3_UBL {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_UDMA_OVER_UBL_VF), HNAE3_DEV_SUPPORT_UDMA_OVER_UBL_DCB_BITS}, -- Gitee From 737ec46e963210dc3b856637e871fa5b0c91316e Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Tue, 18 Apr 2023 11:49:25 +0800 Subject: [PATCH 04/15] UNIC: Adds the process of UNIC driver initializing driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ---------------------------------------------------------- Add UB mode to NIC driver, and when the driver runs in UB mode, change the features that UB supports in initializing state. This patch creates new files to host the function interfaces of the UB. Signed-off-by: Fengyan Mu Signed-off-by: Junxin Chen --- drivers/net/ethernet/hisilicon/hns3/Makefile | 2 + .../net/ethernet/hisilicon/hns3/hns3_dcbnl.c | 16 +++++++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 36 +++++++++++++++ .../ethernet/hisilicon/hns3/hns3_ethtool.c | 46 +++++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_unic.c | 34 ++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_unic.h | 23 ++++++++++ 6 files changed, 157 insertions(+) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_unic.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_unic.h diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index 53e1aa50ae8e..91d61b5ab72a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -4,6 +4,7 @@ # ccflags-y += -I$(srctree)/$(src) +ccflags-y += -I$(srctree)/drivers/net/ub/dev ccflags-y += -I$(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3pf ccflags-y += -I$(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3vf ccflags-y += -I$(srctree)/drivers/net/ethernet/hisilicon/hns3/hns3_common @@ -15,6 +16,7 @@ hns3-objs = hns3_enet.o hns3_ethtool.o hns3_debugfs.o hns3-objs += hns3_ext.o hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o +hns3-$(CONFIG_HNS3_UBL) += hns3_unic.o obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c index 3b6dbf158b98..784996583746 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_dcbnl.c @@ -115,6 +115,15 @@ static const struct dcbnl_rtnl_ops hns3_dcbnl_ops = { .setdcbx = hns3_dcbnl_setdcbx, }; +static const struct dcbnl_rtnl_ops hns3_unic_dcbnl_ops = { + .ieee_getets = hns3_dcbnl_ieee_getets, + .ieee_setets = hns3_dcbnl_ieee_setets, + .ieee_setapp = hns3_dcbnl_ieee_setapp, + .ieee_delapp = hns3_dcbnl_ieee_delapp, + .getdcbx = hns3_dcbnl_getdcbx, + .setdcbx = hns3_dcbnl_setdcbx, +}; + /* hclge_dcbnl_setup - DCBNL setup * @handle: the corresponding vport handle * Set up DCBNL @@ -126,5 +135,12 @@ void hns3_dcbnl_setup(struct hnae3_handle *handle) if ((!handle->kinfo.dcb_ops) || (handle->flags & HNAE3_SUPPORT_VF)) return; +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(handle)) + dev->dcbnl_ops = &hns3_unic_dcbnl_ops; + else + dev->dcbnl_ops = &hns3_dcbnl_ops; +#else dev->dcbnl_ops = &hns3_dcbnl_ops; +#endif } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 2b4ee25f891b..af66ee7cd23b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -26,6 +26,7 @@ #include "hnae3.h" #include "hnae3_ext.h" #include "hns3_enet.h" +#include "hns3_unic.h" /* All hns3 tracepoints are defined by the include below, which * must be included exactly once across the whole kernel with * CREATE_TRACE_POINTS defined @@ -3266,6 +3267,28 @@ static u16 hns3_nic_select_queue(struct net_device *netdev, return netdev_pick_tx(netdev, skb, sb_dev); } +const struct net_device_ops hns3_unic_netdev_ops = { + .ndo_open = hns3_nic_net_open, + .ndo_stop = hns3_nic_net_stop, + .ndo_start_xmit = hns3_nic_net_xmit, + .ndo_tx_timeout = hns3_nic_net_timeout, + .ndo_do_ioctl = hns3_nic_do_ioctl, + .ndo_change_mtu = hns3_nic_change_mtu, + .ndo_set_features = hns3_nic_set_features, + .ndo_features_check = hns3_features_check, + .ndo_get_stats64 = hns3_nic_get_stats64, + .ndo_setup_tc = hns3_nic_setup_tc, + .ndo_set_rx_mode = hns3_nic_set_rx_mode, + .ndo_set_vf_trust = hns3_set_vf_trust, +#ifdef CONFIG_RFS_ACCEL + .ndo_rx_flow_steer = hns3_rx_flow_steer, +#endif + .ndo_get_vf_config = hns3_nic_get_vf_config, + .ndo_set_vf_link_state = hns3_nic_set_vf_link_state, + .ndo_set_vf_rate = hns3_nic_set_vf_rate, + .ndo_select_queue = hns3_nic_select_queue, +}; + static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_open = hns3_nic_net_open, .ndo_stop = hns3_nic_net_stop, @@ -5581,7 +5604,16 @@ static int hns3_client_init(struct hnae3_handle *handle) netdev->watchdog_timeo = HNS3_TX_TIMEOUT; netdev->priv_flags |= IFF_UNICAST_FLT; + +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(handle)) + netdev->netdev_ops = &hns3_unic_netdev_ops; + else + netdev->netdev_ops = &hns3_nic_netdev_ops; +#else netdev->netdev_ops = &hns3_nic_netdev_ops; +#endif + SET_NETDEV_DEV(netdev, &pdev->dev); hns3_ethtool_set_ops(netdev); @@ -5649,6 +5681,10 @@ static int hns3_client_init(struct hnae3_handle *handle) } netdev->max_mtu = HNS3_MAX_MTU(ae_dev->dev_specs.max_frm_size); +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(handle)) + hns3_unic_init(netdev); +#endif hns3_state_init(handle); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 315211f7be39..c74d2217a129 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -2101,6 +2101,48 @@ static const struct ethtool_ops hns3vf_ethtool_ops = { .reset = hns3_set_reset, }; +static const struct ethtool_ops hns3_unic_ethtool_ops = { + .supported_coalesce_params = HNS3_ETHTOOL_COALESCE, + .supported_ring_params = HNS3_ETHTOOL_RING, + .self_test = hns3_self_test, + .get_drvinfo = hns3_get_drvinfo, + .get_link = hns3_get_link, + .get_ringparam = hns3_get_ringparam, + .set_ringparam = hns3_set_ringparam, + .get_strings = hns3_get_strings, + .get_ethtool_stats = hns3_get_stats, + .get_sset_count = hns3_get_sset_count, + .get_channels = hns3_get_channels, + .set_channels = hns3_set_channels, + .get_rxnfc = hns3_get_rxnfc, + .set_rxnfc = hns3_set_rxnfc, + .get_rxfh_key_size = hns3_get_rss_key_size, + .get_rxfh_indir_size = hns3_get_rss_indir_size, + .get_rxfh = hns3_get_rss, + .set_rxfh = hns3_set_rss, + .get_link_ksettings = hns3_get_link_ksettings, + .set_link_ksettings = hns3_set_link_ksettings, + .nway_reset = hns3_nway_reset, + .get_coalesce = hns3_get_coalesce, + .set_coalesce = hns3_set_coalesce, + .get_regs_len = hns3_get_regs_len, + .get_regs = hns3_get_regs, + .set_phys_id = hns3_set_phys_id, + .get_msglevel = hns3_get_msglevel, + .set_msglevel = hns3_set_msglevel, + .get_fecparam = hns3_get_fecparam, + .set_fecparam = hns3_set_fecparam, + .get_module_info = hns3_get_module_info, + .get_module_eeprom = hns3_get_module_eeprom, + .get_priv_flags = hns3_get_priv_flags, + .set_priv_flags = hns3_set_priv_flags, + .get_ts_info = hns3_get_ts_info, + .get_tunable = hns3_get_tunable, + .set_tunable = hns3_set_tunable, + .reset = hns3_set_reset, + .get_link_ext_state = hns3_get_link_ext_state, +}; + static const struct ethtool_ops hns3_ethtool_ops = { .supported_coalesce_params = HNS3_ETHTOOL_COALESCE, .supported_ring_params = HNS3_ETHTOOL_RING, @@ -2153,6 +2195,10 @@ void hns3_ethtool_set_ops(struct net_device *netdev) if (h->flags & HNAE3_SUPPORT_VF) netdev->ethtool_ops = &hns3vf_ethtool_ops; +#ifdef CONFIG_HNS3_UBL + else if (hns3_ubl_supported(h)) + netdev->ethtool_ops = &hns3_unic_ethtool_ops; +#endif else netdev->ethtool_ops = &hns3_ethtool_ops; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c new file mode 100644 index 000000000000..26984dfc123a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include + +#include "ubl.h" +#include "hnae3.h" +#include "hns3_enet.h" +#include "hns3_unic.h" + +void hns3_unic_init(struct net_device *netdev) +{ + netdev->features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_CSUM | + NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX); + netdev->features |= NETIF_F_VLAN_CHALLENGED; + netdev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_CSUM | + NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX); + + netdev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h new file mode 100644 index 000000000000..85b3bc4c9525 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HNS3_UNIC_H +#define __HNS3_UNIC_H + +#include "ubl.h" + +void hns3_unic_init(struct net_device *netdev); + +#endif -- Gitee From e48369542152f722f98ffe154c2ca989c5fa8725 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Thu, 9 Feb 2023 09:59:17 +0800 Subject: [PATCH 05/15] unic: export the function of getting l3_type for UB driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ----------------------------------------------------------------- When the driver runs in UB mode, parsing l3 type of the packet depends on the ptype table which located in hns3_enet marked as static. This patch exports the function of getting l3_type for parsing L3 type in UNIC RX. Signed-off-by: Fengyan Mu Signed-off-by: Junxin Chen --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 27 ++++++++++++------- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 1 + 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index af66ee7cd23b..f946c059463e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4420,6 +4420,23 @@ static int hns3_add_frag(struct hns3_enet_ring *ring) return 0; } +u32 hns3_get_l3_type(struct hns3_nic_priv *priv, u32 l234info, u32 ol_info) +{ + u32 l3_type; + + if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) { + u32 ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M, + HNS3_RXD_PTYPE_S); + + l3_type = hns3_rx_ptype_tbl[ptype].l3_type; + } else { + l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M, + HNS3_RXD_L3ID_S); + } + + return l3_type; +} + static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, u32 l234info, u32 bd_base_info, u32 ol_info, u16 csum) @@ -4442,15 +4459,7 @@ static int hns3_set_gro_and_checksum(struct hns3_enet_ring *ring, HNS3_RXD_GRO_COUNT_M, HNS3_RXD_GRO_COUNT_S); - if (test_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state)) { - u32 ptype = hnae3_get_field(ol_info, HNS3_RXD_PTYPE_M, - HNS3_RXD_PTYPE_S); - - l3_type = hns3_rx_ptype_tbl[ptype].l3_type; - } else { - l3_type = hnae3_get_field(l234info, HNS3_RXD_L3ID_M, - HNS3_RXD_L3ID_S); - } + l3_type = hns3_get_l3_type(priv, l234info, ol_info); if (l3_type == HNS3_L3_TYPE_IPV4) skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 3cbf68cd7004..1795eff89aae 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -774,6 +774,7 @@ void hns3_ethtool_set_ops(struct net_device *netdev); int hns3_set_channels(struct net_device *netdev, struct ethtool_channels *ch); +u32 hns3_get_l3_type(struct hns3_nic_priv *priv, u32 l234info, u32 ol_info); void hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget); int hns3_init_all_ring(struct hns3_nic_priv *priv); int hns3_nic_reset_all_ring(struct hnae3_handle *h); -- Gitee From f52063cd675564192638518d0a6d428e330ec7e1 Mon Sep 17 00:00:00 2001 From: Junxin Chen Date: Fri, 1 Sep 2023 14:43:48 +0800 Subject: [PATCH 06/15] UNIC: Replace ether interface by ubl interface driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ---------------------------------------------------------------- When the driver runs in UB mode, the interfaces that connect to the network protocol stack must be replaced with those of UB. This patch replaces them to host the function interfaces of the UB. Signed-off-by: Junxin Chen Signed-off-by: Haiqing Fang --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 37 +++++++++++++++- .../net/ethernet/hisilicon/hns3/hns3_unic.c | 43 +++++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_unic.h | 5 +++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index f946c059463e..2305e303df91 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -23,6 +23,7 @@ #include #include +#include "ubl.h" #include "hnae3.h" #include "hnae3_ext.h" #include "hns3_enet.h" @@ -1916,6 +1917,10 @@ static int hns3_fill_skb_desc(struct hns3_nic_priv *priv, } /* Set txbd */ +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(priv->ae_handle)) + hns3_unic_set_l3_type(skb, ¶m.type_cs_vlan_tso); +#endif desc->tx.ol_type_vlan_len_msec = cpu_to_le32(param.ol_type_vlan_len_msec); desc->tx.type_cs_vlan_tso_len = cpu_to_le32(param.type_cs_vlan_tso); @@ -2577,7 +2582,12 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) hns3_rl_err(netdev, "xmit error: %d!\n", ret); goto out_err_tx_ok; } - +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(hns3_get_handle(netdev))) { + ubl_rmv_sw_ctype(skb); + hns3_unic_set_default_cc(skb); + } +#endif ret = hns3_handle_skb_desc(priv, ring, skb, desc_cb, ring->next_to_use); if (unlikely(ret <= 0)) goto out_err_tx_ok; @@ -4349,8 +4359,14 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length, skb_mark_for_recycle(skb); hns3_ring_stats_update(ring, seg_pkt_cnt); - +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(hns3_get_handle(netdev))) + ring->pull_len = HNS3_RX_HEAD_SIZE; + else + ring->pull_len = eth_get_headlen(netdev, va, HNS3_RX_HEAD_SIZE); +#else ring->pull_len = eth_get_headlen(netdev, va, HNS3_RX_HEAD_SIZE); +#endif __skb_put(skb, ring->pull_len); hns3_nic_reuse_page(skb, ring->frag_num++, ring, ring->pull_len, desc_cb); @@ -4579,7 +4595,17 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) len = skb->len; /* Do update ip stack process */ +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(hns3_get_handle(netdev))) + skb->protocol = ubl_type_trans(skb, netdev, + hns3_unic_get_l3_type(netdev, + ol_info, + l234info)); + else + skb->protocol = eth_type_trans(skb, netdev); +#else skb->protocol = eth_type_trans(skb, netdev); +#endif /* This is needed in order to enable forwarding support */ ret = hns3_set_gro_and_checksum(ring, skb, l234info, @@ -5589,7 +5615,14 @@ static int hns3_client_init(struct hnae3_handle *handle) handle->ae_algo->ops->get_tqps_and_rss_info(handle, &alloc_tqps, &max_rss_size); +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(handle)) + netdev = alloc_ubndev_mq(sizeof(struct hns3_nic_priv), alloc_tqps); + else + netdev = alloc_etherdev_mq(sizeof(struct hns3_nic_priv), alloc_tqps); +#else netdev = alloc_etherdev_mq(sizeof(struct hns3_nic_priv), alloc_tqps); +#endif if (!netdev) return -ENOMEM; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c index 26984dfc123a..223fdfb61e49 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c @@ -20,6 +20,15 @@ #include "hns3_enet.h" #include "hns3_unic.h" +void hns3_unic_set_default_cc(struct sk_buff *skb) +{ + struct ublhdr *ubl = (struct ublhdr *)skb->data; + + if (skb->protocol == htons(ETH_P_IP) || + skb->protocol == htons(ETH_P_IPV6)) + ubl->h_cc = htons(UNIC_CC_DEFAULT_FECN_MODE); +} + void hns3_unic_init(struct net_device *netdev) { netdev->features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_CSUM | @@ -32,3 +41,37 @@ void hns3_unic_init(struct net_device *netdev) netdev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); } + +/** + * L3T is an element of the TX BD interface for software and hardware + * interaction, used to identify the message type. As the message data + * given by software to the chip cannot be self-decoded, the driver needs + * to actively inform the chip of the message type, which is unrelated + * to checksum offloading. + */ +void hns3_unic_set_l3_type(struct sk_buff *skb, u32 *type_cs_vlan_tso) +{ + if (skb->protocol == htons(ETH_P_IP)) + hnae3_set_field(*type_cs_vlan_tso, HNS3_TXD_L3T_M, + HNS3_TXD_L3T_S, HNS3_L3T_IPV4); + else if (skb->protocol == htons(ETH_P_IPV6)) + hnae3_set_field(*type_cs_vlan_tso, HNS3_TXD_L3T_M, + HNS3_TXD_L3T_S, HNS3_L3T_IPV6); +} + +u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info) +{ + struct hns3_nic_priv *priv = netdev_priv(netdev); + u32 l3_type; + + l3_type = hns3_get_l3_type(priv, l234info, ol_info); + + if (l3_type == HNS3_L3_TYPE_IPV4) + return UB_IPV4_CFG_TYPE; + else if (l3_type == HNS3_L3_TYPE_IPV6) + return UB_IPV6_CFG_TYPE; + else if (l3_type != HNS3_L3_TYPE_PARSE_FAIL) + return UB_NOIP_CFG_TYPE; + + return UB_UNKNOWN_CFG_TYPE; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h index 85b3bc4c9525..3055b35a1dd9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h @@ -18,6 +18,11 @@ #include "ubl.h" +#define UNIC_CC_DEFAULT_FECN_MODE 0x4000 + +void hns3_unic_set_default_cc(struct sk_buff *skb); void hns3_unic_init(struct net_device *netdev); +void hns3_unic_set_l3_type(struct sk_buff *skb, u32 *type_cs_vlan_tso); +u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info); #endif -- Gitee From 2922b0712475ada00f0a0b601497415c58f18a3f Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Fri, 1 Sep 2023 11:09:15 +0800 Subject: [PATCH 07/15] UNIC: Support changing MTU size in UB mode driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ----------------------------------------------------------- When the driver runs in UB mode and user prefers to modify the MTU size, thr driver will judge if the size available in UB mode. Signed-off-by: Fengyan Mu Signed-off-by: Haiqing Fang Signed-off-by: Junxin Chen --- .../net/ethernet/hisilicon/hns3/hns3_unic.c | 5 ++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 23 ++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c index 223fdfb61e49..4e517041d931 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c @@ -31,6 +31,10 @@ void hns3_unic_set_default_cc(struct sk_buff *skb) void hns3_unic_init(struct net_device *netdev) { + struct hnae3_handle *h = hns3_get_handle(netdev); + struct pci_dev *pdev = h->pdev; + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev); + netdev->features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX); @@ -40,6 +44,7 @@ void hns3_unic_init(struct net_device *netdev) NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX); netdev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + netdev->max_mtu = ae_dev->dev_specs.max_frm_size; } /** diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ee11da881f5d..bb04577b70df 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -16,6 +16,7 @@ #include #include #include +#include "ubl.h" #include "hclge_cmd.h" #include "hclge_dcb.h" #include "hclge_ext.h" @@ -1829,6 +1830,10 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) vport->vport_id = i; vport->vf_info.link_state = IFLA_VF_LINK_STATE_AUTO; vport->mps = HCLGE_MAC_DEFAULT_FRAME; +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + vport->mps = UB_DATA_LEN; +#endif vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE; vport->port_base_vlan_cfg.tbl_sta = true; vport->rxvlan_cfg.rx_vlan_offload_en = true; @@ -11035,16 +11040,28 @@ static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu) int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu) { + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(vport->nic.pdev); + int l2_hlen = ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN; + int default_size = HCLGE_MAC_DEFAULT_FRAME; + int min_frm_size = HCLGE_MAC_MIN_FRAME; struct hclge_dev *hdev = vport->back; int i, max_frm_size, ret; +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(ae_dev)) { + /* UB MTU */ + l2_hlen = 0; + min_frm_size = UB_MIN_MTU; + default_size = UB_DATA_LEN; + } +#endif /* HW supprt 2 layer vlan */ - max_frm_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN; - if (max_frm_size < HCLGE_MAC_MIN_FRAME || + max_frm_size = new_mtu + l2_hlen; + if (max_frm_size < min_frm_size || max_frm_size > hdev->ae_dev->dev_specs.max_frm_size) return -EINVAL; - max_frm_size = max(max_frm_size, HCLGE_MAC_DEFAULT_FRAME); + max_frm_size = max(max_frm_size, default_size); mutex_lock(&hdev->vport_lock); /* VF's mps must fit within hdev->mps */ if (vport->vport_id && max_frm_size > hdev->mps) { -- Gitee From 41edd9ef262d91405b832c786069ef333c51f4f2 Mon Sep 17 00:00:00 2001 From: Fengyan Mu Date: Tue, 18 Apr 2023 14:53:33 +0800 Subject: [PATCH 08/15] UNIC: Support UDMA client management driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA --------------------------------------------------- Add UDMA client instance to hns3, managing UDMA client in hns3, including struct and interface functions. This patch creates new files to host the function interfaces of the UB. Signed-off-by: Fengyan Mu Signed-off-by: Junxin Chen --- drivers/net/ethernet/hisilicon/hns3/Makefile | 6 +- drivers/net/ethernet/hisilicon/hns3/hnae3.c | 10 +- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 14 +++ .../hisilicon/hns3/hns3pf/hclge_main.c | 65 +++++++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 4 + .../hisilicon/hns3/hns3pf/hclge_udma.c | 106 ++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_udma.h | 26 +++++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 83 +++++++++++++- .../hisilicon/hns3/hns3vf/hclgevf_main.h | 4 + .../hisilicon/hns3/hns3vf/hclgevf_udma.c | 85 ++++++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_udma.h | 26 +++++ 11 files changed, 425 insertions(+), 4 deletions(-) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.h diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index 91d61b5ab72a..320530fd7362 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -21,12 +21,14 @@ hns3-$(CONFIG_HNS3_UBL) += hns3_unic.o obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o hns3vf/hclgevf_regs.o \ - hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o + hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o \ + hns3vf/hclgevf_udma.o obj-$(CONFIG_HNS3_HCLGE) += hclge.o hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_sysfs.o hns3pf/hclge_regs.o \ hns3pf/hclge_mbx.o hns3pf/hclge_err.o hns3pf/hclge_debugfs.o hns3pf/hclge_ptp.o hns3pf/hclge_devlink.o \ - hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o + hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o \ + hns3pf/hclge_udma.o hclge-objs += hns3pf/hclge_ext.o hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c index ee4b7f5910b1..82ce3f5744a0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c @@ -41,7 +41,8 @@ static bool hnae3_client_match(enum hnae3_client_type client_type) { if (client_type == HNAE3_CLIENT_KNIC || client_type == HNAE3_CLIENT_ROCE || - client_type == HNAE3_CLIENT_ROH) + client_type == HNAE3_CLIENT_ROH || + client_type == HNAE3_CLIENT_UDMA) return true; return false; @@ -64,6 +65,9 @@ void hnae3_set_client_init_flag(struct hnae3_client *client, case HNAE3_CLIENT_ROH: hnae3_set_bit(ae_dev->flag, HNAE3_ROH_CLIENT_INITED_B, inited); break; + case HNAE3_CLIENT_UDMA: + hnae3_set_bit(ae_dev->flag, HNAE3_UDMA_CLIENT_INITED_B, inited); + break; default: break; } @@ -88,6 +92,10 @@ static int hnae3_get_client_init_flag(struct hnae3_client *client, inited = hnae3_get_bit(ae_dev->flag, HNAE3_ROH_CLIENT_INITED_B); break; + case HNAE3_CLIENT_UDMA: + inited = hnae3_get_bit(ae_dev->flag, + HNAE3_UDMA_CLIENT_INITED_B); + break; default: break; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 9115b48efc1a..ab3f87e13e07 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -74,6 +74,7 @@ #define HNAE3_UNIC_CLIENT_INITED_B 0x4 #define HNAE3_ROCE_CLIENT_INITED_B 0x5 #define HNAE3_ROH_CLIENT_INITED_B 0x6 +#define HNAE3_UDMA_CLIENT_INITED_B 0x7 #define HNAE3_DEV_SUPPORT_UDMA_B 0x8 #define HNAE3_DEV_SUPPORT_UBL_B 0x9 @@ -251,6 +252,7 @@ enum hnae3_client_type { HNAE3_CLIENT_KNIC, HNAE3_CLIENT_ROCE, HNAE3_CLIENT_ROH, + HNAE3_CLIENT_UDMA, }; enum hnae3_mac_type { @@ -912,6 +914,17 @@ struct hnae3_roh_private_info { unsigned long reset_state; }; +struct hnae3_udma_private_info { + struct net_device *netdev; + void __iomem *udma_io_base; + void __iomem *udma_mem_base; + int base_vector; + int num_vectors; + unsigned long reset_state; + unsigned long instance_state; + unsigned long state; +}; + #define HNAE3_SUPPORT_APP_LOOPBACK BIT(0) #define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1) #define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2) @@ -946,6 +959,7 @@ struct hnae3_handle { struct hnae3_knic_private_info kinfo; struct hnae3_roce_private_info rinfo; struct hnae3_roh_private_info rohinfo; + struct hnae3_udma_private_info udmainfo; }; u32 numa_node_mask; /* for multi-chip support */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index bb04577b70df..82689116ab3e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -29,6 +29,7 @@ #include "hnae3.h" #include "hclge_devlink.h" #include "hclge_comm_cmd.h" +#include "hclge_udma.h" #define HCLGE_NAME "hclge" @@ -791,6 +792,7 @@ static int hclge_query_function_status(struct hclge_dev *hdev) static int hclge_query_pf_resource(struct hclge_dev *hdev) { + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hclge_pf_res_cmd *req; struct hclge_desc desc; int ret; @@ -843,6 +845,11 @@ static int hclge_query_pf_resource(struct hclge_dev *hdev) */ hdev->num_msi = hdev->num_nic_msi + hdev->num_roce_msi + hdev->num_roh_msi; + } else if (hnae3_dev_udma_supported(ae_dev)) { + hdev->num_udma_msi = + le16_to_cpu(req->pf_intr_vector_number_roce); + + hdev->num_msi = hdev->num_nic_msi + hdev->num_udma_msi; } else { hdev->num_msi = hdev->num_nic_msi; } @@ -2938,8 +2945,10 @@ static void hclge_push_link_status(struct hclge_dev *hdev) static void hclge_update_link_status(struct hclge_dev *hdev) { struct hnae3_handle *rhandle = &hdev->vport[0].roce; + struct hnae3_handle *uhandle = &hdev->vport[0].udma; struct hnae3_handle *handle = &hdev->vport[0].nic; struct hnae3_client *rclient = hdev->roce_client; + struct hnae3_client *uclient = hdev->udma_client; struct hnae3_client *client = hdev->nic_client; int state; int ret; @@ -2962,6 +2971,8 @@ static void hclge_update_link_status(struct hclge_dev *hdev) hclge_config_mac_tnl_int(hdev, state); if (rclient && rclient->ops->link_status_change) rclient->ops->link_status_change(rhandle, state); + if (uclient && uclient->ops->link_status_change) + uclient->ops->link_status_change(uhandle, state); hclge_push_link_status(hdev); } @@ -4206,6 +4217,10 @@ static int hclge_reset_prepare(struct hclge_dev *hdev) if (ret) return ret; + ret = hclge_notify_udma_client(hdev, HNAE3_DOWN_CLIENT); + if (ret) + return ret; + rtnl_lock(); ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT); rtnl_unlock(); @@ -4230,6 +4245,10 @@ static int hclge_reset_rebuild(struct hclge_dev *hdev) if (ret) return ret; + ret = hclge_notify_udma_client(hdev, HNAE3_UNINIT_CLIENT); + if (ret) + return ret; + rtnl_lock(); ret = hclge_reset_stack(hdev); rtnl_unlock(); @@ -4254,6 +4273,14 @@ static int hclge_reset_rebuild(struct hclge_dev *hdev) hdev->rst_stats.reset_fail_cnt < HCLGE_RESET_MAX_FAIL_CNT - 1) return ret; + ret = hclge_notify_udma_client(hdev, HNAE3_INIT_CLIENT); + /* ignore udma notify error if it fails HCLGE_RESET_MAX_FAIL_CNT - 1 + * times + */ + if (ret && + hdev->rst_stats.reset_fail_cnt < HCLGE_RESET_MAX_FAIL_CNT - 1) + return ret; + ret = hclge_reset_prepare_up(hdev); if (ret) return ret; @@ -4272,6 +4299,10 @@ static int hclge_reset_rebuild(struct hclge_dev *hdev) if (ret) return ret; + ret = hclge_notify_udma_client(hdev, HNAE3_UP_CLIENT); + if (ret) + return ret; + hdev->last_reset_time = jiffies; hdev->rst_stats.reset_fail_cnt = 0; hdev->rst_stats.reset_done_cnt++; @@ -4781,6 +4812,8 @@ struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle) return container_of(handle, struct hclge_vport, roce); else if (handle->client->type == HNAE3_CLIENT_ROH) return container_of(handle, struct hclge_vport, roh); + else if (handle->client->type == HNAE3_CLIENT_UDMA) + return container_of(handle, struct hclge_vport, udma); else return container_of(handle, struct hclge_vport, nic); } @@ -11703,6 +11736,10 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roce; + ret = hclge_init_udma_client_instance(ae_dev, vport); + if (ret) + goto clear_udma; + break; case HNAE3_CLIENT_ROCE: if (hnae3_dev_roce_supported(hdev)) { @@ -11723,6 +11760,17 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roh; + break; + case HNAE3_CLIENT_UDMA: + if (hnae3_dev_udma_supported(ae_dev)) { + hdev->udma_client = client; + vport->udma.client = client; + } + + ret = hclge_init_udma_client_instance(ae_dev, vport); + if (ret) + goto clear_udma; + break; default: return -EINVAL; @@ -11742,6 +11790,10 @@ static int hclge_init_client_instance(struct hnae3_client *client, hdev->roh_client = NULL; vport->roh.client = NULL; return ret; +clear_udma: + hdev->udma_client = NULL; + vport->udma.client = NULL; + return ret; } static void hclge_uninit_client_instance(struct hnae3_client *client, @@ -11750,6 +11802,19 @@ static void hclge_uninit_client_instance(struct hnae3_client *client, struct hclge_dev *hdev = ae_dev->priv; struct hclge_vport *vport = &hdev->vport[0]; + if (hdev->udma_client && (client->type == HNAE3_CLIENT_UDMA || + client->type == HNAE3_CLIENT_KNIC)) { + clear_bit(HCLGE_STATE_UDMA_REGISTERED, &hdev->state); + while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) + msleep(HCLGE_WAIT_RESET_DONE); + + hdev->udma_client->ops->uninit_instance(&vport->udma, 0); + hdev->udma_client = NULL; + vport->udma.client = NULL; + } + if (client->type == HNAE3_CLIENT_UDMA) + return; + if (hdev->roh_client && (client->type == HNAE3_CLIENT_ROH || client->type == HNAE3_CLIENT_KNIC)) { clear_bit(HCLGE_STATE_ROH_REGISTERED, &hdev->state); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index ce9a2fd1af12..76fbda6cae0f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -205,6 +205,7 @@ enum HCLGE_DEV_STATE { HCLGE_STATE_NIC_REGISTERED, HCLGE_STATE_ROCE_REGISTERED, HCLGE_STATE_ROH_REGISTERED, + HCLGE_STATE_UDMA_REGISTERED, HCLGE_STATE_SERVICE_INITED, HCLGE_STATE_RST_SERVICE_SCHED, HCLGE_STATE_RST_HANDLING, @@ -889,6 +890,7 @@ struct hclge_dev { u16 num_nic_msi; /* Num of nic vectors for this PF */ u16 num_roce_msi; /* Num of roce vectors for this PF */ u16 num_roh_msi; /* Num of roh vectors for this PF */ + u16 num_udma_msi; /* Num of udma vectors for this PF */ unsigned long service_timer_period; unsigned long service_timer_previous; @@ -906,6 +908,7 @@ struct hclge_dev { struct hnae3_client *nic_client; struct hnae3_client *roce_client; struct hnae3_client *roh_client; + struct hnae3_client *udma_client; #define HCLGE_FLAG_MAIN BIT(0) #define HCLGE_FLAG_DCB_CAPABLE BIT(1) @@ -1045,6 +1048,7 @@ struct hclge_vport { struct hnae3_handle nic; struct hnae3_handle roce; struct hnae3_handle roh; + struct hnae3_handle udma; unsigned long state; unsigned long need_notify; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c new file mode 100644 index 000000000000..3863c0a62097 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include "hclge_main.h" +#include "hclge_udma.h" +#include "hclge_err.h" + +static int hclge_init_udma_base_info(struct hclge_vport *vport) +{ + struct hnae3_handle *udma = &vport->udma; + struct hnae3_handle *nic = &vport->nic; + struct hclge_dev *hdev = vport->back; + + udma->udmainfo.num_vectors = vport->back->num_udma_msi; + + if (hdev->num_msi < hdev->num_nic_msi + hdev->num_udma_msi) + return -EINVAL; + + udma->udmainfo.base_vector = hdev->num_nic_msi; + + udma->udmainfo.netdev = nic->kinfo.netdev; + udma->udmainfo.udma_io_base = hdev->hw.hw.io_base; + udma->udmainfo.udma_mem_base = hdev->hw.hw.mem_base; + + udma->pdev = nic->pdev; + udma->ae_algo = nic->ae_algo; + udma->numa_node_mask = nic->numa_node_mask; + + return 0; +} + +int hclge_notify_udma_client(struct hclge_dev *hdev, + enum hnae3_reset_notify_type type) +{ + struct hnae3_handle *handle = &hdev->vport[0].udma; + struct hnae3_client *client = hdev->udma_client; + int ret; + + if (!test_bit(HCLGE_STATE_UDMA_REGISTERED, &hdev->state) || !client) + return 0; + + if (!client->ops->reset_notify) + return -EOPNOTSUPP; + + ret = client->ops->reset_notify(handle, type); + if (ret) + dev_err(&hdev->pdev->dev, "notify udma client failed %d(%d)", + type, ret); + + return ret; +} + +int hclge_init_udma_client_instance(struct hnae3_ae_dev *ae_dev, + struct hclge_vport *vport) +{ + struct hclge_dev *hdev = ae_dev->priv; + struct hnae3_client *client; + int rst_cnt; + int ret; + + if (!hnae3_dev_udma_supported(ae_dev) || !hdev->udma_client || + !hdev->nic_client) + return 0; + + client = hdev->udma_client; + ret = hclge_init_udma_base_info(vport); + if (ret) + return ret; + + rst_cnt = hdev->rst_stats.reset_cnt; + ret = client->ops->init_instance(&vport->udma); + if (ret) + return ret; + + set_bit(HCLGE_STATE_UDMA_REGISTERED, &hdev->state); + if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || + rst_cnt != hdev->rst_stats.reset_cnt) { + ret = -EBUSY; + goto init_udma_err; + } + + hnae3_set_client_init_flag(client, ae_dev, 1); + + return 0; + +init_udma_err: + clear_bit(HCLGE_STATE_UDMA_REGISTERED, &hdev->state); + while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) + msleep(HCLGE_WAIT_RESET_DONE); + + hdev->udma_client->ops->uninit_instance(&vport->udma, 0); + + return ret; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h new file mode 100644 index 000000000000..383a8ec1b90b --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HCLGE_UDMA_H +#define __HCLGE_UDMA_H + +#include "hclge_main.h" + +int hclge_notify_udma_client(struct hclge_dev *hdev, + enum hnae3_reset_notify_type type); +int hclge_init_udma_client_instance(struct hnae3_ae_dev *ae_dev, + struct hclge_vport *vport); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index de59c9150398..c211d8607002 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -11,6 +11,7 @@ #include "hnae3.h" #include "hclgevf_devlink.h" #include "hclge_comm_rss.h" +#include "hclgevf_udma.h" #define HCLGEVF_NAME "hclgevf" @@ -74,6 +75,8 @@ struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle) return container_of(handle, struct hclgevf_dev, nic); else if (handle->client->type == HNAE3_CLIENT_ROCE) return container_of(handle, struct hclgevf_dev, roce); + else if (handle->client->type == HNAE3_CLIENT_UDMA) + return container_of(handle, struct hclgevf_dev, udma); else return container_of(handle, struct hclgevf_dev, nic); } @@ -445,8 +448,10 @@ static void hclgevf_request_link_info(struct hclgevf_dev *hdev) void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state) { struct hnae3_handle *rhandle = &hdev->roce; + struct hnae3_handle *uhandle = &hdev->udma; struct hnae3_handle *handle = &hdev->nic; struct hnae3_client *rclient; + struct hnae3_client *uclient; struct hnae3_client *client; if (test_and_set_bit(HCLGEVF_STATE_LINK_UPDATING, &hdev->state)) @@ -454,6 +459,7 @@ void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state) client = handle->client; rclient = hdev->roce_client; + uclient = hdev->udma_client; link_state = test_bit(HCLGEVF_STATE_DOWN, &hdev->state) ? 0 : link_state; @@ -462,6 +468,8 @@ void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state) client->ops->link_status_change(handle, !!link_state); if (rclient && rclient->ops->link_status_change) rclient->ops->link_status_change(rhandle, !!link_state); + if (uclient && uclient->ops->link_status_change) + uclient->ops->link_status_change(uhandle, !!link_state); } clear_bit(HCLGEVF_STATE_LINK_UPDATING, &hdev->state); @@ -1597,6 +1605,10 @@ static int hclgevf_reset_prepare(struct hclgevf_dev *hdev) if (ret) return ret; + ret = hclgevf_notify_udma_client(hdev, HNAE3_DOWN_CLIENT); + if (ret) + return ret; + rtnl_lock(); /* bring down the nic to stop any ongoing TX/RX */ ret = hclgevf_notify_client(hdev, HNAE3_DOWN_CLIENT); @@ -1616,6 +1628,10 @@ static int hclgevf_reset_rebuild(struct hclgevf_dev *hdev) if (ret) return ret; + ret = hclgevf_notify_udma_client(hdev, HNAE3_UNINIT_CLIENT); + if (ret) + return ret; + rtnl_lock(); /* now, re-initialize the nic client and ae device */ ret = hclgevf_reset_stack(hdev); @@ -1637,6 +1653,18 @@ static int hclgevf_reset_rebuild(struct hclgevf_dev *hdev) if (ret) return ret; + ret = hclgevf_notify_udma_client(hdev, HNAE3_INIT_CLIENT); + /* ignore UDMA notify error if it fails HCLGEVF_RESET_MAX_FAIL_CNT - 1 + * times + */ + if (ret && + hdev->rst_stats.rst_fail_cnt < HCLGEVF_RESET_MAX_FAIL_CNT - 1) + return ret; + + ret = hclgevf_notify_udma_client(hdev, HNAE3_UP_CLIENT); + if (ret) + return ret; + hdev->last_reset_time = jiffies; hdev->rst_stats.rst_done_cnt++; hdev->rst_stats.rst_fail_cnt = 0; @@ -2336,11 +2364,12 @@ static void hclgevf_state_uninit(struct hclgevf_dev *hdev) static int hclgevf_init_msi(struct hclgevf_dev *hdev) { + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct pci_dev *pdev = hdev->pdev; int vectors; int i; - if (hnae3_dev_roce_supported(hdev)) + if (hnae3_dev_roce_supported(hdev) || hnae3_dev_udma_supported(ae_dev)) vectors = pci_alloc_irq_vectors(pdev, hdev->roce_base_msix_offset + 1, hdev->num_msi, @@ -2516,6 +2545,11 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roce; + ret = hclgevf_init_udma_client_instance(ae_dev, + hdev->udma_client); + if (ret) + goto clear_udma; + break; case HNAE3_CLIENT_ROCE: if (hnae3_dev_roce_supported(hdev)) { @@ -2527,6 +2561,17 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roce; + break; + case HNAE3_CLIENT_UDMA: + if (hnae3_dev_udma_supported(ae_dev)) { + hdev->udma_client = client; + hdev->udma.client = client; + } + + ret = hclgevf_init_udma_client_instance(ae_dev, client); + if (ret) + goto clear_udma; + break; default: return -EINVAL; @@ -2542,6 +2587,10 @@ static int hclgevf_init_client_instance(struct hnae3_client *client, hdev->roce_client = NULL; hdev->roce.client = NULL; return ret; +clear_udma: + hdev->udma_client = NULL; + hdev->udma.client = NULL; + return ret; } static void hclgevf_uninit_client_instance(struct hnae3_client *client, @@ -2549,6 +2598,20 @@ static void hclgevf_uninit_client_instance(struct hnae3_client *client, { struct hclgevf_dev *hdev = ae_dev->priv; + /* un-init udma, if it exists and called by nic or udma client */ + if (hdev->udma_client && (client->type == HNAE3_CLIENT_UDMA || + client->type == HNAE3_CLIENT_KNIC)) { + while (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state)) + msleep(HCLGEVF_WAIT_RESET_DONE); + clear_bit(HCLGEVF_STATE_UDMA_REGISTERED, &hdev->state); + + hdev->udma_client->ops->uninit_instance(&hdev->udma, 0); + hdev->udma_client = NULL; + hdev->udma.client = NULL; + } + if (client->type == HNAE3_CLIENT_UDMA) + return; + /* un-init roce, if it exists */ if (hdev->roce_client) { while (test_bit(HCLGEVF_STATE_RST_HANDLING, &hdev->state)) @@ -2659,6 +2722,7 @@ static void hclgevf_pci_uninit(struct hclgevf_dev *hdev) static int hclgevf_query_vf_resource(struct hclgevf_dev *hdev) { + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hclgevf_query_res_cmd *req; struct hclge_desc desc; int ret; @@ -2690,6 +2754,23 @@ static int hclgevf_query_vf_resource(struct hclgevf_dev *hdev) */ hdev->num_msi = hdev->num_roce_msix + hdev->roce_base_msix_offset; + } else if (hnae3_dev_udma_supported(ae_dev)) { + hdev->roce_base_msix_offset = + hnae3_get_field(le16_to_cpu(req->msixcap_localid_ba_rocee), + HCLGEVF_MSIX_OFT_ROCEE_M, + HCLGEVF_MSIX_OFT_ROCEE_S); + hdev->num_udma_msix = + hnae3_get_field(le16_to_cpu(req->vf_intr_vector_number), + HCLGEVF_VEC_NUM_M, HCLGEVF_VEC_NUM_S); + + /* nic's msix numbers is always equals to the udma's. */ + hdev->num_nic_msix = hdev->num_udma_msix; + + /* VF should have NIC vectors and UDMA vectors, NIC vectors + * are queued before UDMA vectors. The offset is fixed to 64. + */ + hdev->num_msi = hdev->num_udma_msix + + hdev->roce_base_msix_offset; } else { hdev->num_msi = hnae3_get_field(le16_to_cpu(req->vf_intr_vector_number), diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index a450b4df5b1c..93eea9a44f09 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -128,6 +128,7 @@ enum hclgevf_states { HCLGEVF_STATE_REMOVING, HCLGEVF_STATE_NIC_REGISTERED, HCLGEVF_STATE_ROCE_REGISTERED, + HCLGEVF_STATE_UDMA_REGISTERED, HCLGEVF_STATE_SERVICE_INITED, /* task states */ HCLGEVF_STATE_RST_SERVICE_SCHED, @@ -252,6 +253,7 @@ struct hclgevf_dev { u16 num_msi_used; u16 num_nic_msix; /* Num of nic vectors for this VF */ u16 num_roce_msix; /* Num of roce vectors for this VF */ + u16 num_udma_msix; /* Num of udma vectors for this VF */ u16 roce_base_msix_offset; u16 *vector_status; int *vector_irq; @@ -271,9 +273,11 @@ struct hclgevf_dev { struct hnae3_handle nic; struct hnae3_handle roce; + struct hnae3_handle udma; struct hnae3_client *nic_client; struct hnae3_client *roce_client; + struct hnae3_client *udma_client; u32 flag; unsigned long serv_processed_cnt; unsigned long last_serv_processed; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.c new file mode 100644 index 000000000000..6e839a54040e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include "hclgevf_main.h" +#include "hclgevf_udma.h" + +int hclgevf_notify_udma_client(struct hclgevf_dev *hdev, + enum hnae3_reset_notify_type type) +{ + struct hnae3_client *client = hdev->udma_client; + struct hnae3_handle *handle = &hdev->udma; + int ret; + + if (!test_bit(HCLGEVF_STATE_UDMA_REGISTERED, &hdev->state) || !client) + return 0; + + if (!client->ops->reset_notify) + return -EOPNOTSUPP; + + ret = client->ops->reset_notify(handle, type); + if (ret) + dev_err(&hdev->pdev->dev, "notify udma client failed %d(%d)", + type, ret); + return ret; +} + +static int hclgevf_init_udma_base_info(struct hclgevf_dev *hdev) +{ + struct hnae3_handle *udma = &hdev->udma; + struct hnae3_handle *nic = &hdev->nic; + + udma->udmainfo.num_vectors = hdev->num_udma_msix; + + if (hdev->num_msi_left < udma->udmainfo.num_vectors || + hdev->num_msi_left == 0) + return -EINVAL; + + udma->udmainfo.base_vector = hdev->roce_base_msix_offset; + + udma->udmainfo.netdev = nic->kinfo.netdev; + udma->udmainfo.udma_io_base = hdev->hw.hw.io_base; + udma->udmainfo.udma_mem_base = hdev->hw.hw.mem_base; + + udma->pdev = nic->pdev; + udma->ae_algo = nic->ae_algo; + udma->numa_node_mask = nic->numa_node_mask; + + return 0; +} + +int hclgevf_init_udma_client_instance(struct hnae3_ae_dev *ae_dev, + struct hnae3_client *client) +{ + struct hclgevf_dev *hdev = ae_dev->priv; + int ret; + + if (!hnae3_dev_udma_supported(ae_dev) || !hdev->udma_client || + !hdev->nic_client) + return 0; + + ret = hclgevf_init_udma_base_info(hdev); + if (ret) + return ret; + + ret = client->ops->init_instance(&hdev->udma); + if (ret) + return ret; + + set_bit(HCLGEVF_STATE_UDMA_REGISTERED, &hdev->state); + hnae3_set_client_init_flag(client, ae_dev, 1); + + return 0; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.h new file mode 100644 index 000000000000..e39d38d29d70 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_udma.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HCLGEVF_UDMA_H +#define __HCLGEVF_UDMA_H + +#include + +int hclgevf_notify_udma_client(struct hclgevf_dev *hdev, + enum hnae3_reset_notify_type type); +int hclgevf_init_udma_client_instance(struct hnae3_ae_dev *ae_dev, + struct hnae3_client *client); + +#endif -- Gitee From 193e5e1d2edcd566ccf9d920354ac22c3241434e Mon Sep 17 00:00:00 2001 From: Junxin Chen Date: Wed, 19 Oct 2022 11:25:21 +0800 Subject: [PATCH 09/15] UNIC: add nfe ras for PFA and TXPM module driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ----------------------------------------------------- This patch supports the dealing process of ras for PFA and TXPM two modules. Firstly, we add PFA and TXPM module for ras parser to support UB version. Next, we add the nfe error checking of ras in driver process for PFA and TXPM. Signed-off-by: Junxin Chen --- .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 3 ++ .../hisilicon/hns3/hns3pf/hclge_err.c | 13 ++++++-- .../hisilicon/hns3/hns3pf/hclge_err.h | 2 ++ .../hisilicon/hns3/hns3pf/hclge_main.c | 11 ++++--- .../hisilicon/hns3/hns3pf/hclge_udma.c | 33 +++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_udma.h | 7 ++++ 6 files changed, 63 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 14294f27e3b1..29aaec6b4428 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -8,6 +8,7 @@ #include "hclge_main.h" #include "hclge_regs.h" #include "hclge_tm.h" +#include "hclge_udma.h" #include "hnae3.h" static const char * const state_str[] = { "off", "on" }; @@ -1814,6 +1815,8 @@ int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len) hclge_read_dev(&hdev->hw, offset)); } + hclge_dbg_dump_udma_rst_info(hdev, buf, len, &pos); + pos += scnprintf(buf + pos, len - pos, "hdev state: 0x%lx\n", hdev->state); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index 4c8743fe1c6b..bd849e06c658 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -2,6 +2,7 @@ /* Copyright (c) 2016-2017 Hisilicon Limited. */ #include "hclge_err.h" +#include "hclge_udma.h" static const struct hclge_hw_error hclge_imp_tcm_ecc_int[] = { { @@ -1245,6 +1246,12 @@ static const struct hclge_hw_module_id hclge_hw_module_id_st[] = { }, { .module_id = MODULE_HIMAC, .msg = "MODULE_HIMAC" + }, { + .module_id = MODULE_PFA, + .msg = "MODULE_PFA" + }, { + .module_id = MODULE_TXPM, + .msg = "MODULE_TXPM" }, { .module_id = MODULE_ROCEE_TOP, .msg = "MODULE_ROCEE_TOP" @@ -2751,7 +2758,7 @@ void hclge_handle_all_hns_hw_errors(struct hnae3_ae_dev *ae_dev) bool hclge_find_error_source(struct hclge_dev *hdev) { - u32 msix_src_flag, hw_err_src_flag; + u32 msix_src_flag, hw_err_src_flag, udma_err_src_flag; msix_src_flag = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS) & HCLGE_VECTOR0_REG_MSIX_MASK; @@ -2759,8 +2766,10 @@ bool hclge_find_error_source(struct hclge_dev *hdev) hw_err_src_flag = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG) & HCLGE_RAS_REG_ERR_MASK; + udma_err_src_flag = hclge_get_udma_error_reg(hdev) & + HCLGE_RAS_REG_ERR_MASK_UB; - return msix_src_flag || hw_err_src_flag; + return msix_src_flag || hw_err_src_flag || udma_err_src_flag; } void hclge_handle_occurred_error(struct hclge_dev *hdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h index 6d66483e17c2..aea392dce165 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h @@ -141,6 +141,8 @@ enum hclge_mod_name_list { MODULE_TXDMA = 13, MODULE_MASTER = 14, MODULE_HIMAC = 15, + MODULE_PFA = 16, + MODULE_TXPM = 17, /* add new MODULE NAME for NIC here in order */ MODULE_ROCEE_TOP = 40, MODULE_ROCEE_TIMER = 41, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 82689116ab3e..71459963449c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3427,13 +3427,14 @@ static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf, static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) { - u32 cmdq_src_reg, msix_src_reg, hw_err_src_reg; + u32 cmdq_src_reg, msix_src_reg, hw_err_src_reg, udma_err_src_reg; /* fetch the events from their corresponding regs */ cmdq_src_reg = hclge_read_dev(&hdev->hw, HCLGE_VECTOR0_CMDQ_SRC_REG); msix_src_reg = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS); hw_err_src_reg = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG); + udma_err_src_reg = hclge_get_udma_error_reg(hdev); /* Assumption: If by any chance reset and mailbox events are reported * together then we will only process reset event in this go and will @@ -3463,7 +3464,8 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) /* check for vector0 msix event and hardware error event source */ if (msix_src_reg & HCLGE_VECTOR0_REG_MSIX_MASK || - hw_err_src_reg & HCLGE_RAS_REG_ERR_MASK) + hw_err_src_reg & HCLGE_RAS_REG_ERR_MASK || + udma_err_src_reg & HCLGE_RAS_REG_ERR_MASK_UB) return HCLGE_VECTOR0_EVENT_ERR; /* check for vector0 ptp event source */ @@ -3481,8 +3483,9 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) /* print other vector0 event source */ dev_info(&hdev->pdev->dev, - "INT status: CMDQ(%#x) HW errors(%#x) other(%#x)\n", - cmdq_src_reg, hw_err_src_reg, msix_src_reg); + "INT status: CMDQ(%#x) HW errors(%#x, %#x) other(%#x)\n", + cmdq_src_reg, hw_err_src_reg, udma_err_src_reg, + msix_src_reg); return HCLGE_VECTOR0_EVENT_OTHER; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c index 3863c0a62097..4aba834ebff4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c @@ -16,6 +16,11 @@ #include "hclge_main.h" #include "hclge_udma.h" #include "hclge_err.h" +#include "hclge_debugfs.h" + +static const struct hclge_dbg_status_dfx_info hclge_dbg_rst_info_ub[] = { + {HCLGE_RAS_PF_OTHER_INT_STS_REG_UB, "UB RAS interrupt status"} +}; static int hclge_init_udma_base_info(struct hclge_vport *vport) { @@ -104,3 +109,31 @@ int hclge_init_udma_client_instance(struct hnae3_ae_dev *ae_dev, return ret; } + +u32 hclge_get_udma_error_reg(struct hclge_dev *hdev) +{ + u32 hw_err_src_reg = 0; + + if (hnae3_dev_ubl_supported(hdev->ae_dev) || + hnae3_dev_udma_supported(hdev->ae_dev)) + hw_err_src_reg = hclge_read_dev(&hdev->hw, + HCLGE_RAS_PF_OTHER_INT_STS_REG_UB); + + return hw_err_src_reg; +} + +void hclge_dbg_dump_udma_rst_info(struct hclge_dev *hdev, char *buf, int len, + int *pos) +{ + u32 i, offset; + + if (hnae3_dev_ubl_supported(hdev->ae_dev) || + hnae3_dev_udma_supported(hdev->ae_dev)) { + for (i = 0; i < ARRAY_SIZE(hclge_dbg_rst_info_ub); i++) { + offset = hclge_dbg_rst_info_ub[i].offset; + *pos += scnprintf(buf + *pos, len - *pos, "%s: 0x%x\n", + hclge_dbg_rst_info_ub[i].message, + hclge_read_dev(&hdev->hw, offset)); + } + } +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h index 383a8ec1b90b..b3a99df54218 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.h @@ -18,9 +18,16 @@ #include "hclge_main.h" +#define HCLGE_RAS_PF_OTHER_INT_STS_REG_UB 0x20B04 +#define HCLGE_RAS_REG_NFE_MASK_UB 0x12 +#define HCLGE_RAS_REG_ERR_MASK_UB HCLGE_RAS_REG_NFE_MASK_UB + int hclge_notify_udma_client(struct hclge_dev *hdev, enum hnae3_reset_notify_type type); int hclge_init_udma_client_instance(struct hnae3_ae_dev *ae_dev, struct hclge_vport *vport); +u32 hclge_get_udma_error_reg(struct hclge_dev *hdev); +void hclge_dbg_dump_udma_rst_info(struct hclge_dev *hdev, char *buf, int len, + int *pos); #endif -- Gitee From 17bd48f8a91f10d84e43e20ee39f9796a7911e8c Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Thu, 9 Feb 2023 19:29:18 +0800 Subject: [PATCH 10/15] UNIC: PF supports MAC loopback driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ----------------------------------------------------- Loopback can be used to test the connectivity of the system hardware. This patch supports loopback by using standard tools with packets sent in UB packet format. Signed-off-by: Haibin Lu Signed-off-by: Junxin Chen --- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 43 ++++++++++-- .../net/ethernet/hisilicon/hns3/hns3_unic.c | 68 +++++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_unic.h | 9 +++ 3 files changed, 114 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index c74d2217a129..4f732e950f09 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -8,6 +8,7 @@ #include "hns3_enet.h" #include "hns3_ethtool.h" +#include "hns3_unic.h" /* tqp related stats */ #define HNS3_TQP_STAT(_string, _member) { \ @@ -178,6 +179,32 @@ static void hns3_lp_setup_skb(struct sk_buff *skb) packet[i] = (unsigned char)(i & 0xff); } +static struct sk_buff *hns3_lp_skb_prepare(struct net_device *ndev) +{ + unsigned int size = hns3_ubl_supported(hns3_get_handle(ndev)) ? + HNS3_NIC_LB_TEST_PACKET_SIZE + 1 + NET_IP_ALIGN : + HNS3_NIC_LB_TEST_PACKET_SIZE + ETH_HLEN + NET_IP_ALIGN; + struct sk_buff *skb; + + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) + return NULL; + + skb->dev = ndev; +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(hns3_get_handle(ndev))) { + skb->protocol = htons(ETH_P_UB); + hns3_unic_lp_setup_skb(skb); + } else { + hns3_lp_setup_skb(skb); + } +#else + hns3_lp_setup_skb(skb); +#endif + skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID; + return skb; +} + static void hns3_lb_check_skb_data(struct hns3_enet_ring *ring, struct sk_buff *skb) { @@ -218,7 +245,16 @@ static u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget) pre_rx_pkt = rx_group->total_packets; preempt_disable(); +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(hns3_get_handle(priv->netdev))) + hns3_clean_rx_ring(ring, budget, + hns3_unic_lb_check_skb_data); + else + hns3_clean_rx_ring(ring, budget, + hns3_lb_check_skb_data); +#else hns3_clean_rx_ring(ring, budget, hns3_lb_check_skb_data); +#endif preempt_enable(); rcv_good_pkt_total += (rx_group->total_packets - pre_rx_pkt); @@ -253,15 +289,10 @@ static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode) u32 i, good_cnt; int ret_val = 0; - skb = alloc_skb(HNS3_NIC_LB_TEST_PACKET_SIZE + ETH_HLEN + NET_IP_ALIGN, - GFP_KERNEL); + skb = hns3_lp_skb_prepare(ndev); if (!skb) return HNS3_NIC_LB_TEST_NO_MEM_ERR; - skb->dev = ndev; - hns3_lp_setup_skb(skb); - skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID; - good_cnt = 0; for (i = 0; i < HNS3_NIC_LB_TEST_PKT_NUM; i++) { netdev_tx_t tx_ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c index 4e517041d931..1e43d619d652 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c @@ -20,6 +20,8 @@ #include "hns3_enet.h" #include "hns3_unic.h" +#define HNS3_UNIC_LB_TEST_PACKET_SIZE 128 + void hns3_unic_set_default_cc(struct sk_buff *skb) { struct ublhdr *ubl = (struct ublhdr *)skb->data; @@ -80,3 +82,69 @@ u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info) return UB_UNKNOWN_CFG_TYPE; } + +#define UNIC_DHCPV4_PROTO 0x0100 +void hns3_unic_lp_setup_skb(struct sk_buff *skb) +{ + unsigned int nip_ctrl_len = sizeof(struct ub_nip_ctrl_fld); + struct net_device *ndev = skb->dev; + struct ub_nip_ctrl_fld *ctrl_fld; + unsigned char *sw_ptype; + unsigned char *packet; + unsigned int i; + + skb_reserve(skb, NET_IP_ALIGN); + + sw_ptype = (unsigned char *)skb_put(skb, sizeof(unsigned char)); + *sw_ptype = UB_NOIP_CFG_TYPE; + ctrl_fld = (struct ub_nip_ctrl_fld *)skb_put(skb, nip_ctrl_len); + packet = (unsigned char *)skb_put(skb, HNS3_UNIC_LB_TEST_PACKET_SIZE - + nip_ctrl_len); + ctrl_fld->proto = htons(UNIC_DHCPV4_PROTO); + memcpy(ctrl_fld->d_guid, ndev->dev_addr, UBL_ALEN); + memcpy(ctrl_fld->s_guid, ndev->dev_addr, UBL_ALEN); + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + + for (i = 0; i < HNS3_UNIC_LB_TEST_PACKET_SIZE - nip_ctrl_len; i++) + packet[i] = (unsigned char)(i & 0xff); +} + +void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring, + struct sk_buff *skb) +{ + unsigned int nip_ctrl_len = sizeof(struct ub_nip_ctrl_fld); + struct hns3_enet_tqp_vector *tqp_vector = ring->tqp_vector; + struct net_device *ndev = skb->dev; + struct ub_nip_ctrl_fld *ctrl_fld; + u32 len = skb_headlen(skb); + bool is_success = false; + unsigned char *packet; + u32 i; + + if (len != HNS3_UNIC_LB_TEST_PACKET_SIZE + 1) + goto out; + + ctrl_fld = (struct ub_nip_ctrl_fld *)(skb->data + 1); + if (memcmp(ctrl_fld->d_guid, ndev->dev_addr, UBL_ALEN) || + memcmp(ctrl_fld->s_guid, ndev->dev_addr, UBL_ALEN) || + ctrl_fld->proto != htons(UNIC_DHCPV4_PROTO)) + goto out; + + packet = (unsigned char *)ctrl_fld + nip_ctrl_len; + for (i = 0; i < HNS3_UNIC_LB_TEST_PACKET_SIZE - nip_ctrl_len; i++) + if (packet[i] != (unsigned char)(i & 0xff)) + goto out; + + is_success = true; + +out: + if (is_success) + tqp_vector->rx_group.total_packets++; + else + print_hex_dump(KERN_ERR, "ubn selftest:", DUMP_PREFIX_OFFSET, + 16, 1, skb->data, len, true); + + dev_kfree_skb_any(skb); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h index 3055b35a1dd9..cc202e107cfd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h @@ -20,9 +20,18 @@ #define UNIC_CC_DEFAULT_FECN_MODE 0x4000 +struct ub_nip_ctrl_fld { + __be16 proto; + unsigned char d_guid[UBL_ALEN]; + unsigned char s_guid[UBL_ALEN]; +}; + void hns3_unic_set_default_cc(struct sk_buff *skb); void hns3_unic_init(struct net_device *netdev); void hns3_unic_set_l3_type(struct sk_buff *skb, u32 *type_cs_vlan_tso); u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info); +void hns3_unic_lp_setup_skb(struct sk_buff *skb); +void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring, + struct sk_buff *skb); #endif -- Gitee From f9c293879d6e53940a7331aaf5c942417b986fc1 Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Thu, 15 Jun 2023 11:31:46 +0800 Subject: [PATCH 11/15] UNIC: add support for querying and configuring the function guid driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA --------------------------------------------------- In UB mode, there is no MAC address. Therefore, each function requires a guid as the identity ID, and each function needs to be configured with a guid during initialization. This patch supports the initialization and configuration of the function guid. The guid is unique and comes from imp or random. Signed-off-by: Fengyan Mu Signed-off-by: Haibin Lu Signed-off-by: Haiqing Fang Signed-off-by: Junxin Chen --- drivers/net/ethernet/hisilicon/hns3/Makefile | 2 + drivers/net/ethernet/hisilicon/hns3/hnae3.h | 3 + .../hns3/hns3_common/hclge_comm_cmd.h | 4 + .../hns3/hns3_common/hclge_comm_unic_addr.c | 112 ++++++++++++++++++ .../hns3/hns3_common/hclge_comm_unic_addr.h | 43 +++++++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 7 ++ .../net/ethernet/hisilicon/hns3/hns3_unic.c | 29 +++++ .../net/ethernet/hisilicon/hns3/hns3_unic.h | 2 + .../hisilicon/hns3/hns3pf/hclge_cmd.h | 4 +- .../hisilicon/hns3/hns3pf/hclge_main.c | 24 ++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 5 + .../hisilicon/hns3/hns3pf/hclge_unic_guid.c | 45 +++++++ .../hisilicon/hns3/hns3pf/hclge_unic_guid.h | 19 +++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 9 +- .../hisilicon/hns3/hns3vf/hclgevf_main.h | 2 + .../hisilicon/hns3/hns3vf/hclgevf_unic_guid.c | 24 ++++ .../hisilicon/hns3/hns3vf/hclgevf_unic_guid.h | 14 +++ 17 files changed, 345 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index 320530fd7362..458ae9c69945 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o hns3vf/hclgevf_regs.o \ hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o \ hns3vf/hclgevf_udma.o +hclgevf-$(CONFIG_HNS3_UBL) += hns3_common/hclge_comm_unic_addr.o hns3vf/hclgevf_unic_guid.o obj-$(CONFIG_HNS3_HCLGE) += hclge.o hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_sysfs.o hns3pf/hclge_regs.o \ @@ -31,4 +32,5 @@ hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hc hns3pf/hclge_udma.o hclge-objs += hns3pf/hclge_ext.o +hclge-$(CONFIG_HNS3_UBL) += hns3_common/hclge_comm_unic_addr.o hns3pf/hclge_unic_guid.o hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index ab3f87e13e07..fa72858d66a6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -427,6 +427,7 @@ struct hnae3_dev_specs { u16 mc_mac_size; u32 mac_stats_num; u8 tnl_num; + u16 guid_tbl_space; }; struct hnae3_client_ops { @@ -826,6 +827,8 @@ struct hnae3_ae_ops { struct ethtool_wolinfo *wol); int (*priv_ops)(struct hnae3_handle *handle, int opcode, void *data, size_t length); + int (*get_func_guid)(struct hnae3_handle *handle, u8 *guid); + int (*set_func_guid)(struct hnae3_handle *handle, u8 *guid); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h index 8b2544f1b4a0..c5820efd9b45 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h @@ -310,6 +310,10 @@ enum hclge_opcode_type { /* Query link diagnosis info command */ HCLGE_OPC_QUERY_LINK_DIAGNOSIS = 0x702A, + + /* UB commands */ + HCLGE_OPC_COMM_GET_FUNC_GUID = 0xA001, + HCLGE_OPC_COMM_CFG_FUNC_GUID = 0xA122, }; enum hclge_comm_cmd_return_status { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c new file mode 100644 index 000000000000..0aa455b5d9e4 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include "hclge_comm_unic_addr.h" + +static void +hclge_comm_unic_func_guid_cmd_prepare(u8 *guid, + struct hclge_comm_func_guid_cmd *req) +{ + req->entry_vld = HCLGE_COMM_FUNC_GUID_ENTRY_VALID_EN; + memcpy(req->guid, guid, UBL_ALEN); +} + +int hclge_comm_unic_set_func_guid(struct hclge_comm_hw *hw, u8 *guid) +{ + struct hclge_comm_func_guid_cmd *req; + struct hclge_desc desc; + int ret; + + req = (struct hclge_comm_func_guid_cmd *)desc.data; + + hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMM_CFG_FUNC_GUID, + false); + hclge_comm_unic_func_guid_cmd_prepare(guid, req); + + ret = hclge_comm_cmd_send(hw, &desc, 1); + if (ret) + dev_err(&hw->cmq.csq.pdev->dev, + "failed to set guid for cmd_send, ret = %d\n", ret); + + return ret; +} + +void hclge_comm_unic_rm_func_guid(struct hclge_comm_hw *hw) +{ + struct hclge_comm_func_guid_cmd *req; + struct hclge_desc desc; + int ret; + + req = (struct hclge_comm_func_guid_cmd *)desc.data; + + hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMM_CFG_FUNC_GUID, + false); + req->entry_vld = 0; + ret = hclge_comm_cmd_send(hw, &desc, 1); + if (ret) + dev_warn(&hw->cmq.csq.pdev->dev, + "failed to delete func guid for cmd_send, ret = %d.\n", + ret); +} + +static bool hclge_comm_unic_is_valid_func_guid(u8 *guid) +{ + u8 invalid_guid_zero[UBL_ALEN] = {0}; + u8 invalid_guid_all_one[UBL_ALEN]; + + memset(invalid_guid_all_one, 0xff, UBL_ALEN); + if (!(memcmp(guid, invalid_guid_all_one, HCLGE_COMM_MGUID_PREFIX_LEN) && + memcmp(guid, invalid_guid_zero, UBL_ALEN))) + return false; + + return true; +} + +static void hclge_comm_unic_guid_le_to_net_trans(u8 *src_guid, u8 *dest_guid) +{ + int i; + + for (i = 0; i < UBL_ALEN; i++) + dest_guid[i] = src_guid[UBL_ALEN - i - 1]; +} + +int hclge_comm_unic_get_func_guid(struct hclge_comm_hw *hw, u8 *guid) +{ + struct hclge_desc desc; + bool is_random = false; + int ret; + + hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMM_GET_FUNC_GUID, + true); + ret = hclge_comm_cmd_send(hw, &desc, 1); + if (ret) { + dev_err(&hw->cmq.csq.pdev->dev, + "failed to get function GUID, ret = %d\n", ret); + return ret; + } + + hclge_comm_unic_guid_le_to_net_trans((u8 *)desc.data, guid); + while (unlikely(!hclge_comm_unic_is_valid_func_guid(guid))) { + get_random_bytes(guid, UBL_ALEN); + is_random = true; + } + + if (unlikely(is_random)) + dev_warn(&hw->cmq.csq.pdev->dev, + "using random GUID %02x:%02x:...:%02x:%02x\n", + guid[0], guid[1], + guid[UBL_ALEN - 2], guid[UBL_ALEN - 1]); + + return 0; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h new file mode 100644 index 000000000000..d80405a03046 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HCLGE_COMM_UNIC_ADDR_H +#define __HCLGE_COMM_UNIC_ADDR_H + +#include + +#include "ubl.h" +#include "hclge_comm_cmd.h" + +#define HCLGE_COMM_MGUID_PREFIX_LEN 14 + +#define HCLGE_COMM_FUNC_GUID_ENTRY_VALID_EN 0x01 + +struct hclge_comm_func_guid_cmd { + u8 entry_vld : 1; + u8 lookup_enable : 1; + u8 rsv0 : 6; + u8 rsv1; + __le16 rsv2; + /* use big endian here */ + u8 guid[UBL_ALEN]; + __le16 hit_info; + __le16 rsv3; +}; + +int hclge_comm_unic_set_func_guid(struct hclge_comm_hw *hw, u8 *guid); +int hclge_comm_unic_get_func_guid(struct hclge_comm_hw *hw, u8 *guid); +void hclge_comm_unic_rm_func_guid(struct hclge_comm_hw *hw); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 2305e303df91..0ad547005d27 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -5455,6 +5455,9 @@ static int hns3_init_mac_addr(struct net_device *netdev) u8 mac_addr_temp[ETH_ALEN]; int ret = 0; + if (hns3_ubl_supported(h)) + return 0; + if (h->ae_algo->ops->get_mac_addr) h->ae_algo->ops->get_mac_addr(h, mac_addr_temp); @@ -6043,6 +6046,10 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle) dev_err(priv->dev, "hns3_client_start fail! ret=%d\n", ret); goto err_client_start_fail; } +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(handle)) + hns3_unic_init_guid(netdev); +#endif set_bit(HNS3_NIC_STATE_INITED, &priv->state); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c index 1e43d619d652..577d336acef4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c @@ -47,6 +47,8 @@ void hns3_unic_init(struct net_device *netdev) netdev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); netdev->max_mtu = ae_dev->dev_specs.max_frm_size; + + hns3_unic_init_guid(netdev); } /** @@ -83,6 +85,33 @@ u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info) return UB_UNKNOWN_CFG_TYPE; } +void hns3_unic_init_guid(struct net_device *netdev) +{ + struct hns3_nic_priv *priv = netdev_priv(netdev); + struct hnae3_handle *h = priv->ae_handle; + u8 temp_guid_addr[UBL_ALEN]; + int ret; + + if (!h->ae_algo->ops->get_func_guid || + !h->ae_algo->ops->set_func_guid) { + netdev_err(netdev, "the guid handlers does not exist\n"); + return; + } + + ret = h->ae_algo->ops->get_func_guid(h, temp_guid_addr); + if (ret) { + netdev_err(netdev, "get function guid fail, ret = %d!\n", ret); + return; + } + + memcpy(netdev->dev_addr, temp_guid_addr, netdev->addr_len); + memcpy(netdev->perm_addr, temp_guid_addr, netdev->addr_len); + + ret = h->ae_algo->ops->set_func_guid(h, netdev->dev_addr); + if (ret) + netdev_err(netdev, "set function guid fail, ret = %d\n", ret); +} + #define UNIC_DHCPV4_PROTO 0x0100 void hns3_unic_lp_setup_skb(struct sk_buff *skb) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h index cc202e107cfd..4f3b12e90dd2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h @@ -30,8 +30,10 @@ void hns3_unic_set_default_cc(struct sk_buff *skb); void hns3_unic_init(struct net_device *netdev); void hns3_unic_set_l3_type(struct sk_buff *skb, u32 *type_cs_vlan_tso); u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info); +void hns3_unic_init_guid(struct net_device *netdev); void hns3_unic_lp_setup_skb(struct sk_buff *skb); void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring, struct sk_buff *skb); +void hns3_unic_init_guid(struct net_device *netdev); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index dde17c5425bf..1b21ba01ab6f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -846,7 +846,9 @@ struct hclge_dev_specs_1_cmd { u8 rsv0[2]; __le16 umv_size; __le16 mc_mac_size; - u8 rsv1[6]; + u8 rsv1[2]; + __le16 guid_tbl_space; + u8 rsv[2]; u8 tnl_num; u8 rsv2[5]; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 71459963449c..e6ce71aa294f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -30,6 +30,7 @@ #include "hclge_devlink.h" #include "hclge_comm_cmd.h" #include "hclge_udma.h" +#include "hclge_unic_guid.h" #define HCLGE_NAME "hclge" @@ -1371,12 +1372,27 @@ static void hclge_parse_dev_specs(struct hclge_dev *hdev, ae_dev->dev_specs.umv_size = le16_to_cpu(req1->umv_size); ae_dev->dev_specs.mc_mac_size = le16_to_cpu(req1->mc_mac_size); ae_dev->dev_specs.tnl_num = req1->tnl_num; +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(ae_dev)) + ae_dev->dev_specs.guid_tbl_space = + le16_to_cpu(req1->guid_tbl_space); +#endif } static void hclge_check_dev_specs(struct hclge_dev *hdev) { struct hnae3_dev_specs *dev_specs = &hdev->ae_dev->dev_specs; +#ifdef CONFIG_HNS3_UBL + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); + if (hnae3_dev_ubl_supported(ae_dev)) { + if (!dev_specs->guid_tbl_space) { + dev_warn(&hdev->pdev->dev, + "Can't get guid table size from firmware!\n"); + dev_specs->guid_tbl_space = HCLGE_DEFAULT_GUID_TBL_SIZE; + } + } +#endif if (!dev_specs->max_non_tso_bd_num) dev_specs->max_non_tso_bd_num = HCLGE_MAX_NON_TSO_BD_NUM; if (!dev_specs->rss_ind_tbl_size) @@ -12818,6 +12834,10 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) hclge_ptp_uninit(hdev); hclge_uninit_rxd_adv_layout(hdev); hclge_uninit_mac_table(hdev); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(ae_dev)) + hclge_unic_rm_func_guid(hdev); +#endif hclge_del_all_fd_entries(hdev); if (mac->phydev) @@ -13392,6 +13412,10 @@ struct hnae3_ae_ops hclge_ops = { .get_wol = hclge_get_wol, .set_wol = hclge_set_wol, .priv_ops = hclge_ext_ops_handle, +#ifdef CONFIG_HNS3_UBL + .get_func_guid = hclge_unic_get_func_guid, + .set_func_guid = hclge_unic_set_func_guid, +#endif }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 76fbda6cae0f..2eedb0b61551 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -97,6 +97,7 @@ #define HCLGE_UMV_TBL_SIZE 3072 #define HCLGE_DEFAULT_UMV_SPACE_PER_PF \ (HCLGE_UMV_TBL_SIZE / HCLGE_MAX_PF_NUM) +#define HCLGE_DEFAULT_GUID_TBL_SIZE 64 #define HCLGE_TQP_RESET_TRY_TIMES 200 @@ -287,6 +288,10 @@ struct hclge_mac { __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); }; +#ifndef UBL_ALEN +#define UBL_ALEN 16 +#endif + struct hclge_hw { struct hclge_comm_hw hw; struct hclge_mac mac; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c new file mode 100644 index 000000000000..0b685a1a6837 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include +#include + +#include "ubl.h" +#include "hclge_cmd.h" +#include "hclge_main.h" +#include "hclge_mbx.h" +#include "hclge_unic_guid.h" +#include "hnae3.h" + +int hclge_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + return hclge_comm_unic_set_func_guid(&hdev->hw.hw, guid); +} + +int hclge_unic_get_func_guid(struct hnae3_handle *handle, u8 *guid) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + return hclge_comm_unic_get_func_guid(&hdev->hw.hw, guid); +} + +void hclge_unic_rm_func_guid(struct hclge_dev *hdev) +{ + hclge_comm_unic_rm_func_guid(&hdev->hw.hw); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h new file mode 100644 index 000000000000..2f9fcfb6caa8 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +// Copyright (c) 2023 Hisilicon Limited. + +#ifndef __HCLGE_UNIC_GUID_H +#define __HCLGE_UNIC_GUID_H + +#include + +#include "ubl.h" +#include "hclge_mbx.h" +#include "hclge_comm_unic_addr.h" + +struct hclge_dev; + +int hclge_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid); +int hclge_unic_get_func_guid(struct hnae3_handle *handle, u8 *guid); +void hclge_unic_rm_func_guid(struct hclge_dev *hdev); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index c211d8607002..0a26c440840f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -12,6 +12,7 @@ #include "hclgevf_devlink.h" #include "hclge_comm_rss.h" #include "hclgevf_udma.h" +#include "hclgevf_unic_guid.h" #define HCLGEVF_NAME "hclgevf" @@ -117,8 +118,8 @@ static void hclgevf_get_stats(struct hnae3_handle *handle, u64 *data) hclge_comm_tqps_get_stats(handle, data); } -static void hclgevf_build_send_msg(struct hclge_vf_to_pf_msg *msg, u8 code, - u8 subcode) +void hclgevf_build_send_msg(struct hclge_vf_to_pf_msg *msg, u8 code, + u8 subcode) { if (msg) { memset(msg, 0, sizeof(struct hclge_vf_to_pf_msg)); @@ -3468,6 +3469,10 @@ static const struct hnae3_ae_ops hclgevf_ops = { .get_cmdq_stat = hclgevf_get_cmdq_stat, .request_flush_qb_config = hclgevf_set_fd_qb, .query_fd_qb_state = hclgevf_query_fd_qb_state, +#ifdef CONFIG_HNS3_UBL + .get_func_guid = hclgevf_unic_get_func_guid, + .set_func_guid = hclgevf_unic_set_func_guid, +#endif }; static struct hnae3_ae_algo ae_algovf = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 93eea9a44f09..e09769908d07 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -305,4 +305,6 @@ void hclgevf_mbx_task_schedule(struct hclgevf_dev *hdev); void hclgevf_update_port_base_vlan_info(struct hclgevf_dev *hdev, u16 state, struct hclge_mbx_port_base_vlan *port_base_vlan); struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle); +void hclgevf_build_send_msg(struct hclge_vf_to_pf_msg *msg, u8 code, + u8 subcode); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c new file mode 100644 index 000000000000..c8acaee47b3d --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2023 Hisilicon Limited. + +#include + +#include "ubl.h" +#include "hclgevf_main.h" +#include "hclge_comm_unic_addr.h" +#include "hclge_mbx.h" +#include "hclgevf_unic_guid.h" + +int hclgevf_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + + return hclge_comm_unic_set_func_guid(&hdev->hw.hw, guid); +} + +int hclgevf_unic_get_func_guid(struct hnae3_handle *handle, u8 *guid) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + + return hclge_comm_unic_get_func_guid(&hdev->hw.hw, guid); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h new file mode 100644 index 000000000000..0635940302a5 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +// Copyright (c) 2023 Hisilicon Limited. + +#ifndef __HCLGEVF_UNIC_GUID_H +#define __HCLGEVF_UNIC_GUID_H + +#include + +#include "ubl.h" + +int hclgevf_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid); +int hclgevf_unic_get_func_guid(struct hnae3_handle *handle, u8 *guid); + +#endif -- Gitee From 1cdab7738ac98414f73d5d56f7d643e4398b9bf2 Mon Sep 17 00:00:00 2001 From: Junxin Chen Date: Fri, 1 Sep 2023 17:54:59 +0800 Subject: [PATCH 12/15] UNIC: Supports query, configuration, and management of IP entry driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ---------------------------------------------------------------- When the driver runs in UB mode, it should support get ipv4/6 configuration information from user and configure it to hardware. As network layer of UNIC, the driver is supposed to deliver IPv4/v6 address to the hardware filtering distribution table which is used to filter and deliver packets by searching when receive packets. This patch adds the interface for configuring ip address to hardware by users through kernel and supports driver IP table management in UB mode, which means physical function and virtual function are both able to set IP address to intercept from other source IP address. The driver do the table management after initialization. The table size depends on the hardware and will be divided to private table size of every function and share table size which can be used by all functions. Signed-off-by: Fengyan Mu Signed-off-by: Haibin Lu Signed-off-by: Junxin Chen --- drivers/net/ethernet/hisilicon/hns3/Makefile | 6 +- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 8 + drivers/net/ethernet/hisilicon/hns3/hnae3.h | 12 + .../hns3/hns3_common/hclge_comm_cmd.h | 2 + .../hns3/hns3_common/hclge_comm_unic_addr.c | 226 +++++++ .../hns3/hns3_common/hclge_comm_unic_addr.h | 50 ++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 11 + .../net/ethernet/hisilicon/hns3/hns3_enet.h | 1 + .../net/ethernet/hisilicon/hns3/hns3_unic.c | 93 +++ .../net/ethernet/hisilicon/hns3/hns3_unic.h | 2 + .../hisilicon/hns3/hns3pf/hclge_cmd.h | 20 +- .../hisilicon/hns3/hns3pf/hclge_main.c | 53 +- .../hisilicon/hns3/hns3pf/hclge_main.h | 21 + .../hisilicon/hns3/hns3pf/hclge_mbx.c | 37 + .../hisilicon/hns3/hns3pf/hclge_unic_addr.c | 49 ++ .../hisilicon/hns3/hns3pf/hclge_unic_addr.h | 25 + .../hisilicon/hns3/hns3pf/hclge_unic_guid.c | 1 + .../hisilicon/hns3/hns3pf/hclge_unic_guid.h | 2 - .../hisilicon/hns3/hns3pf/hclge_unic_ip.c | 634 ++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_unic_ip.h | 39 ++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 19 + .../hisilicon/hns3/hns3vf/hclgevf_main.h | 7 + .../hisilicon/hns3/hns3vf/hclgevf_unic_addr.c | 44 ++ .../hisilicon/hns3/hns3vf/hclgevf_unic_addr.h | 25 + .../hisilicon/hns3/hns3vf/hclgevf_unic_ip.c | 146 ++++ .../hisilicon/hns3/hns3vf/hclgevf_unic_ip.h | 28 + 26 files changed, 1553 insertions(+), 8 deletions(-) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.h create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.h create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.h create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.h diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index 458ae9c69945..9e54740bf171 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -23,7 +23,8 @@ obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlink.o hns3vf/hclgevf_regs.o \ hns3_common/hclge_comm_cmd.o hns3_common/hclge_comm_rss.o hns3_common/hclge_comm_tqp_stats.o \ hns3vf/hclgevf_udma.o -hclgevf-$(CONFIG_HNS3_UBL) += hns3_common/hclge_comm_unic_addr.o hns3vf/hclgevf_unic_guid.o +hclgevf-$(CONFIG_HNS3_UBL) += hns3_common/hclge_comm_unic_addr.o hns3vf/hclgevf_unic_ip.o hns3vf/hclgevf_unic_guid.o \ + hns3vf/hclgevf_unic_addr.o obj-$(CONFIG_HNS3_HCLGE) += hclge.o hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_sysfs.o hns3pf/hclge_regs.o \ @@ -32,5 +33,6 @@ hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hc hns3pf/hclge_udma.o hclge-objs += hns3pf/hclge_ext.o -hclge-$(CONFIG_HNS3_UBL) += hns3_common/hclge_comm_unic_addr.o hns3pf/hclge_unic_guid.o +hclge-$(CONFIG_HNS3_UBL) += hns3_common/hclge_comm_unic_addr.o hns3pf/hclge_unic_ip.o hns3pf/hclge_unic_guid.o \ + hns3pf/hclge_unic_addr.o hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 0de9b83c9d4e..0f9e07aee5fe 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -50,6 +50,8 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_SET_QB = 0x28, /* (VF -> PF) set queue bonding */ HCLGE_MBX_PUSH_QB_STATE, /* (PF -> VF) push qb state */ + HCLGE_UNIC_MBX_SET_IP = 0x51, /* (VF -> PF) set ip addr */ + HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ HCLGE_MBX_NCSI_ERROR, /* (M7 -> PF) receive a NCSI error */ @@ -65,6 +67,12 @@ enum hclge_mbx_mac_vlan_subcode { HCLGE_MBX_MAC_VLAN_MC_REMOVE, /* remove MC mac addr */ }; +/* below are per-VF ip table subcodes */ +enum hclge_mbx_ip_table_subcode { + HCLGE_UNIC_MBX_IP_TABLE_ADD = 0, /* add ip addr */ + HCLGE_UNIC_MBX_IP_TABLE_REMOVE, /* remove ip addr */ +}; + /* below are per-VF vlan cfg subcodes */ enum hclge_mbx_vlan_cfg_subcode { HCLGE_MBX_VLAN_FILTER = 0, /* set vlan filter */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index fa72858d66a6..76407550650e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -428,6 +428,7 @@ struct hnae3_dev_specs { u32 mac_stats_num; u8 tnl_num; u16 guid_tbl_space; + u16 ip_tbl_space; }; struct hnae3_client_ops { @@ -462,6 +463,11 @@ struct hnae3_ae_dev { void *priv; }; +enum hnae3_unic_addr_type { + HNAE3_UNIC_IP_ADDR, + HNAE3_UNIC_MCGUID_ADDR +}; + /* This struct defines the operation on the handle. * * init_ae_dev(): (mandatory) @@ -827,6 +833,12 @@ struct hnae3_ae_ops { struct ethtool_wolinfo *wol); int (*priv_ops)(struct hnae3_handle *handle, int opcode, void *data, size_t length); + int (*add_addr)(struct hnae3_handle *handle, + const unsigned char *addr, + enum hnae3_unic_addr_type addr_type); + int (*rm_addr)(struct hnae3_handle *handle, + const unsigned char *addr, + enum hnae3_unic_addr_type addr_type); int (*get_func_guid)(struct hnae3_handle *handle, u8 *guid); int (*set_func_guid)(struct hnae3_handle *handle, u8 *guid); }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h index c5820efd9b45..f7e73a24723f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h @@ -313,6 +313,8 @@ enum hclge_opcode_type { /* UB commands */ HCLGE_OPC_COMM_GET_FUNC_GUID = 0xA001, + HCLGE_OPC_ADD_IP_TBL = 0xA100, + HCLGE_OPC_DEL_IP_TBL = 0xA101, HCLGE_OPC_COMM_CFG_FUNC_GUID = 0xA122, }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c index 0aa455b5d9e4..136ec25d2c45 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.c @@ -14,6 +14,232 @@ #include "hclge_comm_unic_addr.h" +static struct hclge_comm_unic_addr_node * +hclge_comm_unic_find_addr_node(struct list_head *list, const u8 *addr) +{ + struct hclge_comm_unic_addr_node *addr_node, *tmp; + + list_for_each_entry_safe(addr_node, tmp, list, node) + if (hclge_comm_unic_addr_equal((const u8 *)&addr_node->unic_addr, + addr)) + return addr_node; + + return NULL; +} + +static void +hclge_comm_unic_update_addr_node(struct hclge_comm_unic_addr_node *addr_node, + enum HCLGE_COMM_ADDR_NODE_STATE state) +{ + switch (state) { + /* from set_rx_mode or tmp_add_list */ + case HCLGE_COMM_UNIC_ADDR_TO_ADD: + if (addr_node->state == HCLGE_COMM_UNIC_ADDR_TO_DEL) + addr_node->state = HCLGE_COMM_UNIC_ADDR_ACTIVE; + break; + /* only from set_rx_mode */ + case HCLGE_COMM_UNIC_ADDR_TO_DEL: + if (addr_node->state == HCLGE_COMM_UNIC_ADDR_TO_ADD) { + list_del(&addr_node->node); + kfree(addr_node); + } else { + addr_node->state = HCLGE_COMM_UNIC_ADDR_TO_DEL; + } + break; + /* only from tmp_add_list, the addr_node->state won't be + * ACTIVE. + */ + case HCLGE_COMM_UNIC_ADDR_ACTIVE: + if (addr_node->state == HCLGE_COMM_UNIC_ADDR_TO_ADD) + addr_node->state = HCLGE_COMM_UNIC_ADDR_ACTIVE; + break; + } +} + +void hclge_comm_unic_sync_from_addr_del_list(struct list_head *del_list, + struct list_head *addr_list) +{ + struct hclge_comm_unic_addr_node *addr_node, *tmp, *new_node; + + list_for_each_entry_safe(addr_node, tmp, del_list, node) { + new_node = hclge_comm_unic_find_addr_node(addr_list, + addr_node->unic_addr); + if (new_node) { + /* If the addr exists in the addr list, it means + * received a new TO_ADD request during the time window + * of configuring the addr, so we just need + * to change the addr node state to ACTIVE. + */ + new_node->state = HCLGE_COMM_UNIC_ADDR_ACTIVE; + list_del(&addr_node->node); + kfree(addr_node); + } else { + list_move_tail(&addr_node->node, addr_list); + } + } +} + +static void +hclge_comm_unic_sync_from_addr_add_list(struct list_head *add_list, + struct list_head *addr_list, + bool *all_added) +{ + struct hclge_comm_unic_addr_node *addr_node, *tmp, *new_node; + + list_for_each_entry_safe(addr_node, tmp, add_list, node) { + if (*all_added && + addr_node->state == HCLGE_COMM_UNIC_ADDR_TO_ADD) + *all_added = false; + + /* If the addr from tmp_add_list is not in the + * addr_list, it means have received a TO_DEL request + * during the time window of adding the addr. If addr_node + * state is ACTIVE, then change its state to TO_DEL, + * then it will be removed at next time. If is TO_ADD, + * it means this address hasn't been added successfully, + * so just remove the addr node. + */ + new_node = hclge_comm_unic_find_addr_node(addr_list, + addr_node->unic_addr); + if (new_node) { + hclge_comm_unic_update_addr_node(new_node, + addr_node->state); + list_del(&addr_node->node); + kfree(addr_node); + } else if (addr_node->state == HCLGE_COMM_UNIC_ADDR_ACTIVE) { + addr_node->state = HCLGE_COMM_UNIC_ADDR_TO_DEL; + list_move_tail(&addr_node->node, addr_list); + } else { + list_del(&addr_node->node); + kfree(addr_node); + } + } +} + +int hclge_comm_unic_update_addr_list(struct list_head *list, + spinlock_t *addr_list_lock, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const unsigned char *addr) +{ + struct hclge_comm_unic_addr_node *addr_node; + + spin_lock_bh(addr_list_lock); + + /* if the addr is already in the addr list, no need to add a new + * one into it, just check the addr state, convert it to a new + * state, or just remove it, or do nothing. + */ + addr_node = hclge_comm_unic_find_addr_node(list, addr); + if (addr_node) { + hclge_comm_unic_update_addr_node(addr_node, state); + spin_unlock_bh(addr_list_lock); + return 0; + } + + /* if this addr is never added, unnecessary to delete */ + if (state == HCLGE_COMM_UNIC_ADDR_TO_DEL) { + spin_unlock_bh(addr_list_lock); + return -ENOENT; + } + + addr_node = kzalloc(sizeof(*addr_node), GFP_ATOMIC); + if (!addr_node) { + spin_unlock_bh(addr_list_lock); + return -ENOMEM; + } + + addr_node->state = state; + memcpy(addr_node->unic_addr, addr, UNIC_ADDR_LEN); + list_add_tail(&addr_node->node, list); + + spin_unlock_bh(addr_list_lock); + + return 0; +} + +bool hclge_comm_unic_sync_addr_table(struct hnae3_handle *handle, + struct list_head *list, + spinlock_t *addr_list_lock, + void (*sync)(struct hnae3_handle *, + struct list_head *), + void (*unsync)(struct hnae3_handle *, + struct list_head *)) +{ + struct hclge_comm_unic_addr_node *addr_node, *tmp, *new_node; + struct list_head tmp_add_list, tmp_del_list; + bool all_added = true; + + INIT_LIST_HEAD(&tmp_add_list); + INIT_LIST_HEAD(&tmp_del_list); + + /* move the addr to the tmp_add_list and tmp_del_list, then + * we can add/delete these addr outside the spin lock + */ + spin_lock_bh(addr_list_lock); + + list_for_each_entry_safe(addr_node, tmp, list, node) { + switch (addr_node->state) { + case HCLGE_COMM_UNIC_ADDR_TO_DEL: + list_move_tail(&addr_node->node, &tmp_del_list); + break; + case HCLGE_COMM_UNIC_ADDR_TO_ADD: + new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); + if (!new_node) + goto stop_traverse; + memcpy(new_node->unic_addr, addr_node->unic_addr, + UNIC_ADDR_LEN); + new_node->state = addr_node->state; + list_add_tail(&new_node->node, &tmp_add_list); + break; + default: + break; + } + } + +stop_traverse: + spin_unlock_bh(addr_list_lock); + + /* delete first, in order to get max addr table space for adding */ + if (unsync) + unsync(handle, &tmp_del_list); + if (sync) + sync(handle, &tmp_add_list); + + /* if some addr were added/deleted fail, move back to the + * addr_list, and retry at next time. + */ + spin_lock_bh(addr_list_lock); + + hclge_comm_unic_sync_from_addr_del_list(&tmp_del_list, list); + hclge_comm_unic_sync_from_addr_add_list(&tmp_add_list, list, + &all_added); + + spin_unlock_bh(addr_list_lock); + + return all_added; +} + +int hclge_comm_unic_convert_ip_addr(const struct sockaddr *addr, + struct in6_addr *ip_addr) +{ + __be32 v4addr; + + switch (addr->sa_family) { + case AF_INET: + /* we transform ipv4 addr to ipv6 addr for later configuring */ + v4addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + ipv6_addr_set_v4mapped(v4addr, ip_addr); + break; + case AF_INET6: + memcpy(ip_addr, &((struct sockaddr_in6 *)addr)->sin6_addr, + sizeof(struct in6_addr)); + break; + default: + return -EINVAL; + } + return 0; +} + static void hclge_comm_unic_func_guid_cmd_prepare(u8 *guid, struct hclge_comm_func_guid_cmd *req) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h index d80405a03046..bf98a32a66ca 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h @@ -15,12 +15,38 @@ #ifndef __HCLGE_COMM_UNIC_ADDR_H #define __HCLGE_COMM_UNIC_ADDR_H +#include #include +#include #include "ubl.h" +#include "hnae3.h" #include "hclge_comm_cmd.h" +#define HCLGE_COMM_UNIC_IPV6_UPPER_LEN 13 +#define HCLGE_COMM_UNIC_IPV6_LOWER_LEN 3 +#define HCLGE_COMM_UNIC_MSG_IPADDR_POS 1 + +enum HCLGE_COMM_ADDR_NODE_STATE { + HCLGE_COMM_UNIC_ADDR_TO_ADD, + HCLGE_COMM_UNIC_ADDR_TO_DEL, + HCLGE_COMM_UNIC_ADDR_ACTIVE +}; + +#define UNIC_ADDR_LEN 16 #define HCLGE_COMM_MGUID_PREFIX_LEN 14 +struct hclge_comm_unic_addr_node { + struct list_head node; + enum HCLGE_COMM_ADDR_NODE_STATE state; + union { + u8 unic_addr[UNIC_ADDR_LEN]; + struct { + u8 prefix[HCLGE_COMM_MGUID_PREFIX_LEN]; + __le16 proto; + }; + struct in6_addr ip_addr; + }; +}; #define HCLGE_COMM_FUNC_GUID_ENTRY_VALID_EN 0x01 @@ -36,6 +62,30 @@ struct hclge_comm_func_guid_cmd { __le16 rsv3; }; +static inline bool hclge_comm_unic_addr_equal(const u8 *addr1, const u8 *addr2) +{ + const u32 *a = (const u32 *)addr1; + const u32 *b = (const u32 *)addr2; + + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | + (a[2] ^ b[2]) | (a[3] ^ b[3])) == 0; +} + +void hclge_comm_unic_sync_from_addr_del_list(struct list_head *del_list, + struct list_head *addr_list); +int hclge_comm_unic_update_addr_list(struct list_head *list, + spinlock_t *addr_list_lock, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const unsigned char *addr); +bool hclge_comm_unic_sync_addr_table(struct hnae3_handle *handle, + struct list_head *list, + spinlock_t *addr_list_lock, + void (*sync)(struct hnae3_handle *, + struct list_head *), + void (*unsync)(struct hnae3_handle *, + struct list_head *)); +int hclge_comm_unic_convert_ip_addr(const struct sockaddr *addr, + struct in6_addr *ip_addr); int hclge_comm_unic_set_func_guid(struct hclge_comm_hw *hw, u8 *guid); int hclge_comm_unic_get_func_guid(struct hclge_comm_hw *hw, u8 *guid); void hclge_comm_unic_rm_func_guid(struct hclge_comm_hw *hw); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 0ad547005d27..cba5572acfb2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3327,6 +3327,11 @@ static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_select_queue = hns3_nic_select_queue, }; +bool hns3_unic_port_dev_check(const struct net_device *dev) +{ + return dev->netdev_ops == &hns3_unic_netdev_ops; +} + bool hns3_is_phys_func(struct pci_dev *pdev) { u32 dev_id = pdev->device; @@ -6339,6 +6344,9 @@ static int __init hns3_init_module(void) if (ret) goto err_reg_driver; +#ifdef CONFIG_HNS3_UBL + register_ipaddr_notifier(); +#endif return ret; err_reg_driver: @@ -6355,6 +6363,9 @@ module_init(hns3_init_module); */ static void __exit hns3_exit_module(void) { +#ifdef CONFIG_HNS3_UBL + unregister_ipaddr_notifier(); +#endif pci_unregister_driver(&hns3_driver); hnae3_unregister_client(&client); hns3_dbg_unregister_debugfs(); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 1795eff89aae..fb9a9fd7ea36 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -780,6 +780,7 @@ int hns3_init_all_ring(struct hns3_nic_priv *priv); int hns3_nic_reset_all_ring(struct hnae3_handle *h); void hns3_fini_ring(struct hns3_enet_ring *ring); netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev); +bool hns3_unic_port_dev_check(const struct net_device *dev); bool hns3_is_phys_func(struct pci_dev *pdev); int hns3_clean_rx_ring( struct hns3_enet_ring *ring, int budget, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c index 577d336acef4..cf84b0217b77 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c @@ -14,6 +14,11 @@ */ #include +#include +#include +#include +#include +#include #include "ubl.h" #include "hnae3.h" @@ -112,6 +117,94 @@ void hns3_unic_init_guid(struct net_device *netdev) netdev_err(netdev, "set function guid fail, ret = %d\n", ret); } +static int addr_event(struct notifier_block *nb, unsigned long event, + struct sockaddr *sa, struct net_device *ndev) +{ + struct hnae3_handle *handle; + int ret; + + if (ndev->type != ARPHRD_UB) + return NOTIFY_DONE; + + if (!hns3_unic_port_dev_check(ndev)) + return NOTIFY_DONE; + + handle = hns3_get_handle(ndev); + + switch (event) { + case NETDEV_UP: + if (handle->ae_algo->ops->add_addr) { + ret = handle->ae_algo->ops->add_addr(handle, + (const unsigned char *)sa, HNAE3_UNIC_IP_ADDR); + if (ret) + return NOTIFY_BAD; + } else { + return NOTIFY_DONE; + } + break; + case NETDEV_DOWN: + if (handle->ae_algo->ops->rm_addr) { + ret = handle->ae_algo->ops->rm_addr(handle, + (const unsigned char *)sa, HNAE3_UNIC_IP_ADDR); + if (ret) + return NOTIFY_BAD; + } else { + return NOTIFY_DONE; + } + break; + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static int unic_inetaddr_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct in_ifaddr *ifa4 = (struct in_ifaddr *)ptr; + struct net_device *ndev = (struct net_device *)ifa4->ifa_dev->dev; + struct sockaddr_in in; + + in.sin_family = AF_INET; + in.sin_addr.s_addr = ifa4->ifa_address; + + return addr_event(this, event, (struct sockaddr *)&in, ndev); +} + +static int unic_inet6addr_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct inet6_ifaddr *ifa6 = (struct inet6_ifaddr *)ptr; + struct net_device *ndev = (struct net_device *)ifa6->idev->dev; + struct sockaddr_in6 in6; + + in6.sin6_family = AF_INET6; + in6.sin6_addr = ifa6->addr; + + return addr_event(this, event, (struct sockaddr *)&in6, ndev); +} + +static struct notifier_block unic_inetaddr_notifier = { + .notifier_call = unic_inetaddr_event +}; + +static struct notifier_block unic_inet6addr_notifier = { + .notifier_call = unic_inet6addr_event +}; + +void register_ipaddr_notifier(void) +{ + register_inetaddr_notifier(&unic_inetaddr_notifier); + register_inet6addr_notifier(&unic_inet6addr_notifier); +} + +void unregister_ipaddr_notifier(void) +{ + unregister_inetaddr_notifier(&unic_inetaddr_notifier); + unregister_inet6addr_notifier(&unic_inet6addr_notifier); +} + #define UNIC_DHCPV4_PROTO 0x0100 void hns3_unic_lp_setup_skb(struct sk_buff *skb) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h index 4f3b12e90dd2..2b69162235dc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h @@ -34,6 +34,8 @@ void hns3_unic_init_guid(struct net_device *netdev); void hns3_unic_lp_setup_skb(struct sk_buff *skb); void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring, struct sk_buff *skb); +void register_ipaddr_notifier(void); +void unregister_ipaddr_notifier(void); void hns3_unic_init_guid(struct net_device *netdev); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 1b21ba01ab6f..3b2b1831e5da 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -426,6 +426,24 @@ struct hclge_check_mac_addr_cmd { u8 rsv[16]; }; +enum hclge_ip_tbl_opcode { + HCLGE_IP_TBL_ADD, /* Add new or modify ip_table */ + HCLGE_IP_TBL_REMOVE, /* Remove an entry through ip_table key */ + HCLGE_IP_TBL_LKUP, /* Lookup an entry through ip_table key */ +}; + +#define HCLGE_ADD_IP_TBL_OVERFLOW 2 +#define HCLGE_IP_PORT_VFID_S 0 +#define HCLGE_IP_PORT_VFID_M GENMASK(7, 0) + +struct hclge_ip_tbl_entry_cmd { + u8 resp_code; + u8 rsv1[3]; + u8 ipaddr[16]; + __le16 dip_ad; + u8 rsv2[2]; +}; + #define HCLGE_UMV_SPC_ALC_B 0 struct hclge_umv_spc_alc_cmd { u8 allocate; @@ -848,7 +866,7 @@ struct hclge_dev_specs_1_cmd { __le16 mc_mac_size; u8 rsv1[2]; __le16 guid_tbl_space; - u8 rsv[2]; + __le16 ip_tbl_space; u8 tnl_num; u8 rsv2[5]; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index e6ce71aa294f..32637092de85 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -30,7 +30,10 @@ #include "hclge_devlink.h" #include "hclge_comm_cmd.h" #include "hclge_udma.h" +#include "hclge_comm_unic_addr.h" +#include "hclge_unic_ip.h" #include "hclge_unic_guid.h" +#include "hclge_unic_addr.h" #define HCLGE_NAME "hclge" @@ -1373,9 +1376,12 @@ static void hclge_parse_dev_specs(struct hclge_dev *hdev, ae_dev->dev_specs.mc_mac_size = le16_to_cpu(req1->mc_mac_size); ae_dev->dev_specs.tnl_num = req1->tnl_num; #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(ae_dev)) + if (hnae3_dev_ubl_supported(ae_dev)) { ae_dev->dev_specs.guid_tbl_space = le16_to_cpu(req1->guid_tbl_space); + ae_dev->dev_specs.ip_tbl_space = + le16_to_cpu(req1->ip_tbl_space); + } #endif } @@ -1391,6 +1397,11 @@ static void hclge_check_dev_specs(struct hclge_dev *hdev) "Can't get guid table size from firmware!\n"); dev_specs->guid_tbl_space = HCLGE_DEFAULT_GUID_TBL_SIZE; } + if (!dev_specs->ip_tbl_space) { + dev_warn(&hdev->pdev->dev, + "Can't get ip table size from firmware!\n"); + dev_specs->ip_tbl_space = HCLGE_DEFAULT_IP_TBL_SIZE; + } } #endif if (!dev_specs->max_non_tso_bd_num) @@ -1568,6 +1579,11 @@ static int hclge_configure(struct hclge_dev *hdev) hdev->fd_en = true; hdev->fd_active_type = HCLGE_FD_RULE_NONE; } +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(ae_dev)) + hdev->iptbl_info.max_iptbl_size = + hdev->ae_dev->dev_specs.ip_tbl_space; +#endif ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed); if (ret) { @@ -1854,8 +1870,11 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) vport->vf_info.link_state = IFLA_VF_LINK_STATE_AUTO; vport->mps = HCLGE_MAC_DEFAULT_FRAME; #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { vport->mps = UB_DATA_LEN; + INIT_LIST_HEAD(&vport->ip_list); + spin_lock_init(&vport->ip_list_lock); + } #endif vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE; vport->port_base_vlan_cfg.tbl_sta = true; @@ -4745,6 +4764,10 @@ static void hclge_periodic_service_task(struct hclge_dev *hdev) */ hclge_update_link_status(hdev); hclge_sync_mac_table(hdev); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclge_unic_sync_ip_table(hdev); +#endif hclge_sync_promisc_mode(hdev); hclge_sync_fd_qb_mode(hdev); hclge_sync_fd_table(hdev); @@ -8492,6 +8515,10 @@ int hclge_vport_start(struct hclge_vport *vport) if (vport->vport_id) { hclge_restore_mac_table_common(vport); hclge_restore_vport_vlan_table(vport); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclge_unic_restore_ip_table(vport); +#endif } else { hclge_restore_hw_table(hdev); } @@ -10703,6 +10730,10 @@ static void hclge_restore_hw_table(struct hclge_dev *hdev) set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state); clear_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); hclge_restore_fd_entries(handle); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclge_unic_restore_ip_table(vport); +#endif } int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) @@ -12323,6 +12354,14 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) if (ret) goto err_mdiobus_unreg; +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(ae_dev)) { + ret = hclge_unic_init_iptbl_info(hdev); + if (ret) + goto err_mdiobus_unreg; + } +#endif + ret = hclge_mac_init(hdev); if (ret) { dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret); @@ -12700,6 +12739,10 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) memset(hdev->vf_vlan_full, 0, sizeof(hdev->vf_vlan_full)); bitmap_set(hdev->vport_config_block, 0, hdev->num_alloc_vport); hclge_reset_umv_space(hdev); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(ae_dev)) + hclge_unic_reset_iptbl_space(hdev); +#endif } ret = hclge_comm_cmd_init(hdev->ae_dev, &hdev->hw.hw, &hdev->fw_version, @@ -12835,8 +12878,10 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) hclge_uninit_rxd_adv_layout(hdev); hclge_uninit_mac_table(hdev); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(ae_dev)) + if (hnae3_dev_ubl_supported(ae_dev)) { + hclge_unic_uninit_ip_table(hdev); hclge_unic_rm_func_guid(hdev); + } #endif hclge_del_all_fd_entries(hdev); @@ -13413,6 +13458,8 @@ struct hnae3_ae_ops hclge_ops = { .set_wol = hclge_set_wol, .priv_ops = hclge_ext_ops_handle, #ifdef CONFIG_HNS3_UBL + .add_addr = hclge_unic_add_addr, + .rm_addr = hclge_unic_rm_addr, .get_func_guid = hclge_unic_get_func_guid, .set_func_guid = hclge_unic_set_func_guid, #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 2eedb0b61551..cccb9cae89c1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -98,6 +98,7 @@ #define HCLGE_DEFAULT_UMV_SPACE_PER_PF \ (HCLGE_UMV_TBL_SIZE / HCLGE_MAX_PF_NUM) #define HCLGE_DEFAULT_GUID_TBL_SIZE 64 +#define HCLGE_DEFAULT_IP_TBL_SIZE 1024 #define HCLGE_TQP_RESET_TRY_TIMES 200 @@ -814,6 +815,18 @@ struct hclge_vf_vlan_cfg { #pragma pack() +struct unic_ip_table_info { + u16 max_iptbl_size; + /* private ip table space, it's same for PF and its VFs */ + u16 priv_iptbl_size; + /* ip table space shared by PF and its VFs */ + u16 share_iptbl_size; + /* store ip addr to assemble */ + struct sockaddr_in6 ipaddr_to_assemble; + /* save upper ip addr subcode, NOT SET: 255 */ + u8 upper_ip_addr_state; +}; + /* For each bit of TCAM entry, it uses a pair of 'x' and * 'y' to indicate which value to match, like below: * ---------------------------------- @@ -957,6 +970,8 @@ struct hclge_dev { /* multicast mac address number used by PF and its VFs */ u16 used_mc_mac_num; + struct unic_ip_table_info iptbl_info; + DECLARE_KFIFO(mac_tnl_log, struct hclge_mac_tnl_stats, HCLGE_MAC_TNL_LOG_SIZE); @@ -998,6 +1013,7 @@ enum HCLGE_VPORT_STATE { HCLGE_VPORT_STATE_PROMISC_CHANGE, HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, HCLGE_VPORT_STATE_INITED, + HCLGE_VPORT_STATE_IP_TBL_CHANGE, HCLGE_VPORT_STATE_MAX }; @@ -1048,6 +1064,8 @@ struct hclge_vport { u16 used_umv_num; + u16 used_iptbl_num; + u16 vport_id; struct hclge_dev *back; /* Back reference to associated dev */ struct hnae3_handle nic; @@ -1069,6 +1087,9 @@ struct hclge_vport { struct list_head mc_mac_list; /* Store VF multicast table */ struct list_head vlan_list; /* Store VF vlan table */ + + spinlock_t ip_list_lock; /* protect ip address need to add/detele */ + struct list_head ip_list; /* Store VF ip table */ }; struct hclge_speed_bit_map { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index b429f700d4ec..da76b4e54f14 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -5,6 +5,8 @@ #include "hclge_mbx.h" #include "hnae3.h" #include "hclge_comm_rss.h" +#include "hclge_comm_unic_addr.h" +#include "hclge_unic_ip.h" #define CREATE_TRACE_POINTS #include "hclge_trace.h" @@ -825,6 +827,10 @@ static void hclge_handle_vf_tbl(struct hclge_vport *vport, hclge_rm_vport_all_mac_table(vport, true, HCLGE_MAC_ADDR_UC); hclge_rm_vport_all_mac_table(vport, true, HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(vport, true); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclge_unic_rm_vport_all_ip_table(vport, true); +#endif } else { dev_warn(&hdev->pdev->dev, "Invalid cmd(%u)\n", msg_cmd->subcode); @@ -1021,21 +1027,33 @@ static int hclge_mbx_get_link_mode_handler(struct hclge_mbx_ops_param *param) static int hclge_mbx_get_vf_flr_status_handler(struct hclge_mbx_ops_param *param) { + struct hclge_dev *hdev = param->vport->back; + hclge_rm_vport_all_mac_table(param->vport, false, HCLGE_MAC_ADDR_UC); hclge_rm_vport_all_mac_table(param->vport, false, HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(param->vport, false); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclge_unic_rm_vport_all_ip_table(param->vport, false); +#endif return 0; } static int hclge_mbx_vf_uninit_handler(struct hclge_mbx_ops_param *param) { + struct hclge_dev *hdev = param->vport->back; + hclge_rm_vport_all_mac_table(param->vport, true, HCLGE_MAC_ADDR_UC); hclge_rm_vport_all_mac_table(param->vport, true, HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(param->vport, true); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclge_unic_rm_vport_all_ip_table(param->vport, false); +#endif param->vport->mps = 0; return 0; } @@ -1076,6 +1094,22 @@ static int hclge_mbx_handle_vf_qb_handler(struct hclge_mbx_ops_param *param) return 0; } +#ifdef CONFIG_HNS3_UBL +static int +hclge_unic_mbx_set_vf_ip_addr_handler(struct hclge_mbx_ops_param *param) +{ + int ret; + + ret = hclge_unic_set_vf_ip_addr(param->vport, param->req); + if (ret) + dev_err(¶m->vport->back->pdev->dev, + "PF fail(%d) to set VF IP Addr\n", + ret); + + return ret; +} +#endif + static const hclge_mbx_ops_fn hclge_mbx_ops_list[HCLGE_MBX_OPCODE_MAX] = { [HCLGE_MBX_RESET] = hclge_mbx_reset_handler, [HCLGE_MBX_SET_UNICAST] = hclge_mbx_set_unicast_handler, @@ -1101,6 +1135,9 @@ static const hclge_mbx_ops_fn hclge_mbx_ops_list[HCLGE_MBX_OPCODE_MAX] = { [HCLGE_MBX_HANDLE_VF_TBL] = hclge_mbx_handle_vf_tbl_handler, [HCLGE_MBX_GET_RING_VECTOR_MAP] = hclge_mbx_get_ring_vector_map_handler, [HCLGE_MBX_SET_QB] = hclge_mbx_handle_vf_qb_handler, +#ifdef CONFIG_HNS3_UBL + [HCLGE_UNIC_MBX_SET_IP] = hclge_unic_mbx_set_vf_ip_addr_handler, +#endif [HCLGE_MBX_GET_VF_FLR_STATUS] = hclge_mbx_get_vf_flr_status_handler, [HCLGE_MBX_PUSH_LINK_STATUS] = hclge_mbx_push_link_status_handler, [HCLGE_MBX_NCSI_ERROR] = hclge_mbx_ncsi_error_handler, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c new file mode 100644 index 000000000000..b7adcef27a3e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include "hclge_comm_unic_addr.h" +#include "hclge_main.h" +#include "hclge_mbx.h" +#include "hclge_unic_ip.h" +#include "hclge_unic_addr.h" + +int hclge_unic_add_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + + switch (addr_type) { + case HNAE3_UNIC_IP_ADDR: + return hclge_unic_update_ip_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_ADD, + (const struct sockaddr *)addr); + default: + return -EINVAL; + } +} + +int hclge_unic_rm_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + + switch (addr_type) { + case HNAE3_UNIC_IP_ADDR: + return hclge_unic_update_ip_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_DEL, + (const struct sockaddr *)addr); + default: + return -EINVAL; + } +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.h new file mode 100644 index 000000000000..8ad9fbbaad85 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HCLGE_UNIC_ADDR_H +#define __HCLGE_UNIC_ADDR_H + +#include "hnae3.h" + +int hclge_unic_add_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type); +int hclge_unic_rm_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c index 0b685a1a6837..d15ad6af4aec 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c @@ -21,6 +21,7 @@ #include "hclge_main.h" #include "hclge_mbx.h" #include "hclge_unic_guid.h" +#include "hclge_comm_unic_addr.h" #include "hnae3.h" int hclge_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h index 2f9fcfb6caa8..3022fa289965 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h @@ -6,9 +6,7 @@ #include -#include "ubl.h" #include "hclge_mbx.h" -#include "hclge_comm_unic_addr.h" struct hclge_dev; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.c new file mode 100644 index 000000000000..9028fc080aa0 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include +#include +#include +#include + +#include "ubl.h" +#include "hclge_cmd.h" +#include "hclge_main.h" +#include "hclge_comm_cmd.h" +#include "hclge_err.h" +#include "hclge_mbx.h" +#include "hclge_comm_unic_addr.h" +#include "hclge_unic_guid.h" +#include "hclge_unic_ip.h" + +static int hclge_unic_get_ip_tbl_cmd_status(struct hclge_vport *vport, + u16 cmdq_resp, u8 resp_code, + enum hclge_ip_tbl_opcode op) +{ + struct hclge_dev *hdev = vport->back; + + if (cmdq_resp) { + dev_err(&hdev->pdev->dev, + "cmdq execute failed for get_ip_tbl_cmd_status, status=%u.\n", + cmdq_resp); + return -EIO; + } + + if (op == HCLGE_IP_TBL_ADD) { + if (!resp_code || resp_code == 1) + return 0; + else if (resp_code == HCLGE_ADD_IP_TBL_OVERFLOW) + return -ENOSPC; + + dev_err(&hdev->pdev->dev, + "add ip addr failed for undefined, code=%u.\n", + resp_code); + return -EIO; + } else if (op == HCLGE_IP_TBL_REMOVE) { + if (!resp_code) { + return 0; + } else if (resp_code == 1) { + dev_dbg(&hdev->pdev->dev, + "remove ip addr failed for miss.\n"); + return -ENOENT; + } + + dev_err(&hdev->pdev->dev, + "remove ip addr failed for undefined, code=%u.\n", + resp_code); + return -EIO; + } else if (op == HCLGE_IP_TBL_LKUP) { + if (!resp_code) { + return 0; + } else if (resp_code == 1) { + dev_dbg(&hdev->pdev->dev, + "lookup ip addr failed for miss.\n"); + return -ENOENT; + } + + dev_err(&hdev->pdev->dev, + "lookup ip addr failed for undefined, code=%u.\n", + resp_code); + return -EIO; + } + + dev_err(&hdev->pdev->dev, + "unknown opcode for get_ip_tbl_cmd_status, opcode=%d.\n", op); + + return -EINVAL; +} + +static int hclge_unic_remove_ip_tbl(struct hclge_vport *vport, + struct hclge_ip_tbl_entry_cmd *req) +{ + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc; + u8 resp_code; + u16 retval; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_DEL_IP_TBL, false); + + memcpy(desc.data, req, sizeof(struct hclge_ip_tbl_entry_cmd)); + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "del ip addr failed for cmd_send, ret =%d.\n", + ret); + return ret; + } + resp_code = (le32_to_cpu(desc.data[0])) & 0xff; + retval = le16_to_cpu(desc.retval); + + return hclge_unic_get_ip_tbl_cmd_status(vport, retval, resp_code, + HCLGE_IP_TBL_REMOVE); +} + +static int hclge_unic_lookup_ip_tbl(struct hclge_vport *vport, + struct hclge_ip_tbl_entry_cmd *req, + struct hclge_desc *desc) +{ + struct hclge_dev *hdev = vport->back; + u8 resp_code; + u16 retval; + int ret; + + hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_ADD_IP_TBL, true); + + memcpy(desc[0].data, req, sizeof(struct hclge_ip_tbl_entry_cmd)); + + ret = hclge_cmd_send(&hdev->hw, desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "lookup ip addr failed for cmd_send, ret =%d.\n", + ret); + return ret; + } + resp_code = (le32_to_cpu(desc[0].data[0])) & 0xff; + retval = le16_to_cpu(desc[0].retval); + + return hclge_unic_get_ip_tbl_cmd_status(vport, retval, resp_code, + HCLGE_IP_TBL_LKUP); +} + +static int hclge_unic_add_ip_tbl(struct hclge_vport *vport, + struct hclge_ip_tbl_entry_cmd *req) +{ + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc; + u8 resp_code; + u16 retval; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ADD_IP_TBL, false); + + memcpy(desc.data, req, sizeof(struct hclge_ip_tbl_entry_cmd)); + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "add ip addr failed for cmd_send, ret =%d.\n", + ret); + return ret; + } + + resp_code = (le32_to_cpu(desc.data[0])) & 0xff; + retval = le16_to_cpu(desc.retval); + + return hclge_unic_get_ip_tbl_cmd_status(vport, retval, resp_code, + HCLGE_IP_TBL_ADD); +} + +int hclge_unic_init_iptbl_info(struct hclge_dev *hdev) +{ + struct unic_ip_table_info *iptbl_info = &hdev->iptbl_info; + + iptbl_info->priv_iptbl_size = iptbl_info->max_iptbl_size / + (hdev->num_alloc_vport + 1); + iptbl_info->share_iptbl_size = iptbl_info->priv_iptbl_size + + iptbl_info->max_iptbl_size % (hdev->num_alloc_vport + 1); + + memset(&iptbl_info->ipaddr_to_assemble, 0, + sizeof(struct sockaddr_in6)); + iptbl_info->upper_ip_addr_state = HCLGE_UNIC_IP_ADDR_NOTSET; + + return 0; +} + +void hclge_unic_reset_iptbl_space(struct hclge_dev *hdev) +{ + struct unic_ip_table_info *iptbl_info = &hdev->iptbl_info; + struct hclge_vport *vport; + int i; + + for (i = 0; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + vport->used_iptbl_num = 0; + } + + mutex_lock(&hdev->vport_lock); + iptbl_info->share_iptbl_size = iptbl_info->priv_iptbl_size + + iptbl_info->max_iptbl_size % (hdev->num_alloc_vport + 1); + mutex_unlock(&hdev->vport_lock); +} + +static bool hclge_unic_is_iptbl_space_full(struct hclge_vport *vport, + bool need_lock) +{ + struct hclge_dev *hdev = vport->back; + struct unic_ip_table_info *iptbl_info = &hdev->iptbl_info; + bool is_full; + + if (need_lock) + mutex_lock(&hdev->vport_lock); + + is_full = (vport->used_iptbl_num >= iptbl_info->priv_iptbl_size && + iptbl_info->share_iptbl_size == 0); + + if (need_lock) + mutex_unlock(&hdev->vport_lock); + + return is_full; +} + +static void hclge_unic_update_iptbl_space(struct hclge_vport *vport, + bool is_free) +{ + struct hclge_dev *hdev = vport->back; + struct unic_ip_table_info *iptbl_info = &hdev->iptbl_info; + + if (is_free) { + if (vport->used_iptbl_num > iptbl_info->priv_iptbl_size) + iptbl_info->share_iptbl_size++; + + if (vport->used_iptbl_num > 0) + vport->used_iptbl_num--; + } else { + if (vport->used_iptbl_num >= iptbl_info->priv_iptbl_size && + iptbl_info->share_iptbl_size > 0) + iptbl_info->share_iptbl_size--; + vport->used_iptbl_num++; + } +} + +int hclge_unic_update_ip_list(struct hclge_vport *vport, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const struct sockaddr *addr) +{ + struct hclge_dev *hdev = vport->back; + struct in6_addr ip_addr; + int ret; + + hclge_comm_unic_convert_ip_addr(addr, &ip_addr); + + ret = hclge_comm_unic_update_addr_list(&vport->ip_list, + &vport->ip_list_lock, + state, + (const unsigned char *)&ip_addr); + + if (ret == -ENOENT) + dev_err(&hdev->pdev->dev, + "failed to delete ip %pI6c from ip list\n", + ip_addr.s6_addr); + + if (!ret) + set_bit(HCLGE_VPORT_STATE_IP_TBL_CHANGE, &vport->state); + + return ret; +} + +static int hclge_unic_add_ip_addr_common(struct hclge_vport *vport, + struct in6_addr *addr) +{ + struct hclge_dev *hdev = vport->back; + struct hclge_ip_tbl_entry_cmd req; + struct hclge_desc desc; + u16 dip_ad = 0; + int ret; + + memset(&req, 0, sizeof(req)); + + hnae3_set_field(dip_ad, HCLGE_IP_PORT_VFID_M, + HCLGE_IP_PORT_VFID_S, vport->vport_id); + + req.dip_ad = cpu_to_le16(dip_ad); + memcpy(req.ipaddr, addr->s6_addr, sizeof(req.ipaddr)); + + /* Lookup the ip address in the ip address table, and add + * it if the entry is inexistent. Repeated unicast entry + * is not allowed in the ip address table. + */ + ret = hclge_unic_lookup_ip_tbl(vport, &req, &desc); + if (ret == -ENOENT) { + mutex_lock(&hdev->vport_lock); + if (!hclge_unic_is_iptbl_space_full(vport, false)) { + ret = hclge_unic_add_ip_tbl(vport, &req); + if (!ret) + hclge_unic_update_iptbl_space(vport, false); + mutex_unlock(&hdev->vport_lock); + return ret; + } + mutex_unlock(&hdev->vport_lock); + + if (!(vport->overflow_promisc_flags & HNAE3_OVERFLOW_MPE)) + dev_err(&hdev->pdev->dev, "IP table full(%u)\n", + hdev->iptbl_info.priv_iptbl_size); + + return -ENOSPC; + } + + /* check if we just hit the duplicate */ + if (!ret) + return -EEXIST; + + return ret; +} + +static int hclge_unic_rm_ip_addr_common(struct hclge_vport *vport, + struct in6_addr *addr) +{ + struct hclge_dev *hdev = vport->back; + struct hclge_ip_tbl_entry_cmd req; + int ret; + + memset(&req, 0, sizeof(req)); + memcpy(req.ipaddr, addr->s6_addr, sizeof(req.ipaddr)); + ret = hclge_unic_remove_ip_tbl(vport, &req); + if (!ret || ret == -ENOENT) { + mutex_lock(&hdev->vport_lock); + hclge_unic_update_iptbl_space(vport, true); + mutex_unlock(&hdev->vport_lock); + return 0; + } + + return ret; +} + +static void hclge_unic_sync_vport_ip_list(struct hnae3_handle *h, + struct list_head *list) +{ + struct hclge_vport *vport = container_of(h, struct hclge_vport, nic); + struct hclge_comm_unic_addr_node *ip_node, *tmp; + int ret; + + list_for_each_entry_safe(ip_node, tmp, list, node) { + ret = hclge_unic_add_ip_addr_common(vport, &ip_node->ip_addr); + if (!ret) { + ip_node->state = HCLGE_COMM_UNIC_ADDR_ACTIVE; + } else { + set_bit(HCLGE_VPORT_STATE_IP_TBL_CHANGE, + &vport->state); + + if (ret != -EEXIST) + break; + } + } +} + +static void hclge_unic_unsync_vport_ip_list(struct hnae3_handle *h, + struct list_head *list) +{ + struct hclge_vport *vport = container_of(h, struct hclge_vport, nic); + struct hclge_comm_unic_addr_node *ip_node, *tmp; + int ret; + + list_for_each_entry_safe(ip_node, tmp, list, node) { + ret = hclge_unic_rm_ip_addr_common(vport, &ip_node->ip_addr); + if (!ret || ret == -ENOENT) { + list_del(&ip_node->node); + kfree(ip_node); + } else { + set_bit(HCLGE_VPORT_STATE_IP_TBL_CHANGE, + &vport->state); + break; + } + } +} + +static void hclge_unic_sync_vport_ip_table(struct hclge_vport *vport) +{ + void (*unsync)(struct hnae3_handle *h, struct list_head *list); + void (*sync)(struct hnae3_handle *h, struct list_head *list); + bool all_added; + + sync = hclge_unic_sync_vport_ip_list; + unsync = hclge_unic_unsync_vport_ip_list; + all_added = hclge_comm_unic_sync_addr_table(&vport->nic, + &vport->ip_list, + &vport->ip_list_lock, + sync, unsync); + + if (all_added) + vport->overflow_promisc_flags &= ~HNAE3_OVERFLOW_MPE; + else + vport->overflow_promisc_flags |= HNAE3_OVERFLOW_MPE; +} + +static bool hclge_unic_need_sync_ip_table(struct hclge_vport *vport) +{ + struct hclge_dev *hdev = vport->back; + + if (test_bit(vport->vport_id, hdev->vport_config_block)) + return false; + + if (test_and_clear_bit(HCLGE_VPORT_STATE_IP_TBL_CHANGE, &vport->state)) + return true; + + return false; +} + +void hclge_unic_sync_ip_table(struct hclge_dev *hdev) +{ + int i; + + for (i = 0; i < hdev->num_alloc_vport; i++) { + struct hclge_vport *vport = &hdev->vport[i]; + + if (!hclge_unic_need_sync_ip_table(vport)) + continue; + + hclge_unic_sync_vport_ip_table(vport); + } +} + +/* For global reset and imp reset, hardware will clear the ip table, + * so we change the ip state from ACTIVE to TO_ADD, then they + * can be restored in the service task after reset completed. Furtherly, + * the ip address with state TO_DEL are unnecessary to be restored + * after reset, so just remove these ip nodes from ip_list. + */ +void hclge_unic_restore_ip_table(struct hclge_vport *vport) +{ + struct hclge_comm_unic_addr_node *ip_node, *tmp; + struct list_head *list = &vport->ip_list; + + spin_lock_bh(&vport->ip_list_lock); + + list_for_each_entry_safe(ip_node, tmp, list, node) { + if (ip_node->state == HCLGE_COMM_UNIC_ADDR_ACTIVE) { + ip_node->state = HCLGE_COMM_UNIC_ADDR_TO_ADD; + } else if (ip_node->state == HCLGE_COMM_UNIC_ADDR_TO_DEL) { + list_del(&ip_node->node); + kfree(ip_node); + } + } + set_bit(HCLGE_VPORT_STATE_IP_TBL_CHANGE, &vport->state); + + spin_unlock_bh(&vport->ip_list_lock); +} + +static void hclge_unic_build_ip_del_list(struct list_head *list, + bool is_del_list, + struct list_head *tmp_del_list) +{ + struct hclge_comm_unic_addr_node *ip_cfg, *tmp; + + list_for_each_entry_safe(ip_cfg, tmp, list, node) { + switch (ip_cfg->state) { + case HCLGE_COMM_UNIC_ADDR_TO_DEL: + case HCLGE_COMM_UNIC_ADDR_ACTIVE: + list_move_tail(&ip_cfg->node, tmp_del_list); + break; + case HCLGE_COMM_UNIC_ADDR_TO_ADD: + if (is_del_list) { + list_del(&ip_cfg->node); + kfree(ip_cfg); + } + break; + } + } +} + +static void hclge_unic_unsync_ip_del_list(struct hclge_vport *vport, + int (*unsync)(struct hclge_vport *vport, + struct in6_addr *addr), + bool is_del_list, + struct list_head *tmp_del_list) +{ + struct hclge_comm_unic_addr_node *ip_cfg, *tmp; + int ret; + + list_for_each_entry_safe(ip_cfg, tmp, tmp_del_list, node) { + ret = unsync(vport, &ip_cfg->ip_addr); + if (!ret || ret == -ENOENT) { + /* clear all ip addr from hardware, but remain these + * ip addr in the ip list, and restore them after + * vf reset finished. + */ + if (!is_del_list && + ip_cfg->state == HCLGE_COMM_UNIC_ADDR_ACTIVE) { + ip_cfg->state = HCLGE_COMM_UNIC_ADDR_TO_ADD; + } else { + list_del(&ip_cfg->node); + kfree(ip_cfg); + } + } else if (is_del_list) { + ip_cfg->state = HCLGE_COMM_UNIC_ADDR_TO_DEL; + } + } +} + +void hclge_unic_rm_vport_all_ip_table(struct hclge_vport *vport, + bool is_del_list) +{ + int (*unsync)(struct hclge_vport *vport, struct in6_addr *addr); + struct hclge_dev *hdev = vport->back; + struct list_head tmp_del_list, *list; + + list = &vport->ip_list; + unsync = hclge_unic_rm_ip_addr_common; + INIT_LIST_HEAD(&tmp_del_list); + + if (!is_del_list) + set_bit(vport->vport_id, hdev->vport_config_block); + + spin_lock_bh(&vport->ip_list_lock); + hclge_unic_build_ip_del_list(list, is_del_list, &tmp_del_list); + spin_unlock_bh(&vport->ip_list_lock); + + hclge_unic_unsync_ip_del_list(vport, unsync, is_del_list, + &tmp_del_list); + + spin_lock_bh(&vport->ip_list_lock); + hclge_comm_unic_sync_from_addr_del_list(&tmp_del_list, list); + spin_unlock_bh(&vport->ip_list_lock); +} + +/* remove all ip address when uninitailize */ +static void hclge_unic_uninit_vport_ip_list(struct hclge_vport *vport) +{ + struct hclge_comm_unic_addr_node *ip_node, *tmp; + struct hclge_dev *hdev = vport->back; + struct list_head tmp_del_list, *list; + + INIT_LIST_HEAD(&tmp_del_list); + + list = &vport->ip_list; + + spin_lock_bh(&vport->ip_list_lock); + + list_for_each_entry_safe(ip_node, tmp, list, node) { + switch (ip_node->state) { + case HCLGE_COMM_UNIC_ADDR_TO_DEL: + case HCLGE_COMM_UNIC_ADDR_ACTIVE: + list_move_tail(&ip_node->node, &tmp_del_list); + break; + case HCLGE_COMM_UNIC_ADDR_TO_ADD: + list_del(&ip_node->node); + kfree(ip_node); + break; + } + } + + spin_unlock_bh(&vport->ip_list_lock); + + hclge_unic_unsync_vport_ip_list(&vport->nic, &tmp_del_list); + + if (!list_empty(&tmp_del_list)) + dev_warn(&hdev->pdev->dev, + "uninit ip list for vport %u not completely.\n", + vport->vport_id); + + list_for_each_entry_safe(ip_node, tmp, &tmp_del_list, node) { + list_del(&ip_node->node); + kfree(ip_node); + } +} + +void hclge_unic_uninit_ip_table(struct hclge_dev *hdev) +{ + struct hclge_vport *vport; + int i; + + for (i = 0; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + hclge_unic_uninit_vport_ip_list(vport); + } +} + +static int hclge_unic_iptbl_parse_subcode(u8 msg_subcode, + struct hclge_vport *vport, + struct sockaddr *ip_addr) +{ + struct hclge_dev *hdev = vport->back; + + switch (msg_subcode) { + case HCLGE_UNIC_MBX_IP_TABLE_ADD: + return hclge_unic_update_ip_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_ADD, + (const struct sockaddr *)ip_addr); + case HCLGE_UNIC_MBX_IP_TABLE_REMOVE: + return hclge_unic_update_ip_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_DEL, + (const struct sockaddr *)ip_addr); + default: + dev_err(&hdev->pdev->dev, + "failed to set ip addr, unknown subcode %u\n", + msg_subcode); + return -EIO; + } +} + +int hclge_unic_set_vf_ip_addr(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req) +{ + struct hclge_dev *hdev = vport->back; + struct unic_ip_table_info *iptbl_info = &hdev->iptbl_info; + struct sockaddr_in6 *ip_addr = &iptbl_info->ipaddr_to_assemble; + char *lower_ip_addr = &ip_addr->sin6_addr.s6_addr[HCLGE_COMM_UNIC_IPV6_UPPER_LEN]; + char *msg_ip_addr = &mbx_req->msg.data[HCLGE_COMM_UNIC_MSG_IPADDR_POS]; + int ret; + + if (iptbl_info->upper_ip_addr_state == HCLGE_UNIC_IP_ADDR_NOTSET && + mbx_req->msg.data[0] == HCLGE_COMM_UNIC_IPV6_UPPER_LEN) { + memcpy(&ip_addr->sin6_addr.s6_addr, msg_ip_addr, + sizeof(u8) * HCLGE_COMM_UNIC_IPV6_UPPER_LEN); + iptbl_info->upper_ip_addr_state = mbx_req->msg.subcode; + + return 0; + } else if (mbx_req->msg.subcode == iptbl_info->upper_ip_addr_state && + mbx_req->msg.data[0] == HCLGE_COMM_UNIC_IPV6_LOWER_LEN) { + memcpy(lower_ip_addr, msg_ip_addr, + sizeof(u8) * HCLGE_COMM_UNIC_IPV6_LOWER_LEN); + + ip_addr->sin6_family = AF_INET6; + ret = hclge_unic_iptbl_parse_subcode(mbx_req->msg.subcode, + vport, + (struct sockaddr *)ip_addr); + } else { + dev_err(&hdev->pdev->dev, + "failed to configure ip table, unknown subcode %u or different ip addr\n", + mbx_req->msg.subcode); + ret = -EIO; + } + memset(ip_addr, 0, sizeof(struct sockaddr_in6)); + iptbl_info->upper_ip_addr_state = HCLGE_UNIC_IP_ADDR_NOTSET; + + return ret; +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.h new file mode 100644 index 000000000000..f5f6339b7db2 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_ip.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HCLGE_UNIC_IP_H +#define __HCLGE_UNIC_IP_H + +#include +#include +#include + +struct hclge_dev; + +#define HCLGE_UNIC_IP_ADDR_NOTSET 255 + +int hclge_unic_init_iptbl_info(struct hclge_dev *hdev); +void hclge_unic_reset_iptbl_space(struct hclge_dev *hdev); +void hclge_unic_sync_ip_table(struct hclge_dev *hdev); +void hclge_unic_restore_ip_table(struct hclge_vport *vport); +void hclge_unic_rm_vport_all_ip_table(struct hclge_vport *vport, + bool is_del_list); +void hclge_unic_uninit_ip_table(struct hclge_dev *hdev); +int hclge_unic_set_vf_ip_addr(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req); +int hclge_unic_update_ip_list(struct hclge_vport *vport, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const struct sockaddr *addr); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 0a26c440840f..0ac254ea64ea 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -12,7 +12,10 @@ #include "hclgevf_devlink.h" #include "hclge_comm_rss.h" #include "hclgevf_udma.h" +#include "hclge_comm_unic_addr.h" +#include "hclgevf_unic_ip.h" #include "hclgevf_unic_guid.h" +#include "hclgevf_unic_addr.h" #define HCLGEVF_NAME "hclgevf" @@ -1996,6 +1999,10 @@ static void hclgevf_periodic_service_task(struct hclgevf_dev *hdev) hclgevf_sync_mac_table(hdev); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclgevf_unic_sync_ip_list(hdev); +#endif hclgevf_sync_promisc_mode(hdev); hclgevf_update_fd_qb_state(hdev); @@ -2347,6 +2354,12 @@ static void hclgevf_state_init(struct hclgevf_dev *hdev) spin_lock_init(&hdev->mac_table.mac_list_lock); INIT_LIST_HEAD(&hdev->mac_table.uc_mac_list); INIT_LIST_HEAD(&hdev->mac_table.mc_mac_list); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + spin_lock_init(&hdev->ip_table.ip_list_lock); + INIT_LIST_HEAD(&hdev->ip_table.ip_list); + } +#endif /* bring the device down */ set_bit(HCLGEVF_STATE_DOWN, &hdev->state); @@ -3130,6 +3143,10 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev) hclgevf_devlink_uninit(hdev); hclgevf_pci_uninit(hdev); hclgevf_uninit_mac_list(hdev); +#ifdef CONFIG_HNS3_UBL + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + hclgevf_unic_clear_ip_list(hdev); +#endif } static int hclgevf_init_ae_dev(struct hnae3_ae_dev *ae_dev) @@ -3470,6 +3487,8 @@ static const struct hnae3_ae_ops hclgevf_ops = { .request_flush_qb_config = hclgevf_set_fd_qb, .query_fd_qb_state = hclgevf_query_fd_qb_state, #ifdef CONFIG_HNS3_UBL + .add_addr = hclgevf_unic_add_addr, + .rm_addr = hclgevf_unic_rm_addr, .get_func_guid = hclgevf_unic_get_func_guid, .set_func_guid = hclgevf_unic_set_func_guid, #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index e09769908d07..0a0a97f9400e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -207,6 +207,11 @@ struct hclgevf_mac_table_cfg { struct list_head mc_mac_list; }; +struct hclgevf_ip_table_cfg { + spinlock_t ip_list_lock; /* protect ip address need to add/detele */ + struct list_head ip_list; +}; + struct hclgevf_qb_cfg { bool pf_support_qb; bool hw_qb_en; @@ -264,6 +269,8 @@ struct hclgevf_dev { struct hclgevf_mac_table_cfg mac_table; + struct hclgevf_ip_table_cfg ip_table; + struct hclgevf_mbx_resp_status mbx_resp; /* mailbox response */ struct hclgevf_mbx_arq_ring arq; /* mailbox async rx queue */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c new file mode 100644 index 000000000000..d09c911ed291 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include "hclgevf_main.h" +#include "hclge_comm_unic_addr.h" +#include "hclgevf_unic_ip.h" +#include "hclgevf_unic_addr.h" + +int hclgevf_unic_add_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type) +{ + switch (addr_type) { + case HNAE3_UNIC_IP_ADDR: + return hclgevf_unic_update_ip_list(handle, + HCLGE_COMM_UNIC_ADDR_TO_ADD, + (const struct sockaddr *)addr); + default: + return -EINVAL; + } +} + +int hclgevf_unic_rm_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type) +{ + switch (addr_type) { + case HNAE3_UNIC_IP_ADDR: + return hclgevf_unic_update_ip_list(handle, + HCLGE_COMM_UNIC_ADDR_TO_DEL, + (const struct sockaddr *)addr); + default: + return -EINVAL; + } +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.h new file mode 100644 index 000000000000..d3c757d6b5d7 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HCLGEVF_UNIC_ADDR_H +#define __HCLGEVF_UNIC_ADDR_H + +#include "hnae3.h" + +int hclgevf_unic_add_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type); +int hclgevf_unic_rm_addr(struct hnae3_handle *handle, const unsigned char *addr, + enum hnae3_unic_addr_type addr_type); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.c new file mode 100644 index 000000000000..08ee7fc154a1 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include +#include +#include + +#include "hclgevf_main.h" +#include "hclge_comm_unic_addr.h" +#include "hclge_mbx.h" +#include "hclgevf_unic_ip.h" + +int hclgevf_unic_update_ip_list(struct hnae3_handle *handle, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const struct sockaddr *addr) +{ + struct hclgevf_dev *hdev = container_of(handle, struct hclgevf_dev, nic); + struct in6_addr ip_addr; + int ret; + + hclge_comm_unic_convert_ip_addr(addr, &ip_addr); + + ret = hclge_comm_unic_update_addr_list(&hdev->ip_table.ip_list, + &hdev->ip_table.ip_list_lock, + state, + (const unsigned char *)&ip_addr); + + if (ret == -ENOENT) + dev_err(&hdev->pdev->dev, + "failed to delete ip %pI6c from ip list\n", + ip_addr.s6_addr); + + return ret; +} + +static void +hclgevf_unic_prepare_ip_msg(u8 code, int index, + struct hclge_comm_unic_addr_node *ip_node, + struct hclge_vf_to_pf_msg *send_msg) +{ + memset(send_msg, 0, sizeof(struct hclge_vf_to_pf_msg)); + send_msg->code = code; + + if (ip_node->state == HCLGE_COMM_UNIC_ADDR_TO_ADD) + send_msg->subcode = HCLGE_UNIC_MBX_IP_TABLE_ADD; + else + send_msg->subcode = HCLGE_UNIC_MBX_IP_TABLE_REMOVE; + + if (index == 0) { + send_msg->data[0] = HCLGE_COMM_UNIC_IPV6_UPPER_LEN; + memcpy(&send_msg->data[HCLGE_COMM_UNIC_MSG_IPADDR_POS], + &ip_node->ip_addr.s6_addr, + sizeof(u8) * HCLGE_COMM_UNIC_IPV6_UPPER_LEN); + } else { + send_msg->data[0] = HCLGE_COMM_UNIC_IPV6_LOWER_LEN; + memcpy(&send_msg->data[HCLGE_COMM_UNIC_MSG_IPADDR_POS], + &ip_node->ip_addr.s6_addr[HCLGE_COMM_UNIC_IPV6_UPPER_LEN], + sizeof(u8) * HCLGE_COMM_UNIC_IPV6_LOWER_LEN); + } +} + +static int +hclgevf_unic_add_del_ip_addr(struct hclgevf_dev *hdev, + struct hclge_comm_unic_addr_node *ip_node) +{ + struct hclge_vf_to_pf_msg send_msg; + int ret; + + hclgevf_unic_prepare_ip_msg(HCLGE_UNIC_MBX_SET_IP, 0, ip_node, + &send_msg); + ret = hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + if (ret) { + dev_err(&hdev->pdev->dev, + "VF send ip address to PF failed, ret=%d", ret); + return ret; + } + + hclgevf_unic_prepare_ip_msg(HCLGE_UNIC_MBX_SET_IP, 1, ip_node, + &send_msg); + ret = hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + if (ret) { + dev_err(&hdev->pdev->dev, + "VF send ip address to PF failed, ret=%d", ret); + return ret; + } + return 0; +} + +static void hclgevf_unic_config_ip_list(struct hnae3_handle *h, + struct list_head *list) +{ + struct hclgevf_dev *hdev = container_of(h, struct hclgevf_dev, nic); + struct hclge_comm_unic_addr_node *ip_node, *tmp; + int ret; + + list_for_each_entry_safe(ip_node, tmp, list, node) { + ret = hclgevf_unic_add_del_ip_addr(hdev, ip_node); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to configure ip %pI6c, state = %d, ret = %d\n", + ip_node->ip_addr.s6_addr, ip_node->state, ret); + return; + } + if (ip_node->state == HCLGE_COMM_UNIC_ADDR_TO_ADD) { + ip_node->state = HCLGE_COMM_UNIC_ADDR_ACTIVE; + } else { + list_del(&ip_node->node); + kfree(ip_node); + } + } +} + +void hclgevf_unic_clear_ip_list(struct hclgevf_dev *hdev) +{ + struct hclge_comm_unic_addr_node *ip_node, *tmp; + struct list_head *list; + + list = &hdev->ip_table.ip_list; + + spin_lock_bh(&hdev->ip_table.ip_list_lock); + list_for_each_entry_safe(ip_node, tmp, list, node) { + list_del(&ip_node->node); + kfree(ip_node); + } + spin_unlock_bh(&hdev->ip_table.ip_list_lock); +} + +void hclgevf_unic_sync_ip_list(struct hclgevf_dev *hdev) +{ + (void)hclge_comm_unic_sync_addr_table(&hdev->nic, + &hdev->ip_table.ip_list, + &hdev->ip_table.ip_list_lock, + hclgevf_unic_config_ip_list, + hclgevf_unic_config_ip_list); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.h new file mode 100644 index 000000000000..1bbbe24ed5de --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_ip.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HCLGEVF_UNIC_IP_H +#define __HCLGEVF_UNIC_IP_H + +#include +#include +#include + +void hclgevf_unic_sync_ip_list(struct hclgevf_dev *hdev); +void hclgevf_unic_clear_ip_list(struct hclgevf_dev *hdev); +int hclgevf_unic_update_ip_list(struct hnae3_handle *handle, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const struct sockaddr *addr); + +#endif -- Gitee From a1799222294b713b168b8444b973c2b9d69c64d9 Mon Sep 17 00:00:00 2001 From: Junxin Chen Date: Fri, 1 Sep 2023 18:31:16 +0800 Subject: [PATCH 13/15] UNIC: Support using MC GUID and table management driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ----------------------------------------------------- The MC guid is designed to send ub network control packets to the peer end without knowing the peer guid. The packets whose destination address is the MC guid can be sent to all ports that support the MC guid. It is defined as 112-bit 1 and 16-bit protocol. Therefore, the valid data of the MC guid is the last 16 bits. If the peer end supports an MC guid, it indicates that the packets of the corresponding protocol can be processed. The driver implements a new .set_rx_mode for the ub to reuse the ip maddr adding and deleting interfaces. Because the original interface supports only an 8-byte address, only the lower 64 bits of the mc guid can be configured. In addition, the upper 48 bits of the 64 bits must be 1. In terms of hardware entry management, hardware entries are limited and one entry can be shared by multiple functions. Therefore, entries are managed by checking whether the entry exists before being added. In addition, promiscuous entries are enabled when the number of entries is full. In addition, for security purposes, hardware entries cannot be configured for virtual functions. Signed-off-by: Junxin Chen Signed-off-by: Haibin Lu --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 9 +- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 3 +- .../hns3/hns3_common/hclge_comm_cmd.h | 1 + .../hns3/hns3_common/hclge_comm_unic_addr.h | 14 + .../net/ethernet/hisilicon/hns3/hns3_enet.c | 4 +- .../net/ethernet/hisilicon/hns3/hns3_unic.c | 140 ++++- .../net/ethernet/hisilicon/hns3/hns3_unic.h | 26 +- .../hisilicon/hns3/hns3pf/hclge_main.c | 22 +- .../hisilicon/hns3/hns3pf/hclge_main.h | 10 + .../hisilicon/hns3/hns3pf/hclge_mbx.c | 26 +- .../hisilicon/hns3/hns3pf/hclge_unic_addr.c | 9 + .../hisilicon/hns3/hns3pf/hclge_unic_guid.c | 555 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_unic_guid.h | 27 + .../hisilicon/hns3/hns3vf/hclgevf_main.c | 10 +- .../hisilicon/hns3/hns3vf/hclgevf_main.h | 3 + .../hisilicon/hns3/hns3vf/hclgevf_unic_addr.c | 9 + .../hisilicon/hns3/hns3vf/hclgevf_unic_guid.c | 94 +++ .../hisilicon/hns3/hns3vf/hclgevf_unic_guid.h | 5 + 18 files changed, 925 insertions(+), 42 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 0f9e07aee5fe..14e830ff1892 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -50,7 +50,8 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_SET_QB = 0x28, /* (VF -> PF) set queue bonding */ HCLGE_MBX_PUSH_QB_STATE, /* (PF -> VF) push qb state */ - HCLGE_UNIC_MBX_SET_IP = 0x51, /* (VF -> PF) set ip addr */ + HCLGE_MBX_SET_MGUID = 0x50, /* (VF -> PF) set mc guid */ + HCLGE_UNIC_MBX_SET_IP, /* (VF -> PF) set ip addr */ HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ @@ -83,6 +84,12 @@ enum hclge_mbx_vlan_cfg_subcode { HCLGE_MBX_ENABLE_VLAN_FILTER, }; +/* below are per-VF mc guid subcodes */ +enum hclge_mbx_mc_guid_subcode { + HCLGE_MBX_MC_GUID_MC_ADD = 0, /* add new MC guid addr */ + HCLGE_MBX_MC_GUID_MC_DELETE, /* delete MC guid addr */ +}; + enum hclge_mbx_tbl_cfg_subcode { HCLGE_MBX_VPORT_LIST_CLEAR, }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 76407550650e..f26ef5ef21bc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -952,7 +952,8 @@ struct hnae3_udma_private_info { #define HNAE3_BPE BIT(2) /* broadcast promisc enable */ #define HNAE3_OVERFLOW_UPE BIT(3) /* unicast mac vlan overflow */ #define HNAE3_OVERFLOW_MPE BIT(4) /* multicast mac vlan overflow */ -#define HNAE3_UPE (HNAE3_USER_UPE | HNAE3_OVERFLOW_UPE) +#define HNAE3_OVERFLOW_MGP BIT(5) /* multicast guid overflow */ +#define HNAE3_UPE (HNAE3_USER_UPE | HNAE3_OVERFLOW_UPE | HNAE3_OVERFLOW_MGP) #define HNAE3_MPE (HNAE3_USER_MPE | HNAE3_OVERFLOW_MPE) enum hnae3_pflag { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h index f7e73a24723f..9f47d86c37f1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h @@ -316,6 +316,7 @@ enum hclge_opcode_type { HCLGE_OPC_ADD_IP_TBL = 0xA100, HCLGE_OPC_DEL_IP_TBL = 0xA101, HCLGE_OPC_COMM_CFG_FUNC_GUID = 0xA122, + HCLGE_OPC_CFG_MC_GUID_CMD = 0xA123, }; enum hclge_comm_cmd_return_status { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h index bf98a32a66ca..0db62ac8dbcb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_unic_addr.h @@ -40,6 +40,7 @@ struct hclge_comm_unic_addr_node { enum HCLGE_COMM_ADDR_NODE_STATE state; union { u8 unic_addr[UNIC_ADDR_LEN]; + u8 mguid[UBL_ALEN]; struct { u8 prefix[HCLGE_COMM_MGUID_PREFIX_LEN]; __le16 proto; @@ -62,6 +63,19 @@ struct hclge_comm_func_guid_cmd { __le16 rsv3; }; +#define HCLGE_COMM_FORMAT_GUID_ADDR_LEN 48 +#define HCLGE_COMM_FORMAT_GUID_ADDR_PROTO_HIGH 14 +#define HCLGE_COMM_FORMAT_GUID_ADDR_PROTO_LOW 15 + +static inline void hclge_comm_format_guid_addr(char *format_guid_addr, + const u8 *guid_addr) +{ + snprintf(format_guid_addr, HCLGE_COMM_FORMAT_GUID_ADDR_LEN, + "ff:ff:**:**:**:**:**:**:**:**:**:**:**:**:%02x:%02x", + guid_addr[HCLGE_COMM_FORMAT_GUID_ADDR_PROTO_HIGH], + guid_addr[HCLGE_COMM_FORMAT_GUID_ADDR_PROTO_LOW]); +} + static inline bool hclge_comm_unic_addr_equal(const u8 *addr1, const u8 *addr2) { const u32 *a = (const u32 *)addr1; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index cba5572acfb2..26deefda36f1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3288,7 +3288,9 @@ const struct net_device_ops hns3_unic_netdev_ops = { .ndo_features_check = hns3_features_check, .ndo_get_stats64 = hns3_nic_get_stats64, .ndo_setup_tc = hns3_nic_setup_tc, - .ndo_set_rx_mode = hns3_nic_set_rx_mode, +#ifdef CONFIG_HNS3_UBL + .ndo_set_rx_mode = hns3_unic_set_rx_mode, +#endif .ndo_set_vf_trust = hns3_set_vf_trust, #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = hns3_rx_flow_steer, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c index cf84b0217b77..3320d1ad5bd9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.c @@ -90,33 +90,6 @@ u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info) return UB_UNKNOWN_CFG_TYPE; } -void hns3_unic_init_guid(struct net_device *netdev) -{ - struct hns3_nic_priv *priv = netdev_priv(netdev); - struct hnae3_handle *h = priv->ae_handle; - u8 temp_guid_addr[UBL_ALEN]; - int ret; - - if (!h->ae_algo->ops->get_func_guid || - !h->ae_algo->ops->set_func_guid) { - netdev_err(netdev, "the guid handlers does not exist\n"); - return; - } - - ret = h->ae_algo->ops->get_func_guid(h, temp_guid_addr); - if (ret) { - netdev_err(netdev, "get function guid fail, ret = %d!\n", ret); - return; - } - - memcpy(netdev->dev_addr, temp_guid_addr, netdev->addr_len); - memcpy(netdev->perm_addr, temp_guid_addr, netdev->addr_len); - - ret = h->ae_algo->ops->set_func_guid(h, netdev->dev_addr); - if (ret) - netdev_err(netdev, "set function guid fail, ret = %d\n", ret); -} - static int addr_event(struct notifier_block *nb, unsigned long event, struct sockaddr *sa, struct net_device *ndev) { @@ -270,3 +243,116 @@ void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring, dev_kfree_skb_any(skb); } + +static void hns3_unic_extern_mc_guid(u8 *mguid, const unsigned char *addr) +{ + int proto_size = sizeof(u16); + int addr_proto_oft = HNS3_SIMPLE_GUID_LEN - proto_size; + int proto_oft = UBL_ALEN - proto_size; + + memset(mguid, 0xFF, proto_oft); + memcpy(&mguid[proto_oft], &addr[addr_proto_oft], proto_size); +} + +static int hns3_unic_add_mc_guid(struct net_device *netdev, + const unsigned char *addr) +{ + u8 format_simple_guid_addr[HNS3_SIMPLE_FORMAT_GUID_ADDR_LEN] = {0}; + struct hnae3_handle *h = hns3_get_handle(netdev); + u8 mguid[UBL_ALEN] = {0}; + + if (!hns3_unic_mguid_valid_check(addr)) { + hns3_unic_format_sim_guid_addr(format_simple_guid_addr, addr); + netdev_err(netdev, "Add mc guid err! invalid guid: %s\n", + format_simple_guid_addr); + return -EINVAL; + } + + hns3_unic_extern_mc_guid(mguid, addr); + if (h->ae_algo->ops->add_addr) + return h->ae_algo->ops->add_addr(h, (const u8 *)mguid, + HNAE3_UNIC_MCGUID_ADDR); + + return 0; +} + +static int hns3_unic_del_mc_guid(struct net_device *netdev, + const unsigned char *addr) +{ + u8 format_simple_guid_addr[HNS3_SIMPLE_FORMAT_GUID_ADDR_LEN] = {0}; + struct hnae3_handle *h = hns3_get_handle(netdev); + u8 mguid[UBL_ALEN] = {0}; + + if (!hns3_unic_mguid_valid_check(addr)) { + hns3_unic_format_sim_guid_addr(format_simple_guid_addr, addr); + netdev_err(netdev, "Del mc guid err! invalid guid: %s\n", + format_simple_guid_addr); + return -EINVAL; + } + + hns3_unic_extern_mc_guid(mguid, addr); + if (h->ae_algo->ops->rm_addr) + return h->ae_algo->ops->rm_addr(h, (const u8 *)mguid, + HNAE3_UNIC_MCGUID_ADDR); + + return 0; +} + +static u8 hns3_unic_get_netdev_flags(struct net_device *netdev) +{ + u8 flags = 0; + + /* GUID promiscuous multiplexing unicast promiscuous, IP promiscuous + * multiplexing multicast promiscuous + */ + if (netdev->flags & IFF_PROMISC) + flags = HNAE3_USER_UPE | HNAE3_USER_MPE; + + return flags; +} + +void hns3_unic_set_rx_mode(struct net_device *netdev) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + u8 new_flags; + + new_flags = hns3_unic_get_netdev_flags(netdev); + + __dev_mc_sync(netdev, hns3_unic_add_mc_guid, hns3_unic_del_mc_guid); + + h->netdev_flags = new_flags; + hns3_request_update_promisc_mode(h); +} + +void hns3_unic_init_guid(struct net_device *netdev) +{ + const u8 bc_guid[HNS3_SIMPLE_GUID_LEN] = {0xff, 0xff, 0xff, 0xff, + 0xff, 0xff}; + struct hns3_nic_priv *priv = netdev_priv(netdev); + struct hnae3_handle *h = priv->ae_handle; + u8 temp_guid_addr[UBL_ALEN]; + int ret; + + if (!h->ae_algo->ops->get_func_guid || + !h->ae_algo->ops->set_func_guid) { + netdev_err(netdev, "the guid handlers may not exist\n"); + return; + } + + ret = h->ae_algo->ops->get_func_guid(h, temp_guid_addr); + if (ret) { + netdev_err(netdev, "get function guid fail, ret = %d!\n", ret); + return; + } + + memcpy(netdev->dev_addr, temp_guid_addr, netdev->addr_len); + memcpy(netdev->perm_addr, temp_guid_addr, netdev->addr_len); + + ret = h->ae_algo->ops->set_func_guid(h, netdev->dev_addr); + if (ret) { + netdev_err(netdev, "set function guid fail, ret = %d\n", ret); + return; + } + + hns3_unic_add_mc_guid(netdev, bc_guid); +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h index 2b69162235dc..d4071dd72376 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic.h @@ -26,16 +26,40 @@ struct ub_nip_ctrl_fld { unsigned char s_guid[UBL_ALEN]; }; +static inline bool hns3_unic_mguid_valid_check(const u8 *addr) +{ +#define HNS3_UNIC_MCGUID_VALID_PREFIX 0xffffffffu + u32 *upper = (u32 *)addr; + + /* The guid from the user is used as the lower 48 bits of the actual + * guid. Therefore, this interface is used to check only the lower + * 48 bits of the guid. + */ + return *upper == HNS3_UNIC_MCGUID_VALID_PREFIX; +} + +#define HNS3_SIMPLE_FORMAT_GUID_ADDR_LEN 18 +#define HNS3_SIMPLE_GUID_LEN 6 + +static inline void hns3_unic_format_sim_guid_addr(char *format_simple_guid_addr, + const u8 *guid_addr) +{ + snprintf(format_simple_guid_addr, HNS3_SIMPLE_FORMAT_GUID_ADDR_LEN, + "%02x:%02x:%02x:%02x:%02x:%02x", + guid_addr[0], guid_addr[1], guid_addr[2], + guid_addr[3], guid_addr[4], guid_addr[5]); +} + void hns3_unic_set_default_cc(struct sk_buff *skb); void hns3_unic_init(struct net_device *netdev); void hns3_unic_set_l3_type(struct sk_buff *skb, u32 *type_cs_vlan_tso); u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info); -void hns3_unic_init_guid(struct net_device *netdev); void hns3_unic_lp_setup_skb(struct sk_buff *skb); void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring, struct sk_buff *skb); void register_ipaddr_notifier(void); void unregister_ipaddr_notifier(void); +void hns3_unic_set_rx_mode(struct net_device *netdev); void hns3_unic_init_guid(struct net_device *netdev); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 32637092de85..e9159f2988db 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1872,6 +1872,8 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) #ifdef CONFIG_HNS3_UBL if (hnae3_dev_ubl_supported(hdev->ae_dev)) { vport->mps = UB_DATA_LEN; + INIT_LIST_HEAD(&vport->mc_guid_list); + spin_lock_init(&vport->mguid_list_lock); INIT_LIST_HEAD(&vport->ip_list); spin_lock_init(&vport->ip_list_lock); } @@ -4765,8 +4767,10 @@ static void hclge_periodic_service_task(struct hclge_dev *hdev) hclge_update_link_status(hdev); hclge_sync_mac_table(hdev); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclge_unic_sync_mguid_table(hdev); hclge_unic_sync_ip_table(hdev); + } #endif hclge_sync_promisc_mode(hdev); hclge_sync_fd_qb_mode(hdev); @@ -8516,8 +8520,10 @@ int hclge_vport_start(struct hclge_vport *vport) hclge_restore_mac_table_common(vport); hclge_restore_vport_vlan_table(vport); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclge_unic_restore_mc_guid_table(vport); hclge_unic_restore_ip_table(vport); + } #endif } else { hclge_restore_hw_table(hdev); @@ -10731,8 +10737,10 @@ static void hclge_restore_hw_table(struct hclge_dev *hdev) clear_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); hclge_restore_fd_entries(handle); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclge_unic_restore_mc_guid_table(vport); hclge_unic_restore_ip_table(vport); + } #endif } @@ -12740,8 +12748,10 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) bitmap_set(hdev->vport_config_block, 0, hdev->num_alloc_vport); hclge_reset_umv_space(hdev); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(ae_dev)) + if (hnae3_dev_ubl_supported(ae_dev)) { hclge_unic_reset_iptbl_space(hdev); + hclge_unic_reset_mc_guid_space(hdev); + } #endif } @@ -12879,6 +12889,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) hclge_uninit_mac_table(hdev); #ifdef CONFIG_HNS3_UBL if (hnae3_dev_ubl_supported(ae_dev)) { + hclge_unic_uninit_mguid_table(hdev); hclge_unic_uninit_ip_table(hdev); hclge_unic_rm_func_guid(hdev); } @@ -13124,7 +13135,8 @@ static int hclge_sync_vport_promisc_mode(struct hclge_vport *vport) /* for VF */ if (vport->vf_info.trusted) { uc_en = vport->vf_info.request_uc_en > 0 || - vport->overflow_promisc_flags & HNAE3_OVERFLOW_UPE; + vport->overflow_promisc_flags & HNAE3_OVERFLOW_UPE || + vport->overflow_promisc_flags & HNAE3_OVERFLOW_MGP; mc_en = vport->vf_info.request_mc_en > 0 || vport->overflow_promisc_flags & HNAE3_OVERFLOW_MPE; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index cccb9cae89c1..6c9209a51b27 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -853,6 +853,8 @@ struct unic_ip_table_info { #define HCLGE_MAC_TNL_LOG_SIZE 8 #define HCLGE_VPORT_NUM 256 + +#define HCLGE_UNIC_MC_GUID_NUM 64 struct hclge_dev { struct pci_dev *pdev; struct hnae3_ae_dev *ae_dev; @@ -972,6 +974,10 @@ struct hclge_dev { struct unic_ip_table_info iptbl_info; + /* multicast guid number used by PF and its VFs */ + u16 used_mc_guid_num; + DECLARE_BITMAP(mc_guid_tbl_bmap, HCLGE_UNIC_MC_GUID_NUM); + DECLARE_KFIFO(mac_tnl_log, struct hclge_mac_tnl_stats, HCLGE_MAC_TNL_LOG_SIZE); @@ -1013,6 +1019,7 @@ enum HCLGE_VPORT_STATE { HCLGE_VPORT_STATE_PROMISC_CHANGE, HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, HCLGE_VPORT_STATE_INITED, + HCLGE_VPORT_STATE_GUID_TBL_CHANGE, HCLGE_VPORT_STATE_IP_TBL_CHANGE, HCLGE_VPORT_STATE_MAX }; @@ -1088,6 +1095,9 @@ struct hclge_vport { struct list_head vlan_list; /* Store VF vlan table */ + spinlock_t mguid_list_lock; /* protect mc guid need to add/detele */ + struct list_head mc_guid_list; /* Store VF mc guid table */ + spinlock_t ip_list_lock; /* protect ip address need to add/detele */ struct list_head ip_list; /* Store VF ip table */ }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index da76b4e54f14..61e0adb4b2b0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -6,6 +6,7 @@ #include "hnae3.h" #include "hclge_comm_rss.h" #include "hclge_comm_unic_addr.h" +#include "hclge_unic_guid.h" #include "hclge_unic_ip.h" #define CREATE_TRACE_POINTS @@ -828,8 +829,10 @@ static void hclge_handle_vf_tbl(struct hclge_vport *vport, hclge_rm_vport_all_mac_table(vport, true, HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(vport, true); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclge_unic_del_vport_all_mc_guid_table(vport, true); hclge_unic_rm_vport_all_ip_table(vport, true); + } #endif } else { dev_warn(&hdev->pdev->dev, "Invalid cmd(%u)\n", @@ -1035,8 +1038,10 @@ hclge_mbx_get_vf_flr_status_handler(struct hclge_mbx_ops_param *param) HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(param->vport, false); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclge_unic_del_vport_all_mc_guid_table(param->vport, false); hclge_unic_rm_vport_all_ip_table(param->vport, false); + } #endif return 0; } @@ -1051,8 +1056,10 @@ static int hclge_mbx_vf_uninit_handler(struct hclge_mbx_ops_param *param) HCLGE_MAC_ADDR_MC); hclge_rm_vport_all_vlan_table(param->vport, true); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclge_unic_del_vport_all_mc_guid_table(param->vport, false); hclge_unic_rm_vport_all_ip_table(param->vport, false); + } #endif param->vport->mps = 0; return 0; @@ -1095,6 +1102,18 @@ static int hclge_mbx_handle_vf_qb_handler(struct hclge_mbx_ops_param *param) } #ifdef CONFIG_HNS3_UBL +static int hclge_unic_mbx_set_mc_guid_handler(struct hclge_mbx_ops_param *param) +{ + int ret; + + ret = hclge_unic_set_vf_mc_guid(param->vport, param->req); + if (ret) + dev_err(¶m->vport->back->pdev->dev, + "PF fail(%d) to set VF MC guid\n", + ret); + return ret; +} + static int hclge_unic_mbx_set_vf_ip_addr_handler(struct hclge_mbx_ops_param *param) { @@ -1136,6 +1155,7 @@ static const hclge_mbx_ops_fn hclge_mbx_ops_list[HCLGE_MBX_OPCODE_MAX] = { [HCLGE_MBX_GET_RING_VECTOR_MAP] = hclge_mbx_get_ring_vector_map_handler, [HCLGE_MBX_SET_QB] = hclge_mbx_handle_vf_qb_handler, #ifdef CONFIG_HNS3_UBL + [HCLGE_MBX_SET_MGUID] = hclge_unic_mbx_set_mc_guid_handler, [HCLGE_UNIC_MBX_SET_IP] = hclge_unic_mbx_set_vf_ip_addr_handler, #endif [HCLGE_MBX_GET_VF_FLR_STATUS] = hclge_mbx_get_vf_flr_status_handler, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c index b7adcef27a3e..9ae5ca22537f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_addr.c @@ -15,6 +15,7 @@ #include "hclge_comm_unic_addr.h" #include "hclge_main.h" #include "hclge_mbx.h" +#include "hclge_unic_guid.h" #include "hclge_unic_ip.h" #include "hclge_unic_addr.h" @@ -28,6 +29,10 @@ int hclge_unic_add_addr(struct hnae3_handle *handle, const unsigned char *addr, return hclge_unic_update_ip_list(vport, HCLGE_COMM_UNIC_ADDR_TO_ADD, (const struct sockaddr *)addr); + case HNAE3_UNIC_MCGUID_ADDR: + return hclge_unic_update_guid_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_ADD, + addr); default: return -EINVAL; } @@ -43,6 +48,10 @@ int hclge_unic_rm_addr(struct hnae3_handle *handle, const unsigned char *addr, return hclge_unic_update_ip_list(vport, HCLGE_COMM_UNIC_ADDR_TO_DEL, (const struct sockaddr *)addr); + case HNAE3_UNIC_MCGUID_ADDR: + return hclge_unic_update_guid_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_DEL, + addr); default: return -EINVAL; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c index d15ad6af4aec..afbffa0aafc2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.c @@ -20,9 +20,562 @@ #include "hclge_cmd.h" #include "hclge_main.h" #include "hclge_mbx.h" -#include "hclge_unic_guid.h" #include "hclge_comm_unic_addr.h" #include "hnae3.h" +#include "hclge_unic_guid.h" + +static bool hclge_unic_need_sync_guid_table(struct hclge_vport *vport) +{ + struct hclge_dev *hdev = vport->back; + + if (test_bit(vport->vport_id, hdev->vport_config_block)) + return false; + + if (test_and_clear_bit(HCLGE_VPORT_STATE_GUID_TBL_CHANGE, &vport->state)) + return true; + + return false; +} + +int hclge_unic_update_guid_list(struct hclge_vport *vport, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const unsigned char *addr) +{ + char format_guid_addr[HCLGE_COMM_FORMAT_GUID_ADDR_LEN]; + struct hclge_dev *hdev = vport->back; + int ret; + + ret = hclge_comm_unic_update_addr_list(&vport->mc_guid_list, + &vport->mguid_list_lock, + state, addr); + + if (ret == -ENOENT) { + hclge_comm_format_guid_addr(format_guid_addr, addr); + dev_err(&hdev->pdev->dev, + "failed to delete guid %s from mc guid list\n", + format_guid_addr); + } + + if (!ret) + set_bit(HCLGE_VPORT_STATE_GUID_TBL_CHANGE, &vport->state); + + return ret; +} + +static int hclge_unic_lookup_mc_guid(struct hclge_vport *vport, + struct hclge_unic_mc_guid_cfg_cmd *req, + struct hclge_desc *desc) +{ + struct hclge_unic_mc_guid_cfg_cmd *resp; + struct hclge_dev *hdev = vport->back; + u16 resp_code; + u16 retval; + int ret; + + resp = (struct hclge_unic_mc_guid_cfg_cmd *)desc[0].data; + hnae3_set_bit(req->vld_lookup_flag, HCLGE_UNIC_LOOKUP_EN_B, 1); + hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_CFG_MC_GUID_CMD, true); + desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + memcpy(desc[0].data, req, sizeof(struct hclge_unic_mc_guid_cfg_cmd)); + hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_CFG_MC_GUID_CMD, true); + desc[1].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_cmd_setup_basic_desc(&desc[2], HCLGE_OPC_CFG_MC_GUID_CMD, true); + ret = hclge_cmd_send(&hdev->hw, desc, 3); + if (ret) { + dev_err(&hdev->pdev->dev, "lookup mc guid failed for cmd_send, ret = %d\n", + ret); + return ret; + } + resp_code = resp->hit_info; + retval = le16_to_cpu(desc[0].retval); + if (retval) { + dev_err(&hdev->pdev->dev, "cmdq execute failed for lookup mc guid, status = %u.\n", + retval); + return -EIO; + } else if (!(resp_code & HCLGE_UNIC_GUID_HIT)) { + dev_dbg(&hdev->pdev->dev, "lookup mc guid failed for miss.\n"); + return -ENOENT; + } + + return ret; +} + +static int hclge_unic_fill_add_desc(struct hclge_vport *vport, + struct hclge_unic_mc_guid_cfg_cmd *req, + struct hclge_desc *desc, + bool is_new_guid) +{ + struct hclge_unic_mc_guid_cfg_cmd *rsp; + struct hclge_dev *hdev = vport->back; + u16 mc_guid_tbl_size; + + mc_guid_tbl_size = min(HCLGE_UNIC_MC_GUID_NUM, + hdev->ae_dev->dev_specs.guid_tbl_space - + HCLGE_VPORT_NUM); + if (is_new_guid) { + req->index = find_first_zero_bit(hdev->mc_guid_tbl_bmap, + HCLGE_UNIC_MC_GUID_NUM); + if (req->index >= mc_guid_tbl_size) + return -ENOSPC; + } else { + rsp = (struct hclge_unic_mc_guid_cfg_cmd *)desc[0].data; + req->index = rsp->index; + } + + if (vport->vport_id >= HCLGE_VPORT_NUM) + return -EIO; + req->ad_data = req->index; + if (vport->vport_id >= HCLGE_UNIC_BIT_NUM_PER_BD && + test_and_set_bit(vport->vport_id - HCLGE_UNIC_BIT_NUM_PER_BD, + (unsigned long *)&desc[1].data[2])) + return -EEXIST; + else if (test_and_set_bit(vport->vport_id, + (unsigned long *)&desc[2].data[2])) + return -EEXIST; + + return 0; +} + +static int hclge_unic_add_mc_guid_cmd(struct hclge_vport *vport, + struct hclge_unic_mc_guid_cfg_cmd *req, + struct hclge_desc *desc) +{ + struct hclge_dev *hdev = vport->back; + u16 retval; + int ret; + + req->vld_lookup_flag = BIT(HCLGE_UNIC_ENTRY_VLD_B); + hclge_comm_cmd_reuse_desc(&desc[0], false); + desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_comm_cmd_reuse_desc(&desc[1], false); + desc[1].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_comm_cmd_reuse_desc(&desc[2], false); + desc[2].flag &= cpu_to_le16(~HCLGE_COMM_CMD_FLAG_NEXT); + memcpy(desc[0].data, req, sizeof(struct hclge_unic_mc_guid_cfg_cmd)); + ret = hclge_cmd_send(&hdev->hw, desc, 3); + if (ret) { + dev_err(&hdev->pdev->dev, "add mc guid failed, ret = %d\n", ret); + return ret; + } + retval = le16_to_cpu(desc[0].retval); + if (retval) { + dev_err(&hdev->pdev->dev, "cmdq execute failed for add mc guid, status = %u.\n", + retval); + return -EIO; + } + + return 0; +} + +int hclge_unic_add_mc_guid_common(struct hclge_vport *vport, + const unsigned char *mguid) +{ + struct hclge_unic_mc_guid_cfg_cmd req = {0}; + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc[3]; + bool is_new_guid = false; + int ret; + + memcpy(req.mguid, mguid, UBL_ALEN); + ret = hclge_unic_lookup_mc_guid(vport, &req, desc); + if (ret) { + if (hdev->used_mc_guid_num >= + hdev->ae_dev->dev_specs.guid_tbl_space - HCLGE_VPORT_NUM) + goto err_no_space; + is_new_guid = true; + memset(desc[0].data, 0, sizeof(desc[0].data)); + memset(desc[1].data, 0, sizeof(desc[0].data)); + memset(desc[2].data, 0, sizeof(desc[0].data)); + } + + ret = hclge_unic_fill_add_desc(vport, &req, desc, is_new_guid); + if (ret == -EEXIST) + return 0; + if (ret == -ENOSPC) + goto err_no_space; + if (ret) + return ret; + ret = hclge_unic_add_mc_guid_cmd(vport, &req, desc); + if (!ret && is_new_guid) { + set_bit(req.index, hdev->mc_guid_tbl_bmap); + hdev->used_mc_guid_num++; + } + + return 0; +err_no_space: + /* if already overflow, not to print each time */ + if (!(vport->overflow_promisc_flags & HNAE3_OVERFLOW_MGP)) { + vport->overflow_promisc_flags |= HNAE3_OVERFLOW_MGP; + dev_err(&hdev->pdev->dev, "mc guid table is full\n"); + } + + return -ENOSPC; +} + +static bool hclge_unic_is_all_function_deleted(struct hclge_desc *desc) +{ +#define HCLGE_UNIC_DWORD_OF_MGUID 4 + int i; + + for (i = 0; i < HCLGE_UNIC_DWORD_OF_MGUID; i++) { + if (desc[1].data[2 + i] || desc[2].data[2 + i]) + return false; + } + + return true; +} + +static int hclge_unic_fill_del_desc(struct hclge_vport *vport, + struct hclge_unic_mc_guid_cfg_cmd *req, + struct hclge_desc *desc) +{ + struct hclge_unic_mc_guid_cfg_cmd *rsp; + + if (vport->vport_id >= HCLGE_VPORT_NUM) + return -EIO; + rsp = (struct hclge_unic_mc_guid_cfg_cmd *)desc[0].data; + req->index = rsp->index; + req->ad_data = rsp->index; + if (vport->vport_id >= HCLGE_UNIC_BIT_NUM_PER_BD) + clear_bit(vport->vport_id - HCLGE_UNIC_BIT_NUM_PER_BD, + (unsigned long *)&desc[1].data[2]); + else + clear_bit(vport->vport_id, (unsigned long *)&desc[2].data[2]); + + return 0; +} + +static int hclge_unic_del_mc_guid_cmd(struct hclge_vport *vport, + struct hclge_unic_mc_guid_cfg_cmd *req, + struct hclge_desc *desc) +{ + struct hclge_dev *hdev = vport->back; + u16 retval; + int ret; + + req->vld_lookup_flag = 0; + hclge_comm_cmd_reuse_desc(&desc[0], false); + desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_comm_cmd_reuse_desc(&desc[1], false); + desc[1].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_comm_cmd_reuse_desc(&desc[2], false); + desc[2].flag &= cpu_to_le16(~HCLGE_COMM_CMD_FLAG_NEXT); + memcpy(desc[0].data, req, sizeof(struct hclge_unic_mc_guid_cfg_cmd)); + ret = hclge_cmd_send(&hdev->hw, desc, 3); + if (ret) { + dev_err(&hdev->pdev->dev, "del mc guid failed, ret = %d\n", ret); + return ret; + } + retval = le16_to_cpu(desc[0].retval); + if (retval) { + dev_err(&hdev->pdev->dev, "cmdq execute failed for add mc guid, status = %u.\n", + retval); + return -EIO; + } + + return 0; +} + +int hclge_unic_del_mc_guid_common(struct hclge_vport *vport, + const unsigned char *mguid) +{ + struct hclge_unic_mc_guid_cfg_cmd req = {0}; + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc[3]; + int ret; + + memcpy(req.mguid, mguid, UBL_ALEN); + ret = hclge_unic_lookup_mc_guid(vport, &req, desc); + if (!ret) { + ret = hclge_unic_fill_del_desc(vport, &req, desc); + if (ret) + return ret; + if (hclge_unic_is_all_function_deleted(desc)) { + ret = hclge_unic_del_mc_guid_cmd(vport, &req, desc); + if (!ret) { + clear_bit(req.index, hdev->mc_guid_tbl_bmap); + hdev->used_mc_guid_num--; + } + } else { + return hclge_unic_add_mc_guid_cmd(vport, &req, desc); + } + } else if (ret == -ENOENT) { + ret = 0; + } + + return ret; +} + +static void hclge_unic_sync_vport_mguid_list(struct hnae3_handle *h, + struct list_head *list) +{ + struct hclge_vport *vport = container_of(h, struct hclge_vport, nic); + struct hclge_comm_unic_addr_node *guid_node, *tmp; + int ret; + + list_for_each_entry_safe(guid_node, tmp, list, node) { + ret = hclge_unic_add_mc_guid_common(vport, guid_node->mguid); + if (!ret) { + guid_node->state = HCLGE_COMM_UNIC_ADDR_ACTIVE; + } else { + set_bit(HCLGE_VPORT_STATE_GUID_TBL_CHANGE, + &vport->state); + + /* Mc guid can be reusable, even though there is no + * space to add new mc guid, we should check whether + * other mc guid are existing in hardware for reuse. + */ + if (ret != -ENOSPC) + break; + } + } +} + +static void hclge_unic_unsync_vport_mguid_list(struct hnae3_handle *h, + struct list_head *list) +{ + struct hclge_vport *vport = container_of(h, struct hclge_vport, nic); + struct hclge_comm_unic_addr_node *guid_node, *tmp; + int ret; + + list_for_each_entry_safe(guid_node, tmp, list, node) { + ret = hclge_unic_del_mc_guid_common(vport, guid_node->mguid); + if (!ret || ret == -ENOENT) { + list_del(&guid_node->node); + kfree(guid_node); + } else { + set_bit(HCLGE_VPORT_STATE_GUID_TBL_CHANGE, + &vport->state); + break; + } + } +} + +static void hclge_unic_sync_vport_guid_table(struct hclge_vport *vport) +{ + void (*unsync)(struct hnae3_handle *h, struct list_head *list); + void (*sync)(struct hnae3_handle *h, struct list_head *list); + bool all_added; + + sync = hclge_unic_sync_vport_mguid_list; + unsync = hclge_unic_unsync_vport_mguid_list; + all_added = hclge_comm_unic_sync_addr_table(&vport->nic, + &vport->mc_guid_list, + &vport->mguid_list_lock, + sync, unsync); + if (all_added) + vport->overflow_promisc_flags &= ~HNAE3_OVERFLOW_MGP; + else + vport->overflow_promisc_flags |= HNAE3_OVERFLOW_MGP; +} + +void hclge_unic_sync_mguid_table(struct hclge_dev *hdev) +{ + int i; + + for (i = 0; i < hdev->num_alloc_vport; i++) { + struct hclge_vport *vport = &hdev->vport[i]; + + if (!hclge_unic_need_sync_guid_table(vport)) + continue; + hclge_unic_sync_vport_guid_table(vport); + } +} + +/* remove all guid when uninitailize */ +static void hclge_unic_uninit_vport_guid_list(struct hclge_vport *vport) +{ + struct hclge_comm_unic_addr_node *guid_node, *tmp; + struct hclge_dev *hdev = vport->back; + struct list_head tmp_del_list, *list; + + INIT_LIST_HEAD(&tmp_del_list); + + list = &vport->mc_guid_list; + + spin_lock_bh(&vport->mguid_list_lock); + + list_for_each_entry_safe(guid_node, tmp, list, node) { + switch (guid_node->state) { + case HCLGE_COMM_UNIC_ADDR_TO_DEL: + case HCLGE_COMM_UNIC_ADDR_ACTIVE: + list_move_tail(&guid_node->node, &tmp_del_list); + break; + case HCLGE_COMM_UNIC_ADDR_TO_ADD: + list_del(&guid_node->node); + kfree(guid_node); + break; + } + } + + spin_unlock_bh(&vport->mguid_list_lock); + + hclge_unic_unsync_vport_mguid_list(&vport->nic, &tmp_del_list); + + if (!list_empty(&tmp_del_list)) + dev_warn(&hdev->pdev->dev, + "uninit mguid list for vport %u not completely.\n", + vport->vport_id); + + list_for_each_entry_safe(guid_node, tmp, &tmp_del_list, node) { + list_del(&guid_node->node); + kfree(guid_node); + } +} + +void hclge_unic_uninit_mguid_table(struct hclge_dev *hdev) +{ + struct hclge_vport *vport; + int i; + + for (i = 0; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + hclge_unic_uninit_vport_guid_list(vport); + } + bitmap_zero(hdev->mc_guid_tbl_bmap, HCLGE_UNIC_MC_GUID_NUM); +} + +int hclge_unic_set_vf_mc_guid(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req) +{ + __le16 proto = *(__le16 *)(mbx_req->msg.data); + struct hclge_dev *hdev = vport->back; + __le16 *mguid_proto = NULL; + u8 mguid[UBL_ALEN]; + int ret = 0; + + memset(mguid, 0xff, UBL_ALEN); + mguid_proto = (__le16 *)&mguid[HCLGE_COMM_MGUID_PREFIX_LEN]; + *mguid_proto = proto; + + if (mbx_req->msg.subcode == HCLGE_MBX_MC_GUID_MC_ADD) { + ret = hclge_unic_update_guid_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_ADD, + (const u8 *)mguid); + } else if (mbx_req->msg.subcode == HCLGE_MBX_MC_GUID_MC_DELETE) { + ret = hclge_unic_update_guid_list(vport, + HCLGE_COMM_UNIC_ADDR_TO_DEL, + (const u8 *)mguid); + } else { + dev_err(&hdev->pdev->dev, + "failed to set mc guid, unknown subcode %u\n", + mbx_req->msg.subcode); + return -EIO; + } + + return ret; +} + +/* For global reset and imp reset, hardware will clear the guid table, + * so we change the guid state from ACTIVE to TO_ADD, then they + * can be restored in the service task after reset complete. Furtherly, + * the guid with state TO_DEL or DEL_FAIL are unnecessary to + * be restored after reset, so just remove these guid nodes from guid_list. + */ +void hclge_unic_restore_mc_guid_table(struct hclge_vport *vport) +{ + struct hclge_comm_unic_addr_node *guid_node, *tmp; + struct list_head *list = &vport->mc_guid_list; + + spin_lock_bh(&vport->mguid_list_lock); + + list_for_each_entry_safe(guid_node, tmp, list, node) { + if (guid_node->state == HCLGE_COMM_UNIC_ADDR_ACTIVE) { + guid_node->state = HCLGE_COMM_UNIC_ADDR_TO_ADD; + } else if (guid_node->state == HCLGE_COMM_UNIC_ADDR_TO_DEL) { + list_del(&guid_node->node); + kfree(guid_node); + } + } + set_bit(HCLGE_VPORT_STATE_GUID_TBL_CHANGE, &vport->state); + + spin_unlock_bh(&vport->mguid_list_lock); +} + +static void hclge_unic_build_del_list(struct list_head *list, + bool is_del_list, + struct list_head *tmp_del_list) +{ + struct hclge_comm_unic_addr_node *guid_node, *tmp; + + list_for_each_entry_safe(guid_node, tmp, list, node) { + switch (guid_node->state) { + case HCLGE_COMM_UNIC_ADDR_TO_DEL: + case HCLGE_COMM_UNIC_ADDR_ACTIVE: + list_move_tail(&guid_node->node, tmp_del_list); + break; + case HCLGE_COMM_UNIC_ADDR_TO_ADD: + if (is_del_list) { + list_del(&guid_node->node); + kfree(guid_node); + } + break; + } + } +} + +static void hclge_unic_unsync_del_list(struct hclge_vport *vport, + int (*unsync)(struct hclge_vport *vport, + const unsigned char *mguid), + bool is_del_list, + struct list_head *tmp_del_list) +{ + struct hclge_comm_unic_addr_node *guid_node, *tmp; + int ret; + + list_for_each_entry_safe(guid_node, tmp, tmp_del_list, node) { + ret = unsync(vport, guid_node->mguid); + if (!ret || ret == -ENOENT) { + /* clear all mac addr from hardware, but remain these + * mac addr in the mac list, and restore them after + * vf reset finished. + */ + if (!is_del_list && + guid_node->state == HCLGE_COMM_UNIC_ADDR_ACTIVE) { + guid_node->state = HCLGE_COMM_UNIC_ADDR_TO_ADD; + } else { + list_del(&guid_node->node); + kfree(guid_node); + } + } else if (is_del_list) { + guid_node->state = HCLGE_COMM_UNIC_ADDR_TO_DEL; + } + } +} + +void hclge_unic_del_vport_all_mc_guid_table(struct hclge_vport *vport, + bool is_del_list) +{ + struct hclge_dev *hdev = vport->back; + struct list_head tmp_del_list, *list; + + list = &vport->mc_guid_list; + INIT_LIST_HEAD(&tmp_del_list); + + if (!is_del_list) + set_bit(vport->vport_id, hdev->vport_config_block); + + spin_lock_bh(&vport->mguid_list_lock); + + hclge_unic_build_del_list(list, is_del_list, &tmp_del_list); + + spin_unlock_bh(&vport->mguid_list_lock); + + hclge_unic_unsync_del_list(vport, hclge_unic_del_mc_guid_common, + is_del_list, &tmp_del_list); + + spin_lock_bh(&vport->mguid_list_lock); + + hclge_comm_unic_sync_from_addr_del_list(&tmp_del_list, list); + + spin_unlock_bh(&vport->mguid_list_lock); +} + +void hclge_unic_reset_mc_guid_space(struct hclge_dev *hdev) +{ + hdev->used_mc_guid_num = 0; + bitmap_zero(hdev->mc_guid_tbl_bmap, HCLGE_UNIC_MC_GUID_NUM); +} int hclge_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h index 3022fa289965..c9b66400f51d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_unic_guid.h @@ -10,6 +10,33 @@ struct hclge_dev; +struct hclge_unic_mc_guid_cfg_cmd { + __le16 index; + u8 vld_lookup_flag; + u8 rsvd; + u8 mguid[UBL_ALEN]; + __le16 ad_data; + __le16 hit_info; +}; + +#define HCLGE_UNIC_BIT_NUM_PER_BD 128 + +#define HCLGE_UNIC_ENTRY_VLD_B 0 +#define HCLGE_UNIC_LOOKUP_EN_B 1 + +#define HCLGE_UNIC_GUID_HIT BIT(15) + +void hclge_unic_sync_mguid_table(struct hclge_dev *hdev); +void hclge_unic_uninit_mguid_table(struct hclge_dev *hdev); +int hclge_unic_set_vf_mc_guid(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req); +void hclge_unic_restore_mc_guid_table(struct hclge_vport *vport); +void hclge_unic_reset_mc_guid_space(struct hclge_dev *hdev); +void hclge_unic_del_vport_all_mc_guid_table(struct hclge_vport *vport, + bool is_del_list); +int hclge_unic_update_guid_list(struct hclge_vport *vport, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const unsigned char *addr); int hclge_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid); int hclge_unic_get_func_guid(struct hnae3_handle *handle, u8 *guid); void hclge_unic_rm_func_guid(struct hclge_dev *hdev); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 0ac254ea64ea..0a381de67749 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -2000,8 +2000,10 @@ static void hclgevf_periodic_service_task(struct hclgevf_dev *hdev) hclgevf_sync_mac_table(hdev); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclgevf_unic_sync_mc_guid_list(hdev); hclgevf_unic_sync_ip_list(hdev); + } #endif hclgevf_sync_promisc_mode(hdev); @@ -2356,6 +2358,8 @@ static void hclgevf_state_init(struct hclgevf_dev *hdev) INIT_LIST_HEAD(&hdev->mac_table.mc_mac_list); #ifdef CONFIG_HNS3_UBL if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + spin_lock_init(&hdev->mguid_list_lock); + INIT_LIST_HEAD(&hdev->mc_guid_list); spin_lock_init(&hdev->ip_table.ip_list_lock); INIT_LIST_HEAD(&hdev->ip_table.ip_list); } @@ -3144,8 +3148,10 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev) hclgevf_pci_uninit(hdev); hclgevf_uninit_mac_list(hdev); #ifdef CONFIG_HNS3_UBL - if (hnae3_dev_ubl_supported(hdev->ae_dev)) + if (hnae3_dev_ubl_supported(hdev->ae_dev)) { + hclgevf_unic_uninit_mc_guid_list(hdev); hclgevf_unic_clear_ip_list(hdev); + } #endif } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 0a0a97f9400e..699a2afaef0e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -291,6 +291,9 @@ struct hclgevf_dev { struct hclgevf_qb_cfg qb_cfg; struct devlink *devlink; + + spinlock_t mguid_list_lock; /* protect mc guid need to add/detele */ + struct list_head mc_guid_list; /* Store VF mc guid table */ }; static inline bool hclgevf_is_reset_pending(struct hclgevf_dev *hdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c index d09c911ed291..5359563851a5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_addr.c @@ -14,6 +14,7 @@ #include "hclgevf_main.h" #include "hclge_comm_unic_addr.h" +#include "hclgevf_unic_guid.h" #include "hclgevf_unic_ip.h" #include "hclgevf_unic_addr.h" @@ -25,6 +26,10 @@ int hclgevf_unic_add_addr(struct hnae3_handle *handle, const unsigned char *addr return hclgevf_unic_update_ip_list(handle, HCLGE_COMM_UNIC_ADDR_TO_ADD, (const struct sockaddr *)addr); + case HNAE3_UNIC_MCGUID_ADDR: + return hclgevf_unic_update_guid_list(handle, + HCLGE_COMM_UNIC_ADDR_TO_ADD, + addr); default: return -EINVAL; } @@ -38,6 +43,10 @@ int hclgevf_unic_rm_addr(struct hnae3_handle *handle, const unsigned char *addr, return hclgevf_unic_update_ip_list(handle, HCLGE_COMM_UNIC_ADDR_TO_DEL, (const struct sockaddr *)addr); + case HNAE3_UNIC_MCGUID_ADDR: + return hclgevf_unic_update_guid_list(handle, + HCLGE_COMM_UNIC_ADDR_TO_DEL, + addr); default: return -EINVAL; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c index c8acaee47b3d..53b2b206e745 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.c @@ -6,9 +6,103 @@ #include "ubl.h" #include "hclgevf_main.h" #include "hclge_comm_unic_addr.h" +#include "hclge_comm_cmd.h" #include "hclge_mbx.h" #include "hclgevf_unic_guid.h" +int hclgevf_unic_update_guid_list(struct hnae3_handle *handle, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const unsigned char *addr) +{ + struct hclgevf_dev *hdev = container_of(handle, struct hclgevf_dev, nic); + char format_guid_addr[HCLGE_COMM_FORMAT_GUID_ADDR_LEN]; + int ret; + + ret = hclge_comm_unic_update_addr_list(&hdev->mc_guid_list, + &hdev->mguid_list_lock, + state, addr); + + if (ret == -ENOENT) { + hclge_comm_format_guid_addr(format_guid_addr, addr); + dev_err(&hdev->pdev->dev, + "failed to delete guid %s from mc guid list\n", + format_guid_addr); + } + + return ret; +} + +static int +hclgevf_unic_add_del_mc_guid(struct hclgevf_dev *hdev, + struct hclge_comm_unic_addr_node *guid_node) +{ + struct hclge_vf_to_pf_msg send_msg = {0}; + + send_msg.code = HCLGE_MBX_SET_MGUID; + if (guid_node->state == HCLGE_COMM_UNIC_ADDR_TO_ADD) + send_msg.subcode = HCLGE_MBX_MC_GUID_MC_ADD; + else + send_msg.subcode = HCLGE_MBX_MC_GUID_MC_DELETE; + + memcpy(send_msg.data, &guid_node->proto, sizeof(__le16)); + return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); +} + +static void hclgevf_unic_config_mguid_list(struct hnae3_handle *h, + struct list_head *list) +{ + struct hclgevf_dev *hdev = container_of(h, struct hclgevf_dev, nic); + char format_guid_addr[HCLGE_COMM_FORMAT_GUID_ADDR_LEN]; + struct hclge_comm_unic_addr_node *guid_node, *tmp; + int ret; + + list_for_each_entry_safe(guid_node, tmp, list, node) { + ret = hclgevf_unic_add_del_mc_guid(hdev, guid_node); + if (ret) { + hclge_comm_format_guid_addr(format_guid_addr, + guid_node->mguid); + dev_err(&hdev->pdev->dev, + "failed to configure mc guid %s, state = %d, ret = %d\n", + format_guid_addr, guid_node->state, ret); + return; + } + if (guid_node->state == HCLGE_COMM_UNIC_ADDR_TO_ADD) { + guid_node->state = HCLGE_COMM_UNIC_ADDR_ACTIVE; + } else { + list_del(&guid_node->node); + kfree(guid_node); + } + } +} + +void hclgevf_unic_sync_mc_guid_list(struct hclgevf_dev *hdev) +{ + (void)hclge_comm_unic_sync_addr_table(&hdev->nic, + &hdev->mc_guid_list, + &hdev->mguid_list_lock, + hclgevf_unic_config_mguid_list, + hclgevf_unic_config_mguid_list); +} + +static void hclgevf_unic_clear_guid_list(struct list_head *list) +{ + struct hclge_comm_unic_addr_node *guid_node, *tmp; + + list_for_each_entry_safe(guid_node, tmp, list, node) { + list_del(&guid_node->node); + kfree(guid_node); + } +} + +void hclgevf_unic_uninit_mc_guid_list(struct hclgevf_dev *hdev) +{ + spin_lock_bh(&hdev->mguid_list_lock); + + hclgevf_unic_clear_guid_list(&hdev->mc_guid_list); + + spin_unlock_bh(&hdev->mguid_list_lock); +} + int hclgevf_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h index 0635940302a5..faf9c90106d9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_unic_guid.h @@ -8,6 +8,11 @@ #include "ubl.h" +void hclgevf_unic_sync_mc_guid_list(struct hclgevf_dev *hdev); +void hclgevf_unic_uninit_mc_guid_list(struct hclgevf_dev *hdev); +int hclgevf_unic_update_guid_list(struct hnae3_handle *handle, + enum HCLGE_COMM_ADDR_NODE_STATE state, + const unsigned char *addr); int hclgevf_unic_set_func_guid(struct hnae3_handle *handle, u8 *guid); int hclgevf_unic_get_func_guid(struct hnae3_handle *handle, u8 *guid); -- Gitee From 97d2f80908920509797ff7c0459fd5545d95234d Mon Sep 17 00:00:00 2001 From: Haibin Lu Date: Tue, 18 Apr 2023 21:18:22 +0800 Subject: [PATCH 14/15] UNIC: Debugfs supports query of ip and guid table's list and specification driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA ----------------------------------------------------------------- IP table and GUID table specification including function number, address and state of the table which have been configured to hardware is significant for user to choose the scheme of using the table. This patch is to use debugfs to query the specification and list of the IP and GUID table. Signed-off-by: Haibin Lu Signed-off-by: Junxin Chen --- drivers/net/ethernet/hisilicon/hns3/Makefile | 2 +- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 5 + .../ethernet/hisilicon/hns3/hns3_debugfs.c | 13 + .../hisilicon/hns3/hns3_unic_debugfs.c | 233 ++++++++++++++++++ .../hisilicon/hns3/hns3_unic_debugfs.h | 28 +++ .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 174 ++++++++++++- .../hisilicon/hns3/hns3pf/hclge_udma.c | 2 +- 7 files changed, 451 insertions(+), 6 deletions(-) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.h diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index 9e54740bf171..bd5aea7dd490 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -16,7 +16,7 @@ hns3-objs = hns3_enet.o hns3_ethtool.o hns3_debugfs.o hns3-objs += hns3_ext.o hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o -hns3-$(CONFIG_HNS3_UBL) += hns3_unic.o +hns3-$(CONFIG_HNS3_UBL) += hns3_unic.o hns3_unic_debugfs.o obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index f26ef5ef21bc..0d6137ed357b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -371,6 +371,10 @@ enum hnae3_dbg_cmd { HNAE3_DBG_CMD_PAGE_POOL_INFO, HNAE3_DBG_CMD_COAL_INFO, HNAE3_DBG_CMD_WOL_INFO, + HNAE3_DBG_CMD_IP_SPEC, + HNAE3_DBG_CMD_GUID_SPEC, + HNAE3_DBG_CMD_IP_LIST, + HNAE3_DBG_CMD_GUID_LIST, HNAE3_DBG_CMD_UNKNOWN, }; @@ -987,6 +991,7 @@ struct hnae3_handle { /* protects concurrent contention between debugfs commands */ struct mutex dbgfs_lock; char **dbgfs_buf; + char **ub_dbgfs_buf; /* Network interface message level enabled bits */ u32 msg_enable; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 00d3de71de01..5cdfa8e06ddf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -7,6 +7,7 @@ #include "hnae3.h" #include "hns3_debugfs.h" #include "hns3_enet.h" +#include "hns3_unic_debugfs.h" static struct dentry *hns3_dbgfs_root; @@ -1415,6 +1416,13 @@ int hns3_dbg_init(struct hnae3_handle *handle) goto out; } } +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(handle)) { + ret = hns3_unic_dbg_init(handle, handle->hnae3_dbgfs); + if (ret) + goto out; + } +#endif return 0; @@ -1432,6 +1440,11 @@ void hns3_dbg_uninit(struct hnae3_handle *handle) debugfs_remove_recursive(handle->hnae3_dbgfs); handle->hnae3_dbgfs = NULL; +#ifdef CONFIG_HNS3_UBL + if (hns3_ubl_supported(handle)) + hns3_unic_dbg_uninit(handle); +#endif + for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) if (handle->dbgfs_buf[i]) { kvfree(handle->dbgfs_buf[i]); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.c new file mode 100644 index 000000000000..1d68fd31636e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include + +#include "hnae3.h" +#include "hns3_debugfs.h" +#include "hns3_enet.h" +#include "hns3_unic_debugfs.h" + +static const char ub_dbg_root_name[] = "ub"; +static struct dentry *ub_dbg_root; + +static struct hns3_dbg_dentry_info ub_dbg_dentry[] = { + { + .name = "ip_tbl" + }, + { + .name = "guid_tbl" + }, +}; + +static int hns3_unic_dbg_file_init(struct hnae3_handle *handle, u32 cmd); + +static const struct hns3_dbg_cmd_info ub_dbg_cmd[] = { + { + .name = "ip_tbl_spec", + .cmd = HNAE3_DBG_CMD_IP_SPEC, + .dentry = UB_DBG_DENTRY_IP, + .buf_len = HNS3_DBG_READ_LEN, + .init = hns3_unic_dbg_file_init, + }, + { + .name = "guid_tbl_spec", + .cmd = HNAE3_DBG_CMD_GUID_SPEC, + .dentry = UB_DBG_DENTRY_GUID, + .buf_len = HNS3_DBG_READ_LEN, + .init = hns3_unic_dbg_file_init, + }, + { + .name = "ip_tbl_list", + .cmd = HNAE3_DBG_CMD_IP_LIST, + .dentry = UB_DBG_DENTRY_IP, + .buf_len = HNS3_DBG_READ_LEN, + .init = hns3_unic_dbg_file_init, + }, + { + .name = "guid_tbl_list", + .cmd = HNAE3_DBG_CMD_GUID_LIST, + .dentry = UB_DBG_DENTRY_GUID, + .buf_len = HNS3_DBG_READ_LEN, + .init = hns3_unic_dbg_file_init, + }, +}; + +static int hns3_unic_dbg_get_cmd_index(struct hns3_dbg_data *dbg_data, + u32 *index) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(ub_dbg_cmd); i++) { + if (ub_dbg_cmd[i].cmd == dbg_data->cmd) { + *index = i; + return 0; + } + } + + dev_err(&dbg_data->handle->pdev->dev, "unknown unic command(%d)\n", + dbg_data->cmd); + return -EINVAL; +} + +static int hns3_unic_dbg_read_cmd(struct hns3_dbg_data *dbg_data, + enum hnae3_dbg_cmd cmd, char *buf, int len) +{ + const struct hnae3_ae_ops *ops = dbg_data->handle->ae_algo->ops; + + if (!ops->dbg_read_cmd) + return -EOPNOTSUPP; + + return ops->dbg_read_cmd(dbg_data->handle, cmd, buf, len); +} + +static ssize_t hns3_unic_dbg_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct hns3_dbg_data *dbg_data = filp->private_data; + struct hnae3_handle *handle = dbg_data->handle; + struct hns3_nic_priv *priv = handle->priv; + char **save_buf; + char *read_buf; + ssize_t size; + u32 index; + int ret; + + ret = hns3_unic_dbg_get_cmd_index(dbg_data, &index); + if (ret) + return ret; + + mutex_lock(&handle->dbgfs_lock); + save_buf = &handle->ub_dbgfs_buf[index]; + + if (!test_bit(HNS3_NIC_STATE_INITED, &priv->state) || + test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) { + ret = -EBUSY; + goto out; + } + + if (*save_buf) { + read_buf = *save_buf; + } else { + read_buf = kvzalloc(ub_dbg_cmd[index].buf_len, GFP_KERNEL); + if (!read_buf) { + ret = -ENOMEM; + goto out; + } + + /* save the buffer addr until the last read operation */ + *save_buf = read_buf; + + /* get data ready for the first time to read */ + ret = hns3_unic_dbg_read_cmd(dbg_data, ub_dbg_cmd[index].cmd, + read_buf, + ub_dbg_cmd[index].buf_len); + if (ret) + goto out; + } + + size = simple_read_from_buffer(buffer, count, ppos, read_buf, + strlen(read_buf)); + if (size > 0) { + mutex_unlock(&handle->dbgfs_lock); + return size; + } + +out: + /* free the buffer for the last read operation */ + if (*save_buf) { + kvfree(*save_buf); + *save_buf = NULL; + } + + mutex_unlock(&handle->dbgfs_lock); + return ret; +} + +static const struct file_operations ub_dbg_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = hns3_unic_dbg_read, +}; + +static int hns3_unic_dbg_file_init(struct hnae3_handle *handle, u32 cmd) +{ + struct hns3_dbg_data *data; + struct dentry *entry_dir; + + data = devm_kzalloc(&handle->pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->handle = handle; + data->cmd = ub_dbg_cmd[cmd].cmd; + entry_dir = ub_dbg_dentry[ub_dbg_cmd[cmd].dentry].dentry; + debugfs_create_file(ub_dbg_cmd[cmd].name, 0400, entry_dir, + data, &ub_dbg_fops); + + return 0; +} + +int hns3_unic_dbg_init(struct hnae3_handle *handle, struct dentry *parent) +{ + int ret = 0; + u32 i; + + if (!parent) + return -EINVAL; + + handle->ub_dbgfs_buf = devm_kcalloc(&handle->pdev->dev, + ARRAY_SIZE(ub_dbg_cmd), + sizeof(*handle->ub_dbgfs_buf), + GFP_KERNEL); + if (!handle->ub_dbgfs_buf) + return -ENOMEM; + + ub_dbg_root = debugfs_create_dir(ub_dbg_root_name, parent); + + for (i = 0; i < UB_DBG_DENTRY_END; i++) + ub_dbg_dentry[i].dentry = + debugfs_create_dir(ub_dbg_dentry[i].name, ub_dbg_root); + + for (i = 0; i < ARRAY_SIZE(ub_dbg_cmd); i++) { + if (!ub_dbg_cmd[i].init) { + dev_err(&handle->pdev->dev, + "cmd %s lack of init func\n", + ub_dbg_cmd[i].name); + ret = -EINVAL; + break; + } + + ret = ub_dbg_cmd[i].init(handle, i); + if (ret) { + dev_err(&handle->pdev->dev, "failed to init cmd %s\n", + ub_dbg_cmd[i].name); + break; + } + } + + return ret; +} + +void hns3_unic_dbg_uninit(struct hnae3_handle *handle) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(ub_dbg_cmd); i++) + if (handle->ub_dbgfs_buf[i]) { + kvfree(handle->ub_dbgfs_buf[i]); + handle->ub_dbgfs_buf[i] = NULL; + } +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.h new file mode 100644 index 000000000000..2e1e2a2138ec --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_unic_debugfs.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Hisilicon UNIC Linux driver + * Copyright (c) 2023-2023 Hisilicon Limited. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#ifndef __HNS3_UNIC_DEBUGFS_H +#define __HNS3_UNIC_DEBUGFS_H + +enum hns3_dbg_ub_dentry_type { + UB_DBG_DENTRY_IP, + UB_DBG_DENTRY_GUID, + UB_DBG_DENTRY_END, +}; + +int hns3_unic_dbg_init(struct hnae3_handle *handle, struct dentry *parent); +void hns3_unic_dbg_uninit(struct hnae3_handle *handle); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 29aaec6b4428..54ce0cb8b05e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -6,13 +6,14 @@ #include "hclge_debugfs.h" #include "hclge_err.h" #include "hclge_main.h" +#include "hclge_comm_unic_addr.h" #include "hclge_regs.h" #include "hclge_tm.h" #include "hclge_udma.h" #include "hnae3.h" static const char * const state_str[] = { "off", "on" }; -static const char * const hclge_mac_state_str[] = { +static const char * const hclge_entry_state_str[] = { "TO_ADD", "TO_DEL", "ACTIVE" }; @@ -394,9 +395,14 @@ static void hclge_dbg_dump_mac_type(struct hclge_dev *hdev, char *buf, int len, { struct hclge_vport *vport = &hdev->vport[0]; struct hnae3_handle *handle = &vport->nic; + char *type; - *pos += scnprintf(buf + *pos, len - *pos, "type: %s\n", - handle->mac_type ? "ROH" : "Ethernet"); + if (hnae3_dev_ubl_supported(hdev->ae_dev)) + type = "UB"; + else + type = handle->mac_type ? "ROH" : "Ethernet"; + + *pos += scnprintf(buf + *pos, len - *pos, "type: %s\n", type); } static int hclge_dbg_dump_mac(struct hclge_dev *hdev, char *buf, int len) @@ -2121,7 +2127,7 @@ static void hclge_dbg_dump_mac_list(struct hclge_dev *hdev, char *buf, int len, func_id); sprintf(result[i++], "%pM", mac_node->mac_addr); sprintf(result[i++], "%5s", - hclge_mac_state_str[mac_node->state]); + hclge_entry_state_str[mac_node->state]); hclge_dbg_fill_content(content, sizeof(content), mac_list_items, (const char **)result, @@ -2575,6 +2581,150 @@ static int hclge_dbg_dump_wol_info(struct hclge_dev *hdev, char *buf, int len) return 0; } +static int hclge_dbg_dump_ip_spec(struct hclge_dev *hdev, char *buf, int len) +{ + struct unic_ip_table_info *iptbl_info = &hdev->iptbl_info; + u8 func_num = pci_num_vf(hdev->pdev) + 1; + struct hclge_vport *vport; + int pos = 0; + u8 i; + + pos += scnprintf(buf, len, "num_alloc_vport : %u\n", + hdev->num_alloc_vport); + pos += scnprintf(buf + pos, len - pos, "max_ip_table_size : %u\n", + iptbl_info->max_iptbl_size); + pos += scnprintf(buf + pos, len - pos, "priv_ip_table_size : %u\n", + iptbl_info->priv_iptbl_size); + + mutex_lock(&hdev->vport_lock); + pos += scnprintf(buf + pos, len - pos, "share_ip_table_size : %u\n", + iptbl_info->share_iptbl_size); + for (i = 0; i < func_num; i++) { + vport = &hdev->vport[i]; + pos += scnprintf(buf + pos, len - pos, + "vport(%u) used_ip_table_num : %u\n", + i, vport->used_iptbl_num); + } + mutex_unlock(&hdev->vport_lock); + + return 0; +} + +static int hclge_dbg_dump_guid_spec(struct hclge_dev *hdev, char *buf, int len) +{ + u16 mc_guid_tbl_size; + + mc_guid_tbl_size = min(HCLGE_UNIC_MC_GUID_NUM, + hdev->ae_dev->dev_specs.guid_tbl_space - + HCLGE_VPORT_NUM); + scnprintf(buf, len, "function guid tbl size: %u\nmc guid tbl size: %u\n", + HCLGE_VPORT_NUM, mc_guid_tbl_size); + + return 0; +} + +#define HCLGE_UNIC_DBG_DATA_STR_LEN 50 +#define HCLGE_UNIC_IPV6_LEN 16 + +static const struct hclge_dbg_item ip_list_items[] = { + { "FUNC_ID", 2 }, + { "IP_ADDR", 34 }, + { "STATE", 2 }, +}; + +static int hclge_dbg_dump_ip_list(struct hclge_dev *hdev, char *buf, int len) +{ + char data_str[ARRAY_SIZE(ip_list_items)][HCLGE_UNIC_DBG_DATA_STR_LEN]; + char content[HCLGE_DBG_INFO_LEN], str_id[HCLGE_DBG_ID_LEN]; + struct hclge_comm_unic_addr_node *ip_node, *tmp; + char *result[ARRAY_SIZE(ip_list_items)]; + struct hclge_vport *vport; + struct list_head *list; + u16 used_iptbl_num = 0; + u32 func_id; + int pos = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(ip_list_items); i++) + result[i] = &data_str[i][0]; + + for (i = 0; i < hdev->num_alloc_vport; i++) + used_iptbl_num += hdev->vport[i].used_iptbl_num; + + pos += scnprintf(buf + pos, len - pos, "used ip number: %u\n", + used_iptbl_num); + + hclge_dbg_fill_content(content, sizeof(content), ip_list_items, + NULL, ARRAY_SIZE(ip_list_items)); + pos += scnprintf(buf + pos, len - pos, "%s", content); + + for (func_id = 0; func_id < hdev->num_alloc_vport; func_id++) { + vport = &hdev->vport[func_id]; + list = &vport->ip_list; + spin_lock_bh(&vport->ip_list_lock); + list_for_each_entry_safe(ip_node, tmp, list, node) { + i = 0; + result[i++] = hclge_dbg_get_func_id_str(str_id, + func_id); + sprintf(result[i++], "%pI6c", &ip_node->ip_addr.s6_addr); + sprintf(result[i++], "%5s", + hclge_entry_state_str[ip_node->state]); + hclge_dbg_fill_content(content, sizeof(content), + ip_list_items, + (const char **)result, + ARRAY_SIZE(ip_list_items)); + + if (len - pos < strlen(content)) { + spin_unlock_bh(&vport->ip_list_lock); + dev_warn(&hdev->pdev->dev, + "Warning: IP list debugfs buffer overflow.\n"); + return 0; + } + + pos += scnprintf(buf + pos, len - pos, "%s", content); + } + spin_unlock_bh(&vport->ip_list_lock); + } + return 0; +} + +static int hclge_dbg_dump_guid_list(struct hclge_dev *hdev, char *buf, int len) +{ + char format_guid_addr[HCLGE_COMM_FORMAT_GUID_ADDR_LEN]; + struct hclge_comm_unic_addr_node *guid_node, *tmp; + char str_id[HCLGE_DBG_ID_LEN]; + struct hclge_vport *vport; + struct list_head *list; + u16 func_id; + int pos = 0; + u16 i; + + pos += scnprintf(buf + pos, len - pos, "used mc guid number: %u\n", + hdev->used_mc_guid_num); + pos += scnprintf(buf + pos, len - pos, "mc guid table bitmap: "); + for (i = 0; i < BITS_TO_LONGS(HCLGE_UNIC_MC_GUID_NUM); i++) + pos += scnprintf(buf + pos, len - pos, "%lx ", + hdev->mc_guid_tbl_bmap[i]); + pos += scnprintf(buf + pos, len - pos, "\nMC GUID LIST:\n"); + pos += scnprintf(buf + pos, len - pos, "No. FUNC_ID %-48s STATE\n", "MC_GUID"); + for (func_id = 0, i = 0; func_id < hdev->num_alloc_vport; func_id++) { + vport = &hdev->vport[func_id]; + list = &vport->mc_guid_list; + spin_lock_bh(&vport->mguid_list_lock); + list_for_each_entry_safe(guid_node, tmp, list, node) { + hclge_comm_format_guid_addr(format_guid_addr, + guid_node->mguid); + pos += scnprintf(buf + pos, len - pos, + "%-3d %-7s %-48s %s\n", i++, + hclge_dbg_get_func_id_str(str_id, func_id), + format_guid_addr, + hclge_entry_state_str[guid_node->state]); + } + spin_unlock_bh(&vport->mguid_list_lock); + } + return 0; +} + static const struct hclge_dbg_func hclge_dbg_cmd_func[] = { { .cmd = HNAE3_DBG_CMD_TM_NODES, @@ -2728,6 +2878,22 @@ static const struct hclge_dbg_func hclge_dbg_cmd_func[] = { .cmd = HNAE3_DBG_CMD_WOL_INFO, .dbg_dump = hclge_dbg_dump_wol_info, }, + { + .cmd = HNAE3_DBG_CMD_IP_SPEC, + .dbg_dump = hclge_dbg_dump_ip_spec, + }, + { + .cmd = HNAE3_DBG_CMD_GUID_SPEC, + .dbg_dump = hclge_dbg_dump_guid_spec, + }, + { + .cmd = HNAE3_DBG_CMD_IP_LIST, + .dbg_dump = hclge_dbg_dump_ip_list, + }, + { + .cmd = HNAE3_DBG_CMD_GUID_LIST, + .dbg_dump = hclge_dbg_dump_guid_list, + }, }; int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c index 4aba834ebff4..f4ca53136b69 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_udma.c @@ -14,9 +14,9 @@ */ #include "hclge_main.h" -#include "hclge_udma.h" #include "hclge_err.h" #include "hclge_debugfs.h" +#include "hclge_udma.h" static const struct hclge_dbg_status_dfx_info hclge_dbg_rst_info_ub[] = { {HCLGE_RAS_PF_OTHER_INT_STS_REG_UB, "UB RAS interrupt status"} -- Gitee From 1620efa4afd663ce9de4b6828c8005eda7569829 Mon Sep 17 00:00:00 2001 From: Junxin Chen Date: Mon, 14 Aug 2023 19:41:49 +0800 Subject: [PATCH 15/15] UNIC: add support for tc speed limitation driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ CVE: NA --------------------------------------------------- In UB mode, support for 5 TC is required, while alse needing support for TC-level rate limiting to differentiate between services. This patch adds support for UB on the basis of originally only supporting TC speed limit in ROH mode. Signed-off-by: Junxin Chen --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c | 5 +++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index cc4c6049fb64..d7092b401cae 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -523,7 +523,8 @@ static int hclge_mqprio_qopt_check_rate(struct hclge_dev *hdev, u64 min_rate, if (!max_rate) return 0; - if (hnae3_dev_roh_supported(hdev)) { + if (hnae3_dev_roh_supported(hdev) || + hnae3_dev_ubl_supported(hdev->ae_dev)) { if (max_rate < TM_RATE_PORT_RATE_SCALE || max_speed > hdev->hw.mac.max_speed) { dev_err(&hdev->pdev->dev, @@ -624,7 +625,7 @@ static int hclge_config_tc(struct hclge_dev *hdev, if (ret) return ret; - if (hnae3_dev_roh_supported(hdev)) + if (hnae3_dev_roh_supported(hdev) || hnae3_dev_ubl_supported(hdev->ae_dev)) return hclge_tm_set_tc_rate_limit(hdev, tc_info); return 0; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 2b7086cb62d2..b3c11cfcddd1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -1734,7 +1734,8 @@ int hclge_tm_init_hw(struct hclge_dev *hdev, bool init) if (ret) return ret; - if (hnae3_dev_roh_supported(hdev)) + if (hnae3_dev_roh_supported(hdev) || + hnae3_dev_ubl_supported(hdev->ae_dev)) return hclge_tm_set_tc_rate_limit(hdev, tc_info); return 0; -- Gitee