From 8eb992e876a88de7539b1b9e132dd171d865cd2f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:06 -0400 Subject: [PATCH 01/12] bnxt_en: Update firmware interface spec to 1.7.6.2. Features added include WoL and selftest. Signed-off-by: Deepak Khungar Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 351 +++++++++++++++--- .../net/ethernet/broadcom/bnxt/bnxt_sriov.c | 8 +- .../net/ethernet/broadcom/bnxt/bnxt_sriov.h | 1 + 3 files changed, 310 insertions(+), 50 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index 6e275c23d68b..7dc71bb95837 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -11,19 +11,21 @@ #ifndef BNXT_HSI_H #define BNXT_HSI_H -/* HSI and HWRM Specification 1.7.0 */ +/* HSI and HWRM Specification 1.7.6 */ #define HWRM_VERSION_MAJOR 1 #define HWRM_VERSION_MINOR 7 -#define HWRM_VERSION_UPDATE 0 +#define HWRM_VERSION_UPDATE 6 -#define HWRM_VERSION_STR "1.7.0" +#define HWRM_VERSION_RSVD 2 /* non-zero means beta version */ + +#define HWRM_VERSION_STR "1.7.6.2" /* * Following is the signature for HWRM message field that indicates not * applicable (All F's). Need to cast it the size of the field if needed. */ #define HWRM_NA_SIGNATURE ((__le32)(-1)) #define HWRM_MAX_REQ_LEN (128) /* hwrm_func_buf_rgtr */ -#define HWRM_MAX_RESP_LEN (176) /* hwrm_func_qstats */ +#define HWRM_MAX_RESP_LEN (248) /* hwrm_selftest_qlist */ #define HW_HASH_INDEX_SIZE 0x80 /* 7 bit indirection table index. */ #define HW_HASH_KEY_SIZE 40 #define HWRM_RESP_VALID_KEY 1 /* valid key for HWRM response */ @@ -571,9 +573,10 @@ struct hwrm_ver_get_output { __le16 max_req_win_len; __le16 max_resp_len; __le16 def_req_timeout; + u8 init_pending; + #define VER_GET_RESP_INIT_PENDING_DEV_NOT_RDY 0x1UL u8 unused_0; u8 unused_1; - u8 unused_2; u8 valid; }; @@ -809,6 +812,8 @@ struct hwrm_func_qcfg_output { #define FUNC_QCFG_RESP_FLAGS_OOB_WOL_BMP_ENABLED 0x2UL #define FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED 0x4UL #define FUNC_QCFG_RESP_FLAGS_STD_TX_RING_MODE_ENABLED 0x8UL + #define FUNC_QCFG_RESP_FLAGS_FW_LLDP_AGENT_ENABLED 0x10UL + #define FUNC_QCFG_RESP_FLAGS_MULTI_HOST 0x20UL u8 mac_address[6]; __le16 pci_id; __le16 alloc_rsscos_ctx; @@ -827,10 +832,12 @@ struct hwrm_func_qcfg_output { #define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_5 0x3UL #define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR2_0 0x4UL #define FUNC_QCFG_RESP_PORT_PARTITION_TYPE_UNKNOWN 0xffUL - u8 unused_0; + u8 port_pf_cnt; + #define FUNC_QCFG_RESP_PORT_PF_CNT_UNAVAIL 0x0UL __le16 dflt_vnic_id; - u8 unused_1; - u8 unused_2; + u8 host_cnt; + #define FUNC_QCFG_RESP_HOST_CNT_UNAVAIL 0x0UL + u8 unused_0; __le32 min_bw; #define FUNC_QCFG_RESP_MIN_BW_BW_VALUE_MASK 0xfffffffUL #define FUNC_QCFG_RESP_MIN_BW_BW_VALUE_SFT 0 @@ -867,12 +874,12 @@ struct hwrm_func_qcfg_output { #define FUNC_QCFG_RESP_EVB_MODE_NO_EVB 0x0UL #define FUNC_QCFG_RESP_EVB_MODE_VEB 0x1UL #define FUNC_QCFG_RESP_EVB_MODE_VEPA 0x2UL - u8 unused_3; + u8 unused_1; __le16 alloc_vfs; __le32 alloc_mcast_filters; __le32 alloc_hw_ring_grps; __le16 alloc_sp_tx_rings; - u8 unused_4; + u8 unused_2; u8 valid; }; @@ -888,16 +895,13 @@ struct hwrm_func_cfg_input { u8 unused_0; u8 unused_1; __le32 flags; - #define FUNC_CFG_REQ_FLAGS_PROM_MODE 0x1UL - #define FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK 0x2UL - #define FUNC_CFG_REQ_FLAGS_SRC_IP_ADDR_CHECK 0x4UL - #define FUNC_CFG_REQ_FLAGS_VLAN_PRI_MATCH 0x8UL - #define FUNC_CFG_REQ_FLAGS_DFLT_PRI_NOMATCH 0x10UL - #define FUNC_CFG_REQ_FLAGS_DISABLE_PAUSE 0x20UL - #define FUNC_CFG_REQ_FLAGS_DISABLE_STP 0x40UL - #define FUNC_CFG_REQ_FLAGS_DISABLE_LLDP 0x80UL - #define FUNC_CFG_REQ_FLAGS_DISABLE_PTPV2 0x100UL - #define FUNC_CFG_REQ_FLAGS_STD_TX_RING_MODE 0x200UL + #define FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE 0x1UL + #define FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE 0x2UL + #define FUNC_CFG_REQ_FLAGS_RSVD_MASK 0x1fcUL + #define FUNC_CFG_REQ_FLAGS_RSVD_SFT 2 + #define FUNC_CFG_REQ_FLAGS_STD_TX_RING_MODE_ENABLE 0x200UL + #define FUNC_CFG_REQ_FLAGS_STD_TX_RING_MODE_DISABLE 0x400UL + #define FUNC_CFG_REQ_FLAGS_VIRT_MAC_PERSIST 0x800UL __le32 enables; #define FUNC_CFG_REQ_ENABLES_MTU 0x1UL #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL @@ -1013,7 +1017,7 @@ struct hwrm_func_qstats_output { __le64 tx_ucast_pkts; __le64 tx_mcast_pkts; __le64 tx_bcast_pkts; - __le64 tx_err_pkts; + __le64 tx_discard_pkts; __le64 tx_drop_pkts; __le64 tx_ucast_bytes; __le64 tx_mcast_bytes; @@ -1021,7 +1025,7 @@ struct hwrm_func_qstats_output { __le64 rx_ucast_pkts; __le64 rx_mcast_pkts; __le64 rx_bcast_pkts; - __le64 rx_err_pkts; + __le64 rx_discard_pkts; __le64 rx_drop_pkts; __le64 rx_ucast_bytes; __le64 rx_mcast_bytes; @@ -4743,6 +4747,165 @@ struct hwrm_temp_monitor_query_output { u8 valid; }; +/* hwrm_wol_filter_alloc */ +/* Input (64 bytes) */ +struct hwrm_wol_filter_alloc_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + __le32 flags; + __le32 enables; + #define WOL_FILTER_ALLOC_REQ_ENABLES_MAC_ADDRESS 0x1UL + #define WOL_FILTER_ALLOC_REQ_ENABLES_PATTERN_OFFSET 0x2UL + #define WOL_FILTER_ALLOC_REQ_ENABLES_PATTERN_BUF_SIZE 0x4UL + #define WOL_FILTER_ALLOC_REQ_ENABLES_PATTERN_BUF_ADDR 0x8UL + #define WOL_FILTER_ALLOC_REQ_ENABLES_PATTERN_MASK_ADDR 0x10UL + #define WOL_FILTER_ALLOC_REQ_ENABLES_PATTERN_MASK_SIZE 0x20UL + __le16 port_id; + u8 wol_type; + #define WOL_FILTER_ALLOC_REQ_WOL_TYPE_MAGICPKT 0x0UL + #define WOL_FILTER_ALLOC_REQ_WOL_TYPE_BMP 0x1UL + #define WOL_FILTER_ALLOC_REQ_WOL_TYPE_INVALID 0xffUL + u8 unused_0; + __le32 unused_1; + u8 mac_address[6]; + __le16 pattern_offset; + __le16 pattern_buf_size; + __le16 pattern_mask_size; + __le32 unused_2; + __le64 pattern_buf_addr; + __le64 pattern_mask_addr; +}; + +/* Output (16 bytes) */ +struct hwrm_wol_filter_alloc_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 wol_filter_id; + u8 unused_0; + __le16 unused_1; + u8 unused_2; + u8 unused_3; + u8 unused_4; + u8 valid; +}; + +/* hwrm_wol_filter_free */ +/* Input (32 bytes) */ +struct hwrm_wol_filter_free_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + __le32 flags; + #define WOL_FILTER_FREE_REQ_FLAGS_FREE_ALL_WOL_FILTERS 0x1UL + __le32 enables; + #define WOL_FILTER_FREE_REQ_ENABLES_WOL_FILTER_ID 0x1UL + __le16 port_id; + u8 wol_filter_id; + u8 unused_0[5]; +}; + +/* Output (16 bytes) */ +struct hwrm_wol_filter_free_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + __le32 unused_0; + u8 unused_1; + u8 unused_2; + u8 unused_3; + u8 valid; +}; + +/* hwrm_wol_filter_qcfg */ +/* Input (56 bytes) */ +struct hwrm_wol_filter_qcfg_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + __le16 port_id; + __le16 handle; + __le32 unused_0; + __le64 pattern_buf_addr; + __le16 pattern_buf_size; + u8 unused_1; + u8 unused_2; + u8 unused_3[3]; + u8 unused_4; + __le64 pattern_mask_addr; + __le16 pattern_mask_size; + __le16 unused_5[3]; +}; + +/* Output (32 bytes) */ +struct hwrm_wol_filter_qcfg_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + __le16 next_handle; + u8 wol_filter_id; + u8 wol_type; + #define WOL_FILTER_QCFG_RESP_WOL_TYPE_MAGICPKT 0x0UL + #define WOL_FILTER_QCFG_RESP_WOL_TYPE_BMP 0x1UL + #define WOL_FILTER_QCFG_RESP_WOL_TYPE_INVALID 0xffUL + __le32 unused_0; + u8 mac_address[6]; + __le16 pattern_offset; + __le16 pattern_size; + __le16 pattern_mask_size; + u8 unused_1; + u8 unused_2; + u8 unused_3; + u8 valid; +}; + +/* hwrm_wol_reason_qcfg */ +/* Input (40 bytes) */ +struct hwrm_wol_reason_qcfg_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + __le16 port_id; + u8 unused_0; + u8 unused_1; + u8 unused_2[3]; + u8 unused_3; + __le64 wol_pkt_buf_addr; + __le16 wol_pkt_buf_size; + __le16 unused_4[3]; +}; + +/* Output (16 bytes) */ +struct hwrm_wol_reason_qcfg_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 wol_filter_id; + u8 wol_reason; + #define WOL_REASON_QCFG_RESP_WOL_REASON_MAGICPKT 0x0UL + #define WOL_REASON_QCFG_RESP_WOL_REASON_BMP 0x1UL + #define WOL_REASON_QCFG_RESP_WOL_REASON_INVALID 0xffUL + u8 wol_pkt_len; + u8 unused_0; + u8 unused_1; + u8 unused_2; + u8 unused_3; + u8 valid; +}; + /* hwrm_nvm_read */ /* Input (40 bytes) */ struct hwrm_nvm_read_input { @@ -4773,32 +4936,6 @@ struct hwrm_nvm_read_output { u8 valid; }; -/* hwrm_nvm_raw_dump */ -/* Input (32 bytes) */ -struct hwrm_nvm_raw_dump_input { - __le16 req_type; - __le16 cmpl_ring; - __le16 seq_id; - __le16 target_id; - __le64 resp_addr; - __le64 host_dest_addr; - __le32 offset; - __le32 len; -}; - -/* Output (16 bytes) */ -struct hwrm_nvm_raw_dump_output { - __le16 error_code; - __le16 req_type; - __le16 seq_id; - __le16 resp_len; - __le32 unused_0; - u8 unused_1; - u8 unused_2; - u8 unused_3; - u8 valid; -}; - /* hwrm_nvm_get_dir_entries */ /* Input (24 bytes) */ struct hwrm_nvm_get_dir_entries_input { @@ -4881,6 +5018,15 @@ struct hwrm_nvm_write_output { u8 valid; }; +/* Command specific Error Codes (8 bytes) */ +struct hwrm_nvm_write_cmd_err { + u8 code; + #define NVM_WRITE_CMD_ERR_CODE_UNKNOWN 0x0UL + #define NVM_WRITE_CMD_ERR_CODE_FRAG_ERR 0x1UL + #define NVM_WRITE_CMD_ERR_CODE_NO_SPACE 0x2UL + u8 unused_0[7]; +}; + /* hwrm_nvm_modify */ /* Input (40 bytes) */ struct hwrm_nvm_modify_input { @@ -5112,6 +5258,100 @@ struct hwrm_nvm_install_update_cmd_err { u8 unused_0[7]; }; +/* hwrm_selftest_qlist */ +/* Input (16 bytes) */ +struct hwrm_selftest_qlist_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; +}; + +/* Output (248 bytes) */ +struct hwrm_selftest_qlist_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 num_tests; + u8 available_tests; + #define SELFTEST_QLIST_RESP_AVAILABLE_TESTS_NVM_TEST 0x1UL + #define SELFTEST_QLIST_RESP_AVAILABLE_TESTS_LINK_TEST 0x2UL + #define SELFTEST_QLIST_RESP_AVAILABLE_TESTS_REGISTER_TEST 0x4UL + #define SELFTEST_QLIST_RESP_AVAILABLE_TESTS_MEMORY_TEST 0x8UL + u8 offline_tests; + #define SELFTEST_QLIST_RESP_OFFLINE_TESTS_NVM_TEST 0x1UL + #define SELFTEST_QLIST_RESP_OFFLINE_TESTS_LINK_TEST 0x2UL + #define SELFTEST_QLIST_RESP_OFFLINE_TESTS_REGISTER_TEST 0x4UL + #define SELFTEST_QLIST_RESP_OFFLINE_TESTS_MEMORY_TEST 0x8UL + u8 unused_0; + __le16 test_timeout; + u8 unused_1; + u8 unused_2; + char test0_name[32]; + char test1_name[32]; + char test2_name[32]; + char test3_name[32]; + char test4_name[32]; + char test5_name[32]; + char test6_name[32]; + char test7_name[32]; +}; + +/* hwrm_selftest_exec */ +/* Input (24 bytes) */ +struct hwrm_selftest_exec_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + u8 flags; + #define SELFTEST_EXEC_REQ_FLAGS_NVM_TEST 0x1UL + #define SELFTEST_EXEC_REQ_FLAGS_LINK_TEST 0x2UL + #define SELFTEST_EXEC_REQ_FLAGS_REGISTER_TEST 0x4UL + #define SELFTEST_EXEC_REQ_FLAGS_MEMORY_TEST 0x8UL + u8 unused_0[7]; +}; + +/* Output (16 bytes) */ +struct hwrm_selftest_exec_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 requested_tests; + #define SELFTEST_EXEC_RESP_REQUESTED_TESTS_NVM_TEST 0x1UL + #define SELFTEST_EXEC_RESP_REQUESTED_TESTS_LINK_TEST 0x2UL + #define SELFTEST_EXEC_RESP_REQUESTED_TESTS_REGISTER_TEST 0x4UL + #define SELFTEST_EXEC_RESP_REQUESTED_TESTS_MEMORY_TEST 0x8UL + u8 test_success; + #define SELFTEST_EXEC_RESP_TEST_SUCCESS_NVM_TEST 0x1UL + #define SELFTEST_EXEC_RESP_TEST_SUCCESS_LINK_TEST 0x2UL + #define SELFTEST_EXEC_RESP_TEST_SUCCESS_REGISTER_TEST 0x4UL + #define SELFTEST_EXEC_RESP_TEST_SUCCESS_MEMORY_TEST 0x8UL + __le16 unused_0[3]; +}; + +/* hwrm_selftest_irq */ +/* Input (16 bytes) */ +struct hwrm_selftest_irq_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; +}; + +/* Output (8 bytes) */ +struct hwrm_selftest_irq_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; +}; + /* Hardware Resource Manager Specification */ /* Input (16 bytes) */ struct input { @@ -5130,6 +5370,16 @@ struct output { __le16 resp_len; }; +/* Short Command Structure (16 bytes) */ +struct hwrm_short_input { + __le16 req_type; + __le16 signature; + #define SHORT_REQ_SIGNATURE_SHORT_CMD 0x4321UL + __le16 unused_0; + __le16 size; + __le64 req_addr; +}; + /* Command numbering (8 bytes) */ struct cmd_nums { __le16 req_type; @@ -5252,11 +5502,15 @@ struct cmd_nums { #define HWRM_CFA_FLOW_FLUSH (0x105UL) #define HWRM_CFA_FLOW_STATS (0x106UL) #define HWRM_CFA_FLOW_INFO (0x107UL) + #define HWRM_SELFTEST_QLIST (0x200UL) + #define HWRM_SELFTEST_EXEC (0x201UL) + #define HWRM_SELFTEST_IRQ (0x202UL) #define HWRM_DBG_READ_DIRECT (0xff10UL) #define HWRM_DBG_READ_INDIRECT (0xff11UL) #define HWRM_DBG_WRITE_DIRECT (0xff12UL) #define HWRM_DBG_WRITE_INDIRECT (0xff13UL) #define HWRM_DBG_DUMP (0xff14UL) + #define HWRM_NVM_FACTORY_DEFAULTS (0xffeeUL) #define HWRM_NVM_VALIDATE_OPTION (0xffefUL) #define HWRM_NVM_FLUSH (0xfff0UL) #define HWRM_NVM_GET_VARIABLE (0xfff1UL) @@ -5464,6 +5718,7 @@ struct hwrm_struct_hdr { #define STRUCT_HDR_STRUCT_ID_DCBX_FEATURE_STATE 0x422UL #define STRUCT_HDR_STRUCT_ID_LLDP_GENERIC 0x424UL #define STRUCT_HDR_STRUCT_ID_LLDP_DEVICE 0x426UL + #define STRUCT_HDR_STRUCT_ID_AFM_OPAQUE 0x1UL #define STRUCT_HDR_STRUCT_ID_PORT_DESCRIPTION 0xaUL __le16 len; u8 version; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index 0b8cd7443843..f89353175e6b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -1,6 +1,7 @@ /* Broadcom NetXtreme-C/E network driver. * * Copyright (c) 2014-2016 Broadcom Corporation + * Copyright (c) 2016-2017 Broadcom Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -84,6 +85,9 @@ int bnxt_set_vf_spoofchk(struct net_device *dev, int vf_id, bool setting) u32 func_flags; int rc; + if (bp->hwrm_spec_code < 0x10701) + return -ENOTSUPP; + rc = bnxt_vf_ndo_prep(bp, vf_id); if (rc) return rc; @@ -96,9 +100,9 @@ int bnxt_set_vf_spoofchk(struct net_device *dev, int vf_id, bool setting) func_flags = vf->func_flags; if (setting) - func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK; + func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE; else - func_flags &= ~FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK; + func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE; /*TODO: if the driver supports VLAN filter on guest VLAN, * the spoof check should also include vlan anti-spoofing */ diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h index 1ab72e4820af..dbc8d977fc5a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h @@ -1,6 +1,7 @@ /* Broadcom NetXtreme-C/E network driver. * * Copyright (c) 2014-2016 Broadcom Corporation + * Copyright (c) 2016-2017 Broadcom Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From c1ef146a5bd3b286d5c3eb2c9f631b38647c76d3 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:07 -0400 Subject: [PATCH 02/12] bnxt_en: Add basic WoL infrastructure. Add code to driver probe function to check if the device is WoL capable and if Magic packet WoL filter is currently set. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 43 +++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +++ 2 files changed, 47 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 174ec8f84637..70cc3132cc4c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4532,6 +4532,9 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp) pf->max_tx_wm_flows = le32_to_cpu(resp->max_tx_wm_flows); pf->max_rx_em_flows = le32_to_cpu(resp->max_rx_em_flows); pf->max_rx_wm_flows = le32_to_cpu(resp->max_rx_wm_flows); + if (resp->flags & + cpu_to_le32(FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED)) + bp->flags |= BNXT_FLAG_WOL_CAP; } else { #ifdef CONFIG_BNXT_SRIOV struct bnxt_vf_info *vf = &bp->vf; @@ -5839,6 +5842,44 @@ static int bnxt_hwrm_port_led_qcaps(struct bnxt *bp) return 0; } +static u16 bnxt_hwrm_get_wol_fltrs(struct bnxt *bp, u16 handle) +{ + struct hwrm_wol_filter_qcfg_input req = {0}; + struct hwrm_wol_filter_qcfg_output *resp = bp->hwrm_cmd_resp_addr; + u16 next_handle = 0; + int rc; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_WOL_FILTER_QCFG, -1, -1); + req.port_id = cpu_to_le16(bp->pf.port_id); + req.handle = cpu_to_le16(handle); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (!rc) { + next_handle = le16_to_cpu(resp->next_handle); + if (next_handle != 0) { + if (resp->wol_type == + WOL_FILTER_ALLOC_REQ_WOL_TYPE_MAGICPKT) { + bp->wol = 1; + bp->wol_filter_id = resp->wol_filter_id; + } + } + } + mutex_unlock(&bp->hwrm_cmd_lock); + return next_handle; +} + +static void bnxt_get_wol_settings(struct bnxt *bp) +{ + u16 handle = 0; + + if (!BNXT_PF(bp) || !(bp->flags & BNXT_FLAG_WOL_CAP)) + return; + + do { + handle = bnxt_hwrm_get_wol_fltrs(bp, handle); + } while (handle && handle != 0xffff); +} + static bool bnxt_eee_config_ok(struct bnxt *bp) { struct ethtool_eee *eee = &bp->eee; @@ -7575,6 +7616,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err_pci_clean; + bnxt_get_wol_settings(bp); + rc = register_netdev(dev); if (rc) goto init_err_clr_int; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 3cb07778a690..02de812dd966 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -989,6 +989,7 @@ struct bnxt { #define BNXT_FLAG_UDP_RSS_CAP 0x800 #define BNXT_FLAG_EEE_CAP 0x1000 #define BNXT_FLAG_NEW_RSS_CAP 0x2000 + #define BNXT_FLAG_WOL_CAP 0x4000 #define BNXT_FLAG_ROCEV1_CAP 0x8000 #define BNXT_FLAG_ROCEV2_CAP 0x10000 #define BNXT_FLAG_ROCE_CAP (BNXT_FLAG_ROCEV1_CAP | \ @@ -1180,6 +1181,9 @@ struct bnxt { u32 lpi_tmr_lo; u32 lpi_tmr_hi; + u8 wol_filter_id; + u8 wol; + u8 num_leds; struct bnxt_led_info leds[BNXT_MAX_LED]; From d196ece740bf337aa25731cd8cb44660a2a227dd Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:08 -0400 Subject: [PATCH 03/12] bnxt_en: Add pci shutdown method. Add pci shutdown method to put device in the proper WoL and power state. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 70cc3132cc4c..10a9cdaf2c17 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7617,6 +7617,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto init_err_pci_clean; bnxt_get_wol_settings(bp); + if (bp->flags & BNXT_FLAG_WOL_CAP) + device_set_wakeup_enable(&pdev->dev, bp->wol); + else + device_set_wakeup_capable(&pdev->dev, false); rc = register_netdev(dev); if (rc) @@ -7641,6 +7645,32 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } +static void bnxt_shutdown(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnxt *bp; + + if (!dev) + return; + + rtnl_lock(); + bp = netdev_priv(dev); + if (!bp) + goto shutdown_exit; + + if (netif_running(dev)) + dev_close(dev); + + if (system_state == SYSTEM_POWER_OFF) { + bnxt_clear_int_mode(bp); + pci_wake_from_d3(pdev, bp->wol); + pci_set_power_state(pdev, PCI_D3hot); + } + +shutdown_exit: + rtnl_unlock(); +} + /** * bnxt_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device @@ -7757,6 +7787,7 @@ static struct pci_driver bnxt_pci_driver = { .id_table = bnxt_pci_tbl, .probe = bnxt_init_one, .remove = bnxt_remove_one, + .shutdown = bnxt_shutdown, .err_handler = &bnxt_err_handler, #if defined(CONFIG_BNXT_SRIOV) .sriov_configure = bnxt_sriov_configure, From 8e202366dd752564d7f090ba280cc51cbf7bbbd9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:09 -0400 Subject: [PATCH 04/12] bnxt_en: Add ethtool get_wol method. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 16 ++++++++++++++++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 6903a873f072..2b947048aaba 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1,6 +1,7 @@ /* Broadcom NetXtreme-C/E network driver. * * Copyright (c) 2014-2016 Broadcom Corporation + * Copyright (c) 2016-2017 Broadcom Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -832,6 +833,20 @@ static void bnxt_get_drvinfo(struct net_device *dev, kfree(pkglog); } +static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnxt *bp = netdev_priv(dev); + + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); + if (bp->flags & BNXT_FLAG_WOL_CAP) { + wol->supported = WAKE_MAGIC; + if (bp->wol) + wol->wolopts = WAKE_MAGIC; + } +} + u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) { u32 speed_mask = 0; @@ -2134,6 +2149,7 @@ const struct ethtool_ops bnxt_ethtool_ops = { .get_pauseparam = bnxt_get_pauseparam, .set_pauseparam = bnxt_set_pauseparam, .get_drvinfo = bnxt_get_drvinfo, + .get_wol = bnxt_get_wol, .get_coalesce = bnxt_get_coalesce, .set_coalesce = bnxt_set_coalesce, .get_msglevel = bnxt_get_msglevel, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index ed1e555292e9..27621710e07b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -1,6 +1,7 @@ /* Broadcom NetXtreme-C/E network driver. * * Copyright (c) 2014-2016 Broadcom Corporation + * Copyright (c) 2016-2017 Broadcom Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 5282db6c794fed3ea8b399bc5305c4078e084f7b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:10 -0400 Subject: [PATCH 05/12] bnxt_en: Add ethtool set_wol method. And add functions to set and free magic packet filter. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 32 +++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 ++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 26 +++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 10a9cdaf2c17..e432d0a92d52 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5842,6 +5842,38 @@ static int bnxt_hwrm_port_led_qcaps(struct bnxt *bp) return 0; } +int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp) +{ + struct hwrm_wol_filter_alloc_input req = {0}; + struct hwrm_wol_filter_alloc_output *resp = bp->hwrm_cmd_resp_addr; + int rc; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_WOL_FILTER_ALLOC, -1, -1); + req.port_id = cpu_to_le16(bp->pf.port_id); + req.wol_type = WOL_FILTER_ALLOC_REQ_WOL_TYPE_MAGICPKT; + req.enables = cpu_to_le32(WOL_FILTER_ALLOC_REQ_ENABLES_MAC_ADDRESS); + memcpy(req.mac_address, bp->dev->dev_addr, ETH_ALEN); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (!rc) + bp->wol_filter_id = resp->wol_filter_id; + mutex_unlock(&bp->hwrm_cmd_lock); + return rc; +} + +int bnxt_hwrm_free_wol_fltr(struct bnxt *bp) +{ + struct hwrm_wol_filter_free_input req = {0}; + int rc; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_WOL_FILTER_FREE, -1, -1); + req.port_id = cpu_to_le16(bp->pf.port_id); + req.enables = cpu_to_le32(WOL_FILTER_FREE_REQ_ENABLES_WOL_FILTER_ID); + req.wol_filter_id = bp->wol_filter_id; + rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + return rc; +} + static u16 bnxt_hwrm_get_wol_fltrs(struct bnxt *bp, u16 handle) { struct hwrm_wol_filter_qcfg_input req = {0}; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 02de812dd966..aba25ba365fc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1242,6 +1242,8 @@ void bnxt_tx_disable(struct bnxt *bp); void bnxt_tx_enable(struct bnxt *bp); int bnxt_hwrm_set_pause(struct bnxt *); int bnxt_hwrm_set_link_setting(struct bnxt *, bool, bool); +int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp); +int bnxt_hwrm_free_wol_fltr(struct bnxt *bp); int bnxt_hwrm_fw_set_time(struct bnxt *); int bnxt_open_nic(struct bnxt *, bool, bool); int bnxt_close_nic(struct bnxt *, bool, bool); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 2b947048aaba..84cd4ca43c04 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -847,6 +847,31 @@ static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } } +static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnxt *bp = netdev_priv(dev); + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGIC) { + if (!(bp->flags & BNXT_FLAG_WOL_CAP)) + return -EINVAL; + if (!bp->wol) { + if (bnxt_hwrm_alloc_wol_fltr(bp)) + return -EBUSY; + bp->wol = 1; + } + } else { + if (bp->wol) { + if (bnxt_hwrm_free_wol_fltr(bp)) + return -EBUSY; + bp->wol = 0; + } + } + return 0; +} + u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) { u32 speed_mask = 0; @@ -2150,6 +2175,7 @@ const struct ethtool_ops bnxt_ethtool_ops = { .set_pauseparam = bnxt_set_pauseparam, .get_drvinfo = bnxt_get_drvinfo, .get_wol = bnxt_get_wol, + .set_wol = bnxt_set_wol, .get_coalesce = bnxt_get_coalesce, .set_coalesce = bnxt_set_coalesce, .get_msglevel = bnxt_get_msglevel, From f65a2044a8c988adf16788c51c04ac10dbbdb494 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:11 -0400 Subject: [PATCH 06/12] bnxt_en: Add suspend/resume callbacks. Add suspend/resume callbacks using the newer dev_pm_ops method. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e432d0a92d52..4e77bbf7adf0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7703,6 +7703,62 @@ static void bnxt_shutdown(struct pci_dev *pdev) rtnl_unlock(); } +#ifdef CONFIG_PM_SLEEP +static int bnxt_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct net_device *dev = pci_get_drvdata(pdev); + struct bnxt *bp = netdev_priv(dev); + int rc = 0; + + rtnl_lock(); + if (netif_running(dev)) { + netif_device_detach(dev); + rc = bnxt_close(dev); + } + bnxt_hwrm_func_drv_unrgtr(bp); + rtnl_unlock(); + return rc; +} + +static int bnxt_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct net_device *dev = pci_get_drvdata(pdev); + struct bnxt *bp = netdev_priv(dev); + int rc = 0; + + rtnl_lock(); + if (bnxt_hwrm_ver_get(bp) || bnxt_hwrm_func_drv_rgtr(bp)) { + rc = -ENODEV; + goto resume_exit; + } + rc = bnxt_hwrm_func_reset(bp); + if (rc) { + rc = -EBUSY; + goto resume_exit; + } + bnxt_get_wol_settings(bp); + if (netif_running(dev)) { + rc = bnxt_open(dev); + if (!rc) + netif_device_attach(dev); + } + +resume_exit: + rtnl_unlock(); + return rc; +} + +static SIMPLE_DEV_PM_OPS(bnxt_pm_ops, bnxt_suspend, bnxt_resume); +#define BNXT_PM_OPS (&bnxt_pm_ops) + +#else + +#define BNXT_PM_OPS NULL + +#endif /* CONFIG_PM_SLEEP */ + /** * bnxt_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device @@ -7820,6 +7876,7 @@ static struct pci_driver bnxt_pci_driver = { .probe = bnxt_init_one, .remove = bnxt_remove_one, .shutdown = bnxt_shutdown, + .driver.pm = BNXT_PM_OPS, .err_handler = &bnxt_err_handler, #if defined(CONFIG_BNXT_SRIOV) .sriov_configure = bnxt_sriov_configure, From eb51365846bc418687af4c4f41b68b6e84cdd449 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:12 -0400 Subject: [PATCH 07/12] bnxt_en: Add basic ethtool -t selftest support. Add the basic infrastructure and only firmware tests initially. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 + drivers/net/ethernet/broadcom/bnxt/bnxt.h | 13 +- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 136 +++++++++++++++++- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 2 + 4 files changed, 150 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4e77bbf7adf0..7b72ba9fd0aa 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7281,6 +7281,7 @@ static void bnxt_remove_one(struct pci_dev *pdev) bnxt_clear_int_mode(bp); bnxt_hwrm_func_drv_unrgtr(bp); bnxt_free_hwrm_resources(bp); + bnxt_ethtool_free(bp); bnxt_dcb_free(bp); kfree(bp->edev); bp->edev = NULL; @@ -7603,6 +7604,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_hwrm_func_qcfg(bp); bnxt_hwrm_port_led_qcaps(bp); + bnxt_ethtool_init(bp); bnxt_set_rx_skb_mode(bp, false); bnxt_set_tpa_flags(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index aba25ba365fc..4affaacb7aa9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -426,8 +426,6 @@ struct rx_tpa_end_cmp_ext { #define BNXT_MIN_PKT_SIZE 52 -#define BNXT_NUM_TESTS(bp) 0 - #define BNXT_DEFAULT_RX_RING_SIZE 511 #define BNXT_DEFAULT_TX_RING_SIZE 511 @@ -911,6 +909,14 @@ struct bnxt_led_info { __le16 led_color_caps; }; +#define BNXT_MAX_TEST 8 + +struct bnxt_test_info { + u8 offline_mask; + u16 timeout; + char string[BNXT_MAX_TEST][ETH_GSTRING_LEN]; +}; + #define BNXT_GRCPF_REG_WINDOW_BASE_OUT 0x400 #define BNXT_CAG_REG_LEGACY_INT_STATUS 0x4014 #define BNXT_CAG_REG_BASE 0x300000 @@ -1181,6 +1187,9 @@ struct bnxt { u32 lpi_tmr_lo; u32 lpi_tmr_hi; + u8 num_tests; + struct bnxt_test_info *test_info; + u8 wol_filter_id; u8 wol; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 84cd4ca43c04..711d7fd56d26 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -210,6 +210,10 @@ static int bnxt_get_sset_count(struct net_device *dev, int sset) return num_stats; } + case ETH_SS_TEST: + if (!bp->num_tests) + return -EOPNOTSUPP; + return bp->num_tests; default: return -EOPNOTSUPP; } @@ -307,6 +311,11 @@ static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) } } break; + case ETH_SS_TEST: + if (bp->num_tests) + memcpy(buf, bp->test_info->string, + bp->num_tests * ETH_GSTRING_LEN); + break; default: netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", stringset); @@ -825,7 +834,7 @@ static void bnxt_get_drvinfo(struct net_device *dev, sizeof(info->fw_version)); strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); info->n_stats = BNXT_NUM_STATS * bp->cp_nr_rings; - info->testinfo_len = BNXT_NUM_TESTS(bp); + info->testinfo_len = bp->num_tests; /* TODO CHIMP_FW: eeprom dump details */ info->eedump_len = 0; /* TODO CHIMP FW: reg dump details */ @@ -2168,6 +2177,130 @@ static int bnxt_set_phys_id(struct net_device *dev, return rc; } +static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) +{ + struct hwrm_selftest_exec_output *resp = bp->hwrm_cmd_resp_addr; + struct hwrm_selftest_exec_input req = {0}; + int rc; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_EXEC, -1, -1); + mutex_lock(&bp->hwrm_cmd_lock); + resp->test_success = 0; + req.flags = test_mask; + rc = _hwrm_send_message(bp, &req, sizeof(req), bp->test_info->timeout); + *test_results = resp->test_success; + mutex_unlock(&bp->hwrm_cmd_lock); + return rc; +} + +#define BNXT_DRV_TESTS 0 + +static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, + u64 *buf) +{ + struct bnxt *bp = netdev_priv(dev); + bool offline = false; + u8 test_results = 0; + u8 test_mask = 0; + int rc, i; + + if (!bp->num_tests || !BNXT_SINGLE_PF(bp)) + return; + memset(buf, 0, sizeof(u64) * bp->num_tests); + if (!netif_running(dev)) { + etest->flags |= ETH_TEST_FL_FAILED; + return; + } + + if (etest->flags & ETH_TEST_FL_OFFLINE) { + if (bp->pf.active_vfs) { + etest->flags |= ETH_TEST_FL_FAILED; + netdev_warn(dev, "Offline tests cannot be run with active VFs\n"); + return; + } + offline = true; + } + + for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { + u8 bit_val = 1 << i; + + if (!(bp->test_info->offline_mask & bit_val)) + test_mask |= bit_val; + else if (offline) + test_mask |= bit_val; + } + if (!offline) { + bnxt_run_fw_tests(bp, test_mask, &test_results); + } else { + rc = bnxt_close_nic(bp, false, false); + if (rc) + return; + bnxt_run_fw_tests(bp, test_mask, &test_results); + bnxt_open_nic(bp, false, true); + } + for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { + u8 bit_val = 1 << i; + + if ((test_mask & bit_val) && !(test_results & bit_val)) { + buf[i] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + } +} + +void bnxt_ethtool_init(struct bnxt *bp) +{ + struct hwrm_selftest_qlist_output *resp = bp->hwrm_cmd_resp_addr; + struct hwrm_selftest_qlist_input req = {0}; + struct bnxt_test_info *test_info; + int i, rc; + + if (bp->hwrm_spec_code < 0x10704 || !BNXT_SINGLE_PF(bp)) + return; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_QLIST, -1, -1); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (rc) + goto ethtool_init_exit; + + test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL); + if (!test_info) + goto ethtool_init_exit; + + bp->test_info = test_info; + bp->num_tests = resp->num_tests + BNXT_DRV_TESTS; + if (bp->num_tests > BNXT_MAX_TEST) + bp->num_tests = BNXT_MAX_TEST; + + test_info->offline_mask = resp->offline_tests; + test_info->timeout = le16_to_cpu(resp->test_timeout); + if (!test_info->timeout) + test_info->timeout = HWRM_CMD_TIMEOUT; + for (i = 0; i < bp->num_tests; i++) { + char *str = test_info->string[i]; + char *fw_str = resp->test0_name + i * 32; + + strlcpy(str, fw_str, ETH_GSTRING_LEN); + strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); + if (test_info->offline_mask & (1 << i)) + strncat(str, " (offline)", + ETH_GSTRING_LEN - strlen(str)); + else + strncat(str, " (online)", + ETH_GSTRING_LEN - strlen(str)); + } + +ethtool_init_exit: + mutex_unlock(&bp->hwrm_cmd_lock); +} + +void bnxt_ethtool_free(struct bnxt *bp) +{ + kfree(bp->test_info); + bp->test_info = NULL; +} + const struct ethtool_ops bnxt_ethtool_ops = { .get_link_ksettings = bnxt_get_link_ksettings, .set_link_ksettings = bnxt_set_link_ksettings, @@ -2203,4 +2336,5 @@ const struct ethtool_ops bnxt_ethtool_ops = { .get_module_eeprom = bnxt_get_module_eeprom, .nway_reset = bnxt_nway_reset, .set_phys_id = bnxt_set_phys_id, + .self_test = bnxt_self_test, }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index 27621710e07b..f1bc90b6fb5b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -39,5 +39,7 @@ extern const struct ethtool_ops bnxt_ethtool_ops; u32 _bnxt_fw_to_ethtool_adv_spds(u16, u8); u32 bnxt_fw_to_ethtool_speed(u16); u16 bnxt_get_fw_auto_link_speeds(u32); +void bnxt_ethtool_init(struct bnxt *bp); +void bnxt_ethtool_free(struct bnxt *bp); #endif From f7dc1ea6c4c1f31371b7098d6fae0d49dc6cdff1 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:13 -0400 Subject: [PATCH 08/12] bnxt_en: Add ethtool mac loopback self test. The mac loopback self test operates in polling mode. To support that, we need to add functions to open and close the NIC half way. The half open mode allows the rings to operate without IRQ and NAPI. We use the XDP transmit function to send the loopback packet. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 37 ++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 165 +++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 4 +- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h | 2 + 5 files changed, 199 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7b72ba9fd0aa..9d71c19f5496 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6097,6 +6097,43 @@ int bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) return rc; } +/* rtnl_lock held, open the NIC half way by allocating all resources, but + * NAPI, IRQ, and TX are not enabled. This is mainly used for offline + * self tests. + */ +int bnxt_half_open_nic(struct bnxt *bp) +{ + int rc = 0; + + rc = bnxt_alloc_mem(bp, false); + if (rc) { + netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc); + goto half_open_err; + } + rc = bnxt_init_nic(bp, false); + if (rc) { + netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc); + goto half_open_err; + } + return 0; + +half_open_err: + bnxt_free_skbs(bp); + bnxt_free_mem(bp, false); + dev_close(bp->dev); + return rc; +} + +/* rtnl_lock held, this call can only be made after a previous successful + * call to bnxt_half_open_nic(). + */ +void bnxt_half_close_nic(struct bnxt *bp) +{ + bnxt_hwrm_resource_free(bp, false, false); + bnxt_free_skbs(bp); + bnxt_free_mem(bp, false); +} + static int bnxt_open(struct net_device *dev) { struct bnxt *bp = netdev_priv(dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 4affaacb7aa9..c9a1688a65de 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1255,6 +1255,8 @@ int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp); int bnxt_hwrm_free_wol_fltr(struct bnxt *bp); int bnxt_hwrm_fw_set_time(struct bnxt *); int bnxt_open_nic(struct bnxt *, bool, bool); +int bnxt_half_open_nic(struct bnxt *bp); +void bnxt_half_close_nic(struct bnxt *bp); int bnxt_close_nic(struct bnxt *, bool, bool); int bnxt_reserve_rings(struct bnxt *bp, int tx, int rx, int tcs, int tx_xdp); int bnxt_setup_mq_tc(struct net_device *dev, u8 tc); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 711d7fd56d26..ecb441724b10 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -18,6 +18,7 @@ #include #include "bnxt_hsi.h" #include "bnxt.h" +#include "bnxt_xdp.h" #include "bnxt_ethtool.h" #include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */ #include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */ @@ -2177,6 +2178,130 @@ static int bnxt_set_phys_id(struct net_device *dev, return rc; } +static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) +{ + struct hwrm_port_mac_cfg_input req = {0}; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1); + + req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK); + if (enable) + req.lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL; + else + req.lpbk = PORT_MAC_CFG_REQ_LPBK_NONE; + return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); +} + +static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi, + u32 raw_cons, int pkt_size) +{ + struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + struct bnxt_rx_ring_info *rxr = bnapi->rx_ring; + struct bnxt_sw_rx_bd *rx_buf; + struct rx_cmp *rxcmp; + u16 cp_cons, cons; + u8 *data; + u32 len; + int i; + + cp_cons = RING_CMP(raw_cons); + rxcmp = (struct rx_cmp *) + &cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)]; + cons = rxcmp->rx_cmp_opaque; + rx_buf = &rxr->rx_buf_ring[cons]; + data = rx_buf->data_ptr; + len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT; + if (len != pkt_size) + return -EIO; + i = ETH_ALEN; + if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr)) + return -EIO; + i += ETH_ALEN; + for ( ; i < pkt_size; i++) { + if (data[i] != (u8)(i & 0xff)) + return -EIO; + } + return 0; +} + +static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size) +{ + struct bnxt_napi *bnapi = bp->bnapi[0]; + struct bnxt_cp_ring_info *cpr; + struct tx_cmp *txcmp; + int rc = -EIO; + u32 raw_cons; + u32 cons; + int i; + + cpr = &bnapi->cp_ring; + raw_cons = cpr->cp_raw_cons; + for (i = 0; i < 200; i++) { + cons = RING_CMP(raw_cons); + txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; + + if (!TX_CMP_VALID(txcmp, raw_cons)) { + udelay(5); + continue; + } + + /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); + if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) { + rc = bnxt_rx_loopback(bp, bnapi, raw_cons, pkt_size); + raw_cons = NEXT_RAW_CMP(raw_cons); + raw_cons = NEXT_RAW_CMP(raw_cons); + break; + } + raw_cons = NEXT_RAW_CMP(raw_cons); + } + cpr->cp_raw_cons = raw_cons; + return rc; +} + +static int bnxt_run_loopback(struct bnxt *bp) +{ + struct bnxt_tx_ring_info *txr = &bp->tx_ring[0]; + int pkt_size, i = 0; + struct sk_buff *skb; + dma_addr_t map; + u8 *data; + int rc; + + pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh); + skb = netdev_alloc_skb(bp->dev, pkt_size); + if (!skb) + return -ENOMEM; + data = skb_put(skb, pkt_size); + eth_broadcast_addr(data); + i += ETH_ALEN; + ether_addr_copy(&data[i], bp->dev->dev_addr); + i += ETH_ALEN; + for ( ; i < pkt_size; i++) + data[i] = (u8)(i & 0xff); + + map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, + PCI_DMA_TODEVICE); + if (dma_mapping_error(&bp->pdev->dev, map)) { + dev_kfree_skb(skb); + return -EIO; + } + bnxt_xmit_xdp(bp, txr, map, pkt_size, 0); + + /* Sync BD data before updating doorbell */ + wmb(); + + writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell); + writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell); + rc = bnxt_poll_loopback(bp, pkt_size); + + dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + return rc; +} + static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) { struct hwrm_selftest_exec_output *resp = bp->hwrm_cmd_resp_addr; @@ -2193,7 +2318,8 @@ static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) return rc; } -#define BNXT_DRV_TESTS 0 +#define BNXT_DRV_TESTS 1 +#define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) @@ -2236,6 +2362,23 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, if (rc) return; bnxt_run_fw_tests(bp, test_mask, &test_results); + + buf[BNXT_MACLPBK_TEST_IDX] = 1; + bnxt_hwrm_mac_loopback(bp, true); + msleep(250); + rc = bnxt_half_open_nic(bp); + if (rc) { + bnxt_hwrm_mac_loopback(bp, false); + etest->flags |= ETH_TEST_FL_FAILED; + return; + } + if (bnxt_run_loopback(bp)) + etest->flags |= ETH_TEST_FL_FAILED; + else + buf[BNXT_MACLPBK_TEST_IDX] = 0; + + bnxt_half_close_nic(bp); + bnxt_hwrm_mac_loopback(bp, false); bnxt_open_nic(bp, false, true); } for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { @@ -2281,14 +2424,18 @@ void bnxt_ethtool_init(struct bnxt *bp) char *str = test_info->string[i]; char *fw_str = resp->test0_name + i * 32; - strlcpy(str, fw_str, ETH_GSTRING_LEN); - strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); - if (test_info->offline_mask & (1 << i)) - strncat(str, " (offline)", - ETH_GSTRING_LEN - strlen(str)); - else - strncat(str, " (online)", - ETH_GSTRING_LEN - strlen(str)); + if (i == BNXT_MACLPBK_TEST_IDX) { + strcpy(str, "Mac loopback test (offline)"); + } else { + strlcpy(str, fw_str, ETH_GSTRING_LEN); + strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); + if (test_info->offline_mask & (1 << i)) + strncat(str, " (offline)", + ETH_GSTRING_LEN - strlen(str)); + else + strncat(str, " (online)", + ETH_GSTRING_LEN - strlen(str)); + } } ethtool_init_exit: diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 899c30fb5188..8b27137c63ac 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -19,8 +19,8 @@ #include "bnxt.h" #include "bnxt_xdp.h" -static void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr, - dma_addr_t mapping, u32 len, u16 rx_prod) +void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr, + dma_addr_t mapping, u32 len, u16 rx_prod) { struct bnxt_sw_tx_bd *tx_buf; struct tx_bd_ext *txbd1; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h index b529f2c5355b..12a5ad66b564 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.h @@ -10,6 +10,8 @@ #ifndef BNXT_XDP_H #define BNXT_XDP_H +void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr, + dma_addr_t mapping, u32 len, u16 rx_prod); void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts); bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, struct page *page, u8 **data_ptr, unsigned int *len, From 91725d89b97acea168a94c577d999801c3b3bcfb Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:14 -0400 Subject: [PATCH 09/12] bnxt_en: Add PHY loopback to ethtool self-test. It is necessary to disable autoneg before enabling PHY loopback, otherwise link won't come up. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 62 ++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index ecb441724b10..dde3e21d8c56 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2192,6 +2192,54 @@ static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); } +static int bnxt_disable_an_for_lpbk(struct bnxt *bp, + struct hwrm_port_phy_cfg_input *req) +{ + struct bnxt_link_info *link_info = &bp->link_info; + u16 fw_advertising = link_info->advertising; + u16 fw_speed; + int rc; + + if (!link_info->autoneg) + return 0; + + fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; + if (netif_carrier_ok(bp->dev)) + fw_speed = bp->link_info.link_speed; + else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB) + fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; + else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB) + fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; + else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB) + fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; + else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB) + fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; + + req->force_link_speed = cpu_to_le16(fw_speed); + req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE | + PORT_PHY_CFG_REQ_FLAGS_RESET_PHY); + rc = hwrm_send_message(bp, req, sizeof(*req), HWRM_CMD_TIMEOUT); + req->flags = 0; + req->force_link_speed = cpu_to_le16(0); + return rc; +} + +static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable) +{ + struct hwrm_port_phy_cfg_input req = {0}; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1); + + if (enable) { + bnxt_disable_an_for_lpbk(bp, &req); + req.lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL; + } else { + req.lpbk = PORT_PHY_CFG_REQ_LPBK_NONE; + } + req.enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK); + return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); +} + static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi, u32 raw_cons, int pkt_size) { @@ -2318,8 +2366,9 @@ static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) return rc; } -#define BNXT_DRV_TESTS 1 +#define BNXT_DRV_TESTS 2 #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) +#define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) @@ -2377,8 +2426,15 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, else buf[BNXT_MACLPBK_TEST_IDX] = 0; - bnxt_half_close_nic(bp); bnxt_hwrm_mac_loopback(bp, false); + bnxt_hwrm_phy_loopback(bp, true); + msleep(1000); + if (bnxt_run_loopback(bp)) { + buf[BNXT_PHYLPBK_TEST_IDX] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + bnxt_hwrm_phy_loopback(bp, false); + bnxt_half_close_nic(bp); bnxt_open_nic(bp, false, true); } for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { @@ -2426,6 +2482,8 @@ void bnxt_ethtool_init(struct bnxt *bp) if (i == BNXT_MACLPBK_TEST_IDX) { strcpy(str, "Mac loopback test (offline)"); + } else if (i == BNXT_PHYLPBK_TEST_IDX) { + strcpy(str, "Phy loopback test (offline)"); } else { strlcpy(str, fw_str, ETH_GSTRING_LEN); strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); From 67fea463fd873492ab641459a6d1af0e9ea3c9ce Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:15 -0400 Subject: [PATCH 10/12] bnxt_en: Add interrupt test to ethtool -t selftest. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index dde3e21d8c56..848ecf212b8f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2178,6 +2178,29 @@ static int bnxt_set_phys_id(struct net_device *dev, return rc; } +static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring) +{ + struct hwrm_selftest_irq_input req = {0}; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_IRQ, cmpl_ring, -1); + return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); +} + +static int bnxt_test_irq(struct bnxt *bp) +{ + int i; + + for (i = 0; i < bp->cp_nr_rings; i++) { + u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id; + int rc; + + rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring); + if (rc) + return rc; + } + return 0; +} + static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable) { struct hwrm_port_mac_cfg_input req = {0}; @@ -2366,9 +2389,10 @@ static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results) return rc; } -#define BNXT_DRV_TESTS 2 +#define BNXT_DRV_TESTS 3 #define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS) #define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1) +#define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2) static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) @@ -2437,6 +2461,10 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, bnxt_half_close_nic(bp); bnxt_open_nic(bp, false, true); } + if (bnxt_test_irq(bp)) { + buf[BNXT_IRQ_TEST_IDX] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) { u8 bit_val = 1 << i; @@ -2484,6 +2512,8 @@ void bnxt_ethtool_init(struct bnxt *bp) strcpy(str, "Mac loopback test (offline)"); } else if (i == BNXT_PHYLPBK_TEST_IDX) { strcpy(str, "Phy loopback test (offline)"); + } else if (i == BNXT_IRQ_TEST_IDX) { + strcpy(str, "Interrupt_test (offline)"); } else { strlcpy(str, fw_str, ETH_GSTRING_LEN); strncat(str, " test", ETH_GSTRING_LEN - strlen(str)); From 932dbf83ba18bdb871e0c03a4ffdd9785f7a9c07 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:16 -0400 Subject: [PATCH 11/12] bnxt_en: Use short TX BDs for the XDP TX ring. No offload is performed on the XDP_TX ring so we can use the short TX BDs. This has the effect of doubling the size of the XDP TX ring so that it now matches the size of the rx ring by default. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 8b27137c63ac..9dae32756767 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -23,7 +23,6 @@ void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr, dma_addr_t mapping, u32 len, u16 rx_prod) { struct bnxt_sw_tx_bd *tx_buf; - struct tx_bd_ext *txbd1; struct tx_bd *txbd; u32 flags; u16 prod; @@ -33,22 +32,12 @@ void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr, tx_buf->rx_prod = rx_prod; txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; - flags = (len << TX_BD_LEN_SHIFT) | TX_BD_TYPE_LONG_TX_BD | - (2 << TX_BD_FLAGS_BD_CNT_SHIFT) | TX_BD_FLAGS_COAL_NOW | + flags = (len << TX_BD_LEN_SHIFT) | (1 << TX_BD_FLAGS_BD_CNT_SHIFT) | TX_BD_FLAGS_PACKET_END | bnxt_lhint_arr[len >> 9]; txbd->tx_bd_len_flags_type = cpu_to_le32(flags); txbd->tx_bd_opaque = prod; txbd->tx_bd_haddr = cpu_to_le64(mapping); - prod = NEXT_TX(prod); - txbd1 = (struct tx_bd_ext *) - &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)]; - - txbd1->tx_bd_hsize_lflags = cpu_to_le32(0); - txbd1->tx_bd_mss = cpu_to_le32(0); - txbd1->tx_bd_cfa_action = cpu_to_le32(0); - txbd1->tx_bd_cfa_meta = cpu_to_le32(0); - prod = NEXT_TX(prod); txr->tx_prod = prod; } @@ -66,7 +55,6 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts) for (i = 0; i < nr_pkts; i++) { last_tx_cons = tx_cons; tx_cons = NEXT_TX(tx_cons); - tx_cons = NEXT_TX(tx_cons); } txr->tx_cons = tx_cons; if (bnxt_tx_avail(bp, txr) == bp->tx_ring_size) { @@ -133,7 +121,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons, return false; case XDP_TX: - if (tx_avail < 2) { + if (tx_avail < 1) { trace_xdp_exception(bp->dev, xdp_prog, act); bnxt_reuse_rx_data(rxr, cons, page); return true; From 68a946bb81e07ed0e59a99e0c068d091ed42cc1b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 4 Apr 2017 18:14:17 -0400 Subject: [PATCH 12/12] bnxt_en: Cap the msix vector with the max completion rings. The current code enables up to the maximum MSIX vectors in the PCIE config space without considering the max completion rings available. An MSIX vector is only useful when it has an associated completion ring, so it is better to cap it. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9d71c19f5496..43b7342c6e82 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5183,9 +5183,10 @@ static unsigned int bnxt_get_max_func_irqs(struct bnxt *bp) { #if defined(CONFIG_BNXT_SRIOV) if (BNXT_VF(bp)) - return bp->vf.max_irqs; + return min_t(unsigned int, bp->vf.max_irqs, + bp->vf.max_cp_rings); #endif - return bp->pf.max_irqs; + return min_t(unsigned int, bp->pf.max_irqs, bp->pf.max_cp_rings); } void bnxt_set_max_func_irqs(struct bnxt *bp, unsigned int max_irqs)