Commit c0c050c5 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

bnxt_en: New Broadcom ethernet driver.

Broadcom ethernet driver for the new family of NetXtreme-C/E
ethernet devices.

v5:
  - Removed empty blank lines at end of files (noted by David Miller).
  - Moved busy poll helper functions to bnxt.h to at least make the
    .c file look less cluttered with #ifdef (noted by Stephen Hemminger).

v4:
  - Broke up 2 long message strings with "\n" (suggested by John Linville)
  - Constify an array of strings (suggested by Stephen Hemminger)
  - Improve bnxt_vf_pciid() (suggested by Stephen Hemminger)
  - Use PCI_VDEVICE() to populate pci_device_id table for more compact
    source.

v3:
  - Fixed 2 more sparse warnings.
  - Removed some unused structures in .h files.

v2:
  - Fixed all kbuild test robot reported warnings.
  - Fixed many of the checkpatch.pl errors and warnings.
  - Fixed the Kconfig description (noted by Dmitry Kravkov).
Acked-by: default avatarEddie Wai <eddie.wai@broadcom.com>
Acked-by: default avatarJeffrey Huang <huangjw@broadcom.com>
Signed-off-by: default avatarPrashant Sreedharan <prashant@broadcom.com>
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0a31adae
...@@ -170,4 +170,23 @@ config SYSTEMPORT ...@@ -170,4 +170,23 @@ config SYSTEMPORT
Broadcom BCM7xxx Set Top Box family chipset using an internal Broadcom BCM7xxx Set Top Box family chipset using an internal
Ethernet switch. Ethernet switch.
config BNXT
tristate "Broadcom NetXtreme-C/E support"
depends on PCI
select FW_LOADER
select LIBCRC32C
---help---
This driver supports Broadcom NetXtreme-C/E 10/25/40/50 gigabit
Ethernet cards. To compile this driver as a module, choose M here:
the module will be called bnxt_en. This is recommended.
config BNXT_SRIOV
bool "Broadcom NetXtreme-C/E SR-IOV support"
depends on BNXT && PCI_IOV
default y
---help---
This configuration parameter enables Single Root Input Output
Virtualization support in the NetXtreme-C/E products. This
allows for virtual function acceleration in virtual environments.
endif # NET_VENDOR_BROADCOM endif # NET_VENDOR_BROADCOM
...@@ -12,3 +12,4 @@ obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o ...@@ -12,3 +12,4 @@ obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_TIGON3) += tg3.o
obj-$(CONFIG_BGMAC) += bgmac.o obj-$(CONFIG_BGMAC) += bgmac.o
obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o obj-$(CONFIG_SYSTEMPORT) += bcmsysport.o
obj-$(CONFIG_BNXT) += bnxt/
obj-$(CONFIG_BNXT) += bnxt_en.o
bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2015 Broadcom Corporation
*
* 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
* the Free Software Foundation.
*/
#ifndef BNXT_H
#define BNXT_H
#define DRV_MODULE_NAME "bnxt_en"
#define DRV_MODULE_VERSION "0.1.24"
#define DRV_VER_MAJ 0
#define DRV_VER_MIN 1
#define DRV_VER_UPD 24
struct tx_bd {
__le32 tx_bd_len_flags_type;
#define TX_BD_TYPE (0x3f << 0)
#define TX_BD_TYPE_SHORT_TX_BD (0x00 << 0)
#define TX_BD_TYPE_LONG_TX_BD (0x10 << 0)
#define TX_BD_FLAGS_PACKET_END (1 << 6)
#define TX_BD_FLAGS_NO_CMPL (1 << 7)
#define TX_BD_FLAGS_BD_CNT (0x1f << 8)
#define TX_BD_FLAGS_BD_CNT_SHIFT 8
#define TX_BD_FLAGS_LHINT (3 << 13)
#define TX_BD_FLAGS_LHINT_SHIFT 13
#define TX_BD_FLAGS_LHINT_512_AND_SMALLER (0 << 13)
#define TX_BD_FLAGS_LHINT_512_TO_1023 (1 << 13)
#define TX_BD_FLAGS_LHINT_1024_TO_2047 (2 << 13)
#define TX_BD_FLAGS_LHINT_2048_AND_LARGER (3 << 13)
#define TX_BD_FLAGS_COAL_NOW (1 << 15)
#define TX_BD_LEN (0xffff << 16)
#define TX_BD_LEN_SHIFT 16
u32 tx_bd_opaque;
__le64 tx_bd_haddr;
} __packed;
struct tx_bd_ext {
__le32 tx_bd_hsize_lflags;
#define TX_BD_FLAGS_TCP_UDP_CHKSUM (1 << 0)
#define TX_BD_FLAGS_IP_CKSUM (1 << 1)
#define TX_BD_FLAGS_NO_CRC (1 << 2)
#define TX_BD_FLAGS_STAMP (1 << 3)
#define TX_BD_FLAGS_T_IP_CHKSUM (1 << 4)
#define TX_BD_FLAGS_LSO (1 << 5)
#define TX_BD_FLAGS_IPID_FMT (1 << 6)
#define TX_BD_FLAGS_T_IPID (1 << 7)
#define TX_BD_HSIZE (0xff << 16)
#define TX_BD_HSIZE_SHIFT 16
__le32 tx_bd_mss;
__le32 tx_bd_cfa_action;
#define TX_BD_CFA_ACTION (0xffff << 16)
#define TX_BD_CFA_ACTION_SHIFT 16
__le32 tx_bd_cfa_meta;
#define TX_BD_CFA_META_MASK 0xfffffff
#define TX_BD_CFA_META_VID_MASK 0xfff
#define TX_BD_CFA_META_PRI_MASK (0xf << 12)
#define TX_BD_CFA_META_PRI_SHIFT 12
#define TX_BD_CFA_META_TPID_MASK (3 << 16)
#define TX_BD_CFA_META_TPID_SHIFT 16
#define TX_BD_CFA_META_KEY (0xf << 28)
#define TX_BD_CFA_META_KEY_SHIFT 28
#define TX_BD_CFA_META_KEY_VLAN (1 << 28)
};
struct rx_bd {
__le32 rx_bd_len_flags_type;
#define RX_BD_TYPE (0x3f << 0)
#define RX_BD_TYPE_RX_PACKET_BD 0x4
#define RX_BD_TYPE_RX_BUFFER_BD 0x5
#define RX_BD_TYPE_RX_AGG_BD 0x6
#define RX_BD_TYPE_16B_BD_SIZE (0 << 4)
#define RX_BD_TYPE_32B_BD_SIZE (1 << 4)
#define RX_BD_TYPE_48B_BD_SIZE (2 << 4)
#define RX_BD_TYPE_64B_BD_SIZE (3 << 4)
#define RX_BD_FLAGS_SOP (1 << 6)
#define RX_BD_FLAGS_EOP (1 << 7)
#define RX_BD_FLAGS_BUFFERS (3 << 8)
#define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
#define RX_BD_FLAGS_2_BUFFER_PACKET (1 << 8)
#define RX_BD_FLAGS_3_BUFFER_PACKET (2 << 8)
#define RX_BD_FLAGS_4_BUFFER_PACKET (3 << 8)
#define RX_BD_LEN (0xffff << 16)
#define RX_BD_LEN_SHIFT 16
u32 rx_bd_opaque;
__le64 rx_bd_haddr;
};
struct tx_cmp {
__le32 tx_cmp_flags_type;
#define CMP_TYPE (0x3f << 0)
#define CMP_TYPE_TX_L2_CMP 0
#define CMP_TYPE_RX_L2_CMP 17
#define CMP_TYPE_RX_AGG_CMP 18
#define CMP_TYPE_RX_L2_TPA_START_CMP 19
#define CMP_TYPE_RX_L2_TPA_END_CMP 21
#define CMP_TYPE_STATUS_CMP 32
#define CMP_TYPE_REMOTE_DRIVER_REQ 34
#define CMP_TYPE_REMOTE_DRIVER_RESP 36
#define CMP_TYPE_ERROR_STATUS 48
#define CMPL_BASE_TYPE_STAT_EJECT (0x1aUL << 0)
#define CMPL_BASE_TYPE_HWRM_DONE (0x20UL << 0)
#define CMPL_BASE_TYPE_HWRM_FWD_REQ (0x22UL << 0)
#define CMPL_BASE_TYPE_HWRM_FWD_RESP (0x24UL << 0)
#define CMPL_BASE_TYPE_HWRM_ASYNC_EVENT (0x2eUL << 0)
#define TX_CMP_FLAGS_ERROR (1 << 6)
#define TX_CMP_FLAGS_PUSH (1 << 7)
u32 tx_cmp_opaque;
__le32 tx_cmp_errors_v;
#define TX_CMP_V (1 << 0)
#define TX_CMP_ERRORS_BUFFER_ERROR (7 << 1)
#define TX_CMP_ERRORS_BUFFER_ERROR_NO_ERROR 0
#define TX_CMP_ERRORS_BUFFER_ERROR_BAD_FORMAT 2
#define TX_CMP_ERRORS_BUFFER_ERROR_INVALID_STAG 4
#define TX_CMP_ERRORS_BUFFER_ERROR_STAG_BOUNDS 5
#define TX_CMP_ERRORS_ZERO_LENGTH_PKT (1 << 4)
#define TX_CMP_ERRORS_EXCESSIVE_BD_LEN (1 << 5)
#define TX_CMP_ERRORS_DMA_ERROR (1 << 6)
#define TX_CMP_ERRORS_HINT_TOO_SHORT (1 << 7)
__le32 tx_cmp_unsed_3;
};
struct rx_cmp {
__le32 rx_cmp_len_flags_type;
#define RX_CMP_CMP_TYPE (0x3f << 0)
#define RX_CMP_FLAGS_ERROR (1 << 6)
#define RX_CMP_FLAGS_PLACEMENT (7 << 7)
#define RX_CMP_FLAGS_RSS_VALID (1 << 10)
#define RX_CMP_FLAGS_UNUSED (1 << 11)
#define RX_CMP_FLAGS_ITYPES_SHIFT 12
#define RX_CMP_FLAGS_ITYPE_UNKNOWN (0 << 12)
#define RX_CMP_FLAGS_ITYPE_IP (1 << 12)
#define RX_CMP_FLAGS_ITYPE_TCP (2 << 12)
#define RX_CMP_FLAGS_ITYPE_UDP (3 << 12)
#define RX_CMP_FLAGS_ITYPE_FCOE (4 << 12)
#define RX_CMP_FLAGS_ITYPE_ROCE (5 << 12)
#define RX_CMP_FLAGS_ITYPE_PTP_WO_TS (8 << 12)
#define RX_CMP_FLAGS_ITYPE_PTP_W_TS (9 << 12)
#define RX_CMP_LEN (0xffff << 16)
#define RX_CMP_LEN_SHIFT 16
u32 rx_cmp_opaque;
__le32 rx_cmp_misc_v1;
#define RX_CMP_V1 (1 << 0)
#define RX_CMP_AGG_BUFS (0x1f << 1)
#define RX_CMP_AGG_BUFS_SHIFT 1
#define RX_CMP_RSS_HASH_TYPE (0x7f << 9)
#define RX_CMP_RSS_HASH_TYPE_SHIFT 9
#define RX_CMP_PAYLOAD_OFFSET (0xff << 16)
#define RX_CMP_PAYLOAD_OFFSET_SHIFT 16
__le32 rx_cmp_rss_hash;
};
#define RX_CMP_HASH_VALID(rxcmp) \
((rxcmp)->rx_cmp_len_flags_type & cpu_to_le32(RX_CMP_FLAGS_RSS_VALID))
#define RX_CMP_HASH_TYPE(rxcmp) \
((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\
RX_CMP_RSS_HASH_TYPE_SHIFT)
struct rx_cmp_ext {
__le32 rx_cmp_flags2;
#define RX_CMP_FLAGS2_IP_CS_CALC 0x1
#define RX_CMP_FLAGS2_L4_CS_CALC (0x1 << 1)
#define RX_CMP_FLAGS2_T_IP_CS_CALC (0x1 << 2)
#define RX_CMP_FLAGS2_T_L4_CS_CALC (0x1 << 3)
#define RX_CMP_FLAGS2_META_FORMAT_VLAN (0x1 << 4)
__le32 rx_cmp_meta_data;
#define RX_CMP_FLAGS2_METADATA_VID_MASK 0xfff
#define RX_CMP_FLAGS2_METADATA_TPID_MASK 0xffff0000
#define RX_CMP_FLAGS2_METADATA_TPID_SFT 16
__le32 rx_cmp_cfa_code_errors_v2;
#define RX_CMP_V (1 << 0)
#define RX_CMPL_ERRORS_MASK (0x7fff << 1)
#define RX_CMPL_ERRORS_SFT 1
#define RX_CMPL_ERRORS_BUFFER_ERROR_MASK (0x7 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_NO_BUFFER (0x0 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_DID_NOT_FIT (0x1 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_NOT_ON_CHIP (0x2 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_BAD_FORMAT (0x3 << 1)
#define RX_CMPL_ERRORS_IP_CS_ERROR (0x1 << 4)
#define RX_CMPL_ERRORS_L4_CS_ERROR (0x1 << 5)
#define RX_CMPL_ERRORS_T_IP_CS_ERROR (0x1 << 6)
#define RX_CMPL_ERRORS_T_L4_CS_ERROR (0x1 << 7)
#define RX_CMPL_ERRORS_CRC_ERROR (0x1 << 8)
#define RX_CMPL_ERRORS_T_PKT_ERROR_MASK (0x7 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_NO_ERROR (0x0 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_L3_BAD_VERSION (0x1 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_L3_BAD_HDR_LEN (0x2 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_TUNNEL_TOTAL_ERROR (0x3 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_IP_TOTAL_ERROR (0x4 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_UDP_TOTAL_ERROR (0x5 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL (0x6 << 9)
#define RX_CMPL_ERRORS_PKT_ERROR_MASK (0xf << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_NO_ERROR (0x0 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L3_BAD_VERSION (0x1 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L3_BAD_HDR_LEN (0x2 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L3_BAD_TTL (0x3 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_IP_TOTAL_ERROR (0x4 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_UDP_TOTAL_ERROR (0x5 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN (0x6 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN_TOO_SMALL (0x7 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN (0x8 << 12)
#define RX_CMPL_CFA_CODE_MASK (0xffff << 16)
#define RX_CMPL_CFA_CODE_SFT 16
__le32 rx_cmp_unused3;
};
#define RX_CMP_L2_ERRORS \
cpu_to_le32(RX_CMPL_ERRORS_BUFFER_ERROR_MASK | RX_CMPL_ERRORS_CRC_ERROR)
#define RX_CMP_L4_CS_BITS \
(cpu_to_le32(RX_CMP_FLAGS2_L4_CS_CALC | RX_CMP_FLAGS2_T_L4_CS_CALC))
#define RX_CMP_L4_CS_ERR_BITS \
(cpu_to_le32(RX_CMPL_ERRORS_L4_CS_ERROR | RX_CMPL_ERRORS_T_L4_CS_ERROR))
#define RX_CMP_L4_CS_OK(rxcmp1) \
(((rxcmp1)->rx_cmp_flags2 & RX_CMP_L4_CS_BITS) && \
!((rxcmp1)->rx_cmp_cfa_code_errors_v2 & RX_CMP_L4_CS_ERR_BITS))
#define RX_CMP_ENCAP(rxcmp1) \
((le32_to_cpu((rxcmp1)->rx_cmp_flags2) & \
RX_CMP_FLAGS2_T_L4_CS_CALC) >> 3)
struct rx_agg_cmp {
__le32 rx_agg_cmp_len_flags_type;
#define RX_AGG_CMP_TYPE (0x3f << 0)
#define RX_AGG_CMP_LEN (0xffff << 16)
#define RX_AGG_CMP_LEN_SHIFT 16
u32 rx_agg_cmp_opaque;
__le32 rx_agg_cmp_v;
#define RX_AGG_CMP_V (1 << 0)
__le32 rx_agg_cmp_unused;
};
struct rx_tpa_start_cmp {
__le32 rx_tpa_start_cmp_len_flags_type;
#define RX_TPA_START_CMP_TYPE (0x3f << 0)
#define RX_TPA_START_CMP_FLAGS (0x3ff << 6)
#define RX_TPA_START_CMP_FLAGS_SHIFT 6
#define RX_TPA_START_CMP_FLAGS_PLACEMENT (0x7 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_SHIFT 7
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_JUMBO (0x1 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_HDS (0x2 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_GRO_JUMBO (0x5 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_GRO_HDS (0x6 << 7)
#define RX_TPA_START_CMP_FLAGS_RSS_VALID (0x1 << 10)
#define RX_TPA_START_CMP_FLAGS_ITYPES (0xf << 12)
#define RX_TPA_START_CMP_FLAGS_ITYPES_SHIFT 12
#define RX_TPA_START_CMP_FLAGS_ITYPE_TCP (0x2 << 12)
#define RX_TPA_START_CMP_LEN (0xffff << 16)
#define RX_TPA_START_CMP_LEN_SHIFT 16
u32 rx_tpa_start_cmp_opaque;
__le32 rx_tpa_start_cmp_misc_v1;
#define RX_TPA_START_CMP_V1 (0x1 << 0)
#define RX_TPA_START_CMP_RSS_HASH_TYPE (0x7f << 9)
#define RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT 9
#define RX_TPA_START_CMP_AGG_ID (0x7f << 25)
#define RX_TPA_START_CMP_AGG_ID_SHIFT 25
__le32 rx_tpa_start_cmp_rss_hash;
};
#define TPA_START_HASH_VALID(rx_tpa_start) \
((rx_tpa_start)->rx_tpa_start_cmp_len_flags_type & \
cpu_to_le32(RX_TPA_START_CMP_FLAGS_RSS_VALID))
#define TPA_START_HASH_TYPE(rx_tpa_start) \
((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
RX_TPA_START_CMP_RSS_HASH_TYPE) >> \
RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT)
#define TPA_START_AGG_ID(rx_tpa_start) \
((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
RX_TPA_START_CMP_AGG_ID) >> RX_TPA_START_CMP_AGG_ID_SHIFT)
struct rx_tpa_start_cmp_ext {
__le32 rx_tpa_start_cmp_flags2;
#define RX_TPA_START_CMP_FLAGS2_IP_CS_CALC (0x1 << 0)
#define RX_TPA_START_CMP_FLAGS2_L4_CS_CALC (0x1 << 1)
#define RX_TPA_START_CMP_FLAGS2_T_IP_CS_CALC (0x1 << 2)
#define RX_TPA_START_CMP_FLAGS2_T_L4_CS_CALC (0x1 << 3)
__le32 rx_tpa_start_cmp_metadata;
__le32 rx_tpa_start_cmp_cfa_code_v2;
#define RX_TPA_START_CMP_V2 (0x1 << 0)
#define RX_TPA_START_CMP_CFA_CODE (0xffff << 16)
#define RX_TPA_START_CMPL_CFA_CODE_SHIFT 16
__le32 rx_tpa_start_cmp_unused5;
};
struct rx_tpa_end_cmp {
__le32 rx_tpa_end_cmp_len_flags_type;
#define RX_TPA_END_CMP_TYPE (0x3f << 0)
#define RX_TPA_END_CMP_FLAGS (0x3ff << 6)
#define RX_TPA_END_CMP_FLAGS_SHIFT 6
#define RX_TPA_END_CMP_FLAGS_PLACEMENT (0x7 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_SHIFT 7
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_JUMBO (0x1 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_HDS (0x2 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_JUMBO (0x5 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_HDS (0x6 << 7)
#define RX_TPA_END_CMP_FLAGS_RSS_VALID (0x1 << 10)
#define RX_TPA_END_CMP_FLAGS_ITYPES (0xf << 12)
#define RX_TPA_END_CMP_FLAGS_ITYPES_SHIFT 12
#define RX_TPA_END_CMP_FLAGS_ITYPE_TCP (0x2 << 12)
#define RX_TPA_END_CMP_LEN (0xffff << 16)
#define RX_TPA_END_CMP_LEN_SHIFT 16
u32 rx_tpa_end_cmp_opaque;
__le32 rx_tpa_end_cmp_misc_v1;
#define RX_TPA_END_CMP_V1 (0x1 << 0)
#define RX_TPA_END_CMP_AGG_BUFS (0x3f << 1)
#define RX_TPA_END_CMP_AGG_BUFS_SHIFT 1
#define RX_TPA_END_CMP_TPA_SEGS (0xff << 8)
#define RX_TPA_END_CMP_TPA_SEGS_SHIFT 8
#define RX_TPA_END_CMP_PAYLOAD_OFFSET (0xff << 16)
#define RX_TPA_END_CMP_PAYLOAD_OFFSET_SHIFT 16
#define RX_TPA_END_CMP_AGG_ID (0x7f << 25)
#define RX_TPA_END_CMP_AGG_ID_SHIFT 25
__le32 rx_tpa_end_cmp_tsdelta;
#define RX_TPA_END_GRO_TS (0x1 << 31)
};
#define TPA_END_AGG_ID(rx_tpa_end) \
((le32_to_cpu((rx_tpa_end)->rx_tpa_end_cmp_misc_v1) & \
RX_TPA_END_CMP_AGG_ID) >> RX_TPA_END_CMP_AGG_ID_SHIFT)
#define TPA_END_TPA_SEGS(rx_tpa_end) \
((le32_to_cpu((rx_tpa_end)->rx_tpa_end_cmp_misc_v1) & \
RX_TPA_END_CMP_TPA_SEGS) >> RX_TPA_END_CMP_TPA_SEGS_SHIFT)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_ANY_GRO \
cpu_to_le32(RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_JUMBO & \
RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_HDS)
#define TPA_END_GRO(rx_tpa_end) \
((rx_tpa_end)->rx_tpa_end_cmp_len_flags_type & \
RX_TPA_END_CMP_FLAGS_PLACEMENT_ANY_GRO)
#define TPA_END_GRO_TS(rx_tpa_end) \
((rx_tpa_end)->rx_tpa_end_cmp_tsdelta & cpu_to_le32(RX_TPA_END_GRO_TS))
struct rx_tpa_end_cmp_ext {
__le32 rx_tpa_end_cmp_dup_acks;
#define RX_TPA_END_CMP_TPA_DUP_ACKS (0xf << 0)
__le32 rx_tpa_end_cmp_seg_len;
#define RX_TPA_END_CMP_TPA_SEG_LEN (0xffff << 0)
__le32 rx_tpa_end_cmp_errors_v2;
#define RX_TPA_END_CMP_V2 (0x1 << 0)
#define RX_TPA_END_CMP_ERRORS (0x7fff << 1)
#define RX_TPA_END_CMPL_ERRORS_SHIFT 1
u32 rx_tpa_end_cmp_start_opaque;
};
#define DB_IDX_MASK 0xffffff
#define DB_IDX_VALID (0x1 << 26)
#define DB_IRQ_DIS (0x1 << 27)
#define DB_KEY_TX (0x0 << 28)
#define DB_KEY_RX (0x1 << 28)
#define DB_KEY_CP (0x2 << 28)
#define DB_KEY_ST (0x3 << 28)
#define DB_KEY_TX_PUSH (0x4 << 28)
#define DB_LONG_TX_PUSH (0x2 << 24)
#define INVALID_HW_RING_ID ((u16)-1)
#define BNXT_RSS_HASH_TYPE_FLAG_IPV4 0x01
#define BNXT_RSS_HASH_TYPE_FLAG_TCP_IPV4 0x02
#define BNXT_RSS_HASH_TYPE_FLAG_IPV6 0x04
#define BNXT_RSS_HASH_TYPE_FLAG_TCP_IPV6 0x08
/* The hardware supports certain page sizes. Use the supported page sizes
* to allocate the rings.
*/
#if (PAGE_SHIFT < 12)
#define BNXT_PAGE_SHIFT 12
#elif (PAGE_SHIFT <= 13)
#define BNXT_PAGE_SHIFT PAGE_SHIFT
#elif (PAGE_SHIFT < 16)
#define BNXT_PAGE_SHIFT 13
#else
#define BNXT_PAGE_SHIFT 16
#endif
#define BNXT_PAGE_SIZE (1 << BNXT_PAGE_SHIFT)
#define BNXT_MIN_PKT_SIZE 45
#define BNXT_NUM_TESTS(bp) 0
#define BNXT_DEFAULT_RX_RING_SIZE 1023
#define BNXT_DEFAULT_TX_RING_SIZE 512
#define MAX_TPA 64
#define MAX_RX_PAGES 8
#define MAX_RX_AGG_PAGES 32
#define MAX_TX_PAGES 8
#define MAX_CP_PAGES 64
#define RX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct rx_bd))
#define TX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct tx_bd))
#define CP_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct tx_cmp))
#define SW_RXBD_RING_SIZE (sizeof(struct bnxt_sw_rx_bd) * RX_DESC_CNT)
#define HW_RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT)
#define SW_RXBD_AGG_RING_SIZE (sizeof(struct bnxt_sw_rx_agg_bd) * RX_DESC_CNT)
#define SW_TXBD_RING_SIZE (sizeof(struct bnxt_sw_tx_bd) * TX_DESC_CNT)
#define HW_TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT)
#define HW_CMPD_RING_SIZE (sizeof(struct tx_cmp) * CP_DESC_CNT)
#define BNXT_MAX_RX_DESC_CNT (RX_DESC_CNT * MAX_RX_PAGES - 1)
#define BNXT_MAX_RX_JUM_DESC_CNT (RX_DESC_CNT * MAX_RX_AGG_PAGES - 1)
#define BNXT_MAX_TX_DESC_CNT (TX_DESC_CNT * MAX_TX_PAGES - 1)
#define RX_RING(x) (((x) & ~(RX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
#define RX_IDX(x) ((x) & (RX_DESC_CNT - 1))
#define TX_RING(x) (((x) & ~(TX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
#define TX_IDX(x) ((x) & (TX_DESC_CNT - 1))
#define CP_RING(x) (((x) & ~(CP_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
#define CP_IDX(x) ((x) & (CP_DESC_CNT - 1))
#define TX_CMP_VALID(txcmp, raw_cons) \
(!!((txcmp)->tx_cmp_errors_v & cpu_to_le32(TX_CMP_V)) == \
!((raw_cons) & bp->cp_bit))
#define RX_CMP_VALID(rxcmp1, raw_cons) \
(!!((rxcmp1)->rx_cmp_cfa_code_errors_v2 & cpu_to_le32(RX_CMP_V)) ==\
!((raw_cons) & bp->cp_bit))
#define RX_AGG_CMP_VALID(agg, raw_cons) \
(!!((agg)->rx_agg_cmp_v & cpu_to_le32(RX_AGG_CMP_V)) == \
!((raw_cons) & bp->cp_bit))
#define TX_CMP_TYPE(txcmp) \
(le32_to_cpu((txcmp)->tx_cmp_flags_type) & CMP_TYPE)
#define RX_CMP_TYPE(rxcmp) \
(le32_to_cpu((rxcmp)->rx_cmp_len_flags_type) & RX_CMP_CMP_TYPE)
#define NEXT_RX(idx) (((idx) + 1) & bp->rx_ring_mask)
#define NEXT_RX_AGG(idx) (((idx) + 1) & bp->rx_agg_ring_mask)
#define NEXT_TX(idx) (((idx) + 1) & bp->tx_ring_mask)
#define ADV_RAW_CMP(idx, n) ((idx) + (n))
#define NEXT_RAW_CMP(idx) ADV_RAW_CMP(idx, 1)
#define RING_CMP(idx) ((idx) & bp->cp_ring_mask)
#define NEXT_CMP(idx) RING_CMP(ADV_RAW_CMP(idx, 1))
#define HWRM_CMD_TIMEOUT 500
#define HWRM_RESET_TIMEOUT ((HWRM_CMD_TIMEOUT) * 4)
#define HWRM_RESP_ERR_CODE_MASK 0xffff
#define HWRM_RESP_LEN_MASK 0xffff0000
#define HWRM_RESP_LEN_SFT 16
#define HWRM_RESP_VALID_MASK 0xff000000
#define BNXT_HWRM_REQ_MAX_SIZE 128
#define BNXT_HWRM_REQS_PER_PAGE (BNXT_PAGE_SIZE / \
BNXT_HWRM_REQ_MAX_SIZE)
struct bnxt_sw_tx_bd {
struct sk_buff *skb;
DEFINE_DMA_UNMAP_ADDR(mapping);
u8 is_gso;
u8 is_push;
unsigned short nr_frags;
};
struct bnxt_sw_rx_bd {
u8 *data;
DEFINE_DMA_UNMAP_ADDR(mapping);
};
struct bnxt_sw_rx_agg_bd {
struct page *page;
dma_addr_t mapping;
};
struct bnxt_ring_struct {
int nr_pages;
int page_size;
void **pg_arr;
dma_addr_t *dma_arr;
__le64 *pg_tbl;
dma_addr_t pg_tbl_map;
int vmem_size;
void **vmem;
u16 fw_ring_id; /* Ring id filled by Chimp FW */
u8 queue_id;
};
struct tx_push_bd {
__le32 doorbell;
struct tx_bd txbd1;
struct tx_bd_ext txbd2;
};
struct bnxt_tx_ring_info {
u16 tx_prod;
u16 tx_cons;
void __iomem *tx_doorbell;
struct tx_bd *tx_desc_ring[MAX_TX_PAGES];
struct bnxt_sw_tx_bd *tx_buf_ring;
dma_addr_t tx_desc_mapping[MAX_TX_PAGES];
struct tx_push_bd *tx_push;
dma_addr_t tx_push_mapping;
#define BNXT_DEV_STATE_CLOSING 0x1
u32 dev_state;
struct bnxt_ring_struct tx_ring_struct;
};
struct bnxt_tpa_info {
u8 *data;
dma_addr_t mapping;
u16 len;
unsigned short gso_type;
u32 flags2;
u32 metadata;
enum pkt_hash_types hash_type;
u32 rss_hash;
};
struct bnxt_rx_ring_info {
u16 rx_prod;
u16 rx_agg_prod;
u16 rx_sw_agg_prod;
void __iomem *rx_doorbell;
void __iomem *rx_agg_doorbell;
struct rx_bd *rx_desc_ring[MAX_RX_PAGES];
struct bnxt_sw_rx_bd *rx_buf_ring;
struct rx_bd *rx_agg_desc_ring[MAX_RX_AGG_PAGES];
struct bnxt_sw_rx_agg_bd *rx_agg_ring;
unsigned long *rx_agg_bmap;
u16 rx_agg_bmap_size;
dma_addr_t rx_desc_mapping[MAX_RX_PAGES];
dma_addr_t rx_agg_desc_mapping[MAX_RX_AGG_PAGES];
struct bnxt_tpa_info *rx_tpa;
struct bnxt_ring_struct rx_ring_struct;
struct bnxt_ring_struct rx_agg_ring_struct;
};
struct bnxt_cp_ring_info {
u32 cp_raw_cons;
void __iomem *cp_doorbell;
struct tx_cmp *cp_desc_ring[MAX_CP_PAGES];
dma_addr_t cp_desc_mapping[MAX_CP_PAGES];
struct ctx_hw_stats *hw_stats;
dma_addr_t hw_stats_map;
u32 hw_stats_ctx_id;
u64 rx_l4_csum_errors;
struct bnxt_ring_struct cp_ring_struct;
};
struct bnxt_napi {
struct napi_struct napi;
struct bnxt *bp;
int index;
struct bnxt_cp_ring_info cp_ring;
struct bnxt_rx_ring_info rx_ring;
struct bnxt_tx_ring_info tx_ring;
#ifdef CONFIG_NET_RX_BUSY_POLL
atomic_t poll_state;
#endif
};
#ifdef CONFIG_NET_RX_BUSY_POLL
enum bnxt_poll_state_t {
BNXT_STATE_IDLE = 0,
BNXT_STATE_NAPI,
BNXT_STATE_POLL,
BNXT_STATE_DISABLE,
};
#endif
struct bnxt_irq {
irq_handler_t handler;
unsigned int vector;
u8 requested;
char name[IFNAMSIZ + 2];
};
#define HWRM_RING_ALLOC_TX 0x1
#define HWRM_RING_ALLOC_RX 0x2
#define HWRM_RING_ALLOC_AGG 0x4
#define HWRM_RING_ALLOC_CMPL 0x8
#define INVALID_STATS_CTX_ID -1
struct hwrm_cmd_req_hdr {
#define HWRM_CMPL_RING_MASK 0xffff0000
#define HWRM_CMPL_RING_SFT 16
__le32 cmpl_ring_req_type;
#define HWRM_SEQ_ID_MASK 0xffff
#define HWRM_SEQ_ID_INVALID -1
#define HWRM_RESP_LEN_OFFSET 4
#define HWRM_TARGET_FID_MASK 0xffff0000
#define HWRM_TARGET_FID_SFT 16
__le32 target_id_seq_id;
__le64 resp_addr;
};
struct bnxt_ring_grp_info {
u16 fw_stats_ctx;
u16 fw_grp_id;
u16 rx_fw_ring_id;
u16 agg_fw_ring_id;
u16 cp_fw_ring_id;
};
struct bnxt_vnic_info {
u16 fw_vnic_id; /* returned by Chimp during alloc */
u16 fw_rss_cos_lb_ctx;
u16 fw_l2_ctx_id;
#define BNXT_MAX_UC_ADDRS 4
__le64 fw_l2_filter_id[BNXT_MAX_UC_ADDRS];
/* index 0 always dev_addr */
u16 uc_filter_count;
u8 *uc_list;
u16 *fw_grp_ids;
u16 hash_type;
dma_addr_t rss_table_dma_addr;
__le16 *rss_table;
dma_addr_t rss_hash_key_dma_addr;
u64 *rss_hash_key;
u32 rx_mask;
u8 *mc_list;
int mc_list_size;
int mc_list_count;
dma_addr_t mc_list_mapping;
#define BNXT_MAX_MC_ADDRS 16
u32 flags;
#define BNXT_VNIC_RSS_FLAG 1
#define BNXT_VNIC_RFS_FLAG 2
#define BNXT_VNIC_MCAST_FLAG 4
#define BNXT_VNIC_UCAST_FLAG 8
};
#if defined(CONFIG_BNXT_SRIOV)
struct bnxt_vf_info {
u16 fw_fid;
u8 mac_addr[ETH_ALEN];
u16 max_rsscos_ctxs;
u16 max_cp_rings;
u16 max_tx_rings;
u16 max_rx_rings;
u16 max_l2_ctxs;
u16 max_irqs;
u16 max_vnics;
u16 max_stat_ctxs;
u16 vlan;
u32 flags;
#define BNXT_VF_QOS 0x1
#define BNXT_VF_SPOOFCHK 0x2
#define BNXT_VF_LINK_FORCED 0x4
#define BNXT_VF_LINK_UP 0x8
u32 func_flags; /* func cfg flags */
u32 min_tx_rate;
u32 max_tx_rate;
void *hwrm_cmd_req_addr;
dma_addr_t hwrm_cmd_req_dma_addr;
};
struct bnxt_pf_info {
#define BNXT_FIRST_PF_FID 1
#define BNXT_FIRST_VF_FID 128
u32 fw_fid;
u8 port_id;
u8 mac_addr[ETH_ALEN];
u16 max_rsscos_ctxs;
u16 max_cp_rings;
u16 max_tx_rings; /* HW assigned max tx rings for this PF */
u16 max_pf_tx_rings; /* runtime max tx rings owned by PF */
u16 max_rx_rings; /* HW assigned max rx rings for this PF */
u16 max_pf_rx_rings; /* runtime max rx rings owned by PF */
u16 max_irqs;
u16 max_l2_ctxs;
u16 max_vnics;
u16 max_stat_ctxs;
u32 first_vf_id;
u16 active_vfs;
u16 max_vfs;
u32 max_encap_records;
u32 max_decap_records;
u32 max_tx_em_flows;
u32 max_tx_wm_flows;
u32 max_rx_em_flows;
u32 max_rx_wm_flows;
unsigned long *vf_event_bmap;
u16 hwrm_cmd_req_pages;
void *hwrm_cmd_req_addr[4];
dma_addr_t hwrm_cmd_req_dma_addr[4];
struct bnxt_vf_info *vf;
};
#endif
struct bnxt_ntuple_filter {
struct hlist_node hash;
u8 src_mac_addr[ETH_ALEN];
struct flow_keys fkeys;
__le64 filter_id;
u16 sw_id;
u16 rxq;
u32 flow_id;
unsigned long state;
#define BNXT_FLTR_VALID 0
#define BNXT_FLTR_UPDATE 1
};
#define BNXT_ALL_COPPER_ETHTOOL_SPEED \
(ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full | \
ADVERTISED_10000baseT_Full)
struct bnxt_link_info {
u8 media_type;
u8 transceiver;
u8 phy_addr;
u8 phy_link_status;
#define BNXT_LINK_NO_LINK PORT_PHY_QCFG_RESP_LINK_NO_LINK
#define BNXT_LINK_SIGNAL PORT_PHY_QCFG_RESP_LINK_SIGNAL
#define BNXT_LINK_LINK PORT_PHY_QCFG_RESP_LINK_LINK
u8 wire_speed;
u8 loop_back;
u8 link_up;
u8 duplex;
#define BNXT_LINK_DUPLEX_HALF PORT_PHY_QCFG_RESP_DUPLEX_HALF
#define BNXT_LINK_DUPLEX_FULL PORT_PHY_QCFG_RESP_DUPLEX_FULL
u8 pause;
#define BNXT_LINK_PAUSE_TX PORT_PHY_QCFG_RESP_PAUSE_TX
#define BNXT_LINK_PAUSE_RX PORT_PHY_QCFG_RESP_PAUSE_RX
#define BNXT_LINK_PAUSE_BOTH (PORT_PHY_QCFG_RESP_PAUSE_RX | \
PORT_PHY_QCFG_RESP_PAUSE_TX)
u8 auto_pause_setting;
u8 force_pause_setting;
u8 duplex_setting;
u8 auto_mode;
#define BNXT_AUTO_MODE(mode) ((mode) > BNXT_LINK_AUTO_NONE && \
(mode) <= BNXT_LINK_AUTO_MSK)
#define BNXT_LINK_AUTO_NONE PORT_PHY_QCFG_RESP_AUTO_MODE_NONE
#define BNXT_LINK_AUTO_ALLSPDS PORT_PHY_QCFG_RESP_AUTO_MODE_ALL_SPEEDS
#define BNXT_LINK_AUTO_ONESPD PORT_PHY_QCFG_RESP_AUTO_MODE_ONE_SPEED
#define BNXT_LINK_AUTO_ONEORBELOW PORT_PHY_QCFG_RESP_AUTO_MODE_ONE_OR_BELOW
#define BNXT_LINK_AUTO_MSK PORT_PHY_QCFG_RESP_AUTO_MODE_MASK
#define PHY_VER_LEN 3
u8 phy_ver[PHY_VER_LEN];
u16 link_speed;
#define BNXT_LINK_SPEED_100MB PORT_PHY_QCFG_RESP_LINK_SPEED_100MB
#define BNXT_LINK_SPEED_1GB PORT_PHY_QCFG_RESP_LINK_SPEED_1GB
#define BNXT_LINK_SPEED_2GB PORT_PHY_QCFG_RESP_LINK_SPEED_2GB
#define BNXT_LINK_SPEED_2_5GB PORT_PHY_QCFG_RESP_LINK_SPEED_2_5GB
#define BNXT_LINK_SPEED_10GB PORT_PHY_QCFG_RESP_LINK_SPEED_10GB
#define BNXT_LINK_SPEED_20GB PORT_PHY_QCFG_RESP_LINK_SPEED_20GB
#define BNXT_LINK_SPEED_25GB PORT_PHY_QCFG_RESP_LINK_SPEED_25GB
#define BNXT_LINK_SPEED_40GB PORT_PHY_QCFG_RESP_LINK_SPEED_40GB
#define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB
u16 support_speeds;
u16 auto_link_speeds;
#define BNXT_LINK_SPEED_MSK_100MB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_100MB
#define BNXT_LINK_SPEED_MSK_1GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_1GB
#define BNXT_LINK_SPEED_MSK_2GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_2GB
#define BNXT_LINK_SPEED_MSK_10GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_10GB
#define BNXT_LINK_SPEED_MSK_2_5GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_2_5GB
#define BNXT_LINK_SPEED_MSK_20GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_20GB
#define BNXT_LINK_SPEED_MSK_25GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_25GB
#define BNXT_LINK_SPEED_MSK_40GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_40GB
#define BNXT_LINK_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_50GB
u16 auto_link_speed;
u16 force_link_speed;
u32 preemphasis;
/* copy of requested setting from ethtool cmd */
u8 autoneg;
#define BNXT_AUTONEG_SPEED 1
#define BNXT_AUTONEG_FLOW_CTRL 2
u8 req_duplex;
u8 req_flow_ctrl;
u16 req_link_speed;
u32 advertising;
bool force_link_chng;
/* a copy of phy_qcfg output used to report link
* info to VF
*/
struct hwrm_port_phy_qcfg_output phy_qcfg_resp;
};
#define BNXT_MAX_QUEUE 8
struct bnxt_queue_info {
u8 queue_id;
u8 queue_profile;
};
struct bnxt {
void __iomem *bar0;
void __iomem *bar1;
void __iomem *bar2;
u32 reg_base;
struct net_device *dev;
struct pci_dev *pdev;
atomic_t intr_sem;
u32 flags;
#define BNXT_FLAG_DCB_ENABLED 0x1
#define BNXT_FLAG_VF 0x2
#define BNXT_FLAG_LRO 0x4
#define BNXT_FLAG_GRO 0x8
#define BNXT_FLAG_TPA (BNXT_FLAG_LRO | BNXT_FLAG_GRO)
#define BNXT_FLAG_JUMBO 0x10
#define BNXT_FLAG_STRIP_VLAN 0x20
#define BNXT_FLAG_AGG_RINGS (BNXT_FLAG_JUMBO | BNXT_FLAG_GRO | \
BNXT_FLAG_LRO)
#define BNXT_FLAG_USING_MSIX 0x40
#define BNXT_FLAG_MSIX_CAP 0x80
#define BNXT_FLAG_RFS 0x100
#define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA | \
BNXT_FLAG_RFS | \
BNXT_FLAG_STRIP_VLAN)
#define BNXT_PF(bp) (!((bp)->flags & BNXT_FLAG_VF))
#define BNXT_VF(bp) ((bp)->flags & BNXT_FLAG_VF)
struct bnxt_napi **bnapi;
u32 rx_buf_size;
u32 rx_buf_use_size; /* useable size */
u32 rx_ring_size;
u32 rx_agg_ring_size;
u32 rx_copy_thresh;
u32 rx_ring_mask;
u32 rx_agg_ring_mask;
int rx_nr_pages;
int rx_agg_nr_pages;
int rx_nr_rings;
int rsscos_nr_ctxs;
u32 tx_ring_size;
u32 tx_ring_mask;
int tx_nr_pages;
int tx_nr_rings;
int tx_nr_rings_per_tc;
int tx_wake_thresh;
int tx_push_thresh;
int tx_push_size;
u32 cp_ring_size;
u32 cp_ring_mask;
u32 cp_bit;
int cp_nr_pages;
int cp_nr_rings;
int num_stat_ctxs;
struct bnxt_ring_grp_info *grp_info;
struct bnxt_vnic_info *vnic_info;
int nr_vnics;
u8 max_tc;
struct bnxt_queue_info q_info[BNXT_MAX_QUEUE];
unsigned int current_interval;
#define BNXT_TIMER_INTERVAL (HZ / 2)
struct timer_list timer;
int state;
#define BNXT_STATE_CLOSED 0
#define BNXT_STATE_OPEN 1
struct bnxt_irq *irq_tbl;
u8 mac_addr[ETH_ALEN];
u32 msg_enable;
u16 hwrm_cmd_seq;
u32 hwrm_intr_seq_id;
void *hwrm_cmd_resp_addr;
dma_addr_t hwrm_cmd_resp_dma_addr;
void *hwrm_dbg_resp_addr;
dma_addr_t hwrm_dbg_resp_dma_addr;
#define HWRM_DBG_REG_BUF_SIZE 128
struct mutex hwrm_cmd_lock; /* serialize hwrm messages */
struct hwrm_ver_get_output ver_resp;
#define FW_VER_STR_LEN 32
#define BC_HWRM_STR_LEN 21
#define PHY_VER_STR_LEN (FW_VER_STR_LEN - BC_HWRM_STR_LEN)
char fw_ver_str[FW_VER_STR_LEN];
__be16 vxlan_port;
u8 vxlan_port_cnt;
__le16 vxlan_fw_dst_port_id;
u8 nge_port_cnt;
__le16 nge_fw_dst_port_id;
u16 coal_ticks;
u16 coal_ticks_irq;
u16 coal_bufs;
u16 coal_bufs_irq;
#define BNXT_USEC_TO_COAL_TIMER(x) ((x) * 25 / 2)
#define BNXT_COAL_TIMER_TO_USEC(x) ((x) * 2 / 25)
struct work_struct sp_task;
unsigned long sp_event;
#define BNXT_RX_MASK_SP_EVENT 0
#define BNXT_RX_NTP_FLTR_SP_EVENT 1
#define BNXT_LINK_CHNG_SP_EVENT 2
#define BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT 4
#define BNXT_VXLAN_ADD_PORT_SP_EVENT 8
#define BNXT_VXLAN_DEL_PORT_SP_EVENT 16
#define BNXT_RESET_TASK_SP_EVENT 32
#define BNXT_RST_RING_SP_EVENT 64
#ifdef CONFIG_BNXT_SRIOV
int nr_vfs;
struct bnxt_pf_info pf;
struct bnxt_vf_info vf;
wait_queue_head_t sriov_cfg_wait;
bool sriov_cfg;
#define BNXT_SRIOV_CFG_WAIT_TMO msecs_to_jiffies(10000)
#endif
#define BNXT_NTP_FLTR_MAX_FLTR 4096
#define BNXT_NTP_FLTR_HASH_SIZE 512
#define BNXT_NTP_FLTR_HASH_MASK (BNXT_NTP_FLTR_HASH_SIZE - 1)
struct hlist_head ntp_fltr_hash_tbl[BNXT_NTP_FLTR_HASH_SIZE];
spinlock_t ntp_fltr_lock; /* for hash table add, del */
unsigned long *ntp_fltr_bmap;
int ntp_fltr_count;
struct bnxt_link_info link_info;
};
#ifdef CONFIG_NET_RX_BUSY_POLL
static inline void bnxt_enable_poll(struct bnxt_napi *bnapi)
{
atomic_set(&bnapi->poll_state, BNXT_STATE_IDLE);
}
/* called from the NAPI poll routine to get ownership of a bnapi */
static inline bool bnxt_lock_napi(struct bnxt_napi *bnapi)
{
int rc = atomic_cmpxchg(&bnapi->poll_state, BNXT_STATE_IDLE,
BNXT_STATE_NAPI);
return rc == BNXT_STATE_IDLE;
}
static inline void bnxt_unlock_napi(struct bnxt_napi *bnapi)
{
atomic_set(&bnapi->poll_state, BNXT_STATE_IDLE);
}
/* called from the busy poll routine to get ownership of a bnapi */
static inline bool bnxt_lock_poll(struct bnxt_napi *bnapi)
{
int rc = atomic_cmpxchg(&bnapi->poll_state, BNXT_STATE_IDLE,
BNXT_STATE_POLL);
return rc == BNXT_STATE_IDLE;
}
static inline void bnxt_unlock_poll(struct bnxt_napi *bnapi)
{
atomic_set(&bnapi->poll_state, BNXT_STATE_IDLE);
}
static inline bool bnxt_busy_polling(struct bnxt_napi *bnapi)
{
return atomic_read(&bnapi->poll_state) == BNXT_STATE_POLL;
}
static inline void bnxt_disable_poll(struct bnxt_napi *bnapi)
{
int old;
while (1) {
old = atomic_cmpxchg(&bnapi->poll_state, BNXT_STATE_IDLE,
BNXT_STATE_DISABLE);
if (old == BNXT_STATE_IDLE)
break;
usleep_range(500, 5000);
}
}
#else
static inline void bnxt_enable_poll(struct bnxt_napi *bnapi)
{
}
static inline bool bnxt_lock_napi(struct bnxt_napi *bnapi)
{
return true;
}
static inline void bnxt_unlock_napi(struct bnxt_napi *bnapi)
{
}
static inline bool bnxt_lock_poll(struct bnxt_napi *bnapi)
{
return false;
}
static inline void bnxt_unlock_poll(struct bnxt_napi *bnapi)
{
}
static inline bool bnxt_busy_polling(struct bnxt_napi *bnapi)
{
return false;
}
static inline void bnxt_disable_poll(struct bnxt_napi *bnapi)
{
}
#endif
void bnxt_set_ring_params(struct bnxt *);
void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16);
int _hwrm_send_message(struct bnxt *, void *, u32, int);
int hwrm_send_message(struct bnxt *, void *, u32, int);
int bnxt_hwrm_set_coal(struct bnxt *);
int bnxt_hwrm_set_pause(struct bnxt *);
int bnxt_hwrm_set_link_setting(struct bnxt *, bool);
int bnxt_open_nic(struct bnxt *, bool, bool);
int bnxt_close_nic(struct bnxt *, bool, bool);
void bnxt_get_max_rings(struct bnxt *, int *, int *);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2015 Broadcom Corporation
*
* 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
* the Free Software Foundation.
*/
#include <linux/ethtool.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include "bnxt_hsi.h"
#include "bnxt.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 */
#define FLASH_NVRAM_TIMEOUT ((HWRM_CMD_TIMEOUT) * 100)
static u32 bnxt_get_msglevel(struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
return bp->msg_enable;
}
static void bnxt_set_msglevel(struct net_device *dev, u32 value)
{
struct bnxt *bp = netdev_priv(dev);
bp->msg_enable = value;
}
static int bnxt_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
struct bnxt *bp = netdev_priv(dev);
memset(coal, 0, sizeof(*coal));
coal->rx_coalesce_usecs =
max_t(u16, BNXT_COAL_TIMER_TO_USEC(bp->coal_ticks), 1);
coal->rx_max_coalesced_frames = bp->coal_bufs / 2;
coal->rx_coalesce_usecs_irq =
max_t(u16, BNXT_COAL_TIMER_TO_USEC(bp->coal_ticks_irq), 1);
coal->rx_max_coalesced_frames_irq = bp->coal_bufs_irq / 2;
return 0;
}
static int bnxt_set_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
struct bnxt *bp = netdev_priv(dev);
int rc = 0;
bp->coal_ticks = BNXT_USEC_TO_COAL_TIMER(coal->rx_coalesce_usecs);
bp->coal_bufs = coal->rx_max_coalesced_frames * 2;
bp->coal_ticks_irq =
BNXT_USEC_TO_COAL_TIMER(coal->rx_coalesce_usecs_irq);
bp->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * 2;
if (netif_running(dev))
rc = bnxt_hwrm_set_coal(bp);
return rc;
}
#define BNXT_NUM_STATS 21
static int bnxt_get_sset_count(struct net_device *dev, int sset)
{
struct bnxt *bp = netdev_priv(dev);
switch (sset) {
case ETH_SS_STATS:
return BNXT_NUM_STATS * bp->cp_nr_rings;
default:
return -EOPNOTSUPP;
}
}
static void bnxt_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *buf)
{
u32 i, j = 0;
struct bnxt *bp = netdev_priv(dev);
u32 buf_size = sizeof(struct ctx_hw_stats) * bp->cp_nr_rings;
u32 stat_fields = sizeof(struct ctx_hw_stats) / 8;
memset(buf, 0, buf_size);
if (!bp->bnapi)
return;
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
__le64 *hw_stats = (__le64 *)cpr->hw_stats;
int k;
for (k = 0; k < stat_fields; j++, k++)
buf[j] = le64_to_cpu(hw_stats[k]);
buf[j++] = cpr->rx_l4_csum_errors;
}
}
static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnxt *bp = netdev_priv(dev);
u32 i;
switch (stringset) {
/* The number of strings must match BNXT_NUM_STATS defined above. */
case ETH_SS_STATS:
for (i = 0; i < bp->cp_nr_rings; i++) {
sprintf(buf, "[%d]: rx_ucast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_mcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_bcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_discards", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_drops", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_ucast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_mcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_bcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_ucast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_mcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_bcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_discards", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_drops", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_ucast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_mcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_bcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_events", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_aborts", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_l4_csum_errors", i);
buf += ETH_GSTRING_LEN;
}
break;
default:
netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n",
stringset);
break;
}
}
static void bnxt_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
struct bnxt *bp = netdev_priv(dev);
ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT;
ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT;
ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT;
ering->rx_pending = bp->rx_ring_size;
ering->rx_jumbo_pending = bp->rx_agg_ring_size;
ering->tx_pending = bp->tx_ring_size;
}
static int bnxt_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
struct bnxt *bp = netdev_priv(dev);
if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) ||
(ering->tx_pending > BNXT_MAX_TX_DESC_CNT) ||
(ering->tx_pending <= MAX_SKB_FRAGS))
return -EINVAL;
if (netif_running(dev))
bnxt_close_nic(bp, false, false);
bp->rx_ring_size = ering->rx_pending;
bp->tx_ring_size = ering->tx_pending;
bnxt_set_ring_params(bp);
if (netif_running(dev))
return bnxt_open_nic(bp, false, false);
return 0;
}
static void bnxt_get_channels(struct net_device *dev,
struct ethtool_channels *channel)
{
struct bnxt *bp = netdev_priv(dev);
int max_rx_rings, max_tx_rings, tcs;
bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings);
tcs = netdev_get_num_tc(dev);
if (tcs > 1)
max_tx_rings /= tcs;
channel->max_rx = max_rx_rings;
channel->max_tx = max_tx_rings;
channel->max_other = 0;
channel->max_combined = 0;
channel->rx_count = bp->rx_nr_rings;
channel->tx_count = bp->tx_nr_rings_per_tc;
}
static int bnxt_set_channels(struct net_device *dev,
struct ethtool_channels *channel)
{
struct bnxt *bp = netdev_priv(dev);
int max_rx_rings, max_tx_rings, tcs;
u32 rc = 0;
if (channel->other_count || channel->combined_count ||
!channel->rx_count || !channel->tx_count)
return -EINVAL;
bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings);
tcs = netdev_get_num_tc(dev);
if (tcs > 1)
max_tx_rings /= tcs;
if (channel->rx_count > max_rx_rings ||
channel->tx_count > max_tx_rings)
return -EINVAL;
if (netif_running(dev)) {
if (BNXT_PF(bp)) {
/* TODO CHIMP_FW: Send message to all VF's
* before PF unload
*/
}
rc = bnxt_close_nic(bp, true, false);
if (rc) {
netdev_err(bp->dev, "Set channel failure rc :%x\n",
rc);
return rc;
}
}
bp->rx_nr_rings = channel->rx_count;
bp->tx_nr_rings_per_tc = channel->tx_count;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
if (tcs > 1)
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs;
bp->cp_nr_rings = max_t(int, bp->tx_nr_rings, bp->rx_nr_rings);
bp->num_stat_ctxs = bp->cp_nr_rings;
if (netif_running(dev)) {
rc = bnxt_open_nic(bp, true, false);
if ((!rc) && BNXT_PF(bp)) {
/* TODO CHIMP_FW: Send message to all VF's
* to renable
*/
}
}
return rc;
}
#ifdef CONFIG_RFS_ACCEL
static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
int i, j = 0;
cmd->data = bp->ntp_fltr_count;
for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
struct hlist_head *head;
struct bnxt_ntuple_filter *fltr;
head = &bp->ntp_fltr_hash_tbl[i];
rcu_read_lock();
hlist_for_each_entry_rcu(fltr, head, hash) {
if (j == cmd->rule_cnt)
break;
rule_locs[j++] = fltr->sw_id;
}
rcu_read_unlock();
if (j == cmd->rule_cnt)
break;
}
cmd->rule_cnt = j;
return 0;
}
static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fs =
(struct ethtool_rx_flow_spec *)&cmd->fs;
struct bnxt_ntuple_filter *fltr;
struct flow_keys *fkeys;
int i, rc = -EINVAL;
if (fs->location < 0 || fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
return rc;
for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
struct hlist_head *head;
head = &bp->ntp_fltr_hash_tbl[i];
rcu_read_lock();
hlist_for_each_entry_rcu(fltr, head, hash) {
if (fltr->sw_id == fs->location)
goto fltr_found;
}
rcu_read_unlock();
}
return rc;
fltr_found:
fkeys = &fltr->fkeys;
if (fkeys->basic.ip_proto == IPPROTO_TCP)
fs->flow_type = TCP_V4_FLOW;
else if (fkeys->basic.ip_proto == IPPROTO_UDP)
fs->flow_type = UDP_V4_FLOW;
else
goto fltr_err;
fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0);
fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0);
fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0);
fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
fs->ring_cookie = fltr->rxq;
rc = 0;
fltr_err:
rcu_read_unlock();
return rc;
}
static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
struct bnxt *bp = netdev_priv(dev);
int rc = 0;
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
cmd->data = bp->rx_nr_rings;
break;
case ETHTOOL_GRXCLSRLCNT:
cmd->rule_cnt = bp->ntp_fltr_count;
cmd->data = BNXT_NTP_FLTR_MAX_FLTR;
break;
case ETHTOOL_GRXCLSRLALL:
rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs);
break;
case ETHTOOL_GRXCLSRULE:
rc = bnxt_grxclsrule(bp, cmd);
break;
default:
rc = -EOPNOTSUPP;
break;
}
return rc;
}
#endif
static u32 bnxt_get_rxfh_indir_size(struct net_device *dev)
{
return HW_HASH_INDEX_SIZE;
}
static u32 bnxt_get_rxfh_key_size(struct net_device *dev)
{
return HW_HASH_KEY_SIZE;
}
static int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
u8 *hfunc)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vnic_info *vnic = &bp->vnic_info[0];
int i = 0;
if (hfunc)
*hfunc = ETH_RSS_HASH_TOP;
if (indir)
for (i = 0; i < HW_HASH_INDEX_SIZE; i++)
indir[i] = le16_to_cpu(vnic->rss_table[i]);
if (key)
memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);
return 0;
}
static void bnxt_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct bnxt *bp = netdev_priv(dev);
strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
strlcpy(info->fw_version, bp->fw_ver_str, 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);
/* TODO CHIMP_FW: eeprom dump details */
info->eedump_len = 0;
/* TODO CHIMP FW: reg dump details */
info->regdump_len = 0;
}
static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)
{
u16 fw_speeds = link_info->support_speeds;
u32 speed_mask = 0;
if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
speed_mask |= SUPPORTED_100baseT_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
speed_mask |= SUPPORTED_1000baseT_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
speed_mask |= SUPPORTED_2500baseX_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
speed_mask |= SUPPORTED_10000baseT_Full;
/* TODO: support 25GB, 50GB with different cable type */
if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB)
speed_mask |= SUPPORTED_20000baseMLD2_Full |
SUPPORTED_20000baseKR2_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
speed_mask |= SUPPORTED_40000baseKR4_Full |
SUPPORTED_40000baseCR4_Full |
SUPPORTED_40000baseSR4_Full |
SUPPORTED_40000baseLR4_Full;
return speed_mask;
}
static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)
{
u16 fw_speeds = link_info->auto_link_speeds;
u32 speed_mask = 0;
/* TODO: support 25GB, 40GB, 50GB with different cable type */
/* set the advertised speeds */
if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
speed_mask |= ADVERTISED_100baseT_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
speed_mask |= ADVERTISED_1000baseT_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
speed_mask |= ADVERTISED_2500baseX_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
speed_mask |= ADVERTISED_10000baseT_Full;
/* TODO: how to advertise 20, 25, 40, 50GB with different cable type ?*/
if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB)
speed_mask |= ADVERTISED_20000baseMLD2_Full |
ADVERTISED_20000baseKR2_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
speed_mask |= ADVERTISED_40000baseKR4_Full |
ADVERTISED_40000baseCR4_Full |
ADVERTISED_40000baseSR4_Full |
ADVERTISED_40000baseLR4_Full;
return speed_mask;
}
u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
{
switch (fw_link_speed) {
case BNXT_LINK_SPEED_100MB:
return SPEED_100;
case BNXT_LINK_SPEED_1GB:
return SPEED_1000;
case BNXT_LINK_SPEED_2_5GB:
return SPEED_2500;
case BNXT_LINK_SPEED_10GB:
return SPEED_10000;
case BNXT_LINK_SPEED_20GB:
return SPEED_20000;
case BNXT_LINK_SPEED_25GB:
return SPEED_25000;
case BNXT_LINK_SPEED_40GB:
return SPEED_40000;
case BNXT_LINK_SPEED_50GB:
return SPEED_50000;
default:
return SPEED_UNKNOWN;
}
}
static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
u16 ethtool_speed;
cmd->supported = bnxt_fw_to_ethtool_support_spds(link_info);
if (link_info->auto_link_speeds)
cmd->supported |= SUPPORTED_Autoneg;
if (BNXT_AUTO_MODE(link_info->auto_mode)) {
cmd->advertising =
bnxt_fw_to_ethtool_advertised_spds(link_info);
cmd->advertising |= ADVERTISED_Autoneg;
cmd->autoneg = AUTONEG_ENABLE;
} else {
cmd->autoneg = AUTONEG_DISABLE;
cmd->advertising = 0;
}
if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) {
if ((link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) ==
BNXT_LINK_PAUSE_BOTH) {
cmd->advertising |= ADVERTISED_Pause;
cmd->supported |= SUPPORTED_Pause;
} else {
cmd->advertising |= ADVERTISED_Asym_Pause;
cmd->supported |= SUPPORTED_Asym_Pause;
if (link_info->auto_pause_setting &
BNXT_LINK_PAUSE_RX)
cmd->advertising |= ADVERTISED_Pause;
}
} else if (link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) {
if ((link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) ==
BNXT_LINK_PAUSE_BOTH) {
cmd->supported |= SUPPORTED_Pause;
} else {
cmd->supported |= SUPPORTED_Asym_Pause;
if (link_info->force_pause_setting &
BNXT_LINK_PAUSE_RX)
cmd->supported |= SUPPORTED_Pause;
}
}
cmd->port = PORT_NONE;
if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
cmd->port = PORT_TP;
cmd->supported |= SUPPORTED_TP;
cmd->advertising |= ADVERTISED_TP;
} else {
cmd->supported |= SUPPORTED_FIBRE;
cmd->advertising |= ADVERTISED_FIBRE;
if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC)
cmd->port = PORT_DA;
else if (link_info->media_type ==
PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE)
cmd->port = PORT_FIBRE;
}
if (link_info->phy_link_status == BNXT_LINK_LINK) {
if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
cmd->duplex = DUPLEX_FULL;
} else {
cmd->duplex = DUPLEX_UNKNOWN;
}
ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
ethtool_cmd_speed_set(cmd, ethtool_speed);
if (link_info->transceiver ==
PORT_PHY_QCFG_RESP_TRANSCEIVER_TYPE_XCVR_INTERNAL)
cmd->transceiver = XCVR_INTERNAL;
else
cmd->transceiver = XCVR_EXTERNAL;
cmd->phy_address = link_info->phy_addr;
return 0;
}
static u32 bnxt_get_fw_speed(struct net_device *dev, u16 ethtool_speed)
{
switch (ethtool_speed) {
case SPEED_100:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100MB;
case SPEED_1000:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_1GB;
case SPEED_2500:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_2_5GB;
case SPEED_10000:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10GB;
case SPEED_20000:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_20GB;
case SPEED_25000:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_25GB;
case SPEED_40000:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_40GB;
case SPEED_50000:
return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_50GB;
default:
netdev_err(dev, "unsupported speed!\n");
break;
}
return 0;
}
static u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
{
u16 fw_speed_mask = 0;
/* only support autoneg at speed 100, 1000, and 10000 */
if (advertising & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB;
}
if (advertising & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half)) {
fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB;
}
if (advertising & ADVERTISED_10000baseT_Full)
fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB;
return fw_speed_mask;
}
static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
int rc = 0;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
u32 speed, fw_advertising = 0;
bool set_pause = false;
if (BNXT_VF(bp))
return rc;
if (cmd->autoneg == AUTONEG_ENABLE) {
if (link_info->media_type != PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
netdev_err(dev, "Media type doesn't support autoneg\n");
rc = -EINVAL;
goto set_setting_exit;
}
if (cmd->advertising & ~(BNXT_ALL_COPPER_ETHTOOL_SPEED |
ADVERTISED_Autoneg |
ADVERTISED_TP |
ADVERTISED_Pause |
ADVERTISED_Asym_Pause)) {
netdev_err(dev, "Unsupported advertising mask (adv: 0x%x)\n",
cmd->advertising);
rc = -EINVAL;
goto set_setting_exit;
}
fw_advertising = bnxt_get_fw_auto_link_speeds(cmd->advertising);
if (fw_advertising & ~link_info->support_speeds) {
netdev_err(dev, "Advertising parameters are not supported! (adv: 0x%x)\n",
cmd->advertising);
rc = -EINVAL;
goto set_setting_exit;
}
link_info->autoneg |= BNXT_AUTONEG_SPEED;
if (!fw_advertising)
link_info->advertising = link_info->support_speeds;
else
link_info->advertising = fw_advertising;
/* any change to autoneg will cause link change, therefore the
* driver should put back the original pause setting in autoneg
*/
set_pause = true;
} else {
/* TODO: currently don't support half duplex */
if (cmd->duplex == DUPLEX_HALF) {
netdev_err(dev, "HALF DUPLEX is not supported!\n");
rc = -EINVAL;
goto set_setting_exit;
}
/* If received a request for an unknown duplex, assume full*/
if (cmd->duplex == DUPLEX_UNKNOWN)
cmd->duplex = DUPLEX_FULL;
speed = ethtool_cmd_speed(cmd);
link_info->req_link_speed = bnxt_get_fw_speed(dev, speed);
link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
link_info->autoneg &= ~BNXT_AUTONEG_SPEED;
link_info->advertising = 0;
}
if (netif_running(dev))
rc = bnxt_hwrm_set_link_setting(bp, set_pause);
set_setting_exit:
return rc;
}
static void bnxt_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
if (BNXT_VF(bp))
return;
epause->autoneg = !!(link_info->auto_pause_setting &
BNXT_LINK_PAUSE_BOTH);
epause->rx_pause = ((link_info->pause & BNXT_LINK_PAUSE_RX) != 0);
epause->tx_pause = ((link_info->pause & BNXT_LINK_PAUSE_TX) != 0);
}
static int bnxt_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
int rc = 0;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
if (BNXT_VF(bp))
return rc;
if (epause->autoneg) {
link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_BOTH;
} else {
/* when transition from auto pause to force pause,
* force a link change
*/
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
link_info->force_link_chng = true;
link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL;
link_info->req_flow_ctrl &= ~BNXT_LINK_PAUSE_BOTH;
}
if (epause->rx_pause)
link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX;
else
link_info->req_flow_ctrl &= ~BNXT_LINK_PAUSE_RX;
if (epause->tx_pause)
link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX;
else
link_info->req_flow_ctrl &= ~BNXT_LINK_PAUSE_TX;
if (netif_running(dev))
rc = bnxt_hwrm_set_pause(bp);
return rc;
}
static u32 bnxt_get_link(struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
/* TODO: handle MF, VF, driver close case */
return bp->link_info.link_up;
}
static int bnxt_flash_nvram(struct net_device *dev,
u16 dir_type,
u16 dir_ordinal,
u16 dir_ext,
u16 dir_attr,
const u8 *data,
size_t data_len)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
struct hwrm_nvm_write_input req = {0};
dma_addr_t dma_handle;
u8 *kmem;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_WRITE, -1, -1);
req.dir_type = cpu_to_le16(dir_type);
req.dir_ordinal = cpu_to_le16(dir_ordinal);
req.dir_ext = cpu_to_le16(dir_ext);
req.dir_attr = cpu_to_le16(dir_attr);
req.dir_data_length = cpu_to_le32(data_len);
kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle,
GFP_KERNEL);
if (!kmem) {
netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
(unsigned)data_len);
return -ENOMEM;
}
memcpy(kmem, data, data_len);
req.host_src_addr = cpu_to_le64(dma_handle);
rc = hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT);
dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle);
return rc;
}
static int bnxt_flash_firmware(struct net_device *dev,
u16 dir_type,
const u8 *fw_data,
size_t fw_size)
{
int rc = 0;
u16 code_type;
u32 stored_crc;
u32 calculated_crc;
struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data;
switch (dir_type) {
case BNX_DIR_TYPE_BOOTCODE:
case BNX_DIR_TYPE_BOOTCODE_2:
code_type = CODE_BOOT;
break;
default:
netdev_err(dev, "Unsupported directory entry type: %u\n",
dir_type);
return -EINVAL;
}
if (fw_size < sizeof(struct bnxt_fw_header)) {
netdev_err(dev, "Invalid firmware file size: %u\n",
(unsigned int)fw_size);
return -EINVAL;
}
if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) {
netdev_err(dev, "Invalid firmware signature: %08X\n",
le32_to_cpu(header->signature));
return -EINVAL;
}
if (header->code_type != code_type) {
netdev_err(dev, "Expected firmware type: %d, read: %d\n",
code_type, header->code_type);
return -EINVAL;
}
if (header->device != DEVICE_CUMULUS_FAMILY) {
netdev_err(dev, "Expected firmware device family %d, read: %d\n",
DEVICE_CUMULUS_FAMILY, header->device);
return -EINVAL;
}
/* Confirm the CRC32 checksum of the file: */
stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size -
sizeof(stored_crc)));
calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc));
if (calculated_crc != stored_crc) {
netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n",
(unsigned long)stored_crc,
(unsigned long)calculated_crc);
return -EINVAL;
}
/* TODO: Validate digital signature (RSA-encrypted SHA-256 hash) here */
rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
0, 0, fw_data, fw_size);
if (rc == 0) { /* Firmware update successful */
/* TODO: Notify processor it needs to reset itself
*/
}
return rc;
}
static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type)
{
switch (dir_type) {
case BNX_DIR_TYPE_CHIMP_PATCH:
case BNX_DIR_TYPE_BOOTCODE:
case BNX_DIR_TYPE_BOOTCODE_2:
case BNX_DIR_TYPE_APE_FW:
case BNX_DIR_TYPE_APE_PATCH:
case BNX_DIR_TYPE_KONG_FW:
case BNX_DIR_TYPE_KONG_PATCH:
return true;
}
return false;
}
static bool bnxt_dir_type_is_unprotected_exec_format(u16 dir_type)
{
switch (dir_type) {
case BNX_DIR_TYPE_AVS:
case BNX_DIR_TYPE_EXP_ROM_MBA:
case BNX_DIR_TYPE_PCIE:
case BNX_DIR_TYPE_TSCF_UCODE:
case BNX_DIR_TYPE_EXT_PHY:
case BNX_DIR_TYPE_CCM:
case BNX_DIR_TYPE_ISCSI_BOOT:
case BNX_DIR_TYPE_ISCSI_BOOT_IPV6:
case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6:
return true;
}
return false;
}
static bool bnxt_dir_type_is_executable(u16 dir_type)
{
return bnxt_dir_type_is_ape_bin_format(dir_type) ||
bnxt_dir_type_is_unprotected_exec_format(dir_type);
}
static int bnxt_flash_firmware_from_file(struct net_device *dev,
u16 dir_type,
const char *filename)
{
const struct firmware *fw;
int rc;
if (bnxt_dir_type_is_executable(dir_type) == false)
return -EINVAL;
rc = request_firmware(&fw, filename, &dev->dev);
if (rc != 0) {
netdev_err(dev, "Error %d requesting firmware file: %s\n",
rc, filename);
return rc;
}
if (bnxt_dir_type_is_ape_bin_format(dir_type) == true)
rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size);
else
rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
0, 0, fw->data, fw->size);
release_firmware(fw);
return rc;
}
static int bnxt_flash_package_from_file(struct net_device *dev,
char *filename)
{
netdev_err(dev, "packages are not yet supported\n");
return -EINVAL;
}
static int bnxt_flash_device(struct net_device *dev,
struct ethtool_flash *flash)
{
if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) {
netdev_err(dev, "flashdev not supported from a virtual function\n");
return -EINVAL;
}
if (flash->region == ETHTOOL_FLASH_ALL_REGIONS)
return bnxt_flash_package_from_file(dev, flash->data);
return bnxt_flash_firmware_from_file(dev, flash->region, flash->data);
}
static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
struct hwrm_nvm_get_dir_info_input req = {0};
struct hwrm_nvm_get_dir_info_output *output = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_INFO, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
*entries = le32_to_cpu(output->entries);
*length = le32_to_cpu(output->entry_length);
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_get_eeprom_len(struct net_device *dev)
{
/* The -1 return value allows the entire 32-bit range of offsets to be
* passed via the ethtool command-line utility.
*/
return -1;
}
static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
u32 dir_entries;
u32 entry_length;
u8 *buf;
size_t buflen;
dma_addr_t dma_handle;
struct hwrm_nvm_get_dir_entries_input req = {0};
rc = nvm_get_dir_info(dev, &dir_entries, &entry_length);
if (rc != 0)
return rc;
/* Insert 2 bytes of directory info (count and size of entries) */
if (len < 2)
return -EINVAL;
*data++ = dir_entries;
*data++ = entry_length;
len -= 2;
memset(data, 0xff, len);
buflen = dir_entries * entry_length;
buf = dma_alloc_coherent(&bp->pdev->dev, buflen, &dma_handle,
GFP_KERNEL);
if (!buf) {
netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
(unsigned)buflen);
return -ENOMEM;
}
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_ENTRIES, -1, -1);
req.host_dest_addr = cpu_to_le64(dma_handle);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc == 0)
memcpy(data, buf, len > buflen ? buflen : len);
dma_free_coherent(&bp->pdev->dev, buflen, buf, dma_handle);
return rc;
}
static int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset,
u32 length, u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
u8 *buf;
dma_addr_t dma_handle;
struct hwrm_nvm_read_input req = {0};
buf = dma_alloc_coherent(&bp->pdev->dev, length, &dma_handle,
GFP_KERNEL);
if (!buf) {
netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
(unsigned)length);
return -ENOMEM;
}
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_READ, -1, -1);
req.host_dest_addr = cpu_to_le64(dma_handle);
req.dir_idx = cpu_to_le16(index);
req.offset = cpu_to_le32(offset);
req.len = cpu_to_le32(length);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc == 0)
memcpy(data, buf, length);
dma_free_coherent(&bp->pdev->dev, length, buf, dma_handle);
return rc;
}
static int bnxt_get_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom,
u8 *data)
{
u32 index;
u32 offset;
if (eeprom->offset == 0) /* special offset value to get directory */
return bnxt_get_nvram_directory(dev, eeprom->len, data);
index = eeprom->offset >> 24;
offset = eeprom->offset & 0xffffff;
if (index == 0) {
netdev_err(dev, "unsupported index value: %d\n", index);
return -EINVAL;
}
return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len, data);
}
static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index)
{
struct bnxt *bp = netdev_priv(dev);
struct hwrm_nvm_erase_dir_entry_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_ERASE_DIR_ENTRY, -1, -1);
req.dir_idx = cpu_to_le16(index);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_set_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom,
u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
u8 index, dir_op;
u16 type, ext, ordinal, attr;
if (!BNXT_PF(bp)) {
netdev_err(dev, "NVM write not supported from a virtual function\n");
return -EINVAL;
}
type = eeprom->magic >> 16;
if (type == 0xffff) { /* special value for directory operations */
index = eeprom->magic & 0xff;
dir_op = eeprom->magic >> 8;
if (index == 0)
return -EINVAL;
switch (dir_op) {
case 0x0e: /* erase */
if (eeprom->offset != ~eeprom->magic)
return -EINVAL;
return bnxt_erase_nvram_directory(dev, index - 1);
default:
return -EINVAL;
}
}
/* Create or re-write an NVM item: */
if (bnxt_dir_type_is_executable(type) == true)
return -EINVAL;
ext = eeprom->magic & 0xffff;
ordinal = eeprom->offset >> 16;
attr = eeprom->offset & 0xffff;
return bnxt_flash_nvram(dev, type, ordinal, ext, attr, data,
eeprom->len);
}
const struct ethtool_ops bnxt_ethtool_ops = {
.get_settings = bnxt_get_settings,
.set_settings = bnxt_set_settings,
.get_pauseparam = bnxt_get_pauseparam,
.set_pauseparam = bnxt_set_pauseparam,
.get_drvinfo = bnxt_get_drvinfo,
.get_coalesce = bnxt_get_coalesce,
.set_coalesce = bnxt_set_coalesce,
.get_msglevel = bnxt_get_msglevel,
.set_msglevel = bnxt_set_msglevel,
.get_sset_count = bnxt_get_sset_count,
.get_strings = bnxt_get_strings,
.get_ethtool_stats = bnxt_get_ethtool_stats,
.set_ringparam = bnxt_set_ringparam,
.get_ringparam = bnxt_get_ringparam,
.get_channels = bnxt_get_channels,
.set_channels = bnxt_set_channels,
#ifdef CONFIG_RFS_ACCEL
.get_rxnfc = bnxt_get_rxnfc,
#endif
.get_rxfh_indir_size = bnxt_get_rxfh_indir_size,
.get_rxfh_key_size = bnxt_get_rxfh_key_size,
.get_rxfh = bnxt_get_rxfh,
.flash_device = bnxt_flash_device,
.get_eeprom_len = bnxt_get_eeprom_len,
.get_eeprom = bnxt_get_eeprom,
.set_eeprom = bnxt_set_eeprom,
.get_link = bnxt_get_link,
};
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2015 Broadcom Corporation
*
* 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
* the Free Software Foundation.
*/
#ifndef BNXT_ETHTOOL_H
#define BNXT_ETHTOOL_H
extern const struct ethtool_ops bnxt_ethtool_ops;
u32 bnxt_fw_to_ethtool_speed(u16);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2015 Broadcom Corporation
*
* 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
* the Free Software Foundation.
*/
#ifndef __BNXT_FW_HDR_H__
#define __BNXT_FW_HDR_H__
#define BNXT_FIRMWARE_BIN_SIGNATURE 0x1a4d4342 /* "BCM"+0x1a */
enum SUPPORTED_FAMILY {
DEVICE_5702_3_4_FAMILY, /* 0 - Denali, Vinson, K2 */
DEVICE_5705_FAMILY, /* 1 - Bachelor */
DEVICE_SHASTA_FAMILY, /* 2 - 5751 */
DEVICE_5706_FAMILY, /* 3 - Teton */
DEVICE_5714_FAMILY, /* 4 - Hamilton */
DEVICE_STANFORD_FAMILY, /* 5 - 5755 */
DEVICE_STANFORD_ME_FAMILY, /* 6 - 5756 */
DEVICE_SOLEDAD_FAMILY, /* 7 - 5761[E] */
DEVICE_CILAI_FAMILY, /* 8 - 57780/60/90/91 */
DEVICE_ASPEN_FAMILY, /* 9 - 57781/85/61/65/91/95 */
DEVICE_ASPEN_PLUS_FAMILY, /* 10 - 57786 */
DEVICE_LOGAN_FAMILY, /* 11 - Any device in the Logan family
*/
DEVICE_LOGAN_5762, /* 12 - Logan Enterprise (aka Columbia)
*/
DEVICE_LOGAN_57767, /* 13 - Logan Client */
DEVICE_LOGAN_57787, /* 14 - Logan Consumer */
DEVICE_LOGAN_5725, /* 15 - Logan Server (TruManage-enabled)
*/
DEVICE_SAWTOOTH_FAMILY, /* 16 - 5717/18 */
DEVICE_COTOPAXI_FAMILY, /* 17 - 5719 */
DEVICE_SNAGGLETOOTH_FAMILY, /* 18 - 5720 */
DEVICE_CUMULUS_FAMILY, /* 19 - Cumulus/Whitney */
MAX_DEVICE_FAMILY
};
enum SUPPORTED_CODE {
CODE_ASF1, /* 0 - ASF VERSION 1.03 <deprecated> */
CODE_ASF2, /* 1 - ASF VERSION 2.00 <deprecated> */
CODE_PASSTHRU, /* 2 - PassThru <deprecated> */
CODE_PT_SEC, /* 3 - PassThru with security <deprecated> */
CODE_UMP, /* 4 - UMP <deprecated> */
CODE_BOOT, /* 5 - Bootcode */
CODE_DASH, /* 6 - TruManage (DASH + ASF + PMCI)
* Management firmwares
*/
CODE_MCTP_PASSTHRU, /* 7 - NCSI / MCTP Passt-hrough firmware */
CODE_PM_OFFLOAD, /* 8 - Power-Management Proxy Offload firmwares
*/
CODE_MDNS_SD_OFFLOAD, /* 9 - Multicast DNS Service Discovery Proxys
* Offload firmware
*/
CODE_DISC_OFFLOAD, /* 10 - Discovery Offload firmware */
CODE_MUSTANG, /* 11 - I2C Error reporting APE firmwares
* <deprecated>
*/
CODE_ARP_BATCH, /* 12 - ARP Batch firmware */
CODE_SMASH, /* 13 - TruManage (SMASH + DCMI/IPMI + PMCI)
* Management firmware
*/
CODE_APE_DIAG, /* 14 - APE Test Diag firmware */
CODE_APE_PATCH, /* 15 - APE Patch firmware */
CODE_TANG_PATCH, /* 16 - TANG Patch firmware */
CODE_KONG_FW, /* 17 - KONG firmware */
CODE_KONG_PATCH, /* 18 - KONG Patch firmware */
CODE_BONO_FW, /* 19 - BONO firmware */
CODE_BONO_PATCH, /* 20 - BONO Patch firmware */
MAX_CODE_TYPE,
};
enum SUPPORTED_MEDIA {
MEDIA_COPPER, /* 0 */
MEDIA_FIBER, /* 1 */
MEDIA_NONE, /* 2 */
MEDIA_COPPER_FIBER, /* 3 */
MAX_MEDIA_TYPE,
};
struct bnxt_fw_header {
__le32 signature; /* constains the constant value of
* BNXT_Firmware_Bin_Signatures
*/
u8 flags; /* reserved for ChiMP use */
u8 code_type; /* enum SUPPORTED_CODE */
u8 device; /* enum SUPPORTED_FAMILY */
u8 media; /* enum SUPPORTED_MEDIA */
u8 version[16]; /* the null terminated version string to
* indicate the version of the
* file, this will be copied from the binary
* file version string
*/
u8 build;
u8 revision;
u8 minor_ver;
u8 major_ver;
};
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2015 Broadcom Corporation
*
* 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
* the Free Software Foundation.
*/
#ifndef _BNXT_NVM_DEFS_H_
#define _BNXT_NVM_DEFS_H_
enum bnxt_nvm_directory_type {
BNX_DIR_TYPE_UNUSED = 0,
BNX_DIR_TYPE_PKG_LOG = 1,
BNX_DIR_TYPE_CHIMP_PATCH = 3,
BNX_DIR_TYPE_BOOTCODE = 4,
BNX_DIR_TYPE_VPD = 5,
BNX_DIR_TYPE_EXP_ROM_MBA = 6,
BNX_DIR_TYPE_AVS = 7,
BNX_DIR_TYPE_PCIE = 8,
BNX_DIR_TYPE_PORT_MACRO = 9,
BNX_DIR_TYPE_APE_FW = 10,
BNX_DIR_TYPE_APE_PATCH = 11,
BNX_DIR_TYPE_KONG_FW = 12,
BNX_DIR_TYPE_KONG_PATCH = 13,
BNX_DIR_TYPE_BONO_FW = 14,
BNX_DIR_TYPE_BONO_PATCH = 15,
BNX_DIR_TYPE_TANG_FW = 16,
BNX_DIR_TYPE_TANG_PATCH = 17,
BNX_DIR_TYPE_BOOTCODE_2 = 18,
BNX_DIR_TYPE_CCM = 19,
BNX_DIR_TYPE_PCI_CFG = 20,
BNX_DIR_TYPE_TSCF_UCODE = 21,
BNX_DIR_TYPE_ISCSI_BOOT = 22,
BNX_DIR_TYPE_ISCSI_BOOT_IPV6 = 24,
BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6 = 25,
BNX_DIR_TYPE_ISCSI_BOOT_CFG6 = 26,
BNX_DIR_TYPE_EXT_PHY = 27,
BNX_DIR_TYPE_SHARED_CFG = 40,
BNX_DIR_TYPE_PORT_CFG = 41,
BNX_DIR_TYPE_FUNC_CFG = 42,
BNX_DIR_TYPE_MGMT_CFG = 48,
BNX_DIR_TYPE_MGMT_DATA = 49,
BNX_DIR_TYPE_MGMT_WEB_DATA = 50,
BNX_DIR_TYPE_MGMT_WEB_META = 51,
BNX_DIR_TYPE_MGMT_EVENT_LOG = 52,
BNX_DIR_TYPE_MGMT_AUDIT_LOG = 53
};
#define BNX_DIR_ORDINAL_FIRST 0
#define BNX_DIR_EXT_INACTIVE (1 << 0)
#define BNX_DIR_EXT_UPDATE (1 << 1)
#define BNX_DIR_ATTR_NO_CHKSUM (1 << 0)
#define BNX_DIR_ATTR_PROP_STREAM (1 << 1)
#endif /* Don't add anything after this line */
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2015 Broadcom Corporation
*
* 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
* the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/etherdevice.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_sriov.h"
#include "bnxt_ethtool.h"
#ifdef CONFIG_BNXT_SRIOV
static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id)
{
if (bp->state != BNXT_STATE_OPEN) {
netdev_err(bp->dev, "vf ndo called though PF is down\n");
return -EINVAL;
}
if (!bp->pf.active_vfs) {
netdev_err(bp->dev, "vf ndo called though sriov is disabled\n");
return -EINVAL;
}
if (vf_id >= bp->pf.max_vfs) {
netdev_err(bp->dev, "Invalid VF id %d\n", vf_id);
return -EINVAL;
}
return 0;
}
int bnxt_set_vf_spoofchk(struct net_device *dev, int vf_id, bool setting)
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
bool old_setting = false;
u32 func_flags;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
vf = &bp->pf.vf[vf_id];
if (vf->flags & BNXT_VF_SPOOFCHK)
old_setting = true;
if (old_setting == setting)
return 0;
func_flags = vf->func_flags;
if (setting)
func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK;
else
func_flags &= ~FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK;
/*TODO: if the driver supports VLAN filter on guest VLAN,
* the spoof check should also include vlan anti-spoofing
*/
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.vf_id = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(func_flags);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
vf->func_flags = func_flags;
if (setting)
vf->flags |= BNXT_VF_SPOOFCHK;
else
vf->flags &= ~BNXT_VF_SPOOFCHK;
}
return rc;
}
int bnxt_get_vf_config(struct net_device *dev, int vf_id,
struct ifla_vf_info *ivi)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
ivi->vf = vf_id;
vf = &bp->pf.vf[vf_id];
memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN);
ivi->max_tx_rate = vf->max_tx_rate;
ivi->min_tx_rate = vf->min_tx_rate;
ivi->vlan = vf->vlan;
ivi->qos = vf->flags & BNXT_VF_QOS;
ivi->spoofchk = vf->flags & BNXT_VF_SPOOFCHK;
if (!(vf->flags & BNXT_VF_LINK_FORCED))
ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
else if (vf->flags & BNXT_VF_LINK_UP)
ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
else
ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
return 0;
}
int bnxt_set_vf_mac(struct net_device *dev, int vf_id, u8 *mac)
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
/* reject bc or mc mac addr, zero mac addr means allow
* VF to use its own mac addr
*/
if (is_multicast_ether_addr(mac)) {
netdev_err(dev, "Invalid VF ethernet address\n");
return -EINVAL;
}
vf = &bp->pf.vf[vf_id];
memcpy(vf->mac_addr, mac, ETH_ALEN);
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.vf_id = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(vf->func_flags);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR);
memcpy(req.dflt_mac_addr, mac, ETH_ALEN);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
int bnxt_set_vf_vlan(struct net_device *dev, int vf_id, u16 vlan_id, u8 qos)
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
u16 vlan_tag;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
/* TODO: needed to implement proper handling of user priority,
* currently fail the command if there is valid priority
*/
if (vlan_id > 4095 || qos)
return -EINVAL;
vf = &bp->pf.vf[vf_id];
vlan_tag = vlan_id;
if (vlan_tag == vf->vlan)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.vf_id = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(vf->func_flags);
req.dflt_vlan = cpu_to_le16(vlan_tag);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc)
vf->vlan = vlan_tag;
return rc;
}
int bnxt_set_vf_bw(struct net_device *dev, int vf_id, int min_tx_rate,
int max_tx_rate)
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
u32 pf_link_speed;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
vf = &bp->pf.vf[vf_id];
pf_link_speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed);
if (max_tx_rate > pf_link_speed) {
netdev_info(bp->dev, "max tx rate %d exceed PF link speed for VF %d\n",
max_tx_rate, vf_id);
return -EINVAL;
}
if (min_tx_rate > pf_link_speed || min_tx_rate > max_tx_rate) {
netdev_info(bp->dev, "min tx rate %d is invalid for VF %d\n",
min_tx_rate, vf_id);
return -EINVAL;
}
if (min_tx_rate == vf->min_tx_rate && max_tx_rate == vf->max_tx_rate)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.vf_id = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(vf->func_flags);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW);
req.max_bw = cpu_to_le32(max_tx_rate);
req.enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_MIN_BW);
req.min_bw = cpu_to_le32(min_tx_rate);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
vf->min_tx_rate = min_tx_rate;
vf->max_tx_rate = max_tx_rate;
}
return rc;
}
int bnxt_set_vf_link_state(struct net_device *dev, int vf_id, int link)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
vf = &bp->pf.vf[vf_id];
vf->flags &= ~(BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED);
switch (link) {
case IFLA_VF_LINK_STATE_AUTO:
vf->flags |= BNXT_VF_LINK_UP;
break;
case IFLA_VF_LINK_STATE_DISABLE:
vf->flags |= BNXT_VF_LINK_FORCED;
break;
case IFLA_VF_LINK_STATE_ENABLE:
vf->flags |= BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED;
break;
default:
netdev_err(bp->dev, "Invalid link option\n");
rc = -EINVAL;
break;
}
/* CHIMP TODO: send msg to VF to update new link state */
return rc;
}
static int bnxt_set_vf_attr(struct bnxt *bp, int num_vfs)
{
int i;
struct bnxt_vf_info *vf;
for (i = 0; i < num_vfs; i++) {
vf = &bp->pf.vf[i];
memset(vf, 0, sizeof(*vf));
vf->flags = BNXT_VF_QOS | BNXT_VF_LINK_UP;
}
return 0;
}
static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp)
{
int i, rc = 0;
struct bnxt_pf_info *pf = &bp->pf;
struct hwrm_func_vf_resc_free_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESC_FREE, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
for (i = pf->first_vf_id; i < pf->first_vf_id + pf->active_vfs; i++) {
req.vf_id = cpu_to_le16(i);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
if (rc)
break;
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static void bnxt_free_vf_resources(struct bnxt *bp)
{
struct pci_dev *pdev = bp->pdev;
int i;
kfree(bp->pf.vf_event_bmap);
bp->pf.vf_event_bmap = NULL;
for (i = 0; i < 4; i++) {
if (bp->pf.hwrm_cmd_req_addr[i]) {
dma_free_coherent(&pdev->dev, BNXT_PAGE_SIZE,
bp->pf.hwrm_cmd_req_addr[i],
bp->pf.hwrm_cmd_req_dma_addr[i]);
bp->pf.hwrm_cmd_req_addr[i] = NULL;
}
}
kfree(bp->pf.vf);
bp->pf.vf = NULL;
}
static int bnxt_alloc_vf_resources(struct bnxt *bp, int num_vfs)
{
struct pci_dev *pdev = bp->pdev;
u32 nr_pages, size, i, j, k = 0;
bp->pf.vf = kcalloc(num_vfs, sizeof(struct bnxt_vf_info), GFP_KERNEL);
if (!bp->pf.vf)
return -ENOMEM;
bnxt_set_vf_attr(bp, num_vfs);
size = num_vfs * BNXT_HWRM_REQ_MAX_SIZE;
nr_pages = size / BNXT_PAGE_SIZE;
if (size & (BNXT_PAGE_SIZE - 1))
nr_pages++;
for (i = 0; i < nr_pages; i++) {
bp->pf.hwrm_cmd_req_addr[i] =
dma_alloc_coherent(&pdev->dev, BNXT_PAGE_SIZE,
&bp->pf.hwrm_cmd_req_dma_addr[i],
GFP_KERNEL);
if (!bp->pf.hwrm_cmd_req_addr[i])
return -ENOMEM;
for (j = 0; j < BNXT_HWRM_REQS_PER_PAGE && k < num_vfs; j++) {
struct bnxt_vf_info *vf = &bp->pf.vf[k];
vf->hwrm_cmd_req_addr = bp->pf.hwrm_cmd_req_addr[i] +
j * BNXT_HWRM_REQ_MAX_SIZE;
vf->hwrm_cmd_req_dma_addr =
bp->pf.hwrm_cmd_req_dma_addr[i] + j *
BNXT_HWRM_REQ_MAX_SIZE;
k++;
}
}
/* Max 128 VF's */
bp->pf.vf_event_bmap = kzalloc(16, GFP_KERNEL);
if (!bp->pf.vf_event_bmap)
return -ENOMEM;
bp->pf.hwrm_cmd_req_pages = nr_pages;
return 0;
}
static int bnxt_hwrm_func_buf_rgtr(struct bnxt *bp)
{
struct hwrm_func_buf_rgtr_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_BUF_RGTR, -1, -1);
req.req_buf_num_pages = cpu_to_le16(bp->pf.hwrm_cmd_req_pages);
req.req_buf_page_size = cpu_to_le16(BNXT_PAGE_SHIFT);
req.req_buf_len = cpu_to_le16(BNXT_HWRM_REQ_MAX_SIZE);
req.req_buf_page_addr0 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[0]);
req.req_buf_page_addr1 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[1]);
req.req_buf_page_addr2 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[2]);
req.req_buf_page_addr3 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[3]);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
/* only call by PF to reserve resources for VF */
static int bnxt_hwrm_func_cfg(struct bnxt *bp, int *num_vfs)
{
u32 rc = 0, mtu, i;
u16 vf_tx_rings, vf_rx_rings, vf_cp_rings, vf_stat_ctx, vf_vnics;
struct hwrm_func_cfg_input req = {0};
struct bnxt_pf_info *pf = &bp->pf;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
/* Remaining rings are distributed equally amongs VF's for now */
/* TODO: the following workaroud is needed to restrict total number
* of vf_cp_rings not exceed number of HW ring groups. This WA should
* be removed once new HWRM provides HW ring groups capability in
* hwrm_func_qcap.
*/
vf_cp_rings = min_t(u16, bp->pf.max_cp_rings, bp->pf.max_stat_ctxs);
vf_cp_rings = (vf_cp_rings - bp->cp_nr_rings) / *num_vfs;
/* TODO: restore this logic below once the WA above is removed */
/* vf_cp_rings = (bp->pf.max_cp_rings - bp->cp_nr_rings) / *num_vfs; */
vf_stat_ctx = (bp->pf.max_stat_ctxs - bp->num_stat_ctxs) / *num_vfs;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
vf_rx_rings = (bp->pf.max_rx_rings - bp->rx_nr_rings * 2) /
*num_vfs;
else
vf_rx_rings = (bp->pf.max_rx_rings - bp->rx_nr_rings) /
*num_vfs;
vf_tx_rings = (bp->pf.max_tx_rings - bp->tx_nr_rings) / *num_vfs;
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MTU |
FUNC_CFG_REQ_ENABLES_MRU |
FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_L2_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_VNICS);
mtu = bp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
req.mru = cpu_to_le16(mtu);
req.mtu = cpu_to_le16(mtu);
req.num_rsscos_ctxs = cpu_to_le16(1);
req.num_cmpl_rings = cpu_to_le16(vf_cp_rings);
req.num_tx_rings = cpu_to_le16(vf_tx_rings);
req.num_rx_rings = cpu_to_le16(vf_rx_rings);
req.num_l2_ctxs = cpu_to_le16(4);
vf_vnics = 1;
req.num_vnics = cpu_to_le16(vf_vnics);
/* FIXME spec currently uses 1 bit for stats ctx */
req.num_stat_ctxs = cpu_to_le16(vf_stat_ctx);
mutex_lock(&bp->hwrm_cmd_lock);
for (i = 0; i < *num_vfs; i++) {
req.vf_id = cpu_to_le16(pf->first_vf_id + i);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
if (rc)
break;
bp->pf.active_vfs = i + 1;
bp->pf.vf[i].fw_fid = le16_to_cpu(req.vf_id);
}
mutex_unlock(&bp->hwrm_cmd_lock);
if (!rc) {
bp->pf.max_pf_tx_rings = bp->tx_nr_rings;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
bp->pf.max_pf_rx_rings = bp->rx_nr_rings * 2;
else
bp->pf.max_pf_rx_rings = bp->rx_nr_rings;
}
return rc;
}
static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
{
int rc = 0, vfs_supported;
int min_rx_rings, min_tx_rings, min_rss_ctxs;
int tx_ok = 0, rx_ok = 0, rss_ok = 0;
/* Check if we can enable requested num of vf's. At a mininum
* we require 1 RX 1 TX rings for each VF. In this minimum conf
* features like TPA will not be available.
*/
vfs_supported = *num_vfs;
while (vfs_supported) {
min_rx_rings = vfs_supported;
min_tx_rings = vfs_supported;
min_rss_ctxs = vfs_supported;
if (bp->flags & BNXT_FLAG_AGG_RINGS) {
if (bp->pf.max_rx_rings - bp->rx_nr_rings * 2 >=
min_rx_rings)
rx_ok = 1;
} else {
if (bp->pf.max_rx_rings - bp->rx_nr_rings >=
min_rx_rings)
rx_ok = 1;
}
if (bp->pf.max_tx_rings - bp->tx_nr_rings >= min_tx_rings)
tx_ok = 1;
if (bp->pf.max_rsscos_ctxs - bp->rsscos_nr_ctxs >= min_rss_ctxs)
rss_ok = 1;
if (tx_ok && rx_ok && rss_ok)
break;
vfs_supported--;
}
if (!vfs_supported) {
netdev_err(bp->dev, "Cannot enable VF's as all resources are used by PF\n");
return -EINVAL;
}
if (vfs_supported != *num_vfs) {
netdev_info(bp->dev, "Requested VFs %d, can enable %d\n",
*num_vfs, vfs_supported);
*num_vfs = vfs_supported;
}
rc = bnxt_alloc_vf_resources(bp, *num_vfs);
if (rc)
goto err_out1;
/* Reserve resources for VFs */
rc = bnxt_hwrm_func_cfg(bp, num_vfs);
if (rc)
goto err_out2;
/* Register buffers for VFs */
rc = bnxt_hwrm_func_buf_rgtr(bp);
if (rc)
goto err_out2;
rc = pci_enable_sriov(bp->pdev, *num_vfs);
if (rc)
goto err_out2;
return 0;
err_out2:
/* Free the resources reserved for various VF's */
bnxt_hwrm_func_vf_resource_free(bp);
err_out1:
bnxt_free_vf_resources(bp);
return rc;
}
void bnxt_sriov_disable(struct bnxt *bp)
{
if (!bp->pf.active_vfs)
return;
pci_disable_sriov(bp->pdev);
/* Free the resources reserved for various VF's */
bnxt_hwrm_func_vf_resource_free(bp);
bnxt_free_vf_resources(bp);
bp->pf.active_vfs = 0;
bp->pf.max_pf_rx_rings = bp->pf.max_rx_rings;
bp->pf.max_pf_tx_rings = bp->pf.max_tx_rings;
}
int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct bnxt *bp = netdev_priv(dev);
if (!(bp->flags & BNXT_FLAG_USING_MSIX)) {
netdev_warn(dev, "Not allow SRIOV if the irq mode is not MSIX\n");
return 0;
}
rtnl_lock();
if (!netif_running(dev)) {
netdev_warn(dev, "Reject SRIOV config request since if is down!\n");
rtnl_unlock();
return 0;
}
bp->sriov_cfg = true;
rtnl_unlock();
if (!num_vfs) {
bnxt_sriov_disable(bp);
return 0;
}
/* Check if enabled VFs is same as requested */
if (num_vfs == bp->pf.active_vfs)
return 0;
bnxt_sriov_enable(bp, &num_vfs);
bp->sriov_cfg = false;
wake_up(&bp->sriov_cfg_wait);
return num_vfs;
}
static int bnxt_hwrm_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf,
void *encap_resp, __le64 encap_resp_addr,
__le16 encap_resp_cpr, u32 msg_size)
{
int rc = 0;
struct hwrm_fwd_resp_input req = {0};
struct hwrm_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FWD_RESP, -1, -1);
/* Set the new target id */
req.target_id = cpu_to_le16(vf->fw_fid);
req.encap_resp_len = cpu_to_le16(msg_size);
req.encap_resp_addr = encap_resp_addr;
req.encap_resp_cmpl_ring = encap_resp_cpr;
memcpy(req.encap_resp, encap_resp, msg_size);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
netdev_err(bp->dev, "hwrm_fwd_resp failed. rc:%d\n", rc);
goto fwd_resp_exit;
}
if (resp->error_code) {
netdev_err(bp->dev, "hwrm_fwd_resp error %d\n",
resp->error_code);
rc = -1;
}
fwd_resp_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_hwrm_fwd_err_resp(struct bnxt *bp, struct bnxt_vf_info *vf,
u32 msg_size)
{
int rc = 0;
struct hwrm_reject_fwd_resp_input req = {0};
struct hwrm_reject_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_REJECT_FWD_RESP, -1, -1);
/* Set the new target id */
req.target_id = cpu_to_le16(vf->fw_fid);
memcpy(req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
netdev_err(bp->dev, "hwrm_fwd_err_resp failed. rc:%d\n", rc);
goto fwd_err_resp_exit;
}
if (resp->error_code) {
netdev_err(bp->dev, "hwrm_fwd_err_resp error %d\n",
resp->error_code);
rc = -1;
}
fwd_err_resp_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_hwrm_exec_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf,
u32 msg_size)
{
int rc = 0;
struct hwrm_exec_fwd_resp_input req = {0};
struct hwrm_exec_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_EXEC_FWD_RESP, -1, -1);
/* Set the new target id */
req.target_id = cpu_to_le16(vf->fw_fid);
memcpy(req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
netdev_err(bp->dev, "hwrm_exec_fw_resp failed. rc:%d\n", rc);
goto exec_fwd_resp_exit;
}
if (resp->error_code) {
netdev_err(bp->dev, "hwrm_exec_fw_resp error %d\n",
resp->error_code);
rc = -1;
}
exec_fwd_resp_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_vf_validate_set_mac(struct bnxt *bp, struct bnxt_vf_info *vf)
{
u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input);
struct hwrm_cfa_l2_filter_alloc_input *req =
(struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr;
if (!is_valid_ether_addr(vf->mac_addr) ||
ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr))
return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size);
else
return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size);
}
static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
{
int rc = 0;
if (!(vf->flags & BNXT_VF_LINK_FORCED)) {
/* real link */
rc = bnxt_hwrm_exec_fwd_resp(
bp, vf, sizeof(struct hwrm_port_phy_qcfg_input));
} else {
struct hwrm_port_phy_qcfg_output phy_qcfg_resp;
struct hwrm_port_phy_qcfg_input *phy_qcfg_req;
phy_qcfg_req =
(struct hwrm_port_phy_qcfg_input *)vf->hwrm_cmd_req_addr;
mutex_lock(&bp->hwrm_cmd_lock);
memcpy(&phy_qcfg_resp, &bp->link_info.phy_qcfg_resp,
sizeof(phy_qcfg_resp));
mutex_unlock(&bp->hwrm_cmd_lock);
phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id;
if (vf->flags & BNXT_VF_LINK_UP) {
/* if physical link is down, force link up on VF */
if (phy_qcfg_resp.link ==
PORT_PHY_QCFG_RESP_LINK_NO_LINK) {
phy_qcfg_resp.link =
PORT_PHY_QCFG_RESP_LINK_LINK;
if (phy_qcfg_resp.auto_link_speed)
phy_qcfg_resp.link_speed =
phy_qcfg_resp.auto_link_speed;
else
phy_qcfg_resp.link_speed =
phy_qcfg_resp.force_link_speed;
phy_qcfg_resp.duplex =
PORT_PHY_QCFG_RESP_DUPLEX_FULL;
phy_qcfg_resp.pause =
(PORT_PHY_QCFG_RESP_PAUSE_TX |
PORT_PHY_QCFG_RESP_PAUSE_RX);
}
} else {
/* force link down */
phy_qcfg_resp.link = PORT_PHY_QCFG_RESP_LINK_NO_LINK;
phy_qcfg_resp.link_speed = 0;
phy_qcfg_resp.duplex = PORT_PHY_QCFG_RESP_DUPLEX_HALF;
phy_qcfg_resp.pause = 0;
}
rc = bnxt_hwrm_fwd_resp(bp, vf, &phy_qcfg_resp,
phy_qcfg_req->resp_addr,
phy_qcfg_req->cmpl_ring,
sizeof(phy_qcfg_resp));
}
return rc;
}
static int bnxt_vf_req_validate_snd(struct bnxt *bp, struct bnxt_vf_info *vf)
{
int rc = 0;
struct hwrm_cmd_req_hdr *encap_req = vf->hwrm_cmd_req_addr;
u32 req_type = le32_to_cpu(encap_req->cmpl_ring_req_type) & 0xffff;
switch (req_type) {
case HWRM_CFA_L2_FILTER_ALLOC:
rc = bnxt_vf_validate_set_mac(bp, vf);
break;
case HWRM_FUNC_CFG:
/* TODO Validate if VF is allowed to change mac address,
* mtu, num of rings etc
*/
rc = bnxt_hwrm_exec_fwd_resp(
bp, vf, sizeof(struct hwrm_func_cfg_input));
break;
case HWRM_PORT_PHY_QCFG:
rc = bnxt_vf_set_link(bp, vf);
break;
default:
break;
}
return rc;
}
void bnxt_hwrm_exec_fwd_req(struct bnxt *bp)
{
u32 i = 0, active_vfs = bp->pf.active_vfs, vf_id;
/* Scan through VF's and process commands */
while (1) {
vf_id = find_next_bit(bp->pf.vf_event_bmap, active_vfs, i);
if (vf_id >= active_vfs)
break;
clear_bit(vf_id, bp->pf.vf_event_bmap);
bnxt_vf_req_validate_snd(bp, &bp->pf.vf[vf_id]);
i = vf_id + 1;
}
}
#else
void bnxt_sriov_disable(struct bnxt *bp)
{
}
void bnxt_hwrm_exec_fwd_req(struct bnxt *bp)
{
netdev_err(dev, "Invalid VF message received when SRIOV is not enable\n");
}
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2015 Broadcom Corporation
*
* 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
* the Free Software Foundation.
*/
#ifndef BNXT_SRIOV_H
#define BNXT_SRIOV_H
int bnxt_get_vf_config(struct net_device *, int, struct ifla_vf_info *);
int bnxt_set_vf_mac(struct net_device *, int, u8 *);
int bnxt_set_vf_vlan(struct net_device *, int, u16, u8);
int bnxt_set_vf_bw(struct net_device *, int, int, int);
int bnxt_set_vf_link_state(struct net_device *, int, int);
int bnxt_set_vf_spoofchk(struct net_device *, int, bool);
int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs);
void bnxt_sriov_disable(struct bnxt *);
void bnxt_hwrm_exec_fwd_req(struct bnxt *);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment