diff --git a/MAINTAINERS b/MAINTAINERS index 33056b3b5b2c0fdc19a302dbec9df974dc042f4d..4e479283ed181f7cda5b4ec0171b24df409a012a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9531,6 +9531,11 @@ S: Maintained F: Documentation/ABI/testing/debugfs-hisi-zip F: drivers/crypto/hisilicon/zip/ +HISILICON HNS3 PTP SYNC DRIVER +M: Yonglong Liu +S: Supported +F: drivers/ptp/ptp_hisi.c + HMM - Heterogeneous Memory Management M: Jérôme Glisse L: linux-mm@kvack.org diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 3627a99a60c522cb918a169e945014390a31f53f..5b5287a9f1e4b158939c632ec6dbf58f41ab7540 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -1934,7 +1934,7 @@ CONFIG_NET_SELFTESTS=y CONFIG_NET_SOCK_MSG=y CONFIG_NET_DEVLINK=y CONFIG_PAGE_POOL=y -# CONFIG_PAGE_POOL_STATS is not set +CONFIG_PAGE_POOL_STATS=y CONFIG_FAILOVER=m CONFIG_ETHTOOL_NETLINK=y CONFIG_NETACC_BPF=y @@ -3857,6 +3857,7 @@ CONFIG_PTP_1588_CLOCK_KVM=y # CONFIG_PTP_1588_CLOCK_IDTCM is not set # CONFIG_PTP_1588_CLOCK_MOCK is not set # CONFIG_PTP_1588_CLOCK_OCP is not set +CONFIG_PTP_HISI=m # end of PTP clock support CONFIG_PINCTRL=y diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 3312e1d93c3b5120d4fccb087369caf415679cc0..14bd24316d419b537e787335dc0a321e2b2164ba 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -92,6 +92,7 @@ config HNS3 depends on PCI select NET_DEVLINK select PAGE_POOL + select PAGE_POOL_STATS help This selects the framework support for Hisilicon Network Subsystem 3. This layer facilitates clients like ENET, RoCE and user-space ethernet diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index cc9158097e933d87ef4c7e9cca3893a976f59a61..1cc61b2062c0b20709b3a244c4bd8e30e5e19280 100644 --- a/drivers/net/ethernet/hisilicon/hns3/Makefile +++ b/drivers/net/ethernet/hisilicon/hns3/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_HNS3) += hnae3.o obj-$(CONFIG_HNS3_ENET) += hns3.o hns3-objs = hns3_enet.o hns3_ethtool.o hns3_debugfs.o -hns3-objs += hns3_ext.o +hns3-objs += hns3_ext.o hns3_roh.o hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index abcd7877f7d2a585df38e017f1d86107b96a1253..0de9b83c9d4ecfd32b21c2639112e651ba7e1378 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -47,6 +47,8 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_VF_UNINIT, /* (VF -> PF) vf is unintializing */ HCLGE_MBX_HANDLE_VF_TBL, /* (VF -> PF) store/clear hw table */ HCLGE_MBX_GET_RING_VECTOR_MAP, /* (VF -> PF) get ring-to-vector map */ + HCLGE_MBX_SET_QB = 0x28, /* (VF -> PF) set queue bonding */ + HCLGE_MBX_PUSH_QB_STATE, /* (PF -> VF) push qb state */ HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ @@ -77,6 +79,12 @@ enum hclge_mbx_tbl_cfg_subcode { HCLGE_MBX_VPORT_LIST_CLEAR, }; +enum hclge_mbx_qb_cfg_subcode { + HCLGE_MBX_QB_CHECK_CAPS = 0, /* query whether support qb */ + HCLGE_MBX_QB_ENABLE, /* request pf enable qb */ + HCLGE_MBX_QB_GET_STATE /* query whether qb enabled */ +}; + #define HCLGE_MBX_MAX_MSG_SIZE 14 #define HCLGE_MBX_MAX_RESP_DATA_SIZE 8U #define HCLGE_MBX_MAX_RING_CHAIN_PARAM_NUM 4 diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c index 67b0bf310daaafd1f4a6f4b3bf6c64d06d99e10f..ee4b7f5910b1fa3d97405c2c350da0acce483397 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c @@ -40,7 +40,8 @@ static DEFINE_MUTEX(hnae3_common_lock); 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_ROCE || + client_type == HNAE3_CLIENT_ROH) return true; return false; @@ -60,6 +61,9 @@ void hnae3_set_client_init_flag(struct hnae3_client *client, case HNAE3_CLIENT_ROCE: hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited); break; + case HNAE3_CLIENT_ROH: + hnae3_set_bit(ae_dev->flag, HNAE3_ROH_CLIENT_INITED_B, inited); + break; default: break; } @@ -80,6 +84,10 @@ static int hnae3_get_client_init_flag(struct hnae3_client *client, inited = hnae3_get_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B); break; + case HNAE3_CLIENT_ROH: + inited = hnae3_get_bit(ae_dev->flag, + HNAE3_ROH_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 c1c7d0fba871e33162eb5b83070afc160081339d..d98e951574de4ff9a86bd627a3f8ad0d05c165f7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -55,7 +55,10 @@ #define HNAE3_DEV_ID_50GE_RDMA 0xA224 #define HNAE3_DEV_ID_50GE_RDMA_MACSEC 0xA225 #define HNAE3_DEV_ID_100G_RDMA_MACSEC 0xA226 +#define HNAE3_DEV_ID_100G_ROH 0xA227 #define HNAE3_DEV_ID_200G_RDMA 0xA228 +#define HNAE3_DEV_ID_200G_ROH 0xA22C +#define HNAE3_DEV_ID_400G_ROH 0xA22D #define HNAE3_DEV_ID_VF 0xA22E #define HNAE3_DEV_ID_RDMA_DCB_PFC_VF 0xA22F @@ -67,10 +70,19 @@ #define HNAE3_KNIC_CLIENT_INITED_B 0x3 #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_ROH_B 0xA #define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) | \ BIT(HNAE3_DEV_SUPPORT_ROCE_B)) +#define HNAE3_DEV_SUPPORT_ROCE_ROH_DCB_BITS \ + (BIT(HNAE3_DEV_SUPPORT_DCB_B) | BIT(HNAE3_DEV_SUPPORT_ROCE_B) | \ + BIT(HNAE3_DEV_SUPPORT_ROH_B)) + +#define hnae3_dev_roh_supported(hdev) \ + hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_ROH_B) + #define hnae3_dev_roce_supported(hdev) \ hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_ROCE_B) @@ -106,6 +118,7 @@ enum HNAE3_DEV_CAP_BITS { HNAE3_DEV_SUPPORT_TM_FLUSH_B, HNAE3_DEV_SUPPORT_VF_FAULT_B, HNAE3_DEV_SUPPORT_NOTIFY_PKT_B, + HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B, }; #define hnae3_ae_dev_fd_supported(ae_dev) \ @@ -186,6 +199,9 @@ enum HNAE3_DEV_CAP_BITS { #define hnae3_ae_dev_notify_pkt_supported(ae_dev) \ test_bit(HNAE3_DEV_SUPPORT_NOTIFY_PKT_B, (ae_dev)->caps) +#define hnae3_ae_dev_gen_reg_dfx_supported(hdev) \ + test_bit(HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B, (hdev)->ae_dev->caps) + enum HNAE3_PF_CAP_BITS { HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B = 0, }; @@ -225,6 +241,12 @@ enum hnae3_loop { enum hnae3_client_type { HNAE3_CLIENT_KNIC, HNAE3_CLIENT_ROCE, + HNAE3_CLIENT_ROH, +}; + +enum hnae3_mac_type { + HNAE3_MAC_ETH, + HNAE3_MAC_ROH, }; /* mac media type */ @@ -367,6 +389,15 @@ struct hnae3_vector_info { #define HNAE3_FW_VERSION_BYTE0_SHIFT 0 #define HNAE3_FW_VERSION_BYTE0_MASK GENMASK(7, 0) +#define HNAE3_SCC_VERSION_BYTE3_SHIFT 24 +#define HNAE3_SCC_VERSION_BYTE3_MASK GENMASK(31, 24) +#define HNAE3_SCC_VERSION_BYTE2_SHIFT 16 +#define HNAE3_SCC_VERSION_BYTE2_MASK GENMASK(23, 16) +#define HNAE3_SCC_VERSION_BYTE1_SHIFT 8 +#define HNAE3_SCC_VERSION_BYTE1_MASK GENMASK(15, 8) +#define HNAE3_SCC_VERSION_BYTE0_SHIFT 0 +#define HNAE3_SCC_VERSION_BYTE0_MASK GENMASK(7, 0) + struct hnae3_ring_chain_node { struct hnae3_ring_chain_node *next; u32 tqp_index; @@ -574,6 +605,10 @@ struct hnae3_ae_dev { * Check if any cls flower rule exist * dbg_read_cmd * Execute debugfs read command. + * request_flush_qb_config + * Request to update queue bonding configuration + * query_fd_qb_state + * Query whether hw queue bonding enabled * set_tx_hwts_info * Save information for 1588 tx packet * get_rx_hwts @@ -773,6 +808,8 @@ struct hnae3_ae_ops { struct ethtool_link_ksettings *cmd); int (*set_phy_link_ksettings)(struct hnae3_handle *handle, const struct ethtool_link_ksettings *cmd); + void (*request_flush_qb_config)(struct hnae3_handle *handle); + bool (*query_fd_qb_state)(struct hnae3_handle *handle); bool (*set_tx_hwts_info)(struct hnae3_handle *handle, struct sk_buff *skb); void (*get_rx_hwts)(struct hnae3_handle *handle, struct sk_buff *skb, @@ -829,6 +866,7 @@ struct hnae3_tc_info { bool mqprio_active; bool mqprio_destroy; bool dcb_ets_active; + u64 max_rate[HNAE3_MAX_TC]; /* Unit Bps */ }; #define HNAE3_MAX_DSCP 64 @@ -871,6 +909,12 @@ struct hnae3_roce_private_info { unsigned long state; }; +struct hnae3_roh_private_info { + struct net_device *netdev; + void __iomem *roh_io_base; + int base_vector; +}; + #define HNAE3_SUPPORT_APP_LOOPBACK BIT(0) #define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1) #define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2) @@ -888,6 +932,8 @@ struct hnae3_roce_private_info { enum hnae3_pflag { HNAE3_PFLAG_LIMIT_PROMISC, + HNAE3_PFLAG_FD_QB_ENABLE, + HNAE3_PFLAG_ROH_ARP_PROXY_ENABLE, HNAE3_PFLAG_MAX }; @@ -902,6 +948,7 @@ struct hnae3_handle { struct net_device *netdev; /* first member */ struct hnae3_knic_private_info kinfo; struct hnae3_roce_private_info rinfo; + struct hnae3_roh_private_info rohinfo; }; u32 numa_node_mask; /* for multi-chip support */ @@ -919,6 +966,10 @@ struct hnae3_handle { unsigned long supported_pflags; unsigned long priv_flags; + + enum hnae3_mac_type mac_type; + + unsigned long link_change_assert_time; }; #define hnae3_set_field(origin, mask, shift, val) \ @@ -933,6 +984,11 @@ struct hnae3_handle { #define hnae3_get_bit(origin, shift) \ hnae3_get_field(origin, 0x1 << (shift), shift) +static inline bool hnae3_check_roh_mac_type(struct hnae3_handle *handle) +{ + return handle->mac_type == HNAE3_MAC_ROH; +} + #define HNAE3_FORMAT_MAC_ADDR_LEN 18 #define HNAE3_FORMAT_MAC_ADDR_OFFSET_0 0 #define HNAE3_FORMAT_MAC_ADDR_OFFSET_4 4 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c index 20d50422daa990350709e4b83541bf11815b05fe..4f4b5292f3588897a6528d0e27eeac40f4e6ea12 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.c @@ -159,6 +159,7 @@ static const struct hclge_comm_caps_bit_map hclge_pf_cmd_caps[] = { {HCLGE_COMM_CAP_TM_FLUSH_B, HNAE3_DEV_SUPPORT_TM_FLUSH_B}, {HCLGE_COMM_CAP_VF_FAULT_B, HNAE3_DEV_SUPPORT_VF_FAULT_B}, {HCLGE_COMM_CAP_NOTIFY_PKT_B, HNAE3_DEV_SUPPORT_NOTIFY_PKT_B}, + {HCLGE_COMM_CAP_ERR_MOD_GEN_REG_B, HNAE3_DEV_SUPPORT_ERR_MOD_GEN_REG_B}, }; static const struct hclge_comm_caps_bit_map hclge_vf_cmd_caps[] = { @@ -471,10 +472,14 @@ static int hclge_comm_cmd_check_result(struct hclge_comm_hw *hw, int hclge_comm_cmd_send(struct hclge_comm_hw *hw, struct hclge_desc *desc, int num) { + bool is_special = hclge_comm_is_special_opcode(desc->opcode); struct hclge_comm_cmq_ring *csq = &hw->cmq.csq; int ret; int ntc; + if (hw->cmq.ops.trace_cmd_send) + hw->cmq.ops.trace_cmd_send(hw, desc, num, is_special); + spin_lock_bh(&hw->cmq.csq.lock); if (test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hw->comm_state)) { @@ -508,6 +513,9 @@ int hclge_comm_cmd_send(struct hclge_comm_hw *hw, struct hclge_desc *desc, spin_unlock_bh(&hw->cmq.csq.lock); + if (hw->cmq.ops.trace_cmd_get) + hw->cmq.ops.trace_cmd_get(hw, desc, num, is_special); + return ret; } @@ -585,6 +593,17 @@ int hclge_comm_cmd_queue_init(struct pci_dev *pdev, struct hclge_comm_hw *hw) return ret; } +void hclge_comm_cmd_init_ops(struct hclge_comm_hw *hw, + const struct hclge_comm_cmq_ops *ops) +{ + struct hclge_comm_cmq *cmdq = &hw->cmq; + + if (ops) { + cmdq->ops.trace_cmd_send = ops->trace_cmd_send; + cmdq->ops.trace_cmd_get = ops->trace_cmd_get; + } +} + int hclge_comm_cmd_init(struct hnae3_ae_dev *ae_dev, struct hclge_comm_hw *hw, u32 *fw_version, bool is_pf, unsigned long reset_pending) 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 9de1c868fed52dfb4447a1291a522521698228bb..44a484342b4c457f49a153714d7a541ceaf24640 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 @@ -91,6 +91,7 @@ enum hclge_opcode_type { HCLGE_OPC_DFX_RCB_REG = 0x004D, HCLGE_OPC_DFX_TQP_REG = 0x004E, HCLGE_OPC_DFX_SSU_REG_2 = 0x004F, + HCLGE_OPC_DFX_GEN_REG = 0x7038, HCLGE_OPC_QUERY_DEV_SPECS = 0x0050, HCLGE_OPC_GET_QUEUE_ERR_VF = 0x0067, @@ -154,6 +155,7 @@ enum hclge_opcode_type { HCLGE_OPC_TM_INTERNAL_STS = 0x0850, HCLGE_OPC_TM_INTERNAL_CNT = 0x0851, HCLGE_OPC_TM_INTERNAL_STS_1 = 0x0852, + HCLGE_OPC_TM_TC_RATE_LIMIT_CFG = 0x0871, HCLGE_OPC_TM_FLUSH = 0x0872, /* Packet buffer allocate commands */ @@ -246,6 +248,9 @@ enum hclge_opcode_type { HCLGE_OPC_QCN_AJUST_INIT = 0x1A07, HCLGE_OPC_QCN_DFX_CNT_STATUS = 0x1A08, + /* SCC commands */ + HCLGE_OPC_QUERY_SCC_VER = 0x1A84, + /* Mailbox command */ HCLGEVF_OPC_MBX_PF_TO_VF = 0x2000, HCLGEVF_OPC_MBX_VF_TO_PF = 0x2001, @@ -371,6 +376,7 @@ enum HCLGE_COMM_CAP_BITS { HCLGE_COMM_CAP_WOL_B = 28, HCLGE_COMM_CAP_NOTIFY_PKT_B = 29, HCLGE_COMM_CAP_TM_FLUSH_B = 31, + HCLGE_COMM_CAP_ERR_MOD_GEN_REG_B = 32, }; enum HCLGE_COMM_API_CAP_BITS { @@ -410,6 +416,11 @@ struct hclge_comm_query_version_cmd { __le32 caps[HCLGE_COMM_QUERY_CAP_LENGTH]; /* capabilities of device */ }; +struct hclge_comm_query_scc_cmd { + __le32 scc_version; + u8 rsv[20]; +}; + #define HCLGE_DESC_DATA_LEN 6 struct hclge_desc { __le16 opcode; @@ -441,11 +452,22 @@ enum hclge_comm_cmd_status { HCLGE_COMM_ERR_CSQ_ERROR = -3, }; +struct hclge_comm_hw; +struct hclge_comm_cmq_ops { + void (*trace_cmd_send)(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int num, bool is_special); + void (*trace_cmd_get)(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int num, bool is_special); +}; + struct hclge_comm_cmq { struct hclge_comm_cmq_ring csq; struct hclge_comm_cmq_ring crq; u16 tx_timeout; enum hclge_comm_cmd_status last_status; + struct hclge_comm_cmq_ops ops; }; struct hclge_comm_hw { @@ -492,5 +514,6 @@ int hclge_comm_cmd_queue_init(struct pci_dev *pdev, struct hclge_comm_hw *hw); int hclge_comm_cmd_init(struct hnae3_ae_dev *ae_dev, struct hclge_comm_hw *hw, u32 *fw_version, bool is_pf, unsigned long reset_pending); - +void hclge_comm_cmd_init_ops(struct hclge_comm_hw *hw, + const struct hclge_comm_cmq_ops *ops); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 807eb3bbb11c0408fbdcfa678586646fb92f8861..48192fb9f75bd9052a2c027db7d69f048e83cbd2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -962,7 +962,7 @@ static const struct hns3_dbg_item tx_bd_info_items[] = { { "OT_VLAN_TAG", 3 }, { "TV", 5 }, { "OLT_VLAN_LEN", 2 }, - { "PAYLEN_OL4CS", 2 }, + { "PAYLEN_FDOP_OL4CS", 2 }, { "BD_FE_SC_VLD", 2 }, { "MSS_HW_CSUM", 0 }, }; @@ -981,7 +981,7 @@ static void hns3_dump_tx_bd_info(struct hns3_desc *desc, char **result, int idx) sprintf(result[j++], "%u", le16_to_cpu(desc->tx.tv)); sprintf(result[j++], "%u", le32_to_cpu(desc->tx.ol_type_vlan_len_msec)); - sprintf(result[j++], "%#x", le32_to_cpu(desc->tx.paylen_ol4cs)); + sprintf(result[j++], "%#x", le32_to_cpu(desc->tx.paylen_fdop_ol4cs)); sprintf(result[j++], "%#x", le16_to_cpu(desc->tx.bdtp_fe_sc_vld_ra_ri)); sprintf(result[j++], "%u", le16_to_cpu(desc->tx.mss_hw_csum)); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index de509ae0b18540858d1f9cba36d9aaa9d0679806..dae17c3b72bcb956603f4d3ddced2fe0decb96ec 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -28,6 +28,7 @@ #include "hnae3.h" #include "hnae3_ext.h" #include "hns3_enet.h" +#include "hns3_roh.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 @@ -97,8 +98,14 @@ static const struct pci_device_id hns3_pci_tbl[] = { HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_ROH), + HNAE3_DEV_SUPPORT_ROCE_ROH_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_RDMA), HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_ROH), + HNAE3_DEV_SUPPORT_ROCE_ROH_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), + HNAE3_DEV_SUPPORT_ROCE_ROH_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}, @@ -1162,6 +1169,142 @@ static void hns3_tx_spare_reclaim_cb(struct hns3_enet_ring *ring, } } +static struct hns3_dhcp_packet *hns3_get_dhcp_packet(struct sk_buff *skb, + int *dhcp_len) +{ + struct hns3_dhcp_packet *dhcp; + union l4_hdr_info l4; + int l4_payload_len; + + l4.hdr = skb_transport_header(skb); + if (l4.udp->dest != htons(HNS3_DHCP_CLIENT_PORT) || + l4.udp->source != htons(HNS3_DHCP_SERVER_PORT)) + return NULL; + + dhcp = (struct hns3_dhcp_packet *)(l4.hdr + sizeof(struct udphdr)); + l4_payload_len = ntohs(l4.udp->len) - sizeof(struct udphdr); + if (l4_payload_len < offsetof(struct hns3_dhcp_packet, options) || + dhcp->hlen != ETH_ALEN || + dhcp->cookie != htonl(HNS3_DHCP_MAGIC)) + return NULL; + + *dhcp_len = l4_payload_len; + return dhcp; +} + +static u8 *hns3_dhcp_option_scan(struct hns3_dhcp_packet *packet, + struct hns3_dhcp_opt_state *opt_state) +{ + int opt_len; + u8 *cur_opt; + + /* option bytes: [code][len][data0~data[len-1]] */ + while (opt_state->rem > 0) { + switch (opt_state->opt_ptr[DHCP_OPT_CODE]) { + /* option padding and end have no len and data byte. */ + case DHCP_OPT_PADDING: + opt_state->rem--; + opt_state->opt_ptr++; + break; + case DHCP_OPT_END: + if (DHCP_OVERLOAD_USE_FILE(opt_state->overload_flag)) { + opt_state->overload_flag |= + DHCP_OVERLOAD_FILE_USED; + opt_state->opt_ptr = packet->file; + opt_state->rem = sizeof(packet->file); + break; + } + if (DHCP_OVERLOAD_USE_SNAME(opt_state->overload_flag)) { + opt_state->overload_flag |= + DHCP_OVERLOAD_SNAME_USED; + opt_state->opt_ptr = packet->sname; + opt_state->rem = sizeof(packet->sname); + break; + } + return NULL; + default: + if (opt_state->rem <= DHCP_OPT_LEN) + return NULL; + /* opt_len includes code, len and data bytes */ + opt_len = opt_state->opt_ptr[DHCP_OPT_LEN] + + DHCP_OPT_DATA; + cur_opt = opt_state->opt_ptr; + if (opt_state->rem < opt_len) + return NULL; + + opt_state->opt_ptr += opt_len; + opt_state->rem -= opt_len; + if (cur_opt[DHCP_OPT_CODE] == DHCP_OPT_OVERLOAD) { + opt_state->overload_flag |= + cur_opt[DHCP_OPT_DATA]; + break; + } + return cur_opt; + } + } + + return NULL; +} + +static void hns3_dhcp_update_option61(struct hns3_nic_priv *priv, + struct hns3_dhcp_packet *packet, + int dhcp_len) +{ + struct hns3_dhcp_opt_state opt_state; + u8 *cur_opt; + + opt_state.opt_ptr = packet->options; + opt_state.rem = dhcp_len - offsetof(struct hns3_dhcp_packet, options); + opt_state.overload_flag = 0; + + cur_opt = hns3_dhcp_option_scan(packet, &opt_state); + while (cur_opt) { + if (cur_opt[DHCP_OPT_CODE] != DHCP_OPT_CLIENT_ID) { + cur_opt = hns3_dhcp_option_scan(packet, &opt_state); + continue; + } + if (cur_opt[DHCP_OPT_LEN] > ETH_ALEN) + ether_addr_copy(&cur_opt[DHCP_CLIENT_ID_MAC_OFT], + priv->roh_perm_mac); + break; + } +} + +static void hns3_dhcp_cal_l4_csum(struct sk_buff *skb) +{ + union l3_hdr_info l3; + union l4_hdr_info l4; + __wsum csum; + int offset; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + return; + + l3.hdr = skb_network_header(skb); + l4.hdr = skb_transport_header(skb); + offset = skb_transport_offset(skb); + l4.udp->check = 0; + csum = csum_partial(l4.udp, ntohs(l4.udp->len), 0); + l4.udp->check = csum_tcpudp_magic(l3.v4->saddr, l3.v4->daddr, + skb->len - offset, IPPROTO_UDP, csum); +} + +static void hns3_dhcp_packet_convert(struct hns3_nic_priv *priv, + struct sk_buff *skb, + struct hns3_dhcp_packet *dhcp, + int dhcp_len) +{ + struct ethhdr *l2hdr = eth_hdr(skb); + + if (!dhcp) + return; + + ether_addr_copy(dhcp->chaddr, l2hdr->h_source); + hns3_dhcp_update_option61(priv, dhcp, dhcp_len); + /* for l4 payload changed, need to re-calculate the csum */ + hns3_dhcp_cal_l4_csum(skb); +} + static int hns3_set_tso(struct sk_buff *skb, u32 *paylen_fdop_ol4cs, u16 *mss, u32 *type_cs_vlan_tso, u32 *send_bytes) { @@ -1542,6 +1685,73 @@ static int hns3_handle_vtags(struct hns3_enet_ring *tx_ring, return 0; } +static bool hns3_query_fd_qb_state(struct hnae3_handle *handle) +{ + const struct hnae3_ae_ops *ops = handle->ae_algo->ops; + + if (!test_bit(HNAE3_PFLAG_FD_QB_ENABLE, &handle->priv_flags)) + return false; + + if (!ops->query_fd_qb_state) + return false; + + return ops->query_fd_qb_state(handle); +} + +/* fd_op is the field of tx bd indicates hw whether to add or delete + * a qb rule or do nothing. + */ +static u8 hns3_fd_qb_handle(struct hns3_enet_ring *ring, struct sk_buff *skb) +{ + struct hnae3_handle *handle = ring->tqp->handle; + union l4_hdr_info l4; + union l3_hdr_info l3; + u8 l4_proto_tmp = 0; + __be16 frag_off; + u8 ip_version; + u8 fd_op = 0; + + if (!hns3_query_fd_qb_state(handle)) + return 0; + + if (skb->encapsulation) { + ip_version = inner_ip_hdr(skb)->version; + l3.hdr = skb_inner_network_header(skb); + l4.hdr = skb_inner_transport_header(skb); + } else { + ip_version = ip_hdr(skb)->version; + l3.hdr = skb_network_header(skb); + l4.hdr = skb_transport_header(skb); + } + + if (ip_version == IP_VERSION_IPV6) { + unsigned char *exthdr; + + exthdr = l3.hdr + sizeof(*l3.v6); + l4_proto_tmp = l3.v6->nexthdr; + if (l4.hdr != exthdr) + ipv6_skip_exthdr(skb, exthdr - skb->data, + &l4_proto_tmp, &frag_off); + } else if (ip_version == IP_VERSION_IPV4) { + l4_proto_tmp = l3.v4->protocol; + } + + if (l4_proto_tmp != IPPROTO_TCP) + return 0; + + ring->fd_qb_tx_sample++; + if (l4.tcp->fin || l4.tcp->rst) { + hnae3_set_bit(fd_op, HNS3_TXD_FD_DEL_B, 1); + ring->fd_qb_tx_sample = 0; + } else if (l4.tcp->syn || + ring->fd_qb_tx_sample >= HNS3_FD_QB_FORCE_CNT_MAX) { + hnae3_set_bit(fd_op, HNS3_TXD_FD_ADD_B, 1); + ring->fd_qb_tx_sample = 0; + } + + return fd_op; +} + /* check if the hardware is capable of checksum offloading */ static bool hns3_check_hw_tx_csum(struct sk_buff *skb) { @@ -1559,7 +1769,7 @@ static bool hns3_check_hw_tx_csum(struct sk_buff *skb) } struct hns3_desc_param { - u32 paylen_ol4cs; + u32 paylen_fdop_ol4cs; u32 ol_type_vlan_len_msec; u32 type_cs_vlan_tso; u16 mss_hw_csum; @@ -1569,7 +1779,7 @@ struct hns3_desc_param { static void hns3_init_desc_data(struct sk_buff *skb, struct hns3_desc_param *pa) { - pa->paylen_ol4cs = skb->len; + pa->paylen_fdop_ol4cs = skb->len; pa->ol_type_vlan_len_msec = 0; pa->type_cs_vlan_tso = 0; pa->mss_hw_csum = 0; @@ -1637,7 +1847,7 @@ static int hns3_handle_csum_partial(struct hns3_enet_ring *ring, return ret; } - ret = hns3_set_tso(skb, ¶m->paylen_ol4cs, ¶m->mss_hw_csum, + ret = hns3_set_tso(skb, ¶m->paylen_fdop_ol4cs, ¶m->mss_hw_csum, ¶m->type_cs_vlan_tso, &desc_cb->send_bytes); if (unlikely(ret < 0)) { hns3_ring_stats_update(ring, tx_tso_err); @@ -1646,11 +1856,25 @@ static int hns3_handle_csum_partial(struct hns3_enet_ring *ring, return 0; } -static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, +static bool hns3_roh_check_udpv4(struct sk_buff *skb) +{ + union l3_hdr_info l3; + + l3.hdr = skb_network_header(skb); + if (skb->protocol != htons(ETH_P_IP) || + l3.v4->version != IP_VERSION_IPV4) + return false; + + return l3.v4->protocol == IPPROTO_UDP; +} + +static int hns3_fill_skb_desc(struct hns3_nic_priv *priv, + struct hns3_enet_ring *ring, struct sk_buff *skb, struct hns3_desc *desc, struct hns3_desc_cb *desc_cb) { struct hns3_desc_param param; + u8 fd_op; int ret; hns3_init_desc_data(skb, ¶m); @@ -1666,11 +1890,24 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, return ret; } + fd_op = hns3_fd_qb_handle(ring, skb); + hnae3_set_field(param.paylen_fdop_ol4cs, HNS3_TXD_FD_OP_M, + HNS3_TXD_FD_OP_S, fd_op); + + if (hnae3_check_roh_mac_type(priv->ae_handle) && + hns3_roh_check_udpv4(skb)) { + struct hns3_dhcp_packet *dhcp; + int dhcp_len; + + dhcp = hns3_get_dhcp_packet(skb, &dhcp_len); + hns3_dhcp_packet_convert(priv, skb, dhcp, dhcp_len); + } + /* Set txbd */ 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); - desc->tx.paylen_ol4cs = cpu_to_le32(param.paylen_ol4cs); + desc->tx.paylen_fdop_ol4cs = cpu_to_le32(param.paylen_fdop_ol4cs); desc->tx.mss_hw_csum = cpu_to_le16(param.mss_hw_csum); desc->tx.vlan_tag = cpu_to_le16(param.inner_vtag); desc->tx.outer_vlan_tag = cpu_to_le16(param.out_vtag); @@ -2271,15 +2508,16 @@ static int hns3_handle_desc_filling(struct hns3_enet_ring *ring, return hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB); } -static int hns3_handle_skb_desc(struct hns3_enet_ring *ring, +static int hns3_handle_skb_desc(struct hns3_nic_priv *priv, + struct hns3_enet_ring *ring, struct sk_buff *skb, struct hns3_desc_cb *desc_cb, int next_to_use_head) { int ret; - ret = hns3_fill_skb_desc(ring, skb, &ring->desc[ring->next_to_use], - desc_cb); + ret = hns3_fill_skb_desc(priv, ring, skb, + &ring->desc[ring->next_to_use], desc_cb); if (unlikely(ret < 0)) goto fill_err; @@ -2328,7 +2566,12 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) goto out_err_tx_ok; } - ret = hns3_handle_skb_desc(ring, skb, desc_cb, ring->next_to_use); + if (test_bit(HNAE3_PFLAG_ROH_ARP_PROXY_ENABLE, + &priv->ae_handle->priv_flags) && + hns3_need_to_handle_roh_arp_req(skb)) + return hns3_handle_roh_arp_req(skb, priv); + + ret = hns3_handle_skb_desc(priv, ring, skb, desc_cb, ring->next_to_use); if (unlikely(ret <= 0)) goto out_err_tx_ok; @@ -3057,7 +3300,10 @@ bool hns3_is_phys_func(struct pci_dev *pdev) case HNAE3_DEV_ID_50GE_RDMA: case HNAE3_DEV_ID_50GE_RDMA_MACSEC: case HNAE3_DEV_ID_100G_RDMA_MACSEC: + case HNAE3_DEV_ID_100G_ROH: case HNAE3_DEV_ID_200G_RDMA: + case HNAE3_DEV_ID_200G_ROH: + case HNAE3_DEV_ID_400G_ROH: return true; case HNAE3_DEV_ID_VF: case HNAE3_DEV_ID_RDMA_DCB_PFC_VF: @@ -4492,6 +4738,9 @@ static int hns3_nic_common_poll(struct napi_struct *napi, int budget) if (tqp_vector->num_tqps > 1) rx_budget = max(budget / tqp_vector->num_tqps, 1); + if (hnae3_check_roh_mac_type(priv->ae_handle)) + hns3_handle_roh_arp_reply(tqp_vector, priv); + hns3_for_each_ring(ring, tqp_vector->rx_group) { int rx_cleaned = hns3_clean_rx_ring(ring, rx_budget, hns3_rx_skb); @@ -4961,6 +5210,11 @@ static void hns3_alloc_page_pool(struct hns3_enet_ring *ring) } } +bool hns3_is_page_pool_enabled(void) +{ + return page_pool_enabled; +} + static int hns3_alloc_ring_memory(struct hns3_enet_ring *ring) { int ret; @@ -5160,6 +5414,10 @@ static int hns3_init_mac_addr(struct net_device *netdev) return 0; } + if (hnae3_check_roh_mac_type(h) && + is_zero_ether_addr(priv->roh_perm_mac)) + ether_addr_copy(priv->roh_perm_mac, netdev->dev_addr); + if (h->ae_algo->ops->set_mac_addr) ret = h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true); @@ -5277,6 +5535,12 @@ static void hns3_state_init(struct hnae3_handle *handle) if (hnae3_ae_dev_rxd_adv_layout_supported(ae_dev)) set_bit(HNS3_NIC_STATE_RXD_ADV_LAYOUT_ENABLE, &priv->state); + + if (hnae3_check_roh_mac_type(handle)) { + set_bit(HNAE3_PFLAG_ROH_ARP_PROXY_ENABLE, + &handle->supported_pflags); + set_bit(HNAE3_PFLAG_ROH_ARP_PROXY_ENABLE, &handle->priv_flags); + } } static void hns3_state_uninit(struct hnae3_handle *handle) @@ -5308,6 +5572,7 @@ static int hns3_client_init(struct hnae3_handle *handle) priv->tx_timeout_count = 0; priv->max_non_tso_bd_num = ae_dev->dev_specs.max_non_tso_bd_num; set_bit(HNS3_NIC_STATE_DOWN, &priv->state); + eth_zero_addr(priv->roh_perm_mac); handle->msg_enable = netif_msg_init(debug, DEFAULT_MSG_LEVEL); @@ -5391,6 +5656,9 @@ static int hns3_client_init(struct hnae3_handle *handle) hns3_state_init(handle); + if (test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps)) + set_bit(HNAE3_PFLAG_FD_QB_ENABLE, &handle->supported_pflags); + ret = register_netdev(netdev); if (ret) { dev_err(priv->dev, "probe register netdev fail!\n"); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index acd756b0c7c9a4134a0d7c47a50b8112dc881ee1..60a4ae38423316f1efb625d98c10a9a8f8c2de84 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -179,6 +179,11 @@ enum hns3_nic_state { #define HNS3_TXD_DECTTL_S 12 #define HNS3_TXD_DECTTL_M (0xf << HNS3_TXD_DECTTL_S) +#define HNS3_TXD_FD_ADD_B 1 +#define HNS3_TXD_FD_DEL_B 0 +#define HNS3_TXD_FD_OP_M GENMASK(21, 20) +#define HNS3_TXD_FD_OP_S 20 + #define HNS3_TXD_OL4CS_B 22 #define HNS3_TXD_MSS_S 0 @@ -214,6 +219,8 @@ enum hns3_nic_state { #define HNS3_CQ_MODE_EQE 1U #define HNS3_CQ_MODE_CQE 0U +#define HNS3_FD_QB_FORCE_CNT_MAX 20 + enum hns3_pkt_l2t_type { HNS3_L2_TYPE_UNICAST, HNS3_L2_TYPE_MULTICAST, @@ -285,7 +292,7 @@ struct __packed hns3_desc { }; }; - __le32 paylen_ol4cs; + __le32 paylen_fdop_ol4cs; __le16 bdtp_fe_sc_vld_ra_ri; __le16 mss_hw_csum; } tx; @@ -398,6 +405,9 @@ enum hns3_pkt_ol4type { HNS3_OL4_TYPE_UNKNOWN }; +#define IP_VERSION_IPV4 0x4 +#define IP_VERSION_IPV6 0x6 + struct hns3_rx_ptype { u32 ptype : 8; u32 csum_level : 2; @@ -461,6 +471,15 @@ struct hns3_tx_spare { u32 len; }; +struct hns3_arp_reply { + __be32 dest_ip; + __be32 src_ip; + u8 dest_hw[ETH_ALEN]; + u8 src_hw[ETH_ALEN]; + u8 has_vlan; + __be16 vlan_tci; +}; + struct hns3_enet_ring { struct hns3_desc *desc; /* dma map address space */ struct hns3_desc_cb *desc_cb; @@ -486,6 +505,11 @@ struct hns3_enet_ring { int next_to_clean; u32 flag; /* ring attribute */ +#define HNS3_APR_REPLY_LTH 32 + struct hns3_arp_reply arp_reply[HNS3_APR_REPLY_LTH]; + int arp_reply_head; + int arp_reply_tail; + int pending_buf; union { /* for Tx ring */ @@ -594,6 +618,56 @@ struct hns3_nic_priv { struct hns3_enet_coalesce rx_coal; u32 tx_copybreak; u32 rx_copybreak; + u8 roh_perm_mac[ETH_ALEN]; +}; + +#define HNS3_DHCP_SERVER_PORT 68 +#define HNS3_DHCP_CLIENT_PORT 67 +#define HNS3_DHCP_MAGIC 0x63825363 +#define DHCP_OPT_CODE 0 +#define DHCP_OPT_LEN 1 +#define DHCP_OPT_DATA 2 +#define DHCP_CLIENT_ID_LEN 7 +#define DHCP_CLIENT_ID_MAC_OFT 3 +#define DHCP_OVERLOAD_FILE 0x1 +#define DHCP_OVERLOAD_SNAME 0x2 +#define DHCP_OVERLOAD_FILE_USED 0x101 +#define DHCP_OVERLOAD_SNAME_USED 0x202 +#define DHCP_OVERLOAD_USE_FILE(x) \ + (((x) & DHCP_OVERLOAD_FILE_USED) == DHCP_OVERLOAD_FILE) +#define DHCP_OVERLOAD_USE_SNAME(x) \ + (((x) & DHCP_OVERLOAD_SNAME_USED) == DHCP_OVERLOAD_SNAME) + +enum DHCP_OPTION_CODES { + DHCP_OPT_PADDING = 0, + DHCP_OPT_OVERLOAD = 52, + DHCP_OPT_CLIENT_ID = 61, + DHCP_OPT_END = 255 +}; + +struct hns3_dhcp_packet { + u8 op; + u8 htype; + u8 hlen; + u8 hops; + u32 xid; + u16 secs; + u16 flags; + u32 ciaddr; + u32 yiaddr; + u32 siaddr_nip; + u32 gateway_nip; + u8 chaddr[16]; /* link-layer client hardware address (MAC) */ + u8 sname[64]; + u8 file[128]; + u32 cookie; /* DHCP magic bytes: 0x63825363 */ + u8 options[312]; +}; + +struct hns3_dhcp_opt_state { + u8 *opt_ptr; /* refer to current option item */ + int rem; /* remain bytes in options */ + u32 overload_flag; /* whether use file and sname field as options */ }; union l3_hdr_info { @@ -754,4 +828,5 @@ void hns3_cq_period_mode_init(struct hns3_nic_priv *priv, void hns3_external_lb_prepare(struct net_device *ndev, bool if_running); void hns3_external_lb_restore(struct net_device *ndev, bool if_running); +bool hns3_is_page_pool_enabled(void); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 682239f33082b0b27b7ef866e15220f88b177fc3..c065c759e8cd11c6a611d363412756ddbfbc2b45 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "hns3_enet.h" #include "hns3_ethtool.h" @@ -466,22 +467,46 @@ static void hns3_update_limit_promisc_mode(struct net_device *netdev, hns3_request_update_promisc_mode(handle); } +static void hns3_update_fd_qb_state(struct net_device *netdev, bool enable) +{ + struct hnae3_handle *handle = hns3_get_handle(netdev); + + if (!handle->ae_algo->ops->request_flush_qb_config) + return; + + handle->ae_algo->ops->request_flush_qb_config(handle); +} + +static void hns3_update_roh_arp_proxy_enable(struct net_device *netdev, + bool enable) +{ + netdev_info(netdev, "%s roh arp proxy\n", + enable ? "enable" : "disable"); +} + static const struct hns3_pflag_desc hns3_priv_flags[HNAE3_PFLAG_MAX] = { - { "limit_promisc", hns3_update_limit_promisc_mode } + { "limit_promisc", hns3_update_limit_promisc_mode }, + { "qb_enable", hns3_update_fd_qb_state }, + { "roh_arp_proxy_enable", hns3_update_roh_arp_proxy_enable }, }; static int hns3_get_sset_count(struct net_device *netdev, int stringset) { struct hnae3_handle *h = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops = h->ae_algo->ops; + int pp_stats_count = 0; if (!ops->get_sset_count) return -EOPNOTSUPP; switch (stringset) { case ETH_SS_STATS: +#ifdef CONFIG_PAGE_POOL_STATS + if (hns3_is_page_pool_enabled()) + pp_stats_count = page_pool_ethtool_stats_get_count(); +#endif return ((HNS3_TQP_STATS_COUNT * h->kinfo.num_tqps) + - ops->get_sset_count(h, stringset)); + ops->get_sset_count(h, stringset) + pp_stats_count); case ETH_SS_TEST: return ops->get_sset_count(h, stringset); @@ -549,6 +574,10 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: +#ifdef CONFIG_PAGE_POOL_STATS + if (hns3_is_page_pool_enabled()) + buff = page_pool_ethtool_stats_get_strings(buff); +#endif buff = hns3_get_strings_tqps(h, buff); ops->get_strings(h, stringset, (u8 *)buff); break; @@ -596,6 +625,28 @@ static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) return data; } +#ifdef CONFIG_PAGE_POOL_STATS +static u64 *hns3_ethtool_pp_stats(struct hnae3_handle *handle, u64 *data) +{ + struct hns3_nic_priv *priv = handle->priv; + int ring_num = handle->kinfo.num_tqps; + struct page_pool_stats stats = {0}; + struct page_pool *page_pool; + int i; + + if (!hns3_is_page_pool_enabled()) + return data; + + for (i = 0; i < ring_num; i++) { + page_pool = priv->ring[i + ring_num].page_pool; + if (page_pool) + page_pool_get_stats(page_pool, &stats); + } + + return page_pool_ethtool_stats_get(data, &stats); +} +#endif + /* hns3_get_stats - get detail statistics. * @netdev: net device * @stats: statistics info. @@ -617,6 +668,10 @@ static void hns3_get_stats(struct net_device *netdev, return; } +#ifdef CONFIG_PAGE_POOL_STATS + p = hns3_ethtool_pp_stats(h, p); +#endif + h->ae_algo->ops->update_stats(h); /* get per-queue stats */ @@ -1783,6 +1838,14 @@ static int hns3_get_module_info(struct net_device *netdev, modinfo->type = ETH_MODULE_SFF_8636; modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; break; + case SFF8024_ID_QSFP_DD: + case SFF8024_ID_QSFP_PLUS_CMIS: + modinfo->type = ETH_MODULE_SFF_8636; + if (sfp_type.flat_mem & HNS3_CMIS_FLAT_MEMORY) + modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; + else + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + break; default: netdev_err(netdev, "Optical module unknown: %#x\n", sfp_type.type); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.h b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.h index da207d1d9aa93d1ce1bc95b58bf4aa9fe49d7f20..34504ed2c0868cf81156c5933aa345c20807846b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.h @@ -12,9 +12,11 @@ struct hns3_stats { int stats_offset; }; +#define HNS3_CMIS_FLAT_MEMORY BIT(7) struct hns3_sfp_type { u8 type; u8 ext_type; + u8 flat_mem; }; struct hns3_pflag_desc { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_roh.c b/drivers/net/ethernet/hisilicon/hns3/hns3_roh.c new file mode 100644 index 0000000000000000000000000000000000000000..1c0341b34f6d1f81b4dab17591e4abc7285618ad --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_roh.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2016-2017 Hisilicon Limited. + +#include +#include +#include +#include + +#include "hns3_roh.h" +#include "hns3_enet.h" + +static void hns3_extract_arp_ip_field(struct arphdr *arphdr, __be32 **sip, + __be32 **tip, unsigned char addr_len) +{ + unsigned char *arp_ptr = (unsigned char *)(arphdr + 1); + + arp_ptr += addr_len; + *sip = (__be32 *)arp_ptr; + arp_ptr += ARP_IP_LEN; + arp_ptr += addr_len; + *tip = (__be32 *)arp_ptr; +} + +bool hns3_need_to_handle_roh_arp_req(struct sk_buff *skb) +{ + struct arphdr *arphdr = arp_hdr(skb); + __be32 *sip, *tip; + + /* Intercept most non-ARP packets based on packet length. */ + if (skb->len > hns3_roh_arp_hlen_max(skb)) + return false; + + /* if txvlan offload is off, check encapsulated protocol in vlan. */ + if (eth_type_vlan(skb->protocol)) { + struct vlan_hdr *vh = (struct vlan_hdr *)(skb->data + ETH_HLEN); + + if (vh->h_vlan_encapsulated_proto == htons(ETH_P_ARP) && + arphdr->ar_op == htons(ARPOP_REQUEST)) + goto check_gratuitous_arp; + return false; + } + + /* if txvlan offload is on or it's a normal packet, check protocol. */ + if (skb->protocol != htons(ETH_P_ARP) || + arphdr->ar_op != htons(ARPOP_REQUEST)) + return false; + + /* don't support Gratuitous ARP, which request packet where the source + * and destination IP are both set to the IP of the machine issuing the + * packet. + */ +check_gratuitous_arp: + hns3_extract_arp_ip_field(arphdr, &sip, &tip, skb->dev->addr_len); + return *tip != *sip; +} + +int hns3_handle_roh_arp_req(struct sk_buff *skb, struct hns3_nic_priv *priv) +{ + struct hnae3_handle *h = priv->ae_handle; + struct hns3_enet_ring *ring; + struct arphdr *arphdr; + struct ethhdr *ethhdr; + int reply_idx, len; + __be32 *sip, *tip; + + /* use same queue num in rx */ + ring = &priv->ring[skb->queue_mapping + h->kinfo.num_tqps]; + reply_idx = ring->arp_reply_tail; + reply_idx = hns3_roh_arp_reply_idx_move_fd(reply_idx); + /* This smp_load_acquire() pairs with smp_store_release() in + * hns3_handle_roh_arp_reply(). + */ + if (reply_idx == smp_load_acquire(&ring->arp_reply_head)) + return NETDEV_TX_BUSY; + len = skb->len; + + if (skb_vlan_tagged(skb)) { + ring->arp_reply[reply_idx].has_vlan = true; + ring->arp_reply[reply_idx].vlan_tci = skb_vlan_tag_get(skb); + skb_vlan_pop(skb); + len += VLAN_HLEN; + } else { + ring->arp_reply[reply_idx].has_vlan = false; + } + + ethhdr = eth_hdr(skb); + arphdr = arp_hdr(skb); + + hns3_extract_arp_ip_field(arphdr, &sip, &tip, skb->dev->addr_len); + ether_addr_copy(ring->arp_reply[reply_idx].dest_hw, ethhdr->h_source); + ether_addr_copy(ring->arp_reply[reply_idx].src_hw, ethhdr->h_dest); + ring->arp_reply[reply_idx].dest_ip = *sip; + ring->arp_reply[reply_idx].src_ip = *tip; + hns3_roh_update_mac_by_ip(be32_to_cpu(*tip), + ring->arp_reply[reply_idx].src_hw); + /* This smp_store_release() pairs with smp_load_acquire() in + * hns3_handle_roh_arp_reply(). Ensure that the arp_reply_tail is + * update validly. + */ + smp_store_release(&ring->arp_reply_tail, reply_idx); + + ring = &priv->ring[skb->queue_mapping]; + u64_stats_update_begin(&ring->syncp); + ring->stats.tx_pkts++; + ring->stats.tx_bytes += len; + u64_stats_update_end(&ring->syncp); + + dev_kfree_skb_any(skb); + napi_schedule(&ring->tqp_vector->napi); + return NETDEV_TX_OK; +} + +static struct sk_buff *setup_arp_reply_skb(struct hns3_arp_reply *arp_reply, + struct hns3_nic_priv *priv) +{ + struct sk_buff *skb = arp_create(ARPOP_REPLY, ETH_P_ARP, + arp_reply->dest_ip, priv->netdev, + arp_reply->src_ip, arp_reply->dest_hw, + arp_reply->src_hw, arp_reply->dest_hw); + if (!skb) + return NULL; + + skb_reset_mac_header(skb); + skb_reset_mac_len(skb); + + if (arp_reply->has_vlan) { + skb = vlan_insert_tag_set_proto(skb, htons(ETH_P_8021Q), + arp_reply->vlan_tci); + if (!skb) + return NULL; + skb_reset_network_header(skb); + } + + skb_reserve(skb, skb->mac_len); + return skb; +} + +void hns3_handle_roh_arp_reply(struct hns3_enet_tqp_vector *tqp_vector, + struct hns3_nic_priv *priv) +{ + struct hns3_arp_reply *arp_reply; + struct hns3_enet_ring *ring; + struct sk_buff *skb; + int reply_idx; + + hns3_for_each_ring(ring, tqp_vector->rx_group) { + /* This smp_load_acquire() pairs with smp_store_release() in + * hns3_handle_roh_arp_reply(). + */ + while (smp_load_acquire(&ring->arp_reply_tail) != + ring->arp_reply_head) { + reply_idx = ring->arp_reply_head; + reply_idx = hns3_roh_arp_reply_idx_move_fd(reply_idx); + arp_reply = &ring->arp_reply[reply_idx]; + skb = setup_arp_reply_skb(arp_reply, priv); + /* This smp_store_release() pairs with + * smp_load_acquire() in hns3_handle_roh_arp_req(). + * Ensure that the arp_reply_head is update validly. + */ + smp_store_release(&ring->arp_reply_head, reply_idx); + + if (!skb) { + hns3_ring_stats_update(ring, rx_err_cnt); + continue; + } + napi_gro_receive(&tqp_vector->napi, skb); + + u64_stats_update_begin(&ring->syncp); + ring->stats.rx_pkts++; + ring->stats.rx_bytes += skb->len; + u64_stats_update_end(&ring->syncp); + } + } +} diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_roh.h b/drivers/net/ethernet/hisilicon/hns3/hns3_roh.h new file mode 100644 index 0000000000000000000000000000000000000000..222ed20d8772a5f4608c133c1d8337fd5482266d --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_roh.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023 Hisilicon Limited. */ + +#ifndef __HNS3_ROH_H +#define __HNS3_ROH_H + +#include "hns3_enet.h" + +#define ARP_IP_LEN 4 +#define HNS3_ROH_MAC_ADDR_MASK 0x00ffffff + +#define hns3_roh_update_mac_by_ip(ip_addr, mac) \ + u64_to_ether_addr((ip_addr) & HNS3_ROH_MAC_ADDR_MASK, mac) +#define hns3_roh_arp_hlen_max(skb) \ + (ETH_HLEN + arp_hdr_len((skb)->dev) + VLAN_HLEN) + +static inline int hns3_roh_arp_reply_idx_move_fd(int idx) +{ + return (idx + 1) % HNS3_APR_REPLY_LTH; +} + +void hns3_handle_roh_arp_reply(struct hns3_enet_tqp_vector *tqp_vector, + struct hns3_nic_priv *priv); +int hns3_handle_roh_arp_req(struct sk_buff *skb, struct hns3_nic_priv *priv); +bool hns3_need_to_handle_roh_arp_req(struct sk_buff *skb); +#endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 21234969e2ba6120c004ca0f2e5d6b11ea33c1e7..81dc8eb946f058ac3ef709cedbaa48f5daf7bf0b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -180,7 +180,8 @@ struct hclge_pf_res_cmd { __le16 tx_buf_size; __le16 dv_buf_size; __le16 ext_tqp_num; - u8 rsv[6]; + __le16 pf_intr_vector_number_roh; + u8 rsv[4]; }; #define HCLGE_CFG_OFFSET_S 0 @@ -733,11 +734,11 @@ struct hclge_fd_tcam_config_3_cmd { #define HCLGE_FD_AD_DROP_B 0 #define HCLGE_FD_AD_DIRECT_QID_B 1 -#define HCLGE_FD_AD_QID_S 2 -#define HCLGE_FD_AD_QID_M GENMASK(11, 2) +#define HCLGE_FD_AD_QID_L_S 2 +#define HCLGE_FD_AD_QID_L_M GENMASK(11, 2) #define HCLGE_FD_AD_USE_COUNTER_B 12 -#define HCLGE_FD_AD_COUNTER_NUM_S 13 -#define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(20, 13) +#define HCLGE_FD_AD_COUNTER_NUM_L_S 13 +#define HCLGE_FD_AD_COUNTER_NUM_L_M GENMASK(19, 13) #define HCLGE_FD_AD_NXT_STEP_B 20 #define HCLGE_FD_AD_NXT_KEY_S 21 #define HCLGE_FD_AD_NXT_KEY_M GENMASK(25, 21) @@ -747,6 +748,8 @@ struct hclge_fd_tcam_config_3_cmd { #define HCLGE_FD_AD_TC_OVRD_B 16 #define HCLGE_FD_AD_TC_SIZE_S 17 #define HCLGE_FD_AD_TC_SIZE_M GENMASK(20, 17) +#define HCLGE_FD_AD_QID_H_B 21 +#define HCLGE_FD_AD_COUNTER_NUM_H_B 26 struct hclge_fd_ad_config_cmd { u8 stage; @@ -764,6 +767,24 @@ struct hclge_fd_ad_cnt_read_cmd { u8 rsv2[8]; }; +struct hclge_fd_qb_cfg_cmd { + u8 en; + u8 vf_id; + u8 rsv[22]; +}; + +#define HCLGE_FD_QB_AD_RULE_ID_VLD_B 0 +#define HCLGE_FD_QB_AD_COUNTER_VLD_B 1 +struct hclge_fd_qb_ad_cmd { + u8 vf_id; + u8 rsv1; + u8 ad_sel; + u8 rsv2; + __le16 hit_rule_id; + u8 counter_id; + u8 rsv3[17]; +}; + #define HCLGE_FD_USER_DEF_OFT_S 0 #define HCLGE_FD_USER_DEF_OFT_M GENMASK(14, 0) #define HCLGE_FD_USER_DEF_EN_B 15 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index eabbacb1c714087a53d0381514b140e802c409b8..416bcac3bf70e2f0b28178565c7104b78ddd31be 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -509,6 +509,36 @@ static u8 hclge_setdcbx(struct hnae3_handle *h, u8 mode) return 0; } +static int hclge_mqprio_qopt_check_rate(struct hclge_dev *hdev, u64 min_rate, + u64 max_rate) +{ + u32 max_speed = hclge_tm_rate_2_port_rate(max_rate); + + if (min_rate) { + dev_err(&hdev->pdev->dev, "unsupported min_rate, min_rate = %lluB/s\n", + min_rate); + return -EOPNOTSUPP; + } + + if (!max_rate) + return 0; + + if (hnae3_dev_roh_supported(hdev)) { + if (max_rate < TM_RATE_PORT_RATE_SCALE || + max_speed > hdev->hw.mac.max_speed) { + dev_err(&hdev->pdev->dev, + "invalid max_rate[%lluB/s]: the range is [1Mbps, %uMbps]\n", + max_rate, hdev->hw.mac.max_speed); + return -EINVAL; + } + return 0; + } + + dev_err(&hdev->pdev->dev, "unsupported max_rate, max_rate = %lluB/s\n", + max_rate); + return -EOPNOTSUPP; +} + static int hclge_mqprio_qopt_check(struct hclge_dev *hdev, struct tc_mqprio_qopt_offload *mqprio_qopt) { @@ -546,11 +576,11 @@ static int hclge_mqprio_qopt_check(struct hclge_dev *hdev, return -EINVAL; } - if (mqprio_qopt->min_rate[i] || mqprio_qopt->max_rate[i]) { - dev_err(&hdev->pdev->dev, - "qopt tx_rate is not supported\n"); - return -EOPNOTSUPP; - } + ret = hclge_mqprio_qopt_check_rate(hdev, + mqprio_qopt->min_rate[i], + mqprio_qopt->max_rate[i]); + if (ret) + return ret; queue_sum = mqprio_qopt->qopt.offset[i]; queue_sum += mqprio_qopt->qopt.count[i]; @@ -576,18 +606,28 @@ static void hclge_sync_mqprio_qopt(struct hnae3_tc_info *tc_info, sizeof_field(struct hnae3_tc_info, tqp_count)); memcpy(tc_info->tqp_offset, mqprio_qopt->qopt.offset, sizeof_field(struct hnae3_tc_info, tqp_offset)); + memcpy(tc_info->max_rate, mqprio_qopt->max_rate, + sizeof_field(struct hnae3_tc_info, max_rate)); } static int hclge_config_tc(struct hclge_dev *hdev, struct hnae3_tc_info *tc_info) { + int ret; int i; hclge_tm_schd_info_update(hdev, tc_info->num_tc); for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) hdev->tm_info.prio_tc[i] = tc_info->prio_tc[i]; - return hclge_map_update(hdev); + ret = hclge_map_update(hdev); + if (ret) + return ret; + + if (hnae3_dev_roh_supported(hdev)) + return hclge_tm_set_tc_rate_limit(hdev, tc_info); + + return 0; } /* Set up TC for hardware offloaded mqprio in channel mode */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index ff3f8f424ad9004bbd549bc32cc43abca3ea2610..4eac6833ddd25f5ca333b976afed896f4056031d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -161,10 +161,8 @@ static int hclge_dbg_get_dfx_bd_num(struct hclge_dev *hdev, int offset, return 0; } -static int hclge_dbg_cmd_send(struct hclge_dev *hdev, - struct hclge_desc *desc_src, - int index, int bd_num, - enum hclge_opcode_type cmd) +int hclge_dbg_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc_src, + int index, int bd_num, enum hclge_opcode_type cmd) { struct hclge_desc *desc = desc_src; int ret, i; @@ -389,6 +387,16 @@ static int hclge_dbg_dump_mac_speed_duplex(struct hclge_dev *hdev, char *buf, return 0; } +static void hclge_dbg_dump_mac_type(struct hclge_dev *hdev, char *buf, int len, + int *pos) +{ + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + + *pos += scnprintf(buf + *pos, len - *pos, "type: %s\n", + handle->mac_type ? "ROH" : "Ethernet"); +} + static int hclge_dbg_dump_mac(struct hclge_dev *hdev, char *buf, int len) { int pos = 0; @@ -402,7 +410,13 @@ static int hclge_dbg_dump_mac(struct hclge_dev *hdev, char *buf, int len) if (ret) return ret; - return hclge_dbg_dump_mac_speed_duplex(hdev, buf, len, &pos); + ret = hclge_dbg_dump_mac_speed_duplex(hdev, buf, len, &pos); + if (ret) + return ret; + + hclge_dbg_dump_mac_type(hdev, buf, len, &pos); + + return 0; } static int hclge_dbg_dump_dcb_qset(struct hclge_dev *hdev, char *buf, int len, @@ -1510,8 +1524,7 @@ static int hclge_dbg_dump_mng_table(struct hclge_dev *hdev, char *buf, int len) #define HCLGE_DBG_TCAM_BUF_SIZE 256 static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, bool sel_x, - char *tcam_buf, - struct hclge_dbg_tcam_msg tcam_msg) + char *tcam_buf, u8 stage, u32 loc) { struct hclge_fd_tcam_config_1_cmd *req1; struct hclge_fd_tcam_config_2_cmd *req2; @@ -1531,9 +1544,9 @@ static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, bool sel_x, req2 = (struct hclge_fd_tcam_config_2_cmd *)desc[1].data; req3 = (struct hclge_fd_tcam_config_3_cmd *)desc[2].data; - req1->stage = tcam_msg.stage; + req1->stage = stage; req1->xy_sel = sel_x ? 1 : 0; - req1->index = cpu_to_le32(tcam_msg.loc); + req1->index = cpu_to_le32(loc); ret = hclge_cmd_send(&hdev->hw, desc, 3); if (ret) @@ -1541,7 +1554,7 @@ static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, bool sel_x, pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos, "read result tcam key %s(%u):\n", sel_x ? "x" : "y", - tcam_msg.loc); + loc); /* tcam_data0 ~ tcam_data1 */ req = (__le32 *)req1->tcam_data; @@ -1586,7 +1599,6 @@ static int hclge_dbg_get_rules_location(struct hclge_dev *hdev, u16 *rule_locs) static int hclge_dbg_dump_fd_tcam(struct hclge_dev *hdev, char *buf, int len) { u32 rule_num = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]; - struct hclge_dbg_tcam_msg tcam_msg; int i, ret, rule_cnt; u16 *rule_locs; char *tcam_buf; @@ -1621,10 +1633,7 @@ static int hclge_dbg_dump_fd_tcam(struct hclge_dev *hdev, char *buf, int len) ret = 0; for (i = 0; i < rule_cnt; i++) { - tcam_msg.stage = HCLGE_FD_STAGE_1; - tcam_msg.loc = rule_locs[i]; - - ret = hclge_dbg_fd_tcam_read(hdev, true, tcam_buf, tcam_msg); + ret = hclge_dbg_fd_tcam_read(hdev, true, tcam_buf, HCLGE_FD_STAGE_1, rule_locs[i]); if (ret) { dev_err(&hdev->pdev->dev, "failed to get fd tcam key x, ret = %d\n", ret); @@ -1633,7 +1642,7 @@ static int hclge_dbg_dump_fd_tcam(struct hclge_dev *hdev, char *buf, int len) pos += scnprintf(buf + pos, len - pos, "%s", tcam_buf); - ret = hclge_dbg_fd_tcam_read(hdev, false, tcam_buf, tcam_msg); + ret = hclge_dbg_fd_tcam_read(hdev, false, tcam_buf, HCLGE_FD_STAGE_1, rule_locs[i]); if (ret) { dev_err(&hdev->pdev->dev, "failed to get fd tcam key y, ret = %d\n", ret); @@ -1649,6 +1658,86 @@ static int hclge_dbg_dump_fd_tcam(struct hclge_dev *hdev, char *buf, int len) return ret; } +static int hclge_query_rules_valid(struct hclge_dev *hdev, u8 stage, u32 loc) +{ +#define HCLGE_TCAM_SELECTION_X 1 + struct hclge_fd_tcam_config_1_cmd *req1; + struct hclge_fd_tcam_config_2_cmd *req2; + struct hclge_fd_tcam_config_3_cmd *req3; + struct hclge_desc desc[3]; + int ret; + + hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_FD_TCAM_OP, true); + desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_FD_TCAM_OP, true); + desc[1].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); + hclge_cmd_setup_basic_desc(&desc[2], HCLGE_OPC_FD_TCAM_OP, true); + + req1 = (struct hclge_fd_tcam_config_1_cmd *)desc[0].data; + req2 = (struct hclge_fd_tcam_config_2_cmd *)desc[1].data; + req3 = (struct hclge_fd_tcam_config_3_cmd *)desc[2].data; + + req1->stage = stage; + req1->xy_sel = HCLGE_TCAM_SELECTION_X; + req1->index = cpu_to_le32(loc); + + ret = hclge_cmd_send(&hdev->hw, desc, 3); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to read tcam status, ret = %d\n", ret); + return ret; + } + + return req1->entry_vld; +} + +static int hclge_dbg_dump_qb_tcam(struct hclge_dev *hdev, char *buf, int len) +{ + char *tcam_buf; + int pos = 0; + int ret = 0; + u32 i; + + if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) { + dev_err(&hdev->pdev->dev, + "Only FD-supported dev supports dump fd tcam\n"); + return -EOPNOTSUPP; + } + + tcam_buf = kzalloc(HCLGE_DBG_TCAM_BUF_SIZE, GFP_KERNEL); + if (!tcam_buf) + return -ENOMEM; + + for (i = 0; i < hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]; i++) { + if (hclge_query_rules_valid(hdev, HCLGE_FD_STAGE_1, i) <= 0) + continue; + + ret = hclge_dbg_fd_tcam_read(hdev, true, tcam_buf, + HCLGE_FD_STAGE_1, i); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get qb tcam key x, ret = %d\n", ret); + goto out; + } + + pos += scnprintf(buf + pos, len - pos, "%s", tcam_buf); + + ret = hclge_dbg_fd_tcam_read(hdev, false, tcam_buf, + HCLGE_FD_STAGE_1, i); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get qb tcam key y, ret = %d\n", ret); + goto out; + } + + pos += scnprintf(buf + pos, len - pos, "%s", tcam_buf); + } + +out: + kfree(tcam_buf); + return ret; +} + static int hclge_dbg_dump_fd_counter(struct hclge_dev *hdev, char *buf, int len) { u8 func_num = pci_num_vf(hdev->pdev) + 1; /* pf and enabled vf num */ @@ -1760,6 +1849,8 @@ static int hclge_dbg_dump_interrupt(struct hclge_dev *hdev, char *buf, int len) hdev->num_nic_msi); pos += scnprintf(buf + pos, len - pos, "num_roce_msi: %u\n", hdev->num_roce_msi); + pos += scnprintf(buf + pos, len - pos, "num_roh_msi: %u\n", + hdev->num_roh_msi); pos += scnprintf(buf + pos, len - pos, "num_msi_used: %u\n", hdev->num_msi_used); pos += scnprintf(buf + pos, len - pos, "num_msi_left: %u\n", @@ -2400,6 +2491,14 @@ static int hclge_dbg_dump_ptp_info(struct hclge_dev *hdev, char *buf, int len) return 0; } +static int hclge_dbg_dump_tcam(struct hclge_dev *hdev, char *buf, int len) +{ + if (test_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state)) + return hclge_dbg_dump_qb_tcam(hdev, buf, len); + else + return hclge_dbg_dump_fd_tcam(hdev, buf, len); +}; + static int hclge_dbg_dump_mac_uc(struct hclge_dev *hdev, char *buf, int len) { hclge_dbg_dump_mac_list(hdev, buf, len, true); @@ -2539,14 +2638,14 @@ static const struct hclge_dbg_func hclge_dbg_cmd_func[] = { .cmd = HNAE3_DBG_CMD_REG_DCB, .dbg_dump = hclge_dbg_dump_dcb, }, - { - .cmd = HNAE3_DBG_CMD_FD_TCAM, - .dbg_dump = hclge_dbg_dump_fd_tcam, - }, { .cmd = HNAE3_DBG_CMD_MAC_TNL_STATUS, .dbg_dump = hclge_dbg_dump_mac_tnl_status, }, + { + .cmd = HNAE3_DBG_CMD_FD_TCAM, + .dbg_dump = hclge_dbg_dump_tcam, + }, { .cmd = HNAE3_DBG_CMD_SERV_INFO, .dbg_dump = hclge_dbg_dump_serv_info, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h index 724052928b884a301967e8bc9c778c76460fd428..3fe78e3c2368e224cfe5337be2055c9a40dff14c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h @@ -69,11 +69,6 @@ struct hclge_dbg_reg_common_msg { enum hclge_opcode_type cmd; }; -struct hclge_dbg_tcam_msg { - u8 stage; - u32 loc; -}; - #define HCLGE_DBG_MAX_DFX_MSG_LEN 60 struct hclge_dbg_dfx_message { int flag; @@ -771,4 +766,7 @@ struct hclge_dbg_vlan_cfg { u8 pri_only2; }; +int hclge_dbg_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc_src, + int index, int bd_num, enum hclge_opcode_type cmd); + #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c index 9a939c0b217f717746924af4f651e384e2f0035a..a1571c1086788b434f19363b095ce00baa71cae9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c @@ -5,6 +5,34 @@ #include "hclge_devlink.h" +static int hclge_devlink_scc_info_get(struct devlink *devlink, + struct devlink_info_req *req) +{ + struct hclge_devlink_priv *priv = devlink_priv(devlink); + char scc_version[HCLGE_DEVLINK_FW_SCC_LEN]; + struct hclge_dev *hdev = priv->hdev; + u32 scc_version_tmp; + int ret; + + ret = hclge_query_scc_version(hdev, &scc_version_tmp); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get scc version, ret = %d\n", ret); + return ret; + } + + snprintf(scc_version, sizeof(scc_version), "%lu.%lu.%lu.%lu", + hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE3_MASK, + HNAE3_FW_VERSION_BYTE3_SHIFT), + hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE2_MASK, + HNAE3_FW_VERSION_BYTE2_SHIFT), + hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE1_MASK, + HNAE3_FW_VERSION_BYTE1_SHIFT), + hnae3_get_field(scc_version_tmp, HNAE3_SCC_VERSION_BYTE0_MASK, + HNAE3_FW_VERSION_BYTE0_SHIFT)); + return devlink_info_version_running_put(req, "fw.scc", scc_version); +} + static int hclge_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, struct netlink_ext_ack *extack) @@ -13,6 +41,7 @@ static int hclge_devlink_info_get(struct devlink *devlink, struct hclge_devlink_priv *priv = devlink_priv(devlink); char version_str[HCLGE_DEVLINK_FW_STRING_LEN]; struct hclge_dev *hdev = priv->hdev; + int ret; snprintf(version_str, sizeof(version_str), "%lu.%lu.%lu.%lu", hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE3_MASK, @@ -24,9 +53,18 @@ static int hclge_devlink_info_get(struct devlink *devlink, hnae3_get_field(hdev->fw_version, HNAE3_FW_VERSION_BYTE0_MASK, HNAE3_FW_VERSION_BYTE0_SHIFT)); - return devlink_info_version_running_put(req, - DEVLINK_INFO_VERSION_GENERIC_FW, - version_str); + ret = devlink_info_version_running_put(req, + DEVLINK_INFO_VERSION_GENERIC_FW, + version_str); + if (ret) { + dev_err(&hdev->pdev->dev, "failed to set running version of fw\n"); + return ret; + } + + if (hdev->pdev->revision > HNAE3_DEVICE_VERSION_V2) + ret = hclge_devlink_scc_info_get(devlink, req); + + return ret; } static int hclge_devlink_reload_down(struct devlink *devlink, bool netns_change, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h index 918be04507a59b38b63cf9d003b6a75b102df53c..148effa5ea897217949c0abf09e3ecd672e21304 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h @@ -6,6 +6,8 @@ #include "hclge_main.h" +#define HCLGE_DEVLINK_FW_SCC_LEN 32 + struct hclge_devlink_priv { struct hclge_dev *hdev; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index d63e114f93d0bb25d0783200d019f1813748cc0e..e198f813e0634715296ca28a8ac52fc28857ca1c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -1198,6 +1198,426 @@ static const struct hclge_hw_error hclge_rocee_qmm_ovf_err_int[] = { } }; +static const struct hclge_mod_reg_info hclge_ssu_reg_0_info[] = { + { + .reg_name = "SSU_BP_STATUS_0~5", + .reg_offset_group = {5, 6, 7, 8, 9, 10}, + .group_size = 6 + }, { + .reg_name = "LO_PRI_UNICAST_CUR_CNT", + .reg_offset_group = {54}, + .group_size = 1 + }, { + .reg_name = "HI/LO_PRI_MULTICAST_CUR_CNT", + .reg_offset_group = {55, 56}, + .group_size = 2 + }, { + .reg_name = "SSU_MB_RD_RLT_DROP_CNT", + .reg_offset_group = {29}, + .group_size = 1 + }, { + .reg_name = "SSU_PPP_MAC_KEY_NUM", + .reg_offset_group = {31, 30}, + .group_size = 2 + }, { + .reg_name = "SSU_PPP_HOST_KEY_NUM", + .reg_offset_group = {33, 32}, + .group_size = 2 + }, { + .reg_name = "PPP_SSU_MAC/HOST_RLT_NUM", + .reg_offset_group = {35, 34, 37, 36}, + .group_size = 4 + }, { + .reg_name = "FULL/PART_DROP_NUM", + .reg_offset_group = {18, 19}, + .group_size = 2 + }, { + .reg_name = "PPP_KEY/RLT_DROP_NUM", + .reg_offset_group = {20, 21}, + .group_size = 2 + }, { + .reg_name = "NIC/ROC_L2_ERR_DROP_PKT_CNT", + .reg_offset_group = {48, 49}, + .group_size = 2 + }, { + .reg_name = "NIC/ROC_L2_ERR_DROP_PKT_CNT_RX", + .reg_offset_group = {50, 51}, + .group_size = 2 + }, +}; + +static const struct hclge_mod_reg_info hclge_ssu_reg_1_info[] = { + { + .reg_name = "RX_PACKET_IN/OUT_CNT", + .reg_offset_group = {13, 12, 15, 14}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_IN/OUT_CNT", + .reg_offset_group = {17, 16, 19, 18}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC0_IN/OUT_CNT", + .reg_offset_group = {25, 24, 41, 40}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC1_IN/OUT_CNT", + .reg_offset_group = {27, 26, 43, 42}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC2_IN/OUT_CNT", + .reg_offset_group = {29, 28, 45, 44}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC3_IN/OUT_CNT", + .reg_offset_group = {31, 30, 47, 46}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC4_IN/OUT_CNT", + .reg_offset_group = {33, 32, 49, 48}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC5_IN/OUT_CNT", + .reg_offset_group = {35, 34, 51, 50}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC6_IN/OUT_CNT", + .reg_offset_group = {37, 36, 53, 52}, + .group_size = 4 + }, { + .reg_name = "RX_PACKET_TC7_IN/OUT_CNT", + .reg_offset_group = {39, 38, 55, 54}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC0_IN/OUT_CNT", + .reg_offset_group = {57, 56, 73, 72}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC1_IN/OUT_CNT", + .reg_offset_group = {59, 58, 75, 74}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC2_IN/OUT_CNT", + .reg_offset_group = {61, 60, 77, 76}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC3_IN/OUT_CNT", + .reg_offset_group = {63, 62, 79, 78}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC4_IN/OUT_CNT", + .reg_offset_group = {65, 64, 81, 80}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC5_IN/OUT_CNT", + .reg_offset_group = {67, 66, 83, 82}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC6_IN/OUT_CNT", + .reg_offset_group = {69, 68, 85, 84}, + .group_size = 4 + }, { + .reg_name = "TX_PACKET_TC7_IN/OUT_CNT", + .reg_offset_group = {71, 70, 87, 86}, + .group_size = 4 + }, { + .reg_name = "PACKET_TC0~3_CURR_BUFFER_CNT", + .reg_offset_group = {1, 2, 3, 4}, + .group_size = 4 + }, { + .reg_name = "PACKET_TC4~7_CURR_BUFFER_CNT", + .reg_offset_group = {5, 6, 7, 8}, + .group_size = 4 + }, { + .reg_name = "ROC_RX_PACKET_IN_CNT", + .reg_offset_group = {21, 20}, + .group_size = 2 + }, { + .reg_name = "ROC_TX_PACKET_OUT_CNT", + .reg_offset_group = {23, 22}, + .group_size = 2 + } +}; + +static const struct hclge_mod_reg_info hclge_rpu_reg_0_info[] = { + { + .reg_name = "RPU_FSM_DFX_ST0/ST1_TNL", + .has_suffix = true, + .reg_offset_group = {1, 2}, + .group_size = 2 + }, { + .reg_name = "RPU_RX_PKT_DROP_CNT_TNL", + .has_suffix = true, + .reg_offset_group = {3}, + .group_size = 1 + } +}; + +static const struct hclge_mod_reg_info hclge_rpu_reg_1_info[] = { + { + .reg_name = "FIFO_DFX_ST0_1_2_4", + .reg_offset_group = {1, 2, 3, 5}, + .group_size = 4 + } +}; + +static const struct hclge_mod_reg_info hclge_igu_egu_reg_info[] = { + { + .reg_name = "IGU_RX_ERR_PKT", + .reg_offset_group = {1}, + .group_size = 1 + }, { + .reg_name = "IGU_RX_OUT_ALL_PKT", + .reg_offset_group = {29, 28}, + .group_size = 2 + }, { + .reg_name = "EGU_TX_OUT_ALL_PKT", + .reg_offset_group = {39, 38}, + .group_size = 2 + }, { + .reg_name = "EGU_TX_ERR_PKT", + .reg_offset_group = {5}, + .group_size = 1 + } +}; + +static const struct hclge_mod_reg_info hclge_gen_reg_info_tnl[] = { + { + .reg_name = "SSU2RPU_TNL_WR_PKT_CNT_TNL", + .has_suffix = true, + .reg_offset_group = {1}, + .group_size = 1 + }, { + .reg_name = "RPU2HST_TNL_WR_PKT_CNT_TNL", + .has_suffix = true, + .reg_offset_group = {12}, + .group_size = 1 + } +}; + +static const struct hclge_mod_reg_info hclge_gen_reg_info[] = { + { + .reg_name = "SSU_OVERSIZE_DROP_CNT", + .reg_offset_group = {12}, + .group_size = 1 + }, { + .reg_name = "ROCE_RX_BYPASS_5NS_DROP_NUM", + .reg_offset_group = {13}, + .group_size = 1 + }, { + .reg_name = "RX_PKT_IN/OUT_ERR_CNT", + .reg_offset_group = {15, 14, 19, 18}, + .group_size = 4 + }, { + .reg_name = "TX_PKT_IN/OUT_ERR_CNT", + .reg_offset_group = {17, 16, 21, 20}, + .group_size = 4 + }, { + .reg_name = "ETS_TC_READY", + .reg_offset_group = {22}, + .group_size = 1 + }, { + .reg_name = "MIB_TX/RX_BAD_PKTS", + .reg_offset_group = {19, 18, 29, 28}, + .group_size = 4 + }, { + .reg_name = "MIB_TX/RX_GOOD_PKTS", + .reg_offset_group = {21, 20, 31, 30}, + .group_size = 4 + }, { + .reg_name = "MIB_TX/RX_TOTAL_PKTS", + .reg_offset_group = {23, 22, 33, 32}, + .group_size = 4 + }, { + .reg_name = "MIB_TX/RX_PAUSE_PKTS", + .reg_offset_group = {25, 24, 35, 34}, + .group_size = 4 + }, { + .reg_name = "MIB_TX_ERR_ALL_PKTS", + .reg_offset_group = {27, 26}, + .group_size = 2 + }, { + .reg_name = "MIB_RX_FCS_ERR_PKTS", + .reg_offset_group = {37, 36}, + .group_size = 2 + }, { + .reg_name = "IGU_EGU_AUTO_GATE_EN", + .reg_offset_group = {42}, + .group_size = 1 + }, { + .reg_name = "IGU_EGU_INT_SRC", + .reg_offset_group = {43}, + .group_size = 1 + }, { + .reg_name = "EGU_READY_NUM_CFG", + .reg_offset_group = {44}, + .group_size = 1 + }, { + .reg_name = "IGU_EGU_TNL_DFX", + .reg_offset_group = {45}, + .group_size = 1 + }, { + .reg_name = "TX_TNL_NOTE_PKT", + .reg_offset_group = {46}, + .group_size = 1 + } +}; + +static const struct hclge_mod_reg_common_msg hclge_ssu_reg_common_msg[] = { + { + .cmd = HCLGE_OPC_DFX_SSU_REG_0, + .result_regs = hclge_ssu_reg_0_info, + .bd_num = HCLGE_BD_NUM_SSU_REG_0, + .result_regs_size = ARRAY_SIZE(hclge_ssu_reg_0_info) + }, { + .cmd = HCLGE_OPC_DFX_SSU_REG_1, + .result_regs = hclge_ssu_reg_1_info, + .bd_num = HCLGE_BD_NUM_SSU_REG_1, + .result_regs_size = ARRAY_SIZE(hclge_ssu_reg_1_info) + }, { + .cmd = HCLGE_OPC_DFX_RPU_REG_0, + .result_regs = hclge_rpu_reg_0_info, + .bd_num = HCLGE_BD_NUM_RPU_REG_0, + .result_regs_size = ARRAY_SIZE(hclge_rpu_reg_0_info), + .need_para = true + }, { + .cmd = HCLGE_OPC_DFX_RPU_REG_1, + .result_regs = hclge_rpu_reg_1_info, + .bd_num = HCLGE_BD_NUM_RPU_REG_1, + .result_regs_size = ARRAY_SIZE(hclge_rpu_reg_1_info) + }, { + .cmd = HCLGE_OPC_DFX_IGU_EGU_REG, + .result_regs = hclge_igu_egu_reg_info, + .bd_num = HCLGE_BD_NUM_IGU_EGU_REG, + .result_regs_size = ARRAY_SIZE(hclge_igu_egu_reg_info) + }, { + .cmd = HCLGE_OPC_DFX_GEN_REG, + .result_regs = hclge_gen_reg_info_tnl, + .bd_num = HCLGE_BD_NUM_GEN_REG, + .result_regs_size = ARRAY_SIZE(hclge_gen_reg_info_tnl), + .need_para = true + }, { + .cmd = HCLGE_OPC_DFX_GEN_REG, + .result_regs = hclge_gen_reg_info, + .bd_num = HCLGE_BD_NUM_GEN_REG, + .result_regs_size = ARRAY_SIZE(hclge_gen_reg_info) + } +}; + +static int +hclge_print_mod_reg_info(struct device *dev, struct hclge_desc *desc, + const struct hclge_mod_reg_info *reg_info, int size) +{ + int i, j, pos, actual_len; + u8 offset, bd_idx, index; + char *buf; + + buf = kzalloc(HCLGE_MOD_REG_INFO_LEN_MAX, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < size; i++) { + actual_len = strlen(reg_info[i].reg_name) + + HCLGE_MOD_REG_EXTRA_LEN + + HCLGE_MOD_REG_VALUE_LEN * reg_info[i].group_size; + if (actual_len > HCLGE_MOD_REG_INFO_LEN_MAX) { + dev_info(dev, "length of reg(%s) is invalid, len=%d\n", + reg_info[i].reg_name, actual_len); + continue; + } + + pos = scnprintf(buf, HCLGE_MOD_REG_INFO_LEN_MAX, "%s", + reg_info[i].reg_name); + if (reg_info[i].has_suffix) + pos += scnprintf(buf + pos, + HCLGE_MOD_REG_INFO_LEN_MAX - pos, "%u", + le32_to_cpu(desc->data[0])); + pos += scnprintf(buf + pos, + HCLGE_MOD_REG_INFO_LEN_MAX - pos, + ":"); + for (j = 0; j < reg_info[i].group_size; j++) { + offset = reg_info[i].reg_offset_group[j]; + index = offset % HCLGE_DESC_DATA_LEN; + bd_idx = offset / HCLGE_DESC_DATA_LEN; + pos += scnprintf(buf + pos, + HCLGE_MOD_REG_INFO_LEN_MAX - pos, + " %08x", + le32_to_cpu(desc[bd_idx].data[index])); + } + buf[pos] = '\0'; + dev_info(dev, "%s\n", buf); + } + + kfree(buf); + return 0; +} + +static bool hclge_err_mod_check_support_cmd(enum hclge_opcode_type opcode, + struct hclge_dev *hdev) +{ + if (opcode == HCLGE_OPC_DFX_GEN_REG && + !hnae3_ae_dev_gen_reg_dfx_supported(hdev)) + return false; + return true; +} + +/* For each common msg, send cmdq to IMP and print result reg info. + * If there is a parameter, loop it and request. + */ +static void +hclge_query_reg_info(struct hclge_dev *hdev, + struct hclge_mod_reg_common_msg *msg, u32 loop_time, + u32 *loop_para) +{ + int desc_len, i, ret; + + desc_len = msg->bd_num * sizeof(struct hclge_desc); + msg->desc = kzalloc(desc_len, GFP_KERNEL); + if (!msg->desc) { + dev_err(&hdev->pdev->dev, "failed to query reg info, ret=%d", + -ENOMEM); + return; + } + + for (i = 0; i < loop_time; i++) { + ret = hclge_dbg_cmd_send(hdev, msg->desc, *loop_para, + msg->bd_num, msg->cmd); + loop_para++; + if (ret) + continue; + ret = hclge_print_mod_reg_info(&hdev->pdev->dev, msg->desc, + msg->result_regs, + msg->result_regs_size); + if (ret) + dev_err(&hdev->pdev->dev, "failed to print mod reg info, ret=%d\n", + ret); + } + + kfree(msg->desc); +} + +static void hclge_query_reg_info_of_ssu(struct hclge_dev *hdev) +{ + u32 loop_para[HCLGE_MOD_MSG_PARA_ARRAY_MAX_SIZE] = {0}; + struct hclge_mod_reg_common_msg msg; + u8 i, j, num; + u32 loop_time; + + num = ARRAY_SIZE(hclge_ssu_reg_common_msg); + for (i = 0; i < num; i++) { + msg = hclge_ssu_reg_common_msg[i]; + if (!hclge_err_mod_check_support_cmd(msg.cmd, hdev)) + continue; + loop_time = 1; + loop_para[0] = 0; + if (msg.need_para) { + loop_time = hdev->ae_dev->dev_specs.tnl_num; + for (j = 0; j < loop_time; j++) + loop_para[j] = j + 1; + } + hclge_query_reg_info(hdev, &msg, loop_time, loop_para); + } +} + static const struct hclge_hw_module_id hclge_hw_module_id_st[] = { { .module_id = MODULE_NONE, @@ -1210,7 +1630,8 @@ static const struct hclge_hw_module_id hclge_hw_module_id_st[] = { .msg = "MODULE_GE" }, { .module_id = MODULE_IGU_EGU, - .msg = "MODULE_IGU_EGU" + .msg = "MODULE_IGU_EGU", + .query_reg_info = hclge_query_reg_info_of_ssu }, { .module_id = MODULE_LGE, .msg = "MODULE_LGE" @@ -1231,7 +1652,8 @@ static const struct hclge_hw_module_id hclge_hw_module_id_st[] = { .msg = "MODULE_RTC" }, { .module_id = MODULE_SSU, - .msg = "MODULE_SSU" + .msg = "MODULE_SSU", + .query_reg_info = hclge_query_reg_info_of_ssu }, { .module_id = MODULE_TM, .msg = "MODULE_TM" @@ -1277,6 +1699,15 @@ static const struct hclge_hw_module_id hclge_hw_module_id_st[] = { }, { .module_id = MODULE_ROCEE_LSAN, .msg = "MODULE_ROCEE_LSAN" + }, { + .module_id = MODULE_ROH_MAC_IF, + .msg = "MODULE_ROH_MAC_IF" + }, { + .module_id = MODULE_ROH_HDLC, + .msg = "MODULE_ROH_HDLC" + }, { + .module_id = MODULE_ROH_HPCS, + .msg = "MODULE_ROH_HPCS" } }; @@ -1337,7 +1768,10 @@ static const struct hclge_hw_type_id hclge_hw_type_id_st[] = { }, { .type_id = ROCEE_BUS_ERR, .msg = "rocee_bus_error" - }, + }, { + .type_id = ROH_ERR, + .msg = "roh_error" + } }; static void hclge_log_error(struct device *dev, char *reg, @@ -2762,7 +3196,7 @@ void hclge_handle_occurred_error(struct hclge_dev *hdev) } static bool -hclge_handle_error_type_reg_log(struct device *dev, +hclge_handle_error_type_reg_log(struct hclge_dev *hdev, struct hclge_mod_err_info *mod_info, struct hclge_type_reg_err_info *type_reg_info) { @@ -2770,6 +3204,7 @@ hclge_handle_error_type_reg_log(struct device *dev, #define HCLGE_ERR_TYPE_IS_RAS_OFFSET 7 u8 mod_id, total_module, type_id, total_type, i, is_ras; + struct device *dev = &hdev->pdev->dev; u8 index_module = MODULE_NONE; u8 index_type = NONE_ERROR; bool cause_by_vf = false; @@ -2810,6 +3245,9 @@ hclge_handle_error_type_reg_log(struct device *dev, for (i = 0; i < type_reg_info->reg_num; i++) dev_err(dev, "0x%08x\n", type_reg_info->hclge_reg[i]); + if (hclge_hw_module_id_st[index_module].query_reg_info) + hclge_hw_module_id_st[index_module].query_reg_info(hdev); + return cause_by_vf; } @@ -2850,7 +3288,7 @@ static void hclge_handle_error_module_log(struct hnae3_ae_dev *ae_dev, type_reg_info = (struct hclge_type_reg_err_info *) &buf[offset++]; - if (hclge_handle_error_type_reg_log(dev, mod_info, + if (hclge_handle_error_type_reg_log(hdev, mod_info, type_reg_info)) cause_by_vf = true; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h index 68b738affa660a9bbcaa8c75c81d93a215615398..1667a6466f375c1000caea544b31ba5d502952a1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h @@ -5,6 +5,7 @@ #define __HCLGE_ERR_H #include "hclge_main.h" +#include "hclge_debugfs.h" #include "hnae3.h" #define HCLGE_MPF_RAS_INT_MIN_BD_NUM 10 @@ -15,8 +16,10 @@ #define HCLGE_RAS_PF_OTHER_INT_STS_REG 0x20B00 #define HCLGE_RAS_REG_NFE_MASK 0xFF00 #define HCLGE_RAS_REG_ROCEE_ERR_MASK 0x3000000 +#define HCLGE_RAS_REG_ROH_ERR_MASK 0x18000000 #define HCLGE_RAS_REG_ERR_MASK \ - (HCLGE_RAS_REG_NFE_MASK | HCLGE_RAS_REG_ROCEE_ERR_MASK) + (HCLGE_RAS_REG_NFE_MASK | HCLGE_RAS_REG_ROCEE_ERR_MASK | \ + HCLGE_RAS_REG_ROH_ERR_MASK) #define HCLGE_VECTOR0_REG_MSIX_MASK 0x1FF00 @@ -115,6 +118,18 @@ #define HCLGE_REG_NUM_MAX 256 #define HCLGE_DESC_NO_DATA_LEN 8 +#define HCLGE_BD_NUM_SSU_REG_0 10 +#define HCLGE_BD_NUM_SSU_REG_1 15 +#define HCLGE_BD_NUM_RPU_REG_0 1 +#define HCLGE_BD_NUM_RPU_REG_1 2 +#define HCLGE_BD_NUM_IGU_EGU_REG 9 +#define HCLGE_BD_NUM_GEN_REG 8 +#define HCLGE_MOD_REG_INFO_LEN_MAX 256 +#define HCLGE_MOD_REG_EXTRA_LEN 11 +#define HCLGE_MOD_REG_VALUE_LEN 9 +#define HCLGE_MOD_REG_GROUP_MAX_SIZE 6 +#define HCLGE_MOD_MSG_PARA_ARRAY_MAX_SIZE 8 + enum hclge_err_int_type { HCLGE_ERR_INT_MSIX = 0, HCLGE_ERR_INT_RAS_CE = 1, @@ -151,6 +166,10 @@ enum hclge_mod_name_list { MODULE_ROCEE_QMM = 48, MODULE_ROCEE_LSAN = 49, /* add new MODULE NAME for RoCEE here in order */ + MODULE_ROH_MAC_IF = 80, + MODULE_ROH_HDLC = 81, + MODULE_ROH_HPCS = 82, + /* add new MODULE NAME for ROH here in order */ }; enum hclge_err_type_list { @@ -174,6 +193,8 @@ enum hclge_err_type_list { ROCEE_OVF_ERR = 41, ROCEE_BUS_ERR = 42, /* add new ERROR TYPE for ROCEE here in order */ + ROH_ERR = 80, + /* add new ERROR TYPE for ROH here in order */ }; struct hclge_hw_blk { @@ -191,6 +212,7 @@ struct hclge_hw_error { struct hclge_hw_module_id { enum hclge_mod_name_list module_id; const char *msg; + void (*query_reg_info)(struct hclge_dev *hdev); }; struct hclge_hw_type_id { @@ -218,6 +240,28 @@ struct hclge_type_reg_err_info { u32 hclge_reg[HCLGE_REG_NUM_MAX]; }; +struct hclge_mod_reg_info { + const char *reg_name; + bool has_suffix; /* add suffix for register name */ + /* the positions of reg values in hclge_desc.data */ + u8 reg_offset_group[HCLGE_MOD_REG_GROUP_MAX_SIZE]; + u8 group_size; +}; + +/* This structure defines cmdq used to query the hardware module debug + * regisgers. + */ +struct hclge_mod_reg_common_msg { + enum hclge_opcode_type cmd; + struct hclge_desc *desc; + u8 bd_num; /* the bd number of hclge_desc used */ + bool need_para; /* whether this cmdq needs to add para */ + + /* the regs need to print */ + const struct hclge_mod_reg_info *result_regs; + u16 result_regs_size; +}; + int hclge_config_mac_tnl_int(struct hclge_dev *hdev, bool en); int hclge_config_nic_hw_error(struct hclge_dev *hdev, bool state); int hclge_config_rocee_ras_interrupt(struct hclge_dev *hdev, bool en); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index f38b02e102ee77764cd1b4d3b9c95ab2eee87c12..be6fb312ed90628785fbeda8248d62b66ee6f435 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "hclge_cmd.h" #include "hclge_dcb.h" #include "hclge_ext.h" @@ -27,6 +28,7 @@ #include "hnae3.h" #include "hclge_devlink.h" #include "hclge_comm_cmd.h" +#include "hclge_trace.h" #define HCLGE_NAME "hclge" @@ -76,7 +78,10 @@ static const struct pci_device_id ae_algo_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA_MACSEC), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), 0}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_ROH), 0}, {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}, /* required last entry */ {0, } }; @@ -334,7 +339,9 @@ static const struct key_info tuple_key_info[] = { { OUTER_SRC_PORT, 16, KEY_OPT_LE16, -1, -1 }, { OUTER_DST_PORT, 16, KEY_OPT_LE16, -1, -1 }, { OUTER_L4_RSV, 32, KEY_OPT_LE32, -1, -1 }, - { OUTER_TUN_VNI, 24, KEY_OPT_VNI, -1, -1 }, + { OUTER_TUN_VNI, 24, KEY_OPT_VNI, + offsetof(struct hclge_fd_rule, tuples.outer_tun_vni), + offsetof(struct hclge_fd_rule, tuples_mask.outer_tun_vni) }, { OUTER_TUN_FLOW_ID, 8, KEY_OPT_U8, -1, -1 }, { INNER_DST_MAC, 48, KEY_OPT_MAC, offsetof(struct hclge_fd_rule, tuples.dst_mac), @@ -392,6 +399,48 @@ int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num) return hclge_comm_cmd_send(&hw->hw, desc, num); } +static void hclge_trace_cmd_send(struct hclge_comm_hw *hw, struct hclge_desc *desc, + int num, bool is_special) +{ + int i; + + trace_hclge_pf_cmd_send(hw, desc, 0, num); + + if (!is_special) { + for (i = 1; i < num; i++) + trace_hclge_pf_cmd_send(hw, &desc[i], i, num); + } else { + for (i = 1; i < num; i++) + trace_hclge_pf_special_cmd_send(hw, (u32 *)&desc[i], + i, num); + } +} + +static void hclge_trace_cmd_get(struct hclge_comm_hw *hw, struct hclge_desc *desc, + int num, bool is_special) +{ + int i; + + if (!HCLGE_COMM_SEND_SYNC(le16_to_cpu(desc->flag))) + return; + + trace_hclge_pf_cmd_get(hw, desc, 0, num); + + if (!is_special) { + for (i = 1; i < num; i++) + trace_hclge_pf_cmd_get(hw, &desc[i], i, num); + } else { + for (i = 1; i < num; i++) + trace_hclge_pf_special_cmd_get(hw, (u32 *)&desc[i], + i, num); + } +} + +static const struct hclge_comm_cmq_ops hclge_cmq_ops = { + .trace_cmd_send = hclge_trace_cmd_send, + .trace_cmd_get = hclge_trace_cmd_get, +}; + static int hclge_mac_update_stats_defective(struct hclge_dev *hdev) { #define HCLGE_MAC_CMD_NUM 21 @@ -831,11 +880,14 @@ static int hclge_query_pf_resource(struct hclge_dev *hdev) if (hnae3_dev_roce_supported(hdev)) { hdev->num_roce_msi = le16_to_cpu(req->pf_intr_vector_number_roce); + hdev->num_roh_msi = + le16_to_cpu(req->pf_intr_vector_number_roh); /* PF should have NIC vectors and Roce vectors, * NIC vectors are queued before Roce vectors. */ - hdev->num_msi = hdev->num_nic_msi + hdev->num_roce_msi; + hdev->num_msi = hdev->num_nic_msi + hdev->num_roce_msi + + hdev->num_roh_msi; } else { hdev->num_msi = hdev->num_nic_msi; } @@ -1436,6 +1488,20 @@ static int hclge_query_dev_specs(struct hclge_dev *hdev) return 0; } +static void hclge_mac_type_init(struct hclge_dev *hdev) +{ + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + u32 dev_id = hdev->pdev->device; + + if (dev_id == HNAE3_DEV_ID_100G_ROH || + dev_id == HNAE3_DEV_ID_200G_ROH || + dev_id == HNAE3_DEV_ID_400G_ROH) + handle->mac_type = HNAE3_MAC_ROH; + else + handle->mac_type = HNAE3_MAC_ETH; +} + static int hclge_get_cap(struct hclge_dev *hdev) { int ret; @@ -2464,6 +2530,25 @@ static int hclge_init_roce_base_info(struct hclge_vport *vport) return 0; } +static int hclge_init_roh_base_info(struct hclge_vport *vport) +{ + struct hnae3_handle *roh = &vport->roh; + struct hnae3_handle *nic = &vport->nic; + struct hclge_dev *hdev = vport->back; + + if (hdev->num_msi < hdev->num_nic_msi + hdev->num_roce_msi + + hdev->num_roh_msi) + return -EINVAL; + + roh->rohinfo.netdev = nic->kinfo.netdev; + roh->rohinfo.roh_io_base = hdev->hw.hw.io_base; + + roh->pdev = nic->pdev; + roh->ae_algo = nic->ae_algo; + + return 0; +} + static int hclge_init_msi(struct hclge_dev *hdev) { struct pci_dev *pdev = hdev->pdev; @@ -2898,11 +2983,27 @@ static void hclge_get_fec(struct hnae3_handle *handle, u8 *fec_ability, *fec_mode = mac->fec_mode; } +static void hclge_roh_convert_mac_addr(struct hclge_dev *hdev) +{ +#define HCLGE_ROH_EID_MASK_BYTE 3 + + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + + if (hnae3_check_roh_mac_type(handle)) { + if (!is_valid_ether_addr(hdev->hw.mac.mac_addr)) + eth_random_addr(hdev->hw.mac.mac_addr); + memset(hdev->hw.mac.mac_addr, 0, HCLGE_ROH_EID_MASK_BYTE); + } +} + static int hclge_mac_init(struct hclge_dev *hdev) { struct hclge_mac *mac = &hdev->hw.mac; int ret; + hclge_roh_convert_mac_addr(hdev); + hclge_mac_type_init(hdev); hdev->support_sfp_query = true; if (!test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) @@ -4583,6 +4684,177 @@ static void hclge_update_vport_alive(struct hclge_dev *hdev) } } +static int hclge_set_fd_qb_counter(struct hclge_dev *hdev, u8 vf_id) +{ + struct hclge_fd_qb_ad_cmd *req; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_QB_AD_OP, false); + req = (struct hclge_fd_qb_ad_cmd *)desc.data; + req->vf_id = vf_id; + hnae3_set_bit(req->ad_sel, HCLGE_FD_QB_AD_COUNTER_VLD_B, 1); + req->counter_id = vf_id % hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1]; + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_warn(&hdev->pdev->dev, + "failed to set qb counter for vport %u, ret = %d.\n", + vf_id, ret); + return ret; +} + +static void hclge_init_fd_qb_counter(struct hclge_dev *hdev) +{ + int ret; + u16 i; + + if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, hdev->ae_dev->caps)) + return; + + for (i = 0; i < hdev->num_alloc_vport; i++) { + ret = hclge_set_fd_qb_counter(hdev, i); + if (ret) + return; + } +} + +static int hclge_set_fd_qb(struct hclge_dev *hdev, u8 vf_id, bool enable) +{ + struct hclge_fd_qb_cfg_cmd *req; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_QB_CTRL, false); + req = (struct hclge_fd_qb_cfg_cmd *)desc.data; + req->en = enable; + req->vf_id = vf_id; + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to %s qb config for vport %u, ret = %d.\n", + enable ? "enable" : "disable", vf_id, ret); + return ret; +} + +static int hclge_sync_pf_qb_mode(struct hclge_dev *hdev) +{ + struct hclge_vport *vport = &hdev->vport[0]; + struct hnae3_handle *handle = &vport->nic; + bool request_enable = true; + int ret; + u16 i; + + if (!test_and_clear_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state)) + return 0; + + spin_lock_bh(&hdev->fd_rule_lock); + if (hdev->fd_active_type == HCLGE_FD_EP_ACTIVE || + hdev->fd_active_type == HCLGE_FD_TC_FLOWER_ACTIVE || + !test_bit(HNAE3_PFLAG_FD_QB_ENABLE, &handle->priv_flags)) + request_enable = false; + + if (request_enable == + test_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state)) { + spin_unlock_bh(&hdev->fd_rule_lock); + return 0; + } + + if (request_enable) + hclge_clear_arfs_rules(hdev); + + ret = hclge_set_fd_qb(hdev, vport->vport_id, request_enable); + if (!ret) { + if (request_enable) { + set_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); + hdev->fd_active_type = HCLGE_FD_QB_ACTIVE; + } else { + clear_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); + hdev->fd_active_type = HCLGE_FD_RULE_NONE; + } + + for (i = 1; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } + } else { + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } + spin_unlock_bh(&hdev->fd_rule_lock); + + return ret; +} + +static int hclge_sync_vf_qb_mode(struct hclge_vport *vport) +{ + struct hclge_dev *hdev = vport->back; + bool request_enable = false; + int ret; + + if (!test_and_clear_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state)) + return 0; + + if (vport->vf_info.trusted && vport->vf_info.request_qb_en && + test_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state)) + request_enable = true; + + ret = hclge_set_fd_qb(hdev, vport->vport_id, request_enable); + if (ret) + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + else + vport->vf_info.qb_en = request_enable ? 1 : 0; + + return ret; +} + +static int hclge_disable_fd_qb_mode(struct hclge_dev *hdev) +{ + struct hnae3_ae_dev *ae_dev = hdev->ae_dev; + struct hclge_vport *vport; + int ret; + u16 i; + + if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps) || + !test_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state)) + return 0; + + ret = hclge_set_fd_qb(hdev, 0, false); + if (ret) + return ret; + + clear_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); + + for (i = 1; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } + + return 0; +} + +static void hclge_sync_fd_qb_mode(struct hclge_dev *hdev) +{ + struct hnae3_ae_dev *ae_dev = hdev->ae_dev; + struct hclge_vport *vport; + int ret; + u16 i; + + if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps)) + return; + + ret = hclge_sync_pf_qb_mode(hdev); + if (ret) + return; + + for (i = 1; i < hdev->num_alloc_vport; i++) { + vport = &hdev->vport[i]; + + ret = hclge_sync_vf_qb_mode(vport); + if (ret) + return; + } +} + static void hclge_periodic_service_task(struct hclge_dev *hdev) { unsigned long delta = round_jiffies_relative(HZ); @@ -4596,6 +4868,7 @@ static void hclge_periodic_service_task(struct hclge_dev *hdev) hclge_update_link_status(hdev); hclge_sync_mac_table(hdev); hclge_sync_promisc_mode(hdev); + hclge_sync_fd_qb_mode(hdev); hclge_sync_fd_table(hdev); if (time_is_after_jiffies(hdev->last_serv_processed + HZ)) { @@ -4678,6 +4951,8 @@ struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle) return container_of(handle, struct hclge_vport, nic); else if (handle->client->type == HNAE3_CLIENT_ROCE) 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 return container_of(handle, struct hclge_vport, nic); } @@ -5114,10 +5389,29 @@ static void hclge_request_update_promisc_mode(struct hnae3_handle *handle) set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); } +static bool hclge_query_fd_qb_state(struct hnae3_handle *handle) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + return test_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); +} + +static void hclge_flush_qb_config(struct hnae3_handle *handle) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); +} + static void hclge_sync_fd_state(struct hclge_dev *hdev) { - if (hlist_empty(&hdev->fd_rule_list)) + struct hclge_vport *vport = &hdev->vport[0]; + + if (hlist_empty(&hdev->fd_rule_list)) { hdev->fd_active_type = HCLGE_FD_RULE_NONE; + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } } static void hclge_fd_inc_rule_cnt(struct hclge_dev *hdev, u16 location) @@ -5523,8 +5817,9 @@ static int hclge_init_fd_config(struct hclge_dev *hdev) /* If use max 400bit key, we can support tuples for ether type */ if (hdev->fd_cfg.fd_mode == HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1) { - key_cfg->tuple_active |= - BIT(INNER_DST_MAC) | BIT(INNER_SRC_MAC); + key_cfg->tuple_active |= BIT(INNER_DST_MAC) | + BIT(INNER_SRC_MAC) | + BIT(OUTER_TUN_VNI); if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3) key_cfg->tuple_active |= HCLGE_FD_TUPLE_USER_DEF_TUPLES; } @@ -5542,6 +5837,11 @@ static int hclge_init_fd_config(struct hclge_dev *hdev) if (ret) return ret; + if (!hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1]) + hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1] = 1; + + hclge_init_fd_qb_counter(hdev); + return hclge_set_fd_key_config(hdev, HCLGE_FD_STAGE_1); } @@ -5590,6 +5890,8 @@ static int hclge_fd_tcam_config(struct hclge_dev *hdev, u8 stage, bool sel_x, static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc, struct hclge_fd_ad_data *action) { +#define HCLGE_FD_COUNTER_MAX_SIZE_DEV_V2 128 + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hclge_fd_ad_config_cmd *req; struct hclge_desc desc; @@ -5616,14 +5918,17 @@ static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc, hnae3_set_bit(ad_data, HCLGE_FD_AD_DROP_B, action->drop_packet); hnae3_set_bit(ad_data, HCLGE_FD_AD_DIRECT_QID_B, action->forward_to_direct_queue); - hnae3_set_field(ad_data, HCLGE_FD_AD_QID_M, HCLGE_FD_AD_QID_S, + hnae3_set_field(ad_data, HCLGE_FD_AD_QID_L_M, HCLGE_FD_AD_QID_L_S, action->queue_id); hnae3_set_bit(ad_data, HCLGE_FD_AD_USE_COUNTER_B, action->use_counter); - hnae3_set_field(ad_data, HCLGE_FD_AD_COUNTER_NUM_M, - HCLGE_FD_AD_COUNTER_NUM_S, action->counter_id); + hnae3_set_field(ad_data, HCLGE_FD_AD_COUNTER_NUM_L_M, + HCLGE_FD_AD_COUNTER_NUM_L_S, action->counter_id); hnae3_set_bit(ad_data, HCLGE_FD_AD_NXT_STEP_B, action->use_next_stage); hnae3_set_field(ad_data, HCLGE_FD_AD_NXT_KEY_M, HCLGE_FD_AD_NXT_KEY_S, - action->counter_id); + action->next_input_key); + hnae3_set_bit(ad_data, HCLGE_FD_AD_QID_H_B, + action->queue_id >= HCLGE_FD_COUNTER_MAX_SIZE_DEV_V2 ? + 1 : 0); req->ad_data = cpu_to_le64(ad_data); ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -5636,6 +5941,8 @@ static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc, static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y, struct hclge_fd_rule *rule) { +#define HCLGE_VNI_LENGTH 3 + int offset, moffset, ip_offset; enum HCLGE_FD_KEY_OPT key_opt; u16 tmp_x_s, tmp_y_s; @@ -5688,6 +5995,14 @@ static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y, *(__le32 *)key_x = cpu_to_le32(tmp_x_l); *(__le32 *)key_y = cpu_to_le32(tmp_y_l); + return true; + case KEY_OPT_VNI: + calc_x(tmp_x_l, *(u32 *)(&p[offset]), *(u32 *)(&p[moffset])); + calc_y(tmp_y_l, *(u32 *)(&p[offset]), *(u32 *)(&p[moffset])); + for (i = 0; i < HCLGE_VNI_LENGTH; i++) { + key_x[i] = (cpu_to_le32(tmp_x_l) >> (i * BITS_PER_BYTE)) & 0xFF; + key_y[i] = (cpu_to_le32(tmp_y_l) >> (i * BITS_PER_BYTE)) & 0xFF; + } return true; default: return false; @@ -5910,6 +6225,45 @@ static int hclge_fd_check_ip4_tuple(struct ethtool_usrip4_spec *spec, return 0; } +static int hclge_fd_check_vxlan4_tuple(struct ethtool_rx_flow_spec *fs, + u32 *unused_tuple) +{ + struct ethtool_vxlan4_spec *spec = &fs->h_u.vxlan_ip4_spec; + struct ethtool_vxlan4_spec *mask = &fs->m_u.vxlan_ip4_spec; + + /* Vni is only 24 bits and must be greater than 0, and it can not be + * masked. + */ + if (!spec->vni || be32_to_cpu(spec->vni) >= VXLAN_N_VID || + mask->vni != HCLGE_FD_VXLAN_VNI_UNMASK || !unused_tuple) + return -EINVAL; + + *unused_tuple |= BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); + + if (is_zero_ether_addr(spec->src)) + *unused_tuple |= BIT(INNER_SRC_MAC); + + if (is_zero_ether_addr(spec->dst)) + *unused_tuple |= BIT(INNER_DST_MAC); + + if (!spec->eth_type) + *unused_tuple |= BIT(INNER_ETH_TYPE); + + if (!spec->ip4src) + *unused_tuple |= BIT(INNER_SRC_IP); + + if (!spec->ip4dst) + *unused_tuple |= BIT(INNER_DST_IP); + + if (!spec->tos) + *unused_tuple |= BIT(INNER_IP_TOS); + + if (!spec->l4_proto) + *unused_tuple |= BIT(INNER_IP_PROTO); + + return 0; +} + static int hclge_fd_check_tcpip6_tuple(struct ethtool_tcpip6_spec *spec, u32 *unused_tuple) { @@ -5965,6 +6319,45 @@ static int hclge_fd_check_ip6_tuple(struct ethtool_usrip6_spec *spec, return 0; } +static int hclge_fd_check_vxlan6_tuple(struct ethtool_rx_flow_spec *fs, + u32 *unused_tuple) +{ + struct ethtool_vxlan6_spec *spec = &fs->h_u.vxlan_ip6_spec; + struct ethtool_vxlan6_spec *mask = &fs->m_u.vxlan_ip6_spec; + + /* Vni is only 24 bits and must be greater than 0, and it can not be + * masked. + */ + if (!spec->vni || be32_to_cpu(spec->vni) >= VXLAN_N_VID || + mask->vni != HCLGE_FD_VXLAN_VNI_UNMASK || !unused_tuple) + return -EINVAL; + + *unused_tuple |= BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); + + if (is_zero_ether_addr(spec->src)) + *unused_tuple |= BIT(INNER_SRC_MAC); + + if (is_zero_ether_addr(spec->dst)) + *unused_tuple |= BIT(INNER_DST_MAC); + + if (!spec->eth_type) + *unused_tuple |= BIT(INNER_ETH_TYPE); + + if (ipv6_addr_any((struct in6_addr *)spec->ip6src)) + *unused_tuple |= BIT(INNER_SRC_IP); + + if (ipv6_addr_any((struct in6_addr *)spec->ip6dst)) + *unused_tuple |= BIT(INNER_DST_IP); + + if (!spec->tclass) + *unused_tuple |= BIT(INNER_IP_TOS); + + if (!spec->l4_proto) + *unused_tuple |= BIT(INNER_IP_PROTO); + + return 0; +} + static int hclge_fd_check_ether_tuple(struct ethhdr *spec, u32 *unused_tuple) { if (!spec || !unused_tuple) @@ -6147,6 +6540,9 @@ static int hclge_fd_check_spec(struct hclge_dev *hdev, ret = hclge_fd_check_ip4_tuple(&fs->h_u.usr_ip4_spec, unused_tuple); break; + case VXLAN_V4_FLOW: + ret = hclge_fd_check_vxlan4_tuple(fs, unused_tuple); + break; case SCTP_V6_FLOW: case TCP_V6_FLOW: case UDP_V6_FLOW: @@ -6157,6 +6553,9 @@ static int hclge_fd_check_spec(struct hclge_dev *hdev, ret = hclge_fd_check_ip6_tuple(&fs->h_u.usr_ip6_spec, unused_tuple); break; + case VXLAN_V6_FLOW: + ret = hclge_fd_check_vxlan6_tuple(fs, unused_tuple); + break; case ETHER_FLOW: if (hdev->fd_cfg.fd_mode != HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1) { @@ -6237,6 +6636,37 @@ static void hclge_fd_get_ip4_tuple(struct ethtool_rx_flow_spec *fs, rule->tuples_mask.ether_proto = 0xFFFF; } +static void hclge_fd_get_vxlan4_tuple(struct ethtool_rx_flow_spec *fs, + struct hclge_fd_rule *rule) +{ + struct ethtool_vxlan4_spec *h = &fs->h_u.vxlan_ip4_spec; + struct ethtool_vxlan4_spec *m = &fs->m_u.vxlan_ip4_spec; + + rule->tuples.outer_tun_vni = be32_to_cpu(h->vni); + rule->tuples_mask.outer_tun_vni = be32_to_cpu(m->vni); + + ether_addr_copy(rule->tuples.src_mac, h->src); + ether_addr_copy(rule->tuples_mask.src_mac, m->src); + + ether_addr_copy(rule->tuples.dst_mac, h->dst); + ether_addr_copy(rule->tuples_mask.dst_mac, m->dst); + + rule->tuples.ether_proto = be16_to_cpu(h->eth_type); + rule->tuples_mask.ether_proto = be16_to_cpu(m->eth_type); + + rule->tuples.ip_tos = h->tos; + rule->tuples_mask.ip_tos = m->tos; + + rule->tuples.ip_proto = h->l4_proto; + rule->tuples_mask.ip_proto = m->l4_proto; + + rule->tuples.src_ip[IPV4_INDEX] = be32_to_cpu(h->ip4src); + rule->tuples_mask.src_ip[IPV4_INDEX] = be32_to_cpu(m->ip4src); + + rule->tuples.dst_ip[IPV4_INDEX] = be32_to_cpu(h->ip4dst); + rule->tuples_mask.dst_ip[IPV4_INDEX] = be32_to_cpu(m->ip4dst); +} + static void hclge_fd_get_tcpip6_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule, u8 ip_proto) { @@ -6266,6 +6696,37 @@ static void hclge_fd_get_tcpip6_tuple(struct ethtool_rx_flow_spec *fs, rule->tuples_mask.ip_proto = 0xFF; } +static void hclge_fd_get_vxlan6_tuple(struct ethtool_rx_flow_spec *fs, + struct hclge_fd_rule *rule) +{ + struct ethtool_vxlan6_spec *h = &fs->h_u.vxlan_ip6_spec; + struct ethtool_vxlan6_spec *m = &fs->m_u.vxlan_ip6_spec; + + rule->tuples.outer_tun_vni = be32_to_cpu(h->vni); + rule->tuples_mask.outer_tun_vni = be32_to_cpu(m->vni); + + ether_addr_copy(rule->tuples.src_mac, h->src); + ether_addr_copy(rule->tuples_mask.src_mac, m->src); + + ether_addr_copy(rule->tuples.dst_mac, h->dst); + ether_addr_copy(rule->tuples_mask.dst_mac, m->dst); + + rule->tuples.ether_proto = be16_to_cpu(h->eth_type); + rule->tuples_mask.ether_proto = be16_to_cpu(m->eth_type); + + rule->tuples.ip_tos = h->tclass; + rule->tuples_mask.ip_tos = m->tclass; + + rule->tuples.ip_proto = h->l4_proto; + rule->tuples_mask.ip_proto = m->l4_proto; + + be32_to_cpu_array(rule->tuples.src_ip, h->ip6src, IPV6_SIZE); + be32_to_cpu_array(rule->tuples_mask.src_ip, m->ip6src, IPV6_SIZE); + + be32_to_cpu_array(rule->tuples.dst_ip, h->ip6dst, IPV6_SIZE); + be32_to_cpu_array(rule->tuples_mask.dst_ip, m->ip6dst, IPV6_SIZE); +} + static void hclge_fd_get_ip6_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { @@ -6344,6 +6805,9 @@ static int hclge_fd_get_tuple(struct ethtool_rx_flow_spec *fs, case IP_USER_FLOW: hclge_fd_get_ip4_tuple(fs, rule); break; + case VXLAN_V4_FLOW: + hclge_fd_get_vxlan4_tuple(fs, rule); + break; case SCTP_V6_FLOW: hclge_fd_get_tcpip6_tuple(fs, rule, IPPROTO_SCTP); break; @@ -6356,6 +6820,9 @@ static int hclge_fd_get_tuple(struct ethtool_rx_flow_spec *fs, case IPV6_USER_FLOW: hclge_fd_get_ip6_tuple(fs, rule); break; + case VXLAN_V6_FLOW: + hclge_fd_get_vxlan6_tuple(fs, rule); + break; case ETHER_FLOW: hclge_fd_get_ether_tuple(fs, rule); break; @@ -6394,6 +6861,10 @@ static int hclge_add_fd_entry_common(struct hclge_dev *hdev, { int ret; + ret = hclge_disable_fd_qb_mode(hdev); + if (ret) + return ret; + spin_lock_bh(&hdev->fd_rule_lock); if (hdev->fd_active_type != rule->rule_type && @@ -6702,6 +7173,48 @@ static void hclge_fd_get_ip4_info(struct hclge_fd_rule *rule, spec->ip_ver = ETH_RX_NFC_IP4; } +static void hclge_fd_get_vxlan4_info(struct hclge_fd_rule *rule, + struct ethtool_vxlan4_spec *spec, + struct ethtool_vxlan4_spec *spec_mask) +{ + spec->vni = cpu_to_be32(rule->tuples.outer_tun_vni); + spec_mask->vni = rule->unused_tuple & BIT(OUTER_TUN_VNI) ? 0 : + cpu_to_be32(rule->tuples_mask.outer_tun_vni); + + ether_addr_copy(spec->src, rule->tuples.src_mac); + ether_addr_copy(spec->dst, rule->tuples.dst_mac); + + if (rule->unused_tuple & BIT(INNER_SRC_MAC)) + eth_zero_addr(spec_mask->src); + else + ether_addr_copy(spec_mask->src, rule->tuples_mask.src_mac); + + if (rule->unused_tuple & BIT(INNER_DST_MAC)) + eth_zero_addr(spec_mask->dst); + else + ether_addr_copy(spec_mask->dst, rule->tuples_mask.dst_mac); + + spec->eth_type = cpu_to_be16(rule->tuples.ether_proto); + spec_mask->eth_type = rule->unused_tuple & BIT(INNER_ETH_TYPE) ? 0 : + cpu_to_be16(rule->tuples_mask.ether_proto); + + spec->tos = rule->tuples.ip_tos; + spec_mask->tos = rule->unused_tuple & BIT(INNER_IP_TOS) ? 0 : + rule->tuples_mask.ip_tos; + + spec->l4_proto = rule->tuples.ip_proto; + spec_mask->l4_proto = rule->unused_tuple & BIT(INNER_IP_PROTO) ? 0 : + rule->tuples_mask.ip_proto; + + spec->ip4src = cpu_to_be32(rule->tuples.src_ip[IPV4_INDEX]); + spec_mask->ip4src = rule->unused_tuple & BIT(INNER_SRC_IP) ? 0 : + cpu_to_be32(rule->tuples_mask.src_ip[IPV4_INDEX]); + + spec->ip4dst = cpu_to_be32(rule->tuples.dst_ip[IPV4_INDEX]); + spec_mask->ip4dst = rule->unused_tuple & BIT(INNER_DST_IP) ? 0 : + cpu_to_be32(rule->tuples_mask.dst_ip[IPV4_INDEX]); +} + static void hclge_fd_get_tcpip6_info(struct hclge_fd_rule *rule, struct ethtool_tcpip6_spec *spec, struct ethtool_tcpip6_spec *spec_mask) @@ -6762,6 +7275,56 @@ static void hclge_fd_get_ip6_info(struct hclge_fd_rule *rule, 0 : rule->tuples_mask.ip_proto; } +static void hclge_fd_get_vxlan6_info(struct hclge_fd_rule *rule, + struct ethtool_vxlan6_spec *spec, + struct ethtool_vxlan6_spec *spec_mask) +{ + spec->vni = cpu_to_be32(rule->tuples.outer_tun_vni); + spec_mask->vni = rule->unused_tuple & BIT(OUTER_TUN_VNI) ? 0 : + cpu_to_be32(rule->tuples_mask.outer_tun_vni); + + ether_addr_copy(spec->src, rule->tuples.src_mac); + ether_addr_copy(spec->dst, rule->tuples.dst_mac); + + if (rule->unused_tuple & BIT(INNER_SRC_MAC)) + eth_zero_addr(spec_mask->src); + else + ether_addr_copy(spec_mask->src, rule->tuples_mask.src_mac); + + if (rule->unused_tuple & BIT(INNER_DST_MAC)) + eth_zero_addr(spec_mask->dst); + else + ether_addr_copy(spec_mask->dst, rule->tuples_mask.dst_mac); + + spec->eth_type = cpu_to_be16(rule->tuples.ether_proto); + spec_mask->eth_type = rule->unused_tuple & BIT(INNER_ETH_TYPE) ? 0 : + cpu_to_be16(rule->tuples_mask.ether_proto); + + spec->tclass = rule->tuples.ip_tos; + spec_mask->tclass = rule->unused_tuple & BIT(INNER_IP_TOS) ? 0 : + rule->tuples_mask.ip_tos; + + spec->l4_proto = rule->tuples.ip_proto; + spec_mask->l4_proto = rule->unused_tuple & BIT(INNER_IP_PROTO) ? 0 : + rule->tuples_mask.ip_proto; + + cpu_to_be32_array(spec->ip6src, + rule->tuples.src_ip, IPV6_SIZE); + cpu_to_be32_array(spec->ip6dst, + rule->tuples.dst_ip, IPV6_SIZE); + if (rule->unused_tuple & BIT(INNER_SRC_IP)) + memset(spec_mask->ip6src, 0, sizeof(spec_mask->ip6src)); + else + cpu_to_be32_array(spec_mask->ip6src, rule->tuples_mask.src_ip, + IPV6_SIZE); + + if (rule->unused_tuple & BIT(INNER_DST_IP)) + memset(spec_mask->ip6dst, 0, sizeof(spec_mask->ip6dst)); + else + cpu_to_be32_array(spec_mask->ip6dst, rule->tuples_mask.dst_ip, + IPV6_SIZE); +} + static void hclge_fd_get_ether_info(struct hclge_fd_rule *rule, struct ethhdr *spec, struct ethhdr *spec_mask) @@ -6888,6 +7451,10 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle, hclge_fd_get_ip4_info(rule, &fs->h_u.usr_ip4_spec, &fs->m_u.usr_ip4_spec); break; + case VXLAN_V4_FLOW: + hclge_fd_get_vxlan4_info(rule, &fs->h_u.vxlan_ip4_spec, + &fs->m_u.vxlan_ip4_spec); + break; case SCTP_V6_FLOW: case TCP_V6_FLOW: case UDP_V6_FLOW: @@ -6898,6 +7465,10 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle, hclge_fd_get_ip6_info(rule, &fs->h_u.usr_ip6_spec, &fs->m_u.usr_ip6_spec); break; + case VXLAN_V6_FLOW: + hclge_fd_get_vxlan6_info(rule, &fs->h_u.vxlan_ip6_spec, + &fs->m_u.vxlan_ip6_spec); + break; /* The flow type of fd rule has been checked before adding in to rule * list. As other flow types have been handled, it must be ETHER_FLOW * for the default case @@ -8039,6 +8610,7 @@ int hclge_vport_start(struct hclge_vport *vport) set_bit(HCLGE_VPORT_STATE_INITED, &vport->state); set_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); vport->last_active_jiffies = jiffies; vport->need_notify = 0; @@ -10217,6 +10789,7 @@ static void hclge_restore_hw_table(struct hclge_dev *hdev) hclge_restore_vport_port_base_vlan_config(hdev); hclge_restore_vport_vlan_table(vport); set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state); + clear_bit(HCLGE_STATE_HW_QB_ENABLE, &hdev->state); hclge_restore_fd_entries(handle); } @@ -10858,6 +11431,24 @@ static u32 hclge_get_fw_version(struct hnae3_handle *handle) return hdev->fw_version; } +int hclge_query_scc_version(struct hclge_dev *hdev, u32 *scc_version) +{ + struct hclge_comm_query_scc_cmd *resp; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_SCC_VER, 1); + resp = (struct hclge_comm_query_scc_cmd *)desc.data; + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + return ret; + + *scc_version = le32_to_cpu(resp->scc_version); + + return 0; +} + static void hclge_set_flowctrl_adv(struct hclge_dev *hdev, u32 rx_en, u32 tx_en) { struct phy_device *phydev = hdev->hw.mac.phydev; @@ -11208,6 +11799,47 @@ static int hclge_init_roce_client_instance(struct hnae3_ae_dev *ae_dev, return ret; } +static int hclge_init_roh_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 (!hdev->roh_client || !hdev->nic_client) + return 0; + + client = hdev->roh_client; + ret = hclge_init_roh_base_info(vport); + if (ret) + return ret; + + rst_cnt = hdev->rst_stats.reset_cnt; + ret = client->ops->init_instance(&vport->roh); + if (ret) + return ret; + + if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || + rst_cnt != hdev->rst_stats.reset_cnt) { + ret = -EBUSY; + goto init_roh_err; + } + + set_bit(HCLGE_STATE_ROH_REGISTERED, &hdev->state); + hnae3_set_client_init_flag(client, ae_dev, 1); + + return 0; + +init_roh_err: + while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) + msleep(HCLGE_WAIT_RESET_DONE); + + hdev->roh_client->ops->uninit_instance(&vport->roh, 0); + + return ret; +} + static int hclge_init_client_instance(struct hnae3_client *client, struct hnae3_ae_dev *ae_dev) { @@ -11223,6 +11855,14 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_nic; + ret = hclge_init_roh_client_instance(ae_dev, vport); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to init roh client, ret = %d\n", ret); + hdev->roh_client = NULL; + vport->roh.client = NULL; + } + ret = hclge_init_roce_client_instance(ae_dev, vport); if (ret) goto clear_roce; @@ -11238,6 +11878,17 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roce; + break; + case HNAE3_CLIENT_ROH: + if (hnae3_dev_roh_supported(hdev)) { + hdev->roh_client = client; + vport->roh.client = client; + } + + ret = hclge_init_roh_client_instance(ae_dev, vport); + if (ret) + goto clear_roh; + break; default: return -EINVAL; @@ -11253,6 +11904,10 @@ static int hclge_init_client_instance(struct hnae3_client *client, hdev->roce_client = NULL; vport->roce.client = NULL; return ret; +clear_roh: + hdev->roh_client = NULL; + vport->roh.client = NULL; + return ret; } static void hclge_uninit_client_instance(struct hnae3_client *client, @@ -11261,6 +11916,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->roh_client && (client->type == HNAE3_CLIENT_ROH || + client->type == HNAE3_CLIENT_KNIC)) { + clear_bit(HCLGE_STATE_ROH_REGISTERED, &hdev->state); + while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) + msleep(HCLGE_WAIT_RESET_DONE); + + hdev->roh_client->ops->uninit_instance(&vport->roh, 0); + hdev->roh_client = NULL; + vport->roh.client = NULL; + } + if (client->type == HNAE3_CLIENT_ROH) + return; + if (hdev->roce_client) { clear_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state); while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) @@ -11651,6 +12319,7 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) goto err_devlink_uninit; /* Firmware command initialize */ + hclge_comm_cmd_init_ops(&hdev->hw.hw, &hclge_cmq_ops); ret = hclge_comm_cmd_init(hdev->ae_dev, &hdev->hw.hw, &hdev->fw_version, true, hdev->reset_pending); if (ret) @@ -11957,6 +12626,8 @@ static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable) return 0; vport->vf_info.trusted = new_trusted; + + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); hclge_task_schedule(hdev, 0); @@ -12699,6 +13370,8 @@ struct hnae3_ae_ops hclge_ops = { .put_vector = hclge_put_vector, .set_promisc_mode = hclge_set_promisc_mode, .request_update_promisc_mode = hclge_request_update_promisc_mode, + .request_flush_qb_config = hclge_flush_qb_config, + .query_fd_qb_state = hclge_query_fd_qb_state, .set_loopback = hclge_set_loopback, .start = hclge_ae_start, .stop = hclge_ae_stop, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 5be6f9685624e7f100dfcd54be156f2be2e73920..7f1e31ea0f9c4e1ed834ab22ae728d5f834b9ead 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -214,6 +214,7 @@ enum HCLGE_DEV_STATE { HCLGE_STATE_REMOVING, HCLGE_STATE_NIC_REGISTERED, HCLGE_STATE_ROCE_REGISTERED, + HCLGE_STATE_ROH_REGISTERED, HCLGE_STATE_SERVICE_INITED, HCLGE_STATE_RST_SERVICE_SCHED, HCLGE_STATE_RST_HANDLING, @@ -226,6 +227,7 @@ enum HCLGE_DEV_STATE { HCLGE_STATE_FD_TBL_CHANGED, HCLGE_STATE_FD_CLEAR_ALL, HCLGE_STATE_FD_USER_DEF_CHANGED, + HCLGE_STATE_HW_QB_ENABLE, HCLGE_STATE_PTP_EN, HCLGE_STATE_PTP_TX_HANDLING, HCLGE_STATE_FEC_STATS_UPDATING, @@ -377,6 +379,8 @@ struct hclge_cfg { u16 umv_space; }; +#define TM_RATE_PORT_RATE_SCALE 125000 + struct hclge_tm_info { u8 num_tc; u8 num_pg; /* It must be 1 if vNET-Base schd */ @@ -643,6 +647,7 @@ struct key_info { #define HCLGE_FD_USER_DEF_DATA GENMASK(15, 0) #define HCLGE_FD_USER_DEF_OFFSET GENMASK(15, 0) #define HCLGE_FD_USER_DEF_OFFSET_UNMASK GENMASK(15, 0) +#define HCLGE_FD_VXLAN_VNI_UNMASK GENMASK(31, 0) /* assigned by firmware, the real filter number for each pf may be less */ #define MAX_FD_FILTER_NUM 4096 @@ -658,6 +663,7 @@ enum HCLGE_FD_ACTIVE_RULE_TYPE { HCLGE_FD_ARFS_ACTIVE, HCLGE_FD_EP_ACTIVE, HCLGE_FD_TC_FLOWER_ACTIVE, + HCLGE_FD_QB_ACTIVE, }; enum HCLGE_FD_PACKET_TYPE { @@ -736,6 +742,7 @@ struct hclge_fd_rule_tuples { u32 l4_user_def; u8 ip_tos; u8 ip_proto; + u32 outer_tun_vni; }; struct hclge_fd_rule { @@ -919,6 +926,7 @@ struct hclge_dev { int *vector_irq; 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 */ unsigned long service_timer_period; unsigned long service_timer_previous; @@ -935,6 +943,7 @@ struct hclge_dev { struct hnae3_client *nic_client; struct hnae3_client *roce_client; + struct hnae3_client *roh_client; #define HCLGE_FLAG_MAIN BIT(0) #define HCLGE_FLAG_DCB_CAPABLE BIT(1) @@ -1015,6 +1024,7 @@ struct hclge_rx_vtag_cfg { enum HCLGE_VPORT_STATE { HCLGE_VPORT_STATE_ALIVE, HCLGE_VPORT_STATE_MAC_TBL_CHANGE, + HCLGE_VPORT_STATE_QB_CHANGE, HCLGE_VPORT_STATE_PROMISC_CHANGE, HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, HCLGE_VPORT_STATE_INITED, @@ -1045,6 +1055,8 @@ struct hclge_vf_info { u32 spoofchk; u32 max_tx_rate; u32 trusted; + u8 request_qb_en; + u8 qb_en; u8 request_uc_en; u8 request_mc_en; u8 request_bc_en; @@ -1070,6 +1082,7 @@ struct hclge_vport { struct hclge_dev *back; /* Back reference to associated dev */ struct hnae3_handle nic; struct hnae3_handle roce; + struct hnae3_handle roh; unsigned long state; unsigned long need_notify; @@ -1174,6 +1187,7 @@ int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en); int hclge_mac_update_stats(struct hclge_dev *hdev); struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf); int hclge_inform_vf_reset(struct hclge_vport *vport, u16 reset_type); +int hclge_query_scc_version(struct hclge_dev *hdev, u32 *scc_version); void hclge_reset_task_schedule(struct hclge_dev *hdev); void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle); void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 4d943f9c483beecf1439b40ec1514297f89cbfa8..700a074ef753b145450280ba2025453a75e8bafd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -831,6 +831,36 @@ static void hclge_handle_vf_tbl(struct hclge_vport *vport, } } +static void hclge_handle_vf_qb(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req, + struct hclge_respond_to_vf_msg *resp_msg) +{ + struct hclge_dev *hdev = vport->back; + + if (mbx_req->msg.subcode == HCLGE_MBX_QB_CHECK_CAPS) { + struct hnae3_handle *handle = &hdev->vport[0].nic; + + resp_msg->data[0] = test_bit(HNAE3_PFLAG_FD_QB_ENABLE, + &handle->supported_pflags); + resp_msg->len = sizeof(u8); + } else if (mbx_req->msg.subcode == HCLGE_MBX_QB_ENABLE) { + vport->vf_info.request_qb_en = mbx_req->msg.data[0]; + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } else if (mbx_req->msg.subcode == HCLGE_MBX_QB_GET_STATE) { + u16 msg_data = vport->vf_info.qb_en; + int ret; + + ret = hclge_send_mbx_msg(vport, (u8 *)&msg_data, + sizeof(msg_data), + HCLGE_MBX_PUSH_QB_STATE, + vport->vport_id); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to inform qb state to vport %u, ret = %d\n", + vport->vport_id, ret); + } +} + static int hclge_mbx_map_ring_to_vector_handler(struct hclge_mbx_ops_param *param) { @@ -1040,6 +1070,12 @@ static int hclge_mbx_handle_vf_tbl_handler(struct hclge_mbx_ops_param *param) return 0; } +static int hclge_mbx_handle_vf_qb_handler(struct hclge_mbx_ops_param *param) +{ + hclge_handle_vf_qb(param->vport, param->req, param->resp_msg); + return 0; +} + 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, @@ -1064,6 +1100,7 @@ static const hclge_mbx_ops_fn hclge_mbx_ops_list[HCLGE_MBX_OPCODE_MAX] = { [HCLGE_MBX_VF_UNINIT] = hclge_mbx_vf_uninit_handler, [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, [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_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 6387120bee04c884d0077e68eb3171c64a94809e..a8350940fd5efeb32ae961eac200421da36bf93b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -1668,8 +1668,58 @@ void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc) hclge_tm_schd_info_init(hdev); } +static int hclge_tc_rate_limit_cfg(struct hclge_dev *hdev, u32 speed, u8 tc) +{ + struct hclge_tc_rate_limit_cmd *tc_rate_limit_cmd; + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TM_TC_RATE_LIMIT_CFG, + false); + + tc_rate_limit_cmd = (struct hclge_tc_rate_limit_cmd *)desc.data; + tc_rate_limit_cmd->speed = cpu_to_le32(speed); + tc_rate_limit_cmd->tc_id = tc; + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_err(&hdev->pdev->dev, + "failed to config tc(%u) rate limit, ret = %d\n", + tc, ret); + + return ret; +} + +int hclge_tm_set_tc_rate_limit(struct hclge_dev *hdev, + struct hnae3_tc_info *tc_info) +{ + u32 speed; + int ret; + int i; + + for (i = 0; i < tc_info->num_tc; i++) { + /* mac speed unit is Mbps, tc max_rate is Bps */ + speed = hclge_tm_rate_2_port_rate(tc_info->max_rate[i]); + if (!speed) + speed = hdev->hw.mac.max_speed; + + ret = hclge_tc_rate_limit_cfg(hdev, speed, i); + if (ret) + return ret; + } + + return 0; +} + +u32 hclge_tm_rate_2_port_rate(u64 rate) +{ + do_div(rate, TM_RATE_PORT_RATE_SCALE); + return rate > U32_MAX ? U32_MAX : (u32)rate; +} + int hclge_tm_init_hw(struct hclge_dev *hdev, bool init) { + struct hnae3_tc_info *tc_info = &hdev->vport[0].nic.kinfo.tc_info; int ret; if ((hdev->tx_sch_mode != HCLGE_FLAG_TC_BASE_SCH_MODE) && @@ -1684,6 +1734,9 @@ int hclge_tm_init_hw(struct hclge_dev *hdev, bool init) if (ret) return ret; + if (hnae3_dev_roh_supported(hdev)) + return hclge_tm_set_tc_rate_limit(hdev, tc_info); + return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index 49cc441f999da556c7fd0cb2e555052fd9504735..64b448370f9338ce2683f783fb1ed1b0500ded58 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -214,6 +214,12 @@ struct hclge_tm_nodes_cmd { __le16 queue_num; }; +struct hclge_tc_rate_limit_cmd { + __le32 speed; /* Unit Mbps */ + u8 tc_id; + u8 rsvd[19]; +}; + struct hclge_tm_shaper_para { u32 rate; u8 ir_b; @@ -279,5 +285,8 @@ int hclge_tm_get_port_shaper(struct hclge_dev *hdev, int hclge_up_to_tc_map(struct hclge_dev *hdev); int hclge_dscp_to_tc_map(struct hclge_dev *hdev); int hclge_tm_flush_cfg(struct hclge_dev *hdev, bool enable); +int hclge_tm_set_tc_rate_limit(struct hclge_dev *hdev, + struct hnae3_tc_info *tc_info); +u32 hclge_tm_rate_2_port_rate(u64 rate); void hclge_reset_tc_config(struct hclge_dev *hdev); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_trace.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_trace.h index 8510b88d49820acf3ef81c34ee263d6eaebd2591..116ac3a5ffc56400439df1fe0b7de55c2a109e6f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_trace.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_trace.h @@ -10,6 +10,7 @@ #include +#define PF_DESC_LEN (sizeof(struct hclge_desc) / sizeof(u32)) #define PF_GET_MBX_LEN (sizeof(struct hclge_mbx_vf_to_pf_cmd) / sizeof(u32)) #define PF_SEND_MBX_LEN (sizeof(struct hclge_mbx_pf_to_vf_cmd) / sizeof(u32)) @@ -77,6 +78,99 @@ TRACE_EVENT(hclge_pf_mbx_send, ) ); +DECLARE_EVENT_CLASS(hclge_pf_cmd_template, + TP_PROTO(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int index, + int num), + TP_ARGS(hw, desc, index, num), + + TP_STRUCT__entry(__field(u16, opcode) + __field(u16, flag) + __field(u16, retval) + __field(u16, rsv) + __field(int, index) + __field(int, num) + __string(pciname, pci_name(hw->cmq.csq.pdev)) + __array(u32, data, HCLGE_DESC_DATA_LEN)), + + TP_fast_assign(int i; + __entry->opcode = le16_to_cpu(desc->opcode); + __entry->flag = le16_to_cpu(desc->flag); + __entry->retval = le16_to_cpu(desc->retval); + __entry->rsv = le16_to_cpu(desc->rsv); + __entry->index = index; + __entry->num = num; + __assign_str(pciname, pci_name(hw->cmq.csq.pdev)); + for (i = 0; i < HCLGE_DESC_DATA_LEN; i++) + __entry->data[i] = le32_to_cpu(desc->data[i]);), + + TP_printk("%s opcode:0x%04x %d-%d flag:0x%04x retval:0x%04x rsv:0x%04x data:%s", + __get_str(pciname), __entry->opcode, + __entry->index, __entry->num, + __entry->flag, __entry->retval, __entry->rsv, + __print_array(__entry->data, + HCLGE_DESC_DATA_LEN, sizeof(u32))) +); + +DEFINE_EVENT(hclge_pf_cmd_template, hclge_pf_cmd_send, + TP_PROTO(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int index, + int num), + TP_ARGS(hw, desc, index, num) +); + +DEFINE_EVENT(hclge_pf_cmd_template, hclge_pf_cmd_get, + TP_PROTO(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int index, + int num), + TP_ARGS(hw, desc, index, num) +); + +DECLARE_EVENT_CLASS(hclge_pf_special_cmd_template, + TP_PROTO(struct hclge_comm_hw *hw, + u32 *data, + int index, + int num), + TP_ARGS(hw, data, index, num), + + TP_STRUCT__entry(__field(int, index) + __field(int, num) + __string(pciname, pci_name(hw->cmq.csq.pdev)) + __array(u32, data, PF_DESC_LEN)), + + TP_fast_assign(int i; + __entry->index = index; + __entry->num = num; + __assign_str(pciname, pci_name(hw->cmq.csq.pdev)); + for (i = 0; i < PF_DESC_LEN; i++) + __entry->data[i] = le32_to_cpu(data[i]); + ), + + TP_printk("%s %d-%d data:%s", + __get_str(pciname), + __entry->index, __entry->num, + __print_array(__entry->data, + PF_DESC_LEN, sizeof(u32))) +); + +DEFINE_EVENT(hclge_pf_special_cmd_template, hclge_pf_special_cmd_send, + TP_PROTO(struct hclge_comm_hw *hw, + u32 *desc, + int index, + int num), + TP_ARGS(hw, desc, index, num)); + +DEFINE_EVENT(hclge_pf_special_cmd_template, hclge_pf_special_cmd_get, + TP_PROTO(struct hclge_comm_hw *hw, + u32 *desc, + int index, + int num), + TP_ARGS(hw, desc, index, num) +); + #endif /* _HCLGE_TRACE_H_ */ /* This must be outside ifdef _HCLGE_TRACE_H */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 0aa9beefd1c7ee6c53d9f2623069bae00848e77f..9bf8bd19cf938a87115c70468006046ebf604fa8 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_trace.h" #define HCLGEVF_NAME "hclgevf" @@ -47,6 +48,42 @@ int hclgevf_cmd_send(struct hclgevf_hw *hw, struct hclge_desc *desc, int num) return hclge_comm_cmd_send(&hw->hw, desc, num); } +static void hclgevf_trace_cmd_send(struct hclge_comm_hw *hw, struct hclge_desc *desc, + int num, bool is_special) +{ + int i; + + trace_hclge_vf_cmd_send(hw, desc, 0, num); + + if (is_special) + return; + + for (i = 1; i < num; i++) + trace_hclge_vf_cmd_send(hw, &desc[i], i, num); +} + +static void hclgevf_trace_cmd_get(struct hclge_comm_hw *hw, struct hclge_desc *desc, + int num, bool is_special) +{ + int i; + + if (!HCLGE_COMM_SEND_SYNC(le16_to_cpu(desc->flag))) + return; + + trace_hclge_vf_cmd_get(hw, desc, 0, num); + + if (is_special) + return; + + for (i = 1; i < num; i++) + trace_hclge_vf_cmd_get(hw, &desc[i], i, num); +} + +static const struct hclge_comm_cmq_ops hclgevf_cmq_ops = { + .trace_cmd_send = hclgevf_trace_cmd_send, + .trace_cmd_get = hclgevf_trace_cmd_get, +}; + void hclgevf_arq_init(struct hclgevf_dev *hdev) { struct hclge_comm_cmq *cmdq = &hdev->hw.hw.cmq; @@ -354,6 +391,74 @@ static int hclgevf_knic_setup(struct hclgevf_dev *hdev) return 0; } +static void hclgevf_update_fd_qb_state(struct hclgevf_dev *hdev) +{ + struct hnae3_handle *handle = &hdev->nic; + struct hclge_vf_to_pf_msg send_msg; + int ret; + + if (!hdev->qb_cfg.pf_support_qb || + !test_bit(HNAE3_PFLAG_FD_QB_ENABLE, &handle->priv_flags)) + return; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_QB, + HCLGE_MBX_QB_GET_STATE); + ret = hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); + if (ret) + dev_err(&hdev->pdev->dev, "failed to get qb state, ret = %d", + ret); +} + +static void hclgevf_get_pf_qb_caps(struct hclgevf_dev *hdev) +{ + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); + struct hclge_vf_to_pf_msg send_msg; + u8 resp_msg; + int ret; + + if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps)) + return; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_QB, + HCLGE_MBX_QB_CHECK_CAPS); + ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, &resp_msg, + sizeof(resp_msg)); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get qb caps from PF, ret = %d", ret); + return; + } + + hdev->qb_cfg.pf_support_qb = resp_msg > 0; +} + +static void hclgevf_set_fd_qb(struct hnae3_handle *handle) +{ +#define HCLGEVF_QB_MBX_STATE_OFFSET 0 + + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct hclge_vf_to_pf_msg send_msg; + u8 resp_msg; + int ret; + + hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_QB, + HCLGE_MBX_QB_ENABLE); + send_msg.data[HCLGEVF_QB_MBX_STATE_OFFSET] = + test_bit(HNAE3_PFLAG_FD_QB_ENABLE, &handle->priv_flags) ? 1 : 0; + ret = hclgevf_send_mbx_msg(hdev, &send_msg, true, &resp_msg, + sizeof(resp_msg)); + if (ret) + dev_err(&hdev->pdev->dev, "failed to set qb state, ret = %d", + ret); +} + +static bool hclgevf_query_fd_qb_state(struct hnae3_handle *handle) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + + return hdev->qb_cfg.hw_qb_en; +} + static void hclgevf_request_link_info(struct hclgevf_dev *hdev) { struct hclge_vf_to_pf_msg send_msg; @@ -1901,6 +2006,8 @@ static void hclgevf_periodic_service_task(struct hclgevf_dev *hdev) hclgevf_sync_promisc_mode(hdev); + hclgevf_update_fd_qb_state(hdev); + hdev->last_serv_processed = jiffies; out: @@ -2796,6 +2903,7 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) } hclgevf_arq_init(hdev); + ret = hclge_comm_cmd_init(hdev->ae_dev, &hdev->hw.hw, &hdev->fw_version, false, hdev->reset_pending); @@ -2854,6 +2962,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) goto err_cmd_queue_init; hclgevf_arq_init(hdev); + + hclge_comm_cmd_init_ops(&hdev->hw.hw, &hclgevf_cmq_ops); ret = hclge_comm_cmd_init(hdev->ae_dev, &hdev->hw.hw, &hdev->fw_version, false, hdev->reset_pending); @@ -2939,6 +3049,8 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) goto err_config; } + hclgevf_get_pf_qb_caps(hdev); + hclgevf_init_rxd_adv_layout(hdev); set_bit(HCLGEVF_STATE_SERVICE_INITED, &hdev->state); @@ -3323,6 +3435,8 @@ static const struct hnae3_ae_ops hclgevf_ops = { .set_promisc_mode = hclgevf_set_promisc_mode, .request_update_promisc_mode = hclgevf_request_update_promisc_mode, .get_cmdq_stat = hclgevf_get_cmdq_stat, + .request_flush_qb_config = hclgevf_set_fd_qb, + .query_fd_qb_state = hclgevf_query_fd_qb_state, }; 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 a73f2bf3a56a6426704c64a20e74403c715ac09f..ad59f6a612540f35a0056ca5f4d44cff2fccb06d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -206,6 +206,11 @@ struct hclgevf_mac_table_cfg { struct list_head mc_mac_list; }; +struct hclgevf_qb_cfg { + bool pf_support_qb; + bool hw_qb_en; +}; + struct hclgevf_dev { struct pci_dev *pdev; struct hnae3_ae_dev *ae_dev; @@ -274,6 +279,7 @@ struct hclgevf_dev { unsigned long serv_processed_cnt; unsigned long last_serv_processed; + struct hclgevf_qb_cfg qb_cfg; struct devlink *devlink; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index 85c2a634c8f96a1d4d3356b0adf9c1f87f8ed9b8..6ccf23ce2744055449204936ac5607e1248bfcc6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -271,6 +271,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_LINK_STAT_MODE: case HCLGE_MBX_PUSH_VLAN_INFO: case HCLGE_MBX_PUSH_PROMISC_INFO: + case HCLGE_MBX_PUSH_QB_STATE: hclgevf_handle_mbx_msg(hdev, req); break; default: @@ -296,6 +297,19 @@ static void hclgevf_parse_promisc_info(struct hclgevf_dev *hdev, "Promisc mode is closed by host for being untrusted.\n"); } +static void hclgevf_parse_qb_info(struct hclgevf_dev *hdev, u16 qb_state) +{ +#define HCLGEVF_HW_QB_ON 1 +#define HCLGEVF_HW_QB_OFF 0 + + if (qb_state > HCLGEVF_HW_QB_ON) { + dev_warn(&hdev->pdev->dev, "Invalid state, ignored.\n"); + return; + } + + hdev->qb_cfg.hw_qb_en = qb_state > HCLGEVF_HW_QB_OFF; +} + void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) { struct hclge_mbx_port_base_vlan *vlan_info; @@ -374,6 +388,9 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_PUSH_PROMISC_INFO: hclgevf_parse_promisc_info(hdev, le16_to_cpu(msg_q[1])); break; + case HCLGE_MBX_PUSH_QB_STATE: + hclgevf_parse_qb_info(hdev, msg_q[1]); + break; default: dev_err(&hdev->pdev->dev, "fetched unsupported(%u) message from arq\n", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h index 5d4895bb57a17d9a01b29545af427ae760c0d578..82263cb5e47bef49cc003bf0b4102afc70ac561e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h @@ -77,6 +77,56 @@ TRACE_EVENT(hclge_vf_mbx_send, ) ); +DECLARE_EVENT_CLASS(hclge_vf_cmd_template, + TP_PROTO(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int index, + int num), + + TP_ARGS(hw, desc, index, num), + + TP_STRUCT__entry(__field(u16, opcode) + __field(u16, flag) + __field(u16, retval) + __field(u16, rsv) + __field(int, index) + __field(int, num) + __string(pciname, pci_name(hw->cmq.csq.pdev)) + __array(u32, data, HCLGE_DESC_DATA_LEN)), + + TP_fast_assign(int i; + __entry->opcode = le16_to_cpu(desc->opcode); + __entry->flag = le16_to_cpu(desc->flag); + __entry->retval = le16_to_cpu(desc->retval); + __entry->rsv = le16_to_cpu(desc->rsv); + __entry->index = index; + __entry->num = num; + __assign_str(pciname, pci_name(hw->cmq.csq.pdev)); + for (i = 0; i < HCLGE_DESC_DATA_LEN; i++) + __entry->data[i] = le32_to_cpu(desc->data[i]);), + + TP_printk("%s opcode:0x%04x %d-%d flag:0x%04x retval:0x%04x rsv:0x%04x data:%s", + __get_str(pciname), __entry->opcode, + __entry->index, __entry->num, + __entry->flag, __entry->retval, __entry->rsv, + __print_array(__entry->data, + HCLGE_DESC_DATA_LEN, sizeof(u32))) +); + +DEFINE_EVENT(hclge_vf_cmd_template, hclge_vf_cmd_send, + TP_PROTO(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int index, + int num), + TP_ARGS(hw, desc, index, num)); + +DEFINE_EVENT(hclge_vf_cmd_template, hclge_vf_cmd_get, + TP_PROTO(struct hclge_comm_hw *hw, + struct hclge_desc *desc, + int index, + int num), + TP_ARGS(hw, desc, index, num)); + #endif /* _HCLGEVF_TRACE_H_ */ /* This must be outside ifdef _HCLGEVF_TRACE_H */ diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index ed9d97a032f1cc64faacc32fcc102603af66504e..14a7b49e47601f37aee4bccac42320d4336b0204 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -211,4 +211,15 @@ config PTP_DFL_TOD To compile this driver as a module, choose M here: the module will be called ptp_dfl_tod. +config PTP_HISI + tristate "HiSilicon PTP sync platform driver" + help + PTP sync driver work on multichip system, eliminates the bus latency + between multichip, and provide a higher precision clock source. But + the clock source of PTP sync device is from the RTC of HNS3 ethernet + device, so, if you want the PTP sync device works, you must enable + HNS3 driver also. + + If unsure, say N. + endmenu diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index dea0cebd2303ed52f5eaf9afd85cfe15b9853cc0..8d21ee20787d3fa1ea9f4629c5b6eac5c8b9a631 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_PTP_1588_CLOCK_MOCK) += ptp_mock.o obj-$(CONFIG_PTP_1588_CLOCK_VMW) += ptp_vmw.o obj-$(CONFIG_PTP_1588_CLOCK_OCP) += ptp_ocp.o obj-$(CONFIG_PTP_DFL_TOD) += ptp_dfl_tod.o +obj-$(CONFIG_PTP_HISI) += ptp_hisi.o diff --git a/drivers/ptp/ptp_hisi.c b/drivers/ptp/ptp_hisi.c new file mode 100644 index 0000000000000000000000000000000000000000..0eb1ebf44dc899d2f1853249d7d118368ffd0dda --- /dev/null +++ b/drivers/ptp/ptp_hisi.c @@ -0,0 +1,1027 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2022 Hisilicon Limited. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PTP_CLOCK_NAME_LEN +#define PTP_CLOCK_NAME_LEN 32 +#endif + +#define HISI_PTP_VERSION "22.10.2" + +#define HISI_PTP_NAME "hisi_ptp" +#define HISI_PTP_INT_NAME_LEN 32 + +#define HISI_PTP_DBGFS_STS_LEN 2048 +#define HISI_PTP_DBGFS_REG_LEN 0x10000 + +#define HISI_RES_T_PERI_SC 0 +#define HISI_RES_N_NET_SC 0 +#define HISI_RES_N_IO_SC 1 + +#define HISI_PTP_INIT_DONE 0 + +/* peri subctrl reg offset */ +#define PERI_SC_PTP_RESET_REQ 0xE18 +#define PERI_SC_PTP_RESET_DREQ 0xE1C +#define PERI_SC_LOCAL_TIMER_COMP_HIGH_ADDR 0x5000 +#define PERI_SC_LOCAL_TIMER_COMP_LOW_ADDR 0x5004 +#define PERI_SC_BAUD_VALUE_ADDR 0x5008 +#define PERI_SC_LOCAL_CNT_EN_ADDR 0x500C +#define PERI_SC_SYNC_ERR_COMP_HIGH_ADDR 0x5010 +#define PERI_SC_SYNC_ERR_COMP_LOW_ADDR 0x5014 +#define PERI_SC_CRC_EN_ADDR 0x5018 +#define PERI_SC_ONE_CYCLE_NUM_ADDR 0x5020 +#define PERI_SC_SYNC_ERR_CLR_ADDR 0x5024 +#define PERI_SC_RX_SHIFT_EN_ADDR 0x5028 +#define PERI_SC_TIMEL_CY_NUM_ADDR 0x502C +#define PERI_SC_INT_PTP_SYNC_ERR_ADDR 0x5044 +#define PERI_SC_INT_PTP_SYNC_ERR_MASK_ADDR 0x5048 +#define PERI_SC_INT_ORIGIN 0x504C +#define PERI_SC_CRC_ERR_COUNT 0x5050 +#define PERI_SC_CRC_INT_CONTRL_ADDR 0x5054 +#define PERI_SC_CAPTURE_PTP_TIME_COMP_HIGH 0x5058 +#define PERI_SC_CAPTURE_PTP_TIME_COMP_LOW 0x505C +#define PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_HIGH 0x5060 +#define PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_LOW 0x5064 +#define PERI_SC_CAPTURE_VLD 0x5068 +#define PERI_SC_LOCAL_TIME_LOW_ADDR 0x5070 +#define PERI_SC_LOCAL_TIME_HIGH_ADDR 0x5074 + +/* net subctrl reg offset */ +#define NET_SC_PTP_BAUD_VALUE_ADDR 0x2008 +#define NET_SC_PTP_COUNTER_EN_ADDR 0x200C +#define NET_SC_PTP_NORMAL_MODE_EN 0x2010 +#define NET_SC_PTP_WIRE_DELAY_CAL_EN 0x2014 +#define NET_SC_SAMPLE_DELAY_CFG_ADDR 0x2018 +#define NET_SC_PTP_TX_DFXBUS0_ADDR 0x201C +#define NET_SC_PTP_TX_DFXBUS1_ADDR 0x2020 +#define NET_SC_PTP_TX_DFXBUS2_ADDR 0x2024 +#define NET_SC_PTP_TX_DFXBUS3_ADDR 0x2028 + +/* io subctrl reg offset */ +#define IO_SC_PTP_BAUD_VALUE_ADDR 0x2008 +#define IO_SC_PTP_COUNTER_EN_ADDR 0x200C +#define IO_SC_PTP_NORMAL_MODE_EN 0x2010 +#define IO_SC_PTP_WIRE_DELAY_CAL_EN 0x2014 +#define IO_SC_SAMPLE_DELAY_CFG_ADDR 0x2018 +#define IO_SC_PTP_TX_DFXBUS0_ADDR 0x201C +#define IO_SC_PTP_TX_DFXBUS1_ADDR 0x2020 +#define IO_SC_PTP_TX_DFXBUS2_ADDR 0x2024 +#define IO_SC_PTP_TX_DFXBUS3_ADDR 0x2028 + +/* default values */ +#define HISI_DEF_BAUD 0x1388 +#define HISI_DEF_TIME_COMP 0xB2432 +#define HISI_DEF_ERR_COMP 0xFFFFFFFF +#define HISI_DEF_ONE_CYCLE_NUM 0x50 + +#define HISI_PTP_TX_IDLE_MASK GENMASK(26, 23) + +#define HISI_PTP_RX_CRC_INT_EN BIT(0) +#define HISI_PTP_RX_CRC_CLR BIT(1) +#define HISI_PTP_RX_CRC_CLR_AND_EN \ + (HISI_PTP_RX_CRC_INT_EN | HISI_PTP_RX_CRC_INT_EN) +#define HISI_PTP_RX_CRC_CLR_AND_DISABLE HISI_PTP_RX_CRC_CLR + +#define HISI_PTP_SUP_CHK_CNT 32 +/* suppress check window and suppress time, unit: ms */ +#define HISI_PTP_SUP_CHK_THR 10 +#define HISI_PTP_SUP_TIME 100 + +enum HISI_PTP_TX_MODE { + HISI_PTP_CAL_MODE, + HISI_PTP_NORMAL_MODE, +}; + +struct hisi_ptp_rx { + struct list_head node; + char name[HISI_PTP_INT_NAME_LEN]; + struct device *dev; + u64 time_comp; /* internal wire time compensation value */ + int irq; + void __iomem *base; +}; + +struct hisi_ptp_tx { + struct device *dev; + void __iomem *base; + void __iomem *io_sc_base; +}; + +struct hisi_ptp_pdev { + struct list_head ptp_rx_list; + struct hisi_ptp_tx *ptp_tx; + u32 tx_cnt; + u32 rx_total; + u32 rx_cnt; + unsigned long flag; + void __iomem *rx_base; /* peri subctl base of chip 0 */ + u32 irq_cnt; + unsigned long last_jiffies; /* record last irq jiffies */ + struct timer_list suppress_timer; + struct ptp_clock *clock; + struct ptp_clock_info info; + rwlock_t rw_lock; + struct dentry *dbgfs_root; +}; + +struct hisi_ptp_reg { + const char *name; + u32 offset; +}; + +static struct hisi_ptp_pdev g_ptpdev; + +static uint err_threshold = HISI_DEF_ERR_COMP; +module_param(err_threshold, uint, 0644); +MODULE_PARM_DESC(err_threshold, "PTP time sync error threshold"); + +static struct hisi_ptp_pdev *hisi_ptp_get_pdev(struct ptp_clock_info *info) +{ + struct hisi_ptp_pdev *ptp = + container_of(info, struct hisi_ptp_pdev, info); + return ptp; +} + +/* This function should call under rw_lock */ +static void hisi_ptp_disable(struct hisi_ptp_pdev *ptp) +{ + struct hisi_ptp_rx *rx; + void __iomem *base; + + /* disable tx */ + if (ptp->ptp_tx && ptp->ptp_tx->base) { + base = ptp->ptp_tx->base; + writel(0, base + NET_SC_PTP_COUNTER_EN_ADDR); + } + + /* disable all totem rx and interrupt */ + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + base = rx->base; + writel(0, base + PERI_SC_RX_SHIFT_EN_ADDR); + writel(1, base + PERI_SC_INT_PTP_SYNC_ERR_MASK_ADDR); + writel(HISI_PTP_RX_CRC_CLR_AND_DISABLE, + base + PERI_SC_CRC_INT_CONTRL_ADDR); + } +} + +/* This function should call under rw_lock */ +static void hisi_ptp_unmask_irq(struct hisi_ptp_pdev *ptp) +{ + struct hisi_ptp_rx *rx; + void __iomem *base; + + /* clear CRC errors and unmask all totem interrupt */ + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + base = rx->base; + writel(HISI_PTP_RX_CRC_INT_EN, + base + PERI_SC_CRC_INT_CONTRL_ADDR); + writel(0, base + PERI_SC_INT_PTP_SYNC_ERR_MASK_ADDR); + } +} + +/* This function should call under rw_lock */ +static void hisi_ptp_wait_and_enable(struct hisi_ptp_pdev *ptp) +{ +#define HISI_PTP_TX_IDLE_WAIT_CNT 20 + void __iomem *nimbus_base; + struct hisi_ptp_rx *rx; + void __iomem *base; + int delay_cnt = 0; + + if (!ptp->ptp_tx || !ptp->ptp_tx->base) + return; + + /* wait for tx idle */ + nimbus_base = ptp->ptp_tx->base; + while (delay_cnt++ < HISI_PTP_TX_IDLE_WAIT_CNT) { + u32 dfx_bus0 = readl(nimbus_base + NET_SC_PTP_TX_DFXBUS0_ADDR); + + /* wait bit26:23 to 0 */ + if ((dfx_bus0 & HISI_PTP_TX_IDLE_MASK) == 0) + break; + + udelay(1); + } + + /* enable all totem interrupt and rx */ + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + base = rx->base; + writel(1, base + PERI_SC_SYNC_ERR_CLR_ADDR); + writel(0, base + PERI_SC_SYNC_ERR_CLR_ADDR); + writel(1, base + PERI_SC_INT_PTP_SYNC_ERR_ADDR); + writel(1, base + PERI_SC_RX_SHIFT_EN_ADDR); + } + + /* enable tx */ + writel(1, nimbus_base + NET_SC_PTP_COUNTER_EN_ADDR); + + hisi_ptp_unmask_irq(ptp); +} + +/* This function should call under rw_lock */ +static bool hisi_ptp_need_suppress(struct hisi_ptp_pdev *ptp) +{ + if (time_is_before_jiffies(ptp->last_jiffies + + msecs_to_jiffies(HISI_PTP_SUP_CHK_THR))) { + ptp->last_jiffies = jiffies; + ptp->irq_cnt = 0; + return false; + } + + if (ptp->irq_cnt++ < HISI_PTP_SUP_CHK_CNT) + return false; + + return true; +} + +static irqreturn_t hisi_ptp_irq_handle(int irq, void *data) +{ + struct hisi_ptp_pdev *ptp = (struct hisi_ptp_pdev *)data; + + dev_dbg(ptp->ptp_tx->dev, "ptp time sync error, irq:%d\n", irq); + + write_lock(&ptp->rw_lock); + + hisi_ptp_disable(ptp); + + if (hisi_ptp_need_suppress(ptp)) { + mod_timer(&ptp->suppress_timer, + jiffies + msecs_to_jiffies(HISI_PTP_SUP_TIME)); + write_unlock(&ptp->rw_lock); + return IRQ_HANDLED; + } + + hisi_ptp_wait_and_enable(ptp); + + write_unlock(&ptp->rw_lock); + + return IRQ_HANDLED; +} + +static int hisi_ptp_get_rx_resource(struct platform_device *pdev, + struct hisi_ptp_pdev *ptp) +{ + struct hisi_ptp_rx *rx; + struct resource *peri; + unsigned long flags; + u32 rx_total = 0; + bool is_base_rx; + int ret; + + ret = device_property_read_u32(&pdev->dev, "rx_num", &rx_total); + if (ret) { + dev_err(&pdev->dev, "failed to read rx total property\n"); + return ret; + } + + rx = devm_kzalloc(&pdev->dev, sizeof(struct hisi_ptp_rx), GFP_KERNEL); + if (!rx) + return -ENOMEM; + + peri = platform_get_resource(pdev, IORESOURCE_MEM, HISI_RES_T_PERI_SC); + if (!peri) { + dev_err(&pdev->dev, "failed to get rx peri resource\n"); + return -EINVAL; + } + + rx->base = devm_ioremap(&pdev->dev, peri->start, resource_size(peri)); + if (!rx->base) { + dev_err(&pdev->dev, "failed to remap rx peri resource\n"); + return -ENOMEM; + } + + rx->irq = platform_get_irq(pdev, 0); + if (rx->irq < 0) { + dev_err(&pdev->dev, "failed to get irq, ret = %d\n", rx->irq); + return rx->irq; + } + snprintf(rx->name, HISI_PTP_INT_NAME_LEN, "%s-%d", HISI_PTP_NAME, + rx->irq); + ret = devm_request_irq(&pdev->dev, rx->irq, hisi_ptp_irq_handle, 0, + rx->name, ptp); + if (ret) { + dev_err(&pdev->dev, "failed to request irq(%d), ret = %d\n", + rx->irq, ret); + return ret; + } + + is_base_rx = device_property_present(&pdev->dev, "base_rx"); + + rx->dev = &pdev->dev; + + write_lock_irqsave(&ptp->rw_lock, flags); + + if (is_base_rx) + ptp->rx_base = rx->base; + + ptp->rx_cnt++; + + /* use the first rx device to init the global rx_total */ + if (ptp->rx_total == 0) + ptp->rx_total = rx_total; + + if (ptp->rx_total != rx_total || ptp->rx_cnt > ptp->rx_total) { + write_unlock_irqrestore(&ptp->rw_lock, flags); + dev_err(&pdev->dev, + "failed to probe rx device, please check the asl file!\n"); + dev_err(&pdev->dev, + "rx_total:%u, current rx_total:%u, rx_cnt:%u\n", + ptp->rx_total, rx_total, ptp->rx_cnt); + + return -EINVAL; + } + + list_add_tail(&rx->node, &ptp->ptp_rx_list); + + write_unlock_irqrestore(&ptp->rw_lock, flags); + + return 0; +} + +static int hisi_ptp_get_tx_resource(struct platform_device *pdev, + struct hisi_ptp_pdev *ptp) +{ + struct hisi_ptp_tx *tx; + struct resource *mem; + unsigned long flags; + + write_lock_irqsave(&ptp->rw_lock, flags); + /* use have only one tx device */ + if (ptp->tx_cnt) { + write_unlock_irqrestore(&ptp->rw_lock, flags); + dev_err(&pdev->dev, + "failed to probe tx device, more than one tx device found, please check the asl file!\n"); + return -EINVAL; + } + write_unlock_irqrestore(&ptp->rw_lock, flags); + + tx = devm_kzalloc(&pdev->dev, sizeof(struct hisi_ptp_tx), GFP_KERNEL); + if (!tx) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, HISI_RES_N_NET_SC); + if (!mem) { + dev_err(&pdev->dev, "failed to get tx net sc resource\n"); + return -EINVAL; + } + + tx->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); + if (!tx->base) { + dev_err(&pdev->dev, "failed to remap tx net sc resource\n"); + return -ENOMEM; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, HISI_RES_N_IO_SC); + if (!mem) { + dev_err(&pdev->dev, "failed to get tx nimbus io sc resource\n"); + return -EINVAL; + } + + tx->io_sc_base = devm_ioremap(&pdev->dev, mem->start, + resource_size(mem)); + if (!tx->io_sc_base) { + dev_err(&pdev->dev, "failed to remap tx nimbus io resource\n"); + return -ENOMEM; + } + + tx->dev = &pdev->dev; + + write_lock_irqsave(&ptp->rw_lock, flags); + ptp->tx_cnt++; + ptp->ptp_tx = tx; + write_unlock_irqrestore(&ptp->rw_lock, flags); + + return 0; +} + +static void hisi_ptp_cal_time_start(struct hisi_ptp_pdev *ptp) +{ + void __iomem *io_sc_base; + struct hisi_ptp_rx *rx; + void __iomem *base; + + /* config all rx to enter calculation mode. */ + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + base = rx->base; + writel(1, base + PERI_SC_PTP_RESET_REQ); + writel(1, base + PERI_SC_PTP_RESET_DREQ); + writel(0, base + PERI_SC_LOCAL_TIMER_COMP_HIGH_ADDR); + writel(0, base + PERI_SC_LOCAL_TIMER_COMP_LOW_ADDR); + writel(1, base + PERI_SC_CRC_EN_ADDR); + writel(0, base + PERI_SC_LOCAL_CNT_EN_ADDR); + writel(1, base + PERI_SC_RX_SHIFT_EN_ADDR); + } + + /* config tx to enter calculation mode. */ + base = ptp->ptp_tx->base; + io_sc_base = ptp->ptp_tx->io_sc_base; + writel(HISI_PTP_CAL_MODE, io_sc_base + IO_SC_PTP_NORMAL_MODE_EN); + writel(HISI_PTP_CAL_MODE, base + NET_SC_PTP_NORMAL_MODE_EN); + + writel(HISI_DEF_BAUD, io_sc_base + IO_SC_PTP_BAUD_VALUE_ADDR); + writel(1, io_sc_base + IO_SC_PTP_COUNTER_EN_ADDR); + writel(0, io_sc_base + IO_SC_PTP_WIRE_DELAY_CAL_EN); + writel(1, io_sc_base + IO_SC_PTP_WIRE_DELAY_CAL_EN); +} + +static void hisi_ptp_cal_time_get(struct hisi_ptp_pdev *ptp) +{ +#define HISI_PTP_MAX_WAIT_CNT 60 + struct hisi_ptp_rx *rx; + void __iomem *base; + int cnt; + u32 rd_l; + u32 rd_h; + u32 td_l; + u32 td_h; + u64 rd; + u64 td; + + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + base = rx->base; + rx->time_comp = HISI_DEF_TIME_COMP; + + cnt = 0; + do { + if (readl(base + PERI_SC_CAPTURE_VLD) == 0) { + mdelay(1); + continue; + } + + rd_h = readl(base + + PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_HIGH); + rd_l = readl(base + + PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_LOW); + td_h = readl(base + PERI_SC_CAPTURE_PTP_TIME_COMP_HIGH); + td_l = readl(base + PERI_SC_CAPTURE_PTP_TIME_COMP_LOW); + + rd = (u64)rd_h << 32 | rd_l; + td = (u64)td_h << 32 | td_l; + + if (!rd || !td || rd < td) { + mdelay(1); + continue; + } + + rx->time_comp = rd - td; + break; + } while (cnt++ <= HISI_PTP_MAX_WAIT_CNT); + } +} + +static void hisi_ptp_cal_time_end(struct hisi_ptp_pdev *ptp) +{ + void __iomem *io_sc_base; + struct hisi_ptp_rx *rx; + void __iomem *base; + + /* config all rx to exit calculation mode. */ + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + base = rx->base; + writel(0, base + PERI_SC_RX_SHIFT_EN_ADDR); + } + + /* config tx to exit calculation mode. */ + base = ptp->ptp_tx->base; + io_sc_base = ptp->ptp_tx->io_sc_base; + + writel(0, io_sc_base + IO_SC_PTP_COUNTER_EN_ADDR); + writel(HISI_PTP_NORMAL_MODE, io_sc_base + IO_SC_PTP_NORMAL_MODE_EN); + writel(HISI_PTP_NORMAL_MODE, base + NET_SC_PTP_NORMAL_MODE_EN); +} + +/* This function should call under rw_lock */ +static void hisi_ptp_cal_time_comp(struct hisi_ptp_pdev *ptp) +{ + hisi_ptp_cal_time_start(ptp); + hisi_ptp_cal_time_get(ptp); + hisi_ptp_cal_time_end(ptp); +} + +/* This function should call under rw_lock */ +static void hisi_ptp_peri_rx_init(struct hisi_ptp_pdev *ptp) +{ + struct hisi_ptp_rx *rx; + void __iomem *base; + + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + base = rx->base; + writel(1, base + PERI_SC_CRC_EN_ADDR); + writel(upper_32_bits(rx->time_comp), + base + PERI_SC_LOCAL_TIMER_COMP_HIGH_ADDR); + writel(lower_32_bits(rx->time_comp), + base + PERI_SC_LOCAL_TIMER_COMP_LOW_ADDR); + writel(err_threshold, + base + PERI_SC_SYNC_ERR_COMP_LOW_ADDR); + writel(1, base + PERI_SC_CRC_INT_CONTRL_ADDR); + writel(0, base + PERI_SC_SYNC_ERR_CLR_ADDR); + writel(1, base + PERI_SC_LOCAL_CNT_EN_ADDR); + writel(1, base + PERI_SC_RX_SHIFT_EN_ADDR); + } +} + +/* This function should call under rw_lock */ +static void hisi_ptp_net_tx_init(struct hisi_ptp_pdev *ptp) +{ + void __iomem *base; + + base = ptp->ptp_tx->base; + writel(1, base + NET_SC_PTP_COUNTER_EN_ADDR); +} + +static int hisi_ptp_adjfine(struct ptp_clock_info *ptp_info, long delta) +{ + return -EOPNOTSUPP; +} + +static int hisi_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta) +{ + return -EOPNOTSUPP; +} + +static int hisi_ptp_settime(struct ptp_clock_info *ptp_info, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + +static int hisi_ptp_gettime(struct ptp_clock_info *ptp_info, + struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct hisi_ptp_pdev *ptp = hisi_ptp_get_pdev(ptp_info); + unsigned long flags; + u32 hi = UINT_MAX; + u32 lo = UINT_MAX; + u64 ns; + + read_lock_irqsave(&ptp->rw_lock, flags); + + if (ptp->rx_base) { + hi = readl(ptp->rx_base + PERI_SC_LOCAL_TIME_HIGH_ADDR); + lo = readl(ptp->rx_base + PERI_SC_LOCAL_TIME_LOW_ADDR); + } + + read_unlock_irqrestore(&ptp->rw_lock, flags); + + ns = (u64)hi * NSEC_PER_SEC + lo; + *ts = ns_to_timespec64(ns); + + return 0; +} + +static int hisi_ptp_create_clock(struct hisi_ptp_pdev *ptp) +{ + dev_info(ptp->ptp_tx->dev, "register ptp clock\n"); + + snprintf(ptp->info.name, PTP_CLOCK_NAME_LEN, "%s", HISI_PTP_NAME); + ptp->info.owner = THIS_MODULE; + ptp->info.adjfine = hisi_ptp_adjfine; + ptp->info.adjtime = hisi_ptp_adjtime; + ptp->info.settime64 = hisi_ptp_settime; + ptp->info.gettimex64 = hisi_ptp_gettime; + ptp->clock = ptp_clock_register(&ptp->info, ptp->ptp_tx->dev); + if (IS_ERR(ptp->clock)) { + dev_err(ptp->ptp_tx->dev, + "failed to register ptp clock, ret = %ld\n", + PTR_ERR(ptp->clock)); + return PTR_ERR(ptp->clock); + } + + return 0; +} + +static void hisi_ptp_timer(struct timer_list *t) +{ + struct hisi_ptp_pdev *ptp = from_timer(ptp, t, suppress_timer); + unsigned long flags; + + write_lock_irqsave(&ptp->rw_lock, flags); + + dev_dbg(ptp->ptp_tx->dev, "ptp timer timeout handler.\n"); + + ptp->last_jiffies = jiffies; + ptp->irq_cnt = 0; + + hisi_ptp_wait_and_enable(ptp); + + write_unlock_irqrestore(&ptp->rw_lock, flags); +} + +static int hisi_ptp_probe(struct platform_device *pdev) +{ + struct hisi_ptp_pdev *ptp = &g_ptpdev; + unsigned long flags; + const char *type; + int ret; + + dev_info(&pdev->dev, "ptp probe start\n"); + + ret = device_property_read_string(&pdev->dev, "type", &type); + if (ret) { + dev_err(&pdev->dev, "failed to read device type, ret = %d\n", + ret); + return ret; + } + + if (!memcmp(type, "rx", strlen("rx"))) { + ret = hisi_ptp_get_rx_resource(pdev, ptp); + } else if (!memcmp(type, "tx", strlen("tx"))) { + ret = hisi_ptp_get_tx_resource(pdev, ptp); + } else { + dev_err(&pdev->dev, + "failed to probe unknown device, type: %s\n", + type); + ret = -EINVAL; + } + if (ret) + return ret; + + write_lock_irqsave(&ptp->rw_lock, flags); + + if (ptp->rx_total == 0 || ptp->rx_total != ptp->rx_cnt || + ptp->tx_cnt != 1) { + write_unlock_irqrestore(&ptp->rw_lock, flags); + dev_info(&pdev->dev, + "waiting for devices...rx total:%u, now:%u. tx total:1, now:%u\n", + ptp->rx_total, ptp->rx_cnt, ptp->tx_cnt); + return 0; + } + + if (!ptp->rx_base) { + write_unlock_irqrestore(&ptp->rw_lock, flags); + dev_err(&pdev->dev, + "failed to probe, no base rx device, please check the asl file!\n"); + return -EINVAL; + } + + hisi_ptp_disable(ptp); + hisi_ptp_cal_time_comp(ptp); + hisi_ptp_peri_rx_init(ptp); + hisi_ptp_net_tx_init(ptp); + hisi_ptp_unmask_irq(ptp); + + write_unlock_irqrestore(&ptp->rw_lock, flags); + + ret = hisi_ptp_create_clock(ptp); + if (ret) { + write_lock_irqsave(&ptp->rw_lock, flags); + hisi_ptp_disable(ptp); + write_unlock_irqrestore(&ptp->rw_lock, flags); + return ret; + } + + set_bit(HISI_PTP_INIT_DONE, &ptp->flag); + + dev_info(&pdev->dev, "ptp probe end\n"); + return 0; +} + +static int hisi_ptp_remove(struct platform_device *pdev) +{ + struct hisi_ptp_pdev *ptp = &g_ptpdev; + struct hisi_ptp_rx *rx; + unsigned long flags; + + if (test_and_clear_bit(HISI_PTP_INIT_DONE, &ptp->flag)) { + ptp_clock_unregister(ptp->clock); + ptp->clock = NULL; + + write_lock_irqsave(&ptp->rw_lock, flags); + hisi_ptp_disable(ptp); + write_unlock_irqrestore(&ptp->rw_lock, flags); + + dev_info(&pdev->dev, "unregister ptp clock\n"); + } + + write_lock_irqsave(&ptp->rw_lock, flags); + if (ptp->ptp_tx && ptp->ptp_tx->dev == &pdev->dev) { + ptp->tx_cnt--; + ptp->ptp_tx = NULL; + dev_info(&pdev->dev, "remove tx ptp device\n"); + } else { + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + if (rx->dev == &pdev->dev) { + ptp->rx_cnt--; + list_del(&rx->node); + dev_info(&pdev->dev, "remove rx ptp device\n"); + break; + } + } + } + write_unlock_irqrestore(&ptp->rw_lock, flags); + + return 0; +} + +static const struct acpi_device_id hisi_ptp_acpi_match[] = { + { "HISI0411", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, hisi_ptp_acpi_match); + +static struct platform_driver hisi_ptp_driver = { + .probe = hisi_ptp_probe, + .remove = hisi_ptp_remove, + .driver = { + .name = HISI_PTP_NAME, + .acpi_match_table = ACPI_PTR(hisi_ptp_acpi_match), + }, +}; + +static ssize_t hisi_ptp_dbg_read_state(struct file *filp, char __user *buf, + size_t cnt, loff_t *ppos) +{ + struct hisi_ptp_pdev *ptp = filp->private_data; + struct hisi_ptp_rx *rx; + unsigned long flags; + ssize_t size = 0; + char *read_buf; + int pos = 0; + int len; + + if (*ppos < 0) + return -EINVAL; + if (cnt == 0) + return 0; + if (!access_ok(buf, cnt)) + return -EFAULT; + + read_buf = kvzalloc(HISI_PTP_DBGFS_STS_LEN, GFP_KERNEL); + if (!read_buf) + return -ENOMEM; + + len = HISI_PTP_DBGFS_STS_LEN; + + write_lock_irqsave(&ptp->rw_lock, flags); + pos += scnprintf(read_buf + pos, len - pos, "error threshold: %#x\n", + err_threshold); + pos += scnprintf(read_buf + pos, len - pos, "tx count: %u\n", + ptp->tx_cnt); + pos += scnprintf(read_buf + pos, len - pos, "rx total: %u\n", + ptp->rx_total); + pos += scnprintf(read_buf + pos, len - pos, "rx count: %u\n", + ptp->rx_cnt); + pos += scnprintf(read_buf + pos, len - pos, "irq count: %u\n", + ptp->irq_cnt); + pos += scnprintf(read_buf + pos, len - pos, "irq last jiffies: %lu\n", + ptp->last_jiffies); + + list_for_each_entry(rx, &ptp->ptp_rx_list, node) { + pos += scnprintf(read_buf + pos, len - pos, "name: %s\n", + rx->name); + pos += scnprintf(read_buf + pos, len - pos, "time comp: %#llx\n", + rx->time_comp); + pos += scnprintf(read_buf + pos, len - pos, "irq: %d\n", + rx->irq); + } + write_unlock_irqrestore(&ptp->rw_lock, flags); + + size = simple_read_from_buffer(buf, cnt, ppos, read_buf, + strlen(read_buf)); + + kvfree(read_buf); + + return size; +} + +static const struct hisi_ptp_reg hisi_ptp_tx_reg[] = { + {"NET_SC_PTP_BAUD_VALUE_ADDR ", + NET_SC_PTP_BAUD_VALUE_ADDR}, + {"NET_SC_PTP_COUNTER_EN_ADDR ", + NET_SC_PTP_COUNTER_EN_ADDR}, + {"NET_SC_PTP_NORMAL_MODE_EN ", + NET_SC_PTP_NORMAL_MODE_EN}, + {"NET_SC_PTP_WIRE_DELAY_CAL_EN", + NET_SC_PTP_WIRE_DELAY_CAL_EN}, + {"NET_SC_SAMPLE_DELAY_CFG_ADDR", + NET_SC_SAMPLE_DELAY_CFG_ADDR}, + {"NET_SC_PTP_TX_DFXBUS0_ADDR ", + NET_SC_PTP_TX_DFXBUS0_ADDR}, + {"NET_SC_PTP_TX_DFXBUS1_ADDR ", + NET_SC_PTP_TX_DFXBUS1_ADDR}, + {"NET_SC_PTP_TX_DFXBUS2_ADDR ", + NET_SC_PTP_TX_DFXBUS2_ADDR}, + {"NET_SC_PTP_TX_DFXBUS3_ADDR ", + NET_SC_PTP_TX_DFXBUS3_ADDR} +}; + +static const struct hisi_ptp_reg hisi_ptp_tx_io_reg[] = { + {"IO_SC_PTP_BAUD_VALUE_ADDR ", + IO_SC_PTP_BAUD_VALUE_ADDR}, + {"IO_SC_PTP_COUNTER_EN_ADDR ", + IO_SC_PTP_COUNTER_EN_ADDR}, + {"IO_SC_PTP_NORMAL_MODE_EN ", + IO_SC_PTP_NORMAL_MODE_EN}, + {"IO_SC_PTP_WIRE_DELAY_CAL_EN", + IO_SC_PTP_WIRE_DELAY_CAL_EN}, + {"IO_SC_SAMPLE_DELAY_CFG_ADDR", + IO_SC_SAMPLE_DELAY_CFG_ADDR}, + {"IO_SC_PTP_TX_DFXBUS0_ADDR ", + IO_SC_PTP_TX_DFXBUS0_ADDR}, + {"IO_SC_PTP_TX_DFXBUS1_ADDR ", + IO_SC_PTP_TX_DFXBUS1_ADDR}, + {"IO_SC_PTP_TX_DFXBUS2_ADDR ", + IO_SC_PTP_TX_DFXBUS2_ADDR}, + {"IO_SC_PTP_TX_DFXBUS3_ADDR ", + IO_SC_PTP_TX_DFXBUS3_ADDR} +}; + +static const struct hisi_ptp_reg hisi_ptp_rx_reg[] = { + {"PERI_SC_LOCAL_TIMER_COMP_HIGH_ADDR ", + PERI_SC_LOCAL_TIMER_COMP_HIGH_ADDR}, + {"PERI_SC_LOCAL_TIMER_COMP_LOW_ADDR ", + PERI_SC_LOCAL_TIMER_COMP_LOW_ADDR}, + {"PERI_SC_BAUD_VALUE_ADDR ", + PERI_SC_BAUD_VALUE_ADDR}, + {"PERI_SC_LOCAL_CNT_EN_ADDR ", + PERI_SC_LOCAL_CNT_EN_ADDR}, + {"PERI_SC_SYNC_ERR_COMP_HIGH_ADDR ", + PERI_SC_SYNC_ERR_COMP_HIGH_ADDR}, + {"PERI_SC_SYNC_ERR_COMP_LOW_ADDR ", + PERI_SC_SYNC_ERR_COMP_LOW_ADDR}, + {"PERI_SC_CRC_EN_ADDR ", + PERI_SC_CRC_EN_ADDR}, + {"PERI_SC_ONE_CYCLE_NUM_ADDR ", + PERI_SC_ONE_CYCLE_NUM_ADDR}, + {"PERI_SC_SYNC_ERR_CLR_ADDR ", + PERI_SC_SYNC_ERR_CLR_ADDR}, + {"PERI_SC_RX_SHIFT_EN_ADDR ", + PERI_SC_RX_SHIFT_EN_ADDR}, + {"PERI_SC_TIMEL_CY_NUM_ADDR ", + PERI_SC_TIMEL_CY_NUM_ADDR}, + {"PERI_SC_INT_PTP_SYNC_ERR_ADDR ", + PERI_SC_INT_PTP_SYNC_ERR_ADDR}, + {"PERI_SC_INT_PTP_SYNC_ERR_MASK_ADDR ", + PERI_SC_INT_PTP_SYNC_ERR_MASK_ADDR}, + {"PERI_SC_INT_ORIGIN ", + PERI_SC_INT_ORIGIN}, + {"PERI_SC_CRC_ERR_COUNT ", + PERI_SC_CRC_ERR_COUNT}, + {"PERI_SC_CRC_INT_CONTRL_ADDR ", + PERI_SC_CRC_INT_CONTRL_ADDR}, + {"PERI_SC_CAPTURE_PTP_TIME_COMP_HIGH ", + PERI_SC_CAPTURE_PTP_TIME_COMP_HIGH}, + {"PERI_SC_CAPTURE_PTP_TIME_COMP_LOW ", + PERI_SC_CAPTURE_PTP_TIME_COMP_LOW}, + {"PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_HIGH", + PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_HIGH}, + {"PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_LOW ", + PERI_SC_CAPTURE_SYSTEM_COUNTER_BIN_LOW}, + {"PERI_SC_CAPTURE_VLD ", + PERI_SC_CAPTURE_VLD}, + {"PERI_SC_LOCAL_TIME_LOW_ADDR ", + PERI_SC_LOCAL_TIME_LOW_ADDR}, + {"PERI_SC_LOCAL_TIME_HIGH_ADDR ", + PERI_SC_LOCAL_TIME_HIGH_ADDR} +}; + +static void hisi_ptp_dump_reg(void __iomem *base, + const struct hisi_ptp_reg *reg, int reg_len, + char *buf, int len, int *pos) +{ + int i; + + for (i = 0; i < reg_len; i++) + *pos += scnprintf(buf + *pos, len - *pos, "%s : 0x%08x\n", + reg[i].name, readl(base + reg[i].offset)); +} + +static ssize_t hisi_ptp_dbg_read_reg(struct file *filp, char __user *buf, + size_t cnt, loff_t *ppos) +{ + struct hisi_ptp_pdev *ptp = filp->private_data; + struct hisi_ptp_rx *rx; + unsigned long flags; + ssize_t size = 0; + char *read_buf; + int pos = 0; + int len; + + if (*ppos < 0) + return -EINVAL; + if (cnt == 0) + return 0; + if (!access_ok(buf, cnt)) + return -EFAULT; + + read_buf = kvzalloc(HISI_PTP_DBGFS_REG_LEN, GFP_KERNEL); + if (!read_buf) + return -ENOMEM; + + len = HISI_PTP_DBGFS_REG_LEN; + + write_lock_irqsave(&ptp->rw_lock, flags); + if (ptp->ptp_tx && ptp->ptp_tx->base) + hisi_ptp_dump_reg(ptp->ptp_tx->base, hisi_ptp_tx_reg, + ARRAY_SIZE(hisi_ptp_tx_reg), + read_buf, len, &pos); + + if (ptp->ptp_tx && ptp->ptp_tx->io_sc_base) + hisi_ptp_dump_reg(ptp->ptp_tx->io_sc_base, hisi_ptp_tx_io_reg, + ARRAY_SIZE(hisi_ptp_tx_io_reg), + read_buf, len, &pos); + + list_for_each_entry(rx, &ptp->ptp_rx_list, node) + hisi_ptp_dump_reg(rx->base, hisi_ptp_rx_reg, + ARRAY_SIZE(hisi_ptp_rx_reg), + read_buf, len, &pos); + + write_unlock_irqrestore(&ptp->rw_lock, flags); + + size = simple_read_from_buffer(buf, cnt, ppos, read_buf, + strlen(read_buf)); + + kvfree(read_buf); + + return size; +} + +static const struct file_operations hisi_ptp_dbg_state_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = hisi_ptp_dbg_read_state, +}; + +static const struct file_operations hisi_ptp_dbg_reg_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = hisi_ptp_dbg_read_reg, +}; + +static void hisi_ptp_dbgfs_init(struct hisi_ptp_pdev *ptp) +{ + ptp->dbgfs_root = debugfs_create_dir(HISI_PTP_NAME, NULL); + debugfs_create_file("state", 0400, ptp->dbgfs_root, ptp, + &hisi_ptp_dbg_state_ops); + debugfs_create_file("reg", 0400, ptp->dbgfs_root, ptp, + &hisi_ptp_dbg_reg_ops); +} + +static void hisi_ptp_dbgfs_uninit(struct hisi_ptp_pdev *ptp) +{ + debugfs_remove_recursive(ptp->dbgfs_root); +} + +static int __init hisi_ptp_module_init(void) +{ + struct hisi_ptp_pdev *ptp = &g_ptpdev; + int ret; + + memset(ptp, 0, sizeof(struct hisi_ptp_pdev)); + rwlock_init(&ptp->rw_lock); + INIT_LIST_HEAD(&ptp->ptp_rx_list); + + timer_setup(&ptp->suppress_timer, hisi_ptp_timer, 0); + + ret = platform_driver_register(&hisi_ptp_driver); + if (ret) { + del_timer_sync(&ptp->suppress_timer); + pr_err("failed to register ptp platform driver, ret = %d\n", + ret); + return ret; + } + + hisi_ptp_dbgfs_init(ptp); + + pr_info("hisi ptp platform driver inited, version: %s\n", + HISI_PTP_VERSION); + + return 0; +} +module_init(hisi_ptp_module_init); + +static void __exit hisi_ptp_module_exit(void) +{ + struct hisi_ptp_pdev *ptp = &g_ptpdev; + + pr_info("hisi ptp platform driver exit\n"); + + hisi_ptp_dbgfs_uninit(ptp); + + platform_driver_unregister(&hisi_ptp_driver); + + if (ptp->suppress_timer.function) + del_timer_sync(&ptp->suppress_timer); + + memset(ptp, 0, sizeof(struct hisi_ptp_pdev)); +} +module_exit(hisi_ptp_module_exit); + +MODULE_DESCRIPTION("HiSilicon PTP driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(HISI_PTP_VERSION); diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 9346cd44814d6aa0b69968baad4a261dfc6adbf9..e0b333d9e9991fb135dbbfce73632b6d6577fc39 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -284,6 +284,18 @@ enum { SFF8024_ID_QSFP_8438 = 0x0c, SFF8024_ID_QSFP_8436_8636 = 0x0d, SFF8024_ID_QSFP28_8636 = 0x11, + SFF8024_ID_CXP2 = 0x12, + SFF8024_ID_CDFP = 0x13, + SFF8024_ID_HD4X_FANOUT = 0x14, + SFF8024_ID_HD8X_FANOUT = 0x15, + SFF8024_ID_CDFP_S3 = 0x16, + SFF8024_ID_MICRO_QSFP = 0x17, + SFF8024_ID_QSFP_DD = 0x18, + SFF8024_ID_OSFP = 0x19, + SFF8024_ID_DSFP = 0x1B, + SFF8024_ID_QSFP_PLUS_CMIS = 0x1E, + SFF8024_ID_SFP_DD_CMIS = 0x1F, + SFF8024_ID_SFP_PLUS_CMIS = 0x20, SFF8024_ENCODING_UNSPEC = 0x00, SFF8024_ENCODING_8B10B = 0x01, diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index f7fba0dc87e545350f8199c84023207f58054930..410bb75552bac4d74656f80cf4a139f4b89d7509 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1017,6 +1017,28 @@ struct ethtool_usrip4_spec { __u8 proto; }; +/** + * struct ethtool_vxlan4_spec - general flow specification for VxLAN IPv4 + * @vni: VxLAN network identifier + * @dst: Inner destination eth addr + * @src: Inner source eth addr + * @eth_type: Inner ethernet type + * @tos: Inner type-of-service + * @l4_proto: Inner transport protocol number + * @ip4src: Inner source host + * @ip4dst: Inner destination host + */ +struct ethtool_vxlan4_spec { + __be32 vni; + __u8 dst[ETH_ALEN]; + __u8 src[ETH_ALEN]; + __be16 eth_type; + __u8 tos; + __u8 l4_proto; + __be32 ip4src; + __be32 ip4dst; +}; + /** * struct ethtool_tcpip6_spec - flow specification for TCP/IPv6 etc. * @ip6src: Source host @@ -1067,6 +1089,28 @@ struct ethtool_usrip6_spec { __u8 l4_proto; }; +/** + * struct ethtool_vxlan6_spec - general flow specification for VxLAN IPv6 + * @vni: VxLAN network identifier + * @dst: Inner destination eth addr + * @src: Inner source eth addr + * @eth_type: Inner ethernet type + * @tclass: Inner traffic Class + * @l4_proto: Inner transport protocol number + * @ip6src: Inner source host + * @ip6dst: Inner destination host + */ +struct ethtool_vxlan6_spec { + __be32 vni; + __u8 dst[ETH_ALEN]; + __u8 src[ETH_ALEN]; + __be16 eth_type; + __u8 tclass; + __u8 l4_proto; + __be32 ip6src[4]; + __be32 ip6dst[4]; +}; + union ethtool_flow_union { struct ethtool_tcpip4_spec tcp_ip4_spec; struct ethtool_tcpip4_spec udp_ip4_spec; @@ -1074,12 +1118,14 @@ union ethtool_flow_union { struct ethtool_ah_espip4_spec ah_ip4_spec; struct ethtool_ah_espip4_spec esp_ip4_spec; struct ethtool_usrip4_spec usr_ip4_spec; + struct ethtool_vxlan4_spec vxlan_ip4_spec; struct ethtool_tcpip6_spec tcp_ip6_spec; struct ethtool_tcpip6_spec udp_ip6_spec; struct ethtool_tcpip6_spec sctp_ip6_spec; struct ethtool_ah_espip6_spec ah_ip6_spec; struct ethtool_ah_espip6_spec esp_ip6_spec; struct ethtool_usrip6_spec usr_ip6_spec; + struct ethtool_vxlan6_spec vxlan_ip6_spec; struct ethhdr ether_spec; __u8 hdata[52]; }; @@ -2011,6 +2057,8 @@ static inline int ethtool_validate_duplex(__u8 duplex) #define IPV4_FLOW 0x10 /* hash only */ #define IPV6_FLOW 0x11 /* hash only */ #define ETHER_FLOW 0x12 /* spec only (ether_spec) */ +#define VXLAN_V4_FLOW 0x43 /* spec only (vxlan_ip4_spec) */ +#define VXLAN_V6_FLOW 0x44 /* spec only (vxlan_ip6_spec) */ /* Flag to enable additional fields in struct ethtool_rx_flow_spec */ #define FLOW_EXT 0x80000000 #define FLOW_MAC_EXT 0x40000000