From: Jiantao Xiao xiaojiantao1@h-partners.com
Some feature driver inclusion
Guangbin Huang (2): net: ethtool: add VxLAN to the NFC API net: hns3: support set/get VxLAN rule of rx flow director by ethtool
Hao Chen (2): net: hns3: correct the logic of hclge_sync_vf_qb_mode() net: hns3: add support to query scc version by devlink info
Hao Lan (3): net: hns3: add command queue trace for hns3 net: sfp: Synchronize some CMIS transceiver modules from ethtool net: hns3: Add support for some CMIS transceiver modules
Jian Shen (5): net: hns3: add support for queue bonding mode of flow director net: hns3: add queue bonding mode support for VF net: hns3: allocate fd counter for queue bonding net: hns3: add support for page_pool_get_stats net: hns3: default select PAGE_POOL_STATS
Ke Chen (5): net: hns3: add ROH MAC type definitions and support query MAC type net: hns3: add support handling tx dhcp packets for ROH net: hns3: HNAE3 framework add support for ROH client net: hns3: fix bug for init roh client instance net: hns3: add support for ROH ras
Peiyang Wang (5): net: hns3: dump more reg info based on ras mod net: hns3: support tc command with max rate parameter net: hns3: support tc limit rate net: hns3: add arp proxy switch in ethtool net: hns3: support arp proxy
Yonglong Liu (1): net: hns3: add support for Hisilicon ptp sync device
liaoguojia (2): net: hns3: refactor the debugfs for dumping FD tcam net: hns3: add support for FD counter
MAINTAINERS | 5 + arch/arm64/configs/openeuler_defconfig | 3 +- drivers/net/ethernet/hisilicon/Kconfig | 1 + drivers/net/ethernet/hisilicon/hns3/Makefile | 2 +- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 8 + drivers/net/ethernet/hisilicon/hns3/hnae3.c | 10 +- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 56 + .../hns3/hns3_common/hclge_comm_cmd.c | 19 + .../hns3/hns3_common/hclge_comm_cmd.h | 25 +- .../ethernet/hisilicon/hns3/hns3_debugfs.c | 4 +- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 286 ++++- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 77 +- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 67 +- .../ethernet/hisilicon/hns3/hns3_ethtool.h | 2 + .../net/ethernet/hisilicon/hns3/hns3_roh.c | 174 +++ .../net/ethernet/hisilicon/hns3/hns3_roh.h | 26 + .../hisilicon/hns3/hns3pf/hclge_cmd.h | 31 +- .../hisilicon/hns3/hns3pf/hclge_dcb.c | 52 +- .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 139 ++- .../hisilicon/hns3/hns3pf/hclge_debugfs.h | 8 +- .../hisilicon/hns3/hns3pf/hclge_devlink.c | 44 +- .../hisilicon/hns3/hns3pf/hclge_devlink.h | 2 + .../hisilicon/hns3/hns3pf/hclge_err.c | 448 ++++++- .../hisilicon/hns3/hns3pf/hclge_err.h | 46 +- .../hisilicon/hns3/hns3pf/hclge_main.c | 691 ++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 14 + .../hisilicon/hns3/hns3pf/hclge_mbx.c | 37 + .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 53 + .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 9 + .../hisilicon/hns3/hns3pf/hclge_trace.h | 94 ++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 114 ++ .../hisilicon/hns3/hns3vf/hclgevf_main.h | 6 + .../hisilicon/hns3/hns3vf/hclgevf_mbx.c | 17 + .../hisilicon/hns3/hns3vf/hclgevf_trace.h | 50 + drivers/ptp/Kconfig | 11 + drivers/ptp/Makefile | 1 + drivers/ptp/ptp_hisi.c | 1027 +++++++++++++++++ include/linux/sfp.h | 12 + include/uapi/linux/ethtool.h | 48 + 39 files changed, 3647 insertions(+), 72 deletions(-) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_roh.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_roh.h create mode 100644 drivers/ptp/ptp_hisi.c
From: Jian Shen shenjian15@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
For device version V3, it supports queue bonding, which can identify the tuple information of TCP stream, and create flow director rules automatically, in order to keep the tx and rx packets are in the same queue pair. The driver set FD_ADD field of TX BD for TCP SYN packet, and set FD_DEL filed for TCP FIN or RST packet. The hardware create or remove a fd rule according to the TX BD, and it also support to age-out a rule if not hit for a long time.
The queue bonding mode is default to be disabled, and can be enabled/disabled with ethtool priv-flags command.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jijie Shao shaojijie@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 7 ++ .../ethernet/hisilicon/hns3/hns3_debugfs.c | 4 +- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 83 +++++++++++- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 12 +- .../ethernet/hisilicon/hns3/hns3_ethtool.c | 13 +- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 6 + .../hisilicon/hns3/hns3pf/hclge_main.c | 119 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 3 + 8 files changed, 238 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index c1c7d0fba871..c2bb47cd2666 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -574,6 +574,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 +777,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, @@ -888,6 +894,7 @@ struct hnae3_roce_private_info {
enum hnae3_pflag { HNAE3_PFLAG_LIMIT_PROMISC, + HNAE3_PFLAG_FD_QB_ENABLE, HNAE3_PFLAG_MAX };
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 807eb3bbb11c..48192fb9f75b 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 de509ae0b185..7632a073c7fd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1542,6 +1542,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 +1626,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 +1636,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 +1704,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); @@ -1651,6 +1718,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, struct hns3_desc_cb *desc_cb) { struct hns3_desc_param param; + u8 fd_op; int ret;
hns3_init_desc_data(skb, ¶m); @@ -1666,11 +1734,15 @@ 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); + /* 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); @@ -5391,6 +5463,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 acd756b0c7c9..2ac735f64ee5 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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 682239f33082..44b33ba6a168 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -466,8 +466,19 @@ 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 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 }, };
static int hns3_get_sset_count(struct net_device *netdev, int stringset) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 21234969e2ba..7fa565548e52 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -764,6 +764,12 @@ 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_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_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index f38b02e102ee..3c5f244b7be9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4583,6 +4583,95 @@ static void hclge_update_vport_alive(struct hclge_dev *hdev) } }
+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; + + 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; + } + } else { + set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); + } + spin_unlock_bh(&hdev->fd_rule_lock); + + return ret; +} + +static int hclge_disable_fd_qb_mode(struct hclge_dev *hdev) +{ + struct hnae3_ae_dev *ae_dev = hdev->ae_dev; + int ret; + + 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); + + return 0; +} + +static void hclge_sync_fd_qb_mode(struct hclge_dev *hdev) +{ + struct hnae3_ae_dev *ae_dev = hdev->ae_dev; + + if (!test_bit(HNAE3_DEV_SUPPORT_QB_B, ae_dev->caps)) + return; + + hclge_sync_pf_qb_mode(hdev); +} + static void hclge_periodic_service_task(struct hclge_dev *hdev) { unsigned long delta = round_jiffies_relative(HZ); @@ -4596,6 +4685,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)) { @@ -5114,10 +5204,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) @@ -6394,6 +6503,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 && @@ -8039,6 +8152,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 +10331,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); }
@@ -12699,6 +12814,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 5be6f9685624..ff62beeb80d4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -226,6 +226,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, @@ -658,6 +659,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 { @@ -1015,6 +1017,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,
From: Jian Shen shenjian15@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
For device version V3, the hardware supports queue bonding mode. VF can not enable queue bond mode unless PF enables it. So VF needs to query whether PF support queue bonding mode when initializing, and query whether PF enables queue bonding mode periodically. For the resource limited, to avoid a VF occupy to many FD rule space, only trust VF is allowed to enable queue bonding mode.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Jian Shen shenjian15@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../net/ethernet/hisilicon/hns3/hclge_mbx.h | 8 ++ .../hisilicon/hns3/hns3pf/hclge_main.c | 51 ++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 2 + .../hisilicon/hns3/hns3pf/hclge_mbx.c | 37 ++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 74 +++++++++++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_main.h | 6 ++ .../hisilicon/hns3/hns3vf/hclgevf_mbx.c | 17 +++++ 7 files changed, 194 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index abcd7877f7d2..0de9b83c9d4e 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/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 3c5f244b7be9..18f9dd7fc4bb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4608,6 +4608,7 @@ static int hclge_sync_pf_qb_mode(struct hclge_dev *hdev) 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; @@ -4636,6 +4637,11 @@ static int hclge_sync_pf_qb_mode(struct hclge_dev *hdev) 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); } @@ -4644,10 +4650,33 @@ static int hclge_sync_pf_qb_mode(struct hclge_dev *hdev) 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); + 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)) @@ -4659,17 +4688,35 @@ static int hclge_disable_fd_qb_mode(struct hclge_dev *hdev)
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;
- hclge_sync_pf_qb_mode(hdev); + 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) @@ -12072,6 +12119,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);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index ff62beeb80d4..d8c97430ab7b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -1048,6 +1048,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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 4d943f9c483b..700a074ef753 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/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 0aa9beefd1c7..9b1882f3a3fa 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -354,6 +354,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 +1969,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: @@ -2939,6 +3009,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 +3395,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 a73f2bf3a56a..ad59f6a61254 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 85c2a634c8f9..6ccf23ce2744 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",
From: liaoguojia liaoguojia@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
On version HNAE3_DEVICE_VERSION_V2, the tcam table entry of the FD is obtained by traversing the list recorded by the driver.
On version HNAE3_DEVICE_VERSION_V3, a new usage mode of FD is supported, called Queue bond mode. In this mode, the hardware automatically creates rules and the driver does not record the flow table entry.
So we needs to check the validity of the entry by traversing the entire hardware entry to dump out the QB tcam table.
Signed-off-by: liaoguojia liaoguojia@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Jian Shen shenjian15@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 113 +++++++++++++++--- .../hisilicon/hns3/hns3pf/hclge_debugfs.h | 5 - 2 files changed, 98 insertions(+), 20 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index ff3f8f424ad9..b376df82f2e5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -1510,8 +1510,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 +1530,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 +1540,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 +1585,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 +1619,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 +1628,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 +1644,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 */ @@ -2400,6 +2475,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 +2622,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 724052928b88..7af1f5a84fba 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;
From: Jian Shen shenjian15@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
For the fd rule of queue bonding is created by hardware automatically, the driver needs to specify the fd counter for each function, then it's available to query how many times the queue bonding fd rules hit.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Jian Shen shenjian15@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- .../hisilicon/hns3/hns3pf/hclge_cmd.h | 12 ++++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 39 +++++++++++++++++++ 2 files changed, 51 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 7fa565548e52..866e01b859f3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -770,6 +770,18 @@ struct hclge_fd_qb_cfg_cmd { 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_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 18f9dd7fc4bb..e8b2aa2a0029 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4583,6 +4583,40 @@ 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; @@ -5698,6 +5732,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); }
From: liaoguojia liaoguojia@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
FD counter is used to count the number of times that the Flow Table rule is hit. It is helpful when user want to take the accurate statistics of some rules.
Signed-off-by: liaoguojia liaoguojia@huawei.com Reviewed-by: shenjian 00434615 shenjian15@huawei.com Reviewed-by: lipeng 00277521 lipeng321@huawei.com Reviewed-by: public TuringEE turingee@huawei.com Signed-off-by: Jijie Shao shaojijie@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 10 ++++++---- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 13 +++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 866e01b859f3..9ccf95a6295e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -733,11 +733,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 +747,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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index e8b2aa2a0029..c61bbba50e34 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5785,6 +5785,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; @@ -5811,14 +5813,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);
From: Hao Chen chenhao418@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Now, hns3 driver set request_enable to qb_en whether hclge_set_fd_qb() returns failure, it's incorrect.
We only set request_enable to qb_en when hclge_set_fd_qb() returns 0. so, change it.
Fixes: b7e2927acb2a ("net: hns3: add queue bonding mode support for VF") Signed-off-by: Hao Chen chenhao418@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c61bbba50e34..2a234746243d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4700,7 +4700,8 @@ static int hclge_sync_vf_qb_mode(struct hclge_vport *vport) ret = hclge_set_fd_qb(hdev, vport->vport_id, request_enable); if (ret) set_bit(HCLGE_VPORT_STATE_QB_CHANGE, &vport->state); - vport->vf_info.qb_en = request_enable ? 1 : 0; + else + vport->vf_info.qb_en = request_enable ? 1 : 0;
return ret; }
From: Hao Chen chenhao418@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Add support to query scc version by devlink info for device V3.
Signed-off-by: Hao Chen chenhao418@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 9 ++++ .../hns3/hns3_common/hclge_comm_cmd.h | 8 ++++ .../hisilicon/hns3/hns3pf/hclge_devlink.c | 44 +++++++++++++++++-- .../hisilicon/hns3/hns3pf/hclge_devlink.h | 2 + .../hisilicon/hns3/hns3pf/hclge_main.c | 18 ++++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 1 + 6 files changed, 79 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index c2bb47cd2666..d137c96763e8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -367,6 +367,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; 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 9de1c868fed5..0d91586e03b6 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 @@ -246,6 +246,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, @@ -410,6 +413,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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c index 9a939c0b217f..a1571c108678 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 918be04507a5..148effa5ea89 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_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2a234746243d..4007d12670ab 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -11065,6 +11065,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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index d8c97430ab7b..14a95c9f7853 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -1179,6 +1179,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,
From: Jian Shen shenjian15@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Add support for page_pool_get_stats, then the hns3 driver can get page pool statistics by ethtool.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 5 +++ .../net/ethernet/hisilicon/hns3/hns3_enet.h | 1 + .../ethernet/hisilicon/hns3/hns3_ethtool.c | 38 ++++++++++++++++++- 3 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 7632a073c7fd..52b1ae1e57e5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -5033,6 +5033,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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 2ac735f64ee5..3afab7db17eb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -764,4 +764,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 44b33ba6a168..9673f518fb31 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -5,6 +5,7 @@ #include <linux/string.h> #include <linux/phy.h> #include <linux/sfp.h> +#include <net/page_pool/helpers.h>
#include "hns3_enet.h" #include "hns3_ethtool.h" @@ -485,14 +486,19 @@ 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); @@ -560,6 +566,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; @@ -607,6 +617,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. @@ -628,6 +660,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 */
From: Peiyang Wang wangpeiyang1@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Dump more reg info base on ras mod before reset, which is useful to analyze the ras error.
Signed-off-by: Peiyang Wang wangpeiyang1@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 + .../hns3/hns3_common/hclge_comm_cmd.c | 1 + .../hns3/hns3_common/hclge_comm_cmd.h | 2 + .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 6 +- .../hisilicon/hns3/hns3pf/hclge_debugfs.h | 3 + .../hisilicon/hns3/hns3pf/hclge_err.c | 434 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_err.h | 36 ++ 7 files changed, 478 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index d137c96763e8..6d0321e07f92 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -106,6 +106,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 +187,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, }; 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 20d50422daa9..42ab3944c39d 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[] = { 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 0d91586e03b6..a2b6a00deb3f 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, @@ -374,6 +375,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 { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index b376df82f2e5..177841b85084 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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h index 7af1f5a84fba..3fe78e3c2368 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h @@ -766,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_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index d63e114f93d0..db1811f7578c 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" @@ -2762,7 +3184,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 +3192,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 +3233,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 +3276,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 68b738affa66..45a783a50643 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 @@ -115,6 +116,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, @@ -191,6 +204,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 +232,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);
From: Hao Lan lanhao@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Currently, the hns3 driver does not have the trace of the command queue. As a result, it is difficult to locate the communication between the driver and firmware. Therefore, the trace function of the command queue is added in this test case to facilitate the locating of communication problems between the driver and firmware.
Signed-off-by: Hao Lan lanhao@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- .../hns3/hns3_common/hclge_comm_cmd.c | 18 ++++ .../hns3/hns3_common/hclge_comm_cmd.h | 14 ++- .../hisilicon/hns3/hns3pf/hclge_main.c | 44 +++++++++ .../hisilicon/hns3/hns3pf/hclge_trace.h | 94 +++++++++++++++++++ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 40 ++++++++ .../hisilicon/hns3/hns3vf/hclgevf_trace.h | 50 ++++++++++ 6 files changed, 259 insertions(+), 1 deletion(-)
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 42ab3944c39d..4f4b5292f358 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 @@ -472,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)) { @@ -509,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; }
@@ -586,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 a2b6a00deb3f..e3d72b21aba8 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 @@ -451,11 +451,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 { @@ -502,5 +513,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/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 4007d12670ab..b19afcb04a53 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -27,6 +27,7 @@ #include "hnae3.h" #include "hclge_devlink.h" #include "hclge_comm_cmd.h" +#include "hclge_trace.h"
#define HCLGE_NAME "hclge"
@@ -392,6 +393,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 @@ -11876,6 +11919,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) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_trace.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_trace.h index 8510b88d4982..116ac3a5ffc5 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 <linux/tracepoint.h>
+#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 9b1882f3a3fa..9bf8bd19cf93 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; @@ -2866,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); @@ -2924,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); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_trace.h index 5d4895bb57a1..82263cb5e47b 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 */
From: Hao Lan lanhao@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Currently, the SFF-8024 Identifier Values that according to the standard support for the Common Management Interface Specification (CMIS) based on standard identifier values in the ethtool is more than in the kernel. When the driver needs to use a newer Identifier Value, the kernel interface does not support it. Therefore, we synchronize the CMIS mode Identifier Values which supported by the ethtool to the kernel.
Signed-off-by: Hao Lan lanhao@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- include/linux/sfp.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 9346cd44814d..e0b333d9e999 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,
From: Hao Lan lanhao@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Add two more SFF-8024 Identifier Values that according to the standard support the Common Management Interface Specification (CMIS) memory map so the hns3 driver will be able to dump, parse and print their EEPROM contents.This two SFF-8024 Identifier Values are SFF8024_ID_QSFP_DD (0x18) and SFF8024_ID_QSFP_PLUS_CMIS (0x1E).
Signed-off-by: Hao Lan lanhao@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 8 ++++++++ drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.h | 2 ++ 2 files changed, 10 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 9673f518fb31..c0a21af54bc9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -1830,6 +1830,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 da207d1d9aa9..34504ed2c086 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 {
From: Ke Chen chenke54@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
HNAE3 framework add MAC type definitions for NIC or RoCE or ROH clients.
There are two types of MAC in Hip09, ethernet and ROH. In ROH type, some operations are different, such as setting MAC address. This type will be used as the judgment condition in subsequent patches.
Signed-off-by: Yufeng Mo moyufeng@huawei.com Signed-off-by: Ke Chen chenke54@huawei.com Reviewed-by: Gang Zhang gang.zhang@huawei.com Reviewed-by: Yefeng Yan yanyefeng@huawei.com Reviewed-by: Jingchao Dai daijingchao1@huawei.com Reviewed-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 14 ++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 18 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.c | 16 ++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 6d0321e07f92..47c4f7a34836 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -231,6 +231,11 @@ enum hnae3_client_type { HNAE3_CLIENT_ROCE, };
+enum hnae3_mac_type { + HNAE3_MAC_ETH, + HNAE3_MAC_ROH, +}; + /* mac media type */ enum hnae3_media_type { HNAE3_MEDIA_TYPE_UNKNOWN, @@ -939,6 +944,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) \ @@ -953,6 +962,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/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 177841b85084..2942c9254e2f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -387,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; @@ -400,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, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index b19afcb04a53..739dbc68404a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1479,6 +1479,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; @@ -2946,6 +2960,8 @@ 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))
From: Peiyang Wang wangpeiyang1@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Traffic class is supposed to support limit rate. Configure different rates for different tc. The followed tc command can be used.
tc qdisc add dev ethx root mqprio num_tc 4 map 0 1 2 3 0 1 2 3 queues 8@0 8@8 8@16 8@24 hw 1 mode channel shaper bw_rlimit max_rate 10mbps 10mbps 10mbps 10mbps
Signed-off-by: Peiyang Wang wangpeiyang1@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 ++ .../hisilicon/hns3/hns3pf/hclge_dcb.c | 42 ++++++++++++++++--- .../hisilicon/hns3/hns3pf/hclge_main.h | 2 + .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 6 +++ .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 1 + 5 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 47c4f7a34836..d484d92ded6f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -71,6 +71,9 @@ #define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) | \ BIT(HNAE3_DEV_SUPPORT_ROCE_B))
+#define hnae3_dev_roh_supported(hdev) \ + hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_ROH_CLIENT_INITED_B) + #define hnae3_dev_roce_supported(hdev) \ hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_ROCE_B)
@@ -853,6 +856,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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index eabbacb1c714..1cfd7a32e6ab 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,6 +606,8 @@ 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, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 14a95c9f7853..59662acd2b9b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -378,6 +378,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 */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 6387120bee04..79a2472230fd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -1668,6 +1668,12 @@ void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc) hclge_tm_schd_info_init(hdev); }
+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) { int ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index 49cc441f999d..896b3b9672eb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -279,5 +279,6 @@ 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); +u32 hclge_tm_rate_2_port_rate(u64 rate); void hclge_reset_tc_config(struct hclge_dev *hdev); #endif
From: Peiyang Wang wangpeiyang1@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Traffic class is supposed to support limit rate. Different tc will be configured different rate. The followed tc command can be used.
tc qdisc add dev eth0 root mqprio num_tc 4 map 0 1 2 3 0 1 2 3 queues 8@0 8@8 8@16 8@24 hw 1 mode channel shaper bw_rlimit max_rate 10gbps 1gbps 100mbps 10mbps
As showed the aboved command, the eth0 has 4 tcs and the limit rate are 80 Gbits/sec, 8 Gbits/sec, 800 Mbits/sec and 80 Mbits/sec respectively.
Signed-off-by: Peiyang Wang wangpeiyang1@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- .../hns3/hns3_common/hclge_comm_cmd.h | 1 + .../hisilicon/hns3/hns3pf/hclge_dcb.c | 10 +++- .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 47 +++++++++++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 8 ++++ 4 files changed, 65 insertions(+), 1 deletion(-)
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 e3d72b21aba8..44a484342b4c 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 @@ -155,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 */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index 1cfd7a32e6ab..416bcac3bf70 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -613,13 +613,21 @@ static void hclge_sync_mqprio_qopt(struct hnae3_tc_info *tc_info, 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_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 79a2472230fd..a8350940fd5e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -1668,6 +1668,49 @@ 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); @@ -1676,6 +1719,7 @@ u32 hclge_tm_rate_2_port_rate(u64 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) && @@ -1690,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 896b3b9672eb..64b448370f93 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,6 +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
From: Peiyang Wang wangpeiyang1@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
To use arp proxy more conviency, add an arp proxy switch in ethool. Use followed command to open or close arp proxy: ethtool --set-priv-flags <device_name> roh_arp_proxy_enable <on/off>
Use followed command to find current state of arp proxy switch: ethtool --show-priv-flags <device_name>
The results are showed as followed: ... roh_arp_proxy_enable: on
Signed-off-by: Peiyang Wang wangpeiyang1@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 6 ++++++ drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 8 ++++++++ 3 files changed, 15 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index d484d92ded6f..484cd7744a49 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -917,6 +917,7 @@ 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 };
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 52b1ae1e57e5..a8f320eb3637 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -5354,6 +5354,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) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index c0a21af54bc9..c065c759e8cd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -477,9 +477,17 @@ static void hns3_update_fd_qb_state(struct net_device *netdev, bool enable) 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 }, { "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)
From: Peiyang Wang wangpeiyang1@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
In RoH mode, the IP and MAC of network devices have a special mapping relationship. The mapping is show as followed: IP: a.b.c.d <------> MAC: 0.0.0.b.c.d Thus, the arp request for find the mac of a ip is not necessary to send to network. The driver can generate a response arp to the protocol stack based on above mapping relationship.
Arp proxy is designed to acheive the above function. The scope of ARP proxy include all ARP request message including vlan, except free ARP request and tunnel message.
Signed-off-by: Peiyang Wang wangpeiyang1@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/Makefile | 2 +- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 9 + .../net/ethernet/hisilicon/hns3/hns3_enet.h | 14 ++ .../net/ethernet/hisilicon/hns3/hns3_roh.c | 174 ++++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3_roh.h | 26 +++ 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_roh.c create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_roh.h
diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile index cc9158097e93..1cc61b2062c0 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/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index a8f320eb3637..c8a32d57c0d1 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 @@ -2400,6 +2401,11 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) goto out_err_tx_ok; }
+ 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(ring, skb, desc_cb, ring->next_to_use); if (unlikely(ret <= 0)) goto out_err_tx_ok; @@ -4564,6 +4570,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); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 3afab7db17eb..1456de40f4b6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -471,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; @@ -496,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 */ 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 000000000000..1c0341b34f6d --- /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 <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/if_vlan.h> +#include <net/arp.h> + +#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 000000000000..222ed20d8772 --- /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
From: Ke Chen chenke54@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
For ROH distributed scenario, EID is allocated by DHCP mode. Driver needs to convert the origin MAC address to EID format, and updates the destination MAC, chaddr and client id(if exists) when transmit DHCP packets. Meantime, the chaddr field should follow the source mac address, in order to make the dhcp server reply to the right client. For the payload of dhcp packet changed, so the checksum of L4 should be calculated too.
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Ke Chen chenke54@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 174 +++++++++++++++++- .../net/ethernet/hisilicon/hns3/hns3_enet.h | 50 +++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 14 ++ 3 files changed, 233 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index c8a32d57c0d1..f17ab8c4788f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1163,6 +1163,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) { @@ -1714,7 +1850,20 @@ 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) { @@ -1739,6 +1888,15 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, 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); @@ -2344,15 +2502,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;
@@ -2406,7 +2565,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) hns3_need_to_handle_roh_arp_req(skb)) return hns3_handle_roh_arp_req(skb, priv);
- ret = hns3_handle_skb_desc(ring, skb, desc_cb, ring->next_to_use); + ret = hns3_handle_skb_desc(priv, ring, skb, desc_cb, ring->next_to_use); if (unlikely(ret <= 0)) goto out_err_tx_ok;
@@ -5246,6 +5405,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);
@@ -5400,6 +5563,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);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 1456de40f4b6..60a4ae384233 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -618,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 { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 739dbc68404a..59ec55a90881 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2955,6 +2955,20 @@ 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;
From: Ke Chen chenke54@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
HNAE3 framework supports ROH clients to register with HNAE3 devices and their associated operations.
The ROH driver works as a client at the HNAE layer. The NIC driver needs to provide some necessary information, such as the vector base address, and suppor the registration of the ROH client.
This patch also supports roh device IDs in the hns3 and hclge modules.
Signed-off-by: Yufeng Mo moyufeng@huawei.com Signed-off-by: Ke Chen chenke54@huawei.com Reviewed-by: Gang Zhang gang.zhang@huawei.com Reviewed-by: Yefeng Yan yanyefeng@huawei.com Reviewed-by: Jingchao Dai daijingchao1@huawei.com Reviewed-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.c | 10 +- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 12 ++ .../net/ethernet/hisilicon/hns3/hns3_enet.c | 9 ++ .../hisilicon/hns3/hns3pf/hclge_cmd.h | 3 +- .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 2 + .../hisilicon/hns3/hns3pf/hclge_main.c | 104 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 4 + 7 files changed, 141 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c index 67b0bf310daa..ee4b7f5910b1 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 484cd7744a49..2055df16dec4 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,6 +70,7 @@ #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_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) | \ BIT(HNAE3_DEV_SUPPORT_ROCE_B)) @@ -232,6 +236,7 @@ enum hnae3_loop { enum hnae3_client_type { HNAE3_CLIENT_KNIC, HNAE3_CLIENT_ROCE, + HNAE3_CLIENT_ROH, };
enum hnae3_mac_type { @@ -899,6 +904,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) @@ -932,6 +943,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 */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index f17ab8c4788f..0df74d71bec8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -98,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_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_DCB_BITS}, + {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), + HNAE3_DEV_SUPPORT_ROCE_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}, @@ -3294,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: diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 9ccf95a6295e..81dc8eb946f0 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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 2942c9254e2f..4eac6833ddd2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -1849,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", diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 59ec55a90881..fc372b326a29 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -77,7 +77,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, } }; @@ -874,11 +877,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; } @@ -2521,6 +2527,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; @@ -4923,6 +4948,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); } @@ -11506,6 +11533,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) { @@ -11521,6 +11589,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; @@ -11536,6 +11612,15 @@ static int hclge_init_client_instance(struct hnae3_client *client, if (ret) goto clear_roce;
+ break; + case HNAE3_CLIENT_ROH: + 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; @@ -11551,6 +11636,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, @@ -11559,6 +11648,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)) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 59662acd2b9b..d795494b352d 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, @@ -923,6 +924,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; @@ -939,6 +941,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) @@ -1077,6 +1080,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;
From: Ke Chen chenke54@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
add support for the roh capability in hnae3_dev flag.
Signed-off-by: Ke Chen chenke54@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 7 ++++++- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 6 +++--- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 ++++-- 3 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 2055df16dec4..d98e951574de 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -71,12 +71,17 @@ #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_ROH_CLIENT_INITED_B) + 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) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 0df74d71bec8..dae17c3b72bc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -99,13 +99,13 @@ static const struct pci_device_id hns3_pci_tbl[] = { {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_DCB_BITS}, + 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_DCB_BITS}, + HNAE3_DEV_SUPPORT_ROCE_ROH_DCB_BITS}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_400G_ROH), - HNAE3_DEV_SUPPORT_ROCE_DCB_BITS}, + 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}, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index fc372b326a29..23769f075c56 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -11614,8 +11614,10 @@ static int hclge_init_client_instance(struct hnae3_client *client,
break; case HNAE3_CLIENT_ROH: - hdev->roh_client = client; - vport->roh.client = client; + 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)
From: Ke Chen chenke54@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Add HCLGE_RAS_REG_ROH_ERR_MASK to support the error recovery of the ROH ras. Add HCLGE_RAS_REG_ERR_MASK to define the combination of the nfe_mask, the rocee_err_mask and the roh_err_mask.
Add new module error types for ROH, adjust the order of these types according to the design of firmware.
Signed-off-by: Jiaran Zhang zhangjiaran@huawei.com Signed-off-by: Ke Chen chenke54@huawei.com Reviewed-by: Gang Zhang gang.zhang@huawei.com Reviewed-by: Yefeng Yan yanyefeng@huawei.com Reviewed-by: Jingchao Dai daijingchao1@huawei.com Reviewed-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c | 14 +++++++++++++- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h | 10 +++++++++- 2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index db1811f7578c..e198f813e063 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -1699,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" } };
@@ -1759,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, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h index 45a783a50643..1667a6466f37 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.h @@ -16,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
@@ -164,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 { @@ -187,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 {
From: Guangbin Huang huangguangbin2@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
To support for steering VxLAN flows using the ethtool NFC interface, this patch adds flow specifications for vxlan4(VxLAN with inner IPv4) and vxlan6 (VxLAN with inner IPv6).
Signed-off-by: Guangbin Huang huangguangbin2@huawei.com Signed-off-by: Jijie Shao shaojijie@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- include/uapi/linux/ethtool.h | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index f7fba0dc87e5..410bb75552ba 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
From: Guangbin Huang huangguangbin2@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
This patch adds support rule type of vxlan4 and vxlan6 for rx flow director by command ethtool -u/-U.
Signed-off-by: Guangbin Huang huangguangbin2@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- .../hisilicon/hns3/hns3pf/hclge_main.c | 272 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 2 + 2 files changed, 271 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 23769f075c56..be6fb312ed90 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 <linux/crash_dump.h> #include <net/ipv6.h> #include <net/rtnetlink.h> +#include <net/vxlan.h> #include "hclge_cmd.h" #include "hclge_dcb.h" #include "hclge_ext.h" @@ -338,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), @@ -5814,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; } @@ -5937,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; @@ -5989,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; @@ -6211,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) { @@ -6266,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) @@ -6448,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: @@ -6458,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) { @@ -6538,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) { @@ -6567,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) { @@ -6645,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; @@ -6657,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; @@ -7007,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) @@ -7067,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) @@ -7193,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: @@ -7203,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 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index d795494b352d..7f1e31ea0f9c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -647,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 @@ -741,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 {
From: Jian Shen shenjian15@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
Default select PAGE_POOL_STATS, so the hns3 driver can supports page pool statistics.
Fixes: ae1b20540202 ("net: hns3: add support for page_pool_get_stats")
Signed-off-by: Jian Shen shenjian15@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- arch/arm64/configs/openeuler_defconfig | 2 +- drivers/net/ethernet/hisilicon/Kconfig | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index afde4d70ee13..492fecf80dfa 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -1932,7 +1932,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 diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 3312e1d93c3b..14bd24316d41 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
From: Yonglong Liu liuyonglong@huawei.com
driver inclusion category:feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9A3QT CVE: NA
----------------------------------------------------------------------
The hns3 driver provide ptp driver to get 1588 clock from ethernet, but only the first PF on main chip can support this, so, if getting ptp time from other chip, may have some bus latency. The PTP sync device use to eliminate the bus latency.
Signed-off-by: Yonglong Liu liuyonglong@huawei.com Signed-off-by: Jiantao Xiao xiaojiantao1@h-partners.com --- MAINTAINERS | 5 + arch/arm64/configs/openeuler_defconfig | 1 + drivers/ptp/Kconfig | 11 + drivers/ptp/Makefile | 1 + drivers/ptp/ptp_hisi.c | 1027 ++++++++++++++++++++++++ 5 files changed, 1045 insertions(+) create mode 100644 drivers/ptp/ptp_hisi.c
diff --git a/MAINTAINERS b/MAINTAINERS index f0dd63afe9e3..a3dc0b545d9a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9532,6 +9532,11 @@ S: Maintained F: Documentation/ABI/testing/debugfs-hisi-zip F: drivers/crypto/hisilicon/zip/
+HISILICON HNS3 PTP SYNC DRIVER +M: Yonglong Liu liuyonglong@huawei.com +S: Supported +F: drivers/ptp/ptp_hisi.c + HMM - Heterogeneous Memory Management M: Jérôme Glisse jglisse@redhat.com L: linux-mm@kvack.org diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 492fecf80dfa..beaeac96796b 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -3842,6 +3842,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/ptp/Kconfig b/drivers/ptp/Kconfig index ed9d97a032f1..14a7b49e4760 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 dea0cebd2303..8d21ee20787d 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 000000000000..0eb1ebf44dc8 --- /dev/null +++ b/drivers/ptp/ptp_hisi.c @@ -0,0 +1,1027 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2022 Hisilicon Limited. +#include <linux/mm.h> +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/ptp_clock_kernel.h> +#include <linux/net_tstamp.h> +#include <linux/debugfs.h> + +#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);
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/5463 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/5...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/5463 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/5...