Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Jian Shen | 20884 | 32.79% | 120 | 20.17% |
Salil | 15018 | 23.58% | 23 | 3.87% |
Li Peng | 6522 | 10.24% | 45 | 7.56% |
Guangbin Huang | 3947 | 6.20% | 54 | 9.08% |
Huazhong Tan | 3163 | 4.97% | 84 | 14.12% |
Lin Yun Sheng | 3002 | 4.71% | 55 | 9.24% |
Yufeng Mo | 2160 | 3.39% | 33 | 5.55% |
Yonglong Liu | 1711 | 2.69% | 23 | 3.87% |
Hao Lan | 1547 | 2.43% | 6 | 1.01% |
Fuyun Liang | 1228 | 1.93% | 23 | 3.87% |
Jie Wang | 862 | 1.35% | 21 | 3.53% |
Zhongzhu Liu | 763 | 1.20% | 13 | 2.18% |
Hao Chen | 655 | 1.03% | 7 | 1.18% |
Guojia Liao | 610 | 0.96% | 18 | 3.03% |
Jiaran Zhang | 381 | 0.60% | 12 | 2.02% |
Weihang Li | 361 | 0.57% | 7 | 1.18% |
Yue haibing | 235 | 0.37% | 2 | 0.34% |
Shiju Jose | 202 | 0.32% | 12 | 2.02% |
Xi Wang | 111 | 0.17% | 4 | 0.67% |
Jijie Shao | 104 | 0.16% | 7 | 1.18% |
Peiyang Wang | 60 | 0.09% | 4 | 0.67% |
qumingguang | 59 | 0.09% | 2 | 0.34% |
Asbjörn Sloth Tönnesen | 51 | 0.08% | 1 | 0.17% |
Andrew Lunn | 12 | 0.02% | 3 | 0.50% |
Colin Ian King | 9 | 0.01% | 5 | 0.84% |
Ratheesh Kannoth | 8 | 0.01% | 1 | 0.17% |
Baokun Li | 5 | 0.01% | 1 | 0.17% |
LiuJian | 2 | 0.00% | 1 | 0.17% |
Jakub Kiciński | 2 | 0.00% | 2 | 0.34% |
Wei Yongjun | 2 | 0.00% | 2 | 0.34% |
caihuoqing | 2 | 0.00% | 1 | 0.17% |
Xiu Jianfeng | 2 | 0.00% | 1 | 0.17% |
Zheng Yongjun | 1 | 0.00% | 1 | 0.17% |
Anirudh Venkataramanan | 1 | 0.00% | 1 | 0.17% |
Total | 63682 | 595 |
// SPDX-License-Identifier: GPL-2.0+ // Copyright (c) 2016-2017 Hisilicon Limited. #include <linux/acpi.h> #include <linux/device.h> #include <linux/etherdevice.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/pci.h> #include <linux/platform_device.h> #include <linux/if_vlan.h> #include <linux/crash_dump.h> #include <net/ipv6.h> #include <net/rtnetlink.h> #include "hclge_cmd.h" #include "hclge_dcb.h" #include "hclge_main.h" #include "hclge_mbx.h" #include "hclge_mdio.h" #include "hclge_regs.h" #include "hclge_tm.h" #include "hclge_err.h" #include "hnae3.h" #include "hclge_devlink.h" #include "hclge_comm_cmd.h" #include "hclge_trace.h" #define HCLGE_NAME "hclge" #define HCLGE_BUF_SIZE_UNIT 256U #define HCLGE_BUF_MUL_BY 2 #define HCLGE_BUF_DIV_BY 2 #define NEED_RESERVE_TC_NUM 2 #define BUF_MAX_PERCENT 100 #define BUF_RESERVE_PERCENT 90 #define HCLGE_RESET_MAX_FAIL_CNT 5 #define HCLGE_RESET_SYNC_TIME 100 #define HCLGE_PF_RESET_SYNC_TIME 20 #define HCLGE_PF_RESET_SYNC_CNT 1500 #define HCLGE_LINK_STATUS_MS 10 static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps); static int hclge_init_vlan_config(struct hclge_dev *hdev); static void hclge_sync_vlan_filter(struct hclge_dev *hdev); static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev); static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle); static void hclge_rfs_filter_expire(struct hclge_dev *hdev); static int hclge_clear_arfs_rules(struct hclge_dev *hdev); static enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev, unsigned long *addr); static int hclge_set_default_loopback(struct hclge_dev *hdev); static void hclge_sync_mac_table(struct hclge_dev *hdev); static void hclge_restore_hw_table(struct hclge_dev *hdev); static void hclge_sync_promisc_mode(struct hclge_dev *hdev); static void hclge_sync_fd_table(struct hclge_dev *hdev); static void hclge_update_fec_stats(struct hclge_dev *hdev); static int hclge_mac_link_status_wait(struct hclge_dev *hdev, int link_ret, int wait_cnt); static int hclge_update_port_info(struct hclge_dev *hdev); static struct hnae3_ae_algo ae_algo; static struct workqueue_struct *hclge_wq; static const struct pci_device_id ae_algo_pci_tbl[] = { {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_GE), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_25GE_RDMA_MACSEC), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_50GE_RDMA_MACSEC), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_100G_RDMA_MACSEC), 0}, {PCI_VDEVICE(HUAWEI, HNAE3_DEV_ID_200G_RDMA), 0}, /* required last entry */ {0, } }; MODULE_DEVICE_TABLE(pci, ae_algo_pci_tbl); static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = { "External Loopback test", "App Loopback test", "Serdes serial Loopback test", "Serdes parallel Loopback test", "Phy Loopback test" }; static const struct hclge_comm_stats_str g_mac_stats_string[] = { {"mac_tx_mac_pause_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_mac_pause_num)}, {"mac_rx_mac_pause_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_mac_pause_num)}, {"mac_tx_pause_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pause_xoff_time)}, {"mac_rx_pause_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pause_xoff_time)}, {"mac_tx_control_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_ctrl_pkt_num)}, {"mac_rx_control_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_ctrl_pkt_num)}, {"mac_tx_pfc_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pause_pkt_num)}, {"mac_tx_pfc_pri0_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri0_pkt_num)}, {"mac_tx_pfc_pri1_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri1_pkt_num)}, {"mac_tx_pfc_pri2_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri2_pkt_num)}, {"mac_tx_pfc_pri3_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri3_pkt_num)}, {"mac_tx_pfc_pri4_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri4_pkt_num)}, {"mac_tx_pfc_pri5_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri5_pkt_num)}, {"mac_tx_pfc_pri6_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri6_pkt_num)}, {"mac_tx_pfc_pri7_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri7_pkt_num)}, {"mac_tx_pfc_pri0_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri0_xoff_time)}, {"mac_tx_pfc_pri1_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri1_xoff_time)}, {"mac_tx_pfc_pri2_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri2_xoff_time)}, {"mac_tx_pfc_pri3_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri3_xoff_time)}, {"mac_tx_pfc_pri4_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri4_xoff_time)}, {"mac_tx_pfc_pri5_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri5_xoff_time)}, {"mac_tx_pfc_pri6_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri6_xoff_time)}, {"mac_tx_pfc_pri7_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_pfc_pri7_xoff_time)}, {"mac_rx_pfc_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pause_pkt_num)}, {"mac_rx_pfc_pri0_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri0_pkt_num)}, {"mac_rx_pfc_pri1_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri1_pkt_num)}, {"mac_rx_pfc_pri2_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri2_pkt_num)}, {"mac_rx_pfc_pri3_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri3_pkt_num)}, {"mac_rx_pfc_pri4_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri4_pkt_num)}, {"mac_rx_pfc_pri5_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri5_pkt_num)}, {"mac_rx_pfc_pri6_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri6_pkt_num)}, {"mac_rx_pfc_pri7_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri7_pkt_num)}, {"mac_rx_pfc_pri0_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri0_xoff_time)}, {"mac_rx_pfc_pri1_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri1_xoff_time)}, {"mac_rx_pfc_pri2_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri2_xoff_time)}, {"mac_rx_pfc_pri3_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri3_xoff_time)}, {"mac_rx_pfc_pri4_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri4_xoff_time)}, {"mac_rx_pfc_pri5_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri5_xoff_time)}, {"mac_rx_pfc_pri6_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri6_xoff_time)}, {"mac_rx_pfc_pri7_xoff_time", HCLGE_MAC_STATS_MAX_NUM_V2, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_pfc_pri7_xoff_time)}, {"mac_tx_total_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_total_pkt_num)}, {"mac_tx_total_oct_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_total_oct_num)}, {"mac_tx_good_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_good_pkt_num)}, {"mac_tx_bad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_bad_pkt_num)}, {"mac_tx_good_oct_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_good_oct_num)}, {"mac_tx_bad_oct_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_bad_oct_num)}, {"mac_tx_uni_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_uni_pkt_num)}, {"mac_tx_multi_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_multi_pkt_num)}, {"mac_tx_broad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_broad_pkt_num)}, {"mac_tx_undersize_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_undersize_pkt_num)}, {"mac_tx_oversize_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_oversize_pkt_num)}, {"mac_tx_64_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_64_oct_pkt_num)}, {"mac_tx_65_127_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_65_127_oct_pkt_num)}, {"mac_tx_128_255_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_128_255_oct_pkt_num)}, {"mac_tx_256_511_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_256_511_oct_pkt_num)}, {"mac_tx_512_1023_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_512_1023_oct_pkt_num)}, {"mac_tx_1024_1518_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_1024_1518_oct_pkt_num)}, {"mac_tx_1519_2047_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_1519_2047_oct_pkt_num)}, {"mac_tx_2048_4095_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_2048_4095_oct_pkt_num)}, {"mac_tx_4096_8191_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_4096_8191_oct_pkt_num)}, {"mac_tx_8192_9216_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_8192_9216_oct_pkt_num)}, {"mac_tx_9217_12287_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_9217_12287_oct_pkt_num)}, {"mac_tx_12288_16383_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_12288_16383_oct_pkt_num)}, {"mac_tx_1519_max_good_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_1519_max_good_oct_pkt_num)}, {"mac_tx_1519_max_bad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_1519_max_bad_oct_pkt_num)}, {"mac_rx_total_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_total_pkt_num)}, {"mac_rx_total_oct_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_total_oct_num)}, {"mac_rx_good_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_good_pkt_num)}, {"mac_rx_bad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_bad_pkt_num)}, {"mac_rx_good_oct_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_good_oct_num)}, {"mac_rx_bad_oct_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_bad_oct_num)}, {"mac_rx_uni_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_uni_pkt_num)}, {"mac_rx_multi_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_multi_pkt_num)}, {"mac_rx_broad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_broad_pkt_num)}, {"mac_rx_undersize_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_undersize_pkt_num)}, {"mac_rx_oversize_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_oversize_pkt_num)}, {"mac_rx_64_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_64_oct_pkt_num)}, {"mac_rx_65_127_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_65_127_oct_pkt_num)}, {"mac_rx_128_255_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_128_255_oct_pkt_num)}, {"mac_rx_256_511_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_256_511_oct_pkt_num)}, {"mac_rx_512_1023_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_512_1023_oct_pkt_num)}, {"mac_rx_1024_1518_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_1024_1518_oct_pkt_num)}, {"mac_rx_1519_2047_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_1519_2047_oct_pkt_num)}, {"mac_rx_2048_4095_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_2048_4095_oct_pkt_num)}, {"mac_rx_4096_8191_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_4096_8191_oct_pkt_num)}, {"mac_rx_8192_9216_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_8192_9216_oct_pkt_num)}, {"mac_rx_9217_12287_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_9217_12287_oct_pkt_num)}, {"mac_rx_12288_16383_oct_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_12288_16383_oct_pkt_num)}, {"mac_rx_1519_max_good_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_1519_max_good_oct_pkt_num)}, {"mac_rx_1519_max_bad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_1519_max_bad_oct_pkt_num)}, {"mac_tx_fragment_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_fragment_pkt_num)}, {"mac_tx_undermin_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_undermin_pkt_num)}, {"mac_tx_jabber_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_jabber_pkt_num)}, {"mac_tx_err_all_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_err_all_pkt_num)}, {"mac_tx_from_app_good_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_from_app_good_pkt_num)}, {"mac_tx_from_app_bad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_tx_from_app_bad_pkt_num)}, {"mac_rx_fragment_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_fragment_pkt_num)}, {"mac_rx_undermin_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_undermin_pkt_num)}, {"mac_rx_jabber_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_jabber_pkt_num)}, {"mac_rx_fcs_err_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_fcs_err_pkt_num)}, {"mac_rx_send_app_good_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_send_app_good_pkt_num)}, {"mac_rx_send_app_bad_pkt_num", HCLGE_MAC_STATS_MAX_NUM_V1, HCLGE_MAC_STATS_FIELD_OFF(mac_rx_send_app_bad_pkt_num)} }; static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = { { .flags = HCLGE_MAC_MGR_MASK_VLAN_B, .ethter_type = cpu_to_le16(ETH_P_LLDP), .mac_addr = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}, .i_port_bitmap = 0x1, }, }; static const struct key_info meta_data_key_info[] = { { PACKET_TYPE_ID, 6 }, { IP_FRAGEMENT, 1 }, { ROCE_TYPE, 1 }, { NEXT_KEY, 5 }, { VLAN_NUMBER, 2 }, { SRC_VPORT, 12 }, { DST_VPORT, 12 }, { TUNNEL_PACKET, 1 }, }; static const struct key_info tuple_key_info[] = { { OUTER_DST_MAC, 48, KEY_OPT_MAC, -1, -1 }, { OUTER_SRC_MAC, 48, KEY_OPT_MAC, -1, -1 }, { OUTER_VLAN_TAG_FST, 16, KEY_OPT_LE16, -1, -1 }, { OUTER_VLAN_TAG_SEC, 16, KEY_OPT_LE16, -1, -1 }, { OUTER_ETH_TYPE, 16, KEY_OPT_LE16, -1, -1 }, { OUTER_L2_RSV, 16, KEY_OPT_LE16, -1, -1 }, { OUTER_IP_TOS, 8, KEY_OPT_U8, -1, -1 }, { OUTER_IP_PROTO, 8, KEY_OPT_U8, -1, -1 }, { OUTER_SRC_IP, 32, KEY_OPT_IP, -1, -1 }, { OUTER_DST_IP, 32, KEY_OPT_IP, -1, -1 }, { OUTER_L3_RSV, 16, KEY_OPT_LE16, -1, -1 }, { 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_FLOW_ID, 8, KEY_OPT_U8, -1, -1 }, { INNER_DST_MAC, 48, KEY_OPT_MAC, offsetof(struct hclge_fd_rule, tuples.dst_mac), offsetof(struct hclge_fd_rule, tuples_mask.dst_mac) }, { INNER_SRC_MAC, 48, KEY_OPT_MAC, offsetof(struct hclge_fd_rule, tuples.src_mac), offsetof(struct hclge_fd_rule, tuples_mask.src_mac) }, { INNER_VLAN_TAG_FST, 16, KEY_OPT_LE16, offsetof(struct hclge_fd_rule, tuples.vlan_tag1), offsetof(struct hclge_fd_rule, tuples_mask.vlan_tag1) }, { INNER_VLAN_TAG_SEC, 16, KEY_OPT_LE16, -1, -1 }, { INNER_ETH_TYPE, 16, KEY_OPT_LE16, offsetof(struct hclge_fd_rule, tuples.ether_proto), offsetof(struct hclge_fd_rule, tuples_mask.ether_proto) }, { INNER_L2_RSV, 16, KEY_OPT_LE16, offsetof(struct hclge_fd_rule, tuples.l2_user_def), offsetof(struct hclge_fd_rule, tuples_mask.l2_user_def) }, { INNER_IP_TOS, 8, KEY_OPT_U8, offsetof(struct hclge_fd_rule, tuples.ip_tos), offsetof(struct hclge_fd_rule, tuples_mask.ip_tos) }, { INNER_IP_PROTO, 8, KEY_OPT_U8, offsetof(struct hclge_fd_rule, tuples.ip_proto), offsetof(struct hclge_fd_rule, tuples_mask.ip_proto) }, { INNER_SRC_IP, 32, KEY_OPT_IP, offsetof(struct hclge_fd_rule, tuples.src_ip), offsetof(struct hclge_fd_rule, tuples_mask.src_ip) }, { INNER_DST_IP, 32, KEY_OPT_IP, offsetof(struct hclge_fd_rule, tuples.dst_ip), offsetof(struct hclge_fd_rule, tuples_mask.dst_ip) }, { INNER_L3_RSV, 16, KEY_OPT_LE16, offsetof(struct hclge_fd_rule, tuples.l3_user_def), offsetof(struct hclge_fd_rule, tuples_mask.l3_user_def) }, { INNER_SRC_PORT, 16, KEY_OPT_LE16, offsetof(struct hclge_fd_rule, tuples.src_port), offsetof(struct hclge_fd_rule, tuples_mask.src_port) }, { INNER_DST_PORT, 16, KEY_OPT_LE16, offsetof(struct hclge_fd_rule, tuples.dst_port), offsetof(struct hclge_fd_rule, tuples_mask.dst_port) }, { INNER_L4_RSV, 32, KEY_OPT_LE32, offsetof(struct hclge_fd_rule, tuples.l4_user_def), offsetof(struct hclge_fd_rule, tuples_mask.l4_user_def) }, }; /** * hclge_cmd_send - send command to command queue * @hw: pointer to the hw struct * @desc: prefilled descriptor for describing the command * @num : the number of descriptors to be sent * * This is the main send command for command queue, it * sends the queue, cleans the queue, etc **/ 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, (__le32 *)&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, (__le32 *)&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 u64 *data = (u64 *)(&hdev->mac_stats); struct hclge_desc desc[HCLGE_MAC_CMD_NUM]; __le64 *desc_data; u32 data_size; int ret; u32 i; hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_STATS_MAC, true); ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_MAC_CMD_NUM); if (ret) { dev_err(&hdev->pdev->dev, "Get MAC pkt stats fail, status = %d.\n", ret); return ret; } /* The first desc has a 64-bit header, so data size need to minus 1 */ data_size = sizeof(desc) / (sizeof(u64)) - 1; desc_data = (__le64 *)(&desc[0].data[0]); for (i = 0; i < data_size; i++) { /* data memory is continuous becase only the first desc has a * header in this command */ *data += le64_to_cpu(*desc_data); data++; desc_data++; } return 0; } static int hclge_mac_update_stats_complete(struct hclge_dev *hdev) { #define HCLGE_REG_NUM_PER_DESC 4 u32 reg_num = hdev->ae_dev->dev_specs.mac_stats_num; u64 *data = (u64 *)(&hdev->mac_stats); struct hclge_desc *desc; __le64 *desc_data; u32 data_size; u32 desc_num; int ret; u32 i; /* The first desc has a 64-bit header, so need to consider it */ desc_num = reg_num / HCLGE_REG_NUM_PER_DESC + 1; /* This may be called inside atomic sections, * so GFP_ATOMIC is more suitalbe here */ desc = kcalloc(desc_num, sizeof(struct hclge_desc), GFP_ATOMIC); if (!desc) return -ENOMEM; hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_STATS_MAC_ALL, true); ret = hclge_cmd_send(&hdev->hw, desc, desc_num); if (ret) { kfree(desc); return ret; } data_size = min_t(u32, sizeof(hdev->mac_stats) / sizeof(u64), reg_num); desc_data = (__le64 *)(&desc[0].data[0]); for (i = 0; i < data_size; i++) { /* data memory is continuous becase only the first desc has a * header in this command */ *data += le64_to_cpu(*desc_data); data++; desc_data++; } kfree(desc); return 0; } static int hclge_mac_query_reg_num(struct hclge_dev *hdev, u32 *reg_num) { struct hclge_desc desc; int ret; /* Driver needs total register number of both valid registers and * reserved registers, but the old firmware only returns number * of valid registers in device V2. To be compatible with these * devices, driver uses a fixed value. */ if (hdev->ae_dev->dev_version == HNAE3_DEVICE_VERSION_V2) { *reg_num = HCLGE_MAC_STATS_MAX_NUM_V1; return 0; } hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_MAC_REG_NUM, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to query mac statistic reg number, ret = %d\n", ret); return ret; } *reg_num = le32_to_cpu(desc.data[0]); if (*reg_num == 0) { dev_err(&hdev->pdev->dev, "mac statistic reg number is invalid!\n"); return -ENODATA; } return 0; } int hclge_mac_update_stats(struct hclge_dev *hdev) { /* The firmware supports the new statistics acquisition method */ if (hdev->ae_dev->dev_specs.mac_stats_num) return hclge_mac_update_stats_complete(hdev); else return hclge_mac_update_stats_defective(hdev); } static int hclge_comm_get_count(struct hclge_dev *hdev, const struct hclge_comm_stats_str strs[], u32 size) { int count = 0; u32 i; for (i = 0; i < size; i++) if (strs[i].stats_num <= hdev->ae_dev->dev_specs.mac_stats_num) count++; return count; } static u64 *hclge_comm_get_stats(struct hclge_dev *hdev, const struct hclge_comm_stats_str strs[], int size, u64 *data) { u64 *buf = data; u32 i; for (i = 0; i < size; i++) { if (strs[i].stats_num > hdev->ae_dev->dev_specs.mac_stats_num) continue; *buf = HCLGE_STATS_READ(&hdev->mac_stats, strs[i].offset); buf++; } return buf; } static u8 *hclge_comm_get_strings(struct hclge_dev *hdev, u32 stringset, const struct hclge_comm_stats_str strs[], int size, u8 *data) { char *buff = (char *)data; u32 i; if (stringset != ETH_SS_STATS) return buff; for (i = 0; i < size; i++) { if (strs[i].stats_num > hdev->ae_dev->dev_specs.mac_stats_num) continue; snprintf(buff, ETH_GSTRING_LEN, "%s", strs[i].desc); buff = buff + ETH_GSTRING_LEN; } return (u8 *)buff; } static void hclge_update_stats_for_all(struct hclge_dev *hdev) { struct hnae3_handle *handle; int status; handle = &hdev->vport[0].nic; if (handle->client) { status = hclge_comm_tqps_update_stats(handle, &hdev->hw.hw); if (status) { dev_err(&hdev->pdev->dev, "Update TQPS stats fail, status = %d.\n", status); } } hclge_update_fec_stats(hdev); status = hclge_mac_update_stats(hdev); if (status) dev_err(&hdev->pdev->dev, "Update MAC stats fail, status = %d.\n", status); } static void hclge_update_stats(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int status; if (test_and_set_bit(HCLGE_STATE_STATISTICS_UPDATING, &hdev->state)) return; status = hclge_mac_update_stats(hdev); if (status) dev_err(&hdev->pdev->dev, "Update MAC stats fail, status = %d.\n", status); status = hclge_comm_tqps_update_stats(handle, &hdev->hw.hw); if (status) dev_err(&hdev->pdev->dev, "Update TQPS stats fail, status = %d.\n", status); clear_bit(HCLGE_STATE_STATISTICS_UPDATING, &hdev->state); } static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) { #define HCLGE_LOOPBACK_TEST_FLAGS (HNAE3_SUPPORT_APP_LOOPBACK | \ HNAE3_SUPPORT_PHY_LOOPBACK | \ HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK | \ HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK | \ HNAE3_SUPPORT_EXTERNAL_LOOPBACK) struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int count = 0; /* Loopback test support rules: * mac: only GE mode support * serdes: all mac mode will support include GE/XGE/LGE/CGE * phy: only support when phy device exist on board */ if (stringset == ETH_SS_TEST) { /* clear loopback bit flags at first */ handle->flags = (handle->flags & (~HCLGE_LOOPBACK_TEST_FLAGS)); if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2 || hdev->hw.mac.speed == HCLGE_MAC_SPEED_10M || hdev->hw.mac.speed == HCLGE_MAC_SPEED_100M || hdev->hw.mac.speed == HCLGE_MAC_SPEED_1G) { count += 1; handle->flags |= HNAE3_SUPPORT_APP_LOOPBACK; } if (hdev->ae_dev->dev_specs.hilink_version != HCLGE_HILINK_H60) { count += 1; handle->flags |= HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK; } count += 1; handle->flags |= HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK; count += 1; handle->flags |= HNAE3_SUPPORT_EXTERNAL_LOOPBACK; if ((hdev->hw.mac.phydev && hdev->hw.mac.phydev->drv && hdev->hw.mac.phydev->drv->set_loopback) || hnae3_dev_phy_imp_supported(hdev)) { count += 1; handle->flags |= HNAE3_SUPPORT_PHY_LOOPBACK; } } else if (stringset == ETH_SS_STATS) { count = hclge_comm_get_count(hdev, g_mac_stats_string, ARRAY_SIZE(g_mac_stats_string)) + hclge_comm_tqps_get_sset_count(handle); } return count; } static void hclge_get_strings(struct hnae3_handle *handle, u32 stringset, u8 *data) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u8 *p = (char *)data; int size; if (stringset == ETH_SS_STATS) { size = ARRAY_SIZE(g_mac_stats_string); p = hclge_comm_get_strings(hdev, stringset, g_mac_stats_string, size, p); p = hclge_comm_tqps_get_strings(handle, p); } else if (stringset == ETH_SS_TEST) { if (handle->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK) { memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) { memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_APP], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } if (handle->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK) { memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } if (handle->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) { memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) { memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_PHY], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } } } static void hclge_get_stats(struct hnae3_handle *handle, u64 *data) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u64 *p; p = hclge_comm_get_stats(hdev, g_mac_stats_string, ARRAY_SIZE(g_mac_stats_string), data); p = hclge_comm_tqps_get_stats(handle, p); } static void hclge_get_mac_stat(struct hnae3_handle *handle, struct hns3_mac_stats *mac_stats) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; hclge_update_stats(handle); mac_stats->tx_pause_cnt = hdev->mac_stats.mac_tx_mac_pause_num; mac_stats->rx_pause_cnt = hdev->mac_stats.mac_rx_mac_pause_num; } static int hclge_parse_func_status(struct hclge_dev *hdev, struct hclge_func_status_cmd *status) { #define HCLGE_MAC_ID_MASK 0xF if (!(status->pf_state & HCLGE_PF_STATE_DONE)) return -EINVAL; /* Set the pf to main pf */ if (status->pf_state & HCLGE_PF_STATE_MAIN) hdev->flag |= HCLGE_FLAG_MAIN; else hdev->flag &= ~HCLGE_FLAG_MAIN; hdev->hw.mac.mac_id = status->mac_id & HCLGE_MAC_ID_MASK; return 0; } static int hclge_query_function_status(struct hclge_dev *hdev) { #define HCLGE_QUERY_MAX_CNT 5 struct hclge_func_status_cmd *req; struct hclge_desc desc; int timeout = 0; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_FUNC_STATUS, true); req = (struct hclge_func_status_cmd *)desc.data; do { ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "query function status failed %d.\n", ret); return ret; } /* Check pf reset is done */ if (req->pf_state) break; usleep_range(1000, 2000); } while (timeout++ < HCLGE_QUERY_MAX_CNT); return hclge_parse_func_status(hdev, req); } static int hclge_query_pf_resource(struct hclge_dev *hdev) { struct hclge_pf_res_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_PF_RSRC, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "query pf resource failed %d.\n", ret); return ret; } req = (struct hclge_pf_res_cmd *)desc.data; hdev->num_tqps = le16_to_cpu(req->tqp_num) + le16_to_cpu(req->ext_tqp_num); hdev->pkt_buf_size = le16_to_cpu(req->buf_size) << HCLGE_BUF_UNIT_S; if (req->tx_buf_size) hdev->tx_buf_size = le16_to_cpu(req->tx_buf_size) << HCLGE_BUF_UNIT_S; else hdev->tx_buf_size = HCLGE_DEFAULT_TX_BUF; hdev->tx_buf_size = roundup(hdev->tx_buf_size, HCLGE_BUF_SIZE_UNIT); if (req->dv_buf_size) hdev->dv_buf_size = le16_to_cpu(req->dv_buf_size) << HCLGE_BUF_UNIT_S; else hdev->dv_buf_size = HCLGE_DEFAULT_DV; hdev->dv_buf_size = roundup(hdev->dv_buf_size, HCLGE_BUF_SIZE_UNIT); hdev->num_nic_msi = le16_to_cpu(req->msixcap_localid_number_nic); if (hdev->num_nic_msi < HNAE3_MIN_VECTOR_NUM) { dev_err(&hdev->pdev->dev, "only %u msi resources available, not enough for pf(min:2).\n", hdev->num_nic_msi); return -EINVAL; } if (hnae3_dev_roce_supported(hdev)) { hdev->num_roce_msi = le16_to_cpu(req->pf_intr_vector_number_roce); /* 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; } else { hdev->num_msi = hdev->num_nic_msi; } return 0; } static int hclge_parse_speed(u8 speed_cmd, u32 *speed) { switch (speed_cmd) { case HCLGE_FW_MAC_SPEED_10M: *speed = HCLGE_MAC_SPEED_10M; break; case HCLGE_FW_MAC_SPEED_100M: *speed = HCLGE_MAC_SPEED_100M; break; case HCLGE_FW_MAC_SPEED_1G: *speed = HCLGE_MAC_SPEED_1G; break; case HCLGE_FW_MAC_SPEED_10G: *speed = HCLGE_MAC_SPEED_10G; break; case HCLGE_FW_MAC_SPEED_25G: *speed = HCLGE_MAC_SPEED_25G; break; case HCLGE_FW_MAC_SPEED_40G: *speed = HCLGE_MAC_SPEED_40G; break; case HCLGE_FW_MAC_SPEED_50G: *speed = HCLGE_MAC_SPEED_50G; break; case HCLGE_FW_MAC_SPEED_100G: *speed = HCLGE_MAC_SPEED_100G; break; case HCLGE_FW_MAC_SPEED_200G: *speed = HCLGE_MAC_SPEED_200G; break; default: return -EINVAL; } return 0; } static const struct hclge_speed_bit_map speed_bit_map[] = { {HCLGE_MAC_SPEED_10M, HCLGE_SUPPORT_10M_BIT}, {HCLGE_MAC_SPEED_100M, HCLGE_SUPPORT_100M_BIT}, {HCLGE_MAC_SPEED_1G, HCLGE_SUPPORT_1G_BIT}, {HCLGE_MAC_SPEED_10G, HCLGE_SUPPORT_10G_BIT}, {HCLGE_MAC_SPEED_25G, HCLGE_SUPPORT_25G_BIT}, {HCLGE_MAC_SPEED_40G, HCLGE_SUPPORT_40G_BIT}, {HCLGE_MAC_SPEED_50G, HCLGE_SUPPORT_50G_BITS}, {HCLGE_MAC_SPEED_100G, HCLGE_SUPPORT_100G_BITS}, {HCLGE_MAC_SPEED_200G, HCLGE_SUPPORT_200G_BITS}, }; static int hclge_get_speed_bit(u32 speed, u32 *speed_bit) { u16 i; for (i = 0; i < ARRAY_SIZE(speed_bit_map); i++) { if (speed == speed_bit_map[i].speed) { *speed_bit = speed_bit_map[i].speed_bit; return 0; } } return -EINVAL; } static int hclge_check_port_speed(struct hnae3_handle *handle, u32 speed) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u32 speed_ability = hdev->hw.mac.speed_ability; u32 speed_bit = 0; int ret; ret = hclge_get_speed_bit(speed, &speed_bit); if (ret) return ret; if (speed_bit & speed_ability) return 0; return -EINVAL; } static void hclge_update_fec_support(struct hclge_mac *mac) { linkmode_clear_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, mac->supported); linkmode_clear_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, mac->supported); linkmode_clear_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, mac->supported); linkmode_clear_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->supported); if (mac->fec_ability & BIT(HNAE3_FEC_BASER)) linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, mac->supported); if (mac->fec_ability & BIT(HNAE3_FEC_RS)) linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, mac->supported); if (mac->fec_ability & BIT(HNAE3_FEC_LLRS)) linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, mac->supported); if (mac->fec_ability & BIT(HNAE3_FEC_NONE)) linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->supported); } static const struct hclge_link_mode_bmap hclge_sr_link_mode_bmap[] = { {HCLGE_SUPPORT_10G_BIT, ETHTOOL_LINK_MODE_10000baseSR_Full_BIT}, {HCLGE_SUPPORT_25G_BIT, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT}, {HCLGE_SUPPORT_40G_BIT, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT}, {HCLGE_SUPPORT_50G_R2_BIT, ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT}, {HCLGE_SUPPORT_50G_R1_BIT, ETHTOOL_LINK_MODE_50000baseSR_Full_BIT}, {HCLGE_SUPPORT_100G_R4_BIT, ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT}, {HCLGE_SUPPORT_100G_R2_BIT, ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT}, {HCLGE_SUPPORT_200G_R4_EXT_BIT, ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT}, {HCLGE_SUPPORT_200G_R4_BIT, ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT}, }; static const struct hclge_link_mode_bmap hclge_lr_link_mode_bmap[] = { {HCLGE_SUPPORT_10G_BIT, ETHTOOL_LINK_MODE_10000baseLR_Full_BIT}, {HCLGE_SUPPORT_40G_BIT, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT}, {HCLGE_SUPPORT_50G_R1_BIT, ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT}, {HCLGE_SUPPORT_100G_R4_BIT, ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT}, {HCLGE_SUPPORT_100G_R2_BIT, ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT}, {HCLGE_SUPPORT_200G_R4_EXT_BIT, ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT}, {HCLGE_SUPPORT_200G_R4_BIT, ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT}, }; static const struct hclge_link_mode_bmap hclge_cr_link_mode_bmap[] = { {HCLGE_SUPPORT_10G_BIT, ETHTOOL_LINK_MODE_10000baseCR_Full_BIT}, {HCLGE_SUPPORT_25G_BIT, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT}, {HCLGE_SUPPORT_40G_BIT, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT}, {HCLGE_SUPPORT_50G_R2_BIT, ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT}, {HCLGE_SUPPORT_50G_R1_BIT, ETHTOOL_LINK_MODE_50000baseCR_Full_BIT}, {HCLGE_SUPPORT_100G_R4_BIT, ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT}, {HCLGE_SUPPORT_100G_R2_BIT, ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT}, {HCLGE_SUPPORT_200G_R4_EXT_BIT, ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT}, {HCLGE_SUPPORT_200G_R4_BIT, ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT}, }; static const struct hclge_link_mode_bmap hclge_kr_link_mode_bmap[] = { {HCLGE_SUPPORT_1G_BIT, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT}, {HCLGE_SUPPORT_10G_BIT, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT}, {HCLGE_SUPPORT_25G_BIT, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT}, {HCLGE_SUPPORT_40G_BIT, ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT}, {HCLGE_SUPPORT_50G_R2_BIT, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT}, {HCLGE_SUPPORT_50G_R1_BIT, ETHTOOL_LINK_MODE_50000baseKR_Full_BIT}, {HCLGE_SUPPORT_100G_R4_BIT, ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT}, {HCLGE_SUPPORT_100G_R2_BIT, ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT}, {HCLGE_SUPPORT_200G_R4_EXT_BIT, ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT}, {HCLGE_SUPPORT_200G_R4_BIT, ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT}, }; static void hclge_convert_setting_sr(u16 speed_ability, unsigned long *link_mode) { int i; for (i = 0; i < ARRAY_SIZE(hclge_sr_link_mode_bmap); i++) { if (speed_ability & hclge_sr_link_mode_bmap[i].support_bit) linkmode_set_bit(hclge_sr_link_mode_bmap[i].link_mode, link_mode); } } static void hclge_convert_setting_lr(u16 speed_ability, unsigned long *link_mode) { int i; for (i = 0; i < ARRAY_SIZE(hclge_lr_link_mode_bmap); i++) { if (speed_ability & hclge_lr_link_mode_bmap[i].support_bit) linkmode_set_bit(hclge_lr_link_mode_bmap[i].link_mode, link_mode); } } static void hclge_convert_setting_cr(u16 speed_ability, unsigned long *link_mode) { int i; for (i = 0; i < ARRAY_SIZE(hclge_cr_link_mode_bmap); i++) { if (speed_ability & hclge_cr_link_mode_bmap[i].support_bit) linkmode_set_bit(hclge_cr_link_mode_bmap[i].link_mode, link_mode); } } static void hclge_convert_setting_kr(u16 speed_ability, unsigned long *link_mode) { int i; for (i = 0; i < ARRAY_SIZE(hclge_kr_link_mode_bmap); i++) { if (speed_ability & hclge_kr_link_mode_bmap[i].support_bit) linkmode_set_bit(hclge_kr_link_mode_bmap[i].link_mode, link_mode); } } static void hclge_convert_setting_fec(struct hclge_mac *mac) { /* If firmware has reported fec_ability, don't need to convert by speed */ if (mac->fec_ability) goto out; switch (mac->speed) { case HCLGE_MAC_SPEED_10G: case HCLGE_MAC_SPEED_40G: mac->fec_ability = BIT(HNAE3_FEC_BASER) | BIT(HNAE3_FEC_AUTO) | BIT(HNAE3_FEC_NONE); break; case HCLGE_MAC_SPEED_25G: case HCLGE_MAC_SPEED_50G: mac->fec_ability = BIT(HNAE3_FEC_BASER) | BIT(HNAE3_FEC_RS) | BIT(HNAE3_FEC_AUTO) | BIT(HNAE3_FEC_NONE); break; case HCLGE_MAC_SPEED_100G: mac->fec_ability = BIT(HNAE3_FEC_RS) | BIT(HNAE3_FEC_AUTO) | BIT(HNAE3_FEC_NONE); break; case HCLGE_MAC_SPEED_200G: mac->fec_ability = BIT(HNAE3_FEC_RS) | BIT(HNAE3_FEC_AUTO) | BIT(HNAE3_FEC_LLRS); break; default: mac->fec_ability = 0; break; } out: hclge_update_fec_support(mac); } static void hclge_parse_fiber_link_mode(struct hclge_dev *hdev, u16 speed_ability) { struct hclge_mac *mac = &hdev->hw.mac; if (speed_ability & HCLGE_SUPPORT_1G_BIT) linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, mac->supported); hclge_convert_setting_sr(speed_ability, mac->supported); hclge_convert_setting_lr(speed_ability, mac->supported); hclge_convert_setting_cr(speed_ability, mac->supported); if (hnae3_dev_fec_supported(hdev)) hclge_convert_setting_fec(mac); if (hnae3_dev_pause_supported(hdev)) linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mac->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mac->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->supported); } static void hclge_parse_backplane_link_mode(struct hclge_dev *hdev, u16 speed_ability) { struct hclge_mac *mac = &hdev->hw.mac; hclge_convert_setting_kr(speed_ability, mac->supported); if (hnae3_dev_fec_supported(hdev)) hclge_convert_setting_fec(mac); if (hnae3_dev_pause_supported(hdev)) linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mac->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, mac->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->supported); } static void hclge_parse_copper_link_mode(struct hclge_dev *hdev, u16 speed_ability) { unsigned long *supported = hdev->hw.mac.supported; /* default to support all speed for GE port */ if (!speed_ability) speed_ability = HCLGE_SUPPORT_GE; if (speed_ability & HCLGE_SUPPORT_1G_BIT) linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, supported); if (speed_ability & HCLGE_SUPPORT_100M_BIT) { linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, supported); linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, supported); } if (speed_ability & HCLGE_SUPPORT_10M_BIT) { linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, supported); linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, supported); } if (hnae3_dev_pause_supported(hdev)) { linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported); linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported); } linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported); linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported); } static void hclge_parse_link_mode(struct hclge_dev *hdev, u16 speed_ability) { u8 media_type = hdev->hw.mac.media_type; if (media_type == HNAE3_MEDIA_TYPE_FIBER) hclge_parse_fiber_link_mode(hdev, speed_ability); else if (media_type == HNAE3_MEDIA_TYPE_COPPER) hclge_parse_copper_link_mode(hdev, speed_ability); else if (media_type == HNAE3_MEDIA_TYPE_BACKPLANE) hclge_parse_backplane_link_mode(hdev, speed_ability); } static u32 hclge_get_max_speed(u16 speed_ability) { if (speed_ability & HCLGE_SUPPORT_200G_BITS) return HCLGE_MAC_SPEED_200G; if (speed_ability & HCLGE_SUPPORT_100G_BITS) return HCLGE_MAC_SPEED_100G; if (speed_ability & HCLGE_SUPPORT_50G_BITS) return HCLGE_MAC_SPEED_50G; if (speed_ability & HCLGE_SUPPORT_40G_BIT) return HCLGE_MAC_SPEED_40G; if (speed_ability & HCLGE_SUPPORT_25G_BIT) return HCLGE_MAC_SPEED_25G; if (speed_ability & HCLGE_SUPPORT_10G_BIT) return HCLGE_MAC_SPEED_10G; if (speed_ability & HCLGE_SUPPORT_1G_BIT) return HCLGE_MAC_SPEED_1G; if (speed_ability & HCLGE_SUPPORT_100M_BIT) return HCLGE_MAC_SPEED_100M; if (speed_ability & HCLGE_SUPPORT_10M_BIT) return HCLGE_MAC_SPEED_10M; return HCLGE_MAC_SPEED_1G; } static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc) { #define HCLGE_TX_SPARE_SIZE_UNIT 4096 #define SPEED_ABILITY_EXT_SHIFT 8 struct hclge_cfg_param_cmd *req; u64 mac_addr_tmp_high; u16 speed_ability_ext; u64 mac_addr_tmp; unsigned int i; req = (struct hclge_cfg_param_cmd *)desc[0].data; /* get the configuration */ cfg->tc_num = hnae3_get_field(__le32_to_cpu(req->param[0]), HCLGE_CFG_TC_NUM_M, HCLGE_CFG_TC_NUM_S); cfg->tqp_desc_num = hnae3_get_field(__le32_to_cpu(req->param[0]), HCLGE_CFG_TQP_DESC_N_M, HCLGE_CFG_TQP_DESC_N_S); cfg->phy_addr = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_PHY_ADDR_M, HCLGE_CFG_PHY_ADDR_S); cfg->media_type = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_MEDIA_TP_M, HCLGE_CFG_MEDIA_TP_S); cfg->rx_buf_len = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_RX_BUF_LEN_M, HCLGE_CFG_RX_BUF_LEN_S); /* get mac_address */ mac_addr_tmp = __le32_to_cpu(req->param[2]); mac_addr_tmp_high = hnae3_get_field(__le32_to_cpu(req->param[3]), HCLGE_CFG_MAC_ADDR_H_M, HCLGE_CFG_MAC_ADDR_H_S); mac_addr_tmp |= (mac_addr_tmp_high << 31) << 1; cfg->default_speed = hnae3_get_field(__le32_to_cpu(req->param[3]), HCLGE_CFG_DEFAULT_SPEED_M, HCLGE_CFG_DEFAULT_SPEED_S); cfg->vf_rss_size_max = hnae3_get_field(__le32_to_cpu(req->param[3]), HCLGE_CFG_RSS_SIZE_M, HCLGE_CFG_RSS_SIZE_S); for (i = 0; i < ETH_ALEN; i++) cfg->mac_addr[i] = (mac_addr_tmp >> (8 * i)) & 0xff; req = (struct hclge_cfg_param_cmd *)desc[1].data; cfg->numa_node_map = __le32_to_cpu(req->param[0]); cfg->speed_ability = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_SPEED_ABILITY_M, HCLGE_CFG_SPEED_ABILITY_S); speed_ability_ext = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_SPEED_ABILITY_EXT_M, HCLGE_CFG_SPEED_ABILITY_EXT_S); cfg->speed_ability |= speed_ability_ext << SPEED_ABILITY_EXT_SHIFT; cfg->vlan_fliter_cap = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_VLAN_FLTR_CAP_M, HCLGE_CFG_VLAN_FLTR_CAP_S); cfg->umv_space = hnae3_get_field(__le32_to_cpu(req->param[1]), HCLGE_CFG_UMV_TBL_SPACE_M, HCLGE_CFG_UMV_TBL_SPACE_S); cfg->pf_rss_size_max = hnae3_get_field(__le32_to_cpu(req->param[2]), HCLGE_CFG_PF_RSS_SIZE_M, HCLGE_CFG_PF_RSS_SIZE_S); /* HCLGE_CFG_PF_RSS_SIZE_M is the PF max rss size, which is a * power of 2, instead of reading out directly. This would * be more flexible for future changes and expansions. * When VF max rss size field is HCLGE_CFG_RSS_SIZE_S, * it does not make sense if PF's field is 0. In this case, PF and VF * has the same max rss size filed: HCLGE_CFG_RSS_SIZE_S. */ cfg->pf_rss_size_max = cfg->pf_rss_size_max ? 1U << cfg->pf_rss_size_max : cfg->vf_rss_size_max; /* The unit of the tx spare buffer size queried from configuration * file is HCLGE_TX_SPARE_SIZE_UNIT(4096) bytes, so a conversion is * needed here. */ cfg->tx_spare_buf_size = hnae3_get_field(__le32_to_cpu(req->param[2]), HCLGE_CFG_TX_SPARE_BUF_SIZE_M, HCLGE_CFG_TX_SPARE_BUF_SIZE_S); cfg->tx_spare_buf_size *= HCLGE_TX_SPARE_SIZE_UNIT; } /* hclge_get_cfg: query the static parameter from flash * @hdev: pointer to struct hclge_dev * @hcfg: the config structure to be getted */ static int hclge_get_cfg(struct hclge_dev *hdev, struct hclge_cfg *hcfg) { struct hclge_desc desc[HCLGE_PF_CFG_DESC_NUM]; struct hclge_cfg_param_cmd *req; unsigned int i; int ret; for (i = 0; i < HCLGE_PF_CFG_DESC_NUM; i++) { u32 offset = 0; req = (struct hclge_cfg_param_cmd *)desc[i].data; hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_GET_CFG_PARAM, true); hnae3_set_field(offset, HCLGE_CFG_OFFSET_M, HCLGE_CFG_OFFSET_S, i * HCLGE_CFG_RD_LEN_BYTES); /* Len should be united by 4 bytes when send to hardware */ hnae3_set_field(offset, HCLGE_CFG_RD_LEN_M, HCLGE_CFG_RD_LEN_S, HCLGE_CFG_RD_LEN_BYTES / HCLGE_CFG_RD_LEN_UNIT); req->offset = cpu_to_le32(offset); } ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_PF_CFG_DESC_NUM); if (ret) { dev_err(&hdev->pdev->dev, "get config failed %d.\n", ret); return ret; } hclge_parse_cfg(hcfg, desc); return 0; } static void hclge_set_default_dev_specs(struct hclge_dev *hdev) { #define HCLGE_MAX_NON_TSO_BD_NUM 8U struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); ae_dev->dev_specs.max_non_tso_bd_num = HCLGE_MAX_NON_TSO_BD_NUM; ae_dev->dev_specs.rss_ind_tbl_size = HCLGE_RSS_IND_TBL_SIZE; ae_dev->dev_specs.rss_key_size = HCLGE_COMM_RSS_KEY_SIZE; ae_dev->dev_specs.max_tm_rate = HCLGE_ETHER_MAX_RATE; ae_dev->dev_specs.max_int_gl = HCLGE_DEF_MAX_INT_GL; ae_dev->dev_specs.max_frm_size = HCLGE_MAC_MAX_FRAME; ae_dev->dev_specs.max_qset_num = HCLGE_MAX_QSET_NUM; ae_dev->dev_specs.umv_size = HCLGE_DEFAULT_UMV_SPACE_PER_PF; ae_dev->dev_specs.tnl_num = 0; } static void hclge_parse_dev_specs(struct hclge_dev *hdev, struct hclge_desc *desc) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hclge_dev_specs_0_cmd *req0; struct hclge_dev_specs_1_cmd *req1; req0 = (struct hclge_dev_specs_0_cmd *)desc[0].data; req1 = (struct hclge_dev_specs_1_cmd *)desc[1].data; ae_dev->dev_specs.max_non_tso_bd_num = req0->max_non_tso_bd_num; ae_dev->dev_specs.rss_ind_tbl_size = le16_to_cpu(req0->rss_ind_tbl_size); ae_dev->dev_specs.int_ql_max = le16_to_cpu(req0->int_ql_max); ae_dev->dev_specs.rss_key_size = le16_to_cpu(req0->rss_key_size); ae_dev->dev_specs.max_tm_rate = le32_to_cpu(req0->max_tm_rate); ae_dev->dev_specs.max_qset_num = le16_to_cpu(req1->max_qset_num); ae_dev->dev_specs.max_int_gl = le16_to_cpu(req1->max_int_gl); ae_dev->dev_specs.max_frm_size = le16_to_cpu(req1->max_frm_size); ae_dev->dev_specs.umv_size = le16_to_cpu(req1->umv_size); ae_dev->dev_specs.mc_mac_size = le16_to_cpu(req1->mc_mac_size); ae_dev->dev_specs.tnl_num = req1->tnl_num; ae_dev->dev_specs.hilink_version = req1->hilink_version; } static void hclge_check_dev_specs(struct hclge_dev *hdev) { struct hnae3_dev_specs *dev_specs = &hdev->ae_dev->dev_specs; if (!dev_specs->max_non_tso_bd_num) dev_specs->max_non_tso_bd_num = HCLGE_MAX_NON_TSO_BD_NUM; if (!dev_specs->rss_ind_tbl_size) dev_specs->rss_ind_tbl_size = HCLGE_RSS_IND_TBL_SIZE; if (!dev_specs->rss_key_size) dev_specs->rss_key_size = HCLGE_COMM_RSS_KEY_SIZE; if (!dev_specs->max_tm_rate) dev_specs->max_tm_rate = HCLGE_ETHER_MAX_RATE; if (!dev_specs->max_qset_num) dev_specs->max_qset_num = HCLGE_MAX_QSET_NUM; if (!dev_specs->max_int_gl) dev_specs->max_int_gl = HCLGE_DEF_MAX_INT_GL; if (!dev_specs->max_frm_size) dev_specs->max_frm_size = HCLGE_MAC_MAX_FRAME; if (!dev_specs->umv_size) dev_specs->umv_size = HCLGE_DEFAULT_UMV_SPACE_PER_PF; } static int hclge_query_mac_stats_num(struct hclge_dev *hdev) { u32 reg_num = 0; int ret; ret = hclge_mac_query_reg_num(hdev, ®_num); if (ret && ret != -EOPNOTSUPP) return ret; hdev->ae_dev->dev_specs.mac_stats_num = reg_num; return 0; } static int hclge_query_dev_specs(struct hclge_dev *hdev) { struct hclge_desc desc[HCLGE_QUERY_DEV_SPECS_BD_NUM]; int ret; int i; ret = hclge_query_mac_stats_num(hdev); if (ret) return ret; /* set default specifications as devices lower than version V3 do not * support querying specifications from firmware. */ if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3) { hclge_set_default_dev_specs(hdev); return 0; } for (i = 0; i < HCLGE_QUERY_DEV_SPECS_BD_NUM - 1; i++) { hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_QUERY_DEV_SPECS, true); desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); } hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_QUERY_DEV_SPECS, true); ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_QUERY_DEV_SPECS_BD_NUM); if (ret) return ret; hclge_parse_dev_specs(hdev, desc); hclge_check_dev_specs(hdev); return 0; } static int hclge_get_cap(struct hclge_dev *hdev) { int ret; ret = hclge_query_function_status(hdev); if (ret) { dev_err(&hdev->pdev->dev, "query function status error %d.\n", ret); return ret; } /* get pf resource */ return hclge_query_pf_resource(hdev); } static void hclge_init_kdump_kernel_config(struct hclge_dev *hdev) { #define HCLGE_MIN_TX_DESC 64 #define HCLGE_MIN_RX_DESC 64 if (!is_kdump_kernel()) return; dev_info(&hdev->pdev->dev, "Running kdump kernel. Using minimal resources\n"); /* minimal queue pairs equals to the number of vports */ hdev->num_tqps = hdev->num_req_vfs + 1; hdev->num_tx_desc = HCLGE_MIN_TX_DESC; hdev->num_rx_desc = HCLGE_MIN_RX_DESC; } static void hclge_init_tc_config(struct hclge_dev *hdev) { unsigned int i; if (hdev->tc_max > HNAE3_MAX_TC || hdev->tc_max < 1) { dev_warn(&hdev->pdev->dev, "TC num = %u.\n", hdev->tc_max); hdev->tc_max = 1; } /* Dev does not support DCB */ if (!hnae3_dev_dcb_supported(hdev)) { hdev->tc_max = 1; hdev->pfc_max = 0; } else { hdev->pfc_max = hdev->tc_max; } hdev->tm_info.num_tc = 1; /* Currently not support uncontiuous tc */ for (i = 0; i < hdev->tm_info.num_tc; i++) hnae3_set_bit(hdev->hw_tc_map, i, 1); hdev->tx_sch_mode = HCLGE_FLAG_TC_BASE_SCH_MODE; } static int hclge_configure(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hclge_cfg cfg; int ret; ret = hclge_get_cfg(hdev, &cfg); if (ret) return ret; hdev->base_tqp_pid = 0; hdev->vf_rss_size_max = cfg.vf_rss_size_max; hdev->pf_rss_size_max = cfg.pf_rss_size_max; hdev->rx_buf_len = cfg.rx_buf_len; ether_addr_copy(hdev->hw.mac.mac_addr, cfg.mac_addr); hdev->hw.mac.media_type = cfg.media_type; hdev->hw.mac.phy_addr = cfg.phy_addr; hdev->num_tx_desc = cfg.tqp_desc_num; hdev->num_rx_desc = cfg.tqp_desc_num; hdev->tm_info.num_pg = 1; hdev->tc_max = cfg.tc_num; hdev->tm_info.hw_pfc_map = 0; if (cfg.umv_space) hdev->wanted_umv_size = cfg.umv_space; else hdev->wanted_umv_size = hdev->ae_dev->dev_specs.umv_size; hdev->tx_spare_buf_size = cfg.tx_spare_buf_size; hdev->gro_en = true; if (cfg.vlan_fliter_cap == HCLGE_VLAN_FLTR_CAN_MDF) set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps); if (hnae3_ae_dev_fd_supported(hdev->ae_dev)) { hdev->fd_en = true; hdev->fd_active_type = HCLGE_FD_RULE_NONE; } ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed); if (ret) { dev_err(&hdev->pdev->dev, "failed to parse speed %u, ret = %d\n", cfg.default_speed, ret); return ret; } hdev->hw.mac.req_speed = hdev->hw.mac.speed; hdev->hw.mac.req_autoneg = AUTONEG_ENABLE; hdev->hw.mac.req_duplex = DUPLEX_FULL; hclge_parse_link_mode(hdev, cfg.speed_ability); hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability); hclge_init_tc_config(hdev); hclge_init_kdump_kernel_config(hdev); return ret; } static int hclge_config_tso(struct hclge_dev *hdev, u16 tso_mss_min, u16 tso_mss_max) { struct hclge_cfg_tso_status_cmd *req; struct hclge_desc desc; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TSO_GENERIC_CONFIG, false); req = (struct hclge_cfg_tso_status_cmd *)desc.data; req->tso_mss_min = cpu_to_le16(tso_mss_min); req->tso_mss_max = cpu_to_le16(tso_mss_max); return hclge_cmd_send(&hdev->hw, &desc, 1); } static int hclge_config_gro(struct hclge_dev *hdev) { struct hclge_cfg_gro_status_cmd *req; struct hclge_desc desc; int ret; if (!hnae3_ae_dev_gro_supported(hdev->ae_dev)) return 0; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GRO_GENERIC_CONFIG, false); req = (struct hclge_cfg_gro_status_cmd *)desc.data; req->gro_en = hdev->gro_en ? 1 : 0; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "GRO hardware config cmd failed, ret = %d\n", ret); return ret; } static int hclge_alloc_tqps(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hclge_comm_tqp *tqp; int i; hdev->htqp = devm_kcalloc(&hdev->pdev->dev, hdev->num_tqps, sizeof(struct hclge_comm_tqp), GFP_KERNEL); if (!hdev->htqp) return -ENOMEM; tqp = hdev->htqp; for (i = 0; i < hdev->num_tqps; i++) { tqp->dev = &hdev->pdev->dev; tqp->index = i; tqp->q.ae_algo = &ae_algo; tqp->q.buf_size = hdev->rx_buf_len; tqp->q.tx_desc_num = hdev->num_tx_desc; tqp->q.rx_desc_num = hdev->num_rx_desc; /* need an extended offset to configure queues >= * HCLGE_TQP_MAX_SIZE_DEV_V2 */ if (i < HCLGE_TQP_MAX_SIZE_DEV_V2) tqp->q.io_base = hdev->hw.hw.io_base + HCLGE_TQP_REG_OFFSET + i * HCLGE_TQP_REG_SIZE; else tqp->q.io_base = hdev->hw.hw.io_base + HCLGE_TQP_REG_OFFSET + HCLGE_TQP_EXT_REG_OFFSET + (i - HCLGE_TQP_MAX_SIZE_DEV_V2) * HCLGE_TQP_REG_SIZE; /* when device supports tx push and has device memory, * the queue can execute push mode or doorbell mode on * device memory. */ if (test_bit(HNAE3_DEV_SUPPORT_TX_PUSH_B, ae_dev->caps)) tqp->q.mem_base = hdev->hw.hw.mem_base + HCLGE_TQP_MEM_OFFSET(hdev, i); tqp++; } return 0; } static int hclge_map_tqps_to_func(struct hclge_dev *hdev, u16 func_id, u16 tqp_pid, u16 tqp_vid, bool is_pf) { struct hclge_tqp_map_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SET_TQP_MAP, false); req = (struct hclge_tqp_map_cmd *)desc.data; req->tqp_id = cpu_to_le16(tqp_pid); req->tqp_vf = func_id; req->tqp_flag = 1U << HCLGE_TQP_MAP_EN_B; if (!is_pf) req->tqp_flag |= 1U << HCLGE_TQP_MAP_TYPE_B; req->tqp_vid = cpu_to_le16(tqp_vid); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "TQP map failed %d.\n", ret); return ret; } static int hclge_assign_tqp(struct hclge_vport *vport, u16 num_tqps) { struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; struct hclge_dev *hdev = vport->back; int i, alloced; for (i = 0, alloced = 0; i < hdev->num_tqps && alloced < num_tqps; i++) { if (!hdev->htqp[i].alloced) { hdev->htqp[i].q.handle = &vport->nic; hdev->htqp[i].q.tqp_index = alloced; hdev->htqp[i].q.tx_desc_num = kinfo->num_tx_desc; hdev->htqp[i].q.rx_desc_num = kinfo->num_rx_desc; kinfo->tqp[alloced] = &hdev->htqp[i].q; hdev->htqp[i].alloced = true; alloced++; } } vport->alloc_tqps = alloced; kinfo->rss_size = min_t(u16, hdev->pf_rss_size_max, vport->alloc_tqps / hdev->tm_info.num_tc); /* ensure one to one mapping between irq and queue at default */ kinfo->rss_size = min_t(u16, kinfo->rss_size, (hdev->num_nic_msi - 1) / hdev->tm_info.num_tc); return 0; } static int hclge_knic_setup(struct hclge_vport *vport, u16 num_tqps, u16 num_tx_desc, u16 num_rx_desc) { struct hnae3_handle *nic = &vport->nic; struct hnae3_knic_private_info *kinfo = &nic->kinfo; struct hclge_dev *hdev = vport->back; int ret; kinfo->num_tx_desc = num_tx_desc; kinfo->num_rx_desc = num_rx_desc; kinfo->rx_buf_len = hdev->rx_buf_len; kinfo->tx_spare_buf_size = hdev->tx_spare_buf_size; kinfo->tqp = devm_kcalloc(&hdev->pdev->dev, num_tqps, sizeof(struct hnae3_queue *), GFP_KERNEL); if (!kinfo->tqp) return -ENOMEM; ret = hclge_assign_tqp(vport, num_tqps); if (ret) dev_err(&hdev->pdev->dev, "fail to assign TQPs %d.\n", ret); return ret; } static int hclge_map_tqp_to_vport(struct hclge_dev *hdev, struct hclge_vport *vport) { struct hnae3_handle *nic = &vport->nic; struct hnae3_knic_private_info *kinfo; u16 i; kinfo = &nic->kinfo; for (i = 0; i < vport->alloc_tqps; i++) { struct hclge_comm_tqp *q = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q); bool is_pf; int ret; is_pf = !(vport->vport_id); ret = hclge_map_tqps_to_func(hdev, vport->vport_id, q->index, i, is_pf); if (ret) return ret; } return 0; } static int hclge_map_tqp(struct hclge_dev *hdev) { struct hclge_vport *vport = hdev->vport; u16 i, num_vport; num_vport = hdev->num_req_vfs + 1; for (i = 0; i < num_vport; i++) { int ret; ret = hclge_map_tqp_to_vport(hdev, vport); if (ret) return ret; vport++; } return 0; } static int hclge_vport_setup(struct hclge_vport *vport, u16 num_tqps) { struct hnae3_handle *nic = &vport->nic; struct hclge_dev *hdev = vport->back; int ret; nic->pdev = hdev->pdev; nic->ae_algo = &ae_algo; bitmap_copy(nic->numa_node_mask.bits, hdev->numa_node_mask.bits, MAX_NUMNODES); nic->kinfo.io_base = hdev->hw.hw.io_base; ret = hclge_knic_setup(vport, num_tqps, hdev->num_tx_desc, hdev->num_rx_desc); if (ret) dev_err(&hdev->pdev->dev, "knic setup failed %d\n", ret); return ret; } static int hclge_alloc_vport(struct hclge_dev *hdev) { struct pci_dev *pdev = hdev->pdev; struct hclge_vport *vport; u32 tqp_main_vport; u32 tqp_per_vport; int num_vport, i; int ret; /* We need to alloc a vport for main NIC of PF */ num_vport = hdev->num_req_vfs + 1; if (hdev->num_tqps < num_vport) { dev_err(&hdev->pdev->dev, "tqps(%u) is less than vports(%d)", hdev->num_tqps, num_vport); return -EINVAL; } /* Alloc the same number of TQPs for every vport */ tqp_per_vport = hdev->num_tqps / num_vport; tqp_main_vport = tqp_per_vport + hdev->num_tqps % num_vport; vport = devm_kcalloc(&pdev->dev, num_vport, sizeof(struct hclge_vport), GFP_KERNEL); if (!vport) return -ENOMEM; hdev->vport = vport; hdev->num_alloc_vport = num_vport; if (IS_ENABLED(CONFIG_PCI_IOV)) hdev->num_alloc_vfs = hdev->num_req_vfs; for (i = 0; i < num_vport; i++) { vport->back = hdev; vport->vport_id = i; vport->vf_info.link_state = IFLA_VF_LINK_STATE_AUTO; vport->mps = HCLGE_MAC_DEFAULT_FRAME; vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE; vport->port_base_vlan_cfg.tbl_sta = true; vport->rxvlan_cfg.rx_vlan_offload_en = true; vport->req_vlan_fltr_en = true; INIT_LIST_HEAD(&vport->vlan_list); INIT_LIST_HEAD(&vport->uc_mac_list); INIT_LIST_HEAD(&vport->mc_mac_list); spin_lock_init(&vport->mac_list_lock); if (i == 0) ret = hclge_vport_setup(vport, tqp_main_vport); else ret = hclge_vport_setup(vport, tqp_per_vport); if (ret) { dev_err(&pdev->dev, "vport setup failed for vport %d, %d\n", i, ret); return ret; } vport++; } return 0; } static int hclge_cmd_alloc_tx_buff(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { /* TX buffer size is unit by 128 byte */ #define HCLGE_BUF_SIZE_UNIT_SHIFT 7 #define HCLGE_BUF_SIZE_UPDATE_EN_MSK BIT(15) struct hclge_tx_buff_alloc_cmd *req; struct hclge_desc desc; int ret; u8 i; req = (struct hclge_tx_buff_alloc_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_TX_BUFF_ALLOC, 0); for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { u32 buf_size = buf_alloc->priv_buf[i].tx_buf_size; req->tx_pkt_buff[i] = cpu_to_le16((buf_size >> HCLGE_BUF_SIZE_UNIT_SHIFT) | HCLGE_BUF_SIZE_UPDATE_EN_MSK); } ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "tx buffer alloc cmd failed %d.\n", ret); return ret; } static int hclge_tx_buffer_alloc(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { int ret = hclge_cmd_alloc_tx_buff(hdev, buf_alloc); if (ret) dev_err(&hdev->pdev->dev, "tx buffer alloc failed %d\n", ret); return ret; } static u32 hclge_get_tc_num(struct hclge_dev *hdev) { unsigned int i; u32 cnt = 0; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) if (hdev->hw_tc_map & BIT(i)) cnt++; return cnt; } /* Get the number of pfc enabled TCs, which have private buffer */ static int hclge_get_pfc_priv_num(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { struct hclge_priv_buf *priv; unsigned int i; int cnt = 0; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { priv = &buf_alloc->priv_buf[i]; if ((hdev->tm_info.hw_pfc_map & BIT(i)) && priv->enable) cnt++; } return cnt; } /* Get the number of pfc disabled TCs, which have private buffer */ static int hclge_get_no_pfc_priv_num(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { struct hclge_priv_buf *priv; unsigned int i; int cnt = 0; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { priv = &buf_alloc->priv_buf[i]; if (hdev->hw_tc_map & BIT(i) && !(hdev->tm_info.hw_pfc_map & BIT(i)) && priv->enable) cnt++; } return cnt; } static u32 hclge_get_rx_priv_buff_alloced(struct hclge_pkt_buf_alloc *buf_alloc) { struct hclge_priv_buf *priv; u32 rx_priv = 0; int i; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { priv = &buf_alloc->priv_buf[i]; if (priv->enable) rx_priv += priv->buf_size; } return rx_priv; } static u32 hclge_get_tx_buff_alloced(struct hclge_pkt_buf_alloc *buf_alloc) { u32 i, total_tx_size = 0; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) total_tx_size += buf_alloc->priv_buf[i].tx_buf_size; return total_tx_size; } static bool hclge_is_rx_buf_ok(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc, u32 rx_all) { u32 shared_buf_min, shared_buf_tc, shared_std, hi_thrd, lo_thrd; u32 tc_num = hclge_get_tc_num(hdev); u32 shared_buf, aligned_mps; u32 rx_priv; int i; aligned_mps = roundup(hdev->mps, HCLGE_BUF_SIZE_UNIT); if (hnae3_dev_dcb_supported(hdev)) shared_buf_min = HCLGE_BUF_MUL_BY * aligned_mps + hdev->dv_buf_size; else shared_buf_min = aligned_mps + HCLGE_NON_DCB_ADDITIONAL_BUF + hdev->dv_buf_size; shared_buf_tc = tc_num * aligned_mps + aligned_mps; shared_std = roundup(max_t(u32, shared_buf_min, shared_buf_tc), HCLGE_BUF_SIZE_UNIT); rx_priv = hclge_get_rx_priv_buff_alloced(buf_alloc); if (rx_all < rx_priv + shared_std) return false; shared_buf = rounddown(rx_all - rx_priv, HCLGE_BUF_SIZE_UNIT); buf_alloc->s_buf.buf_size = shared_buf; if (hnae3_dev_dcb_supported(hdev)) { buf_alloc->s_buf.self.high = shared_buf - hdev->dv_buf_size; buf_alloc->s_buf.self.low = buf_alloc->s_buf.self.high - roundup(aligned_mps / HCLGE_BUF_DIV_BY, HCLGE_BUF_SIZE_UNIT); } else { buf_alloc->s_buf.self.high = aligned_mps + HCLGE_NON_DCB_ADDITIONAL_BUF; buf_alloc->s_buf.self.low = aligned_mps; } if (hnae3_dev_dcb_supported(hdev)) { hi_thrd = shared_buf - hdev->dv_buf_size; if (tc_num <= NEED_RESERVE_TC_NUM) hi_thrd = hi_thrd * BUF_RESERVE_PERCENT / BUF_MAX_PERCENT; if (tc_num) hi_thrd = hi_thrd / tc_num; hi_thrd = max_t(u32, hi_thrd, HCLGE_BUF_MUL_BY * aligned_mps); hi_thrd = rounddown(hi_thrd, HCLGE_BUF_SIZE_UNIT); lo_thrd = hi_thrd - aligned_mps / HCLGE_BUF_DIV_BY; } else { hi_thrd = aligned_mps + HCLGE_NON_DCB_ADDITIONAL_BUF; lo_thrd = aligned_mps; } for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { buf_alloc->s_buf.tc_thrd[i].low = lo_thrd; buf_alloc->s_buf.tc_thrd[i].high = hi_thrd; } return true; } static int hclge_tx_buffer_calc(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { u32 i, total_size; total_size = hdev->pkt_buf_size; /* alloc tx buffer for all enabled tc */ for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i]; if (hdev->hw_tc_map & BIT(i)) { if (total_size < hdev->tx_buf_size) return -ENOMEM; priv->tx_buf_size = hdev->tx_buf_size; } else { priv->tx_buf_size = 0; } total_size -= priv->tx_buf_size; } return 0; } static bool hclge_rx_buf_calc_all(struct hclge_dev *hdev, bool max, struct hclge_pkt_buf_alloc *buf_alloc) { u32 rx_all = hdev->pkt_buf_size - hclge_get_tx_buff_alloced(buf_alloc); u32 aligned_mps = round_up(hdev->mps, HCLGE_BUF_SIZE_UNIT); unsigned int i; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i]; priv->enable = 0; priv->wl.low = 0; priv->wl.high = 0; priv->buf_size = 0; if (!(hdev->hw_tc_map & BIT(i))) continue; priv->enable = 1; if (hdev->tm_info.hw_pfc_map & BIT(i)) { priv->wl.low = max ? aligned_mps : HCLGE_BUF_SIZE_UNIT; priv->wl.high = roundup(priv->wl.low + aligned_mps, HCLGE_BUF_SIZE_UNIT); } else { priv->wl.low = 0; priv->wl.high = max ? (aligned_mps * HCLGE_BUF_MUL_BY) : aligned_mps; } priv->buf_size = priv->wl.high + hdev->dv_buf_size; } return hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all); } static bool hclge_drop_nopfc_buf_till_fit(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { u32 rx_all = hdev->pkt_buf_size - hclge_get_tx_buff_alloced(buf_alloc); int no_pfc_priv_num = hclge_get_no_pfc_priv_num(hdev, buf_alloc); int i; /* let the last to be cleared first */ for (i = HCLGE_MAX_TC_NUM - 1; i >= 0; i--) { struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i]; unsigned int mask = BIT((unsigned int)i); if (hdev->hw_tc_map & mask && !(hdev->tm_info.hw_pfc_map & mask)) { /* Clear the no pfc TC private buffer */ priv->wl.low = 0; priv->wl.high = 0; priv->buf_size = 0; priv->enable = 0; no_pfc_priv_num--; } if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all) || no_pfc_priv_num == 0) break; } return hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all); } static bool hclge_drop_pfc_buf_till_fit(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { u32 rx_all = hdev->pkt_buf_size - hclge_get_tx_buff_alloced(buf_alloc); int pfc_priv_num = hclge_get_pfc_priv_num(hdev, buf_alloc); int i; /* let the last to be cleared first */ for (i = HCLGE_MAX_TC_NUM - 1; i >= 0; i--) { struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i]; unsigned int mask = BIT((unsigned int)i); if (hdev->hw_tc_map & mask && hdev->tm_info.hw_pfc_map & mask) { /* Reduce the number of pfc TC with private buffer */ priv->wl.low = 0; priv->enable = 0; priv->wl.high = 0; priv->buf_size = 0; pfc_priv_num--; } if (hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all) || pfc_priv_num == 0) break; } return hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all); } static int hclge_only_alloc_priv_buff(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { #define COMPENSATE_BUFFER 0x3C00 #define COMPENSATE_HALF_MPS_NUM 5 #define PRIV_WL_GAP 0x1800 u32 rx_priv = hdev->pkt_buf_size - hclge_get_tx_buff_alloced(buf_alloc); u32 tc_num = hclge_get_tc_num(hdev); u32 half_mps = hdev->mps >> 1; u32 min_rx_priv; unsigned int i; if (tc_num) rx_priv = rx_priv / tc_num; if (tc_num <= NEED_RESERVE_TC_NUM) rx_priv = rx_priv * BUF_RESERVE_PERCENT / BUF_MAX_PERCENT; min_rx_priv = hdev->dv_buf_size + COMPENSATE_BUFFER + COMPENSATE_HALF_MPS_NUM * half_mps; min_rx_priv = round_up(min_rx_priv, HCLGE_BUF_SIZE_UNIT); rx_priv = round_down(rx_priv, HCLGE_BUF_SIZE_UNIT); if (rx_priv < min_rx_priv) return false; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i]; priv->enable = 0; priv->wl.low = 0; priv->wl.high = 0; priv->buf_size = 0; if (!(hdev->hw_tc_map & BIT(i))) continue; priv->enable = 1; priv->buf_size = rx_priv; priv->wl.high = rx_priv - hdev->dv_buf_size; priv->wl.low = priv->wl.high - PRIV_WL_GAP; } buf_alloc->s_buf.buf_size = 0; return true; } /* hclge_rx_buffer_calc: calculate the rx private buffer size for all TCs * @hdev: pointer to struct hclge_dev * @buf_alloc: pointer to buffer calculation data * @return: 0: calculate successful, negative: fail */ static int hclge_rx_buffer_calc(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { /* When DCB is not supported, rx private buffer is not allocated. */ if (!hnae3_dev_dcb_supported(hdev)) { u32 rx_all = hdev->pkt_buf_size; rx_all -= hclge_get_tx_buff_alloced(buf_alloc); if (!hclge_is_rx_buf_ok(hdev, buf_alloc, rx_all)) return -ENOMEM; return 0; } if (hclge_only_alloc_priv_buff(hdev, buf_alloc)) return 0; if (hclge_rx_buf_calc_all(hdev, true, buf_alloc)) return 0; /* try to decrease the buffer size */ if (hclge_rx_buf_calc_all(hdev, false, buf_alloc)) return 0; if (hclge_drop_nopfc_buf_till_fit(hdev, buf_alloc)) return 0; if (hclge_drop_pfc_buf_till_fit(hdev, buf_alloc)) return 0; return -ENOMEM; } static int hclge_rx_priv_buf_alloc(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { struct hclge_rx_priv_buff_cmd *req; struct hclge_desc desc; int ret; int i; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_PRIV_BUFF_ALLOC, false); req = (struct hclge_rx_priv_buff_cmd *)desc.data; /* Alloc private buffer TCs */ for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { struct hclge_priv_buf *priv = &buf_alloc->priv_buf[i]; req->buf_num[i] = cpu_to_le16(priv->buf_size >> HCLGE_BUF_UNIT_S); req->buf_num[i] |= cpu_to_le16(1 << HCLGE_TC0_PRI_BUF_EN_B); } req->shared_buf = cpu_to_le16((buf_alloc->s_buf.buf_size >> HCLGE_BUF_UNIT_S) | (1 << HCLGE_TC0_PRI_BUF_EN_B)); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "rx private buffer alloc cmd failed %d\n", ret); return ret; } static int hclge_rx_priv_wl_config(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { struct hclge_rx_priv_wl_buf *req; struct hclge_priv_buf *priv; struct hclge_desc desc[2]; int i, j; int ret; for (i = 0; i < 2; i++) { hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_RX_PRIV_WL_ALLOC, false); req = (struct hclge_rx_priv_wl_buf *)desc[i].data; /* The first descriptor set the NEXT bit to 1 */ if (i == 0) desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); else desc[i].flag &= ~cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); for (j = 0; j < HCLGE_TC_NUM_ONE_DESC; j++) { u32 idx = i * HCLGE_TC_NUM_ONE_DESC + j; priv = &buf_alloc->priv_buf[idx]; req->tc_wl[j].high = cpu_to_le16(priv->wl.high >> HCLGE_BUF_UNIT_S); req->tc_wl[j].high |= cpu_to_le16(BIT(HCLGE_RX_PRIV_EN_B)); req->tc_wl[j].low = cpu_to_le16(priv->wl.low >> HCLGE_BUF_UNIT_S); req->tc_wl[j].low |= cpu_to_le16(BIT(HCLGE_RX_PRIV_EN_B)); } } /* Send 2 descriptor at one time */ ret = hclge_cmd_send(&hdev->hw, desc, 2); if (ret) dev_err(&hdev->pdev->dev, "rx private waterline config cmd failed %d\n", ret); return ret; } static int hclge_common_thrd_config(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { struct hclge_shared_buf *s_buf = &buf_alloc->s_buf; struct hclge_rx_com_thrd *req; struct hclge_desc desc[2]; struct hclge_tc_thrd *tc; int i, j; int ret; for (i = 0; i < 2; i++) { hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_RX_COM_THRD_ALLOC, false); req = (struct hclge_rx_com_thrd *)&desc[i].data; /* The first descriptor set the NEXT bit to 1 */ if (i == 0) desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); else desc[i].flag &= ~cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); for (j = 0; j < HCLGE_TC_NUM_ONE_DESC; j++) { tc = &s_buf->tc_thrd[i * HCLGE_TC_NUM_ONE_DESC + j]; req->com_thrd[j].high = cpu_to_le16(tc->high >> HCLGE_BUF_UNIT_S); req->com_thrd[j].high |= cpu_to_le16(BIT(HCLGE_RX_PRIV_EN_B)); req->com_thrd[j].low = cpu_to_le16(tc->low >> HCLGE_BUF_UNIT_S); req->com_thrd[j].low |= cpu_to_le16(BIT(HCLGE_RX_PRIV_EN_B)); } } /* Send 2 descriptors at one time */ ret = hclge_cmd_send(&hdev->hw, desc, 2); if (ret) dev_err(&hdev->pdev->dev, "common threshold config cmd failed %d\n", ret); return ret; } static int hclge_common_wl_config(struct hclge_dev *hdev, struct hclge_pkt_buf_alloc *buf_alloc) { struct hclge_shared_buf *buf = &buf_alloc->s_buf; struct hclge_rx_com_wl *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RX_COM_WL_ALLOC, false); req = (struct hclge_rx_com_wl *)desc.data; req->com_wl.high = cpu_to_le16(buf->self.high >> HCLGE_BUF_UNIT_S); req->com_wl.high |= cpu_to_le16(BIT(HCLGE_RX_PRIV_EN_B)); req->com_wl.low = cpu_to_le16(buf->self.low >> HCLGE_BUF_UNIT_S); req->com_wl.low |= cpu_to_le16(BIT(HCLGE_RX_PRIV_EN_B)); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "common waterline config cmd failed %d\n", ret); return ret; } int hclge_buffer_alloc(struct hclge_dev *hdev) { struct hclge_pkt_buf_alloc *pkt_buf; int ret; pkt_buf = kzalloc(sizeof(*pkt_buf), GFP_KERNEL); if (!pkt_buf) return -ENOMEM; ret = hclge_tx_buffer_calc(hdev, pkt_buf); if (ret) { dev_err(&hdev->pdev->dev, "could not calc tx buffer size for all TCs %d\n", ret); goto out; } ret = hclge_tx_buffer_alloc(hdev, pkt_buf); if (ret) { dev_err(&hdev->pdev->dev, "could not alloc tx buffers %d\n", ret); goto out; } ret = hclge_rx_buffer_calc(hdev, pkt_buf); if (ret) { dev_err(&hdev->pdev->dev, "could not calc rx priv buffer size for all TCs %d\n", ret); goto out; } ret = hclge_rx_priv_buf_alloc(hdev, pkt_buf); if (ret) { dev_err(&hdev->pdev->dev, "could not alloc rx priv buffer %d\n", ret); goto out; } if (hnae3_dev_dcb_supported(hdev)) { ret = hclge_rx_priv_wl_config(hdev, pkt_buf); if (ret) { dev_err(&hdev->pdev->dev, "could not configure rx private waterline %d\n", ret); goto out; } ret = hclge_common_thrd_config(hdev, pkt_buf); if (ret) { dev_err(&hdev->pdev->dev, "could not configure common threshold %d\n", ret); goto out; } } ret = hclge_common_wl_config(hdev, pkt_buf); if (ret) dev_err(&hdev->pdev->dev, "could not configure common waterline %d\n", ret); out: kfree(pkt_buf); return ret; } static int hclge_init_roce_base_info(struct hclge_vport *vport) { struct hnae3_handle *roce = &vport->roce; struct hnae3_handle *nic = &vport->nic; struct hclge_dev *hdev = vport->back; roce->rinfo.num_vectors = vport->back->num_roce_msi; if (hdev->num_msi < hdev->num_nic_msi + hdev->num_roce_msi) return -EINVAL; roce->rinfo.base_vector = hdev->num_nic_msi; roce->rinfo.netdev = nic->kinfo.netdev; roce->rinfo.roce_io_base = hdev->hw.hw.io_base; roce->rinfo.roce_mem_base = hdev->hw.hw.mem_base; roce->pdev = nic->pdev; roce->ae_algo = nic->ae_algo; bitmap_copy(roce->numa_node_mask.bits, nic->numa_node_mask.bits, MAX_NUMNODES); return 0; } static int hclge_init_msi(struct hclge_dev *hdev) { struct pci_dev *pdev = hdev->pdev; int vectors; int i; vectors = pci_alloc_irq_vectors(pdev, HNAE3_MIN_VECTOR_NUM, hdev->num_msi, PCI_IRQ_MSI | PCI_IRQ_MSIX); if (vectors < 0) { dev_err(&pdev->dev, "failed(%d) to allocate MSI/MSI-X vectors\n", vectors); return vectors; } if (vectors < hdev->num_msi) dev_warn(&hdev->pdev->dev, "requested %u MSI/MSI-X, but allocated %d MSI/MSI-X\n", hdev->num_msi, vectors); hdev->num_msi = vectors; hdev->num_msi_left = vectors; hdev->vector_status = devm_kcalloc(&pdev->dev, hdev->num_msi, sizeof(u16), GFP_KERNEL); if (!hdev->vector_status) { pci_free_irq_vectors(pdev); return -ENOMEM; } for (i = 0; i < hdev->num_msi; i++) hdev->vector_status[i] = HCLGE_INVALID_VPORT; hdev->vector_irq = devm_kcalloc(&pdev->dev, hdev->num_msi, sizeof(int), GFP_KERNEL); if (!hdev->vector_irq) { pci_free_irq_vectors(pdev); return -ENOMEM; } return 0; } static u8 hclge_check_speed_dup(u8 duplex, int speed) { if (!(speed == HCLGE_MAC_SPEED_10M || speed == HCLGE_MAC_SPEED_100M)) duplex = HCLGE_MAC_FULL; return duplex; } static struct hclge_mac_speed_map hclge_mac_speed_map_to_fw[] = { {HCLGE_MAC_SPEED_10M, HCLGE_FW_MAC_SPEED_10M}, {HCLGE_MAC_SPEED_100M, HCLGE_FW_MAC_SPEED_100M}, {HCLGE_MAC_SPEED_1G, HCLGE_FW_MAC_SPEED_1G}, {HCLGE_MAC_SPEED_10G, HCLGE_FW_MAC_SPEED_10G}, {HCLGE_MAC_SPEED_25G, HCLGE_FW_MAC_SPEED_25G}, {HCLGE_MAC_SPEED_40G, HCLGE_FW_MAC_SPEED_40G}, {HCLGE_MAC_SPEED_50G, HCLGE_FW_MAC_SPEED_50G}, {HCLGE_MAC_SPEED_100G, HCLGE_FW_MAC_SPEED_100G}, {HCLGE_MAC_SPEED_200G, HCLGE_FW_MAC_SPEED_200G}, }; static int hclge_convert_to_fw_speed(u32 speed_drv, u32 *speed_fw) { u16 i; for (i = 0; i < ARRAY_SIZE(hclge_mac_speed_map_to_fw); i++) { if (hclge_mac_speed_map_to_fw[i].speed_drv == speed_drv) { *speed_fw = hclge_mac_speed_map_to_fw[i].speed_fw; return 0; } } return -EINVAL; } static int hclge_cfg_mac_speed_dup_hw(struct hclge_dev *hdev, int speed, u8 duplex, u8 lane_num) { struct hclge_config_mac_speed_dup_cmd *req; struct hclge_desc desc; u32 speed_fw; int ret; req = (struct hclge_config_mac_speed_dup_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_SPEED_DUP, false); if (duplex) hnae3_set_bit(req->speed_dup, HCLGE_CFG_DUPLEX_B, 1); ret = hclge_convert_to_fw_speed(speed, &speed_fw); if (ret) { dev_err(&hdev->pdev->dev, "invalid speed (%d)\n", speed); return ret; } hnae3_set_field(req->speed_dup, HCLGE_CFG_SPEED_M, HCLGE_CFG_SPEED_S, speed_fw); hnae3_set_bit(req->mac_change_fec_en, HCLGE_CFG_MAC_SPEED_CHANGE_EN_B, 1); req->lane_num = lane_num; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "mac speed/duplex config cmd failed %d.\n", ret); return ret; } return 0; } int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex, u8 lane_num) { struct hclge_mac *mac = &hdev->hw.mac; int ret; duplex = hclge_check_speed_dup(duplex, speed); if (!mac->support_autoneg && mac->speed == speed && mac->duplex == duplex && (mac->lane_num == lane_num || lane_num == 0)) return 0; ret = hclge_cfg_mac_speed_dup_hw(hdev, speed, duplex, lane_num); if (ret) return ret; hdev->hw.mac.speed = speed; hdev->hw.mac.duplex = duplex; if (!lane_num) hdev->hw.mac.lane_num = lane_num; return 0; } static int hclge_cfg_mac_speed_dup_h(struct hnae3_handle *handle, int speed, u8 duplex, u8 lane_num) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return hclge_cfg_mac_speed_dup(hdev, speed, duplex, lane_num); } static int hclge_set_autoneg_en(struct hclge_dev *hdev, bool enable) { struct hclge_config_auto_neg_cmd *req; struct hclge_desc desc; u32 flag = 0; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_AN_MODE, false); req = (struct hclge_config_auto_neg_cmd *)desc.data; if (enable) hnae3_set_bit(flag, HCLGE_MAC_CFG_AN_EN_B, 1U); req->cfg_an_cmd_flag = cpu_to_le32(flag); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "auto neg set cmd failed %d.\n", ret); return ret; } static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; if (!hdev->hw.mac.support_autoneg) { if (enable) { dev_err(&hdev->pdev->dev, "autoneg is not supported by current port\n"); return -EOPNOTSUPP; } else { return 0; } } return hclge_set_autoneg_en(hdev, enable); } static int hclge_get_autoneg(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct phy_device *phydev = hdev->hw.mac.phydev; if (phydev) return phydev->autoneg; return hdev->hw.mac.autoneg; } static int hclge_restart_autoneg(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int ret; dev_dbg(&hdev->pdev->dev, "restart autoneg\n"); ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT); if (ret) return ret; return hclge_notify_client(hdev, HNAE3_UP_CLIENT); } static int hclge_halt_autoneg(struct hnae3_handle *handle, bool halt) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; if (hdev->hw.mac.support_autoneg && hdev->hw.mac.autoneg) return hclge_set_autoneg_en(hdev, !halt); return 0; } static void hclge_parse_fec_stats_lanes(struct hclge_dev *hdev, struct hclge_desc *desc, u32 desc_len) { u32 lane_size = HCLGE_FEC_STATS_MAX_LANES * 2; u32 desc_index = 0; u32 data_index = 0; u32 i; for (i = 0; i < lane_size; i++) { if (data_index >= HCLGE_DESC_DATA_LEN) { desc_index++; data_index = 0; } if (desc_index >= desc_len) return; hdev->fec_stats.per_lanes[i] += le32_to_cpu(desc[desc_index].data[data_index]); data_index++; } } static void hclge_parse_fec_stats(struct hclge_dev *hdev, struct hclge_desc *desc, u32 desc_len) { struct hclge_query_fec_stats_cmd *req; req = (struct hclge_query_fec_stats_cmd *)desc[0].data; hdev->fec_stats.base_r_lane_num = req->base_r_lane_num; hdev->fec_stats.rs_corr_blocks += le32_to_cpu(req->rs_fec_corr_blocks); hdev->fec_stats.rs_uncorr_blocks += le32_to_cpu(req->rs_fec_uncorr_blocks); hdev->fec_stats.rs_error_blocks += le32_to_cpu(req->rs_fec_error_blocks); hdev->fec_stats.base_r_corr_blocks += le32_to_cpu(req->base_r_fec_corr_blocks); hdev->fec_stats.base_r_uncorr_blocks += le32_to_cpu(req->base_r_fec_uncorr_blocks); hclge_parse_fec_stats_lanes(hdev, &desc[1], desc_len - 1); } static int hclge_update_fec_stats_hw(struct hclge_dev *hdev) { struct hclge_desc desc[HCLGE_FEC_STATS_CMD_NUM]; int ret; u32 i; for (i = 0; i < HCLGE_FEC_STATS_CMD_NUM; i++) { hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_QUERY_FEC_STATS, true); if (i != (HCLGE_FEC_STATS_CMD_NUM - 1)) desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); } ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_FEC_STATS_CMD_NUM); if (ret) return ret; hclge_parse_fec_stats(hdev, desc, HCLGE_FEC_STATS_CMD_NUM); return 0; } static void hclge_update_fec_stats(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); int ret; if (!hnae3_ae_dev_fec_stats_supported(ae_dev) || test_and_set_bit(HCLGE_STATE_FEC_STATS_UPDATING, &hdev->state)) return; ret = hclge_update_fec_stats_hw(hdev); if (ret) dev_err(&hdev->pdev->dev, "failed to update fec stats, ret = %d\n", ret); clear_bit(HCLGE_STATE_FEC_STATS_UPDATING, &hdev->state); } static void hclge_get_fec_stats_total(struct hclge_dev *hdev, struct ethtool_fec_stats *fec_stats) { fec_stats->corrected_blocks.total = hdev->fec_stats.rs_corr_blocks; fec_stats->uncorrectable_blocks.total = hdev->fec_stats.rs_uncorr_blocks; } static void hclge_get_fec_stats_lanes(struct hclge_dev *hdev, struct ethtool_fec_stats *fec_stats) { u32 i; if (hdev->fec_stats.base_r_lane_num == 0 || hdev->fec_stats.base_r_lane_num > HCLGE_FEC_STATS_MAX_LANES) { dev_err(&hdev->pdev->dev, "fec stats lane number(%llu) is invalid\n", hdev->fec_stats.base_r_lane_num); return; } for (i = 0; i < hdev->fec_stats.base_r_lane_num; i++) { fec_stats->corrected_blocks.lanes[i] = hdev->fec_stats.base_r_corr_per_lanes[i]; fec_stats->uncorrectable_blocks.lanes[i] = hdev->fec_stats.base_r_uncorr_per_lanes[i]; } } static void hclge_comm_get_fec_stats(struct hclge_dev *hdev, struct ethtool_fec_stats *fec_stats) { u32 fec_mode = hdev->hw.mac.fec_mode; switch (fec_mode) { case BIT(HNAE3_FEC_RS): case BIT(HNAE3_FEC_LLRS): hclge_get_fec_stats_total(hdev, fec_stats); break; case BIT(HNAE3_FEC_BASER): hclge_get_fec_stats_lanes(hdev, fec_stats); break; default: dev_err(&hdev->pdev->dev, "fec stats is not supported by current fec mode(0x%x)\n", fec_mode); break; } } static void hclge_get_fec_stats(struct hnae3_handle *handle, struct ethtool_fec_stats *fec_stats) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u32 fec_mode = hdev->hw.mac.fec_mode; if (fec_mode == BIT(HNAE3_FEC_NONE) || fec_mode == BIT(HNAE3_FEC_AUTO) || fec_mode == BIT(HNAE3_FEC_USER_DEF)) return; hclge_update_fec_stats(hdev); hclge_comm_get_fec_stats(hdev, fec_stats); } static int hclge_set_fec_hw(struct hclge_dev *hdev, u32 fec_mode) { struct hclge_config_fec_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_FEC_MODE, false); req = (struct hclge_config_fec_cmd *)desc.data; if (fec_mode & BIT(HNAE3_FEC_AUTO)) hnae3_set_bit(req->fec_mode, HCLGE_MAC_CFG_FEC_AUTO_EN_B, 1); if (fec_mode & BIT(HNAE3_FEC_RS)) hnae3_set_field(req->fec_mode, HCLGE_MAC_CFG_FEC_MODE_M, HCLGE_MAC_CFG_FEC_MODE_S, HCLGE_MAC_FEC_RS); if (fec_mode & BIT(HNAE3_FEC_LLRS)) hnae3_set_field(req->fec_mode, HCLGE_MAC_CFG_FEC_MODE_M, HCLGE_MAC_CFG_FEC_MODE_S, HCLGE_MAC_FEC_LLRS); if (fec_mode & BIT(HNAE3_FEC_BASER)) hnae3_set_field(req->fec_mode, HCLGE_MAC_CFG_FEC_MODE_M, HCLGE_MAC_CFG_FEC_MODE_S, HCLGE_MAC_FEC_BASER); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "set fec mode failed %d.\n", ret); return ret; } static int hclge_set_fec(struct hnae3_handle *handle, u32 fec_mode) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_mac *mac = &hdev->hw.mac; int ret; if (fec_mode && !(mac->fec_ability & fec_mode)) { dev_err(&hdev->pdev->dev, "unsupported fec mode\n"); return -EINVAL; } ret = hclge_set_fec_hw(hdev, fec_mode); if (ret) return ret; mac->user_fec_mode = fec_mode | BIT(HNAE3_FEC_USER_DEF); return 0; } static void hclge_get_fec(struct hnae3_handle *handle, u8 *fec_ability, u8 *fec_mode) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_mac *mac = &hdev->hw.mac; if (fec_ability) *fec_ability = mac->fec_ability; if (fec_mode) *fec_mode = mac->fec_mode; } static int hclge_mac_init(struct hclge_dev *hdev) { struct hclge_mac *mac = &hdev->hw.mac; int ret; hdev->support_sfp_query = true; if (!test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) hdev->hw.mac.duplex = HCLGE_MAC_FULL; ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed, hdev->hw.mac.duplex, hdev->hw.mac.lane_num); if (ret) return ret; if (hdev->hw.mac.support_autoneg) { ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.autoneg); if (ret) return ret; } mac->link = 0; if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) { ret = hclge_set_fec_hw(hdev, mac->user_fec_mode); if (ret) return ret; } ret = hclge_set_mac_mtu(hdev, hdev->mps); if (ret) { dev_err(&hdev->pdev->dev, "set mtu failed ret=%d\n", ret); return ret; } ret = hclge_set_default_loopback(hdev); if (ret) return ret; ret = hclge_buffer_alloc(hdev); if (ret) dev_err(&hdev->pdev->dev, "allocate buffer fail, ret=%d\n", ret); return ret; } static void hclge_mbx_task_schedule(struct hclge_dev *hdev) { if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) && !test_and_set_bit(HCLGE_STATE_MBX_SERVICE_SCHED, &hdev->state)) { hdev->last_mbx_scheduled = jiffies; mod_delayed_work(hclge_wq, &hdev->service_task, 0); } } static void hclge_reset_task_schedule(struct hclge_dev *hdev) { if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) && test_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state) && !test_and_set_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state)) { hdev->last_rst_scheduled = jiffies; mod_delayed_work(hclge_wq, &hdev->service_task, 0); } } static void hclge_errhand_task_schedule(struct hclge_dev *hdev) { if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) && !test_and_set_bit(HCLGE_STATE_ERR_SERVICE_SCHED, &hdev->state)) mod_delayed_work(hclge_wq, &hdev->service_task, 0); } void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time) { if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) && !test_bit(HCLGE_STATE_RST_FAIL, &hdev->state)) mod_delayed_work(hclge_wq, &hdev->service_task, delay_time); } static int hclge_get_mac_link_status(struct hclge_dev *hdev, int *link_status) { struct hclge_link_status_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_LINK_STATUS, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "get link status cmd failed %d\n", ret); return ret; } req = (struct hclge_link_status_cmd *)desc.data; *link_status = (req->status & HCLGE_LINK_STATUS_UP_M) > 0 ? HCLGE_LINK_STATUS_UP : HCLGE_LINK_STATUS_DOWN; return 0; } static int hclge_get_mac_phy_link(struct hclge_dev *hdev, int *link_status) { struct phy_device *phydev = hdev->hw.mac.phydev; *link_status = HCLGE_LINK_STATUS_DOWN; if (test_bit(HCLGE_STATE_DOWN, &hdev->state)) return 0; if (phydev && (phydev->state != PHY_RUNNING || !phydev->link)) return 0; return hclge_get_mac_link_status(hdev, link_status); } static void hclge_push_link_status(struct hclge_dev *hdev) { struct hclge_vport *vport; int ret; u16 i; for (i = 0; i < pci_num_vf(hdev->pdev); i++) { vport = &hdev->vport[i + HCLGE_VF_VPORT_START_NUM]; if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state) || vport->vf_info.link_state != IFLA_VF_LINK_STATE_AUTO) continue; ret = hclge_push_vf_link_status(vport); if (ret) { dev_err(&hdev->pdev->dev, "failed to push link status to vf%u, ret = %d\n", i, ret); } } } static void hclge_update_link_status(struct hclge_dev *hdev) { struct hnae3_handle *handle = &hdev->vport[0].nic; struct hnae3_client *client = hdev->nic_client; int state; int ret; if (!client) return; if (test_and_set_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state)) return; ret = hclge_get_mac_phy_link(hdev, &state); if (ret) { clear_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state); return; } if (state != hdev->hw.mac.link) { hdev->hw.mac.link = state; if (state == HCLGE_LINK_STATUS_UP) hclge_update_port_info(hdev); client->ops->link_status_change(handle, state); hclge_config_mac_tnl_int(hdev, state); if (test_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state)) { struct hnae3_handle *rhandle = &hdev->vport[0].roce; struct hnae3_client *rclient = hdev->roce_client; if (rclient && rclient->ops->link_status_change) rclient->ops->link_status_change(rhandle, state); } hclge_push_link_status(hdev); } clear_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state); } static void hclge_update_speed_advertising(struct hclge_mac *mac) { u32 speed_ability; if (hclge_get_speed_bit(mac->speed, &speed_ability)) return; switch (mac->module_type) { case HNAE3_MODULE_TYPE_FIBRE_LR: hclge_convert_setting_lr(speed_ability, mac->advertising); break; case HNAE3_MODULE_TYPE_FIBRE_SR: case HNAE3_MODULE_TYPE_AOC: hclge_convert_setting_sr(speed_ability, mac->advertising); break; case HNAE3_MODULE_TYPE_CR: hclge_convert_setting_cr(speed_ability, mac->advertising); break; case HNAE3_MODULE_TYPE_KR: hclge_convert_setting_kr(speed_ability, mac->advertising); break; default: break; } } static void hclge_update_fec_advertising(struct hclge_mac *mac) { if (mac->fec_mode & BIT(HNAE3_FEC_RS)) linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT, mac->advertising); else if (mac->fec_mode & BIT(HNAE3_FEC_LLRS)) linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT, mac->advertising); else if (mac->fec_mode & BIT(HNAE3_FEC_BASER)) linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT, mac->advertising); else linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->advertising); } static void hclge_update_pause_advertising(struct hclge_dev *hdev) { struct hclge_mac *mac = &hdev->hw.mac; bool rx_en, tx_en; switch (hdev->fc_mode_last_time) { case HCLGE_FC_RX_PAUSE: rx_en = true; tx_en = false; break; case HCLGE_FC_TX_PAUSE: rx_en = false; tx_en = true; break; case HCLGE_FC_FULL: rx_en = true; tx_en = true; break; default: rx_en = false; tx_en = false; break; } linkmode_set_pause(mac->advertising, tx_en, rx_en); } static void hclge_update_advertising(struct hclge_dev *hdev) { struct hclge_mac *mac = &hdev->hw.mac; linkmode_zero(mac->advertising); hclge_update_speed_advertising(mac); hclge_update_fec_advertising(mac); hclge_update_pause_advertising(hdev); } static void hclge_update_port_capability(struct hclge_dev *hdev, struct hclge_mac *mac) { if (hnae3_dev_fec_supported(hdev)) hclge_convert_setting_fec(mac); /* firmware can not identify back plane type, the media type * read from configuration can help deal it */ if (mac->media_type == HNAE3_MEDIA_TYPE_BACKPLANE && mac->module_type == HNAE3_MODULE_TYPE_UNKNOWN) mac->module_type = HNAE3_MODULE_TYPE_KR; else if (mac->media_type == HNAE3_MEDIA_TYPE_COPPER) mac->module_type = HNAE3_MODULE_TYPE_TP; if (mac->support_autoneg) { linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mac->supported); linkmode_copy(mac->advertising, mac->supported); } else { linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mac->supported); hclge_update_advertising(hdev); } } static int hclge_get_sfp_speed(struct hclge_dev *hdev, u32 *speed) { struct hclge_sfp_info_cmd *resp; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_INFO, true); resp = (struct hclge_sfp_info_cmd *)desc.data; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret == -EOPNOTSUPP) { dev_warn(&hdev->pdev->dev, "IMP do not support get SFP speed %d\n", ret); return ret; } else if (ret) { dev_err(&hdev->pdev->dev, "get sfp speed failed %d\n", ret); return ret; } *speed = le32_to_cpu(resp->speed); return 0; } static int hclge_get_sfp_info(struct hclge_dev *hdev, struct hclge_mac *mac) { struct hclge_sfp_info_cmd *resp; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_INFO, true); resp = (struct hclge_sfp_info_cmd *)desc.data; resp->query_type = QUERY_ACTIVE_SPEED; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret == -EOPNOTSUPP) { dev_warn(&hdev->pdev->dev, "IMP does not support get SFP info %d\n", ret); return ret; } else if (ret) { dev_err(&hdev->pdev->dev, "get sfp info failed %d\n", ret); return ret; } /* In some case, mac speed get from IMP may be 0, it shouldn't be * set to mac->speed. */ if (!le32_to_cpu(resp->speed)) return 0; mac->speed = le32_to_cpu(resp->speed); /* if resp->speed_ability is 0, it means it's an old version * firmware, do not update these params */ if (resp->speed_ability) { mac->module_type = le32_to_cpu(resp->module_type); mac->speed_ability = le32_to_cpu(resp->speed_ability); mac->autoneg = resp->autoneg; mac->support_autoneg = resp->autoneg_ability; mac->speed_type = QUERY_ACTIVE_SPEED; mac->lane_num = resp->lane_num; if (!resp->active_fec) mac->fec_mode = 0; else mac->fec_mode = BIT(resp->active_fec); mac->fec_ability = resp->fec_ability; } else { mac->speed_type = QUERY_SFP_SPEED; } return 0; } static int hclge_get_phy_link_ksettings(struct hnae3_handle *handle, struct ethtool_link_ksettings *cmd) { struct hclge_desc desc[HCLGE_PHY_LINK_SETTING_BD_NUM]; struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_phy_link_ksetting_0_cmd *req0; struct hclge_phy_link_ksetting_1_cmd *req1; u32 supported, advertising, lp_advertising; struct hclge_dev *hdev = vport->back; int ret; hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_PHY_LINK_KSETTING, true); desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_PHY_LINK_KSETTING, true); ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_PHY_LINK_SETTING_BD_NUM); if (ret) { dev_err(&hdev->pdev->dev, "failed to get phy link ksetting, ret = %d.\n", ret); return ret; } req0 = (struct hclge_phy_link_ksetting_0_cmd *)desc[0].data; cmd->base.autoneg = req0->autoneg; cmd->base.speed = le32_to_cpu(req0->speed); cmd->base.duplex = req0->duplex; cmd->base.port = req0->port; cmd->base.transceiver = req0->transceiver; cmd->base.phy_address = req0->phy_address; cmd->base.eth_tp_mdix = req0->eth_tp_mdix; cmd->base.eth_tp_mdix_ctrl = req0->eth_tp_mdix_ctrl; supported = le32_to_cpu(req0->supported); advertising = le32_to_cpu(req0->advertising); lp_advertising = le32_to_cpu(req0->lp_advertising); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, supported); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, advertising); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, lp_advertising); req1 = (struct hclge_phy_link_ksetting_1_cmd *)desc[1].data; cmd->base.master_slave_cfg = req1->master_slave_cfg; cmd->base.master_slave_state = req1->master_slave_state; return 0; } static int hclge_set_phy_link_ksettings(struct hnae3_handle *handle, const struct ethtool_link_ksettings *cmd) { struct hclge_desc desc[HCLGE_PHY_LINK_SETTING_BD_NUM]; struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_phy_link_ksetting_0_cmd *req0; struct hclge_phy_link_ksetting_1_cmd *req1; struct hclge_dev *hdev = vport->back; u32 advertising; int ret; if (cmd->base.autoneg == AUTONEG_DISABLE && ((cmd->base.speed != SPEED_100 && cmd->base.speed != SPEED_10) || (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL))) return -EINVAL; hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_PHY_LINK_KSETTING, false); desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_PHY_LINK_KSETTING, false); req0 = (struct hclge_phy_link_ksetting_0_cmd *)desc[0].data; req0->autoneg = cmd->base.autoneg; req0->speed = cpu_to_le32(cmd->base.speed); req0->duplex = cmd->base.duplex; ethtool_convert_link_mode_to_legacy_u32(&advertising, cmd->link_modes.advertising); req0->advertising = cpu_to_le32(advertising); req0->eth_tp_mdix_ctrl = cmd->base.eth_tp_mdix_ctrl; req1 = (struct hclge_phy_link_ksetting_1_cmd *)desc[1].data; req1->master_slave_cfg = cmd->base.master_slave_cfg; ret = hclge_cmd_send(&hdev->hw, desc, HCLGE_PHY_LINK_SETTING_BD_NUM); if (ret) { dev_err(&hdev->pdev->dev, "failed to set phy link ksettings, ret = %d.\n", ret); return ret; } hdev->hw.mac.req_autoneg = cmd->base.autoneg; hdev->hw.mac.req_speed = cmd->base.speed; hdev->hw.mac.req_duplex = cmd->base.duplex; linkmode_copy(hdev->hw.mac.advertising, cmd->link_modes.advertising); return 0; } static int hclge_update_tp_port_info(struct hclge_dev *hdev) { struct ethtool_link_ksettings cmd; int ret; if (!hnae3_dev_phy_imp_supported(hdev)) return 0; ret = hclge_get_phy_link_ksettings(&hdev->vport->nic, &cmd); if (ret) return ret; hdev->hw.mac.autoneg = cmd.base.autoneg; hdev->hw.mac.speed = cmd.base.speed; hdev->hw.mac.duplex = cmd.base.duplex; linkmode_copy(hdev->hw.mac.advertising, cmd.link_modes.advertising); return 0; } static int hclge_tp_port_init(struct hclge_dev *hdev) { struct ethtool_link_ksettings cmd; if (!hnae3_dev_phy_imp_supported(hdev)) return 0; cmd.base.autoneg = hdev->hw.mac.req_autoneg; cmd.base.speed = hdev->hw.mac.req_speed; cmd.base.duplex = hdev->hw.mac.req_duplex; linkmode_copy(cmd.link_modes.advertising, hdev->hw.mac.advertising); return hclge_set_phy_link_ksettings(&hdev->vport->nic, &cmd); } static int hclge_update_port_info(struct hclge_dev *hdev) { struct hclge_mac *mac = &hdev->hw.mac; int speed; int ret; /* get the port info from SFP cmd if not copper port */ if (mac->media_type == HNAE3_MEDIA_TYPE_COPPER) return hclge_update_tp_port_info(hdev); /* if IMP does not support get SFP/qSFP info, return directly */ if (!hdev->support_sfp_query) return 0; if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) { speed = mac->speed; ret = hclge_get_sfp_info(hdev, mac); } else { speed = HCLGE_MAC_SPEED_UNKNOWN; ret = hclge_get_sfp_speed(hdev, &speed); } if (ret == -EOPNOTSUPP) { hdev->support_sfp_query = false; return ret; } else if (ret) { return ret; } if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) { if (mac->speed_type == QUERY_ACTIVE_SPEED) { hclge_update_port_capability(hdev, mac); if (mac->speed != speed) (void)hclge_tm_port_shaper_cfg(hdev); return 0; } return hclge_cfg_mac_speed_dup(hdev, mac->speed, HCLGE_MAC_FULL, mac->lane_num); } else { if (speed == HCLGE_MAC_SPEED_UNKNOWN) return 0; /* do nothing if no SFP */ /* must config full duplex for SFP */ return hclge_cfg_mac_speed_dup(hdev, speed, HCLGE_MAC_FULL, 0); } } static int hclge_get_status(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; hclge_update_link_status(hdev); return hdev->hw.mac.link; } struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf) { if (!pci_num_vf(hdev->pdev)) { dev_err(&hdev->pdev->dev, "SRIOV is disabled, can not get vport(%d) info.\n", vf); return NULL; } if (vf < 0 || vf >= pci_num_vf(hdev->pdev)) { dev_err(&hdev->pdev->dev, "vf id(%d) is out of range(0 <= vfid < %d)\n", vf, pci_num_vf(hdev->pdev)); return NULL; } /* VF start from 1 in vport */ vf += HCLGE_VF_VPORT_START_NUM; return &hdev->vport[vf]; } static int hclge_get_vf_config(struct hnae3_handle *handle, int vf, struct ifla_vf_info *ivf) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; vport = hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; ivf->vf = vf; ivf->linkstate = vport->vf_info.link_state; ivf->spoofchk = vport->vf_info.spoofchk; ivf->trusted = vport->vf_info.trusted; ivf->min_tx_rate = 0; ivf->max_tx_rate = vport->vf_info.max_tx_rate; ivf->vlan = vport->port_base_vlan_cfg.vlan_info.vlan_tag; ivf->vlan_proto = htons(vport->port_base_vlan_cfg.vlan_info.vlan_proto); ivf->qos = vport->port_base_vlan_cfg.vlan_info.qos; ether_addr_copy(ivf->mac, vport->vf_info.mac); return 0; } static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf, int link_state) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int link_state_old; int ret; vport = hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; link_state_old = vport->vf_info.link_state; vport->vf_info.link_state = link_state; /* return success directly if the VF is unalive, VF will * query link state itself when it starts work. */ if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) return 0; ret = hclge_push_vf_link_status(vport); if (ret) { vport->vf_info.link_state = link_state_old; dev_err(&hdev->pdev->dev, "failed to push vf%d link status, ret = %d\n", vf, ret); } return ret; } static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) { u32 cmdq_src_reg, msix_src_reg, hw_err_src_reg; /* fetch the events from their corresponding regs */ cmdq_src_reg = hclge_read_dev(&hdev->hw, HCLGE_VECTOR0_CMDQ_SRC_REG); msix_src_reg = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS); hw_err_src_reg = hclge_read_dev(&hdev->hw, HCLGE_RAS_PF_OTHER_INT_STS_REG); /* Assumption: If by any chance reset and mailbox events are reported * together then we will only process reset event in this go and will * defer the processing of the mailbox events. Since, we would have not * cleared RX CMDQ event this time we would receive again another * interrupt from H/W just for the mailbox. * * check for vector0 reset event sources */ if (BIT(HCLGE_VECTOR0_IMPRESET_INT_B) & msix_src_reg) { dev_info(&hdev->pdev->dev, "IMP reset interrupt\n"); set_bit(HNAE3_IMP_RESET, &hdev->reset_pending); set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state); *clearval = BIT(HCLGE_VECTOR0_IMPRESET_INT_B); hdev->rst_stats.imp_rst_cnt++; return HCLGE_VECTOR0_EVENT_RST; } if (BIT(HCLGE_VECTOR0_GLOBALRESET_INT_B) & msix_src_reg) { dev_info(&hdev->pdev->dev, "global reset interrupt\n"); set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state); set_bit(HNAE3_GLOBAL_RESET, &hdev->reset_pending); *clearval = BIT(HCLGE_VECTOR0_GLOBALRESET_INT_B); hdev->rst_stats.global_rst_cnt++; return HCLGE_VECTOR0_EVENT_RST; } /* check for vector0 msix event and hardware error event source */ if (msix_src_reg & HCLGE_VECTOR0_REG_MSIX_MASK || hw_err_src_reg & HCLGE_RAS_REG_ERR_MASK) return HCLGE_VECTOR0_EVENT_ERR; /* check for vector0 ptp event source */ if (BIT(HCLGE_VECTOR0_REG_PTP_INT_B) & msix_src_reg) { *clearval = msix_src_reg; return HCLGE_VECTOR0_EVENT_PTP; } /* check for vector0 mailbox(=CMDQ RX) event source */ if (BIT(HCLGE_VECTOR0_RX_CMDQ_INT_B) & cmdq_src_reg) { cmdq_src_reg &= ~BIT(HCLGE_VECTOR0_RX_CMDQ_INT_B); *clearval = cmdq_src_reg; return HCLGE_VECTOR0_EVENT_MBX; } /* print other vector0 event source */ dev_info(&hdev->pdev->dev, "INT status: CMDQ(%#x) HW errors(%#x) other(%#x)\n", cmdq_src_reg, hw_err_src_reg, msix_src_reg); return HCLGE_VECTOR0_EVENT_OTHER; } static void hclge_clear_event_cause(struct hclge_dev *hdev, u32 event_type, u32 regclr) { #define HCLGE_IMP_RESET_DELAY 5 switch (event_type) { case HCLGE_VECTOR0_EVENT_PTP: case HCLGE_VECTOR0_EVENT_RST: if (regclr == BIT(HCLGE_VECTOR0_IMPRESET_INT_B)) mdelay(HCLGE_IMP_RESET_DELAY); hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, regclr); break; case HCLGE_VECTOR0_EVENT_MBX: hclge_write_dev(&hdev->hw, HCLGE_VECTOR0_CMDQ_SRC_REG, regclr); break; default: break; } } static void hclge_clear_all_event_cause(struct hclge_dev *hdev) { hclge_clear_event_cause(hdev, HCLGE_VECTOR0_EVENT_RST, BIT(HCLGE_VECTOR0_GLOBALRESET_INT_B) | BIT(HCLGE_VECTOR0_CORERESET_INT_B) | BIT(HCLGE_VECTOR0_IMPRESET_INT_B)); hclge_clear_event_cause(hdev, HCLGE_VECTOR0_EVENT_MBX, 0); } static void hclge_enable_vector(struct hclge_misc_vector *vector, bool enable) { writel(enable ? 1 : 0, vector->addr); } static irqreturn_t hclge_misc_irq_handle(int irq, void *data) { struct hclge_dev *hdev = data; unsigned long flags; u32 clearval = 0; u32 event_cause; hclge_enable_vector(&hdev->misc_vector, false); event_cause = hclge_check_event_cause(hdev, &clearval); /* vector 0 interrupt is shared with reset and mailbox source events. */ switch (event_cause) { case HCLGE_VECTOR0_EVENT_ERR: hclge_errhand_task_schedule(hdev); break; case HCLGE_VECTOR0_EVENT_RST: hclge_reset_task_schedule(hdev); break; case HCLGE_VECTOR0_EVENT_PTP: spin_lock_irqsave(&hdev->ptp->lock, flags); hclge_ptp_clean_tx_hwts(hdev); spin_unlock_irqrestore(&hdev->ptp->lock, flags); break; case HCLGE_VECTOR0_EVENT_MBX: /* If we are here then, * 1. Either we are not handling any mbx task and we are not * scheduled as well * OR * 2. We could be handling a mbx task but nothing more is * scheduled. * In both cases, we should schedule mbx task as there are more * mbx messages reported by this interrupt. */ hclge_mbx_task_schedule(hdev); break; default: dev_warn(&hdev->pdev->dev, "received unknown or unhandled event of vector0\n"); break; } hclge_clear_event_cause(hdev, event_cause, clearval); /* Enable interrupt if it is not caused by reset event or error event */ if (event_cause == HCLGE_VECTOR0_EVENT_PTP || event_cause == HCLGE_VECTOR0_EVENT_MBX || event_cause == HCLGE_VECTOR0_EVENT_OTHER) hclge_enable_vector(&hdev->misc_vector, true); return IRQ_HANDLED; } static void hclge_free_vector(struct hclge_dev *hdev, int vector_id) { if (hdev->vector_status[vector_id] == HCLGE_INVALID_VPORT) { dev_warn(&hdev->pdev->dev, "vector(vector_id %d) has been freed.\n", vector_id); return; } hdev->vector_status[vector_id] = HCLGE_INVALID_VPORT; hdev->num_msi_left += 1; hdev->num_msi_used -= 1; } static void hclge_get_misc_vector(struct hclge_dev *hdev) { struct hclge_misc_vector *vector = &hdev->misc_vector; vector->vector_irq = pci_irq_vector(hdev->pdev, 0); vector->addr = hdev->hw.hw.io_base + HCLGE_MISC_VECTOR_REG_BASE; hdev->vector_status[0] = 0; hdev->num_msi_left -= 1; hdev->num_msi_used += 1; } static int hclge_misc_irq_init(struct hclge_dev *hdev) { int ret; hclge_get_misc_vector(hdev); /* this would be explicitly freed in the end */ snprintf(hdev->misc_vector.name, HNAE3_INT_NAME_LEN, "%s-misc-%s", HCLGE_NAME, pci_name(hdev->pdev)); ret = request_irq(hdev->misc_vector.vector_irq, hclge_misc_irq_handle, 0, hdev->misc_vector.name, hdev); if (ret) { hclge_free_vector(hdev, 0); dev_err(&hdev->pdev->dev, "request misc irq(%d) fail\n", hdev->misc_vector.vector_irq); } return ret; } static void hclge_misc_irq_uninit(struct hclge_dev *hdev) { free_irq(hdev->misc_vector.vector_irq, hdev); hclge_free_vector(hdev, 0); } int hclge_notify_client(struct hclge_dev *hdev, enum hnae3_reset_notify_type type) { struct hnae3_handle *handle = &hdev->vport[0].nic; struct hnae3_client *client = hdev->nic_client; int ret; if (!test_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state) || !client) return 0; if (!client->ops->reset_notify) return -EOPNOTSUPP; ret = client->ops->reset_notify(handle, type); if (ret) dev_err(&hdev->pdev->dev, "notify nic client failed %d(%d)\n", type, ret); return ret; } static int hclge_notify_roce_client(struct hclge_dev *hdev, enum hnae3_reset_notify_type type) { struct hnae3_handle *handle = &hdev->vport[0].roce; struct hnae3_client *client = hdev->roce_client; int ret; if (!test_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state) || !client) return 0; if (!client->ops->reset_notify) return -EOPNOTSUPP; ret = client->ops->reset_notify(handle, type); if (ret) dev_err(&hdev->pdev->dev, "notify roce client failed %d(%d)", type, ret); return ret; } static int hclge_reset_wait(struct hclge_dev *hdev) { #define HCLGE_RESET_WATI_MS 100 #define HCLGE_RESET_WAIT_CNT 350 u32 val, reg, reg_bit; u32 cnt = 0; switch (hdev->reset_type) { case HNAE3_IMP_RESET: reg = HCLGE_GLOBAL_RESET_REG; reg_bit = HCLGE_IMP_RESET_BIT; break; case HNAE3_GLOBAL_RESET: reg = HCLGE_GLOBAL_RESET_REG; reg_bit = HCLGE_GLOBAL_RESET_BIT; break; case HNAE3_FUNC_RESET: reg = HCLGE_FUN_RST_ING; reg_bit = HCLGE_FUN_RST_ING_B; break; default: dev_err(&hdev->pdev->dev, "Wait for unsupported reset type: %d\n", hdev->reset_type); return -EINVAL; } val = hclge_read_dev(&hdev->hw, reg); while (hnae3_get_bit(val, reg_bit) && cnt < HCLGE_RESET_WAIT_CNT) { msleep(HCLGE_RESET_WATI_MS); val = hclge_read_dev(&hdev->hw, reg); cnt++; } if (cnt >= HCLGE_RESET_WAIT_CNT) { dev_warn(&hdev->pdev->dev, "Wait for reset timeout: %d\n", hdev->reset_type); return -EBUSY; } return 0; } static int hclge_set_vf_rst(struct hclge_dev *hdev, int func_id, bool reset) { struct hclge_vf_rst_cmd *req; struct hclge_desc desc; req = (struct hclge_vf_rst_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GBL_RST_STATUS, false); req->dest_vfid = func_id; if (reset) req->vf_rst = 0x1; return hclge_cmd_send(&hdev->hw, &desc, 1); } static int hclge_set_all_vf_rst(struct hclge_dev *hdev, bool reset) { int i; for (i = HCLGE_VF_VPORT_START_NUM; i < hdev->num_alloc_vport; i++) { struct hclge_vport *vport = &hdev->vport[i]; int ret; /* Send cmd to set/clear VF's FUNC_RST_ING */ ret = hclge_set_vf_rst(hdev, vport->vport_id, reset); if (ret) { dev_err(&hdev->pdev->dev, "set vf(%u) rst failed %d!\n", vport->vport_id - HCLGE_VF_VPORT_START_NUM, ret); return ret; } if (!reset || !test_bit(HCLGE_VPORT_STATE_INITED, &vport->state)) continue; if (!test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state) && hdev->reset_type == HNAE3_FUNC_RESET) { set_bit(HCLGE_VPORT_NEED_NOTIFY_RESET, &vport->need_notify); continue; } /* Inform VF to process the reset. * hclge_inform_reset_assert_to_vf may fail if VF * driver is not loaded. */ ret = hclge_inform_reset_assert_to_vf(vport); if (ret) dev_warn(&hdev->pdev->dev, "inform reset to vf(%u) failed %d!\n", vport->vport_id - HCLGE_VF_VPORT_START_NUM, ret); } return 0; } static void hclge_mailbox_service_task(struct hclge_dev *hdev) { if (!test_and_clear_bit(HCLGE_STATE_MBX_SERVICE_SCHED, &hdev->state) || test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state) || test_and_set_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state)) return; if (time_is_before_jiffies(hdev->last_mbx_scheduled + HCLGE_MBX_SCHED_TIMEOUT)) dev_warn(&hdev->pdev->dev, "mbx service task is scheduled after %ums on cpu%u!\n", jiffies_to_msecs(jiffies - hdev->last_mbx_scheduled), smp_processor_id()); hclge_mbx_handler(hdev); clear_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state); } static void hclge_func_reset_sync_vf(struct hclge_dev *hdev) { struct hclge_pf_rst_sync_cmd *req; struct hclge_desc desc; int cnt = 0; int ret; req = (struct hclge_pf_rst_sync_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_VF_RST_RDY, true); do { /* vf need to down netdev by mbx during PF or FLR reset */ hclge_mailbox_service_task(hdev); ret = hclge_cmd_send(&hdev->hw, &desc, 1); /* for compatible with old firmware, wait * 100 ms for VF to stop IO */ if (ret == -EOPNOTSUPP) { msleep(HCLGE_RESET_SYNC_TIME); return; } else if (ret) { dev_warn(&hdev->pdev->dev, "sync with VF fail %d!\n", ret); return; } else if (req->all_vf_ready) { return; } msleep(HCLGE_PF_RESET_SYNC_TIME); hclge_comm_cmd_reuse_desc(&desc, true); } while (cnt++ < HCLGE_PF_RESET_SYNC_CNT); dev_warn(&hdev->pdev->dev, "sync with VF timeout!\n"); } void hclge_report_hw_error(struct hclge_dev *hdev, enum hnae3_hw_error_type type) { struct hnae3_client *client = hdev->nic_client; if (!client || !client->ops->process_hw_error || !test_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state)) return; client->ops->process_hw_error(&hdev->vport[0].nic, type); } static void hclge_handle_imp_error(struct hclge_dev *hdev) { u32 reg_val; reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG); if (reg_val & BIT(HCLGE_VECTOR0_IMP_RD_POISON_B)) { hclge_report_hw_error(hdev, HNAE3_IMP_RD_POISON_ERROR); reg_val &= ~BIT(HCLGE_VECTOR0_IMP_RD_POISON_B); hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); } if (reg_val & BIT(HCLGE_VECTOR0_IMP_CMDQ_ERR_B)) { hclge_report_hw_error(hdev, HNAE3_CMDQ_ECC_ERROR); reg_val &= ~BIT(HCLGE_VECTOR0_IMP_CMDQ_ERR_B); hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, reg_val); } } int hclge_func_reset_cmd(struct hclge_dev *hdev, int func_id) { struct hclge_desc desc; struct hclge_reset_cmd *req = (struct hclge_reset_cmd *)desc.data; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_RST_TRIGGER, false); hnae3_set_bit(req->mac_func_reset, HCLGE_CFG_RESET_FUNC_B, 1); req->fun_reset_vfid = func_id; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "send function reset cmd fail, status =%d\n", ret); return ret; } static void hclge_do_reset(struct hclge_dev *hdev) { struct hnae3_handle *handle = &hdev->vport[0].nic; struct pci_dev *pdev = hdev->pdev; u32 val; if (hclge_get_hw_reset_stat(handle)) { dev_info(&pdev->dev, "hardware reset not finish\n"); dev_info(&pdev->dev, "func_rst_reg:0x%x, global_rst_reg:0x%x\n", hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING), hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG)); return; } switch (hdev->reset_type) { case HNAE3_IMP_RESET: dev_info(&pdev->dev, "IMP reset requested\n"); val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG); hnae3_set_bit(val, HCLGE_TRIGGER_IMP_RESET_B, 1); hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, val); break; case HNAE3_GLOBAL_RESET: dev_info(&pdev->dev, "global reset requested\n"); val = hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG); hnae3_set_bit(val, HCLGE_GLOBAL_RESET_BIT, 1); hclge_write_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG, val); break; case HNAE3_FUNC_RESET: dev_info(&pdev->dev, "PF reset requested\n"); /* schedule again to check later */ set_bit(HNAE3_FUNC_RESET, &hdev->reset_pending); hclge_reset_task_schedule(hdev); break; default: dev_warn(&pdev->dev, "unsupported reset type: %d\n", hdev->reset_type); break; } } static enum hnae3_reset_type hclge_get_reset_level(struct hnae3_ae_dev *ae_dev, unsigned long *addr) { enum hnae3_reset_type rst_level = HNAE3_NONE_RESET; struct hclge_dev *hdev = ae_dev->priv; /* return the highest priority reset level amongst all */ if (test_bit(HNAE3_IMP_RESET, addr)) { rst_level = HNAE3_IMP_RESET; clear_bit(HNAE3_IMP_RESET, addr); clear_bit(HNAE3_GLOBAL_RESET, addr); clear_bit(HNAE3_FUNC_RESET, addr); } else if (test_bit(HNAE3_GLOBAL_RESET, addr)) { rst_level = HNAE3_GLOBAL_RESET; clear_bit(HNAE3_GLOBAL_RESET, addr); clear_bit(HNAE3_FUNC_RESET, addr); } else if (test_bit(HNAE3_FUNC_RESET, addr)) { rst_level = HNAE3_FUNC_RESET; clear_bit(HNAE3_FUNC_RESET, addr); } else if (test_bit(HNAE3_FLR_RESET, addr)) { rst_level = HNAE3_FLR_RESET; clear_bit(HNAE3_FLR_RESET, addr); } if (hdev->reset_type != HNAE3_NONE_RESET && rst_level < hdev->reset_type) return HNAE3_NONE_RESET; return rst_level; } static void hclge_clear_reset_cause(struct hclge_dev *hdev) { u32 clearval = 0; switch (hdev->reset_type) { case HNAE3_IMP_RESET: clearval = BIT(HCLGE_VECTOR0_IMPRESET_INT_B); break; case HNAE3_GLOBAL_RESET: clearval = BIT(HCLGE_VECTOR0_GLOBALRESET_INT_B); break; default: break; } if (!clearval) return; /* For revision 0x20, the reset interrupt source * can only be cleared after hardware reset done */ if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, clearval); hclge_enable_vector(&hdev->misc_vector, true); } static void hclge_reset_handshake(struct hclge_dev *hdev, bool enable) { u32 reg_val; reg_val = hclge_read_dev(&hdev->hw, HCLGE_COMM_NIC_CSQ_DEPTH_REG); if (enable) reg_val |= HCLGE_COMM_NIC_SW_RST_RDY; else reg_val &= ~HCLGE_COMM_NIC_SW_RST_RDY; hclge_write_dev(&hdev->hw, HCLGE_COMM_NIC_CSQ_DEPTH_REG, reg_val); } static int hclge_func_reset_notify_vf(struct hclge_dev *hdev) { int ret; ret = hclge_set_all_vf_rst(hdev, true); if (ret) return ret; hclge_func_reset_sync_vf(hdev); return 0; } static int hclge_reset_prepare_wait(struct hclge_dev *hdev) { u32 reg_val; int ret = 0; switch (hdev->reset_type) { case HNAE3_FUNC_RESET: ret = hclge_func_reset_notify_vf(hdev); if (ret) return ret; ret = hclge_func_reset_cmd(hdev, 0); if (ret) { dev_err(&hdev->pdev->dev, "asserting function reset fail %d!\n", ret); return ret; } /* After performaning pf reset, it is not necessary to do the * mailbox handling or send any command to firmware, because * any mailbox handling or command to firmware is only valid * after hclge_comm_cmd_init is called. */ set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state); hdev->rst_stats.pf_rst_cnt++; break; case HNAE3_FLR_RESET: ret = hclge_func_reset_notify_vf(hdev); if (ret) return ret; break; case HNAE3_IMP_RESET: hclge_handle_imp_error(hdev); reg_val = hclge_read_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG); hclge_write_dev(&hdev->hw, HCLGE_PF_OTHER_INT_REG, BIT(HCLGE_VECTOR0_IMP_RESET_INT_B) | reg_val); break; default: break; } /* inform hardware that preparatory work is done */ msleep(HCLGE_RESET_SYNC_TIME); hclge_reset_handshake(hdev, true); dev_info(&hdev->pdev->dev, "prepare wait ok\n"); return ret; } static void hclge_show_rst_info(struct hclge_dev *hdev) { char *buf; buf = kzalloc(HCLGE_DBG_RESET_INFO_LEN, GFP_KERNEL); if (!buf) return; hclge_dbg_dump_rst_info(hdev, buf, HCLGE_DBG_RESET_INFO_LEN); dev_info(&hdev->pdev->dev, "dump reset info:\n%s", buf); kfree(buf); } static bool hclge_reset_err_handle(struct hclge_dev *hdev) { #define MAX_RESET_FAIL_CNT 5 if (hdev->reset_pending) { dev_info(&hdev->pdev->dev, "Reset pending %lu\n", hdev->reset_pending); return true; } else if (hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS) & HCLGE_RESET_INT_M) { dev_info(&hdev->pdev->dev, "reset failed because new reset interrupt\n"); hclge_clear_reset_cause(hdev); return false; } else if (hdev->rst_stats.reset_fail_cnt < MAX_RESET_FAIL_CNT) { hdev->rst_stats.reset_fail_cnt++; set_bit(hdev->reset_type, &hdev->reset_pending); dev_info(&hdev->pdev->dev, "re-schedule reset task(%u)\n", hdev->rst_stats.reset_fail_cnt); return true; } hclge_clear_reset_cause(hdev); /* recover the handshake status when reset fail */ hclge_reset_handshake(hdev, true); dev_err(&hdev->pdev->dev, "Reset fail!\n"); hclge_show_rst_info(hdev); set_bit(HCLGE_STATE_RST_FAIL, &hdev->state); return false; } static void hclge_update_reset_level(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); enum hnae3_reset_type reset_level; /* reset request will not be set during reset, so clear * pending reset request to avoid unnecessary reset * caused by the same reason. */ hclge_get_reset_level(ae_dev, &hdev->reset_request); /* if default_reset_request has a higher level reset request, * it should be handled as soon as possible. since some errors * need this kind of reset to fix. */ reset_level = hclge_get_reset_level(ae_dev, &hdev->default_reset_request); if (reset_level != HNAE3_NONE_RESET) set_bit(reset_level, &hdev->reset_request); } static int hclge_set_rst_done(struct hclge_dev *hdev) { struct hclge_pf_rst_done_cmd *req; struct hclge_desc desc; int ret; req = (struct hclge_pf_rst_done_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PF_RST_DONE, false); req->pf_rst_done |= HCLGE_PF_RESET_DONE_BIT; ret = hclge_cmd_send(&hdev->hw, &desc, 1); /* To be compatible with the old firmware, which does not support * command HCLGE_OPC_PF_RST_DONE, just print a warning and * return success */ if (ret == -EOPNOTSUPP) { dev_warn(&hdev->pdev->dev, "current firmware does not support command(0x%x)!\n", HCLGE_OPC_PF_RST_DONE); return 0; } else if (ret) { dev_err(&hdev->pdev->dev, "assert PF reset done fail %d!\n", ret); } return ret; } static int hclge_reset_prepare_up(struct hclge_dev *hdev) { int ret = 0; switch (hdev->reset_type) { case HNAE3_FUNC_RESET: case HNAE3_FLR_RESET: ret = hclge_set_all_vf_rst(hdev, false); break; case HNAE3_GLOBAL_RESET: case HNAE3_IMP_RESET: ret = hclge_set_rst_done(hdev); break; default: break; } /* clear up the handshake status after re-initialize done */ hclge_reset_handshake(hdev, false); return ret; } static int hclge_reset_stack(struct hclge_dev *hdev) { int ret; ret = hclge_notify_client(hdev, HNAE3_UNINIT_CLIENT); if (ret) return ret; ret = hclge_reset_ae_dev(hdev->ae_dev); if (ret) return ret; return hclge_notify_client(hdev, HNAE3_INIT_CLIENT); } static int hclge_reset_prepare(struct hclge_dev *hdev) { int ret; hdev->rst_stats.reset_cnt++; /* perform reset of the stack & ae device for a client */ ret = hclge_notify_roce_client(hdev, HNAE3_DOWN_CLIENT); if (ret) return ret; rtnl_lock(); ret = hclge_notify_client(hdev, HNAE3_DOWN_CLIENT); rtnl_unlock(); if (ret) return ret; return hclge_reset_prepare_wait(hdev); } static int hclge_reset_rebuild(struct hclge_dev *hdev) { int ret; hdev->rst_stats.hw_reset_done_cnt++; ret = hclge_notify_roce_client(hdev, HNAE3_UNINIT_CLIENT); if (ret) return ret; rtnl_lock(); ret = hclge_reset_stack(hdev); rtnl_unlock(); if (ret) return ret; hclge_clear_reset_cause(hdev); ret = hclge_notify_roce_client(hdev, HNAE3_INIT_CLIENT); /* ignore RoCE notify error if it fails HCLGE_RESET_MAX_FAIL_CNT - 1 * times */ if (ret && hdev->rst_stats.reset_fail_cnt < HCLGE_RESET_MAX_FAIL_CNT - 1) return ret; ret = hclge_reset_prepare_up(hdev); if (ret) return ret; rtnl_lock(); ret = hclge_notify_client(hdev, HNAE3_UP_CLIENT); rtnl_unlock(); if (ret) return ret; ret = hclge_notify_roce_client(hdev, HNAE3_UP_CLIENT); if (ret) return ret; hdev->last_reset_time = jiffies; hdev->rst_stats.reset_fail_cnt = 0; hdev->rst_stats.reset_done_cnt++; clear_bit(HCLGE_STATE_RST_FAIL, &hdev->state); hclge_update_reset_level(hdev); return 0; } static void hclge_reset(struct hclge_dev *hdev) { if (hclge_reset_prepare(hdev)) goto err_reset; if (hclge_reset_wait(hdev)) goto err_reset; if (hclge_reset_rebuild(hdev)) goto err_reset; return; err_reset: if (hclge_reset_err_handle(hdev)) hclge_reset_task_schedule(hdev); } static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev); struct hclge_dev *hdev = ae_dev->priv; /* We might end up getting called broadly because of 2 below cases: * 1. Recoverable error was conveyed through APEI and only way to bring * normalcy is to reset. * 2. A new reset request from the stack due to timeout * * check if this is a new reset request and we are not here just because * last reset attempt did not succeed and watchdog hit us again. We will * know this if last reset request did not occur very recently (watchdog * timer = 5*HZ, let us check after sufficiently large time, say 4*5*Hz) * In case of new request we reset the "reset level" to PF reset. * And if it is a repeat reset request of the most recent one then we * want to make sure we throttle the reset request. Therefore, we will * not allow it again before 3*HZ times. */ if (time_before(jiffies, (hdev->last_reset_time + HCLGE_RESET_INTERVAL))) { mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL); return; } if (hdev->default_reset_request) { hdev->reset_level = hclge_get_reset_level(ae_dev, &hdev->default_reset_request); } else if (time_after(jiffies, (hdev->last_reset_time + 4 * 5 * HZ))) { hdev->reset_level = HNAE3_FUNC_RESET; } dev_info(&hdev->pdev->dev, "received reset event, reset type is %d\n", hdev->reset_level); /* request reset & schedule reset task */ set_bit(hdev->reset_level, &hdev->reset_request); hclge_reset_task_schedule(hdev); if (hdev->reset_level < HNAE3_GLOBAL_RESET) hdev->reset_level++; } static void hclge_set_def_reset_request(struct hnae3_ae_dev *ae_dev, enum hnae3_reset_type rst_type) { struct hclge_dev *hdev = ae_dev->priv; set_bit(rst_type, &hdev->default_reset_request); } static void hclge_reset_timer(struct timer_list *t) { struct hclge_dev *hdev = from_timer(hdev, t, reset_timer); /* if default_reset_request has no value, it means that this reset * request has already be handled, so just return here */ if (!hdev->default_reset_request) return; dev_info(&hdev->pdev->dev, "triggering reset in reset timer\n"); hclge_reset_event(hdev->pdev, NULL); } static void hclge_reset_subtask(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); /* check if there is any ongoing reset in the hardware. This status can * be checked from reset_pending. If there is then, we need to wait for * hardware to complete reset. * a. If we are able to figure out in reasonable time that hardware * has fully resetted then, we can proceed with driver, client * reset. * b. else, we can come back later to check this status so re-sched * now. */ hdev->last_reset_time = jiffies; hdev->reset_type = hclge_get_reset_level(ae_dev, &hdev->reset_pending); if (hdev->reset_type != HNAE3_NONE_RESET) hclge_reset(hdev); /* check if we got any *new* reset requests to be honored */ hdev->reset_type = hclge_get_reset_level(ae_dev, &hdev->reset_request); if (hdev->reset_type != HNAE3_NONE_RESET) hclge_do_reset(hdev); hdev->reset_type = HNAE3_NONE_RESET; } static void hclge_handle_err_reset_request(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); enum hnae3_reset_type reset_type; if (ae_dev->hw_err_reset_req) { reset_type = hclge_get_reset_level(ae_dev, &ae_dev->hw_err_reset_req); hclge_set_def_reset_request(ae_dev, reset_type); } if (hdev->default_reset_request && ae_dev->ops->reset_event) ae_dev->ops->reset_event(hdev->pdev, NULL); /* enable interrupt after error handling complete */ hclge_enable_vector(&hdev->misc_vector, true); } static void hclge_handle_err_recovery(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); ae_dev->hw_err_reset_req = 0; if (hclge_find_error_source(hdev)) { hclge_handle_error_info_log(ae_dev); hclge_handle_mac_tnl(hdev); hclge_handle_vf_queue_err_ras(hdev); } hclge_handle_err_reset_request(hdev); } static void hclge_misc_err_recovery(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct device *dev = &hdev->pdev->dev; u32 msix_sts_reg; msix_sts_reg = hclge_read_dev(&hdev->hw, HCLGE_MISC_VECTOR_INT_STS); if (msix_sts_reg & HCLGE_VECTOR0_REG_MSIX_MASK) { if (hclge_handle_hw_msix_error (hdev, &hdev->default_reset_request)) dev_info(dev, "received msix interrupt 0x%x\n", msix_sts_reg); } hclge_handle_hw_ras_error(ae_dev); hclge_handle_err_reset_request(hdev); } static void hclge_errhand_service_task(struct hclge_dev *hdev) { if (!test_and_clear_bit(HCLGE_STATE_ERR_SERVICE_SCHED, &hdev->state)) return; if (hnae3_dev_ras_imp_supported(hdev)) hclge_handle_err_recovery(hdev); else hclge_misc_err_recovery(hdev); } static void hclge_reset_service_task(struct hclge_dev *hdev) { if (!test_and_clear_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state)) return; if (time_is_before_jiffies(hdev->last_rst_scheduled + HCLGE_RESET_SCHED_TIMEOUT)) dev_warn(&hdev->pdev->dev, "reset service task is scheduled after %ums on cpu%u!\n", jiffies_to_msecs(jiffies - hdev->last_rst_scheduled), smp_processor_id()); down(&hdev->reset_sem); set_bit(HCLGE_STATE_RST_HANDLING, &hdev->state); hclge_reset_subtask(hdev); clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state); up(&hdev->reset_sem); } static void hclge_update_vport_alive(struct hclge_dev *hdev) { #define HCLGE_ALIVE_SECONDS_NORMAL 8 unsigned long alive_time = HCLGE_ALIVE_SECONDS_NORMAL * HZ; int i; /* start from vport 1 for PF is always alive */ for (i = 1; i < hdev->num_alloc_vport; i++) { struct hclge_vport *vport = &hdev->vport[i]; if (!test_bit(HCLGE_VPORT_STATE_INITED, &vport->state) || !test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) continue; if (time_after(jiffies, vport->last_active_jiffies + alive_time)) { clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); dev_warn(&hdev->pdev->dev, "VF %u heartbeat timeout\n", i - HCLGE_VF_VPORT_START_NUM); } } } static void hclge_periodic_service_task(struct hclge_dev *hdev) { unsigned long delta = round_jiffies_relative(HZ); if (test_bit(HCLGE_STATE_RST_FAIL, &hdev->state)) return; /* Always handle the link updating to make sure link state is * updated when it is triggered by mbx. */ hclge_update_link_status(hdev); hclge_sync_mac_table(hdev); hclge_sync_promisc_mode(hdev); hclge_sync_fd_table(hdev); if (time_is_after_jiffies(hdev->last_serv_processed + HZ)) { delta = jiffies - hdev->last_serv_processed; if (delta < round_jiffies_relative(HZ)) { delta = round_jiffies_relative(HZ) - delta; goto out; } } hdev->serv_processed_cnt++; hclge_update_vport_alive(hdev); if (test_bit(HCLGE_STATE_DOWN, &hdev->state)) { hdev->last_serv_processed = jiffies; goto out; } if (!(hdev->serv_processed_cnt % HCLGE_STATS_TIMER_INTERVAL)) hclge_update_stats_for_all(hdev); hclge_update_port_info(hdev); hclge_sync_vlan_filter(hdev); if (!(hdev->serv_processed_cnt % HCLGE_ARFS_EXPIRE_INTERVAL)) hclge_rfs_filter_expire(hdev); hdev->last_serv_processed = jiffies; out: hclge_task_schedule(hdev, delta); } static void hclge_ptp_service_task(struct hclge_dev *hdev) { unsigned long flags; if (!test_bit(HCLGE_STATE_PTP_EN, &hdev->state) || !test_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state) || !time_is_before_jiffies(hdev->ptp->tx_start + HZ)) return; /* to prevent concurrence with the irq handler */ spin_lock_irqsave(&hdev->ptp->lock, flags); /* check HCLGE_STATE_PTP_TX_HANDLING here again, since the irq * handler may handle it just before spin_lock_irqsave(). */ if (test_bit(HCLGE_STATE_PTP_TX_HANDLING, &hdev->state)) hclge_ptp_clean_tx_hwts(hdev); spin_unlock_irqrestore(&hdev->ptp->lock, flags); } static void hclge_service_task(struct work_struct *work) { struct hclge_dev *hdev = container_of(work, struct hclge_dev, service_task.work); hclge_errhand_service_task(hdev); hclge_reset_service_task(hdev); hclge_ptp_service_task(hdev); hclge_mailbox_service_task(hdev); hclge_periodic_service_task(hdev); /* Handle error recovery, reset and mbx again in case periodical task * delays the handling by calling hclge_task_schedule() in * hclge_periodic_service_task(). */ hclge_errhand_service_task(hdev); hclge_reset_service_task(hdev); hclge_mailbox_service_task(hdev); } struct hclge_vport *hclge_get_vport(struct hnae3_handle *handle) { /* VF handle has no client */ if (!handle->client) 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 return container_of(handle, struct hclge_vport, nic); } static void hclge_get_vector_info(struct hclge_dev *hdev, u16 idx, struct hnae3_vector_info *vector_info) { #define HCLGE_PF_MAX_VECTOR_NUM_DEV_V2 64 vector_info->vector = pci_irq_vector(hdev->pdev, idx); /* need an extend offset to config vector >= 64 */ if (idx - 1 < HCLGE_PF_MAX_VECTOR_NUM_DEV_V2) vector_info->io_addr = hdev->hw.hw.io_base + HCLGE_VECTOR_REG_BASE + (idx - 1) * HCLGE_VECTOR_REG_OFFSET; else vector_info->io_addr = hdev->hw.hw.io_base + HCLGE_VECTOR_EXT_REG_BASE + (idx - 1) / HCLGE_PF_MAX_VECTOR_NUM_DEV_V2 * HCLGE_VECTOR_REG_OFFSET_H + (idx - 1) % HCLGE_PF_MAX_VECTOR_NUM_DEV_V2 * HCLGE_VECTOR_REG_OFFSET; hdev->vector_status[idx] = hdev->vport[0].vport_id; hdev->vector_irq[idx] = vector_info->vector; } static int hclge_get_vector(struct hnae3_handle *handle, u16 vector_num, struct hnae3_vector_info *vector_info) { struct hclge_vport *vport = hclge_get_vport(handle); struct hnae3_vector_info *vector = vector_info; struct hclge_dev *hdev = vport->back; int alloc = 0; u16 i = 0; u16 j; vector_num = min_t(u16, hdev->num_nic_msi - 1, vector_num); vector_num = min(hdev->num_msi_left, vector_num); for (j = 0; j < vector_num; j++) { while (++i < hdev->num_nic_msi) { if (hdev->vector_status[i] == HCLGE_INVALID_VPORT) { hclge_get_vector_info(hdev, i, vector); vector++; alloc++; break; } } } hdev->num_msi_left -= alloc; hdev->num_msi_used += alloc; return alloc; } static int hclge_get_vector_index(struct hclge_dev *hdev, int vector) { int i; for (i = 0; i < hdev->num_msi; i++) if (vector == hdev->vector_irq[i]) return i; return -EINVAL; } static int hclge_put_vector(struct hnae3_handle *handle, int vector) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int vector_id; vector_id = hclge_get_vector_index(hdev, vector); if (vector_id < 0) { dev_err(&hdev->pdev->dev, "Get vector index fail. vector = %d\n", vector); return vector_id; } hclge_free_vector(hdev, vector_id); return 0; } static int hclge_get_rss(struct hnae3_handle *handle, u32 *indir, u8 *key, u8 *hfunc) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_comm_rss_cfg *rss_cfg = &vport->back->rss_cfg; hclge_comm_get_rss_hash_info(rss_cfg, key, hfunc); hclge_comm_get_rss_indir_tbl(rss_cfg, indir, ae_dev->dev_specs.rss_ind_tbl_size); return 0; } static int hclge_set_rss(struct hnae3_handle *handle, const u32 *indir, const u8 *key, const u8 hfunc) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_comm_rss_cfg *rss_cfg = &hdev->rss_cfg; int ret, i; ret = hclge_comm_set_rss_hash_key(rss_cfg, &hdev->hw.hw, key, hfunc); if (ret) { dev_err(&hdev->pdev->dev, "invalid hfunc type %u\n", hfunc); return ret; } /* Update the shadow RSS table with user specified qids */ for (i = 0; i < ae_dev->dev_specs.rss_ind_tbl_size; i++) rss_cfg->rss_indirection_tbl[i] = indir[i]; /* Update the hardware */ return hclge_comm_set_rss_indir_table(ae_dev, &hdev->hw.hw, rss_cfg->rss_indirection_tbl); } static int hclge_set_rss_tuple(struct hnae3_handle *handle, struct ethtool_rxnfc *nfc) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int ret; ret = hclge_comm_set_rss_tuple(hdev->ae_dev, &hdev->hw.hw, &hdev->rss_cfg, nfc); if (ret) { dev_err(&hdev->pdev->dev, "failed to set rss tuple, ret = %d.\n", ret); return ret; } return 0; } static int hclge_get_rss_tuple(struct hnae3_handle *handle, struct ethtool_rxnfc *nfc) { struct hclge_vport *vport = hclge_get_vport(handle); u8 tuple_sets; int ret; nfc->data = 0; ret = hclge_comm_get_rss_tuple(&vport->back->rss_cfg, nfc->flow_type, &tuple_sets); if (ret || !tuple_sets) return ret; nfc->data = hclge_comm_convert_rss_tuple(tuple_sets); return 0; } static int hclge_get_tc_size(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return hdev->pf_rss_size_max; } static int hclge_init_rss_tc_mode(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = hdev->ae_dev; struct hclge_vport *vport = hdev->vport; u16 tc_offset[HCLGE_MAX_TC_NUM] = {0}; u16 tc_valid[HCLGE_MAX_TC_NUM] = {0}; u16 tc_size[HCLGE_MAX_TC_NUM] = {0}; struct hnae3_tc_info *tc_info; u16 roundup_size; u16 rss_size; int i; tc_info = &vport->nic.kinfo.tc_info; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { rss_size = tc_info->tqp_count[i]; tc_valid[i] = 0; if (!(hdev->hw_tc_map & BIT(i))) continue; /* tc_size set to hardware is the log2 of roundup power of two * of rss_size, the acutal queue size is limited by indirection * table. */ if (rss_size > ae_dev->dev_specs.rss_ind_tbl_size || rss_size == 0) { dev_err(&hdev->pdev->dev, "Configure rss tc size failed, invalid TC_SIZE = %u\n", rss_size); return -EINVAL; } roundup_size = roundup_pow_of_two(rss_size); roundup_size = ilog2(roundup_size); tc_valid[i] = 1; tc_size[i] = roundup_size; tc_offset[i] = tc_info->tqp_offset[i]; } return hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset, tc_valid, tc_size); } int hclge_rss_init_hw(struct hclge_dev *hdev) { u16 *rss_indir = hdev->rss_cfg.rss_indirection_tbl; u8 *key = hdev->rss_cfg.rss_hash_key; u8 hfunc = hdev->rss_cfg.rss_algo; int ret; ret = hclge_comm_set_rss_indir_table(hdev->ae_dev, &hdev->hw.hw, rss_indir); if (ret) return ret; ret = hclge_comm_set_rss_algo_key(&hdev->hw.hw, hfunc, key); if (ret) return ret; ret = hclge_comm_set_rss_input_tuple(&hdev->hw.hw, &hdev->rss_cfg); if (ret) return ret; return hclge_init_rss_tc_mode(hdev); } int hclge_bind_ring_with_vector(struct hclge_vport *vport, int vector_id, bool en, struct hnae3_ring_chain_node *ring_chain) { struct hclge_dev *hdev = vport->back; struct hnae3_ring_chain_node *node; struct hclge_desc desc; struct hclge_ctrl_vector_chain_cmd *req = (struct hclge_ctrl_vector_chain_cmd *)desc.data; enum hclge_comm_cmd_status status; enum hclge_opcode_type op; u16 tqp_type_and_id; int i; op = en ? HCLGE_OPC_ADD_RING_TO_VECTOR : HCLGE_OPC_DEL_RING_TO_VECTOR; hclge_cmd_setup_basic_desc(&desc, op, false); req->int_vector_id_l = hnae3_get_field(vector_id, HCLGE_VECTOR_ID_L_M, HCLGE_VECTOR_ID_L_S); req->int_vector_id_h = hnae3_get_field(vector_id, HCLGE_VECTOR_ID_H_M, HCLGE_VECTOR_ID_H_S); i = 0; for (node = ring_chain; node; node = node->next) { tqp_type_and_id = le16_to_cpu(req->tqp_type_and_id[i]); hnae3_set_field(tqp_type_and_id, HCLGE_INT_TYPE_M, HCLGE_INT_TYPE_S, hnae3_get_bit(node->flag, HNAE3_RING_TYPE_B)); hnae3_set_field(tqp_type_and_id, HCLGE_TQP_ID_M, HCLGE_TQP_ID_S, node->tqp_index); hnae3_set_field(tqp_type_and_id, HCLGE_INT_GL_IDX_M, HCLGE_INT_GL_IDX_S, hnae3_get_field(node->int_gl_idx, HNAE3_RING_GL_IDX_M, HNAE3_RING_GL_IDX_S)); req->tqp_type_and_id[i] = cpu_to_le16(tqp_type_and_id); if (++i >= HCLGE_VECTOR_ELEMENTS_PER_CMD) { req->int_cause_num = HCLGE_VECTOR_ELEMENTS_PER_CMD; req->vfid = vport->vport_id; status = hclge_cmd_send(&hdev->hw, &desc, 1); if (status) { dev_err(&hdev->pdev->dev, "Map TQP fail, status is %d.\n", status); return -EIO; } i = 0; hclge_cmd_setup_basic_desc(&desc, op, false); req->int_vector_id_l = hnae3_get_field(vector_id, HCLGE_VECTOR_ID_L_M, HCLGE_VECTOR_ID_L_S); req->int_vector_id_h = hnae3_get_field(vector_id, HCLGE_VECTOR_ID_H_M, HCLGE_VECTOR_ID_H_S); } } if (i > 0) { req->int_cause_num = i; req->vfid = vport->vport_id; status = hclge_cmd_send(&hdev->hw, &desc, 1); if (status) { dev_err(&hdev->pdev->dev, "Map TQP fail, status is %d.\n", status); return -EIO; } } return 0; } static int hclge_map_ring_to_vector(struct hnae3_handle *handle, int vector, struct hnae3_ring_chain_node *ring_chain) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int vector_id; vector_id = hclge_get_vector_index(hdev, vector); if (vector_id < 0) { dev_err(&hdev->pdev->dev, "failed to get vector index. vector=%d\n", vector); return vector_id; } return hclge_bind_ring_with_vector(vport, vector_id, true, ring_chain); } static int hclge_unmap_ring_frm_vector(struct hnae3_handle *handle, int vector, struct hnae3_ring_chain_node *ring_chain) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int vector_id, ret; if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) return 0; vector_id = hclge_get_vector_index(hdev, vector); if (vector_id < 0) { dev_err(&handle->pdev->dev, "Get vector index fail. ret =%d\n", vector_id); return vector_id; } ret = hclge_bind_ring_with_vector(vport, vector_id, false, ring_chain); if (ret) dev_err(&handle->pdev->dev, "Unmap ring from vector fail. vectorid=%d, ret =%d\n", vector_id, ret); return ret; } static int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev, u8 vf_id, bool en_uc, bool en_mc, bool en_bc) { struct hclge_vport *vport = &hdev->vport[vf_id]; struct hnae3_handle *handle = &vport->nic; struct hclge_promisc_cfg_cmd *req; struct hclge_desc desc; bool uc_tx_en = en_uc; u8 promisc_cfg = 0; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PROMISC_MODE, false); req = (struct hclge_promisc_cfg_cmd *)desc.data; req->vf_id = vf_id; if (test_bit(HNAE3_PFLAG_LIMIT_PROMISC, &handle->priv_flags)) uc_tx_en = false; hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_UC_RX_EN, en_uc ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_MC_RX_EN, en_mc ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_BC_RX_EN, en_bc ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_UC_TX_EN, uc_tx_en ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_MC_TX_EN, en_mc ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_BC_TX_EN, en_bc ? 1 : 0); req->extend_promisc = promisc_cfg; /* to be compatible with DEVICE_VERSION_V1/2 */ promisc_cfg = 0; hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_EN_UC, en_uc ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_EN_MC, en_mc ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_EN_BC, en_bc ? 1 : 0); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_TX_EN, 1); hnae3_set_bit(promisc_cfg, HCLGE_PROMISC_RX_EN, 1); req->promisc = promisc_cfg; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "failed to set vport %u promisc mode, ret = %d.\n", vf_id, ret); return ret; } int hclge_set_vport_promisc_mode(struct hclge_vport *vport, bool en_uc_pmc, bool en_mc_pmc, bool en_bc_pmc) { return hclge_cmd_set_promisc_mode(vport->back, vport->vport_id, en_uc_pmc, en_mc_pmc, en_bc_pmc); } static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc, bool en_mc_pmc) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; bool en_bc_pmc = true; /* For device whose version below V2, if broadcast promisc enabled, * vlan filter is always bypassed. So broadcast promisc should be * disabled until user enable promisc mode */ if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) en_bc_pmc = handle->netdev_flags & HNAE3_BPE ? true : false; return hclge_set_vport_promisc_mode(vport, en_uc_pmc, en_mc_pmc, en_bc_pmc); } static void hclge_request_update_promisc_mode(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); } static void hclge_sync_fd_state(struct hclge_dev *hdev) { if (hlist_empty(&hdev->fd_rule_list)) hdev->fd_active_type = HCLGE_FD_RULE_NONE; } static void hclge_fd_inc_rule_cnt(struct hclge_dev *hdev, u16 location) { if (!test_bit(location, hdev->fd_bmap)) { set_bit(location, hdev->fd_bmap); hdev->hclge_fd_rule_num++; } } static void hclge_fd_dec_rule_cnt(struct hclge_dev *hdev, u16 location) { if (test_bit(location, hdev->fd_bmap)) { clear_bit(location, hdev->fd_bmap); hdev->hclge_fd_rule_num--; } } static void hclge_fd_free_node(struct hclge_dev *hdev, struct hclge_fd_rule *rule) { hlist_del(&rule->rule_node); kfree(rule); hclge_sync_fd_state(hdev); } static void hclge_update_fd_rule_node(struct hclge_dev *hdev, struct hclge_fd_rule *old_rule, struct hclge_fd_rule *new_rule, enum HCLGE_FD_NODE_STATE state) { switch (state) { case HCLGE_FD_TO_ADD: case HCLGE_FD_ACTIVE: /* 1) if the new state is TO_ADD, just replace the old rule * with the same location, no matter its state, because the * new rule will be configured to the hardware. * 2) if the new state is ACTIVE, it means the new rule * has been configured to the hardware, so just replace * the old rule node with the same location. * 3) for it doesn't add a new node to the list, so it's * unnecessary to update the rule number and fd_bmap. */ new_rule->rule_node.next = old_rule->rule_node.next; new_rule->rule_node.pprev = old_rule->rule_node.pprev; memcpy(old_rule, new_rule, sizeof(*old_rule)); kfree(new_rule); break; case HCLGE_FD_DELETED: hclge_fd_dec_rule_cnt(hdev, old_rule->location); hclge_fd_free_node(hdev, old_rule); break; case HCLGE_FD_TO_DEL: /* if new request is TO_DEL, and old rule is existent * 1) the state of old rule is TO_DEL, we need do nothing, * because we delete rule by location, other rule content * is unncessary. * 2) the state of old rule is ACTIVE, we need to change its * state to TO_DEL, so the rule will be deleted when periodic * task being scheduled. * 3) the state of old rule is TO_ADD, it means the rule hasn't * been added to hardware, so we just delete the rule node from * fd_rule_list directly. */ if (old_rule->state == HCLGE_FD_TO_ADD) { hclge_fd_dec_rule_cnt(hdev, old_rule->location); hclge_fd_free_node(hdev, old_rule); return; } old_rule->state = HCLGE_FD_TO_DEL; break; } } static struct hclge_fd_rule *hclge_find_fd_rule(struct hlist_head *hlist, u16 location, struct hclge_fd_rule **parent) { struct hclge_fd_rule *rule; struct hlist_node *node; hlist_for_each_entry_safe(rule, node, hlist, rule_node) { if (rule->location == location) return rule; else if (rule->location > location) return NULL; /* record the parent node, use to keep the nodes in fd_rule_list * in ascend order. */ *parent = rule; } return NULL; } /* insert fd rule node in ascend order according to rule->location */ static void hclge_fd_insert_rule_node(struct hlist_head *hlist, struct hclge_fd_rule *rule, struct hclge_fd_rule *parent) { INIT_HLIST_NODE(&rule->rule_node); if (parent) hlist_add_behind(&rule->rule_node, &parent->rule_node); else hlist_add_head(&rule->rule_node, hlist); } static int hclge_fd_set_user_def_cmd(struct hclge_dev *hdev, struct hclge_fd_user_def_cfg *cfg) { struct hclge_fd_user_def_cfg_cmd *req; struct hclge_desc desc; u16 data = 0; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_USER_DEF_OP, false); req = (struct hclge_fd_user_def_cfg_cmd *)desc.data; hnae3_set_bit(data, HCLGE_FD_USER_DEF_EN_B, cfg[0].ref_cnt > 0); hnae3_set_field(data, HCLGE_FD_USER_DEF_OFT_M, HCLGE_FD_USER_DEF_OFT_S, cfg[0].offset); req->ol2_cfg = cpu_to_le16(data); data = 0; hnae3_set_bit(data, HCLGE_FD_USER_DEF_EN_B, cfg[1].ref_cnt > 0); hnae3_set_field(data, HCLGE_FD_USER_DEF_OFT_M, HCLGE_FD_USER_DEF_OFT_S, cfg[1].offset); req->ol3_cfg = cpu_to_le16(data); data = 0; hnae3_set_bit(data, HCLGE_FD_USER_DEF_EN_B, cfg[2].ref_cnt > 0); hnae3_set_field(data, HCLGE_FD_USER_DEF_OFT_M, HCLGE_FD_USER_DEF_OFT_S, cfg[2].offset); req->ol4_cfg = cpu_to_le16(data); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "failed to set fd user def data, ret= %d\n", ret); return ret; } static void hclge_sync_fd_user_def_cfg(struct hclge_dev *hdev, bool locked) { int ret; if (!test_and_clear_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state)) return; if (!locked) spin_lock_bh(&hdev->fd_rule_lock); ret = hclge_fd_set_user_def_cmd(hdev, hdev->fd_cfg.user_def_cfg); if (ret) set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state); if (!locked) spin_unlock_bh(&hdev->fd_rule_lock); } static int hclge_fd_check_user_def_refcnt(struct hclge_dev *hdev, struct hclge_fd_rule *rule) { struct hlist_head *hlist = &hdev->fd_rule_list; struct hclge_fd_rule *fd_rule, *parent = NULL; struct hclge_fd_user_def_info *info, *old_info; struct hclge_fd_user_def_cfg *cfg; if (!rule || rule->rule_type != HCLGE_FD_EP_ACTIVE || rule->ep.user_def.layer == HCLGE_FD_USER_DEF_NONE) return 0; /* for valid layer is start from 1, so need minus 1 to get the cfg */ cfg = &hdev->fd_cfg.user_def_cfg[rule->ep.user_def.layer - 1]; info = &rule->ep.user_def; if (!cfg->ref_cnt || cfg->offset == info->offset) return 0; if (cfg->ref_cnt > 1) goto error; fd_rule = hclge_find_fd_rule(hlist, rule->location, &parent); if (fd_rule) { old_info = &fd_rule->ep.user_def; if (info->layer == old_info->layer) return 0; } error: dev_err(&hdev->pdev->dev, "No available offset for layer%d fd rule, each layer only support one user def offset.\n", info->layer + 1); return -ENOSPC; } static void hclge_fd_inc_user_def_refcnt(struct hclge_dev *hdev, struct hclge_fd_rule *rule) { struct hclge_fd_user_def_cfg *cfg; if (!rule || rule->rule_type != HCLGE_FD_EP_ACTIVE || rule->ep.user_def.layer == HCLGE_FD_USER_DEF_NONE) return; cfg = &hdev->fd_cfg.user_def_cfg[rule->ep.user_def.layer - 1]; if (!cfg->ref_cnt) { cfg->offset = rule->ep.user_def.offset; set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state); } cfg->ref_cnt++; } static void hclge_fd_dec_user_def_refcnt(struct hclge_dev *hdev, struct hclge_fd_rule *rule) { struct hclge_fd_user_def_cfg *cfg; if (!rule || rule->rule_type != HCLGE_FD_EP_ACTIVE || rule->ep.user_def.layer == HCLGE_FD_USER_DEF_NONE) return; cfg = &hdev->fd_cfg.user_def_cfg[rule->ep.user_def.layer - 1]; if (!cfg->ref_cnt) return; cfg->ref_cnt--; if (!cfg->ref_cnt) { cfg->offset = 0; set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state); } } static void hclge_update_fd_list(struct hclge_dev *hdev, enum HCLGE_FD_NODE_STATE state, u16 location, struct hclge_fd_rule *new_rule) { struct hlist_head *hlist = &hdev->fd_rule_list; struct hclge_fd_rule *fd_rule, *parent = NULL; fd_rule = hclge_find_fd_rule(hlist, location, &parent); if (fd_rule) { hclge_fd_dec_user_def_refcnt(hdev, fd_rule); if (state == HCLGE_FD_ACTIVE) hclge_fd_inc_user_def_refcnt(hdev, new_rule); hclge_sync_fd_user_def_cfg(hdev, true); hclge_update_fd_rule_node(hdev, fd_rule, new_rule, state); return; } /* it's unlikely to fail here, because we have checked the rule * exist before. */ if (unlikely(state == HCLGE_FD_TO_DEL || state == HCLGE_FD_DELETED)) { dev_warn(&hdev->pdev->dev, "failed to delete fd rule %u, it's inexistent\n", location); return; } hclge_fd_inc_user_def_refcnt(hdev, new_rule); hclge_sync_fd_user_def_cfg(hdev, true); hclge_fd_insert_rule_node(hlist, new_rule, parent); hclge_fd_inc_rule_cnt(hdev, new_rule->location); if (state == HCLGE_FD_TO_ADD) { set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state); hclge_task_schedule(hdev, 0); } } static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode) { struct hclge_get_fd_mode_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_MODE_CTRL, true); req = (struct hclge_get_fd_mode_cmd *)desc.data; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "get fd mode fail, ret=%d\n", ret); return ret; } *fd_mode = req->mode; return ret; } static int hclge_get_fd_allocation(struct hclge_dev *hdev, u32 *stage1_entry_num, u32 *stage2_entry_num, u16 *stage1_counter_num, u16 *stage2_counter_num) { struct hclge_get_fd_allocation_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_GET_ALLOCATION, true); req = (struct hclge_get_fd_allocation_cmd *)desc.data; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "query fd allocation fail, ret=%d\n", ret); return ret; } *stage1_entry_num = le32_to_cpu(req->stage1_entry_num); *stage2_entry_num = le32_to_cpu(req->stage2_entry_num); *stage1_counter_num = le16_to_cpu(req->stage1_counter_num); *stage2_counter_num = le16_to_cpu(req->stage2_counter_num); return ret; } static int hclge_set_fd_key_config(struct hclge_dev *hdev, enum HCLGE_FD_STAGE stage_num) { struct hclge_set_fd_key_config_cmd *req; struct hclge_fd_key_cfg *stage; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_KEY_CONFIG, false); req = (struct hclge_set_fd_key_config_cmd *)desc.data; stage = &hdev->fd_cfg.key_cfg[stage_num]; req->stage = stage_num; req->key_select = stage->key_sel; req->inner_sipv6_word_en = stage->inner_sipv6_word_en; req->inner_dipv6_word_en = stage->inner_dipv6_word_en; req->outer_sipv6_word_en = stage->outer_sipv6_word_en; req->outer_dipv6_word_en = stage->outer_dipv6_word_en; req->tuple_mask = cpu_to_le32(~stage->tuple_active); req->meta_data_mask = cpu_to_le32(~stage->meta_data_active); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "set fd key fail, ret=%d\n", ret); return ret; } static void hclge_fd_disable_user_def(struct hclge_dev *hdev) { struct hclge_fd_user_def_cfg *cfg = hdev->fd_cfg.user_def_cfg; spin_lock_bh(&hdev->fd_rule_lock); memset(cfg, 0, sizeof(hdev->fd_cfg.user_def_cfg)); spin_unlock_bh(&hdev->fd_rule_lock); hclge_fd_set_user_def_cmd(hdev, cfg); } static int hclge_init_fd_config(struct hclge_dev *hdev) { #define LOW_2_WORDS 0x03 struct hclge_fd_key_cfg *key_cfg; int ret; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return 0; ret = hclge_get_fd_mode(hdev, &hdev->fd_cfg.fd_mode); if (ret) return ret; switch (hdev->fd_cfg.fd_mode) { case HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1: hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH; break; case HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1: hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH / 2; break; default: dev_err(&hdev->pdev->dev, "Unsupported flow director mode %u\n", hdev->fd_cfg.fd_mode); return -EOPNOTSUPP; } key_cfg = &hdev->fd_cfg.key_cfg[HCLGE_FD_STAGE_1]; key_cfg->key_sel = HCLGE_FD_KEY_BASE_ON_TUPLE; key_cfg->inner_sipv6_word_en = LOW_2_WORDS; key_cfg->inner_dipv6_word_en = LOW_2_WORDS; key_cfg->outer_sipv6_word_en = 0; key_cfg->outer_dipv6_word_en = 0; key_cfg->tuple_active = BIT(INNER_VLAN_TAG_FST) | BIT(INNER_ETH_TYPE) | BIT(INNER_IP_PROTO) | BIT(INNER_IP_TOS) | BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) | BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); /* 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); if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3) key_cfg->tuple_active |= HCLGE_FD_TUPLE_USER_DEF_TUPLES; } /* roce_type is used to filter roce frames * dst_vport is used to specify the rule */ key_cfg->meta_data_active = BIT(ROCE_TYPE) | BIT(DST_VPORT); ret = hclge_get_fd_allocation(hdev, &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1], &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_2], &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1], &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_2]); if (ret) return ret; return hclge_set_fd_key_config(hdev, HCLGE_FD_STAGE_1); } static int hclge_fd_tcam_config(struct hclge_dev *hdev, u8 stage, bool sel_x, int loc, u8 *key, bool is_add) { 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, false); desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_FD_TCAM_OP, false); desc[1].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); hclge_cmd_setup_basic_desc(&desc[2], HCLGE_OPC_FD_TCAM_OP, false); req1 = (struct hclge_fd_tcam_config_1_cmd *)desc[0].data; req2 = (struct hclge_fd_tcam_config_2_cmd *)desc[1].data; req3 = (struct hclge_fd_tcam_config_3_cmd *)desc[2].data; req1->stage = stage; req1->xy_sel = sel_x ? 1 : 0; hnae3_set_bit(req1->port_info, HCLGE_FD_EPORT_SW_EN_B, 0); req1->index = cpu_to_le32(loc); req1->entry_vld = sel_x ? is_add : 0; if (key) { memcpy(req1->tcam_data, &key[0], sizeof(req1->tcam_data)); memcpy(req2->tcam_data, &key[sizeof(req1->tcam_data)], sizeof(req2->tcam_data)); memcpy(req3->tcam_data, &key[sizeof(req1->tcam_data) + sizeof(req2->tcam_data)], sizeof(req3->tcam_data)); } ret = hclge_cmd_send(&hdev->hw, desc, 3); if (ret) dev_err(&hdev->pdev->dev, "config tcam key fail, ret=%d\n", ret); return ret; } static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc, struct hclge_fd_ad_data *action) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); struct hclge_fd_ad_config_cmd *req; struct hclge_desc desc; u64 ad_data = 0; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_AD_OP, false); req = (struct hclge_fd_ad_config_cmd *)desc.data; req->index = cpu_to_le32(loc); req->stage = stage; hnae3_set_bit(ad_data, HCLGE_FD_AD_WR_RULE_ID_B, action->write_rule_id_to_bd); hnae3_set_field(ad_data, HCLGE_FD_AD_RULE_ID_M, HCLGE_FD_AD_RULE_ID_S, action->rule_id); if (test_bit(HNAE3_DEV_SUPPORT_FD_FORWARD_TC_B, ae_dev->caps)) { hnae3_set_bit(ad_data, HCLGE_FD_AD_TC_OVRD_B, action->override_tc); hnae3_set_field(ad_data, HCLGE_FD_AD_TC_SIZE_M, HCLGE_FD_AD_TC_SIZE_S, (u32)action->tc_size); } ad_data <<= 32; 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, 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_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); req->ad_data = cpu_to_le64(ad_data); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "fd ad config fail, ret=%d\n", ret); return ret; } static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y, struct hclge_fd_rule *rule) { int offset, moffset, ip_offset; enum HCLGE_FD_KEY_OPT key_opt; u16 tmp_x_s, tmp_y_s; u32 tmp_x_l, tmp_y_l; u8 *p = (u8 *)rule; int i; if (rule->unused_tuple & BIT(tuple_bit)) return true; key_opt = tuple_key_info[tuple_bit].key_opt; offset = tuple_key_info[tuple_bit].offset; moffset = tuple_key_info[tuple_bit].moffset; switch (key_opt) { case KEY_OPT_U8: calc_x(*key_x, p[offset], p[moffset]); calc_y(*key_y, p[offset], p[moffset]); return true; case KEY_OPT_LE16: calc_x(tmp_x_s, *(u16 *)(&p[offset]), *(u16 *)(&p[moffset])); calc_y(tmp_y_s, *(u16 *)(&p[offset]), *(u16 *)(&p[moffset])); *(__le16 *)key_x = cpu_to_le16(tmp_x_s); *(__le16 *)key_y = cpu_to_le16(tmp_y_s); return true; case KEY_OPT_LE32: calc_x(tmp_x_l, *(u32 *)(&p[offset]), *(u32 *)(&p[moffset])); calc_y(tmp_y_l, *(u32 *)(&p[offset]), *(u32 *)(&p[moffset])); *(__le32 *)key_x = cpu_to_le32(tmp_x_l); *(__le32 *)key_y = cpu_to_le32(tmp_y_l); return true; case KEY_OPT_MAC: for (i = 0; i < ETH_ALEN; i++) { calc_x(key_x[ETH_ALEN - 1 - i], p[offset + i], p[moffset + i]); calc_y(key_y[ETH_ALEN - 1 - i], p[offset + i], p[moffset + i]); } return true; case KEY_OPT_IP: ip_offset = IPV4_INDEX * sizeof(u32); calc_x(tmp_x_l, *(u32 *)(&p[offset + ip_offset]), *(u32 *)(&p[moffset + ip_offset])); calc_y(tmp_y_l, *(u32 *)(&p[offset + ip_offset]), *(u32 *)(&p[moffset + ip_offset])); *(__le32 *)key_x = cpu_to_le32(tmp_x_l); *(__le32 *)key_y = cpu_to_le32(tmp_y_l); return true; default: return false; } } static u32 hclge_get_port_number(enum HLCGE_PORT_TYPE port_type, u8 pf_id, u8 vf_id, u8 network_port_id) { u32 port_number = 0; if (port_type == HOST_PORT) { hnae3_set_field(port_number, HCLGE_PF_ID_M, HCLGE_PF_ID_S, pf_id); hnae3_set_field(port_number, HCLGE_VF_ID_M, HCLGE_VF_ID_S, vf_id); hnae3_set_bit(port_number, HCLGE_PORT_TYPE_B, HOST_PORT); } else { hnae3_set_field(port_number, HCLGE_NETWORK_PORT_ID_M, HCLGE_NETWORK_PORT_ID_S, network_port_id); hnae3_set_bit(port_number, HCLGE_PORT_TYPE_B, NETWORK_PORT); } return port_number; } static void hclge_fd_convert_meta_data(struct hclge_fd_key_cfg *key_cfg, __le32 *key_x, __le32 *key_y, struct hclge_fd_rule *rule) { u32 tuple_bit, meta_data = 0, tmp_x, tmp_y, port_number; u8 cur_pos = 0, tuple_size, shift_bits; unsigned int i; for (i = 0; i < MAX_META_DATA; i++) { tuple_size = meta_data_key_info[i].key_length; tuple_bit = key_cfg->meta_data_active & BIT(i); switch (tuple_bit) { case BIT(ROCE_TYPE): hnae3_set_bit(meta_data, cur_pos, NIC_PACKET); cur_pos += tuple_size; break; case BIT(DST_VPORT): port_number = hclge_get_port_number(HOST_PORT, 0, rule->vf_id, 0); hnae3_set_field(meta_data, GENMASK(cur_pos + tuple_size, cur_pos), cur_pos, port_number); cur_pos += tuple_size; break; default: break; } } calc_x(tmp_x, meta_data, 0xFFFFFFFF); calc_y(tmp_y, meta_data, 0xFFFFFFFF); shift_bits = sizeof(meta_data) * 8 - cur_pos; *key_x = cpu_to_le32(tmp_x << shift_bits); *key_y = cpu_to_le32(tmp_y << shift_bits); } /* A complete key is combined with meta data key and tuple key. * Meta data key is stored at the MSB region, and tuple key is stored at * the LSB region, unused bits will be filled 0. */ static int hclge_config_key(struct hclge_dev *hdev, u8 stage, struct hclge_fd_rule *rule) { struct hclge_fd_key_cfg *key_cfg = &hdev->fd_cfg.key_cfg[stage]; u8 key_x[MAX_KEY_BYTES], key_y[MAX_KEY_BYTES]; u8 *cur_key_x, *cur_key_y; u8 meta_data_region; u8 tuple_size; int ret; u32 i; memset(key_x, 0, sizeof(key_x)); memset(key_y, 0, sizeof(key_y)); cur_key_x = key_x; cur_key_y = key_y; for (i = 0; i < MAX_TUPLE; i++) { bool tuple_valid; tuple_size = tuple_key_info[i].key_length / 8; if (!(key_cfg->tuple_active & BIT(i))) continue; tuple_valid = hclge_fd_convert_tuple(i, cur_key_x, cur_key_y, rule); if (tuple_valid) { cur_key_x += tuple_size; cur_key_y += tuple_size; } } meta_data_region = hdev->fd_cfg.max_key_length / 8 - MAX_META_DATA_LENGTH / 8; hclge_fd_convert_meta_data(key_cfg, (__le32 *)(key_x + meta_data_region), (__le32 *)(key_y + meta_data_region), rule); ret = hclge_fd_tcam_config(hdev, stage, false, rule->location, key_y, true); if (ret) { dev_err(&hdev->pdev->dev, "fd key_y config fail, loc=%u, ret=%d\n", rule->queue_id, ret); return ret; } ret = hclge_fd_tcam_config(hdev, stage, true, rule->location, key_x, true); if (ret) dev_err(&hdev->pdev->dev, "fd key_x config fail, loc=%u, ret=%d\n", rule->queue_id, ret); return ret; } static int hclge_config_action(struct hclge_dev *hdev, u8 stage, struct hclge_fd_rule *rule) { struct hclge_vport *vport = hdev->vport; struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; struct hclge_fd_ad_data ad_data; memset(&ad_data, 0, sizeof(struct hclge_fd_ad_data)); ad_data.ad_id = rule->location; if (rule->action == HCLGE_FD_ACTION_DROP_PACKET) { ad_data.drop_packet = true; } else if (rule->action == HCLGE_FD_ACTION_SELECT_TC) { ad_data.override_tc = true; ad_data.queue_id = kinfo->tc_info.tqp_offset[rule->cls_flower.tc]; ad_data.tc_size = ilog2(kinfo->tc_info.tqp_count[rule->cls_flower.tc]); } else { ad_data.forward_to_direct_queue = true; ad_data.queue_id = rule->queue_id; } if (hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1]) { ad_data.use_counter = true; ad_data.counter_id = rule->vf_id % hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1]; } else { ad_data.use_counter = false; ad_data.counter_id = 0; } ad_data.use_next_stage = false; ad_data.next_input_key = 0; ad_data.write_rule_id_to_bd = true; ad_data.rule_id = rule->location; return hclge_fd_ad_config(hdev, stage, ad_data.ad_id, &ad_data); } static int hclge_fd_check_tcpip4_tuple(struct ethtool_tcpip4_spec *spec, u32 *unused_tuple) { if (!spec || !unused_tuple) return -EINVAL; *unused_tuple |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC); if (!spec->ip4src) *unused_tuple |= BIT(INNER_SRC_IP); if (!spec->ip4dst) *unused_tuple |= BIT(INNER_DST_IP); if (!spec->psrc) *unused_tuple |= BIT(INNER_SRC_PORT); if (!spec->pdst) *unused_tuple |= BIT(INNER_DST_PORT); if (!spec->tos) *unused_tuple |= BIT(INNER_IP_TOS); return 0; } static int hclge_fd_check_ip4_tuple(struct ethtool_usrip4_spec *spec, u32 *unused_tuple) { if (!spec || !unused_tuple) return -EINVAL; *unused_tuple |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) | BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); 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->proto) *unused_tuple |= BIT(INNER_IP_PROTO); if (spec->l4_4_bytes) return -EOPNOTSUPP; if (spec->ip_ver != ETH_RX_NFC_IP4) return -EOPNOTSUPP; return 0; } static int hclge_fd_check_tcpip6_tuple(struct ethtool_tcpip6_spec *spec, u32 *unused_tuple) { if (!spec || !unused_tuple) return -EINVAL; *unused_tuple |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC); /* check whether src/dst ip address used */ 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->psrc) *unused_tuple |= BIT(INNER_SRC_PORT); if (!spec->pdst) *unused_tuple |= BIT(INNER_DST_PORT); if (!spec->tclass) *unused_tuple |= BIT(INNER_IP_TOS); return 0; } static int hclge_fd_check_ip6_tuple(struct ethtool_usrip6_spec *spec, u32 *unused_tuple) { if (!spec || !unused_tuple) return -EINVAL; *unused_tuple |= BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) | BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); /* check whether src/dst ip address used */ 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->l4_proto) *unused_tuple |= BIT(INNER_IP_PROTO); if (!spec->tclass) *unused_tuple |= BIT(INNER_IP_TOS); if (spec->l4_4_bytes) return -EOPNOTSUPP; return 0; } static int hclge_fd_check_ether_tuple(struct ethhdr *spec, u32 *unused_tuple) { if (!spec || !unused_tuple) return -EINVAL; *unused_tuple |= BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) | BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT) | BIT(INNER_IP_TOS) | BIT(INNER_IP_PROTO); if (is_zero_ether_addr(spec->h_source)) *unused_tuple |= BIT(INNER_SRC_MAC); if (is_zero_ether_addr(spec->h_dest)) *unused_tuple |= BIT(INNER_DST_MAC); if (!spec->h_proto) *unused_tuple |= BIT(INNER_ETH_TYPE); return 0; } static int hclge_fd_check_ext_tuple(struct hclge_dev *hdev, struct ethtool_rx_flow_spec *fs, u32 *unused_tuple) { if (fs->flow_type & FLOW_EXT) { if (fs->h_ext.vlan_etype) { dev_err(&hdev->pdev->dev, "vlan-etype is not supported!\n"); return -EOPNOTSUPP; } if (!fs->h_ext.vlan_tci) *unused_tuple |= BIT(INNER_VLAN_TAG_FST); if (fs->m_ext.vlan_tci && be16_to_cpu(fs->h_ext.vlan_tci) >= VLAN_N_VID) { dev_err(&hdev->pdev->dev, "failed to config vlan_tci, invalid vlan_tci: %u, max is %d.\n", ntohs(fs->h_ext.vlan_tci), VLAN_N_VID - 1); return -EINVAL; } } else { *unused_tuple |= BIT(INNER_VLAN_TAG_FST); } if (fs->flow_type & FLOW_MAC_EXT) { if (hdev->fd_cfg.fd_mode != HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1) { dev_err(&hdev->pdev->dev, "FLOW_MAC_EXT is not supported in current fd mode!\n"); return -EOPNOTSUPP; } if (is_zero_ether_addr(fs->h_ext.h_dest)) *unused_tuple |= BIT(INNER_DST_MAC); else *unused_tuple &= ~BIT(INNER_DST_MAC); } return 0; } static int hclge_fd_get_user_def_layer(u32 flow_type, u32 *unused_tuple, struct hclge_fd_user_def_info *info) { switch (flow_type) { case ETHER_FLOW: info->layer = HCLGE_FD_USER_DEF_L2; *unused_tuple &= ~BIT(INNER_L2_RSV); break; case IP_USER_FLOW: case IPV6_USER_FLOW: info->layer = HCLGE_FD_USER_DEF_L3; *unused_tuple &= ~BIT(INNER_L3_RSV); break; case TCP_V4_FLOW: case UDP_V4_FLOW: case TCP_V6_FLOW: case UDP_V6_FLOW: info->layer = HCLGE_FD_USER_DEF_L4; *unused_tuple &= ~BIT(INNER_L4_RSV); break; default: return -EOPNOTSUPP; } return 0; } static bool hclge_fd_is_user_def_all_masked(struct ethtool_rx_flow_spec *fs) { return be32_to_cpu(fs->m_ext.data[1] | fs->m_ext.data[0]) == 0; } static int hclge_fd_parse_user_def_field(struct hclge_dev *hdev, struct ethtool_rx_flow_spec *fs, u32 *unused_tuple, struct hclge_fd_user_def_info *info) { u32 tuple_active = hdev->fd_cfg.key_cfg[HCLGE_FD_STAGE_1].tuple_active; u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT); u16 data, offset, data_mask, offset_mask; int ret; info->layer = HCLGE_FD_USER_DEF_NONE; *unused_tuple |= HCLGE_FD_TUPLE_USER_DEF_TUPLES; if (!(fs->flow_type & FLOW_EXT) || hclge_fd_is_user_def_all_masked(fs)) return 0; /* user-def data from ethtool is 64 bit value, the bit0~15 is used * for data, and bit32~47 is used for offset. */ data = be32_to_cpu(fs->h_ext.data[1]) & HCLGE_FD_USER_DEF_DATA; data_mask = be32_to_cpu(fs->m_ext.data[1]) & HCLGE_FD_USER_DEF_DATA; offset = be32_to_cpu(fs->h_ext.data[0]) & HCLGE_FD_USER_DEF_OFFSET; offset_mask = be32_to_cpu(fs->m_ext.data[0]) & HCLGE_FD_USER_DEF_OFFSET; if (!(tuple_active & HCLGE_FD_TUPLE_USER_DEF_TUPLES)) { dev_err(&hdev->pdev->dev, "user-def bytes are not supported\n"); return -EOPNOTSUPP; } if (offset > HCLGE_FD_MAX_USER_DEF_OFFSET) { dev_err(&hdev->pdev->dev, "user-def offset[%u] should be no more than %u\n", offset, HCLGE_FD_MAX_USER_DEF_OFFSET); return -EINVAL; } if (offset_mask != HCLGE_FD_USER_DEF_OFFSET_UNMASK) { dev_err(&hdev->pdev->dev, "user-def offset can't be masked\n"); return -EINVAL; } ret = hclge_fd_get_user_def_layer(flow_type, unused_tuple, info); if (ret) { dev_err(&hdev->pdev->dev, "unsupported flow type for user-def bytes, ret = %d\n", ret); return ret; } info->data = data; info->data_mask = data_mask; info->offset = offset; return 0; } static int hclge_fd_check_spec(struct hclge_dev *hdev, struct ethtool_rx_flow_spec *fs, u32 *unused_tuple, struct hclge_fd_user_def_info *info) { u32 flow_type; int ret; if (fs->location >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) { dev_err(&hdev->pdev->dev, "failed to config fd rules, invalid rule location: %u, max is %u\n.", fs->location, hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1] - 1); return -EINVAL; } ret = hclge_fd_parse_user_def_field(hdev, fs, unused_tuple, info); if (ret) return ret; flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT); switch (flow_type) { case SCTP_V4_FLOW: case TCP_V4_FLOW: case UDP_V4_FLOW: ret = hclge_fd_check_tcpip4_tuple(&fs->h_u.tcp_ip4_spec, unused_tuple); break; case IP_USER_FLOW: ret = hclge_fd_check_ip4_tuple(&fs->h_u.usr_ip4_spec, unused_tuple); break; case SCTP_V6_FLOW: case TCP_V6_FLOW: case UDP_V6_FLOW: ret = hclge_fd_check_tcpip6_tuple(&fs->h_u.tcp_ip6_spec, unused_tuple); break; case IPV6_USER_FLOW: ret = hclge_fd_check_ip6_tuple(&fs->h_u.usr_ip6_spec, unused_tuple); break; case ETHER_FLOW: if (hdev->fd_cfg.fd_mode != HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1) { dev_err(&hdev->pdev->dev, "ETHER_FLOW is not supported in current fd mode!\n"); return -EOPNOTSUPP; } ret = hclge_fd_check_ether_tuple(&fs->h_u.ether_spec, unused_tuple); break; default: dev_err(&hdev->pdev->dev, "unsupported protocol type, protocol type = %#x\n", flow_type); return -EOPNOTSUPP; } if (ret) { dev_err(&hdev->pdev->dev, "failed to check flow union tuple, ret = %d\n", ret); return ret; } return hclge_fd_check_ext_tuple(hdev, fs, unused_tuple); } static void hclge_fd_get_tcpip4_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule, u8 ip_proto) { rule->tuples.src_ip[IPV4_INDEX] = be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4src); rule->tuples_mask.src_ip[IPV4_INDEX] = be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4src); rule->tuples.dst_ip[IPV4_INDEX] = be32_to_cpu(fs->h_u.tcp_ip4_spec.ip4dst); rule->tuples_mask.dst_ip[IPV4_INDEX] = be32_to_cpu(fs->m_u.tcp_ip4_spec.ip4dst); rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip4_spec.psrc); rule->tuples_mask.src_port = be16_to_cpu(fs->m_u.tcp_ip4_spec.psrc); rule->tuples.dst_port = be16_to_cpu(fs->h_u.tcp_ip4_spec.pdst); rule->tuples_mask.dst_port = be16_to_cpu(fs->m_u.tcp_ip4_spec.pdst); rule->tuples.ip_tos = fs->h_u.tcp_ip4_spec.tos; rule->tuples_mask.ip_tos = fs->m_u.tcp_ip4_spec.tos; rule->tuples.ether_proto = ETH_P_IP; rule->tuples_mask.ether_proto = 0xFFFF; rule->tuples.ip_proto = ip_proto; rule->tuples_mask.ip_proto = 0xFF; } static void hclge_fd_get_ip4_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { rule->tuples.src_ip[IPV4_INDEX] = be32_to_cpu(fs->h_u.usr_ip4_spec.ip4src); rule->tuples_mask.src_ip[IPV4_INDEX] = be32_to_cpu(fs->m_u.usr_ip4_spec.ip4src); rule->tuples.dst_ip[IPV4_INDEX] = be32_to_cpu(fs->h_u.usr_ip4_spec.ip4dst); rule->tuples_mask.dst_ip[IPV4_INDEX] = be32_to_cpu(fs->m_u.usr_ip4_spec.ip4dst); rule->tuples.ip_tos = fs->h_u.usr_ip4_spec.tos; rule->tuples_mask.ip_tos = fs->m_u.usr_ip4_spec.tos; rule->tuples.ip_proto = fs->h_u.usr_ip4_spec.proto; rule->tuples_mask.ip_proto = fs->m_u.usr_ip4_spec.proto; rule->tuples.ether_proto = ETH_P_IP; rule->tuples_mask.ether_proto = 0xFFFF; } static void hclge_fd_get_tcpip6_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule, u8 ip_proto) { be32_to_cpu_array(rule->tuples.src_ip, fs->h_u.tcp_ip6_spec.ip6src, IPV6_SIZE); be32_to_cpu_array(rule->tuples_mask.src_ip, fs->m_u.tcp_ip6_spec.ip6src, IPV6_SIZE); be32_to_cpu_array(rule->tuples.dst_ip, fs->h_u.tcp_ip6_spec.ip6dst, IPV6_SIZE); be32_to_cpu_array(rule->tuples_mask.dst_ip, fs->m_u.tcp_ip6_spec.ip6dst, IPV6_SIZE); rule->tuples.src_port = be16_to_cpu(fs->h_u.tcp_ip6_spec.psrc); rule->tuples_mask.src_port = be16_to_cpu(fs->m_u.tcp_ip6_spec.psrc); rule->tuples.dst_port = be16_to_cpu(fs->h_u.tcp_ip6_spec.pdst); rule->tuples_mask.dst_port = be16_to_cpu(fs->m_u.tcp_ip6_spec.pdst); rule->tuples.ether_proto = ETH_P_IPV6; rule->tuples_mask.ether_proto = 0xFFFF; rule->tuples.ip_tos = fs->h_u.tcp_ip6_spec.tclass; rule->tuples_mask.ip_tos = fs->m_u.tcp_ip6_spec.tclass; rule->tuples.ip_proto = ip_proto; rule->tuples_mask.ip_proto = 0xFF; } static void hclge_fd_get_ip6_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { be32_to_cpu_array(rule->tuples.src_ip, fs->h_u.usr_ip6_spec.ip6src, IPV6_SIZE); be32_to_cpu_array(rule->tuples_mask.src_ip, fs->m_u.usr_ip6_spec.ip6src, IPV6_SIZE); be32_to_cpu_array(rule->tuples.dst_ip, fs->h_u.usr_ip6_spec.ip6dst, IPV6_SIZE); be32_to_cpu_array(rule->tuples_mask.dst_ip, fs->m_u.usr_ip6_spec.ip6dst, IPV6_SIZE); rule->tuples.ip_proto = fs->h_u.usr_ip6_spec.l4_proto; rule->tuples_mask.ip_proto = fs->m_u.usr_ip6_spec.l4_proto; rule->tuples.ip_tos = fs->h_u.tcp_ip6_spec.tclass; rule->tuples_mask.ip_tos = fs->m_u.tcp_ip6_spec.tclass; rule->tuples.ether_proto = ETH_P_IPV6; rule->tuples_mask.ether_proto = 0xFFFF; } static void hclge_fd_get_ether_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { ether_addr_copy(rule->tuples.src_mac, fs->h_u.ether_spec.h_source); ether_addr_copy(rule->tuples_mask.src_mac, fs->m_u.ether_spec.h_source); ether_addr_copy(rule->tuples.dst_mac, fs->h_u.ether_spec.h_dest); ether_addr_copy(rule->tuples_mask.dst_mac, fs->m_u.ether_spec.h_dest); rule->tuples.ether_proto = be16_to_cpu(fs->h_u.ether_spec.h_proto); rule->tuples_mask.ether_proto = be16_to_cpu(fs->m_u.ether_spec.h_proto); } static void hclge_fd_get_user_def_tuple(struct hclge_fd_user_def_info *info, struct hclge_fd_rule *rule) { switch (info->layer) { case HCLGE_FD_USER_DEF_L2: rule->tuples.l2_user_def = info->data; rule->tuples_mask.l2_user_def = info->data_mask; break; case HCLGE_FD_USER_DEF_L3: rule->tuples.l3_user_def = info->data; rule->tuples_mask.l3_user_def = info->data_mask; break; case HCLGE_FD_USER_DEF_L4: rule->tuples.l4_user_def = (u32)info->data << 16; rule->tuples_mask.l4_user_def = (u32)info->data_mask << 16; break; default: break; } rule->ep.user_def = *info; } static int hclge_fd_get_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule, struct hclge_fd_user_def_info *info) { u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT); switch (flow_type) { case SCTP_V4_FLOW: hclge_fd_get_tcpip4_tuple(fs, rule, IPPROTO_SCTP); break; case TCP_V4_FLOW: hclge_fd_get_tcpip4_tuple(fs, rule, IPPROTO_TCP); break; case UDP_V4_FLOW: hclge_fd_get_tcpip4_tuple(fs, rule, IPPROTO_UDP); break; case IP_USER_FLOW: hclge_fd_get_ip4_tuple(fs, rule); break; case SCTP_V6_FLOW: hclge_fd_get_tcpip6_tuple(fs, rule, IPPROTO_SCTP); break; case TCP_V6_FLOW: hclge_fd_get_tcpip6_tuple(fs, rule, IPPROTO_TCP); break; case UDP_V6_FLOW: hclge_fd_get_tcpip6_tuple(fs, rule, IPPROTO_UDP); break; case IPV6_USER_FLOW: hclge_fd_get_ip6_tuple(fs, rule); break; case ETHER_FLOW: hclge_fd_get_ether_tuple(fs, rule); break; default: return -EOPNOTSUPP; } if (fs->flow_type & FLOW_EXT) { rule->tuples.vlan_tag1 = be16_to_cpu(fs->h_ext.vlan_tci); rule->tuples_mask.vlan_tag1 = be16_to_cpu(fs->m_ext.vlan_tci); hclge_fd_get_user_def_tuple(info, rule); } if (fs->flow_type & FLOW_MAC_EXT) { ether_addr_copy(rule->tuples.dst_mac, fs->h_ext.h_dest); ether_addr_copy(rule->tuples_mask.dst_mac, fs->m_ext.h_dest); } return 0; } static int hclge_fd_config_rule(struct hclge_dev *hdev, struct hclge_fd_rule *rule) { int ret; ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule); if (ret) return ret; return hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule); } static int hclge_add_fd_entry_common(struct hclge_dev *hdev, struct hclge_fd_rule *rule) { int ret; spin_lock_bh(&hdev->fd_rule_lock); if (hdev->fd_active_type != rule->rule_type && (hdev->fd_active_type == HCLGE_FD_TC_FLOWER_ACTIVE || hdev->fd_active_type == HCLGE_FD_EP_ACTIVE)) { dev_err(&hdev->pdev->dev, "mode conflict(new type %d, active type %d), please delete existent rules first\n", rule->rule_type, hdev->fd_active_type); spin_unlock_bh(&hdev->fd_rule_lock); return -EINVAL; } ret = hclge_fd_check_user_def_refcnt(hdev, rule); if (ret) goto out; ret = hclge_clear_arfs_rules(hdev); if (ret) goto out; ret = hclge_fd_config_rule(hdev, rule); if (ret) goto out; rule->state = HCLGE_FD_ACTIVE; hdev->fd_active_type = rule->rule_type; hclge_update_fd_list(hdev, rule->state, rule->location, rule); out: spin_unlock_bh(&hdev->fd_rule_lock); return ret; } static bool hclge_is_cls_flower_active(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return hdev->fd_active_type == HCLGE_FD_TC_FLOWER_ACTIVE; } static int hclge_fd_parse_ring_cookie(struct hclge_dev *hdev, u64 ring_cookie, u16 *vport_id, u8 *action, u16 *queue_id) { struct hclge_vport *vport = hdev->vport; if (ring_cookie == RX_CLS_FLOW_DISC) { *action = HCLGE_FD_ACTION_DROP_PACKET; } else { u32 ring = ethtool_get_flow_spec_ring(ring_cookie); u8 vf = ethtool_get_flow_spec_ring_vf(ring_cookie); u16 tqps; /* To keep consistent with user's configuration, minus 1 when * printing 'vf', because vf id from ethtool is added 1 for vf. */ if (vf > hdev->num_req_vfs) { dev_err(&hdev->pdev->dev, "Error: vf id (%u) should be less than %u\n", vf - 1U, hdev->num_req_vfs); return -EINVAL; } *vport_id = vf ? hdev->vport[vf].vport_id : vport->vport_id; tqps = hdev->vport[vf].nic.kinfo.num_tqps; if (ring >= tqps) { dev_err(&hdev->pdev->dev, "Error: queue id (%u) > max tqp num (%u)\n", ring, tqps - 1U); return -EINVAL; } *action = HCLGE_FD_ACTION_SELECT_QUEUE; *queue_id = ring; } return 0; } static int hclge_add_fd_entry(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_fd_user_def_info info; u16 dst_vport_id = 0, q_index = 0; struct ethtool_rx_flow_spec *fs; struct hclge_fd_rule *rule; u32 unused = 0; u8 action; int ret; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) { dev_err(&hdev->pdev->dev, "flow table director is not supported\n"); return -EOPNOTSUPP; } if (!hdev->fd_en) { dev_err(&hdev->pdev->dev, "please enable flow director first\n"); return -EOPNOTSUPP; } fs = (struct ethtool_rx_flow_spec *)&cmd->fs; ret = hclge_fd_check_spec(hdev, fs, &unused, &info); if (ret) return ret; ret = hclge_fd_parse_ring_cookie(hdev, fs->ring_cookie, &dst_vport_id, &action, &q_index); if (ret) return ret; rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (!rule) return -ENOMEM; ret = hclge_fd_get_tuple(fs, rule, &info); if (ret) { kfree(rule); return ret; } rule->flow_type = fs->flow_type; rule->location = fs->location; rule->unused_tuple = unused; rule->vf_id = dst_vport_id; rule->queue_id = q_index; rule->action = action; rule->rule_type = HCLGE_FD_EP_ACTIVE; ret = hclge_add_fd_entry_common(hdev, rule); if (ret) kfree(rule); return ret; } static int hclge_del_fd_entry(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct ethtool_rx_flow_spec *fs; int ret; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return -EOPNOTSUPP; fs = (struct ethtool_rx_flow_spec *)&cmd->fs; if (fs->location >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) return -EINVAL; spin_lock_bh(&hdev->fd_rule_lock); if (hdev->fd_active_type == HCLGE_FD_TC_FLOWER_ACTIVE || !test_bit(fs->location, hdev->fd_bmap)) { dev_err(&hdev->pdev->dev, "Delete fail, rule %u is inexistent\n", fs->location); spin_unlock_bh(&hdev->fd_rule_lock); return -ENOENT; } ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, fs->location, NULL, false); if (ret) goto out; hclge_update_fd_list(hdev, HCLGE_FD_DELETED, fs->location, NULL); out: spin_unlock_bh(&hdev->fd_rule_lock); return ret; } static void hclge_clear_fd_rules_in_list(struct hclge_dev *hdev, bool clear_list) { struct hclge_fd_rule *rule; struct hlist_node *node; u16 location; spin_lock_bh(&hdev->fd_rule_lock); for_each_set_bit(location, hdev->fd_bmap, hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, location, NULL, false); if (clear_list) { hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { hlist_del(&rule->rule_node); kfree(rule); } hdev->fd_active_type = HCLGE_FD_RULE_NONE; hdev->hclge_fd_rule_num = 0; bitmap_zero(hdev->fd_bmap, hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]); } spin_unlock_bh(&hdev->fd_rule_lock); } static void hclge_del_all_fd_entries(struct hclge_dev *hdev) { if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return; hclge_clear_fd_rules_in_list(hdev, true); hclge_fd_disable_user_def(hdev); } static int hclge_restore_fd_entries(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_fd_rule *rule; struct hlist_node *node; /* Return ok here, because reset error handling will check this * return value. If error is returned here, the reset process will * fail. */ if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return 0; /* if fd is disabled, should not restore it when reset */ if (!hdev->fd_en) return 0; spin_lock_bh(&hdev->fd_rule_lock); hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { if (rule->state == HCLGE_FD_ACTIVE) rule->state = HCLGE_FD_TO_ADD; } spin_unlock_bh(&hdev->fd_rule_lock); set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state); return 0; } static int hclge_get_fd_rule_cnt(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev) || hclge_is_cls_flower_active(handle)) return -EOPNOTSUPP; cmd->rule_cnt = hdev->hclge_fd_rule_num; cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]; return 0; } static void hclge_fd_get_tcpip4_info(struct hclge_fd_rule *rule, struct ethtool_tcpip4_spec *spec, struct ethtool_tcpip4_spec *spec_mask) { 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]); spec->psrc = cpu_to_be16(rule->tuples.src_port); spec_mask->psrc = rule->unused_tuple & BIT(INNER_SRC_PORT) ? 0 : cpu_to_be16(rule->tuples_mask.src_port); spec->pdst = cpu_to_be16(rule->tuples.dst_port); spec_mask->pdst = rule->unused_tuple & BIT(INNER_DST_PORT) ? 0 : cpu_to_be16(rule->tuples_mask.dst_port); spec->tos = rule->tuples.ip_tos; spec_mask->tos = rule->unused_tuple & BIT(INNER_IP_TOS) ? 0 : rule->tuples_mask.ip_tos; } static void hclge_fd_get_ip4_info(struct hclge_fd_rule *rule, struct ethtool_usrip4_spec *spec, struct ethtool_usrip4_spec *spec_mask) { 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]); spec->tos = rule->tuples.ip_tos; spec_mask->tos = rule->unused_tuple & BIT(INNER_IP_TOS) ? 0 : rule->tuples_mask.ip_tos; spec->proto = rule->tuples.ip_proto; spec_mask->proto = rule->unused_tuple & BIT(INNER_IP_PROTO) ? 0 : rule->tuples_mask.ip_proto; spec->ip_ver = ETH_RX_NFC_IP4; } static void hclge_fd_get_tcpip6_info(struct hclge_fd_rule *rule, struct ethtool_tcpip6_spec *spec, struct ethtool_tcpip6_spec *spec_mask) { 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); spec->tclass = rule->tuples.ip_tos; spec_mask->tclass = rule->unused_tuple & BIT(INNER_IP_TOS) ? 0 : rule->tuples_mask.ip_tos; spec->psrc = cpu_to_be16(rule->tuples.src_port); spec_mask->psrc = rule->unused_tuple & BIT(INNER_SRC_PORT) ? 0 : cpu_to_be16(rule->tuples_mask.src_port); spec->pdst = cpu_to_be16(rule->tuples.dst_port); spec_mask->pdst = rule->unused_tuple & BIT(INNER_DST_PORT) ? 0 : cpu_to_be16(rule->tuples_mask.dst_port); } static void hclge_fd_get_ip6_info(struct hclge_fd_rule *rule, struct ethtool_usrip6_spec *spec, struct ethtool_usrip6_spec *spec_mask) { 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); 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; } static void hclge_fd_get_ether_info(struct hclge_fd_rule *rule, struct ethhdr *spec, struct ethhdr *spec_mask) { ether_addr_copy(spec->h_source, rule->tuples.src_mac); ether_addr_copy(spec->h_dest, rule->tuples.dst_mac); if (rule->unused_tuple & BIT(INNER_SRC_MAC)) eth_zero_addr(spec_mask->h_source); else ether_addr_copy(spec_mask->h_source, rule->tuples_mask.src_mac); if (rule->unused_tuple & BIT(INNER_DST_MAC)) eth_zero_addr(spec_mask->h_dest); else ether_addr_copy(spec_mask->h_dest, rule->tuples_mask.dst_mac); spec->h_proto = cpu_to_be16(rule->tuples.ether_proto); spec_mask->h_proto = rule->unused_tuple & BIT(INNER_ETH_TYPE) ? 0 : cpu_to_be16(rule->tuples_mask.ether_proto); } static void hclge_fd_get_user_def_info(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { if ((rule->unused_tuple & HCLGE_FD_TUPLE_USER_DEF_TUPLES) == HCLGE_FD_TUPLE_USER_DEF_TUPLES) { fs->h_ext.data[0] = 0; fs->h_ext.data[1] = 0; fs->m_ext.data[0] = 0; fs->m_ext.data[1] = 0; } else { fs->h_ext.data[0] = cpu_to_be32(rule->ep.user_def.offset); fs->h_ext.data[1] = cpu_to_be32(rule->ep.user_def.data); fs->m_ext.data[0] = cpu_to_be32(HCLGE_FD_USER_DEF_OFFSET_UNMASK); fs->m_ext.data[1] = cpu_to_be32(rule->ep.user_def.data_mask); } } static void hclge_fd_get_ext_info(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { if (fs->flow_type & FLOW_EXT) { fs->h_ext.vlan_tci = cpu_to_be16(rule->tuples.vlan_tag1); fs->m_ext.vlan_tci = rule->unused_tuple & BIT(INNER_VLAN_TAG_FST) ? 0 : cpu_to_be16(rule->tuples_mask.vlan_tag1); hclge_fd_get_user_def_info(fs, rule); } if (fs->flow_type & FLOW_MAC_EXT) { ether_addr_copy(fs->h_ext.h_dest, rule->tuples.dst_mac); if (rule->unused_tuple & BIT(INNER_DST_MAC)) eth_zero_addr(fs->m_u.ether_spec.h_dest); else ether_addr_copy(fs->m_u.ether_spec.h_dest, rule->tuples_mask.dst_mac); } } static struct hclge_fd_rule *hclge_get_fd_rule(struct hclge_dev *hdev, u16 location) { struct hclge_fd_rule *rule = NULL; struct hlist_node *node2; hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) { if (rule->location == location) return rule; else if (rule->location > location) return NULL; } return NULL; } static void hclge_fd_get_ring_cookie(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { if (rule->action == HCLGE_FD_ACTION_DROP_PACKET) { fs->ring_cookie = RX_CLS_FLOW_DISC; } else { u64 vf_id; fs->ring_cookie = rule->queue_id; vf_id = rule->vf_id; vf_id <<= ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF; fs->ring_cookie |= vf_id; } } static int hclge_get_fd_rule_info(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_fd_rule *rule = NULL; struct hclge_dev *hdev = vport->back; struct ethtool_rx_flow_spec *fs; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return -EOPNOTSUPP; fs = (struct ethtool_rx_flow_spec *)&cmd->fs; spin_lock_bh(&hdev->fd_rule_lock); rule = hclge_get_fd_rule(hdev, fs->location); if (!rule) { spin_unlock_bh(&hdev->fd_rule_lock); return -ENOENT; } fs->flow_type = rule->flow_type; switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { case SCTP_V4_FLOW: case TCP_V4_FLOW: case UDP_V4_FLOW: hclge_fd_get_tcpip4_info(rule, &fs->h_u.tcp_ip4_spec, &fs->m_u.tcp_ip4_spec); break; case IP_USER_FLOW: hclge_fd_get_ip4_info(rule, &fs->h_u.usr_ip4_spec, &fs->m_u.usr_ip4_spec); break; case SCTP_V6_FLOW: case TCP_V6_FLOW: case UDP_V6_FLOW: hclge_fd_get_tcpip6_info(rule, &fs->h_u.tcp_ip6_spec, &fs->m_u.tcp_ip6_spec); break; case IPV6_USER_FLOW: hclge_fd_get_ip6_info(rule, &fs->h_u.usr_ip6_spec, &fs->m_u.usr_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 */ default: hclge_fd_get_ether_info(rule, &fs->h_u.ether_spec, &fs->m_u.ether_spec); break; } hclge_fd_get_ext_info(fs, rule); hclge_fd_get_ring_cookie(fs, rule); spin_unlock_bh(&hdev->fd_rule_lock); return 0; } static int hclge_get_all_rules(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd, u32 *rule_locs) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_fd_rule *rule; struct hlist_node *node2; int cnt = 0; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return -EOPNOTSUPP; cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]; spin_lock_bh(&hdev->fd_rule_lock); hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) { if (cnt == cmd->rule_cnt) { spin_unlock_bh(&hdev->fd_rule_lock); return -EMSGSIZE; } if (rule->state == HCLGE_FD_TO_DEL) continue; rule_locs[cnt] = rule->location; cnt++; } spin_unlock_bh(&hdev->fd_rule_lock); cmd->rule_cnt = cnt; return 0; } static void hclge_fd_get_flow_tuples(const struct flow_keys *fkeys, struct hclge_fd_rule_tuples *tuples) { #define flow_ip6_src fkeys->addrs.v6addrs.src.in6_u.u6_addr32 #define flow_ip6_dst fkeys->addrs.v6addrs.dst.in6_u.u6_addr32 tuples->ether_proto = be16_to_cpu(fkeys->basic.n_proto); tuples->ip_proto = fkeys->basic.ip_proto; tuples->dst_port = be16_to_cpu(fkeys->ports.dst); if (fkeys->basic.n_proto == htons(ETH_P_IP)) { tuples->src_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.src); tuples->dst_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.dst); } else { int i; for (i = 0; i < IPV6_SIZE; i++) { tuples->src_ip[i] = be32_to_cpu(flow_ip6_src[i]); tuples->dst_ip[i] = be32_to_cpu(flow_ip6_dst[i]); } } } /* traverse all rules, check whether an existed rule has the same tuples */ static struct hclge_fd_rule * hclge_fd_search_flow_keys(struct hclge_dev *hdev, const struct hclge_fd_rule_tuples *tuples) { struct hclge_fd_rule *rule = NULL; struct hlist_node *node; hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { if (!memcmp(tuples, &rule->tuples, sizeof(*tuples))) return rule; } return NULL; } static void hclge_fd_build_arfs_rule(const struct hclge_fd_rule_tuples *tuples, struct hclge_fd_rule *rule) { rule->unused_tuple = BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) | BIT(INNER_VLAN_TAG_FST) | BIT(INNER_IP_TOS) | BIT(INNER_SRC_PORT); rule->action = 0; rule->vf_id = 0; rule->rule_type = HCLGE_FD_ARFS_ACTIVE; rule->state = HCLGE_FD_TO_ADD; if (tuples->ether_proto == ETH_P_IP) { if (tuples->ip_proto == IPPROTO_TCP) rule->flow_type = TCP_V4_FLOW; else rule->flow_type = UDP_V4_FLOW; } else { if (tuples->ip_proto == IPPROTO_TCP) rule->flow_type = TCP_V6_FLOW; else rule->flow_type = UDP_V6_FLOW; } memcpy(&rule->tuples, tuples, sizeof(rule->tuples)); memset(&rule->tuples_mask, 0xFF, sizeof(rule->tuples_mask)); } static int hclge_add_fd_entry_by_arfs(struct hnae3_handle *handle, u16 queue_id, u16 flow_id, struct flow_keys *fkeys) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_fd_rule_tuples new_tuples = {}; struct hclge_dev *hdev = vport->back; struct hclge_fd_rule *rule; u16 bit_id; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return -EOPNOTSUPP; /* when there is already fd rule existed add by user, * arfs should not work */ spin_lock_bh(&hdev->fd_rule_lock); if (hdev->fd_active_type != HCLGE_FD_ARFS_ACTIVE && hdev->fd_active_type != HCLGE_FD_RULE_NONE) { spin_unlock_bh(&hdev->fd_rule_lock); return -EOPNOTSUPP; } hclge_fd_get_flow_tuples(fkeys, &new_tuples); /* check is there flow director filter existed for this flow, * if not, create a new filter for it; * if filter exist with different queue id, modify the filter; * if filter exist with same queue id, do nothing */ rule = hclge_fd_search_flow_keys(hdev, &new_tuples); if (!rule) { bit_id = find_first_zero_bit(hdev->fd_bmap, MAX_FD_FILTER_NUM); if (bit_id >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) { spin_unlock_bh(&hdev->fd_rule_lock); return -ENOSPC; } rule = kzalloc(sizeof(*rule), GFP_ATOMIC); if (!rule) { spin_unlock_bh(&hdev->fd_rule_lock); return -ENOMEM; } rule->location = bit_id; rule->arfs.flow_id = flow_id; rule->queue_id = queue_id; hclge_fd_build_arfs_rule(&new_tuples, rule); hclge_update_fd_list(hdev, rule->state, rule->location, rule); hdev->fd_active_type = HCLGE_FD_ARFS_ACTIVE; } else if (rule->queue_id != queue_id) { rule->queue_id = queue_id; rule->state = HCLGE_FD_TO_ADD; set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state); hclge_task_schedule(hdev, 0); } spin_unlock_bh(&hdev->fd_rule_lock); return rule->location; } static void hclge_rfs_filter_expire(struct hclge_dev *hdev) { #ifdef CONFIG_RFS_ACCEL struct hnae3_handle *handle = &hdev->vport[0].nic; struct hclge_fd_rule *rule; struct hlist_node *node; spin_lock_bh(&hdev->fd_rule_lock); if (hdev->fd_active_type != HCLGE_FD_ARFS_ACTIVE) { spin_unlock_bh(&hdev->fd_rule_lock); return; } hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { if (rule->state != HCLGE_FD_ACTIVE) continue; if (rps_may_expire_flow(handle->netdev, rule->queue_id, rule->arfs.flow_id, rule->location)) { rule->state = HCLGE_FD_TO_DEL; set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state); } } spin_unlock_bh(&hdev->fd_rule_lock); #endif } /* make sure being called after lock up with fd_rule_lock */ static int hclge_clear_arfs_rules(struct hclge_dev *hdev) { #ifdef CONFIG_RFS_ACCEL struct hclge_fd_rule *rule; struct hlist_node *node; int ret; if (hdev->fd_active_type != HCLGE_FD_ARFS_ACTIVE) return 0; hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { switch (rule->state) { case HCLGE_FD_TO_DEL: case HCLGE_FD_ACTIVE: ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, rule->location, NULL, false); if (ret) return ret; fallthrough; case HCLGE_FD_TO_ADD: hclge_fd_dec_rule_cnt(hdev, rule->location); hlist_del(&rule->rule_node); kfree(rule); break; default: break; } } hclge_sync_fd_state(hdev); #endif return 0; } static void hclge_get_cls_key_basic(const struct flow_rule *flow, struct hclge_fd_rule *rule) { if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_BASIC)) { struct flow_match_basic match; u16 ethtype_key, ethtype_mask; flow_rule_match_basic(flow, &match); ethtype_key = ntohs(match.key->n_proto); ethtype_mask = ntohs(match.mask->n_proto); if (ethtype_key == ETH_P_ALL) { ethtype_key = 0; ethtype_mask = 0; } rule->tuples.ether_proto = ethtype_key; rule->tuples_mask.ether_proto = ethtype_mask; rule->tuples.ip_proto = match.key->ip_proto; rule->tuples_mask.ip_proto = match.mask->ip_proto; } else { rule->unused_tuple |= BIT(INNER_IP_PROTO); rule->unused_tuple |= BIT(INNER_ETH_TYPE); } } static void hclge_get_cls_key_mac(const struct flow_rule *flow, struct hclge_fd_rule *rule) { if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { struct flow_match_eth_addrs match; flow_rule_match_eth_addrs(flow, &match); ether_addr_copy(rule->tuples.dst_mac, match.key->dst); ether_addr_copy(rule->tuples_mask.dst_mac, match.mask->dst); ether_addr_copy(rule->tuples.src_mac, match.key->src); ether_addr_copy(rule->tuples_mask.src_mac, match.mask->src); } else { rule->unused_tuple |= BIT(INNER_DST_MAC); rule->unused_tuple |= BIT(INNER_SRC_MAC); } } static void hclge_get_cls_key_vlan(const struct flow_rule *flow, struct hclge_fd_rule *rule) { if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_VLAN)) { struct flow_match_vlan match; flow_rule_match_vlan(flow, &match); rule->tuples.vlan_tag1 = match.key->vlan_id | (match.key->vlan_priority << VLAN_PRIO_SHIFT); rule->tuples_mask.vlan_tag1 = match.mask->vlan_id | (match.mask->vlan_priority << VLAN_PRIO_SHIFT); } else { rule->unused_tuple |= BIT(INNER_VLAN_TAG_FST); } } static int hclge_get_cls_key_ip(const struct flow_rule *flow, struct hclge_fd_rule *rule, struct netlink_ext_ack *extack) { u16 addr_type = 0; if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_CONTROL)) { struct flow_match_control match; flow_rule_match_control(flow, &match); addr_type = match.key->addr_type; if (flow_rule_has_control_flags(match.mask->flags, extack)) return -EOPNOTSUPP; } if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { struct flow_match_ipv4_addrs match; flow_rule_match_ipv4_addrs(flow, &match); rule->tuples.src_ip[IPV4_INDEX] = be32_to_cpu(match.key->src); rule->tuples_mask.src_ip[IPV4_INDEX] = be32_to_cpu(match.mask->src); rule->tuples.dst_ip[IPV4_INDEX] = be32_to_cpu(match.key->dst); rule->tuples_mask.dst_ip[IPV4_INDEX] = be32_to_cpu(match.mask->dst); } else if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { struct flow_match_ipv6_addrs match; flow_rule_match_ipv6_addrs(flow, &match); be32_to_cpu_array(rule->tuples.src_ip, match.key->src.s6_addr32, IPV6_SIZE); be32_to_cpu_array(rule->tuples_mask.src_ip, match.mask->src.s6_addr32, IPV6_SIZE); be32_to_cpu_array(rule->tuples.dst_ip, match.key->dst.s6_addr32, IPV6_SIZE); be32_to_cpu_array(rule->tuples_mask.dst_ip, match.mask->dst.s6_addr32, IPV6_SIZE); } else { rule->unused_tuple |= BIT(INNER_SRC_IP); rule->unused_tuple |= BIT(INNER_DST_IP); } return 0; } static void hclge_get_cls_key_port(const struct flow_rule *flow, struct hclge_fd_rule *rule) { if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_PORTS)) { struct flow_match_ports match; flow_rule_match_ports(flow, &match); rule->tuples.src_port = be16_to_cpu(match.key->src); rule->tuples_mask.src_port = be16_to_cpu(match.mask->src); rule->tuples.dst_port = be16_to_cpu(match.key->dst); rule->tuples_mask.dst_port = be16_to_cpu(match.mask->dst); } else { rule->unused_tuple |= BIT(INNER_SRC_PORT); rule->unused_tuple |= BIT(INNER_DST_PORT); } } static int hclge_parse_cls_flower(struct hclge_dev *hdev, struct flow_cls_offload *cls_flower, struct hclge_fd_rule *rule) { struct flow_rule *flow = flow_cls_offload_flow_rule(cls_flower); struct netlink_ext_ack *extack = cls_flower->common.extack; struct flow_dissector *dissector = flow->match.dissector; int ret; if (dissector->used_keys & ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) | BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) | BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) | BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) | BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) | BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) | BIT_ULL(FLOW_DISSECTOR_KEY_PORTS))) { dev_err(&hdev->pdev->dev, "unsupported key set: %#llx\n", dissector->used_keys); return -EOPNOTSUPP; } hclge_get_cls_key_basic(flow, rule); hclge_get_cls_key_mac(flow, rule); hclge_get_cls_key_vlan(flow, rule); ret = hclge_get_cls_key_ip(flow, rule, extack); if (ret) return ret; hclge_get_cls_key_port(flow, rule); return 0; } static int hclge_check_cls_flower(struct hclge_dev *hdev, struct flow_cls_offload *cls_flower, int tc) { u32 prio = cls_flower->common.prio; if (tc < 0 || tc > hdev->tc_max) { dev_err(&hdev->pdev->dev, "invalid traffic class\n"); return -EINVAL; } if (prio == 0 || prio > hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) { dev_err(&hdev->pdev->dev, "prio %u should be in range[1, %u]\n", prio, hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]); return -EINVAL; } if (test_bit(prio - 1, hdev->fd_bmap)) { dev_err(&hdev->pdev->dev, "prio %u is already used\n", prio); return -EINVAL; } return 0; } static int hclge_add_cls_flower(struct hnae3_handle *handle, struct flow_cls_offload *cls_flower, int tc) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_fd_rule *rule; int ret; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) { dev_err(&hdev->pdev->dev, "cls flower is not supported\n"); return -EOPNOTSUPP; } ret = hclge_check_cls_flower(hdev, cls_flower, tc); if (ret) { dev_err(&hdev->pdev->dev, "failed to check cls flower params, ret = %d\n", ret); return ret; } rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (!rule) return -ENOMEM; ret = hclge_parse_cls_flower(hdev, cls_flower, rule); if (ret) { kfree(rule); return ret; } rule->action = HCLGE_FD_ACTION_SELECT_TC; rule->cls_flower.tc = tc; rule->location = cls_flower->common.prio - 1; rule->vf_id = 0; rule->cls_flower.cookie = cls_flower->cookie; rule->rule_type = HCLGE_FD_TC_FLOWER_ACTIVE; ret = hclge_add_fd_entry_common(hdev, rule); if (ret) kfree(rule); return ret; } static struct hclge_fd_rule *hclge_find_cls_flower(struct hclge_dev *hdev, unsigned long cookie) { struct hclge_fd_rule *rule; struct hlist_node *node; hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { if (rule->cls_flower.cookie == cookie) return rule; } return NULL; } static int hclge_del_cls_flower(struct hnae3_handle *handle, struct flow_cls_offload *cls_flower) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_fd_rule *rule; int ret; if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return -EOPNOTSUPP; spin_lock_bh(&hdev->fd_rule_lock); rule = hclge_find_cls_flower(hdev, cls_flower->cookie); if (!rule) { spin_unlock_bh(&hdev->fd_rule_lock); return -EINVAL; } ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, rule->location, NULL, false); if (ret) { /* if tcam config fail, set rule state to TO_DEL, * so the rule will be deleted when periodic * task being scheduled. */ hclge_update_fd_list(hdev, HCLGE_FD_TO_DEL, rule->location, NULL); set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state); spin_unlock_bh(&hdev->fd_rule_lock); return ret; } hclge_update_fd_list(hdev, HCLGE_FD_DELETED, rule->location, NULL); spin_unlock_bh(&hdev->fd_rule_lock); return 0; } static void hclge_sync_fd_list(struct hclge_dev *hdev, struct hlist_head *hlist) { struct hclge_fd_rule *rule; struct hlist_node *node; int ret = 0; if (!test_and_clear_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state)) return; spin_lock_bh(&hdev->fd_rule_lock); hlist_for_each_entry_safe(rule, node, hlist, rule_node) { switch (rule->state) { case HCLGE_FD_TO_ADD: ret = hclge_fd_config_rule(hdev, rule); if (ret) goto out; rule->state = HCLGE_FD_ACTIVE; break; case HCLGE_FD_TO_DEL: ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, rule->location, NULL, false); if (ret) goto out; hclge_fd_dec_rule_cnt(hdev, rule->location); hclge_fd_free_node(hdev, rule); break; default: break; } } out: if (ret) set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state); spin_unlock_bh(&hdev->fd_rule_lock); } static void hclge_sync_fd_table(struct hclge_dev *hdev) { if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) return; if (test_and_clear_bit(HCLGE_STATE_FD_CLEAR_ALL, &hdev->state)) { bool clear_list = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE; hclge_clear_fd_rules_in_list(hdev, clear_list); } hclge_sync_fd_user_def_cfg(hdev, false); hclge_sync_fd_list(hdev, &hdev->fd_rule_list); } static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return hclge_read_dev(&hdev->hw, HCLGE_GLOBAL_RESET_REG) || hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING); } static bool hclge_get_cmdq_stat(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state); } static bool hclge_ae_dev_resetting(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state); } static unsigned long hclge_ae_dev_reset_cnt(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return hdev->rst_stats.hw_reset_done_cnt; } static void hclge_enable_fd(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; hdev->fd_en = enable; if (!enable) set_bit(HCLGE_STATE_FD_CLEAR_ALL, &hdev->state); else hclge_restore_fd_entries(handle); hclge_task_schedule(hdev, 0); } static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) { #define HCLGE_LINK_STATUS_WAIT_CNT 3 struct hclge_desc desc; struct hclge_config_mac_mode_cmd *req = (struct hclge_config_mac_mode_cmd *)desc.data; u32 loop_en = 0; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, false); if (enable) { hnae3_set_bit(loop_en, HCLGE_MAC_TX_EN_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_RX_EN_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_PAD_TX_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_PAD_RX_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_FCS_TX_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_RX_FCS_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_RX_FCS_STRIP_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_TX_OVERSIZE_TRUNCATE_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_RX_OVERSIZE_TRUNCATE_B, 1U); hnae3_set_bit(loop_en, HCLGE_MAC_TX_UNDER_MIN_ERR_B, 1U); } req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "mac enable fail, ret =%d.\n", ret); return; } if (!enable) hclge_mac_link_status_wait(hdev, HCLGE_LINK_STATUS_DOWN, HCLGE_LINK_STATUS_WAIT_CNT); } static int hclge_config_switch_param(struct hclge_dev *hdev, int vfid, u8 switch_param, u8 param_mask) { struct hclge_mac_vlan_switch_cmd *req; struct hclge_desc desc; u32 func_id; int ret; func_id = hclge_get_port_number(HOST_PORT, 0, vfid, 0); req = (struct hclge_mac_vlan_switch_cmd *)desc.data; /* read current config parameter */ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_SWITCH_PARAM, true); req->roce_sel = HCLGE_MAC_VLAN_NIC_SEL; req->func_id = cpu_to_le32(func_id); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "read mac vlan switch parameter fail, ret = %d\n", ret); return ret; } /* modify and write new config parameter */ hclge_comm_cmd_reuse_desc(&desc, false); req->switch_param = (req->switch_param & param_mask) | switch_param; req->param_mask = param_mask; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "set mac vlan switch parameter fail, ret = %d\n", ret); return ret; } static void hclge_phy_link_status_wait(struct hclge_dev *hdev, int link_ret) { #define HCLGE_PHY_LINK_STATUS_NUM 200 struct phy_device *phydev = hdev->hw.mac.phydev; int i = 0; int ret; do { ret = phy_read_status(phydev); if (ret) { dev_err(&hdev->pdev->dev, "phy update link status fail, ret = %d\n", ret); return; } if (phydev->link == link_ret) break; msleep(HCLGE_LINK_STATUS_MS); } while (++i < HCLGE_PHY_LINK_STATUS_NUM); } static int hclge_mac_link_status_wait(struct hclge_dev *hdev, int link_ret, int wait_cnt) { int link_status; int i = 0; int ret; do { ret = hclge_get_mac_link_status(hdev, &link_status); if (ret) return ret; if (link_status == link_ret) return 0; msleep(HCLGE_LINK_STATUS_MS); } while (++i < wait_cnt); return -EBUSY; } static int hclge_mac_phy_link_status_wait(struct hclge_dev *hdev, bool en, bool is_phy) { #define HCLGE_MAC_LINK_STATUS_NUM 100 int link_ret; link_ret = en ? HCLGE_LINK_STATUS_UP : HCLGE_LINK_STATUS_DOWN; if (is_phy) hclge_phy_link_status_wait(hdev, link_ret); return hclge_mac_link_status_wait(hdev, link_ret, HCLGE_MAC_LINK_STATUS_NUM); } static int hclge_set_app_loopback(struct hclge_dev *hdev, bool en) { struct hclge_config_mac_mode_cmd *req; struct hclge_desc desc; u32 loop_en; int ret; req = (struct hclge_config_mac_mode_cmd *)&desc.data[0]; /* 1 Read out the MAC mode config at first */ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAC_MODE, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "mac loopback get fail, ret =%d.\n", ret); return ret; } /* 2 Then setup the loopback flag */ loop_en = le32_to_cpu(req->txrx_pad_fcs_loop_en); hnae3_set_bit(loop_en, HCLGE_MAC_APP_LP_B, en ? 1 : 0); req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en); /* 3 Config mac work mode with loopback flag * and its original configure parameters */ hclge_comm_cmd_reuse_desc(&desc, false); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "mac loopback set fail, ret =%d.\n", ret); return ret; } static int hclge_cfg_common_loopback_cmd_send(struct hclge_dev *hdev, bool en, enum hnae3_loop loop_mode) { struct hclge_common_lb_cmd *req; struct hclge_desc desc; u8 loop_mode_b; int ret; req = (struct hclge_common_lb_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMMON_LOOPBACK, false); switch (loop_mode) { case HNAE3_LOOP_SERIAL_SERDES: loop_mode_b = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B; break; case HNAE3_LOOP_PARALLEL_SERDES: loop_mode_b = HCLGE_CMD_SERDES_PARALLEL_INNER_LOOP_B; break; case HNAE3_LOOP_PHY: loop_mode_b = HCLGE_CMD_GE_PHY_INNER_LOOP_B; break; default: dev_err(&hdev->pdev->dev, "unsupported loopback mode %d\n", loop_mode); return -ENOTSUPP; } req->mask = loop_mode_b; if (en) req->enable = loop_mode_b; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "failed to send loopback cmd, loop_mode = %d, ret = %d\n", loop_mode, ret); return ret; } static int hclge_cfg_common_loopback_wait(struct hclge_dev *hdev) { #define HCLGE_COMMON_LB_RETRY_MS 10 #define HCLGE_COMMON_LB_RETRY_NUM 100 struct hclge_common_lb_cmd *req; struct hclge_desc desc; u32 i = 0; int ret; req = (struct hclge_common_lb_cmd *)desc.data; do { msleep(HCLGE_COMMON_LB_RETRY_MS); hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_COMMON_LOOPBACK, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to get loopback done status, ret = %d\n", ret); return ret; } } while (++i < HCLGE_COMMON_LB_RETRY_NUM && !(req->result & HCLGE_CMD_COMMON_LB_DONE_B)); if (!(req->result & HCLGE_CMD_COMMON_LB_DONE_B)) { dev_err(&hdev->pdev->dev, "wait loopback timeout\n"); return -EBUSY; } else if (!(req->result & HCLGE_CMD_COMMON_LB_SUCCESS_B)) { dev_err(&hdev->pdev->dev, "failed to do loopback test\n"); return -EIO; } return 0; } static int hclge_cfg_common_loopback(struct hclge_dev *hdev, bool en, enum hnae3_loop loop_mode) { int ret; ret = hclge_cfg_common_loopback_cmd_send(hdev, en, loop_mode); if (ret) return ret; return hclge_cfg_common_loopback_wait(hdev); } static int hclge_set_common_loopback(struct hclge_dev *hdev, bool en, enum hnae3_loop loop_mode) { int ret; ret = hclge_cfg_common_loopback(hdev, en, loop_mode); if (ret) return ret; hclge_cfg_mac_mode(hdev, en); ret = hclge_mac_phy_link_status_wait(hdev, en, false); if (ret) dev_err(&hdev->pdev->dev, "serdes loopback config mac mode timeout\n"); return ret; } static int hclge_enable_phy_loopback(struct hclge_dev *hdev, struct phy_device *phydev) { int ret; if (!phydev->suspended) { ret = phy_suspend(phydev); if (ret) return ret; } ret = phy_resume(phydev); if (ret) return ret; return phy_loopback(phydev, true); } static int hclge_disable_phy_loopback(struct hclge_dev *hdev, struct phy_device *phydev) { int ret; ret = phy_loopback(phydev, false); if (ret) return ret; return phy_suspend(phydev); } static int hclge_set_phy_loopback(struct hclge_dev *hdev, bool en) { struct phy_device *phydev = hdev->hw.mac.phydev; int ret; if (!phydev) { if (hnae3_dev_phy_imp_supported(hdev)) return hclge_set_common_loopback(hdev, en, HNAE3_LOOP_PHY); return -ENOTSUPP; } if (en) ret = hclge_enable_phy_loopback(hdev, phydev); else ret = hclge_disable_phy_loopback(hdev, phydev); if (ret) { dev_err(&hdev->pdev->dev, "set phy loopback fail, ret = %d\n", ret); return ret; } hclge_cfg_mac_mode(hdev, en); ret = hclge_mac_phy_link_status_wait(hdev, en, true); if (ret) dev_err(&hdev->pdev->dev, "phy loopback config mac mode timeout\n"); return ret; } static int hclge_tqp_enable_cmd_send(struct hclge_dev *hdev, u16 tqp_id, u16 stream_id, bool enable) { struct hclge_desc desc; struct hclge_cfg_com_tqp_queue_cmd *req = (struct hclge_cfg_com_tqp_queue_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_COM_TQP_QUEUE, false); req->tqp_id = cpu_to_le16(tqp_id); req->stream_id = cpu_to_le16(stream_id); if (enable) req->enable |= 1U << HCLGE_TQP_ENABLE_B; return hclge_cmd_send(&hdev->hw, &desc, 1); } static int hclge_tqp_enable(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int ret; u16 i; for (i = 0; i < handle->kinfo.num_tqps; i++) { ret = hclge_tqp_enable_cmd_send(hdev, i, 0, enable); if (ret) return ret; } return 0; } static int hclge_set_loopback(struct hnae3_handle *handle, enum hnae3_loop loop_mode, bool en) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int ret = 0; /* Loopback can be enabled in three places: SSU, MAC, and serdes. By * default, SSU loopback is enabled, so if the SMAC and the DMAC are * the same, the packets are looped back in the SSU. If SSU loopback * is disabled, packets can reach MAC even if SMAC is the same as DMAC. */ if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) { u8 switch_param = en ? 0 : BIT(HCLGE_SWITCH_ALW_LPBK_B); ret = hclge_config_switch_param(hdev, PF_VPORT_ID, switch_param, HCLGE_SWITCH_ALW_LPBK_MASK); if (ret) return ret; } switch (loop_mode) { case HNAE3_LOOP_APP: ret = hclge_set_app_loopback(hdev, en); break; case HNAE3_LOOP_SERIAL_SERDES: case HNAE3_LOOP_PARALLEL_SERDES: ret = hclge_set_common_loopback(hdev, en, loop_mode); break; case HNAE3_LOOP_PHY: ret = hclge_set_phy_loopback(hdev, en); break; case HNAE3_LOOP_EXTERNAL: break; default: ret = -ENOTSUPP; dev_err(&hdev->pdev->dev, "loop_mode %d is not supported\n", loop_mode); break; } if (ret) return ret; ret = hclge_tqp_enable(handle, en); if (ret) dev_err(&hdev->pdev->dev, "failed to %s tqp in loopback, ret = %d\n", en ? "enable" : "disable", ret); return ret; } static int hclge_set_default_loopback(struct hclge_dev *hdev) { int ret; ret = hclge_set_app_loopback(hdev, false); if (ret) return ret; ret = hclge_cfg_common_loopback(hdev, false, HNAE3_LOOP_SERIAL_SERDES); if (ret) return ret; return hclge_cfg_common_loopback(hdev, false, HNAE3_LOOP_PARALLEL_SERDES); } static void hclge_flush_link_update(struct hclge_dev *hdev) { #define HCLGE_FLUSH_LINK_TIMEOUT 100000 unsigned long last = hdev->serv_processed_cnt; int i = 0; while (test_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state) && i++ < HCLGE_FLUSH_LINK_TIMEOUT && last == hdev->serv_processed_cnt) usleep_range(1, 1); } static void hclge_set_timer_task(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; if (enable) { hclge_task_schedule(hdev, 0); } else { /* Set the DOWN flag here to disable link updating */ set_bit(HCLGE_STATE_DOWN, &hdev->state); smp_mb__after_atomic(); /* flush memory to make sure DOWN is seen by service task */ hclge_flush_link_update(hdev); } } static int hclge_ae_start(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; /* mac enable */ hclge_cfg_mac_mode(hdev, true); clear_bit(HCLGE_STATE_DOWN, &hdev->state); hdev->hw.mac.link = 0; /* reset tqp stats */ hclge_comm_reset_tqp_stats(handle); hclge_mac_start_phy(hdev); return 0; } static void hclge_ae_stop(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; set_bit(HCLGE_STATE_DOWN, &hdev->state); spin_lock_bh(&hdev->fd_rule_lock); hclge_clear_arfs_rules(hdev); spin_unlock_bh(&hdev->fd_rule_lock); /* If it is not PF reset or FLR, the firmware will disable the MAC, * so it only need to stop phy here. */ if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) { hclge_pfc_pause_en_cfg(hdev, HCLGE_PFC_TX_RX_DISABLE, HCLGE_PFC_DISABLE); if (hdev->reset_type != HNAE3_FUNC_RESET && hdev->reset_type != HNAE3_FLR_RESET) { hclge_mac_stop_phy(hdev); hclge_update_link_status(hdev); return; } } hclge_reset_tqp(handle); hclge_config_mac_tnl_int(hdev, false); /* Mac disable */ hclge_cfg_mac_mode(hdev, false); hclge_mac_stop_phy(hdev); /* reset tqp stats */ hclge_comm_reset_tqp_stats(handle); hclge_update_link_status(hdev); } int hclge_vport_start(struct hclge_vport *vport) { struct hclge_dev *hdev = vport->back; set_bit(HCLGE_VPORT_STATE_INITED, &vport->state); set_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); vport->last_active_jiffies = jiffies; vport->need_notify = 0; if (test_bit(vport->vport_id, hdev->vport_config_block)) { if (vport->vport_id) { hclge_restore_mac_table_common(vport); hclge_restore_vport_vlan_table(vport); } else { hclge_restore_hw_table(hdev); } } clear_bit(vport->vport_id, hdev->vport_config_block); return 0; } void hclge_vport_stop(struct hclge_vport *vport) { clear_bit(HCLGE_VPORT_STATE_INITED, &vport->state); clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); vport->need_notify = 0; } static int hclge_client_start(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); return hclge_vport_start(vport); } static void hclge_client_stop(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); hclge_vport_stop(vport); } static int hclge_get_mac_vlan_cmd_status(struct hclge_vport *vport, u16 cmdq_resp, u8 resp_code, enum hclge_mac_vlan_tbl_opcode op) { struct hclge_dev *hdev = vport->back; if (cmdq_resp) { dev_err(&hdev->pdev->dev, "cmdq execute failed for get_mac_vlan_cmd_status,status=%u.\n", cmdq_resp); return -EIO; } if (op == HCLGE_MAC_VLAN_ADD) { if (!resp_code || resp_code == 1) return 0; else if (resp_code == HCLGE_ADD_UC_OVERFLOW || resp_code == HCLGE_ADD_MC_OVERFLOW) return -ENOSPC; dev_err(&hdev->pdev->dev, "add mac addr failed for undefined, code=%u.\n", resp_code); return -EIO; } else if (op == HCLGE_MAC_VLAN_REMOVE) { if (!resp_code) { return 0; } else if (resp_code == 1) { dev_dbg(&hdev->pdev->dev, "remove mac addr failed for miss.\n"); return -ENOENT; } dev_err(&hdev->pdev->dev, "remove mac addr failed for undefined, code=%u.\n", resp_code); return -EIO; } else if (op == HCLGE_MAC_VLAN_LKUP) { if (!resp_code) { return 0; } else if (resp_code == 1) { dev_dbg(&hdev->pdev->dev, "lookup mac addr failed for miss.\n"); return -ENOENT; } dev_err(&hdev->pdev->dev, "lookup mac addr failed for undefined, code=%u.\n", resp_code); return -EIO; } dev_err(&hdev->pdev->dev, "unknown opcode for get_mac_vlan_cmd_status, opcode=%d.\n", op); return -EINVAL; } static int hclge_update_desc_vfid(struct hclge_desc *desc, int vfid, bool clr) { #define HCLGE_VF_NUM_IN_FIRST_DESC 192 unsigned int word_num; unsigned int bit_num; if (vfid > 255 || vfid < 0) return -EIO; if (vfid >= 0 && vfid < HCLGE_VF_NUM_IN_FIRST_DESC) { word_num = vfid / 32; bit_num = vfid % 32; if (clr) desc[1].data[word_num] &= cpu_to_le32(~(1 << bit_num)); else desc[1].data[word_num] |= cpu_to_le32(1 << bit_num); } else { word_num = (vfid - HCLGE_VF_NUM_IN_FIRST_DESC) / 32; bit_num = vfid % 32; if (clr) desc[2].data[word_num] &= cpu_to_le32(~(1 << bit_num)); else desc[2].data[word_num] |= cpu_to_le32(1 << bit_num); } return 0; } static bool hclge_is_all_function_id_zero(struct hclge_desc *desc) { #define HCLGE_DESC_NUMBER 3 #define HCLGE_FUNC_NUMBER_PER_DESC 6 int i, j; for (i = 1; i < HCLGE_DESC_NUMBER; i++) for (j = 0; j < HCLGE_FUNC_NUMBER_PER_DESC; j++) if (desc[i].data[j]) return false; return true; } static void hclge_prepare_mac_addr(struct hclge_mac_vlan_tbl_entry_cmd *new_req, const u8 *addr, bool is_mc) { const unsigned char *mac_addr = addr; u32 high_val = mac_addr[2] << 16 | (mac_addr[3] << 24) | (mac_addr[0]) | (mac_addr[1] << 8); u32 low_val = mac_addr[4] | (mac_addr[5] << 8); hnae3_set_bit(new_req->flags, HCLGE_MAC_VLAN_BIT0_EN_B, 1); if (is_mc) { hnae3_set_bit(new_req->entry_type, HCLGE_MAC_VLAN_BIT1_EN_B, 1); hnae3_set_bit(new_req->mc_mac_en, HCLGE_MAC_VLAN_BIT0_EN_B, 1); } new_req->mac_addr_hi32 = cpu_to_le32(high_val); new_req->mac_addr_lo16 = cpu_to_le16(low_val & 0xffff); } static int hclge_remove_mac_vlan_tbl(struct hclge_vport *vport, struct hclge_mac_vlan_tbl_entry_cmd *req) { struct hclge_dev *hdev = vport->back; struct hclge_desc desc; u8 resp_code; u16 retval; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_REMOVE, false); memcpy(desc.data, req, sizeof(struct hclge_mac_vlan_tbl_entry_cmd)); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "del mac addr failed for cmd_send, ret =%d.\n", ret); return ret; } resp_code = (le32_to_cpu(desc.data[0]) >> 8) & 0xff; retval = le16_to_cpu(desc.retval); return hclge_get_mac_vlan_cmd_status(vport, retval, resp_code, HCLGE_MAC_VLAN_REMOVE); } static int hclge_lookup_mac_vlan_tbl(struct hclge_vport *vport, struct hclge_mac_vlan_tbl_entry_cmd *req, struct hclge_desc *desc, bool is_mc) { struct hclge_dev *hdev = vport->back; u8 resp_code; u16 retval; int ret; hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_MAC_VLAN_ADD, true); if (is_mc) { desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); memcpy(desc[0].data, req, sizeof(struct hclge_mac_vlan_tbl_entry_cmd)); hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_MAC_VLAN_ADD, true); desc[1].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); hclge_cmd_setup_basic_desc(&desc[2], HCLGE_OPC_MAC_VLAN_ADD, true); ret = hclge_cmd_send(&hdev->hw, desc, 3); } else { memcpy(desc[0].data, req, sizeof(struct hclge_mac_vlan_tbl_entry_cmd)); ret = hclge_cmd_send(&hdev->hw, desc, 1); } if (ret) { dev_err(&hdev->pdev->dev, "lookup mac addr failed for cmd_send, ret =%d.\n", ret); return ret; } resp_code = (le32_to_cpu(desc[0].data[0]) >> 8) & 0xff; retval = le16_to_cpu(desc[0].retval); return hclge_get_mac_vlan_cmd_status(vport, retval, resp_code, HCLGE_MAC_VLAN_LKUP); } static int hclge_add_mac_vlan_tbl(struct hclge_vport *vport, struct hclge_mac_vlan_tbl_entry_cmd *req, struct hclge_desc *mc_desc) { struct hclge_dev *hdev = vport->back; int cfg_status; u8 resp_code; u16 retval; int ret; if (!mc_desc) { struct hclge_desc desc; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ADD, false); memcpy(desc.data, req, sizeof(struct hclge_mac_vlan_tbl_entry_cmd)); ret = hclge_cmd_send(&hdev->hw, &desc, 1); resp_code = (le32_to_cpu(desc.data[0]) >> 8) & 0xff; retval = le16_to_cpu(desc.retval); cfg_status = hclge_get_mac_vlan_cmd_status(vport, retval, resp_code, HCLGE_MAC_VLAN_ADD); } else { hclge_comm_cmd_reuse_desc(&mc_desc[0], false); mc_desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); hclge_comm_cmd_reuse_desc(&mc_desc[1], false); mc_desc[1].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); hclge_comm_cmd_reuse_desc(&mc_desc[2], false); mc_desc[2].flag &= cpu_to_le16(~HCLGE_COMM_CMD_FLAG_NEXT); memcpy(mc_desc[0].data, req, sizeof(struct hclge_mac_vlan_tbl_entry_cmd)); ret = hclge_cmd_send(&hdev->hw, mc_desc, 3); resp_code = (le32_to_cpu(mc_desc[0].data[0]) >> 8) & 0xff; retval = le16_to_cpu(mc_desc[0].retval); cfg_status = hclge_get_mac_vlan_cmd_status(vport, retval, resp_code, HCLGE_MAC_VLAN_ADD); } if (ret) { dev_err(&hdev->pdev->dev, "add mac addr failed for cmd_send, ret =%d.\n", ret); return ret; } return cfg_status; } static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size, u16 *allocated_size) { struct hclge_umv_spc_alc_cmd *req; struct hclge_desc desc; int ret; req = (struct hclge_umv_spc_alc_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_ALLOCATE, false); req->space_size = cpu_to_le32(space_size); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to set umv space, ret = %d\n", ret); return ret; } *allocated_size = le32_to_cpu(desc.data[1]); return 0; } static int hclge_init_umv_space(struct hclge_dev *hdev) { u16 allocated_size = 0; int ret; ret = hclge_set_umv_space(hdev, hdev->wanted_umv_size, &allocated_size); if (ret) return ret; if (allocated_size < hdev->wanted_umv_size) dev_warn(&hdev->pdev->dev, "failed to alloc umv space, want %u, get %u\n", hdev->wanted_umv_size, allocated_size); hdev->max_umv_size = allocated_size; hdev->priv_umv_size = hdev->max_umv_size / (hdev->num_alloc_vport + 1); hdev->share_umv_size = hdev->priv_umv_size + hdev->max_umv_size % (hdev->num_alloc_vport + 1); if (hdev->ae_dev->dev_specs.mc_mac_size) set_bit(HNAE3_DEV_SUPPORT_MC_MAC_MNG_B, hdev->ae_dev->caps); return 0; } static void hclge_reset_umv_space(struct hclge_dev *hdev) { struct hclge_vport *vport; int i; for (i = 0; i < hdev->num_alloc_vport; i++) { vport = &hdev->vport[i]; vport->used_umv_num = 0; } mutex_lock(&hdev->vport_lock); hdev->share_umv_size = hdev->priv_umv_size + hdev->max_umv_size % (hdev->num_alloc_vport + 1); mutex_unlock(&hdev->vport_lock); hdev->used_mc_mac_num = 0; } static bool hclge_is_umv_space_full(struct hclge_vport *vport, bool need_lock) { struct hclge_dev *hdev = vport->back; bool is_full; if (need_lock) mutex_lock(&hdev->vport_lock); is_full = (vport->used_umv_num >= hdev->priv_umv_size && hdev->share_umv_size == 0); if (need_lock) mutex_unlock(&hdev->vport_lock); return is_full; } static void hclge_update_umv_space(struct hclge_vport *vport, bool is_free) { struct hclge_dev *hdev = vport->back; if (is_free) { if (vport->used_umv_num > hdev->priv_umv_size) hdev->share_umv_size++; if (vport->used_umv_num > 0) vport->used_umv_num--; } else { if (vport->used_umv_num >= hdev->priv_umv_size && hdev->share_umv_size > 0) hdev->share_umv_size--; vport->used_umv_num++; } } static struct hclge_mac_node *hclge_find_mac_node(struct list_head *list, const u8 *mac_addr) { struct hclge_mac_node *mac_node, *tmp; list_for_each_entry_safe(mac_node, tmp, list, node) if (ether_addr_equal(mac_addr, mac_node->mac_addr)) return mac_node; return NULL; } static void hclge_update_mac_node(struct hclge_mac_node *mac_node, enum HCLGE_MAC_NODE_STATE state) { switch (state) { /* from set_rx_mode or tmp_add_list */ case HCLGE_MAC_TO_ADD: if (mac_node->state == HCLGE_MAC_TO_DEL) mac_node->state = HCLGE_MAC_ACTIVE; break; /* only from set_rx_mode */ case HCLGE_MAC_TO_DEL: if (mac_node->state == HCLGE_MAC_TO_ADD) { list_del(&mac_node->node); kfree(mac_node); } else { mac_node->state = HCLGE_MAC_TO_DEL; } break; /* only from tmp_add_list, the mac_node->state won't be * ACTIVE. */ case HCLGE_MAC_ACTIVE: if (mac_node->state == HCLGE_MAC_TO_ADD) mac_node->state = HCLGE_MAC_ACTIVE; break; } } int hclge_update_mac_list(struct hclge_vport *vport, enum HCLGE_MAC_NODE_STATE state, enum HCLGE_MAC_ADDR_TYPE mac_type, const unsigned char *addr) { char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev = vport->back; struct hclge_mac_node *mac_node; struct list_head *list; list = (mac_type == HCLGE_MAC_ADDR_UC) ? &vport->uc_mac_list : &vport->mc_mac_list; spin_lock_bh(&vport->mac_list_lock); /* if the mac addr is already in the mac list, no need to add a new * one into it, just check the mac addr state, convert it to a new * state, or just remove it, or do nothing. */ mac_node = hclge_find_mac_node(list, addr); if (mac_node) { hclge_update_mac_node(mac_node, state); spin_unlock_bh(&vport->mac_list_lock); set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state); return 0; } /* if this address is never added, unnecessary to delete */ if (state == HCLGE_MAC_TO_DEL) { spin_unlock_bh(&vport->mac_list_lock); hnae3_format_mac_addr(format_mac_addr, addr); dev_err(&hdev->pdev->dev, "failed to delete address %s from mac list\n", format_mac_addr); return -ENOENT; } mac_node = kzalloc(sizeof(*mac_node), GFP_ATOMIC); if (!mac_node) { spin_unlock_bh(&vport->mac_list_lock); return -ENOMEM; } set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state); mac_node->state = state; ether_addr_copy(mac_node->mac_addr, addr); list_add_tail(&mac_node->node, list); spin_unlock_bh(&vport->mac_list_lock); return 0; } static int hclge_add_uc_addr(struct hnae3_handle *handle, const unsigned char *addr) { struct hclge_vport *vport = hclge_get_vport(handle); return hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, HCLGE_MAC_ADDR_UC, addr); } int hclge_add_uc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev = vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; struct hclge_desc desc; u16 egress_port = 0; int ret; /* mac addr check */ if (is_zero_ether_addr(addr) || is_broadcast_ether_addr(addr) || is_multicast_ether_addr(addr)) { hnae3_format_mac_addr(format_mac_addr, addr); dev_err(&hdev->pdev->dev, "Set_uc mac err! invalid mac:%s. is_zero:%d,is_br=%d,is_mul=%d\n", format_mac_addr, is_zero_ether_addr(addr), is_broadcast_ether_addr(addr), is_multicast_ether_addr(addr)); return -EINVAL; } memset(&req, 0, sizeof(req)); hnae3_set_field(egress_port, HCLGE_MAC_EPORT_VFID_M, HCLGE_MAC_EPORT_VFID_S, vport->vport_id); req.egress_port = cpu_to_le16(egress_port); hclge_prepare_mac_addr(&req, addr, false); /* Lookup the mac address in the mac_vlan table, and add * it if the entry is inexistent. Repeated unicast entry * is not allowed in the mac vlan table. */ ret = hclge_lookup_mac_vlan_tbl(vport, &req, &desc, false); if (ret == -ENOENT) { mutex_lock(&hdev->vport_lock); if (!hclge_is_umv_space_full(vport, false)) { ret = hclge_add_mac_vlan_tbl(vport, &req, NULL); if (!ret) hclge_update_umv_space(vport, false); mutex_unlock(&hdev->vport_lock); return ret; } mutex_unlock(&hdev->vport_lock); if (!(vport->overflow_promisc_flags & HNAE3_OVERFLOW_UPE)) dev_err(&hdev->pdev->dev, "UC MAC table full(%u)\n", hdev->priv_umv_size); return -ENOSPC; } /* check if we just hit the duplicate */ if (!ret) return -EEXIST; return ret; } static int hclge_rm_uc_addr(struct hnae3_handle *handle, const unsigned char *addr) { struct hclge_vport *vport = hclge_get_vport(handle); return hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL, HCLGE_MAC_ADDR_UC, addr); } int hclge_rm_uc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev = vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; int ret; /* mac addr check */ if (is_zero_ether_addr(addr) || is_broadcast_ether_addr(addr) || is_multicast_ether_addr(addr)) { hnae3_format_mac_addr(format_mac_addr, addr); dev_dbg(&hdev->pdev->dev, "Remove mac err! invalid mac:%s.\n", format_mac_addr); return -EINVAL; } memset(&req, 0, sizeof(req)); hnae3_set_bit(req.entry_type, HCLGE_MAC_VLAN_BIT0_EN_B, 0); hclge_prepare_mac_addr(&req, addr, false); ret = hclge_remove_mac_vlan_tbl(vport, &req); if (!ret || ret == -ENOENT) { mutex_lock(&hdev->vport_lock); hclge_update_umv_space(vport, true); mutex_unlock(&hdev->vport_lock); return 0; } return ret; } static int hclge_add_mc_addr(struct hnae3_handle *handle, const unsigned char *addr) { struct hclge_vport *vport = hclge_get_vport(handle); return hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, HCLGE_MAC_ADDR_MC, addr); } int hclge_add_mc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev = vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; struct hclge_desc desc[3]; bool is_new_addr = false; int status; /* mac addr check */ if (!is_multicast_ether_addr(addr)) { hnae3_format_mac_addr(format_mac_addr, addr); dev_err(&hdev->pdev->dev, "Add mc mac err! invalid mac:%s.\n", format_mac_addr); return -EINVAL; } memset(&req, 0, sizeof(req)); hclge_prepare_mac_addr(&req, addr, true); status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true); if (status) { if (hnae3_ae_dev_mc_mac_mng_supported(hdev->ae_dev) && hdev->used_mc_mac_num >= hdev->ae_dev->dev_specs.mc_mac_size) goto err_no_space; is_new_addr = true; /* This mac addr do not exist, add new entry for it */ memset(desc[0].data, 0, sizeof(desc[0].data)); memset(desc[1].data, 0, sizeof(desc[0].data)); memset(desc[2].data, 0, sizeof(desc[0].data)); } status = hclge_update_desc_vfid(desc, vport->vport_id, false); if (status) return status; status = hclge_add_mac_vlan_tbl(vport, &req, desc); if (status == -ENOSPC) goto err_no_space; else if (!status && is_new_addr) hdev->used_mc_mac_num++; return status; err_no_space: /* if already overflow, not to print each time */ if (!(vport->overflow_promisc_flags & HNAE3_OVERFLOW_MPE)) { vport->overflow_promisc_flags |= HNAE3_OVERFLOW_MPE; dev_err(&hdev->pdev->dev, "mc mac vlan table is full\n"); } return -ENOSPC; } static int hclge_rm_mc_addr(struct hnae3_handle *handle, const unsigned char *addr) { struct hclge_vport *vport = hclge_get_vport(handle); return hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL, HCLGE_MAC_ADDR_MC, addr); } int hclge_rm_mc_addr_common(struct hclge_vport *vport, const unsigned char *addr) { char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev = vport->back; struct hclge_mac_vlan_tbl_entry_cmd req; enum hclge_comm_cmd_status status; struct hclge_desc desc[3]; /* mac addr check */ if (!is_multicast_ether_addr(addr)) { hnae3_format_mac_addr(format_mac_addr, addr); dev_dbg(&hdev->pdev->dev, "Remove mc mac err! invalid mac:%s.\n", format_mac_addr); return -EINVAL; } memset(&req, 0, sizeof(req)); hclge_prepare_mac_addr(&req, addr, true); status = hclge_lookup_mac_vlan_tbl(vport, &req, desc, true); if (!status) { /* This mac addr exist, remove this handle's VFID for it */ status = hclge_update_desc_vfid(desc, vport->vport_id, true); if (status) return status; if (hclge_is_all_function_id_zero(desc)) { /* All the vfid is zero, so need to delete this entry */ status = hclge_remove_mac_vlan_tbl(vport, &req); if (!status) hdev->used_mc_mac_num--; } else { /* Not all the vfid is zero, update the vfid */ status = hclge_add_mac_vlan_tbl(vport, &req, desc); } } else if (status == -ENOENT) { status = 0; } return status; } static void hclge_sync_vport_mac_list(struct hclge_vport *vport, struct list_head *list, enum HCLGE_MAC_ADDR_TYPE mac_type) { int (*sync)(struct hclge_vport *vport, const unsigned char *addr); struct hclge_mac_node *mac_node, *tmp; int ret; if (mac_type == HCLGE_MAC_ADDR_UC) sync = hclge_add_uc_addr_common; else sync = hclge_add_mc_addr_common; list_for_each_entry_safe(mac_node, tmp, list, node) { ret = sync(vport, mac_node->mac_addr); if (!ret) { mac_node->state = HCLGE_MAC_ACTIVE; } else { set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state); /* If one unicast mac address is existing in hardware, * we need to try whether other unicast mac addresses * are new addresses that can be added. * Multicast mac address can be reusable, even though * there is no space to add new multicast mac address, * we should check whether other mac addresses are * existing in hardware for reuse. */ if ((mac_type == HCLGE_MAC_ADDR_UC && ret != -EEXIST) || (mac_type == HCLGE_MAC_ADDR_MC && ret != -ENOSPC)) break; } } } static void hclge_unsync_vport_mac_list(struct hclge_vport *vport, struct list_head *list, enum HCLGE_MAC_ADDR_TYPE mac_type) { int (*unsync)(struct hclge_vport *vport, const unsigned char *addr); struct hclge_mac_node *mac_node, *tmp; int ret; if (mac_type == HCLGE_MAC_ADDR_UC) unsync = hclge_rm_uc_addr_common; else unsync = hclge_rm_mc_addr_common; list_for_each_entry_safe(mac_node, tmp, list, node) { ret = unsync(vport, mac_node->mac_addr); if (!ret || ret == -ENOENT) { list_del(&mac_node->node); kfree(mac_node); } else { set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state); break; } } } static bool hclge_sync_from_add_list(struct list_head *add_list, struct list_head *mac_list) { struct hclge_mac_node *mac_node, *tmp, *new_node; bool all_added = true; list_for_each_entry_safe(mac_node, tmp, add_list, node) { if (mac_node->state == HCLGE_MAC_TO_ADD) all_added = false; /* if the mac address from tmp_add_list is not in the * uc/mc_mac_list, it means have received a TO_DEL request * during the time window of adding the mac address into mac * table. if mac_node state is ACTIVE, then change it to TO_DEL, * then it will be removed at next time. else it must be TO_ADD, * this address hasn't been added into mac table, * so just remove the mac node. */ new_node = hclge_find_mac_node(mac_list, mac_node->mac_addr); if (new_node) { hclge_update_mac_node(new_node, mac_node->state); list_del(&mac_node->node); kfree(mac_node); } else if (mac_node->state == HCLGE_MAC_ACTIVE) { mac_node->state = HCLGE_MAC_TO_DEL; list_move_tail(&mac_node->node, mac_list); } else { list_del(&mac_node->node); kfree(mac_node); } } return all_added; } static void hclge_sync_from_del_list(struct list_head *del_list, struct list_head *mac_list) { struct hclge_mac_node *mac_node, *tmp, *new_node; list_for_each_entry_safe(mac_node, tmp, del_list, node) { new_node = hclge_find_mac_node(mac_list, mac_node->mac_addr); if (new_node) { /* If the mac addr exists in the mac list, it means * received a new TO_ADD request during the time window * of configuring the mac address. For the mac node * state is TO_ADD, and the address is already in the * in the hardware(due to delete fail), so we just need * to change the mac node state to ACTIVE. */ new_node->state = HCLGE_MAC_ACTIVE; list_del(&mac_node->node); kfree(mac_node); } else { list_move_tail(&mac_node->node, mac_list); } } } static void hclge_update_overflow_flags(struct hclge_vport *vport, enum HCLGE_MAC_ADDR_TYPE mac_type, bool is_all_added) { if (mac_type == HCLGE_MAC_ADDR_UC) { if (is_all_added) vport->overflow_promisc_flags &= ~HNAE3_OVERFLOW_UPE; else if (hclge_is_umv_space_full(vport, true)) vport->overflow_promisc_flags |= HNAE3_OVERFLOW_UPE; } else { if (is_all_added) vport->overflow_promisc_flags &= ~HNAE3_OVERFLOW_MPE; else vport->overflow_promisc_flags |= HNAE3_OVERFLOW_MPE; } } static void hclge_sync_vport_mac_table(struct hclge_vport *vport, enum HCLGE_MAC_ADDR_TYPE mac_type) { struct hclge_mac_node *mac_node, *tmp, *new_node; struct list_head tmp_add_list, tmp_del_list; struct list_head *list; bool all_added; INIT_LIST_HEAD(&tmp_add_list); INIT_LIST_HEAD(&tmp_del_list); /* move the mac addr to the tmp_add_list and tmp_del_list, then * we can add/delete these mac addr outside the spin lock */ list = (mac_type == HCLGE_MAC_ADDR_UC) ? &vport->uc_mac_list : &vport->mc_mac_list; spin_lock_bh(&vport->mac_list_lock); list_for_each_entry_safe(mac_node, tmp, list, node) { switch (mac_node->state) { case HCLGE_MAC_TO_DEL: list_move_tail(&mac_node->node, &tmp_del_list); break; case HCLGE_MAC_TO_ADD: new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); if (!new_node) goto stop_traverse; ether_addr_copy(new_node->mac_addr, mac_node->mac_addr); new_node->state = mac_node->state; list_add_tail(&new_node->node, &tmp_add_list); break; default: break; } } stop_traverse: spin_unlock_bh(&vport->mac_list_lock); /* delete first, in order to get max mac table space for adding */ hclge_unsync_vport_mac_list(vport, &tmp_del_list, mac_type); hclge_sync_vport_mac_list(vport, &tmp_add_list, mac_type); /* if some mac addresses were added/deleted fail, move back to the * mac_list, and retry at next time. */ spin_lock_bh(&vport->mac_list_lock); hclge_sync_from_del_list(&tmp_del_list, list); all_added = hclge_sync_from_add_list(&tmp_add_list, list); spin_unlock_bh(&vport->mac_list_lock); hclge_update_overflow_flags(vport, mac_type, all_added); } static bool hclge_need_sync_mac_table(struct hclge_vport *vport) { struct hclge_dev *hdev = vport->back; if (test_bit(vport->vport_id, hdev->vport_config_block)) return false; if (test_and_clear_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state)) return true; return false; } static void hclge_sync_mac_table(struct hclge_dev *hdev) { int i; for (i = 0; i < hdev->num_alloc_vport; i++) { struct hclge_vport *vport = &hdev->vport[i]; if (!hclge_need_sync_mac_table(vport)) continue; hclge_sync_vport_mac_table(vport, HCLGE_MAC_ADDR_UC); hclge_sync_vport_mac_table(vport, HCLGE_MAC_ADDR_MC); } } static void hclge_build_del_list(struct list_head *list, bool is_del_list, struct list_head *tmp_del_list) { struct hclge_mac_node *mac_cfg, *tmp; list_for_each_entry_safe(mac_cfg, tmp, list, node) { switch (mac_cfg->state) { case HCLGE_MAC_TO_DEL: case HCLGE_MAC_ACTIVE: list_move_tail(&mac_cfg->node, tmp_del_list); break; case HCLGE_MAC_TO_ADD: if (is_del_list) { list_del(&mac_cfg->node); kfree(mac_cfg); } break; } } } static void hclge_unsync_del_list(struct hclge_vport *vport, int (*unsync)(struct hclge_vport *vport, const unsigned char *addr), bool is_del_list, struct list_head *tmp_del_list) { struct hclge_mac_node *mac_cfg, *tmp; int ret; list_for_each_entry_safe(mac_cfg, tmp, tmp_del_list, node) { ret = unsync(vport, mac_cfg->mac_addr); if (!ret || ret == -ENOENT) { /* clear all mac addr from hardware, but remain these * mac addr in the mac list, and restore them after * vf reset finished. */ if (!is_del_list && mac_cfg->state == HCLGE_MAC_ACTIVE) { mac_cfg->state = HCLGE_MAC_TO_ADD; } else { list_del(&mac_cfg->node); kfree(mac_cfg); } } else if (is_del_list) { mac_cfg->state = HCLGE_MAC_TO_DEL; } } } void hclge_rm_vport_all_mac_table(struct hclge_vport *vport, bool is_del_list, enum HCLGE_MAC_ADDR_TYPE mac_type) { int (*unsync)(struct hclge_vport *vport, const unsigned char *addr); struct hclge_dev *hdev = vport->back; struct list_head tmp_del_list, *list; if (mac_type == HCLGE_MAC_ADDR_UC) { list = &vport->uc_mac_list; unsync = hclge_rm_uc_addr_common; } else { list = &vport->mc_mac_list; unsync = hclge_rm_mc_addr_common; } INIT_LIST_HEAD(&tmp_del_list); if (!is_del_list) set_bit(vport->vport_id, hdev->vport_config_block); spin_lock_bh(&vport->mac_list_lock); hclge_build_del_list(list, is_del_list, &tmp_del_list); spin_unlock_bh(&vport->mac_list_lock); hclge_unsync_del_list(vport, unsync, is_del_list, &tmp_del_list); spin_lock_bh(&vport->mac_list_lock); hclge_sync_from_del_list(&tmp_del_list, list); spin_unlock_bh(&vport->mac_list_lock); } /* remove all mac address when uninitailize */ static void hclge_uninit_vport_mac_list(struct hclge_vport *vport, enum HCLGE_MAC_ADDR_TYPE mac_type) { struct hclge_mac_node *mac_node, *tmp; struct hclge_dev *hdev = vport->back; struct list_head tmp_del_list, *list; INIT_LIST_HEAD(&tmp_del_list); list = (mac_type == HCLGE_MAC_ADDR_UC) ? &vport->uc_mac_list : &vport->mc_mac_list; spin_lock_bh(&vport->mac_list_lock); list_for_each_entry_safe(mac_node, tmp, list, node) { switch (mac_node->state) { case HCLGE_MAC_TO_DEL: case HCLGE_MAC_ACTIVE: list_move_tail(&mac_node->node, &tmp_del_list); break; case HCLGE_MAC_TO_ADD: list_del(&mac_node->node); kfree(mac_node); break; } } spin_unlock_bh(&vport->mac_list_lock); hclge_unsync_vport_mac_list(vport, &tmp_del_list, mac_type); if (!list_empty(&tmp_del_list)) dev_warn(&hdev->pdev->dev, "uninit %s mac list for vport %u not completely.\n", mac_type == HCLGE_MAC_ADDR_UC ? "uc" : "mc", vport->vport_id); list_for_each_entry_safe(mac_node, tmp, &tmp_del_list, node) { list_del(&mac_node->node); kfree(mac_node); } } static void hclge_uninit_mac_table(struct hclge_dev *hdev) { struct hclge_vport *vport; int i; for (i = 0; i < hdev->num_alloc_vport; i++) { vport = &hdev->vport[i]; hclge_uninit_vport_mac_list(vport, HCLGE_MAC_ADDR_UC); hclge_uninit_vport_mac_list(vport, HCLGE_MAC_ADDR_MC); } } static int hclge_get_mac_ethertype_cmd_status(struct hclge_dev *hdev, u16 cmdq_resp, u8 resp_code) { #define HCLGE_ETHERTYPE_SUCCESS_ADD 0 #define HCLGE_ETHERTYPE_ALREADY_ADD 1 #define HCLGE_ETHERTYPE_MGR_TBL_OVERFLOW 2 #define HCLGE_ETHERTYPE_KEY_CONFLICT 3 int return_status; if (cmdq_resp) { dev_err(&hdev->pdev->dev, "cmdq execute failed for get_mac_ethertype_cmd_status, status=%u.\n", cmdq_resp); return -EIO; } switch (resp_code) { case HCLGE_ETHERTYPE_SUCCESS_ADD: case HCLGE_ETHERTYPE_ALREADY_ADD: return_status = 0; break; case HCLGE_ETHERTYPE_MGR_TBL_OVERFLOW: dev_err(&hdev->pdev->dev, "add mac ethertype failed for manager table overflow.\n"); return_status = -EIO; break; case HCLGE_ETHERTYPE_KEY_CONFLICT: dev_err(&hdev->pdev->dev, "add mac ethertype failed for key conflict.\n"); return_status = -EIO; break; default: dev_err(&hdev->pdev->dev, "add mac ethertype failed for undefined, code=%u.\n", resp_code); return_status = -EIO; } return return_status; } static int hclge_set_vf_mac(struct hnae3_handle *handle, int vf, u8 *mac_addr) { struct hclge_vport *vport = hclge_get_vport(handle); char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev = vport->back; vport = hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; hnae3_format_mac_addr(format_mac_addr, mac_addr); if (ether_addr_equal(mac_addr, vport->vf_info.mac)) { dev_info(&hdev->pdev->dev, "Specified MAC(=%s) is same as before, no change committed!\n", format_mac_addr); return 0; } ether_addr_copy(vport->vf_info.mac, mac_addr); /* there is a timewindow for PF to know VF unalive, it may * cause send mailbox fail, but it doesn't matter, VF will * query it when reinit. */ if (test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) { dev_info(&hdev->pdev->dev, "MAC of VF %d has been set to %s, and it will be reinitialized!\n", vf, format_mac_addr); (void)hclge_inform_reset_assert_to_vf(vport); return 0; } dev_info(&hdev->pdev->dev, "MAC of VF %d has been set to %s, will be active after VF reset\n", vf, format_mac_addr); return 0; } static int hclge_add_mgr_tbl(struct hclge_dev *hdev, const struct hclge_mac_mgr_tbl_entry_cmd *req) { struct hclge_desc desc; u8 resp_code; u16 retval; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_ETHTYPE_ADD, false); memcpy(desc.data, req, sizeof(struct hclge_mac_mgr_tbl_entry_cmd)); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "add mac ethertype failed for cmd_send, ret =%d.\n", ret); return ret; } resp_code = (le32_to_cpu(desc.data[0]) >> 8) & 0xff; retval = le16_to_cpu(desc.retval); return hclge_get_mac_ethertype_cmd_status(hdev, retval, resp_code); } static int init_mgr_tbl(struct hclge_dev *hdev) { int ret; int i; for (i = 0; i < ARRAY_SIZE(hclge_mgr_table); i++) { ret = hclge_add_mgr_tbl(hdev, &hclge_mgr_table[i]); if (ret) { dev_err(&hdev->pdev->dev, "add mac ethertype failed, ret =%d.\n", ret); return ret; } } return 0; } static void hclge_get_mac_addr(struct hnae3_handle *handle, u8 *p) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; ether_addr_copy(p, hdev->hw.mac.mac_addr); } int hclge_update_mac_node_for_dev_addr(struct hclge_vport *vport, const u8 *old_addr, const u8 *new_addr) { struct list_head *list = &vport->uc_mac_list; struct hclge_mac_node *old_node, *new_node; new_node = hclge_find_mac_node(list, new_addr); if (!new_node) { new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); if (!new_node) return -ENOMEM; new_node->state = HCLGE_MAC_TO_ADD; ether_addr_copy(new_node->mac_addr, new_addr); list_add(&new_node->node, list); } else { if (new_node->state == HCLGE_MAC_TO_DEL) new_node->state = HCLGE_MAC_ACTIVE; /* make sure the new addr is in the list head, avoid dev * addr may be not re-added into mac table for the umv space * limitation after global/imp reset which will clear mac * table by hardware. */ list_move(&new_node->node, list); } if (old_addr && !ether_addr_equal(old_addr, new_addr)) { old_node = hclge_find_mac_node(list, old_addr); if (old_node) { if (old_node->state == HCLGE_MAC_TO_ADD) { list_del(&old_node->node); kfree(old_node); } else { old_node->state = HCLGE_MAC_TO_DEL; } } } set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state); return 0; } static int hclge_set_mac_addr(struct hnae3_handle *handle, const void *p, bool is_first) { const unsigned char *new_addr = (const unsigned char *)p; struct hclge_vport *vport = hclge_get_vport(handle); char format_mac_addr[HNAE3_FORMAT_MAC_ADDR_LEN]; struct hclge_dev *hdev = vport->back; unsigned char *old_addr = NULL; int ret; /* mac addr check */ if (is_zero_ether_addr(new_addr) || is_broadcast_ether_addr(new_addr) || is_multicast_ether_addr(new_addr)) { hnae3_format_mac_addr(format_mac_addr, new_addr); dev_err(&hdev->pdev->dev, "change uc mac err! invalid mac: %s.\n", format_mac_addr); return -EINVAL; } ret = hclge_pause_addr_cfg(hdev, new_addr); if (ret) { dev_err(&hdev->pdev->dev, "failed to configure mac pause address, ret = %d\n", ret); return ret; } if (!is_first) old_addr = hdev->hw.mac.mac_addr; spin_lock_bh(&vport->mac_list_lock); ret = hclge_update_mac_node_for_dev_addr(vport, old_addr, new_addr); if (ret) { hnae3_format_mac_addr(format_mac_addr, new_addr); dev_err(&hdev->pdev->dev, "failed to change the mac addr:%s, ret = %d\n", format_mac_addr, ret); spin_unlock_bh(&vport->mac_list_lock); if (!is_first) hclge_pause_addr_cfg(hdev, old_addr); return ret; } /* we must update dev addr with spin lock protect, preventing dev addr * being removed by set_rx_mode path. */ ether_addr_copy(hdev->hw.mac.mac_addr, new_addr); spin_unlock_bh(&vport->mac_list_lock); hclge_task_schedule(hdev, 0); return 0; } static int hclge_mii_ioctl(struct hclge_dev *hdev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); if (!hnae3_dev_phy_imp_supported(hdev)) return -EOPNOTSUPP; switch (cmd) { case SIOCGMIIPHY: data->phy_id = hdev->hw.mac.phy_addr; /* this command reads phy id and register at the same time */ fallthrough; case SIOCGMIIREG: data->val_out = hclge_read_phy_reg(hdev, data->reg_num); return 0; case SIOCSMIIREG: return hclge_write_phy_reg(hdev, data->reg_num, data->val_in); default: return -EOPNOTSUPP; } } static int hclge_do_ioctl(struct hnae3_handle *handle, struct ifreq *ifr, int cmd) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; switch (cmd) { case SIOCGHWTSTAMP: return hclge_ptp_get_cfg(hdev, ifr); case SIOCSHWTSTAMP: return hclge_ptp_set_cfg(hdev, ifr); default: if (!hdev->hw.mac.phydev) return hclge_mii_ioctl(hdev, ifr, cmd); } return phy_mii_ioctl(hdev->hw.mac.phydev, ifr, cmd); } static int hclge_set_port_vlan_filter_bypass(struct hclge_dev *hdev, u8 vf_id, bool bypass_en) { struct hclge_port_vlan_filter_bypass_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PORT_VLAN_BYPASS, false); req = (struct hclge_port_vlan_filter_bypass_cmd *)desc.data; req->vf_id = vf_id; hnae3_set_bit(req->bypass_state, HCLGE_INGRESS_BYPASS_B, bypass_en ? 1 : 0); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "failed to set vport%u port vlan filter bypass state, ret = %d.\n", vf_id, ret); return ret; } static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type, u8 fe_type, bool filter_en, u8 vf_id) { struct hclge_vlan_filter_ctrl_cmd *req; struct hclge_desc desc; int ret; /* read current vlan filter parameter */ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_CTRL, true); req = (struct hclge_vlan_filter_ctrl_cmd *)desc.data; req->vlan_type = vlan_type; req->vf_id = vf_id; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to get vport%u vlan filter config, ret = %d.\n", vf_id, ret); return ret; } /* modify and write new config parameter */ hclge_comm_cmd_reuse_desc(&desc, false); req->vlan_fe = filter_en ? (req->vlan_fe | fe_type) : (req->vlan_fe & ~fe_type); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "failed to set vport%u vlan filter, ret = %d.\n", vf_id, ret); return ret; } static int hclge_set_vport_vlan_filter(struct hclge_vport *vport, bool enable) { struct hclge_dev *hdev = vport->back; struct hnae3_ae_dev *ae_dev = hdev->ae_dev; int ret; if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, HCLGE_FILTER_FE_EGRESS_V1_B, enable, vport->vport_id); ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, HCLGE_FILTER_FE_EGRESS, enable, vport->vport_id); if (ret) return ret; if (test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, ae_dev->caps)) { ret = hclge_set_port_vlan_filter_bypass(hdev, vport->vport_id, !enable); } else if (!vport->vport_id) { if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps)) enable = false; ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT, HCLGE_FILTER_FE_INGRESS, enable, 0); } return ret; } static bool hclge_need_enable_vport_vlan_filter(struct hclge_vport *vport) { struct hnae3_handle *handle = &vport->nic; struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev = vport->back; if (vport->vport_id) { if (vport->port_base_vlan_cfg.state != HNAE3_PORT_BASE_VLAN_DISABLE) return true; if (vport->vf_info.trusted && vport->vf_info.request_uc_en) return false; } else if (handle->netdev_flags & HNAE3_USER_UPE) { return false; } if (!vport->req_vlan_fltr_en) return false; /* compatible with former device, always enable vlan filter */ if (!test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps)) return true; list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) if (vlan->vlan_id != 0) return true; return false; } int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en) { struct hclge_dev *hdev = vport->back; bool need_en; int ret; mutex_lock(&hdev->vport_lock); vport->req_vlan_fltr_en = request_en; need_en = hclge_need_enable_vport_vlan_filter(vport); if (need_en == vport->cur_vlan_fltr_en) { mutex_unlock(&hdev->vport_lock); return 0; } ret = hclge_set_vport_vlan_filter(vport, need_en); if (ret) { mutex_unlock(&hdev->vport_lock); return ret; } vport->cur_vlan_fltr_en = need_en; mutex_unlock(&hdev->vport_lock); return 0; } static int hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); return hclge_enable_vport_vlan_filter(vport, enable); } static int hclge_set_vf_vlan_filter_cmd(struct hclge_dev *hdev, u16 vfid, bool is_kill, u16 vlan, struct hclge_desc *desc) { struct hclge_vlan_filter_vf_cfg_cmd *req0; struct hclge_vlan_filter_vf_cfg_cmd *req1; u8 vf_byte_val; u8 vf_byte_off; int ret; hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_VLAN_FILTER_VF_CFG, false); hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_VLAN_FILTER_VF_CFG, false); desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); vf_byte_off = vfid / 8; vf_byte_val = 1 << (vfid % 8); req0 = (struct hclge_vlan_filter_vf_cfg_cmd *)desc[0].data; req1 = (struct hclge_vlan_filter_vf_cfg_cmd *)desc[1].data; req0->vlan_id = cpu_to_le16(vlan); req0->vlan_cfg = is_kill; if (vf_byte_off < HCLGE_MAX_VF_BYTES) req0->vf_bitmap[vf_byte_off] = vf_byte_val; else req1->vf_bitmap[vf_byte_off - HCLGE_MAX_VF_BYTES] = vf_byte_val; ret = hclge_cmd_send(&hdev->hw, desc, 2); if (ret) { dev_err(&hdev->pdev->dev, "Send vf vlan command fail, ret =%d.\n", ret); return ret; } return 0; } static int hclge_check_vf_vlan_cmd_status(struct hclge_dev *hdev, u16 vfid, bool is_kill, struct hclge_desc *desc) { struct hclge_vlan_filter_vf_cfg_cmd *req; req = (struct hclge_vlan_filter_vf_cfg_cmd *)desc[0].data; if (!is_kill) { #define HCLGE_VF_VLAN_NO_ENTRY 2 if (!req->resp_code || req->resp_code == 1) return 0; if (req->resp_code == HCLGE_VF_VLAN_NO_ENTRY) { set_bit(vfid, hdev->vf_vlan_full); dev_warn(&hdev->pdev->dev, "vf vlan table is full, vf vlan filter is disabled\n"); return 0; } dev_err(&hdev->pdev->dev, "Add vf vlan filter fail, ret =%u.\n", req->resp_code); } else { #define HCLGE_VF_VLAN_DEL_NO_FOUND 1 if (!req->resp_code) return 0; /* vf vlan filter is disabled when vf vlan table is full, * then new vlan id will not be added into vf vlan table. * Just return 0 without warning, avoid massive verbose * print logs when unload. */ if (req->resp_code == HCLGE_VF_VLAN_DEL_NO_FOUND) return 0; dev_err(&hdev->pdev->dev, "Kill vf vlan filter fail, ret =%u.\n", req->resp_code); } return -EIO; } static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid, bool is_kill, u16 vlan) { struct hclge_vport *vport = &hdev->vport[vfid]; struct hclge_desc desc[2]; int ret; /* if vf vlan table is full, firmware will close vf vlan filter, it * is unable and unnecessary to add new vlan id to vf vlan filter. * If spoof check is enable, and vf vlan is full, it shouldn't add * new vlan, because tx packets with these vlan id will be dropped. */ if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill) { if (vport->vf_info.spoofchk && vlan) { dev_err(&hdev->pdev->dev, "Can't add vlan due to spoof check is on and vf vlan table is full\n"); return -EPERM; } return 0; } ret = hclge_set_vf_vlan_filter_cmd(hdev, vfid, is_kill, vlan, desc); if (ret) return ret; return hclge_check_vf_vlan_cmd_status(hdev, vfid, is_kill, desc); } static int hclge_set_port_vlan_filter(struct hclge_dev *hdev, __be16 proto, u16 vlan_id, bool is_kill) { struct hclge_vlan_filter_pf_cfg_cmd *req; struct hclge_desc desc; u8 vlan_offset_byte_val; u8 vlan_offset_byte; u8 vlan_offset_160; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_PF_CFG, false); vlan_offset_160 = vlan_id / HCLGE_VLAN_ID_OFFSET_STEP; vlan_offset_byte = (vlan_id % HCLGE_VLAN_ID_OFFSET_STEP) / HCLGE_VLAN_BYTE_SIZE; vlan_offset_byte_val = 1 << (vlan_id % HCLGE_VLAN_BYTE_SIZE); req = (struct hclge_vlan_filter_pf_cfg_cmd *)desc.data; req->vlan_offset = vlan_offset_160; req->vlan_cfg = is_kill; req->vlan_offset_bitmap[vlan_offset_byte] = vlan_offset_byte_val; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "port vlan command, send fail, ret =%d.\n", ret); return ret; } static bool hclge_need_update_port_vlan(struct hclge_dev *hdev, u16 vport_id, u16 vlan_id, bool is_kill) { /* vlan 0 may be added twice when 8021q module is enabled */ if (!is_kill && !vlan_id && test_bit(vport_id, hdev->vlan_table[vlan_id])) return false; if (!is_kill && test_and_set_bit(vport_id, hdev->vlan_table[vlan_id])) { dev_warn(&hdev->pdev->dev, "Add port vlan failed, vport %u is already in vlan %u\n", vport_id, vlan_id); return false; } if (is_kill && !test_and_clear_bit(vport_id, hdev->vlan_table[vlan_id])) { dev_warn(&hdev->pdev->dev, "Delete port vlan failed, vport %u is not in vlan %u\n", vport_id, vlan_id); return false; } return true; } static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto, u16 vport_id, u16 vlan_id, bool is_kill) { u16 vport_idx, vport_num = 0; int ret; if (is_kill && !vlan_id) return 0; if (vlan_id >= VLAN_N_VID) return -EINVAL; ret = hclge_set_vf_vlan_common(hdev, vport_id, is_kill, vlan_id); if (ret) { dev_err(&hdev->pdev->dev, "Set %u vport vlan filter config fail, ret =%d.\n", vport_id, ret); return ret; } if (!hclge_need_update_port_vlan(hdev, vport_id, vlan_id, is_kill)) return 0; for_each_set_bit(vport_idx, hdev->vlan_table[vlan_id], HCLGE_VPORT_NUM) vport_num++; if ((is_kill && vport_num == 0) || (!is_kill && vport_num == 1)) ret = hclge_set_port_vlan_filter(hdev, proto, vlan_id, is_kill); return ret; } static int hclge_set_vlan_tx_offload_cfg(struct hclge_vport *vport) { struct hclge_tx_vtag_cfg *vcfg = &vport->txvlan_cfg; struct hclge_vport_vtag_tx_cfg_cmd *req; struct hclge_dev *hdev = vport->back; struct hclge_desc desc; u16 bmap_index; int status; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_PORT_TX_CFG, false); req = (struct hclge_vport_vtag_tx_cfg_cmd *)desc.data; req->def_vlan_tag1 = cpu_to_le16(vcfg->default_tag1); req->def_vlan_tag2 = cpu_to_le16(vcfg->default_tag2); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_ACCEPT_TAG1_B, vcfg->accept_tag1 ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_ACCEPT_UNTAG1_B, vcfg->accept_untag1 ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_ACCEPT_TAG2_B, vcfg->accept_tag2 ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_ACCEPT_UNTAG2_B, vcfg->accept_untag2 ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_PORT_INS_TAG1_EN_B, vcfg->insert_tag1_en ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_PORT_INS_TAG2_EN_B, vcfg->insert_tag2_en ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_TAG_SHIFT_MODE_EN_B, vcfg->tag_shift_mode_en ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_CFG_NIC_ROCE_SEL_B, 0); req->vf_offset = vport->vport_id / HCLGE_VF_NUM_PER_CMD; bmap_index = vport->vport_id % HCLGE_VF_NUM_PER_CMD / HCLGE_VF_NUM_PER_BYTE; req->vf_bitmap[bmap_index] = 1U << (vport->vport_id % HCLGE_VF_NUM_PER_BYTE); status = hclge_cmd_send(&hdev->hw, &desc, 1); if (status) dev_err(&hdev->pdev->dev, "Send port txvlan cfg command fail, ret =%d\n", status); return status; } static int hclge_set_vlan_rx_offload_cfg(struct hclge_vport *vport) { struct hclge_rx_vtag_cfg *vcfg = &vport->rxvlan_cfg; struct hclge_vport_vtag_rx_cfg_cmd *req; struct hclge_dev *hdev = vport->back; struct hclge_desc desc; u16 bmap_index; int status; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_PORT_RX_CFG, false); req = (struct hclge_vport_vtag_rx_cfg_cmd *)desc.data; hnae3_set_bit(req->vport_vlan_cfg, HCLGE_REM_TAG1_EN_B, vcfg->strip_tag1_en ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_REM_TAG2_EN_B, vcfg->strip_tag2_en ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_SHOW_TAG1_EN_B, vcfg->vlan1_vlan_prionly ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_SHOW_TAG2_EN_B, vcfg->vlan2_vlan_prionly ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_DISCARD_TAG1_EN_B, vcfg->strip_tag1_discard_en ? 1 : 0); hnae3_set_bit(req->vport_vlan_cfg, HCLGE_DISCARD_TAG2_EN_B, vcfg->strip_tag2_discard_en ? 1 : 0); req->vf_offset = vport->vport_id / HCLGE_VF_NUM_PER_CMD; bmap_index = vport->vport_id % HCLGE_VF_NUM_PER_CMD / HCLGE_VF_NUM_PER_BYTE; req->vf_bitmap[bmap_index] = 1U << (vport->vport_id % HCLGE_VF_NUM_PER_BYTE); status = hclge_cmd_send(&hdev->hw, &desc, 1); if (status) dev_err(&hdev->pdev->dev, "Send port rxvlan cfg command fail, ret =%d\n", status); return status; } static int hclge_vlan_offload_cfg(struct hclge_vport *vport, u16 port_base_vlan_state, u16 vlan_tag, u8 qos) { int ret; if (port_base_vlan_state == HNAE3_PORT_BASE_VLAN_DISABLE) { vport->txvlan_cfg.accept_tag1 = true; vport->txvlan_cfg.insert_tag1_en = false; vport->txvlan_cfg.default_tag1 = 0; } else { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(vport->nic.pdev); vport->txvlan_cfg.accept_tag1 = ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3; vport->txvlan_cfg.insert_tag1_en = true; vport->txvlan_cfg.default_tag1 = (qos << VLAN_PRIO_SHIFT) | vlan_tag; } vport->txvlan_cfg.accept_untag1 = true; /* accept_tag2 and accept_untag2 are not supported on * pdev revision(0x20), new revision support them, * this two fields can not be configured by user. */ vport->txvlan_cfg.accept_tag2 = true; vport->txvlan_cfg.accept_untag2 = true; vport->txvlan_cfg.insert_tag2_en = false; vport->txvlan_cfg.default_tag2 = 0; vport->txvlan_cfg.tag_shift_mode_en = true; if (port_base_vlan_state == HNAE3_PORT_BASE_VLAN_DISABLE) { vport->rxvlan_cfg.strip_tag1_en = false; vport->rxvlan_cfg.strip_tag2_en = vport->rxvlan_cfg.rx_vlan_offload_en; vport->rxvlan_cfg.strip_tag2_discard_en = false; } else { vport->rxvlan_cfg.strip_tag1_en = vport->rxvlan_cfg.rx_vlan_offload_en; vport->rxvlan_cfg.strip_tag2_en = true; vport->rxvlan_cfg.strip_tag2_discard_en = true; } vport->rxvlan_cfg.strip_tag1_discard_en = false; vport->rxvlan_cfg.vlan1_vlan_prionly = false; vport->rxvlan_cfg.vlan2_vlan_prionly = false; ret = hclge_set_vlan_tx_offload_cfg(vport); if (ret) return ret; return hclge_set_vlan_rx_offload_cfg(vport); } static int hclge_set_vlan_protocol_type(struct hclge_dev *hdev) { struct hclge_rx_vlan_type_cfg_cmd *rx_req; struct hclge_tx_vlan_type_cfg_cmd *tx_req; struct hclge_desc desc; int status; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_TYPE_ID, false); rx_req = (struct hclge_rx_vlan_type_cfg_cmd *)desc.data; rx_req->ot_fst_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.rx_ot_fst_vlan_type); rx_req->ot_sec_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.rx_ot_sec_vlan_type); rx_req->in_fst_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.rx_in_fst_vlan_type); rx_req->in_sec_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.rx_in_sec_vlan_type); status = hclge_cmd_send(&hdev->hw, &desc, 1); if (status) { dev_err(&hdev->pdev->dev, "Send rxvlan protocol type command fail, ret =%d\n", status); return status; } hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_INSERT, false); tx_req = (struct hclge_tx_vlan_type_cfg_cmd *)desc.data; tx_req->ot_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.tx_ot_vlan_type); tx_req->in_vlan_type = cpu_to_le16(hdev->vlan_type_cfg.tx_in_vlan_type); status = hclge_cmd_send(&hdev->hw, &desc, 1); if (status) dev_err(&hdev->pdev->dev, "Send txvlan protocol type command fail, ret =%d\n", status); return status; } static int hclge_init_vlan_filter(struct hclge_dev *hdev) { struct hclge_vport *vport; bool enable = true; int ret; int i; if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, HCLGE_FILTER_FE_EGRESS_V1_B, true, 0); /* for revision 0x21, vf vlan filter is per function */ for (i = 0; i < hdev->num_alloc_vport; i++) { vport = &hdev->vport[i]; ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, HCLGE_FILTER_FE_EGRESS, true, vport->vport_id); if (ret) return ret; vport->cur_vlan_fltr_en = true; } if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps) && !test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, hdev->ae_dev->caps)) enable = false; return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT, HCLGE_FILTER_FE_INGRESS, enable, 0); } static int hclge_init_vlan_type(struct hclge_dev *hdev) { hdev->vlan_type_cfg.rx_in_fst_vlan_type = ETH_P_8021Q; hdev->vlan_type_cfg.rx_in_sec_vlan_type = ETH_P_8021Q; hdev->vlan_type_cfg.rx_ot_fst_vlan_type = ETH_P_8021Q; hdev->vlan_type_cfg.rx_ot_sec_vlan_type = ETH_P_8021Q; hdev->vlan_type_cfg.tx_ot_vlan_type = ETH_P_8021Q; hdev->vlan_type_cfg.tx_in_vlan_type = ETH_P_8021Q; return hclge_set_vlan_protocol_type(hdev); } static int hclge_init_vport_vlan_offload(struct hclge_dev *hdev) { struct hclge_port_base_vlan_config *cfg; struct hclge_vport *vport; int ret; int i; for (i = 0; i < hdev->num_alloc_vport; i++) { vport = &hdev->vport[i]; cfg = &vport->port_base_vlan_cfg; ret = hclge_vlan_offload_cfg(vport, cfg->state, cfg->vlan_info.vlan_tag, cfg->vlan_info.qos); if (ret) return ret; } return 0; } static int hclge_init_vlan_config(struct hclge_dev *hdev) { struct hnae3_handle *handle = &hdev->vport[0].nic; int ret; ret = hclge_init_vlan_filter(hdev); if (ret) return ret; ret = hclge_init_vlan_type(hdev); if (ret) return ret; ret = hclge_init_vport_vlan_offload(hdev); if (ret) return ret; return hclge_set_vlan_filter(handle, htons(ETH_P_8021Q), 0, false); } static void hclge_add_vport_vlan_table(struct hclge_vport *vport, u16 vlan_id, bool writen_to_tbl) { struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev = vport->back; mutex_lock(&hdev->vport_lock); list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { if (vlan->vlan_id == vlan_id) { mutex_unlock(&hdev->vport_lock); return; } } vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); if (!vlan) { mutex_unlock(&hdev->vport_lock); return; } vlan->hd_tbl_status = writen_to_tbl; vlan->vlan_id = vlan_id; list_add_tail(&vlan->node, &vport->vlan_list); mutex_unlock(&hdev->vport_lock); } static int hclge_add_vport_all_vlan_table(struct hclge_vport *vport) { struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev = vport->back; int ret; mutex_lock(&hdev->vport_lock); list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { if (!vlan->hd_tbl_status) { ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, vlan->vlan_id, false); if (ret) { dev_err(&hdev->pdev->dev, "restore vport vlan list failed, ret=%d\n", ret); mutex_unlock(&hdev->vport_lock); return ret; } } vlan->hd_tbl_status = true; } mutex_unlock(&hdev->vport_lock); return 0; } static void hclge_rm_vport_vlan_table(struct hclge_vport *vport, u16 vlan_id, bool is_write_tbl) { struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev = vport->back; list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { if (vlan->vlan_id == vlan_id) { if (is_write_tbl && vlan->hd_tbl_status) hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, vlan_id, true); list_del(&vlan->node); kfree(vlan); break; } } } void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_list) { struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev = vport->back; mutex_lock(&hdev->vport_lock); list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { if (vlan->hd_tbl_status) hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, vlan->vlan_id, true); vlan->hd_tbl_status = false; if (is_del_list) { list_del(&vlan->node); kfree(vlan); } } clear_bit(vport->vport_id, hdev->vf_vlan_full); mutex_unlock(&hdev->vport_lock); } void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev) { struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_vport *vport; int i; mutex_lock(&hdev->vport_lock); for (i = 0; i < hdev->num_alloc_vport; i++) { vport = &hdev->vport[i]; list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { list_del(&vlan->node); kfree(vlan); } } mutex_unlock(&hdev->vport_lock); } void hclge_restore_vport_port_base_vlan_config(struct hclge_dev *hdev) { struct hclge_vlan_info *vlan_info; struct hclge_vport *vport; u16 vlan_proto; u16 vlan_id; u16 state; int vf_id; int ret; /* PF should restore all vfs port base vlan */ for (vf_id = 0; vf_id < hdev->num_alloc_vfs; vf_id++) { vport = &hdev->vport[vf_id + HCLGE_VF_VPORT_START_NUM]; vlan_info = vport->port_base_vlan_cfg.tbl_sta ? &vport->port_base_vlan_cfg.vlan_info : &vport->port_base_vlan_cfg.old_vlan_info; vlan_id = vlan_info->vlan_tag; vlan_proto = vlan_info->vlan_proto; state = vport->port_base_vlan_cfg.state; if (state != HNAE3_PORT_BASE_VLAN_DISABLE) { clear_bit(vport->vport_id, hdev->vlan_table[vlan_id]); ret = hclge_set_vlan_filter_hw(hdev, htons(vlan_proto), vport->vport_id, vlan_id, false); vport->port_base_vlan_cfg.tbl_sta = ret == 0; } } } void hclge_restore_vport_vlan_table(struct hclge_vport *vport) { struct hclge_vport_vlan_cfg *vlan, *tmp; struct hclge_dev *hdev = vport->back; int ret; mutex_lock(&hdev->vport_lock); if (vport->port_base_vlan_cfg.state == HNAE3_PORT_BASE_VLAN_DISABLE) { list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, vlan->vlan_id, false); if (ret) break; vlan->hd_tbl_status = true; } } mutex_unlock(&hdev->vport_lock); } /* For global reset and imp reset, hardware will clear the mac table, * so we change the mac address state from ACTIVE to TO_ADD, then they * can be restored in the service task after reset complete. Furtherly, * the mac addresses with state TO_DEL or DEL_FAIL are unnecessary to * be restored after reset, so just remove these mac nodes from mac_list. */ static void hclge_mac_node_convert_for_reset(struct list_head *list) { struct hclge_mac_node *mac_node, *tmp; list_for_each_entry_safe(mac_node, tmp, list, node) { if (mac_node->state == HCLGE_MAC_ACTIVE) { mac_node->state = HCLGE_MAC_TO_ADD; } else if (mac_node->state == HCLGE_MAC_TO_DEL) { list_del(&mac_node->node); kfree(mac_node); } } } void hclge_restore_mac_table_common(struct hclge_vport *vport) { spin_lock_bh(&vport->mac_list_lock); hclge_mac_node_convert_for_reset(&vport->uc_mac_list); hclge_mac_node_convert_for_reset(&vport->mc_mac_list); set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state); spin_unlock_bh(&vport->mac_list_lock); } static void hclge_restore_hw_table(struct hclge_dev *hdev) { struct hclge_vport *vport = &hdev->vport[0]; struct hnae3_handle *handle = &vport->nic; hclge_restore_mac_table_common(vport); hclge_restore_vport_port_base_vlan_config(hdev); hclge_restore_vport_vlan_table(vport); set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state); hclge_restore_fd_entries(handle); } int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); if (vport->port_base_vlan_cfg.state == HNAE3_PORT_BASE_VLAN_DISABLE) { vport->rxvlan_cfg.strip_tag1_en = false; vport->rxvlan_cfg.strip_tag2_en = enable; vport->rxvlan_cfg.strip_tag2_discard_en = false; } else { vport->rxvlan_cfg.strip_tag1_en = enable; vport->rxvlan_cfg.strip_tag2_en = true; vport->rxvlan_cfg.strip_tag2_discard_en = true; } vport->rxvlan_cfg.strip_tag1_discard_en = false; vport->rxvlan_cfg.vlan1_vlan_prionly = false; vport->rxvlan_cfg.vlan2_vlan_prionly = false; vport->rxvlan_cfg.rx_vlan_offload_en = enable; return hclge_set_vlan_rx_offload_cfg(vport); } static void hclge_set_vport_vlan_fltr_change(struct hclge_vport *vport) { struct hclge_dev *hdev = vport->back; if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps)) set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, &vport->state); } static int hclge_update_vlan_filter_entries(struct hclge_vport *vport, u16 port_base_vlan_state, struct hclge_vlan_info *new_info, struct hclge_vlan_info *old_info) { struct hclge_dev *hdev = vport->back; int ret; if (port_base_vlan_state == HNAE3_PORT_BASE_VLAN_ENABLE) { hclge_rm_vport_all_vlan_table(vport, false); /* force clear VLAN 0 */ ret = hclge_set_vf_vlan_common(hdev, vport->vport_id, true, 0); if (ret) return ret; return hclge_set_vlan_filter_hw(hdev, htons(new_info->vlan_proto), vport->vport_id, new_info->vlan_tag, false); } vport->port_base_vlan_cfg.tbl_sta = false; /* force add VLAN 0 */ ret = hclge_set_vf_vlan_common(hdev, vport->vport_id, false, 0); if (ret) return ret; ret = hclge_set_vlan_filter_hw(hdev, htons(old_info->vlan_proto), vport->vport_id, old_info->vlan_tag, true); if (ret) return ret; return hclge_add_vport_all_vlan_table(vport); } static bool hclge_need_update_vlan_filter(const struct hclge_vlan_info *new_cfg, const struct hclge_vlan_info *old_cfg) { if (new_cfg->vlan_tag != old_cfg->vlan_tag) return true; if (new_cfg->vlan_tag == 0 && (new_cfg->qos == 0 || old_cfg->qos == 0)) return true; return false; } static int hclge_modify_port_base_vlan_tag(struct hclge_vport *vport, struct hclge_vlan_info *new_info, struct hclge_vlan_info *old_info) { struct hclge_dev *hdev = vport->back; int ret; /* add new VLAN tag */ ret = hclge_set_vlan_filter_hw(hdev, htons(new_info->vlan_proto), vport->vport_id, new_info->vlan_tag, false); if (ret) return ret; vport->port_base_vlan_cfg.tbl_sta = false; /* remove old VLAN tag */ if (old_info->vlan_tag == 0) ret = hclge_set_vf_vlan_common(hdev, vport->vport_id, true, 0); else ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, old_info->vlan_tag, true); if (ret) dev_err(&hdev->pdev->dev, "failed to clear vport%u port base vlan %u, ret = %d.\n", vport->vport_id, old_info->vlan_tag, ret); return ret; } int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state, struct hclge_vlan_info *vlan_info) { struct hnae3_handle *nic = &vport->nic; struct hclge_vlan_info *old_vlan_info; int ret; old_vlan_info = &vport->port_base_vlan_cfg.vlan_info; ret = hclge_vlan_offload_cfg(vport, state, vlan_info->vlan_tag, vlan_info->qos); if (ret) return ret; if (!hclge_need_update_vlan_filter(vlan_info, old_vlan_info)) goto out; if (state == HNAE3_PORT_BASE_VLAN_MODIFY) ret = hclge_modify_port_base_vlan_tag(vport, vlan_info, old_vlan_info); else ret = hclge_update_vlan_filter_entries(vport, state, vlan_info, old_vlan_info); if (ret) return ret; out: vport->port_base_vlan_cfg.state = state; if (state == HNAE3_PORT_BASE_VLAN_DISABLE) nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_DISABLE; else nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_ENABLE; vport->port_base_vlan_cfg.old_vlan_info = *old_vlan_info; vport->port_base_vlan_cfg.vlan_info = *vlan_info; vport->port_base_vlan_cfg.tbl_sta = true; hclge_set_vport_vlan_fltr_change(vport); return 0; } static u16 hclge_get_port_base_vlan_state(struct hclge_vport *vport, enum hnae3_port_base_vlan_state state, u16 vlan, u8 qos) { if (state == HNAE3_PORT_BASE_VLAN_DISABLE) { if (!vlan && !qos) return HNAE3_PORT_BASE_VLAN_NOCHANGE; return HNAE3_PORT_BASE_VLAN_ENABLE; } if (!vlan && !qos) return HNAE3_PORT_BASE_VLAN_DISABLE; if (vport->port_base_vlan_cfg.vlan_info.vlan_tag == vlan && vport->port_base_vlan_cfg.vlan_info.qos == qos) return HNAE3_PORT_BASE_VLAN_NOCHANGE; return HNAE3_PORT_BASE_VLAN_MODIFY; } static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid, u16 vlan, u8 qos, __be16 proto) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_vlan_info vlan_info; u16 state; int ret; if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) return -EOPNOTSUPP; vport = hclge_get_vf_vport(hdev, vfid); if (!vport) return -EINVAL; /* qos is a 3 bits value, so can not be bigger than 7 */ if (vlan > VLAN_N_VID - 1 || qos > 7) return -EINVAL; if (proto != htons(ETH_P_8021Q)) return -EPROTONOSUPPORT; state = hclge_get_port_base_vlan_state(vport, vport->port_base_vlan_cfg.state, vlan, qos); if (state == HNAE3_PORT_BASE_VLAN_NOCHANGE) return 0; vlan_info.vlan_tag = vlan; vlan_info.qos = qos; vlan_info.vlan_proto = ntohs(proto); ret = hclge_update_port_base_vlan_cfg(vport, state, &vlan_info); if (ret) { dev_err(&hdev->pdev->dev, "failed to update port base vlan for vf %d, ret = %d\n", vfid, ret); return ret; } /* there is a timewindow for PF to know VF unalive, it may * cause send mailbox fail, but it doesn't matter, VF will * query it when reinit. * for DEVICE_VERSION_V3, vf doesn't need to know about the port based * VLAN state. */ if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3) { if (test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state)) (void)hclge_push_vf_port_base_vlan_info(&hdev->vport[0], vport->vport_id, state, &vlan_info); else set_bit(HCLGE_VPORT_NEED_NOTIFY_VF_VLAN, &vport->need_notify); } return 0; } static void hclge_clear_vf_vlan(struct hclge_dev *hdev) { struct hclge_vlan_info *vlan_info; struct hclge_vport *vport; int ret; int vf; /* clear port base vlan for all vf */ for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) { vport = &hdev->vport[vf]; vlan_info = &vport->port_base_vlan_cfg.vlan_info; ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, vlan_info->vlan_tag, true); if (ret) dev_err(&hdev->pdev->dev, "failed to clear vf vlan for vf%d, ret = %d\n", vf - HCLGE_VF_VPORT_START_NUM, ret); } } int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto, u16 vlan_id, bool is_kill) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; bool writen_to_tbl = false; int ret = 0; /* When device is resetting or reset failed, firmware is unable to * handle mailbox. Just record the vlan id, and remove it after * reset finished. */ mutex_lock(&hdev->vport_lock); if ((test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || test_bit(HCLGE_STATE_RST_FAIL, &hdev->state)) && is_kill) { set_bit(vlan_id, vport->vlan_del_fail_bmap); mutex_unlock(&hdev->vport_lock); return -EBUSY; } else if (!is_kill && test_bit(vlan_id, vport->vlan_del_fail_bmap)) { clear_bit(vlan_id, vport->vlan_del_fail_bmap); } mutex_unlock(&hdev->vport_lock); /* when port base vlan enabled, we use port base vlan as the vlan * filter entry. In this case, we don't update vlan filter table * when user add new vlan or remove exist vlan, just update the vport * vlan list. The vlan id in vlan list will be writen in vlan filter * table until port base vlan disabled */ if (handle->port_base_vlan_state == HNAE3_PORT_BASE_VLAN_DISABLE) { ret = hclge_set_vlan_filter_hw(hdev, proto, vport->vport_id, vlan_id, is_kill); writen_to_tbl = true; } if (!ret) { if (!is_kill) { hclge_add_vport_vlan_table(vport, vlan_id, writen_to_tbl); } else if (is_kill && vlan_id != 0) { mutex_lock(&hdev->vport_lock); hclge_rm_vport_vlan_table(vport, vlan_id, false); mutex_unlock(&hdev->vport_lock); } } else if (is_kill) { /* when remove hw vlan filter failed, record the vlan id, * and try to remove it from hw later, to be consistence * with stack */ mutex_lock(&hdev->vport_lock); set_bit(vlan_id, vport->vlan_del_fail_bmap); mutex_unlock(&hdev->vport_lock); } hclge_set_vport_vlan_fltr_change(vport); return ret; } static void hclge_sync_vlan_fltr_state(struct hclge_dev *hdev) { struct hclge_vport *vport; int ret; u16 i; for (i = 0; i < hdev->num_alloc_vport; i++) { vport = &hdev->vport[i]; if (!test_and_clear_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, &vport->state)) continue; ret = hclge_enable_vport_vlan_filter(vport, vport->req_vlan_fltr_en); if (ret) { dev_err(&hdev->pdev->dev, "failed to sync vlan filter state for vport%u, ret = %d\n", vport->vport_id, ret); set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, &vport->state); return; } } } static void hclge_sync_vlan_filter(struct hclge_dev *hdev) { #define HCLGE_MAX_SYNC_COUNT 60 int i, ret, sync_cnt = 0; u16 vlan_id; mutex_lock(&hdev->vport_lock); /* start from vport 1 for PF is always alive */ for (i = 0; i < hdev->num_alloc_vport; i++) { struct hclge_vport *vport = &hdev->vport[i]; vlan_id = find_first_bit(vport->vlan_del_fail_bmap, VLAN_N_VID); while (vlan_id != VLAN_N_VID) { ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), vport->vport_id, vlan_id, true); if (ret && ret != -EINVAL) { mutex_unlock(&hdev->vport_lock); return; } clear_bit(vlan_id, vport->vlan_del_fail_bmap); hclge_rm_vport_vlan_table(vport, vlan_id, false); hclge_set_vport_vlan_fltr_change(vport); sync_cnt++; if (sync_cnt >= HCLGE_MAX_SYNC_COUNT) { mutex_unlock(&hdev->vport_lock); return; } vlan_id = find_first_bit(vport->vlan_del_fail_bmap, VLAN_N_VID); } } mutex_unlock(&hdev->vport_lock); hclge_sync_vlan_fltr_state(hdev); } static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps) { struct hclge_config_max_frm_size_cmd *req; struct hclge_desc desc; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CONFIG_MAX_FRM_SIZE, false); req = (struct hclge_config_max_frm_size_cmd *)desc.data; req->max_frm_size = cpu_to_le16(new_mps); req->min_frm_size = HCLGE_MAC_MIN_FRAME; return hclge_cmd_send(&hdev->hw, &desc, 1); } static int hclge_set_mtu(struct hnae3_handle *handle, int new_mtu) { struct hclge_vport *vport = hclge_get_vport(handle); return hclge_set_vport_mtu(vport, new_mtu); } int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu) { struct hclge_dev *hdev = vport->back; int i, max_frm_size, ret; /* HW supprt 2 layer vlan */ max_frm_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN; if (max_frm_size < HCLGE_MAC_MIN_FRAME || max_frm_size > hdev->ae_dev->dev_specs.max_frm_size) return -EINVAL; max_frm_size = max(max_frm_size, HCLGE_MAC_DEFAULT_FRAME); mutex_lock(&hdev->vport_lock); /* VF's mps must fit within hdev->mps */ if (vport->vport_id && max_frm_size > hdev->mps) { mutex_unlock(&hdev->vport_lock); return -EINVAL; } else if (vport->vport_id) { vport->mps = max_frm_size; mutex_unlock(&hdev->vport_lock); return 0; } /* PF's mps must be greater then VF's mps */ for (i = 1; i < hdev->num_alloc_vport; i++) if (max_frm_size < hdev->vport[i].mps) { dev_err(&hdev->pdev->dev, "failed to set pf mtu for less than vport %d, mps = %u.\n", i, hdev->vport[i].mps); mutex_unlock(&hdev->vport_lock); return -EINVAL; } hclge_notify_client(hdev, HNAE3_DOWN_CLIENT); ret = hclge_set_mac_mtu(hdev, max_frm_size); if (ret) { dev_err(&hdev->pdev->dev, "Change mtu fail, ret =%d\n", ret); goto out; } hdev->mps = max_frm_size; vport->mps = max_frm_size; ret = hclge_buffer_alloc(hdev); if (ret) dev_err(&hdev->pdev->dev, "Allocate buffer fail, ret =%d\n", ret); out: hclge_notify_client(hdev, HNAE3_UP_CLIENT); mutex_unlock(&hdev->vport_lock); return ret; } static int hclge_reset_tqp_cmd_send(struct hclge_dev *hdev, u16 queue_id, bool enable) { struct hclge_reset_tqp_queue_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RESET_TQP_QUEUE, false); req = (struct hclge_reset_tqp_queue_cmd *)desc.data; req->tqp_id = cpu_to_le16(queue_id); if (enable) hnae3_set_bit(req->reset_req, HCLGE_TQP_RESET_B, 1U); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "Send tqp reset cmd error, status =%d\n", ret); return ret; } return 0; } static int hclge_get_reset_status(struct hclge_dev *hdev, u16 queue_id, u8 *reset_status) { struct hclge_reset_tqp_queue_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RESET_TQP_QUEUE, true); req = (struct hclge_reset_tqp_queue_cmd *)desc.data; req->tqp_id = cpu_to_le16(queue_id); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "Get reset status error, status =%d\n", ret); return ret; } *reset_status = hnae3_get_bit(req->ready_to_reset, HCLGE_TQP_RESET_B); return 0; } u16 hclge_covert_handle_qid_global(struct hnae3_handle *handle, u16 queue_id) { struct hclge_comm_tqp *tqp; struct hnae3_queue *queue; queue = handle->kinfo.tqp[queue_id]; tqp = container_of(queue, struct hclge_comm_tqp, q); return tqp->index; } static int hclge_reset_tqp_cmd(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u16 reset_try_times = 0; u8 reset_status; u16 queue_gid; int ret; u16 i; for (i = 0; i < handle->kinfo.num_tqps; i++) { queue_gid = hclge_covert_handle_qid_global(handle, i); ret = hclge_reset_tqp_cmd_send(hdev, queue_gid, true); if (ret) { dev_err(&hdev->pdev->dev, "failed to send reset tqp cmd, ret = %d\n", ret); return ret; } while (reset_try_times++ < HCLGE_TQP_RESET_TRY_TIMES) { ret = hclge_get_reset_status(hdev, queue_gid, &reset_status); if (ret) return ret; if (reset_status) break; /* Wait for tqp hw reset */ usleep_range(1000, 1200); } if (reset_try_times >= HCLGE_TQP_RESET_TRY_TIMES) { dev_err(&hdev->pdev->dev, "wait for tqp hw reset timeout\n"); return -ETIME; } ret = hclge_reset_tqp_cmd_send(hdev, queue_gid, false); if (ret) { dev_err(&hdev->pdev->dev, "failed to deassert soft reset, ret = %d\n", ret); return ret; } reset_try_times = 0; } return 0; } static int hclge_reset_rcb(struct hnae3_handle *handle) { #define HCLGE_RESET_RCB_NOT_SUPPORT 0U #define HCLGE_RESET_RCB_SUCCESS 1U struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_reset_cmd *req; struct hclge_desc desc; u8 return_status; u16 queue_gid; int ret; queue_gid = hclge_covert_handle_qid_global(handle, 0); req = (struct hclge_reset_cmd *)desc.data; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_RST_TRIGGER, false); hnae3_set_bit(req->fun_reset_rcb, HCLGE_CFG_RESET_RCB_B, 1); req->fun_reset_rcb_vqid_start = cpu_to_le16(queue_gid); req->fun_reset_rcb_vqid_num = cpu_to_le16(handle->kinfo.num_tqps); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to send rcb reset cmd, ret = %d\n", ret); return ret; } return_status = req->fun_reset_rcb_return_status; if (return_status == HCLGE_RESET_RCB_SUCCESS) return 0; if (return_status != HCLGE_RESET_RCB_NOT_SUPPORT) { dev_err(&hdev->pdev->dev, "failed to reset rcb, ret = %u\n", return_status); return -EIO; } /* if reset rcb cmd is unsupported, we need to send reset tqp cmd * again to reset all tqps */ return hclge_reset_tqp_cmd(handle); } int hclge_reset_tqp(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int ret; /* only need to disable PF's tqp */ if (!vport->vport_id) { ret = hclge_tqp_enable(handle, false); if (ret) { dev_err(&hdev->pdev->dev, "failed to disable tqp, ret = %d\n", ret); return ret; } } return hclge_reset_rcb(handle); } static u32 hclge_get_fw_version(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; 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; if (!phydev) return; phy_set_asym_pause(phydev, rx_en, tx_en); } static int hclge_cfg_pauseparam(struct hclge_dev *hdev, u32 rx_en, u32 tx_en) { int ret; if (hdev->tm_info.fc_mode == HCLGE_FC_PFC) return 0; ret = hclge_mac_pause_en_cfg(hdev, tx_en, rx_en); if (ret) dev_err(&hdev->pdev->dev, "configure pauseparam error, ret = %d.\n", ret); return ret; } int hclge_cfg_flowctrl(struct hclge_dev *hdev) { struct phy_device *phydev = hdev->hw.mac.phydev; u16 remote_advertising = 0; u16 local_advertising; u32 rx_pause, tx_pause; u8 flowctl; if (!phydev->link) return 0; if (!phydev->autoneg) return hclge_mac_pause_setup_hw(hdev); local_advertising = linkmode_adv_to_lcl_adv_t(phydev->advertising); if (phydev->pause) remote_advertising = LPA_PAUSE_CAP; if (phydev->asym_pause) remote_advertising |= LPA_PAUSE_ASYM; flowctl = mii_resolve_flowctrl_fdx(local_advertising, remote_advertising); tx_pause = flowctl & FLOW_CTRL_TX; rx_pause = flowctl & FLOW_CTRL_RX; if (phydev->duplex == HCLGE_MAC_HALF) { tx_pause = 0; rx_pause = 0; } return hclge_cfg_pauseparam(hdev, rx_pause, tx_pause); } static void hclge_get_pauseparam(struct hnae3_handle *handle, u32 *auto_neg, u32 *rx_en, u32 *tx_en) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u8 media_type = hdev->hw.mac.media_type; *auto_neg = (media_type == HNAE3_MEDIA_TYPE_COPPER) ? hclge_get_autoneg(handle) : 0; if (hdev->tm_info.fc_mode == HCLGE_FC_PFC) { *rx_en = 0; *tx_en = 0; return; } if (hdev->tm_info.fc_mode == HCLGE_FC_RX_PAUSE) { *rx_en = 1; *tx_en = 0; } else if (hdev->tm_info.fc_mode == HCLGE_FC_TX_PAUSE) { *tx_en = 1; *rx_en = 0; } else if (hdev->tm_info.fc_mode == HCLGE_FC_FULL) { *rx_en = 1; *tx_en = 1; } else { *rx_en = 0; *tx_en = 0; } } static void hclge_record_user_pauseparam(struct hclge_dev *hdev, u32 rx_en, u32 tx_en) { if (rx_en && tx_en) hdev->fc_mode_last_time = HCLGE_FC_FULL; else if (rx_en && !tx_en) hdev->fc_mode_last_time = HCLGE_FC_RX_PAUSE; else if (!rx_en && tx_en) hdev->fc_mode_last_time = HCLGE_FC_TX_PAUSE; else hdev->fc_mode_last_time = HCLGE_FC_NONE; hdev->tm_info.fc_mode = hdev->fc_mode_last_time; } static int hclge_set_pauseparam(struct hnae3_handle *handle, u32 auto_neg, u32 rx_en, u32 tx_en) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct phy_device *phydev = hdev->hw.mac.phydev; u32 fc_autoneg; if (phydev || hnae3_dev_phy_imp_supported(hdev)) { fc_autoneg = hclge_get_autoneg(handle); if (auto_neg != fc_autoneg) { dev_info(&hdev->pdev->dev, "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n"); return -EOPNOTSUPP; } } if (hdev->tm_info.fc_mode == HCLGE_FC_PFC) { dev_info(&hdev->pdev->dev, "Priority flow control enabled. Cannot set link flow control.\n"); return -EOPNOTSUPP; } hclge_set_flowctrl_adv(hdev, rx_en, tx_en); hclge_record_user_pauseparam(hdev, rx_en, tx_en); if (!auto_neg || hnae3_dev_phy_imp_supported(hdev)) return hclge_cfg_pauseparam(hdev, rx_en, tx_en); if (phydev) return phy_start_aneg(phydev); return -EOPNOTSUPP; } static void hclge_get_ksettings_an_result(struct hnae3_handle *handle, u8 *auto_neg, u32 *speed, u8 *duplex, u32 *lane_num) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; if (speed) *speed = hdev->hw.mac.speed; if (duplex) *duplex = hdev->hw.mac.duplex; if (auto_neg) *auto_neg = hdev->hw.mac.autoneg; if (lane_num) *lane_num = hdev->hw.mac.lane_num; } static void hclge_get_media_type(struct hnae3_handle *handle, u8 *media_type, u8 *module_type) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; /* When nic is down, the service task is not running, doesn't update * the port information per second. Query the port information before * return the media type, ensure getting the correct media information. */ hclge_update_port_info(hdev); if (media_type) *media_type = hdev->hw.mac.media_type; if (module_type) *module_type = hdev->hw.mac.module_type; } static void hclge_get_mdix_mode(struct hnae3_handle *handle, u8 *tp_mdix_ctrl, u8 *tp_mdix) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct phy_device *phydev = hdev->hw.mac.phydev; int mdix_ctrl, mdix, is_resolved; unsigned int retval; if (!phydev) { *tp_mdix_ctrl = ETH_TP_MDI_INVALID; *tp_mdix = ETH_TP_MDI_INVALID; return; } phy_write(phydev, HCLGE_PHY_PAGE_REG, HCLGE_PHY_PAGE_MDIX); retval = phy_read(phydev, HCLGE_PHY_CSC_REG); mdix_ctrl = hnae3_get_field(retval, HCLGE_PHY_MDIX_CTRL_M, HCLGE_PHY_MDIX_CTRL_S); retval = phy_read(phydev, HCLGE_PHY_CSS_REG); mdix = hnae3_get_bit(retval, HCLGE_PHY_MDIX_STATUS_B); is_resolved = hnae3_get_bit(retval, HCLGE_PHY_SPEED_DUP_RESOLVE_B); phy_write(phydev, HCLGE_PHY_PAGE_REG, HCLGE_PHY_PAGE_COPPER); switch (mdix_ctrl) { case 0x0: *tp_mdix_ctrl = ETH_TP_MDI; break; case 0x1: *tp_mdix_ctrl = ETH_TP_MDI_X; break; case 0x3: *tp_mdix_ctrl = ETH_TP_MDI_AUTO; break; default: *tp_mdix_ctrl = ETH_TP_MDI_INVALID; break; } if (!is_resolved) *tp_mdix = ETH_TP_MDI_INVALID; else if (mdix) *tp_mdix = ETH_TP_MDI_X; else *tp_mdix = ETH_TP_MDI; } static void hclge_info_show(struct hclge_dev *hdev) { struct hnae3_handle *handle = &hdev->vport->nic; struct device *dev = &hdev->pdev->dev; dev_info(dev, "PF info begin:\n"); dev_info(dev, "Task queue pairs numbers: %u\n", hdev->num_tqps); dev_info(dev, "Desc num per TX queue: %u\n", hdev->num_tx_desc); dev_info(dev, "Desc num per RX queue: %u\n", hdev->num_rx_desc); dev_info(dev, "Numbers of vports: %u\n", hdev->num_alloc_vport); dev_info(dev, "Numbers of VF for this PF: %u\n", hdev->num_req_vfs); dev_info(dev, "HW tc map: 0x%x\n", hdev->hw_tc_map); dev_info(dev, "Total buffer size for TX/RX: %u\n", hdev->pkt_buf_size); dev_info(dev, "TX buffer size for each TC: %u\n", hdev->tx_buf_size); dev_info(dev, "DV buffer size for each TC: %u\n", hdev->dv_buf_size); dev_info(dev, "This is %s PF\n", hdev->flag & HCLGE_FLAG_MAIN ? "main" : "not main"); dev_info(dev, "DCB %s\n", handle->kinfo.tc_info.dcb_ets_active ? "enable" : "disable"); dev_info(dev, "MQPRIO %s\n", handle->kinfo.tc_info.mqprio_active ? "enable" : "disable"); dev_info(dev, "Default tx spare buffer size: %u\n", hdev->tx_spare_buf_size); dev_info(dev, "PF info end.\n"); } static int hclge_init_nic_client_instance(struct hnae3_ae_dev *ae_dev, struct hclge_vport *vport) { struct hnae3_client *client = vport->nic.client; struct hclge_dev *hdev = ae_dev->priv; int rst_cnt = hdev->rst_stats.reset_cnt; int ret; ret = client->ops->init_instance(&vport->nic); if (ret) return ret; set_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state); if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || rst_cnt != hdev->rst_stats.reset_cnt) { ret = -EBUSY; goto init_nic_err; } /* Enable nic hw error interrupts */ ret = hclge_config_nic_hw_error(hdev, true); if (ret) { dev_err(&ae_dev->pdev->dev, "fail(%d) to enable hw error interrupts\n", ret); goto init_nic_err; } hnae3_set_client_init_flag(client, ae_dev, 1); if (netif_msg_drv(&hdev->vport->nic)) hclge_info_show(hdev); return ret; init_nic_err: clear_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state); while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) msleep(HCLGE_WAIT_RESET_DONE); client->ops->uninit_instance(&vport->nic, 0); return ret; } static int hclge_init_roce_client_instance(struct hnae3_ae_dev *ae_dev, struct hclge_vport *vport) { struct hclge_dev *hdev = ae_dev->priv; struct hnae3_client *client; int rst_cnt; int ret; if (!hnae3_dev_roce_supported(hdev) || !hdev->roce_client || !hdev->nic_client) return 0; client = hdev->roce_client; ret = hclge_init_roce_base_info(vport); if (ret) return ret; rst_cnt = hdev->rst_stats.reset_cnt; ret = client->ops->init_instance(&vport->roce); if (ret) return ret; set_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state); if (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || rst_cnt != hdev->rst_stats.reset_cnt) { ret = -EBUSY; goto init_roce_err; } /* Enable roce ras interrupts */ ret = hclge_config_rocee_ras_interrupt(hdev, true); if (ret) { dev_err(&ae_dev->pdev->dev, "fail(%d) to enable roce ras interrupts\n", ret); goto init_roce_err; } hnae3_set_client_init_flag(client, ae_dev, 1); return 0; init_roce_err: clear_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state); while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) msleep(HCLGE_WAIT_RESET_DONE); hdev->roce_client->ops->uninit_instance(&vport->roce, 0); return ret; } static int hclge_init_client_instance(struct hnae3_client *client, struct hnae3_ae_dev *ae_dev) { struct hclge_dev *hdev = ae_dev->priv; struct hclge_vport *vport = &hdev->vport[0]; int ret; switch (client->type) { case HNAE3_CLIENT_KNIC: hdev->nic_client = client; vport->nic.client = client; ret = hclge_init_nic_client_instance(ae_dev, vport); if (ret) goto clear_nic; ret = hclge_init_roce_client_instance(ae_dev, vport); if (ret) goto clear_roce; break; case HNAE3_CLIENT_ROCE: if (hnae3_dev_roce_supported(hdev)) { hdev->roce_client = client; vport->roce.client = client; } ret = hclge_init_roce_client_instance(ae_dev, vport); if (ret) goto clear_roce; break; default: return -EINVAL; } return 0; clear_nic: hdev->nic_client = NULL; vport->nic.client = NULL; return ret; clear_roce: hdev->roce_client = NULL; vport->roce.client = NULL; return ret; } static bool hclge_uninit_need_wait(struct hclge_dev *hdev) { return test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state) || test_bit(HCLGE_STATE_LINK_UPDATING, &hdev->state); } static void hclge_uninit_client_instance(struct hnae3_client *client, struct hnae3_ae_dev *ae_dev) { struct hclge_dev *hdev = ae_dev->priv; struct hclge_vport *vport = &hdev->vport[0]; if (hdev->roce_client) { clear_bit(HCLGE_STATE_ROCE_REGISTERED, &hdev->state); while (hclge_uninit_need_wait(hdev)) msleep(HCLGE_WAIT_RESET_DONE); hdev->roce_client->ops->uninit_instance(&vport->roce, 0); hdev->roce_client = NULL; vport->roce.client = NULL; } if (client->type == HNAE3_CLIENT_ROCE) return; if (hdev->nic_client && client->ops->uninit_instance) { clear_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state); while (test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) msleep(HCLGE_WAIT_RESET_DONE); client->ops->uninit_instance(&vport->nic, 0); hdev->nic_client = NULL; vport->nic.client = NULL; } } static int hclge_dev_mem_map(struct hclge_dev *hdev) { struct pci_dev *pdev = hdev->pdev; struct hclge_hw *hw = &hdev->hw; /* for device does not have device memory, return directly */ if (!(pci_select_bars(pdev, IORESOURCE_MEM) & BIT(HCLGE_MEM_BAR))) return 0; hw->hw.mem_base = devm_ioremap_wc(&pdev->dev, pci_resource_start(pdev, HCLGE_MEM_BAR), pci_resource_len(pdev, HCLGE_MEM_BAR)); if (!hw->hw.mem_base) { dev_err(&pdev->dev, "failed to map device memory\n"); return -EFAULT; } return 0; } static int hclge_pci_init(struct hclge_dev *hdev) { struct pci_dev *pdev = hdev->pdev; struct hclge_hw *hw; int ret; ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "failed to enable PCI device\n"); return ret; } ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (ret) { ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { dev_err(&pdev->dev, "can't set consistent PCI DMA"); goto err_disable_device; } dev_warn(&pdev->dev, "set DMA mask to 32 bits\n"); } ret = pci_request_regions(pdev, HCLGE_DRIVER_NAME); if (ret) { dev_err(&pdev->dev, "PCI request regions failed %d\n", ret); goto err_disable_device; } pci_set_master(pdev); hw = &hdev->hw; hw->hw.io_base = pcim_iomap(pdev, 2, 0); if (!hw->hw.io_base) { dev_err(&pdev->dev, "Can't map configuration register space\n"); ret = -ENOMEM; goto err_release_regions; } ret = hclge_dev_mem_map(hdev); if (ret) goto err_unmap_io_base; hdev->num_req_vfs = pci_sriov_get_totalvfs(pdev); return 0; err_unmap_io_base: pcim_iounmap(pdev, hdev->hw.hw.io_base); err_release_regions: pci_release_regions(pdev); err_disable_device: pci_disable_device(pdev); return ret; } static void hclge_pci_uninit(struct hclge_dev *hdev) { struct pci_dev *pdev = hdev->pdev; if (hdev->hw.hw.mem_base) devm_iounmap(&pdev->dev, hdev->hw.hw.mem_base); pcim_iounmap(pdev, hdev->hw.hw.io_base); pci_free_irq_vectors(pdev); pci_release_mem_regions(pdev); pci_disable_device(pdev); } static void hclge_state_init(struct hclge_dev *hdev) { set_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state); set_bit(HCLGE_STATE_DOWN, &hdev->state); clear_bit(HCLGE_STATE_RST_SERVICE_SCHED, &hdev->state); clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state); clear_bit(HCLGE_STATE_RST_FAIL, &hdev->state); clear_bit(HCLGE_STATE_MBX_SERVICE_SCHED, &hdev->state); clear_bit(HCLGE_STATE_MBX_HANDLING, &hdev->state); } static void hclge_state_uninit(struct hclge_dev *hdev) { set_bit(HCLGE_STATE_DOWN, &hdev->state); set_bit(HCLGE_STATE_REMOVING, &hdev->state); if (hdev->reset_timer.function) del_timer_sync(&hdev->reset_timer); if (hdev->service_task.work.func) cancel_delayed_work_sync(&hdev->service_task); } static void hclge_reset_prepare_general(struct hnae3_ae_dev *ae_dev, enum hnae3_reset_type rst_type) { #define HCLGE_RESET_RETRY_WAIT_MS 500 #define HCLGE_RESET_RETRY_CNT 5 struct hclge_dev *hdev = ae_dev->priv; int retry_cnt = 0; int ret; while (retry_cnt++ < HCLGE_RESET_RETRY_CNT) { down(&hdev->reset_sem); set_bit(HCLGE_STATE_RST_HANDLING, &hdev->state); hdev->reset_type = rst_type; ret = hclge_reset_prepare(hdev); if (!ret && !hdev->reset_pending) break; dev_err(&hdev->pdev->dev, "failed to prepare to reset, ret=%d, reset_pending:0x%lx, retry_cnt:%d\n", ret, hdev->reset_pending, retry_cnt); clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state); up(&hdev->reset_sem); msleep(HCLGE_RESET_RETRY_WAIT_MS); } /* disable misc vector before reset done */ hclge_enable_vector(&hdev->misc_vector, false); set_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state); if (hdev->reset_type == HNAE3_FLR_RESET) hdev->rst_stats.flr_rst_cnt++; } static void hclge_reset_done(struct hnae3_ae_dev *ae_dev) { struct hclge_dev *hdev = ae_dev->priv; int ret; hclge_enable_vector(&hdev->misc_vector, true); ret = hclge_reset_rebuild(hdev); if (ret) dev_err(&hdev->pdev->dev, "fail to rebuild, ret=%d\n", ret); hdev->reset_type = HNAE3_NONE_RESET; clear_bit(HCLGE_STATE_RST_HANDLING, &hdev->state); up(&hdev->reset_sem); } static void hclge_clear_resetting_state(struct hclge_dev *hdev) { u16 i; for (i = 0; i < hdev->num_alloc_vport; i++) { struct hclge_vport *vport = &hdev->vport[i]; int ret; /* Send cmd to clear vport's FUNC_RST_ING */ ret = hclge_set_vf_rst(hdev, vport->vport_id, false); if (ret) dev_warn(&hdev->pdev->dev, "clear vport(%u) rst failed %d!\n", vport->vport_id, ret); } } static int hclge_clear_hw_resource(struct hclge_dev *hdev) { struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CLEAR_HW_RESOURCE, false); ret = hclge_cmd_send(&hdev->hw, &desc, 1); /* This new command is only supported by new firmware, it will * fail with older firmware. Error value -EOPNOSUPP can only be * returned by older firmware running this command, to keep code * backward compatible we will override this value and return * success. */ if (ret && ret != -EOPNOTSUPP) { dev_err(&hdev->pdev->dev, "failed to clear hw resource, ret = %d\n", ret); return ret; } return 0; } static void hclge_init_rxd_adv_layout(struct hclge_dev *hdev) { if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev)) hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 1); } static void hclge_uninit_rxd_adv_layout(struct hclge_dev *hdev) { if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev)) hclge_write_dev(&hdev->hw, HCLGE_RXD_ADV_LAYOUT_EN_REG, 0); } static struct hclge_wol_info *hclge_get_wol_info(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); return &vport->back->hw.mac.wol; } static int hclge_get_wol_supported_mode(struct hclge_dev *hdev, u32 *wol_supported) { struct hclge_query_wol_supported_cmd *wol_supported_cmd; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_WOL_GET_SUPPORTED_MODE, true); wol_supported_cmd = (struct hclge_query_wol_supported_cmd *)desc.data; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to query wol supported, ret = %d\n", ret); return ret; } *wol_supported = le32_to_cpu(wol_supported_cmd->supported_wake_mode); return 0; } static int hclge_set_wol_cfg(struct hclge_dev *hdev, struct hclge_wol_info *wol_info) { struct hclge_wol_cfg_cmd *wol_cfg_cmd; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_WOL_CFG, false); wol_cfg_cmd = (struct hclge_wol_cfg_cmd *)desc.data; wol_cfg_cmd->wake_on_lan_mode = cpu_to_le32(wol_info->wol_current_mode); wol_cfg_cmd->sopass_size = wol_info->wol_sopass_size; memcpy(wol_cfg_cmd->sopass, wol_info->wol_sopass, SOPASS_MAX); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "failed to set wol config, ret = %d\n", ret); return ret; } static int hclge_update_wol(struct hclge_dev *hdev) { struct hclge_wol_info *wol_info = &hdev->hw.mac.wol; if (!hnae3_ae_dev_wol_supported(hdev->ae_dev)) return 0; return hclge_set_wol_cfg(hdev, wol_info); } static int hclge_init_wol(struct hclge_dev *hdev) { struct hclge_wol_info *wol_info = &hdev->hw.mac.wol; int ret; if (!hnae3_ae_dev_wol_supported(hdev->ae_dev)) return 0; memset(wol_info, 0, sizeof(struct hclge_wol_info)); ret = hclge_get_wol_supported_mode(hdev, &wol_info->wol_support_mode); if (ret) { wol_info->wol_support_mode = 0; return ret; } return hclge_update_wol(hdev); } static void hclge_get_wol(struct hnae3_handle *handle, struct ethtool_wolinfo *wol) { struct hclge_wol_info *wol_info = hclge_get_wol_info(handle); wol->supported = wol_info->wol_support_mode; wol->wolopts = wol_info->wol_current_mode; if (wol_info->wol_current_mode & WAKE_MAGICSECURE) memcpy(wol->sopass, wol_info->wol_sopass, SOPASS_MAX); } static int hclge_set_wol(struct hnae3_handle *handle, struct ethtool_wolinfo *wol) { struct hclge_wol_info *wol_info = hclge_get_wol_info(handle); struct hclge_vport *vport = hclge_get_vport(handle); u32 wol_mode; int ret; wol_mode = wol->wolopts; if (wol_mode & ~wol_info->wol_support_mode) return -EINVAL; wol_info->wol_current_mode = wol_mode; if (wol_mode & WAKE_MAGICSECURE) { memcpy(wol_info->wol_sopass, wol->sopass, SOPASS_MAX); wol_info->wol_sopass_size = SOPASS_MAX; } else { wol_info->wol_sopass_size = 0; } ret = hclge_set_wol_cfg(vport->back, wol_info); if (ret) wol_info->wol_current_mode = 0; return ret; } static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) { struct pci_dev *pdev = ae_dev->pdev; struct hclge_dev *hdev; int ret; hdev = devm_kzalloc(&pdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; hdev->pdev = pdev; hdev->ae_dev = ae_dev; hdev->reset_type = HNAE3_NONE_RESET; hdev->reset_level = HNAE3_FUNC_RESET; ae_dev->priv = hdev; /* HW supprt 2 layer vlan */ hdev->mps = ETH_FRAME_LEN + ETH_FCS_LEN + 2 * VLAN_HLEN; mutex_init(&hdev->vport_lock); spin_lock_init(&hdev->fd_rule_lock); sema_init(&hdev->reset_sem, 1); ret = hclge_pci_init(hdev); if (ret) goto out; /* Firmware command queue initialize */ ret = hclge_comm_cmd_queue_init(hdev->pdev, &hdev->hw.hw); if (ret) goto err_pci_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) goto err_cmd_uninit; ret = hclge_clear_hw_resource(hdev); if (ret) goto err_cmd_uninit; ret = hclge_get_cap(hdev); if (ret) goto err_cmd_uninit; ret = hclge_query_dev_specs(hdev); if (ret) { dev_err(&pdev->dev, "failed to query dev specifications, ret = %d.\n", ret); goto err_cmd_uninit; } ret = hclge_configure(hdev); if (ret) { dev_err(&pdev->dev, "Configure dev error, ret = %d.\n", ret); goto err_cmd_uninit; } ret = hclge_init_msi(hdev); if (ret) { dev_err(&pdev->dev, "Init MSI/MSI-X error, ret = %d.\n", ret); goto err_cmd_uninit; } ret = hclge_misc_irq_init(hdev); if (ret) goto err_msi_uninit; ret = hclge_alloc_tqps(hdev); if (ret) { dev_err(&pdev->dev, "Allocate TQPs error, ret = %d.\n", ret); goto err_msi_irq_uninit; } ret = hclge_alloc_vport(hdev); if (ret) goto err_msi_irq_uninit; ret = hclge_map_tqp(hdev); if (ret) goto err_msi_irq_uninit; if (hdev->hw.mac.media_type == HNAE3_MEDIA_TYPE_COPPER) { clear_bit(HNAE3_DEV_SUPPORT_FEC_B, ae_dev->caps); if (hnae3_dev_phy_imp_supported(hdev)) ret = hclge_update_tp_port_info(hdev); else ret = hclge_mac_mdio_config(hdev); if (ret) goto err_msi_irq_uninit; } ret = hclge_init_umv_space(hdev); if (ret) goto err_mdiobus_unreg; ret = hclge_mac_init(hdev); if (ret) { dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret); goto err_mdiobus_unreg; } ret = hclge_config_tso(hdev, HCLGE_TSO_MSS_MIN, HCLGE_TSO_MSS_MAX); if (ret) { dev_err(&pdev->dev, "Enable tso fail, ret =%d\n", ret); goto err_mdiobus_unreg; } ret = hclge_config_gro(hdev); if (ret) goto err_mdiobus_unreg; ret = hclge_init_vlan_config(hdev); if (ret) { dev_err(&pdev->dev, "VLAN init fail, ret =%d\n", ret); goto err_mdiobus_unreg; } ret = hclge_tm_schd_init(hdev); if (ret) { dev_err(&pdev->dev, "tm schd init fail, ret =%d\n", ret); goto err_mdiobus_unreg; } ret = hclge_comm_rss_init_cfg(&hdev->vport->nic, hdev->ae_dev, &hdev->rss_cfg); if (ret) { dev_err(&pdev->dev, "failed to init rss cfg, ret = %d\n", ret); goto err_mdiobus_unreg; } ret = hclge_rss_init_hw(hdev); if (ret) { dev_err(&pdev->dev, "Rss init fail, ret =%d\n", ret); goto err_mdiobus_unreg; } ret = init_mgr_tbl(hdev); if (ret) { dev_err(&pdev->dev, "manager table init fail, ret =%d\n", ret); goto err_mdiobus_unreg; } ret = hclge_init_fd_config(hdev); if (ret) { dev_err(&pdev->dev, "fd table init fail, ret=%d\n", ret); goto err_mdiobus_unreg; } ret = hclge_ptp_init(hdev); if (ret) goto err_mdiobus_unreg; ret = hclge_update_port_info(hdev); if (ret) goto err_ptp_uninit; INIT_KFIFO(hdev->mac_tnl_log); hclge_dcb_ops_set(hdev); timer_setup(&hdev->reset_timer, hclge_reset_timer, 0); INIT_DELAYED_WORK(&hdev->service_task, hclge_service_task); hclge_clear_all_event_cause(hdev); hclge_clear_resetting_state(hdev); /* Log and clear the hw errors those already occurred */ if (hnae3_dev_ras_imp_supported(hdev)) hclge_handle_occurred_error(hdev); else hclge_handle_all_hns_hw_errors(ae_dev); /* request delayed reset for the error recovery because an immediate * global reset on a PF affecting pending initialization of other PFs */ if (ae_dev->hw_err_reset_req) { enum hnae3_reset_type reset_level; reset_level = hclge_get_reset_level(ae_dev, &ae_dev->hw_err_reset_req); hclge_set_def_reset_request(ae_dev, reset_level); mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL); } hclge_init_rxd_adv_layout(hdev); /* Enable MISC vector(vector0) */ hclge_enable_vector(&hdev->misc_vector, true); ret = hclge_init_wol(hdev); if (ret) dev_warn(&pdev->dev, "failed to wake on lan init, ret = %d\n", ret); ret = hclge_devlink_init(hdev); if (ret) goto err_ptp_uninit; hclge_state_init(hdev); hdev->last_reset_time = jiffies; dev_info(&hdev->pdev->dev, "%s driver initialization finished.\n", HCLGE_DRIVER_NAME); hclge_task_schedule(hdev, round_jiffies_relative(HZ)); return 0; err_ptp_uninit: hclge_ptp_uninit(hdev); err_mdiobus_unreg: if (hdev->hw.mac.phydev) mdiobus_unregister(hdev->hw.mac.mdio_bus); err_msi_irq_uninit: hclge_misc_irq_uninit(hdev); err_msi_uninit: pci_free_irq_vectors(pdev); err_cmd_uninit: hclge_comm_cmd_uninit(hdev->ae_dev, &hdev->hw.hw); err_pci_uninit: pcim_iounmap(pdev, hdev->hw.hw.io_base); pci_release_regions(pdev); pci_disable_device(pdev); out: mutex_destroy(&hdev->vport_lock); return ret; } static void hclge_stats_clear(struct hclge_dev *hdev) { memset(&hdev->mac_stats, 0, sizeof(hdev->mac_stats)); memset(&hdev->fec_stats, 0, sizeof(hdev->fec_stats)); } static int hclge_set_mac_spoofchk(struct hclge_dev *hdev, int vf, bool enable) { return hclge_config_switch_param(hdev, vf, enable, HCLGE_SWITCH_ANTI_SPOOF_MASK); } static int hclge_set_vlan_spoofchk(struct hclge_dev *hdev, int vf, bool enable) { return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, HCLGE_FILTER_FE_NIC_INGRESS_B, enable, vf); } static int hclge_set_vf_spoofchk_hw(struct hclge_dev *hdev, int vf, bool enable) { int ret; ret = hclge_set_mac_spoofchk(hdev, vf, enable); if (ret) { dev_err(&hdev->pdev->dev, "Set vf %d mac spoof check %s failed, ret=%d\n", vf, enable ? "on" : "off", ret); return ret; } ret = hclge_set_vlan_spoofchk(hdev, vf, enable); if (ret) dev_err(&hdev->pdev->dev, "Set vf %d vlan spoof check %s failed, ret=%d\n", vf, enable ? "on" : "off", ret); return ret; } static int hclge_set_vf_spoofchk(struct hnae3_handle *handle, int vf, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u32 new_spoofchk = enable ? 1 : 0; int ret; if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) return -EOPNOTSUPP; vport = hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; if (vport->vf_info.spoofchk == new_spoofchk) return 0; if (enable && test_bit(vport->vport_id, hdev->vf_vlan_full)) dev_warn(&hdev->pdev->dev, "vf %d vlan table is full, enable spoof check may cause its packet send fail\n", vf); else if (enable && hclge_is_umv_space_full(vport, true)) dev_warn(&hdev->pdev->dev, "vf %d mac table is full, enable spoof check may cause its packet send fail\n", vf); ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, enable); if (ret) return ret; vport->vf_info.spoofchk = new_spoofchk; return 0; } static int hclge_reset_vport_spoofchk(struct hclge_dev *hdev) { struct hclge_vport *vport = hdev->vport; int ret; int i; if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) return 0; /* resume the vf spoof check state after reset */ for (i = 0; i < hdev->num_alloc_vport; i++) { ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, vport->vf_info.spoofchk); if (ret) return ret; vport++; } return 0; } static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u32 new_trusted = enable ? 1 : 0; vport = hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; if (vport->vf_info.trusted == new_trusted) return 0; vport->vf_info.trusted = new_trusted; set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); hclge_task_schedule(hdev, 0); return 0; } static void hclge_reset_vf_rate(struct hclge_dev *hdev) { int ret; int vf; /* reset vf rate to default value */ for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) { struct hclge_vport *vport = &hdev->vport[vf]; vport->vf_info.max_tx_rate = 0; ret = hclge_tm_qs_shaper_cfg(vport, vport->vf_info.max_tx_rate); if (ret) dev_err(&hdev->pdev->dev, "vf%d failed to reset to default, ret=%d\n", vf - HCLGE_VF_VPORT_START_NUM, ret); } } static int hclge_vf_rate_param_check(struct hclge_dev *hdev, int min_tx_rate, int max_tx_rate) { if (min_tx_rate != 0 || max_tx_rate < 0 || max_tx_rate > hdev->hw.mac.max_speed) { dev_err(&hdev->pdev->dev, "min_tx_rate:%d [0], max_tx_rate:%d [0, %u]\n", min_tx_rate, max_tx_rate, hdev->hw.mac.max_speed); return -EINVAL; } return 0; } static int hclge_set_vf_rate(struct hnae3_handle *handle, int vf, int min_tx_rate, int max_tx_rate, bool force) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; int ret; ret = hclge_vf_rate_param_check(hdev, min_tx_rate, max_tx_rate); if (ret) return ret; vport = hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; if (!force && max_tx_rate == vport->vf_info.max_tx_rate) return 0; ret = hclge_tm_qs_shaper_cfg(vport, max_tx_rate); if (ret) return ret; vport->vf_info.max_tx_rate = max_tx_rate; return 0; } static int hclge_resume_vf_rate(struct hclge_dev *hdev) { struct hnae3_handle *handle = &hdev->vport->nic; struct hclge_vport *vport; int ret; int vf; /* resume the vf max_tx_rate after reset */ for (vf = 0; vf < pci_num_vf(hdev->pdev); vf++) { vport = hclge_get_vf_vport(hdev, vf); if (!vport) return -EINVAL; /* zero means max rate, after reset, firmware already set it to * max rate, so just continue. */ if (!vport->vf_info.max_tx_rate) continue; ret = hclge_set_vf_rate(handle, vf, 0, vport->vf_info.max_tx_rate, true); if (ret) { dev_err(&hdev->pdev->dev, "vf%d failed to resume tx_rate:%u, ret=%d\n", vf, vport->vf_info.max_tx_rate, ret); return ret; } } return 0; } static void hclge_reset_vport_state(struct hclge_dev *hdev) { struct hclge_vport *vport = hdev->vport; int i; for (i = 0; i < hdev->num_alloc_vport; i++) { clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); vport++; } } static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) { struct hclge_dev *hdev = ae_dev->priv; struct pci_dev *pdev = ae_dev->pdev; int ret; set_bit(HCLGE_STATE_DOWN, &hdev->state); hclge_stats_clear(hdev); /* NOTE: pf reset needn't to clear or restore pf and vf table entry. * so here should not clean table in memory. */ if (hdev->reset_type == HNAE3_IMP_RESET || hdev->reset_type == HNAE3_GLOBAL_RESET) { memset(hdev->vlan_table, 0, sizeof(hdev->vlan_table)); memset(hdev->vf_vlan_full, 0, sizeof(hdev->vf_vlan_full)); bitmap_set(hdev->vport_config_block, 0, hdev->num_alloc_vport); hclge_reset_umv_space(hdev); } ret = hclge_comm_cmd_init(hdev->ae_dev, &hdev->hw.hw, &hdev->fw_version, true, hdev->reset_pending); if (ret) { dev_err(&pdev->dev, "Cmd queue init failed\n"); return ret; } ret = hclge_map_tqp(hdev); if (ret) { dev_err(&pdev->dev, "Map tqp error, ret = %d.\n", ret); return ret; } ret = hclge_mac_init(hdev); if (ret) { dev_err(&pdev->dev, "Mac init error, ret = %d\n", ret); return ret; } ret = hclge_tp_port_init(hdev); if (ret) { dev_err(&pdev->dev, "failed to init tp port, ret = %d\n", ret); return ret; } ret = hclge_config_tso(hdev, HCLGE_TSO_MSS_MIN, HCLGE_TSO_MSS_MAX); if (ret) { dev_err(&pdev->dev, "Enable tso fail, ret =%d\n", ret); return ret; } ret = hclge_config_gro(hdev); if (ret) return ret; ret = hclge_init_vlan_config(hdev); if (ret) { dev_err(&pdev->dev, "VLAN init fail, ret =%d\n", ret); return ret; } hclge_reset_tc_config(hdev); ret = hclge_tm_init_hw(hdev, true); if (ret) { dev_err(&pdev->dev, "tm init hw fail, ret =%d\n", ret); return ret; } ret = hclge_rss_init_hw(hdev); if (ret) { dev_err(&pdev->dev, "Rss init fail, ret =%d\n", ret); return ret; } ret = init_mgr_tbl(hdev); if (ret) { dev_err(&pdev->dev, "failed to reinit manager table, ret = %d\n", ret); return ret; } ret = hclge_init_fd_config(hdev); if (ret) { dev_err(&pdev->dev, "fd table init fail, ret=%d\n", ret); return ret; } ret = hclge_ptp_init(hdev); if (ret) return ret; /* Log and clear the hw errors those already occurred */ if (hnae3_dev_ras_imp_supported(hdev)) hclge_handle_occurred_error(hdev); else hclge_handle_all_hns_hw_errors(ae_dev); /* Re-enable the hw error interrupts because * the interrupts get disabled on global reset. */ ret = hclge_config_nic_hw_error(hdev, true); if (ret) { dev_err(&pdev->dev, "fail(%d) to re-enable NIC hw error interrupts\n", ret); return ret; } if (hdev->roce_client) { ret = hclge_config_rocee_ras_interrupt(hdev, true); if (ret) { dev_err(&pdev->dev, "fail(%d) to re-enable roce ras interrupts\n", ret); return ret; } } hclge_reset_vport_state(hdev); ret = hclge_reset_vport_spoofchk(hdev); if (ret) return ret; ret = hclge_resume_vf_rate(hdev); if (ret) return ret; hclge_init_rxd_adv_layout(hdev); ret = hclge_update_wol(hdev); if (ret) dev_warn(&pdev->dev, "failed to update wol config, ret = %d\n", ret); dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n", HCLGE_DRIVER_NAME); return 0; } static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) { struct hclge_dev *hdev = ae_dev->priv; struct hclge_mac *mac = &hdev->hw.mac; hclge_reset_vf_rate(hdev); hclge_clear_vf_vlan(hdev); hclge_state_uninit(hdev); hclge_ptp_uninit(hdev); hclge_uninit_rxd_adv_layout(hdev); hclge_uninit_mac_table(hdev); hclge_del_all_fd_entries(hdev); if (mac->phydev) mdiobus_unregister(mac->mdio_bus); /* Disable MISC vector(vector0) */ hclge_enable_vector(&hdev->misc_vector, false); synchronize_irq(hdev->misc_vector.vector_irq); /* Disable all hw interrupts */ hclge_config_mac_tnl_int(hdev, false); hclge_config_nic_hw_error(hdev, false); hclge_config_rocee_ras_interrupt(hdev, false); hclge_comm_cmd_uninit(hdev->ae_dev, &hdev->hw.hw); hclge_misc_irq_uninit(hdev); hclge_devlink_uninit(hdev); hclge_pci_uninit(hdev); hclge_uninit_vport_vlan_table(hdev); mutex_destroy(&hdev->vport_lock); ae_dev->priv = NULL; } static u32 hclge_get_max_channels(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; return min_t(u32, hdev->pf_rss_size_max, vport->alloc_tqps); } static void hclge_get_channels(struct hnae3_handle *handle, struct ethtool_channels *ch) { ch->max_combined = hclge_get_max_channels(handle); ch->other_count = 1; ch->max_other = 1; ch->combined_count = handle->kinfo.rss_size; } static void hclge_get_tqps_and_rss_info(struct hnae3_handle *handle, u16 *alloc_tqps, u16 *max_rss_size) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; *alloc_tqps = vport->alloc_tqps; *max_rss_size = hdev->pf_rss_size_max; } static int hclge_set_rss_tc_mode_cfg(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); u16 tc_offset[HCLGE_MAX_TC_NUM] = {0}; struct hclge_dev *hdev = vport->back; u16 tc_size[HCLGE_MAX_TC_NUM] = {0}; u16 tc_valid[HCLGE_MAX_TC_NUM]; u16 roundup_size; unsigned int i; roundup_size = roundup_pow_of_two(vport->nic.kinfo.rss_size); roundup_size = ilog2(roundup_size); /* Set the RSS TC mode according to the new RSS size */ for (i = 0; i < HCLGE_MAX_TC_NUM; i++) { tc_valid[i] = 0; if (!(hdev->hw_tc_map & BIT(i))) continue; tc_valid[i] = 1; tc_size[i] = roundup_size; tc_offset[i] = vport->nic.kinfo.rss_size * i; } return hclge_comm_set_rss_tc_mode(&hdev->hw.hw, tc_offset, tc_valid, tc_size); } static int hclge_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, bool rxfh_configured) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev); struct hclge_vport *vport = hclge_get_vport(handle); struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; struct hclge_dev *hdev = vport->back; u16 cur_rss_size = kinfo->rss_size; u16 cur_tqps = kinfo->num_tqps; u32 *rss_indir; unsigned int i; int ret; kinfo->req_rss_size = new_tqps_num; ret = hclge_tm_vport_map_update(hdev); if (ret) { dev_err(&hdev->pdev->dev, "tm vport map fail, ret =%d\n", ret); return ret; } ret = hclge_set_rss_tc_mode_cfg(handle); if (ret) return ret; /* RSS indirection table has been configured by user */ if (rxfh_configured) goto out; /* Reinitializes the rss indirect table according to the new RSS size */ rss_indir = kcalloc(ae_dev->dev_specs.rss_ind_tbl_size, sizeof(u32), GFP_KERNEL); if (!rss_indir) return -ENOMEM; for (i = 0; i < ae_dev->dev_specs.rss_ind_tbl_size; i++) rss_indir[i] = i % kinfo->rss_size; ret = hclge_set_rss(handle, rss_indir, NULL, 0); if (ret) dev_err(&hdev->pdev->dev, "set rss indir table fail, ret=%d\n", ret); kfree(rss_indir); out: if (!ret) dev_info(&hdev->pdev->dev, "Channels changed, rss_size from %u to %u, tqps from %u to %u", cur_rss_size, kinfo->rss_size, cur_tqps, kinfo->rss_size * kinfo->tc_info.num_tc); return ret; } static int hclge_set_led_status(struct hclge_dev *hdev, u8 locate_led_status) { struct hclge_set_led_state_cmd *req; struct hclge_desc desc; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_LED_STATUS_CFG, false); req = (struct hclge_set_led_state_cmd *)desc.data; hnae3_set_field(req->locate_led_config, HCLGE_LED_LOCATE_STATE_M, HCLGE_LED_LOCATE_STATE_S, locate_led_status); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) dev_err(&hdev->pdev->dev, "Send set led state cmd error, ret =%d\n", ret); return ret; } enum hclge_led_status { HCLGE_LED_OFF, HCLGE_LED_ON, HCLGE_LED_NO_CHANGE = 0xFF, }; static int hclge_set_led_id(struct hnae3_handle *handle, enum ethtool_phys_id_state status) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; switch (status) { case ETHTOOL_ID_ACTIVE: return hclge_set_led_status(hdev, HCLGE_LED_ON); case ETHTOOL_ID_INACTIVE: return hclge_set_led_status(hdev, HCLGE_LED_OFF); default: return -EINVAL; } } static void hclge_get_link_mode(struct hnae3_handle *handle, unsigned long *supported, unsigned long *advertising) { unsigned int size = BITS_TO_LONGS(__ETHTOOL_LINK_MODE_MASK_NBITS); struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; unsigned int idx = 0; for (; idx < size; idx++) { supported[idx] = hdev->hw.mac.supported[idx]; advertising[idx] = hdev->hw.mac.advertising[idx]; } } static int hclge_gro_en(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; bool gro_en_old = hdev->gro_en; int ret; hdev->gro_en = enable; ret = hclge_config_gro(hdev); if (ret) hdev->gro_en = gro_en_old; return ret; } static int hclge_sync_vport_promisc_mode(struct hclge_vport *vport) { struct hnae3_handle *handle = &vport->nic; struct hclge_dev *hdev = vport->back; bool uc_en = false; bool mc_en = false; u8 tmp_flags; bool bc_en; int ret; if (vport->last_promisc_flags != vport->overflow_promisc_flags) { set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); vport->last_promisc_flags = vport->overflow_promisc_flags; } if (!test_and_clear_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state)) return 0; /* for PF */ if (!vport->vport_id) { tmp_flags = handle->netdev_flags | vport->last_promisc_flags; ret = hclge_set_promisc_mode(handle, tmp_flags & HNAE3_UPE, tmp_flags & HNAE3_MPE); if (!ret) set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, &vport->state); else set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); return ret; } /* for VF */ if (vport->vf_info.trusted) { uc_en = vport->vf_info.request_uc_en > 0 || vport->overflow_promisc_flags & HNAE3_OVERFLOW_UPE; mc_en = vport->vf_info.request_mc_en > 0 || vport->overflow_promisc_flags & HNAE3_OVERFLOW_MPE; } bc_en = vport->vf_info.request_bc_en > 0; ret = hclge_cmd_set_promisc_mode(hdev, vport->vport_id, uc_en, mc_en, bc_en); if (ret) { set_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE, &vport->state); return ret; } hclge_set_vport_vlan_fltr_change(vport); return 0; } static void hclge_sync_promisc_mode(struct hclge_dev *hdev) { struct hclge_vport *vport; int ret; u16 i; for (i = 0; i < hdev->num_alloc_vport; i++) { vport = &hdev->vport[i]; ret = hclge_sync_vport_promisc_mode(vport); if (ret) return; } } static bool hclge_module_existed(struct hclge_dev *hdev) { struct hclge_desc desc; u32 existed; int ret; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_EXIST, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to get SFP exist state, ret = %d\n", ret); return false; } existed = le32_to_cpu(desc.data[0]); return existed != 0; } /* need 6 bds(total 140 bytes) in one reading * return the number of bytes actually read, 0 means read failed. */ static u16 hclge_get_sfp_eeprom_info(struct hclge_dev *hdev, u32 offset, u32 len, u8 *data) { struct hclge_desc desc[HCLGE_SFP_INFO_CMD_NUM]; struct hclge_sfp_info_bd0_cmd *sfp_info_bd0; u16 read_len; u16 copy_len; int ret; int i; /* setup all 6 bds to read module eeprom info. */ for (i = 0; i < HCLGE_SFP_INFO_CMD_NUM; i++) { hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_GET_SFP_EEPROM, true); /* bd0~bd4 need next flag */ if (i < HCLGE_SFP_INFO_CMD_NUM - 1) desc[i].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT); } /* setup bd0, this bd contains offset and read length. */ sfp_info_bd0 = (struct hclge_sfp_info_bd0_cmd *)desc[0].data; sfp_info_bd0->offset = cpu_to_le16((u16)offset); read_len = min_t(u16, len, HCLGE_SFP_INFO_MAX_LEN); sfp_info_bd0->read_len = cpu_to_le16(read_len); ret = hclge_cmd_send(&hdev->hw, desc, i); if (ret) { dev_err(&hdev->pdev->dev, "failed to get SFP eeprom info, ret = %d\n", ret); return 0; } /* copy sfp info from bd0 to out buffer. */ copy_len = min_t(u16, len, HCLGE_SFP_INFO_BD0_LEN); memcpy(data, sfp_info_bd0->data, copy_len); read_len = copy_len; /* copy sfp info from bd1~bd5 to out buffer if needed. */ for (i = 1; i < HCLGE_SFP_INFO_CMD_NUM; i++) { if (read_len >= len) return read_len; copy_len = min_t(u16, len - read_len, HCLGE_SFP_INFO_BDX_LEN); memcpy(data + read_len, desc[i].data, copy_len); read_len += copy_len; } return read_len; } static int hclge_get_module_eeprom(struct hnae3_handle *handle, u32 offset, u32 len, u8 *data) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; u32 read_len = 0; u16 data_len; if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_FIBER) return -EOPNOTSUPP; if (!hclge_module_existed(hdev)) return -ENXIO; while (read_len < len) { data_len = hclge_get_sfp_eeprom_info(hdev, offset + read_len, len - read_len, data + read_len); if (!data_len) return -EIO; read_len += data_len; } return 0; } static int hclge_get_link_diagnosis_info(struct hnae3_handle *handle, u32 *status_code) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; struct hclge_desc desc; int ret; if (hdev->ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2) return -EOPNOTSUPP; hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_LINK_DIAGNOSIS, true); ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, "failed to query link diagnosis info, ret = %d\n", ret); return ret; } *status_code = le32_to_cpu(desc.data[0]); return 0; } /* After disable sriov, VF still has some config and info need clean, * which configed by PF. */ static void hclge_clear_vport_vf_info(struct hclge_vport *vport, int vfid) { struct hclge_dev *hdev = vport->back; struct hclge_vlan_info vlan_info; int ret; clear_bit(HCLGE_VPORT_STATE_INITED, &vport->state); clear_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state); vport->need_notify = 0; vport->mps = 0; /* after disable sriov, clean VF rate configured by PF */ ret = hclge_tm_qs_shaper_cfg(vport, 0); if (ret) dev_err(&hdev->pdev->dev, "failed to clean vf%d rate config, ret = %d\n", vfid, ret); vlan_info.vlan_tag = 0; vlan_info.qos = 0; vlan_info.vlan_proto = ETH_P_8021Q; ret = hclge_update_port_base_vlan_cfg(vport, HNAE3_PORT_BASE_VLAN_DISABLE, &vlan_info); if (ret) dev_err(&hdev->pdev->dev, "failed to clean vf%d port base vlan, ret = %d\n", vfid, ret); ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, false); if (ret) dev_err(&hdev->pdev->dev, "failed to clean vf%d spoof config, ret = %d\n", vfid, ret); memset(&vport->vf_info, 0, sizeof(vport->vf_info)); } static void hclge_clean_vport_config(struct hnae3_ae_dev *ae_dev, int num_vfs) { struct hclge_dev *hdev = ae_dev->priv; struct hclge_vport *vport; int i; for (i = 0; i < num_vfs; i++) { vport = &hdev->vport[i + HCLGE_VF_VPORT_START_NUM]; hclge_clear_vport_vf_info(vport, i); } } static int hclge_get_dscp_prio(struct hnae3_handle *h, u8 dscp, u8 *tc_mode, u8 *priority) { struct hclge_vport *vport = hclge_get_vport(h); if (dscp >= HNAE3_MAX_DSCP) return -EINVAL; if (tc_mode) *tc_mode = vport->nic.kinfo.tc_map_mode; if (priority) *priority = vport->nic.kinfo.dscp_prio[dscp] == HNAE3_PRIO_ID_INVALID ? 0 : vport->nic.kinfo.dscp_prio[dscp]; return 0; } static const struct hnae3_ae_ops hclge_ops = { .init_ae_dev = hclge_init_ae_dev, .uninit_ae_dev = hclge_uninit_ae_dev, .reset_prepare = hclge_reset_prepare_general, .reset_done = hclge_reset_done, .init_client_instance = hclge_init_client_instance, .uninit_client_instance = hclge_uninit_client_instance, .map_ring_to_vector = hclge_map_ring_to_vector, .unmap_ring_from_vector = hclge_unmap_ring_frm_vector, .get_vector = hclge_get_vector, .put_vector = hclge_put_vector, .set_promisc_mode = hclge_set_promisc_mode, .request_update_promisc_mode = hclge_request_update_promisc_mode, .set_loopback = hclge_set_loopback, .start = hclge_ae_start, .stop = hclge_ae_stop, .client_start = hclge_client_start, .client_stop = hclge_client_stop, .get_status = hclge_get_status, .get_ksettings_an_result = hclge_get_ksettings_an_result, .cfg_mac_speed_dup_h = hclge_cfg_mac_speed_dup_h, .get_media_type = hclge_get_media_type, .check_port_speed = hclge_check_port_speed, .get_fec_stats = hclge_get_fec_stats, .get_fec = hclge_get_fec, .set_fec = hclge_set_fec, .get_rss_key_size = hclge_comm_get_rss_key_size, .get_rss = hclge_get_rss, .set_rss = hclge_set_rss, .set_rss_tuple = hclge_set_rss_tuple, .get_rss_tuple = hclge_get_rss_tuple, .get_tc_size = hclge_get_tc_size, .get_mac_addr = hclge_get_mac_addr, .set_mac_addr = hclge_set_mac_addr, .do_ioctl = hclge_do_ioctl, .add_uc_addr = hclge_add_uc_addr, .rm_uc_addr = hclge_rm_uc_addr, .add_mc_addr = hclge_add_mc_addr, .rm_mc_addr = hclge_rm_mc_addr, .set_autoneg = hclge_set_autoneg, .get_autoneg = hclge_get_autoneg, .restart_autoneg = hclge_restart_autoneg, .halt_autoneg = hclge_halt_autoneg, .get_pauseparam = hclge_get_pauseparam, .set_pauseparam = hclge_set_pauseparam, .set_mtu = hclge_set_mtu, .reset_queue = hclge_reset_tqp, .get_stats = hclge_get_stats, .get_mac_stats = hclge_get_mac_stat, .update_stats = hclge_update_stats, .get_strings = hclge_get_strings, .get_sset_count = hclge_get_sset_count, .get_fw_version = hclge_get_fw_version, .get_mdix_mode = hclge_get_mdix_mode, .enable_vlan_filter = hclge_enable_vlan_filter, .set_vlan_filter = hclge_set_vlan_filter, .set_vf_vlan_filter = hclge_set_vf_vlan_filter, .enable_hw_strip_rxvtag = hclge_en_hw_strip_rxvtag, .reset_event = hclge_reset_event, .get_reset_level = hclge_get_reset_level, .set_default_reset_request = hclge_set_def_reset_request, .get_tqps_and_rss_info = hclge_get_tqps_and_rss_info, .set_channels = hclge_set_channels, .get_channels = hclge_get_channels, .get_regs_len = hclge_get_regs_len, .get_regs = hclge_get_regs, .set_led_id = hclge_set_led_id, .get_link_mode = hclge_get_link_mode, .add_fd_entry = hclge_add_fd_entry, .del_fd_entry = hclge_del_fd_entry, .get_fd_rule_cnt = hclge_get_fd_rule_cnt, .get_fd_rule_info = hclge_get_fd_rule_info, .get_fd_all_rules = hclge_get_all_rules, .enable_fd = hclge_enable_fd, .add_arfs_entry = hclge_add_fd_entry_by_arfs, .dbg_read_cmd = hclge_dbg_read_cmd, .handle_hw_ras_error = hclge_handle_hw_ras_error, .get_hw_reset_stat = hclge_get_hw_reset_stat, .ae_dev_resetting = hclge_ae_dev_resetting, .ae_dev_reset_cnt = hclge_ae_dev_reset_cnt, .set_gro_en = hclge_gro_en, .get_global_queue_id = hclge_covert_handle_qid_global, .set_timer_task = hclge_set_timer_task, .mac_connect_phy = hclge_mac_connect_phy, .mac_disconnect_phy = hclge_mac_disconnect_phy, .get_vf_config = hclge_get_vf_config, .set_vf_link_state = hclge_set_vf_link_state, .set_vf_spoofchk = hclge_set_vf_spoofchk, .set_vf_trust = hclge_set_vf_trust, .set_vf_rate = hclge_set_vf_rate, .set_vf_mac = hclge_set_vf_mac, .get_module_eeprom = hclge_get_module_eeprom, .get_cmdq_stat = hclge_get_cmdq_stat, .add_cls_flower = hclge_add_cls_flower, .del_cls_flower = hclge_del_cls_flower, .cls_flower_active = hclge_is_cls_flower_active, .get_phy_link_ksettings = hclge_get_phy_link_ksettings, .set_phy_link_ksettings = hclge_set_phy_link_ksettings, .set_tx_hwts_info = hclge_ptp_set_tx_info, .get_rx_hwts = hclge_ptp_get_rx_hwts, .get_ts_info = hclge_ptp_get_ts_info, .get_link_diagnosis_info = hclge_get_link_diagnosis_info, .clean_vf_config = hclge_clean_vport_config, .get_dscp_prio = hclge_get_dscp_prio, .get_wol = hclge_get_wol, .set_wol = hclge_set_wol, }; static struct hnae3_ae_algo ae_algo = { .ops = &hclge_ops, .pdev_id_table = ae_algo_pci_tbl, }; static int __init hclge_init(void) { pr_info("%s is initializing\n", HCLGE_NAME); hclge_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, HCLGE_NAME); if (!hclge_wq) { pr_err("%s: failed to create workqueue\n", HCLGE_NAME); return -ENOMEM; } hnae3_register_ae_algo(&ae_algo); return 0; } static void __exit hclge_exit(void) { hnae3_unregister_ae_algo_prepare(&ae_algo); hnae3_unregister_ae_algo(&ae_algo); destroy_workqueue(hclge_wq); } module_init(hclge_init); module_exit(hclge_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huawei Tech. Co., Ltd."); MODULE_DESCRIPTION("HCLGE Driver"); MODULE_VERSION(HCLGE_MOD_VERSION);
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1