diff options
Diffstat (limited to 'drivers/net/bnx2x')
-rw-r--r-- | drivers/net/bnx2x/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x.h | 165 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_cmn.c | 197 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_cmn.h | 73 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_dcb.c | 2118 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_dcb.h | 196 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_ethtool.c | 357 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_hsi.h | 327 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_init_ops.h | 4 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_link.c | 666 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_link.h | 56 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_main.c | 700 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_reg.h | 52 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_stats.c | 13 | ||||
-rw-r--r-- | drivers/net/bnx2x/bnx2x_stats.h | 2 |
15 files changed, 4508 insertions, 420 deletions
diff --git a/drivers/net/bnx2x/Makefile b/drivers/net/bnx2x/Makefile index 084afce89ae..bb83a296127 100644 --- a/drivers/net/bnx2x/Makefile +++ b/drivers/net/bnx2x/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_BNX2X) += bnx2x.o -bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o +bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 863e73a85fb..77d6c8d6d86 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -13,6 +13,8 @@ #ifndef BNX2X_H #define BNX2X_H +#include <linux/netdevice.h> +#include <linux/types.h> /* compilation time flags */ @@ -20,15 +22,17 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.60.00-4" -#define DRV_MODULE_RELDATE "2010/11/01" +#define DRV_MODULE_VERSION "1.62.00-3" +#define DRV_MODULE_RELDATE "2010/12/21" #define BNX2X_BC_VER 0x040200 #define BNX2X_MULTI_QUEUE #define BNX2X_NEW_NAPI - +#if defined(CONFIG_DCB) +#define BCM_DCB +#endif #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE) #define BCM_CNIC 1 #include "../cnic_if.h" @@ -48,6 +52,7 @@ #include "bnx2x_fw_defs.h" #include "bnx2x_hsi.h" #include "bnx2x_link.h" +#include "bnx2x_dcb.h" #include "bnx2x_stats.h" /* error/debug prints */ @@ -199,10 +204,25 @@ void bnx2x_panic_dump(struct bnx2x *bp); /* EQ completions */ #define HC_SP_INDEX_EQ_CONS 7 +/* FCoE L2 connection completions */ +#define HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS 6 +#define HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS 4 /* iSCSI L2 */ #define HC_SP_INDEX_ETH_ISCSI_CQ_CONS 5 #define HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS 1 +/* Special clients parameters */ + +/* SB indices */ +/* FCoE L2 */ +#define BNX2X_FCOE_L2_RX_INDEX \ + (&bp->def_status_blk->sp_sb.\ + index_values[HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS]) + +#define BNX2X_FCOE_L2_TX_INDEX \ + (&bp->def_status_blk->sp_sb.\ + index_values[HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS]) + /** * CIDs and CLIDs: * CLIDs below is a CLID for func 0, then the CLID for other @@ -215,12 +235,19 @@ void bnx2x_panic_dump(struct bnx2x *bp); #define BNX2X_ISCSI_ETH_CL_ID 17 #define BNX2X_ISCSI_ETH_CID 17 +/* FCoE L2 */ +#define BNX2X_FCOE_ETH_CL_ID 18 +#define BNX2X_FCOE_ETH_CID 18 + /** Additional rings budgeting */ #ifdef BCM_CNIC #define CNIC_CONTEXT_USE 1 +#define FCOE_CONTEXT_USE 1 #else #define CNIC_CONTEXT_USE 0 +#define FCOE_CONTEXT_USE 0 #endif /* BCM_CNIC */ +#define NONE_ETH_CONTEXT_USE (FCOE_CONTEXT_USE) #define AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR \ AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR @@ -401,6 +428,17 @@ struct bnx2x_fastpath { }; #define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) +#ifdef BCM_CNIC +/* FCoE L2 `fastpath' is right after the eth entries */ +#define FCOE_IDX BNX2X_NUM_ETH_QUEUES(bp) +#define bnx2x_fcoe_fp(bp) (&bp->fp[FCOE_IDX]) +#define bnx2x_fcoe(bp, var) (bnx2x_fcoe_fp(bp)->var) +#define IS_FCOE_FP(fp) (fp->index == FCOE_IDX) +#define IS_FCOE_IDX(idx) ((idx) == FCOE_IDX) +#else +#define IS_FCOE_FP(fp) false +#define IS_FCOE_IDX(idx) false +#endif /* MC hsi */ @@ -669,8 +707,14 @@ struct bnx2x_port { enum { CAM_ETH_LINE = 0, CAM_ISCSI_ETH_LINE, - CAM_MAX_PF_LINE = CAM_ISCSI_ETH_LINE + CAM_FIP_ETH_LINE, + CAM_FIP_MCAST_LINE, + CAM_MAX_PF_LINE = CAM_FIP_MCAST_LINE }; +/* number of MACs per function in NIG memory - used for SI mode */ +#define NIG_LLH_FUNC_MEM_SIZE 16 +/* number of entries in NIG_REG_LLHX_FUNC_MEM */ +#define NIG_LLH_FUNC_MEM_MAX_OFFSET 8 #define BNX2X_VF_ID_INVALID 0xFF @@ -710,6 +754,14 @@ enum { */ #define L2_FP_COUNT(cid_cnt) ((cid_cnt) - CNIC_CONTEXT_USE) +/* + * The number of FP-SB allocated by the driver == max number of regular L2 + * queues + 1 for the CNIC which also consumes an FP-SB + */ +#define FP_SB_COUNT(cid_cnt) ((cid_cnt) - FCOE_CONTEXT_USE) +#define NUM_IGU_SB_REQUIRED(cid_cnt) \ + (FP_SB_COUNT(cid_cnt) - NONE_ETH_CONTEXT_USE) + union cdu_context { struct eth_context eth; char pad[1024]; @@ -722,7 +774,8 @@ union cdu_context { #ifdef BCM_CNIC #define CNIC_ISCSI_CID_MAX 256 -#define CNIC_CID_MAX (CNIC_ISCSI_CID_MAX) +#define CNIC_FCOE_CID_MAX 2048 +#define CNIC_CID_MAX (CNIC_ISCSI_CID_MAX + CNIC_FCOE_CID_MAX) #define CNIC_ILT_LINES DIV_ROUND_UP(CNIC_CID_MAX, ILT_PAGE_CIDS) #endif @@ -770,6 +823,8 @@ struct bnx2x_slowpath { u32 wb_comp; u32 wb_data[4]; + /* pfc configuration for DCBX ramrod */ + struct flow_control_configuration pfc_config; }; #define bnx2x_sp(bp, var) (&bp->slowpath->var) @@ -918,6 +973,10 @@ struct bnx2x { #define DISABLE_MSI_FLAG 0x200 #define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG) #define MF_FUNC_DIS 0x1000 +#define FCOE_MACS_SET 0x2000 +#define NO_FCOE_FLAG 0x4000 + +#define NO_FCOE(bp) ((bp)->flags & NO_FCOE_FLAG) int pf_num; /* absolute PF number */ int pfid; /* per-path PF number */ @@ -967,6 +1026,8 @@ struct bnx2x { u16 mf_ov; u8 mf_mode; #define IS_MF(bp) (bp->mf_mode != 0) +#define IS_MF_SI(bp) (bp->mf_mode == MULTI_FUNCTION_SI) +#define IS_MF_SD(bp) (bp->mf_mode == MULTI_FUNCTION_SD) u8 wol; @@ -1010,6 +1071,7 @@ struct bnx2x { #define BNX2X_ACCEPT_ALL_UNICAST 0x0004 #define BNX2X_ACCEPT_ALL_MULTICAST 0x0008 #define BNX2X_ACCEPT_BROADCAST 0x0010 +#define BNX2X_ACCEPT_UNMATCHED_UCAST 0x0020 #define BNX2X_PROMISCUOUS_MODE 0x10000 u32 rx_mode; @@ -1062,7 +1124,8 @@ struct bnx2x { u16 cnic_kwq_pending; u16 cnic_spq_pending; struct mutex cnic_mutex; - u8 iscsi_mac[6]; + u8 iscsi_mac[ETH_ALEN]; + u8 fip_mac[ETH_ALEN]; #endif int dmae_ready; @@ -1122,6 +1185,31 @@ struct bnx2x { char fw_ver[32]; const struct firmware *firmware; + /* LLDP params */ + struct bnx2x_config_lldp_params lldp_config_params; + + /* DCB support on/off */ + u16 dcb_state; +#define BNX2X_DCB_STATE_OFF 0 +#define BNX2X_DCB_STATE_ON 1 + + /* DCBX engine mode */ + int dcbx_enabled; +#define BNX2X_DCBX_ENABLED_OFF 0 +#define BNX2X_DCBX_ENABLED_ON_NEG_OFF 1 +#define BNX2X_DCBX_ENABLED_ON_NEG_ON 2 +#define BNX2X_DCBX_ENABLED_INVALID (-1) + + bool dcbx_mode_uset; + + struct bnx2x_config_dcbx_params dcbx_config_params; + + struct bnx2x_dcbx_port_params dcbx_port_params; + int dcb_version; + + /* DCBX Negotation results */ + struct dcbx_features dcbx_local_feat; + u32 dcbx_error; }; /** @@ -1152,10 +1240,17 @@ struct bnx2x { #define RSS_IPV6_TCP_CAP 0x0008 #define BNX2X_NUM_QUEUES(bp) (bp->num_queues) +#define BNX2X_NUM_ETH_QUEUES(bp) (BNX2X_NUM_QUEUES(bp) - NONE_ETH_CONTEXT_USE) + +/* ethtool statistics are displayed for all regular ethernet queues and the + * fcoe L2 queue if not disabled + */ +#define BNX2X_NUM_STAT_QUEUES(bp) (NO_FCOE(bp) ? BNX2X_NUM_ETH_QUEUES(bp) : \ + (BNX2X_NUM_ETH_QUEUES(bp) + FCOE_CONTEXT_USE)) + #define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 1) #define BNX2X_MAX_QUEUES(bp) (bp->igu_sb_cnt - CNIC_CONTEXT_USE) -#define is_eth_multi(bp) (BNX2X_NUM_ETH_QUEUES(bp) > 1) #define RSS_IPV4_CAP_MASK \ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY @@ -1248,6 +1343,7 @@ struct bnx2x_client_ramrod_params { u16 cl_id; u32 cid; u8 poll; +#define CLIENT_IS_FCOE 0x01 #define CLIENT_IS_LEADING_RSS 0x02 u8 flags; }; @@ -1280,11 +1376,54 @@ struct bnx2x_func_init_params { u16 spq_prod; /* valid iff FUNC_FLG_SPQ */ }; +#define for_each_eth_queue(bp, var) \ + for (var = 0; var < BNX2X_NUM_ETH_QUEUES(bp); var++) + +#define for_each_nondefault_eth_queue(bp, var) \ + for (var = 1; var < BNX2X_NUM_ETH_QUEUES(bp); var++) + +#define for_each_napi_queue(bp, var) \ + for (var = 0; \ + var < BNX2X_NUM_ETH_QUEUES(bp) + FCOE_CONTEXT_USE; var++) \ + if (skip_queue(bp, var)) \ + continue; \ + else + #define for_each_queue(bp, var) \ - for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) + for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) \ + if (skip_queue(bp, var)) \ + continue; \ + else + +#define for_each_rx_queue(bp, var) \ + for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) \ + if (skip_rx_queue(bp, var)) \ + continue; \ + else + +#define for_each_tx_queue(bp, var) \ + for (var = 0; var < BNX2X_NUM_QUEUES(bp); var++) \ + if (skip_tx_queue(bp, var)) \ + continue; \ + else + #define for_each_nondefault_queue(bp, var) \ - for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++) + for (var = 1; var < BNX2X_NUM_QUEUES(bp); var++) \ + if (skip_queue(bp, var)) \ + continue; \ + else + +/* skip rx queue + * if FCOE l2 support is diabled and this is the fcoe L2 queue + */ +#define skip_rx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) +/* skip tx queue + * if FCOE l2 support is diabled and this is the fcoe L2 queue + */ +#define skip_tx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) + +#define skip_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) #define WAIT_RAMROD_POLL 0x01 #define WAIT_RAMROD_COMMON 0x02 @@ -1329,7 +1468,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, #define BNX2X_ILT_ZALLOC(x, y, size) \ do { \ - x = pci_alloc_consistent(bp->pdev, size, y); \ + x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ if (x) \ memset(x, 0, size); \ } while (0) @@ -1337,7 +1476,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, #define BNX2X_ILT_FREE(x, y, size) \ do { \ if (x) { \ - pci_free_consistent(bp->pdev, size, x, y); \ + dma_free_coherent(&bp->pdev->dev, size, x, y); \ x = NULL; \ y = 0; \ } \ @@ -1608,10 +1747,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, MAC_CONFIGURATION_ENTRY_ACTION_TYPE) == \ (T_ETH_MAC_COMMAND_INVALIDATE)) -#define CAM_INVALIDATE(x) \ - (x.target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE) - - /* Number of u32 elements in MC hash array */ #define MC_HASH_SIZE 8 #define MC_HASH_OFFSET(bp, i) (BAR_TSTRORM_INTMEM + \ diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 94d5f59d5a6..710ce5d04c5 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -698,6 +698,29 @@ void bnx2x_release_phy_lock(struct bnx2x *bp) mutex_unlock(&bp->port.phy_mutex); } +/* calculates MF speed according to current linespeed and MF configuration */ +u16 bnx2x_get_mf_speed(struct bnx2x *bp) +{ + u16 line_speed = bp->link_vars.line_speed; + if (IS_MF(bp)) { + u16 maxCfg = (bp->mf_config[BP_VN(bp)] & + FUNC_MF_CFG_MAX_BW_MASK) >> + FUNC_MF_CFG_MAX_BW_SHIFT; + /* Calculate the current MAX line speed limit for the DCC + * capable devices + */ + if (IS_MF_SD(bp)) { + u16 vn_max_rate = maxCfg * 100; + + if (vn_max_rate < line_speed) + line_speed = vn_max_rate; + } else /* IS_MF_SI(bp)) */ + line_speed = (line_speed * maxCfg) / 100; + } + + return line_speed; +} + void bnx2x_link_report(struct bnx2x *bp) { if (bp->flags & MF_FUNC_DIS) { @@ -713,17 +736,8 @@ void bnx2x_link_report(struct bnx2x *bp) netif_carrier_on(bp->dev); netdev_info(bp->dev, "NIC Link is Up, "); - line_speed = bp->link_vars.line_speed; - if (IS_MF(bp)) { - u16 vn_max_rate; + line_speed = bnx2x_get_mf_speed(bp); - vn_max_rate = - ((bp->mf_config[BP_VN(bp)] & - FUNC_MF_CFG_MAX_BW_MASK) >> - FUNC_MF_CFG_MAX_BW_SHIFT) * 100; - if (vn_max_rate < line_speed) - line_speed = vn_max_rate; - } pr_cont("%d Mbps ", line_speed); if (bp->link_vars.duplex == DUPLEX_FULL) @@ -813,7 +827,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) DP(NETIF_MSG_IFUP, "mtu %d rx_buf_size %d\n", bp->dev->mtu, bp->rx_buf_size); - for_each_queue(bp, j) { + for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; if (!fp->disable_tpa) { @@ -866,7 +880,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) } } - for_each_queue(bp, j) { + for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; fp->rx_bd_cons = 0; @@ -897,7 +911,7 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp) { int i; - for_each_queue(bp, i) { + for_each_tx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; u16 bd_cons = fp->tx_bd_cons; @@ -915,7 +929,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp) { int i, j; - for_each_queue(bp, j) { + for_each_rx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; for (i = 0; i < NUM_RX_BD; i++) { @@ -956,7 +970,7 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp) #ifdef BCM_CNIC offset++; #endif - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq " "state %x\n", i, bp->msix_table[i + offset].vector, bnx2x_fp(bp, i, state)); @@ -990,14 +1004,14 @@ int bnx2x_enable_msix(struct bnx2x *bp) bp->msix_table[msix_vec].entry, bp->msix_table[msix_vec].entry); msix_vec++; #endif - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { bp->msix_table[msix_vec].entry = msix_vec; DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d " "(fastpath #%u)\n", msix_vec, msix_vec, i); msix_vec++; } - req_cnt = BNX2X_NUM_QUEUES(bp) + CNIC_CONTEXT_USE + 1; + req_cnt = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_CONTEXT_USE + 1; rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt); @@ -1053,7 +1067,7 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp) #ifdef BCM_CNIC offset++; #endif - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", bp->dev->name, i); @@ -1070,7 +1084,7 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp) fp->state = BNX2X_FP_STATE_IRQ; } - i = BNX2X_NUM_QUEUES(bp); + i = BNX2X_NUM_ETH_QUEUES(bp); offset = 1 + CNIC_CONTEXT_USE; netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d" " ... fp[%d] %d\n", @@ -1117,7 +1131,7 @@ static void bnx2x_napi_enable(struct bnx2x *bp) { int i; - for_each_queue(bp, i) + for_each_napi_queue(bp, i) napi_enable(&bnx2x_fp(bp, i, napi)); } @@ -1125,7 +1139,7 @@ static void bnx2x_napi_disable(struct bnx2x *bp) { int i; - for_each_queue(bp, i) + for_each_napi_queue(bp, i) napi_disable(&bnx2x_fp(bp, i, napi)); } @@ -1153,6 +1167,35 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) netif_tx_disable(bp->dev); } +u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb) +{ +#ifdef BCM_CNIC + struct bnx2x *bp = netdev_priv(dev); + if (NO_FCOE(bp)) + return skb_tx_hash(dev, skb); + else { + struct ethhdr *hdr = (struct ethhdr *)skb->data; + u16 ether_type = ntohs(hdr->h_proto); + + /* Skip VLAN tag if present */ + if (ether_type == ETH_P_8021Q) { + struct vlan_ethhdr *vhdr = + (struct vlan_ethhdr *)skb->data; + + ether_type = ntohs(vhdr->h_vlan_encapsulated_proto); + } + + /* If ethertype is FCoE or FIP - use FCoE ring */ + if ((ether_type == ETH_P_FCOE) || (ether_type == ETH_P_FIP)) + return bnx2x_fcoe(bp, index); + } +#endif + /* Select a none-FCoE queue: if FCoE is enabled, exclude FCoE L2 ring + */ + return __skb_tx_hash(dev, skb, + dev->real_num_tx_queues - FCOE_CONTEXT_USE); +} + void bnx2x_set_num_queues(struct bnx2x *bp) { switch (bp->multi_mode) { @@ -1167,8 +1210,23 @@ void bnx2x_set_num_queues(struct bnx2x *bp) bp->num_queues = 1; break; } + + /* Add special queues */ + bp->num_queues += NONE_ETH_CONTEXT_USE; } +#ifdef BCM_CNIC +static inline void bnx2x_set_fcoe_eth_macs(struct bnx2x *bp) +{ + if (!NO_FCOE(bp)) { + if (!IS_MF_SD(bp)) + bnx2x_set_fip_eth_mac_addr(bp, 1); + bnx2x_set_all_enode_macs(bp, 1); + bp->flags |= FCOE_MACS_SET; + } +} +#endif + static void bnx2x_release_firmware(struct bnx2x *bp) { kfree(bp->init_ops_offsets); @@ -1177,6 +1235,20 @@ static void bnx2x_release_firmware(struct bnx2x *bp) release_firmware(bp->firmware); } +static inline int bnx2x_set_real_num_queues(struct bnx2x *bp) +{ + int rc, num = bp->num_queues; + +#ifdef BCM_CNIC + if (NO_FCOE(bp)) + num -= FCOE_CONTEXT_USE; + +#endif + netif_set_real_num_tx_queues(bp->dev, num); + rc = netif_set_real_num_rx_queues(bp->dev, num); + return rc; +} + /* must be called with rtnl_lock */ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) { @@ -1203,10 +1275,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) if (bnx2x_alloc_mem(bp)) return -ENOMEM; - netif_set_real_num_tx_queues(bp->dev, bp->num_queues); - rc = netif_set_real_num_rx_queues(bp->dev, bp->num_queues); + rc = bnx2x_set_real_num_queues(bp); if (rc) { - BNX2X_ERR("Unable to update real_num_rx_queues\n"); + BNX2X_ERR("Unable to set real_num_queues\n"); goto load_error0; } @@ -1214,6 +1285,10 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bnx2x_fp(bp, i, disable_tpa) = ((bp->flags & TPA_ENABLE_FLAG) == 0); +#ifdef BCM_CNIC + /* We don't want TPA on FCoE L2 ring */ + bnx2x_fcoe(bp, disable_tpa) = 1; +#endif bnx2x_napi_enable(bp); /* Send LOAD_REQUEST command to MCP @@ -1296,6 +1371,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) } } + bnx2x_dcbx_init(bp); + bp->state = BNX2X_STATE_OPENING_WAIT4_PORT; rc = bnx2x_func_start(bp); @@ -1344,6 +1421,10 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Now when Clients are configured we are ready to work */ bp->state = BNX2X_STATE_OPEN; +#ifdef BCM_CNIC + bnx2x_set_fcoe_eth_macs(bp); +#endif + bnx2x_set_eth_mac(bp, 1); if (bp->port.pmf) @@ -1402,7 +1483,7 @@ load_error3: /* Free SKBs, SGEs, TPA pool and driver internals */ bnx2x_free_skbs(bp); - for_each_queue(bp, i) + for_each_rx_queue(bp, i) bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); /* Release IRQs */ @@ -1473,7 +1554,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) /* Free SKBs, SGEs, TPA pool and driver internals */ bnx2x_free_skbs(bp); - for_each_queue(bp, i) + for_each_rx_queue(bp, i) bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); bnx2x_free_mem(bp); @@ -1577,6 +1658,17 @@ int bnx2x_poll(struct napi_struct *napi, int budget) /* Fall out from the NAPI loop if needed */ if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) { +#ifdef BCM_CNIC + /* No need to update SB for FCoE L2 ring as long as + * it's connected to the default SB and the SB + * has been updated when NAPI was scheduled. + */ + if (IS_FCOE_FP(fp)) { + napi_complete(napi); + break; + } +#endif + bnx2x_update_fpsb_idx(fp); /* bnx2x_has_rx_work() reads the status block, * thus we need to ensure that status block indices @@ -1692,11 +1784,10 @@ static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) } } - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) - rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP); - - else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) - rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6); + if (skb_is_gso_v6(skb)) + rc |= XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6; + else if (skb_is_gso(skb)) + rc |= XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP; return rc; } @@ -1782,15 +1873,15 @@ exit_lbl: } #endif -static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, - struct eth_tx_parse_bd_e2 *pbd, - u32 xmit_type) +static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data, + u32 xmit_type) { - pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) << - ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT; + *parsing_data |= (skb_shinfo(skb)->gso_size << + ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) & + ETH_TX_PARSE_BD_E2_LSO_MSS; if ((xmit_type & XMIT_GSO_V6) && (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6)) - pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR; + *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR; } /** @@ -1835,15 +1926,15 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, * @return header len */ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, - struct eth_tx_parse_bd_e2 *pbd, - u32 xmit_type) + u32 *parsing_data, u32 xmit_type) { - pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) << - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT; + *parsing_data |= ((tcp_hdrlen(skb)/4) << + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; - pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) - - skb->data) / 2) << - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT; + *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) << + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; } @@ -1912,6 +2003,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL; struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; struct eth_tx_parse_bd_e2 *pbd_e2 = NULL; + u32 pbd_e2_parsing_data = 0; u16 pkt_prod, bd_prod; int nbd, fp_index; dma_addr_t mapping; @@ -2033,8 +2125,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); /* Set PBD in checksum offload case */ if (xmit_type & XMIT_CSUM) - hlen = bnx2x_set_pbd_csum_e2(bp, - skb, pbd_e2, xmit_type); + hlen = bnx2x_set_pbd_csum_e2(bp, skb, + &pbd_e2_parsing_data, + xmit_type); } else { pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x; memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); @@ -2076,10 +2169,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd, hlen, bd_prod, ++nbd); if (CHIP_IS_E2(bp)) - bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type); + bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data, + xmit_type); else bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type); } + + /* Set the PBD's parsing_data field if not zero + * (for the chips newer than 57711). + */ + if (pbd_e2_parsing_data) + pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data); + tx_data_bd = (struct eth_tx_bd *)tx_start_bd; /* Handle fragmented skb */ @@ -2232,7 +2333,7 @@ int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp) bp->fp = fp; /* msix table */ - tbl = kzalloc((bp->l2_cid_count + 1) * sizeof(*tbl), + tbl = kzalloc((FP_SB_COUNT(bp->l2_cid_count) + 1) * sizeof(*tbl), GFP_KERNEL); if (!tbl) goto alloc_err; diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 6b28739c530..03eb4d68e6b 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -73,6 +73,16 @@ void bnx2x__link_status_update(struct bnx2x *bp); void bnx2x_link_report(struct bnx2x *bp); /** + * calculates MF speed according to current linespeed and MF + * configuration + * + * @param bp + * + * @return u16 + */ +u16 bnx2x_get_mf_speed(struct bnx2x *bp); + +/** * MSI-X slowpath interrupt handler * * @param irq @@ -232,6 +242,30 @@ int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource); */ void bnx2x_set_eth_mac(struct bnx2x *bp, int set); +#ifdef BCM_CNIC +/** + * Set/Clear FIP MAC(s) at the next enties in the CAM after the ETH + * MAC(s). This function will wait until the ramdord completion + * returns. + * + * @param bp driver handle + * @param set set or clear the CAM entry + * + * @return 0 if cussess, -ENODEV if ramrod doesn't return. + */ +int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set); + +/** + * Set/Clear ALL_ENODE mcast MAC. + * + * @param bp + * @param set + * + * @return int + */ +int bnx2x_set_all_enode_macs(struct bnx2x *bp, int set); +#endif + /** * Set MAC filtering configurations. * @@ -290,6 +324,13 @@ int bnx2x_func_start(struct bnx2x *bp); void bnx2x_ilt_set_info(struct bnx2x *bp); /** + * Inintialize dcbx protocol + * + * @param bp + */ +void bnx2x_dcbx_init(struct bnx2x *bp); + +/** * Set power state to the requested value. Currently only D0 and * D3hot are supported. * @@ -309,6 +350,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode); /* hard_xmit callback */ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev); +/* select_queue callback */ +u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb); + int bnx2x_change_mac_addr(struct net_device *dev, void *p); /* NAPI poll Rx part */ @@ -685,7 +729,7 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp) int i; /* Add NAPI objects */ - for_each_queue(bp, i) + for_each_napi_queue(bp, i) netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), bnx2x_poll, BNX2X_NAPI_WEIGHT); } @@ -694,7 +738,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp) { int i; - for_each_queue(bp, i) + for_each_napi_queue(bp, i) netif_napi_del(&bnx2x_fp(bp, i, napi)); } @@ -860,7 +904,7 @@ static inline void bnx2x_init_tx_rings(struct bnx2x *bp) { int i, j; - for_each_queue(bp, j) { + for_each_tx_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; for (i = 1; i <= NUM_TX_RINGS; i++) { @@ -939,7 +983,30 @@ static inline void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp) } } +#ifdef BCM_CNIC +static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp) +{ + bnx2x_fcoe(bp, cl_id) = BNX2X_FCOE_ETH_CL_ID + + BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE; + bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID; + bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID; + bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id; + bnx2x_fcoe(bp, bp) = bp; + bnx2x_fcoe(bp, state) = BNX2X_FP_STATE_CLOSED; + bnx2x_fcoe(bp, index) = FCOE_IDX; + bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX; + bnx2x_fcoe(bp, tx_cons_sb) = BNX2X_FCOE_L2_TX_INDEX; + /* qZone id equals to FW (per path) client id */ + bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fcoe(bp, cl_id) + + BP_PORT(bp)*(CHIP_IS_E2(bp) ? ETH_MAX_RX_CLIENTS_E2 : + ETH_MAX_RX_CLIENTS_E1H); + /* init shortcut */ + bnx2x_fcoe(bp, ustorm_rx_prods_offset) = CHIP_IS_E2(bp) ? + USTORM_RX_PRODS_E2_OFFSET(bnx2x_fcoe(bp, cl_qzone_id)) : + USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), bnx2x_fcoe_fp(bp)->cl_id); +} +#endif static inline void __storm_memset_struct(struct bnx2x *bp, u32 addr, size_t size, u32 *data) diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c new file mode 100644 index 00000000000..fb60021f81f --- /dev/null +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -0,0 +1,2118 @@ +/* bnx2x_dcb.c: Broadcom Everest network driver. + * + * Copyright 2009-2010 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Maintained by: Eilon Greenstein <eilong@broadcom.com> + * Written by: Dmitry Kravkov + * + */ +#include <linux/netdevice.h> +#include <linux/types.h> +#include <linux/errno.h> + +#include "bnx2x.h" +#include "bnx2x_cmn.h" +#include "bnx2x_dcb.h" + + +/* forward declarations of dcbx related functions */ +static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp); +static void bnx2x_pfc_set_pfc(struct bnx2x *bp); +static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp); +static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp); +static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, + u32 *set_configuration_ets_pg, + u32 *pri_pg_tbl); +static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, + u32 *pg_pri_orginal_spread, + struct pg_help_data *help_data); +static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp, + struct pg_help_data *help_data, + struct dcbx_ets_feature *ets, + u32 *pg_pri_orginal_spread); +static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + struct dcbx_ets_feature *ets); +static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp); + + +static void bnx2x_pfc_set(struct bnx2x *bp) +{ + struct bnx2x_nig_brb_pfc_port_params pfc_params = {0}; + u32 pri_bit, val = 0; + u8 pri; + + /* Tx COS configuration */ + if (bp->dcbx_port_params.ets.cos_params[0].pauseable) + pfc_params.rx_cos0_priority_mask = + bp->dcbx_port_params.ets.cos_params[0].pri_bitmask; + if (bp->dcbx_port_params.ets.cos_params[1].pauseable) + pfc_params.rx_cos1_priority_mask = + bp->dcbx_port_params.ets.cos_params[1].pri_bitmask; + + + /** + * Rx COS configuration + * Changing PFC RX configuration . + * In RX COS0 will always be configured to lossy and COS1 to lossless + */ + for (pri = 0 ; pri < MAX_PFC_PRIORITIES ; pri++) { + pri_bit = 1 << pri; + + if (pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp)) + val |= 1 << (pri * 4); + } + + pfc_params.pkt_priority_to_cos = val; + + /* RX COS0 */ + pfc_params.llfc_low_priority_classes = 0; + /* RX COS1 */ + pfc_params.llfc_high_priority_classes = DCBX_PFC_PRI_PAUSE_MASK(bp); + + /* BRB configuration */ + pfc_params.cos0_pauseable = false; + pfc_params.cos1_pauseable = true; + + bnx2x_acquire_phy_lock(bp); + bp->link_params.feature_config_flags |= FEATURE_CONFIG_PFC_ENABLED; + bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &pfc_params); + bnx2x_release_phy_lock(bp); +} + +static void bnx2x_pfc_clear(struct bnx2x *bp) +{ + struct bnx2x_nig_brb_pfc_port_params nig_params = {0}; + nig_params.pause_enable = 1; +#ifdef BNX2X_SAFC + if (bp->flags & SAFC_TX_FLAG) { + u32 high = 0, low = 0; + int i; + + for (i = 0; i < BNX2X_MAX_PRIORITY; i++) { + if (bp->pri_map[i] == 1) + high |= (1 << i); + if (bp->pri_map[i] == 0) + low |= (1 << i); + } + + nig_params.llfc_low_priority_classes = high; + nig_params.llfc_low_priority_classes = low; + + nig_params.pause_enable = 0; + nig_params.llfc_enable = 1; + nig_params.llfc_out_en = 1; + } +#endif /* BNX2X_SAFC */ + bnx2x_acquire_phy_lock(bp); + bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_PFC_ENABLED; + bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &nig_params); + bnx2x_release_phy_lock(bp); +} + +static void bnx2x_dump_dcbx_drv_param(struct bnx2x *bp, + struct dcbx_features *features, + u32 error) +{ + u8 i = 0; + DP(NETIF_MSG_LINK, "local_mib.error %x\n", error); + + /* PG */ + DP(NETIF_MSG_LINK, + "local_mib.features.ets.enabled %x\n", features->ets.enabled); + for (i = 0; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) + DP(NETIF_MSG_LINK, + "local_mib.features.ets.pg_bw_tbl[%d] %d\n", i, + DCBX_PG_BW_GET(features->ets.pg_bw_tbl, i)); + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) + DP(NETIF_MSG_LINK, + "local_mib.features.ets.pri_pg_tbl[%d] %d\n", i, + DCBX_PRI_PG_GET(features->ets.pri_pg_tbl, i)); + + /* pfc */ + DP(NETIF_MSG_LINK, "dcbx_features.pfc.pri_en_bitmap %x\n", + features->pfc.pri_en_bitmap); + DP(NETIF_MSG_LINK, "dcbx_features.pfc.pfc_caps %x\n", + features->pfc.pfc_caps); + DP(NETIF_MSG_LINK, "dcbx_features.pfc.enabled %x\n", + features->pfc.enabled); + + DP(NETIF_MSG_LINK, "dcbx_features.app.default_pri %x\n", + features->app.default_pri); + DP(NETIF_MSG_LINK, "dcbx_features.app.tc_supported %x\n", + features->app.tc_supported); + DP(NETIF_MSG_LINK, "dcbx_features.app.enabled %x\n", + features->app.enabled); + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { + DP(NETIF_MSG_LINK, + "dcbx_features.app.app_pri_tbl[%x].app_id %x\n", + i, features->app.app_pri_tbl[i].app_id); + DP(NETIF_MSG_LINK, + "dcbx_features.app.app_pri_tbl[%x].pri_bitmap %x\n", + i, features->app.app_pri_tbl[i].pri_bitmap); + DP(NETIF_MSG_LINK, + "dcbx_features.app.app_pri_tbl[%x].appBitfield %x\n", + i, features->app.app_pri_tbl[i].appBitfield); + } +} + +static void bnx2x_dcbx_get_ap_priority(struct bnx2x *bp, + u8 pri_bitmap, + u8 llfc_traf_type) +{ + u32 pri = MAX_PFC_PRIORITIES; + u32 index = MAX_PFC_PRIORITIES - 1; + u32 pri_mask; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + + /* Choose the highest priority */ + while ((MAX_PFC_PRIORITIES == pri) && (0 != index)) { + pri_mask = 1 << index; + if (GET_FLAGS(pri_bitmap, pri_mask)) + pri = index ; + index--; + } + + if (pri < MAX_PFC_PRIORITIES) + ttp[llfc_traf_type] = max_t(u32, ttp[llfc_traf_type], pri); +} + +static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp, + struct dcbx_app_priority_feature *app, + u32 error) { + u8 index; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + + if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR)) + DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_ERROR\n"); + + if (app->enabled && !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR)) { + + bp->dcbx_port_params.app.enabled = true; + + for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++) + ttp[index] = 0; + + if (app->default_pri < MAX_PFC_PRIORITIES) + ttp[LLFC_TRAFFIC_TYPE_NW] = app->default_pri; + + for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) { + struct dcbx_app_priority_entry *entry = + app->app_pri_tbl; + + if (GET_FLAGS(entry[index].appBitfield, + DCBX_APP_SF_ETH_TYPE) && + ETH_TYPE_FCOE == entry[index].app_id) + bnx2x_dcbx_get_ap_priority(bp, + entry[index].pri_bitmap, + LLFC_TRAFFIC_TYPE_FCOE); + + if (GET_FLAGS(entry[index].appBitfield, + DCBX_APP_SF_PORT) && + TCP_PORT_ISCSI == entry[index].app_id) + bnx2x_dcbx_get_ap_priority(bp, + entry[index].pri_bitmap, + LLFC_TRAFFIC_TYPE_ISCSI); + } + } else { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_DISABLED\n"); + bp->dcbx_port_params.app.enabled = false; + for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++) + ttp[index] = INVALID_TRAFFIC_TYPE_PRIORITY; + } +} + +static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp, + struct dcbx_ets_feature *ets, + u32 error) { + int i = 0; + u32 pg_pri_orginal_spread[DCBX_MAX_NUM_PG_BW_ENTRIES] = {0}; + struct pg_help_data pg_help_data; + struct bnx2x_dcbx_cos_params *cos_params = + bp->dcbx_port_params.ets.cos_params; + + memset(&pg_help_data, 0, sizeof(struct pg_help_data)); + + + if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR)) + DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ERROR\n"); + + + /* Clean up old settings of ets on COS */ + for (i = 0; i < E2_NUM_OF_COS ; i++) { + + cos_params[i].pauseable = false; + cos_params[i].strict = BNX2X_DCBX_COS_NOT_STRICT; + cos_params[i].bw_tbl = DCBX_INVALID_COS_BW; + cos_params[i].pri_bitmask = DCBX_PFC_PRI_GET_NON_PAUSE(bp, 0); + } + + if (bp->dcbx_port_params.app.enabled && + !GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR) && + ets->enabled) { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ENABLE\n"); + bp->dcbx_port_params.ets.enabled = true; + + bnx2x_dcbx_get_ets_pri_pg_tbl(bp, + pg_pri_orginal_spread, + ets->pri_pg_tbl); + + bnx2x_dcbx_get_num_pg_traf_type(bp, + pg_pri_orginal_spread, + &pg_help_data); + + bnx2x_dcbx_fill_cos_params(bp, &pg_help_data, + ets, pg_pri_orginal_spread); + + } else { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_DISABLED\n"); + bp->dcbx_port_params.ets.enabled = false; + ets->pri_pg_tbl[0] = 0; + + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES ; i++) + DCBX_PG_BW_SET(ets->pg_bw_tbl, i, 1); + } +} + +static void bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp, + struct dcbx_pfc_feature *pfc, u32 error) +{ + + if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR)) + DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_ERROR\n"); + + if (bp->dcbx_port_params.app.enabled && + !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR) && + pfc->enabled) { + bp->dcbx_port_params.pfc.enabled = true; + bp->dcbx_port_params.pfc.priority_non_pauseable_mask = + ~(pfc->pri_en_bitmap); + } else { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_DISABLED\n"); + bp->dcbx_port_params.pfc.enabled = false; + bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 0; + } +} + +static void bnx2x_get_dcbx_drv_param(struct bnx2x *bp, + struct dcbx_features *features, + u32 error) +{ + bnx2x_dcbx_get_ap_feature(bp, &features->app, error); + + bnx2x_dcbx_get_pfc_feature(bp, &features->pfc, error); + + bnx2x_dcbx_get_ets_feature(bp, &features->ets, error); +} + +#define DCBX_LOCAL_MIB_MAX_TRY_READ (100) +static int bnx2x_dcbx_read_mib(struct bnx2x *bp, + u32 *base_mib_addr, + u32 offset, + int read_mib_type) +{ + int max_try_read = 0, i; + u32 *buff, mib_size, prefix_seq_num, suffix_seq_num; + struct lldp_remote_mib *remote_mib ; + struct lldp_local_mib *local_mib; + + + switch (read_mib_type) { + case DCBX_READ_LOCAL_MIB: + mib_size = sizeof(struct lldp_local_mib); + break; + case DCBX_READ_REMOTE_MIB: + mib_size = sizeof(struct lldp_remote_mib); + break; + default: + return 1; /*error*/ + } + + offset += BP_PORT(bp) * mib_size; + + do { + buff = base_mib_addr; + for (i = 0; i < mib_size; i += 4, buff++) + *buff = REG_RD(bp, offset + i); + + max_try_read++; + + switch (read_mib_type) { + case DCBX_READ_LOCAL_MIB: + local_mib = (struct lldp_local_mib *) base_mib_addr; + prefix_seq_num = local_mib->prefix_seq_num; + suffix_seq_num = local_mib->suffix_seq_num; + break; + case DCBX_READ_REMOTE_MIB: + remote_mib = (struct lldp_remote_mib *) base_mib_addr; + prefix_seq_num = remote_mib->prefix_seq_num; + suffix_seq_num = remote_mib->suffix_seq_num; + break; + default: + return 1; /*error*/ + } + } while ((prefix_seq_num != suffix_seq_num) && + (max_try_read < DCBX_LOCAL_MIB_MAX_TRY_READ)); + + if (max_try_read >= DCBX_LOCAL_MIB_MAX_TRY_READ) { + BNX2X_ERR("MIB could not be read\n"); + return 1; + } + + return 0; +} + +static void bnx2x_pfc_set_pfc(struct bnx2x *bp) +{ + if (CHIP_IS_E2(bp)) { + if (BP_PORT(bp)) { + BNX2X_ERR("4 port mode is not supported"); + return; + } + + if (bp->dcbx_port_params.pfc.enabled) + + /* 1. Fills up common PFC structures if required.*/ + /* 2. Configure NIG, MAC and BRB via the elink: + * elink must first check if BMAC is not in reset + * and only then configures the BMAC + * Or, configure EMAC. + */ + bnx2x_pfc_set(bp); + + else + bnx2x_pfc_clear(bp); + } +} + +static void bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp) +{ + DP(NETIF_MSG_LINK, "sending STOP TRAFFIC\n"); + bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STOP_TRAFFIC, + 0 /* connectionless */, + 0 /* dataHi is zero */, + 0 /* dataLo is zero */, + 1 /* common */); +} + +static void bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp) +{ + bnx2x_pfc_fw_struct_e2(bp); + DP(NETIF_MSG_LINK, "sending START TRAFFIC\n"); + bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, + 0, /* connectionless */ + U64_HI(bnx2x_sp_mapping(bp, pfc_config)), + U64_LO(bnx2x_sp_mapping(bp, pfc_config)), + 1 /* commmon */); +} + +static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp) +{ + struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets); + u8 status = 0; + + bnx2x_ets_disabled(&bp->link_params); + + if (!ets->enabled) + return; + + if ((ets->num_of_cos == 0) || (ets->num_of_cos > E2_NUM_OF_COS)) { + BNX2X_ERR("illegal num of cos= %x", ets->num_of_cos); + return; + } + + /* valid COS entries */ + if (ets->num_of_cos == 1) /* no ETS */ + return; + + /* sanity */ + if (((BNX2X_DCBX_COS_NOT_STRICT == ets->cos_params[0].strict) && + (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) || + ((BNX2X_DCBX_COS_NOT_STRICT == ets->cos_params[1].strict) && + (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) { + BNX2X_ERR("all COS should have at least bw_limit or strict" + "ets->cos_params[0].strict= %x" + "ets->cos_params[0].bw_tbl= %x" + "ets->cos_params[1].strict= %x" + "ets->cos_params[1].bw_tbl= %x", + ets->cos_params[0].strict, + ets->cos_params[0].bw_tbl, + ets->cos_params[1].strict, + ets->cos_params[1].bw_tbl); + return; + } + /* If we join a group and there is bw_tbl and strict then bw rules */ + if ((DCBX_INVALID_COS_BW != ets->cos_params[0].bw_tbl) && + (DCBX_INVALID_COS_BW != ets->cos_params[1].bw_tbl)) { + u32 bw_tbl_0 = ets->cos_params[0].bw_tbl; + u32 bw_tbl_1 = ets->cos_params[1].bw_tbl; + /* Do not allow 0-100 configuration + * since PBF does not support it + * force 1-99 instead + */ + if (bw_tbl_0 == 0) { + bw_tbl_0 = 1; + bw_tbl_1 = 99; + } else if (bw_tbl_1 == 0) { + bw_tbl_1 = 1; + bw_tbl_0 = 99; + } + + bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1); + } else { + if (ets->cos_params[0].strict == BNX2X_DCBX_COS_HIGH_STRICT) + status = bnx2x_ets_strict(&bp->link_params, 0); + else if (ets->cos_params[1].strict + == BNX2X_DCBX_COS_HIGH_STRICT) + status = bnx2x_ets_strict(&bp->link_params, 1); + + if (status) + BNX2X_ERR("update_ets_params failed\n"); + } +} + +static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp) +{ + struct lldp_local_mib local_mib = {0}; + u32 dcbx_neg_res_offset = SHMEM2_RD(bp, dcbx_neg_res_offset); + int rc; + + DP(NETIF_MSG_LINK, "dcbx_neg_res_offset 0x%x\n", dcbx_neg_res_offset); + + if (SHMEM_DCBX_NEG_RES_NONE == dcbx_neg_res_offset) { + BNX2X_ERR("FW doesn't support dcbx_neg_res_offset\n"); + return -EINVAL; + } + rc = bnx2x_dcbx_read_mib(bp, (u32 *)&local_mib, dcbx_neg_res_offset, + DCBX_READ_LOCAL_MIB); + + if (rc) { + BNX2X_ERR("Faild to read local mib from FW\n"); + return rc; + } + + /* save features and error */ + bp->dcbx_local_feat = local_mib.features; + bp->dcbx_error = local_mib.error; + return 0; +} + +void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) +{ + switch (state) { + case BNX2X_DCBX_STATE_NEG_RECEIVED: + { + DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n"); + + /* Read neg results if dcbx is in the FW */ + if (bnx2x_dcbx_read_shmem_neg_results(bp)) + return; + + bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat, + bp->dcbx_error); + + bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat, + bp->dcbx_error); + + if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) { + bnx2x_dcbx_stop_hw_tx(bp); + return; + } + /* fall through */ + } + case BNX2X_DCBX_STATE_TX_PAUSED: + DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_PAUSED\n"); + bnx2x_pfc_set_pfc(bp); + + bnx2x_dcbx_update_ets_params(bp); + if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) { + bnx2x_dcbx_resume_hw_tx(bp); + return; + } + /* fall through */ + case BNX2X_DCBX_STATE_TX_RELEASED: + DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_RELEASED\n"); + if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) + bnx2x_fw_command(bp, DRV_MSG_CODE_DCBX_PMF_DRV_OK, 0); + + return; + default: + BNX2X_ERR("Unknown DCBX_STATE\n"); + } +} + + +#define LLDP_STATS_OFFSET(bp) (BP_PORT(bp)*\ + sizeof(struct lldp_dcbx_stat)) + +/* calculate struct offset in array according to chip information */ +#define LLDP_PARAMS_OFFSET(bp) (BP_PORT(bp)*sizeof(struct lldp_params)) + +#define LLDP_ADMIN_MIB_OFFSET(bp) (PORT_MAX*sizeof(struct lldp_params) + \ + BP_PORT(bp)*sizeof(struct lldp_admin_mib)) + +static void bnx2x_dcbx_lldp_updated_params(struct bnx2x *bp, + u32 dcbx_lldp_params_offset) +{ + struct lldp_params lldp_params = {0}; + u32 i = 0, *buff = NULL; + u32 offset = dcbx_lldp_params_offset + LLDP_PARAMS_OFFSET(bp); + + DP(NETIF_MSG_LINK, "lldp_offset 0x%x\n", offset); + + if ((bp->lldp_config_params.overwrite_settings == + BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE)) { + /* Read the data first */ + buff = (u32 *)&lldp_params; + for (i = 0; i < sizeof(struct lldp_params); i += 4, buff++) + *buff = REG_RD(bp, (offset + i)); + + lldp_params.msg_tx_hold = + (u8)bp->lldp_config_params.msg_tx_hold; + lldp_params.msg_fast_tx_interval = + (u8)bp->lldp_config_params.msg_fast_tx; + lldp_params.tx_crd_max = + (u8)bp->lldp_config_params.tx_credit_max; + lldp_params.msg_tx_interval = + (u8)bp->lldp_config_params.msg_tx_interval; + lldp_params.tx_fast = + (u8)bp->lldp_config_params.tx_fast; + + /* Write the data.*/ + buff = (u32 *)&lldp_params; + for (i = 0; i < sizeof(struct lldp_params); i += 4, buff++) + REG_WR(bp, (offset + i) , *buff); + + + } else if (BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE == + bp->lldp_config_params.overwrite_settings) + bp->lldp_config_params.overwrite_settings = + BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID; +} + +static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp, + u32 dcbx_lldp_params_offset) +{ + struct lldp_admin_mib admin_mib; + u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0; + u32 *buff; + u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp); + + /*shortcuts*/ + struct dcbx_features *af = &admin_mib.features; + struct bnx2x_config_dcbx_params *dp = &bp->dcbx_config_params; + + memset(&admin_mib, 0, sizeof(struct lldp_admin_mib)); + buff = (u32 *)&admin_mib; + /* Read the data first */ + for (i = 0; i < sizeof(struct lldp_admin_mib); i += 4, buff++) + *buff = REG_RD(bp, (offset + i)); + + if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED); + + if ((BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE == + dp->overwrite_settings)) { + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_CEE_VERSION_MASK); + admin_mib.ver_cfg_flags |= + (dp->admin_dcbx_version << DCBX_CEE_VERSION_SHIFT) & + DCBX_CEE_VERSION_MASK; + + af->ets.enabled = (u8)dp->admin_ets_enable; + + af->pfc.enabled = (u8)dp->admin_pfc_enable; + + /* FOR IEEE dp->admin_tc_supported_tx_enable */ + if (dp->admin_ets_configuration_tx_enable) + SET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_ETS_CONFIG_TX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_ETS_CONFIG_TX_ENABLED); + /* For IEEE admin_ets_recommendation_tx_enable */ + if (dp->admin_pfc_tx_enable) + SET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_PFC_CONFIG_TX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_PFC_CONFIG_TX_ENABLED); + + if (dp->admin_application_priority_tx_enable) + SET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_APP_CONFIG_TX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_APP_CONFIG_TX_ENABLED); + + if (dp->admin_ets_willing) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING); + /* For IEEE admin_ets_reco_valid */ + if (dp->admin_pfc_willing) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING); + + if (dp->admin_app_priority_willing) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING); + + for (i = 0 ; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) { + DCBX_PG_BW_SET(af->ets.pg_bw_tbl, i, + (u8)dp->admin_configuration_bw_precentage[i]); + + DP(NETIF_MSG_LINK, "pg_bw_tbl[%d] = %02x\n", + i, DCBX_PG_BW_GET(af->ets.pg_bw_tbl, i)); + } + + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) { + DCBX_PRI_PG_SET(af->ets.pri_pg_tbl, i, + (u8)dp->admin_configuration_ets_pg[i]); + + DP(NETIF_MSG_LINK, "pri_pg_tbl[%d] = %02x\n", + i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i)); + } + + /*For IEEE admin_recommendation_bw_precentage + *For IEEE admin_recommendation_ets_pg */ + af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap; + for (i = 0; i < 4; i++) { + if (dp->admin_priority_app_table[i].valid) { + struct bnx2x_admin_priority_app_table *table = + dp->admin_priority_app_table; + if ((ETH_TYPE_FCOE == table[i].app_id) && + (TRAFFIC_TYPE_ETH == table[i].traffic_type)) + traf_type = FCOE_APP_IDX; + else if ((TCP_PORT_ISCSI == table[i].app_id) && + (TRAFFIC_TYPE_PORT == table[i].traffic_type)) + traf_type = ISCSI_APP_IDX; + else + traf_type = other_traf_type++; + + af->app.app_pri_tbl[traf_type].app_id = + table[i].app_id; + + af->app.app_pri_tbl[traf_type].pri_bitmap = + (u8)(1 << table[i].priority); + + af->app.app_pri_tbl[traf_type].appBitfield = + (DCBX_APP_ENTRY_VALID); + + af->app.app_pri_tbl[traf_type].appBitfield |= + (TRAFFIC_TYPE_ETH == table[i].traffic_type) ? + DCBX_APP_SF_ETH_TYPE : DCBX_APP_SF_PORT; + } + } + + af->app.default_pri = (u8)dp->admin_default_priority; + + } else if (BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE == + dp->overwrite_settings) + dp->overwrite_settings = BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID; + + /* Write the data. */ + buff = (u32 *)&admin_mib; + for (i = 0; i < sizeof(struct lldp_admin_mib); i += 4, buff++) + REG_WR(bp, (offset + i), *buff); +} + +void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled) +{ + if (CHIP_IS_E2(bp) && !CHIP_MODE_IS_4_PORT(bp)) { + bp->dcb_state = dcb_on; + bp->dcbx_enabled = dcbx_enabled; + } else { + bp->dcb_state = false; + bp->dcbx_enabled = BNX2X_DCBX_ENABLED_INVALID; + } + DP(NETIF_MSG_LINK, "DCB state [%s:%s]\n", + dcb_on ? "ON" : "OFF", + dcbx_enabled == BNX2X_DCBX_ENABLED_OFF ? "user-mode" : + dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF ? "on-chip static" : + dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON ? + "on-chip with negotiation" : "invalid"); +} + +void bnx2x_dcbx_init_params(struct bnx2x *bp) +{ + bp->dcbx_config_params.admin_dcbx_version = 0x0; /* 0 - CEE; 1 - IEEE */ + bp->dcbx_config_params.admin_ets_willing = 1; + bp->dcbx_config_params.admin_pfc_willing = 1; + bp->dcbx_config_params.overwrite_settings = 1; + bp->dcbx_config_params.admin_ets_enable = 1; + bp->dcbx_config_params.admin_pfc_enable = 1; + bp->dcbx_config_params.admin_tc_supported_tx_enable = 1; + bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; + bp->dcbx_config_params.admin_pfc_tx_enable = 1; + bp->dcbx_config_params.admin_application_priority_tx_enable = 1; + bp->dcbx_config_params.admin_ets_reco_valid = 1; + bp->dcbx_config_params.admin_app_priority_willing = 1; + bp->dcbx_config_params.admin_configuration_bw_precentage[0] = 00; + bp->dcbx_config_params.admin_configuration_bw_precentage[1] = 50; + bp->dcbx_config_params.admin_configuration_bw_precentage[2] = 50; + bp->dcbx_config_params.admin_configuration_bw_precentage[3] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[4] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[5] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[6] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[7] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[0] = 1; + bp->dcbx_config_params.admin_configuration_ets_pg[1] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[2] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[3] = 2; + bp->dcbx_config_params.admin_configuration_ets_pg[4] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[5] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[6] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[7] = 0; + bp->dcbx_config_params.admin_recommendation_bw_precentage[0] = 0; + bp->dcbx_config_params.admin_recommendation_bw_precentage[1] = 1; + bp->dcbx_config_params.admin_recommendation_bw_precentage[2] = 2; + bp->dcbx_config_params.admin_recommendation_bw_precentage[3] = 0; + bp->dcbx_config_params.admin_recommendation_bw_precentage[4] = 7; + bp->dcbx_config_params.admin_recommendation_bw_precentage[5] = 5; + bp->dcbx_config_params.admin_recommendation_bw_precentage[6] = 6; + bp->dcbx_config_params.admin_recommendation_bw_precentage[7] = 7; + bp->dcbx_config_params.admin_recommendation_ets_pg[0] = 0; + bp->dcbx_config_params.admin_recommendation_ets_pg[1] = 1; + bp->dcbx_config_params.admin_recommendation_ets_pg[2] = 2; + bp->dcbx_config_params.admin_recommendation_ets_pg[3] = 3; + bp->dcbx_config_params.admin_recommendation_ets_pg[4] = 4; + bp->dcbx_config_params.admin_recommendation_ets_pg[5] = 5; + bp->dcbx_config_params.admin_recommendation_ets_pg[6] = 6; + bp->dcbx_config_params.admin_recommendation_ets_pg[7] = 7; + bp->dcbx_config_params.admin_pfc_bitmap = 0x8; /* FCoE(3) enable */ + bp->dcbx_config_params.admin_priority_app_table[0].valid = 1; + bp->dcbx_config_params.admin_priority_app_table[1].valid = 1; + bp->dcbx_config_params.admin_priority_app_table[2].valid = 0; + bp->dcbx_config_params.admin_priority_app_table[3].valid = 0; + bp->dcbx_config_params.admin_priority_app_table[0].priority = 3; + bp->dcbx_config_params.admin_priority_app_table[1].priority = 0; + bp->dcbx_config_params.admin_priority_app_table[2].priority = 0; + bp->dcbx_config_params.admin_priority_app_table[3].priority = 0; + bp->dcbx_config_params.admin_priority_app_table[0].traffic_type = 0; + bp->dcbx_config_params.admin_priority_app_table[1].traffic_type = 1; + bp->dcbx_config_params.admin_priority_app_table[2].traffic_type = 0; + bp->dcbx_config_params.admin_priority_app_table[3].traffic_type = 0; + bp->dcbx_config_params.admin_priority_app_table[0].app_id = 0x8906; + bp->dcbx_config_params.admin_priority_app_table[1].app_id = 3260; + bp->dcbx_config_params.admin_priority_app_table[2].app_id = 0; + bp->dcbx_config_params.admin_priority_app_table[3].app_id = 0; + bp->dcbx_config_params.admin_default_priority = + bp->dcbx_config_params.admin_priority_app_table[1].priority; +} + +void bnx2x_dcbx_init(struct bnx2x *bp) +{ + u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE; + + if (bp->dcbx_enabled <= 0) + return; + + /* validate: + * chip of good for dcbx version, + * dcb is wanted + * the function is pmf + * shmem2 contains DCBX support fields + */ + DP(NETIF_MSG_LINK, "dcb_state %d bp->port.pmf %d\n", + bp->dcb_state, bp->port.pmf); + + if (bp->dcb_state == BNX2X_DCB_STATE_ON && bp->port.pmf && + SHMEM2_HAS(bp, dcbx_lldp_params_offset)) { + dcbx_lldp_params_offset = + SHMEM2_RD(bp, dcbx_lldp_params_offset); + + DP(NETIF_MSG_LINK, "dcbx_lldp_params_offset 0x%x\n", + dcbx_lldp_params_offset); + + if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) { + bnx2x_dcbx_lldp_updated_params(bp, + dcbx_lldp_params_offset); + + bnx2x_dcbx_admin_mib_updated_params(bp, + dcbx_lldp_params_offset); + + /* set default configuration BC has */ + bnx2x_dcbx_set_params(bp, + BNX2X_DCBX_STATE_NEG_RECEIVED); + + bnx2x_fw_command(bp, + DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG, 0); + } + } +} + +void bnx2x_dcb_init_intmem_pfc(struct bnx2x *bp) +{ + struct priority_cos pricos[MAX_PFC_TRAFFIC_TYPES]; + u32 i = 0, addr; + memset(pricos, 0, sizeof(pricos)); + /* Default initialization */ + for (i = 0; i < MAX_PFC_TRAFFIC_TYPES; i++) + pricos[i].priority = LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED; + + /* Store per port struct to internal memory */ + addr = BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(BP_PORT(bp)) + + offsetof(struct cmng_struct_per_port, + traffic_type_to_priority_cos); + __storm_memset_struct(bp, addr, sizeof(pricos), (u32 *)pricos); + + + /* LLFC disabled.*/ + REG_WR8(bp , BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(BP_PORT(bp)) + + offsetof(struct cmng_struct_per_port, llfc_mode), + LLFC_MODE_NONE); + + /* DCBX disabled.*/ + REG_WR8(bp , BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(BP_PORT(bp)) + + offsetof(struct cmng_struct_per_port, dcb_enabled), + DCB_DISABLED); +} + +static void +bnx2x_dcbx_print_cos_params(struct bnx2x *bp, + struct flow_control_configuration *pfc_fw_cfg) +{ + u8 pri = 0; + u8 cos = 0; + + DP(NETIF_MSG_LINK, + "pfc_fw_cfg->dcb_version %x\n", pfc_fw_cfg->dcb_version); + DP(NETIF_MSG_LINK, + "pdev->params.dcbx_port_params.pfc." + "priority_non_pauseable_mask %x\n", + bp->dcbx_port_params.pfc.priority_non_pauseable_mask); + + for (cos = 0 ; cos < bp->dcbx_port_params.ets.num_of_cos ; cos++) { + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].pri_bitmask %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask); + + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].bw_tbl %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].bw_tbl); + + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].strict %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].strict); + + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].pauseable %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].pauseable); + } + + for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) { + DP(NETIF_MSG_LINK, + "pfc_fw_cfg->traffic_type_to_priority_cos[%d]." + "priority %x\n", pri, + pfc_fw_cfg->traffic_type_to_priority_cos[pri].priority); + + DP(NETIF_MSG_LINK, + "pfc_fw_cfg->traffic_type_to_priority_cos[%d].cos %x\n", + pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].cos); + } +} + +/* fills help_data according to pg_info */ +static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, + u32 *pg_pri_orginal_spread, + struct pg_help_data *help_data) +{ + bool pg_found = false; + u32 i, traf_type, add_traf_type, add_pg; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + struct pg_entry_help_data *data = help_data->data; /*shotcut*/ + + /* Set to invalid */ + for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) + data[i].pg = DCBX_ILLEGAL_PG; + + for (add_traf_type = 0; + add_traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; add_traf_type++) { + pg_found = false; + if (ttp[add_traf_type] < MAX_PFC_PRIORITIES) { + add_pg = (u8)pg_pri_orginal_spread[ttp[add_traf_type]]; + for (traf_type = 0; + traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; + traf_type++) { + if (data[traf_type].pg == add_pg) { + if (!(data[traf_type].pg_priority & + (1 << ttp[add_traf_type]))) + data[traf_type]. + num_of_dif_pri++; + data[traf_type].pg_priority |= + (1 << ttp[add_traf_type]); + pg_found = true; + break; + } + } + if (false == pg_found) { + data[help_data->num_of_pg].pg = add_pg; + data[help_data->num_of_pg].pg_priority = + (1 << ttp[add_traf_type]); + data[help_data->num_of_pg].num_of_dif_pri = 1; + help_data->num_of_pg++; + } + } + DP(NETIF_MSG_LINK, + "add_traf_type %d pg_found %s num_of_pg %d\n", + add_traf_type, (false == pg_found) ? "NO" : "YES", + help_data->num_of_pg); + } +} + + +/******************************************************************************* + * Description: single priority group + * + * Return: + ******************************************************************************/ +static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp, + struct cos_help_data *cos_data, + u32 pri_join_mask) +{ + /* Only one priority than only one COS */ + cos_data->data[0].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + cos_data->data[0].pri_join_mask = pri_join_mask; + cos_data->data[0].cos_bw = 100; + cos_data->num_of_cos = 1; +} + +/******************************************************************************* + * Description: updating the cos bw + * + * Return: + ******************************************************************************/ +static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp, + struct cos_entry_help_data *data, + u8 pg_bw) +{ + if (data->cos_bw == DCBX_INVALID_COS_BW) + data->cos_bw = pg_bw; + else + data->cos_bw += pg_bw; +} + +/******************************************************************************* + * Description: single priority group + * + * Return: + ******************************************************************************/ +static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + struct dcbx_ets_feature *ets) +{ + u32 pri_tested = 0; + u8 i = 0; + u8 entry = 0; + u8 pg_entry = 0; + u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX; + + cos_data->data[0].pausable = true; + cos_data->data[1].pausable = false; + cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0; + + for (i = 0 ; i < num_of_pri ; i++) { + pri_tested = 1 << bp->dcbx_port_params. + app.traffic_type_priority[i]; + + if (pri_tested & DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) { + cos_data->data[1].pri_join_mask |= pri_tested; + entry = 1; + } else { + cos_data->data[0].pri_join_mask |= pri_tested; + entry = 0; + } + pg_entry = (u8)pg_pri_orginal_spread[bp->dcbx_port_params. + app.traffic_type_priority[i]]; + /* There can be only one strict pg */ + if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) + bnx2x_dcbx_add_to_cos_bw(bp, &cos_data->data[entry], + DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry)); + else + /* If we join a group and one is strict + * than the bw rulls */ + cos_data->data[entry].strict = + BNX2X_DCBX_COS_HIGH_STRICT; + } + if ((0 == cos_data->data[0].pri_join_mask) && + (0 == cos_data->data[1].pri_join_mask)) + BNX2X_ERR("dcbx error: Both groups must have priorities\n"); +} + + +#ifndef POWER_OF_2 +#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1)))) +#endif + +static void bxn2x_dcbx_single_pg_to_cos_params(struct bnx2x *bp, + struct pg_help_data *pg_help_data, + struct cos_help_data *cos_data, + u32 pri_join_mask, + u8 num_of_dif_pri) +{ + u8 i = 0; + u32 pri_tested = 0; + u32 pri_mask_without_pri = 0; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + /*debug*/ + if (num_of_dif_pri == 1) { + bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, pri_join_mask); + return; + } + /* single priority group */ + if (pg_help_data->data[0].pg < DCBX_MAX_NUM_PG_BW_ENTRIES) { + /* If there are both pauseable and non-pauseable priorities, + * the pauseable priorities go to the first queue and + * the non-pauseable priorities go to the second queue. + */ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { + /* Pauseable */ + cos_data->data[0].pausable = true; + /* Non pauseable.*/ + cos_data->data[1].pausable = false; + + if (2 == num_of_dif_pri) { + cos_data->data[0].cos_bw = 50; + cos_data->data[1].cos_bw = 50; + } + + if (3 == num_of_dif_pri) { + if (POWER_OF_2(DCBX_PFC_PRI_GET_PAUSE(bp, + pri_join_mask))) { + cos_data->data[0].cos_bw = 33; + cos_data->data[1].cos_bw = 67; + } else { + cos_data->data[0].cos_bw = 67; + cos_data->data[1].cos_bw = 33; + } + } + + } else if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask)) { + /* If there are only pauseable priorities, + * then one/two priorities go to the first queue + * and one priority goes to the second queue. + */ + if (2 == num_of_dif_pri) { + cos_data->data[0].cos_bw = 50; + cos_data->data[1].cos_bw = 50; + } else { + cos_data->data[0].cos_bw = 67; + cos_data->data[1].cos_bw = 33; + } + cos_data->data[1].pausable = true; + cos_data->data[0].pausable = true; + /* All priorities except FCOE */ + cos_data->data[0].pri_join_mask = (pri_join_mask & + ((u8)~(1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]))); + /* Only FCOE priority.*/ + cos_data->data[1].pri_join_mask = + (1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]); + } else + /* If there are only non-pauseable priorities, + * they will all go to the same queue. + */ + bnx2x_dcbx_ets_disabled_entry_data(bp, + cos_data, pri_join_mask); + } else { + /* priority group which is not BW limited (PG#15):*/ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { + /* If there are both pauseable and non-pauseable + * priorities, the pauseable priorities go to the first + * queue and the non-pauseable priorities + * go to the second queue. + */ + if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) > + DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) { + cos_data->data[0].strict = + BNX2X_DCBX_COS_HIGH_STRICT; + cos_data->data[1].strict = + BNX2X_DCBX_COS_LOW_STRICT; + } else { + cos_data->data[0].strict = + BNX2X_DCBX_COS_LOW_STRICT; + cos_data->data[1].strict = + BNX2X_DCBX_COS_HIGH_STRICT; + } + /* Pauseable */ + cos_data->data[0].pausable = true; + /* Non pause-able.*/ + cos_data->data[1].pausable = false; + } else { + /* If there are only pauseable priorities or + * only non-pauseable,* the lower priorities go + * to the first queue and the higherpriorities go + * to the second queue. + */ + cos_data->data[0].pausable = + cos_data->data[1].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + + for (i = 0 ; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) { + pri_tested = 1 << bp->dcbx_port_params. + app.traffic_type_priority[i]; + /* Remove priority tested */ + pri_mask_without_pri = + (pri_join_mask & ((u8)(~pri_tested))); + if (pri_mask_without_pri < pri_tested) + break; + } + + if (i == LLFC_DRIVER_TRAFFIC_TYPE_MAX) + BNX2X_ERR("Invalid value for pri_join_mask -" + " could not find a priority\n"); + + cos_data->data[0].pri_join_mask = pri_mask_without_pri; + cos_data->data[1].pri_join_mask = pri_tested; + /* Both queues are strict priority, + * and that with the highest priority + * gets the highest strict priority in the arbiter. + */ + cos_data->data[0].strict = BNX2X_DCBX_COS_LOW_STRICT; + cos_data->data[1].strict = BNX2X_DCBX_COS_HIGH_STRICT; + } + } +} + +static void bnx2x_dcbx_two_pg_to_cos_params( + struct bnx2x *bp, + struct pg_help_data *pg_help_data, + struct dcbx_ets_feature *ets, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + u32 pri_join_mask, + u8 num_of_dif_pri) +{ + u8 i = 0; + u8 pg[E2_NUM_OF_COS] = {0}; + + /* If there are both pauseable and non-pauseable priorities, + * the pauseable priorities go to the first queue and + * the non-pauseable priorities go to the second queue. + */ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, + pg_help_data->data[0].pg_priority) || + IS_DCBX_PFC_PRI_MIX_PAUSE(bp, + pg_help_data->data[1].pg_priority)) { + /* If one PG contains both pauseable and + * non-pauseable priorities then ETS is disabled. + */ + bnx2x_dcbx_separate_pauseable_from_non(bp, cos_data, + pg_pri_orginal_spread, ets); + bp->dcbx_port_params.ets.enabled = false; + return; + } + + /* Pauseable */ + cos_data->data[0].pausable = true; + /* Non pauseable. */ + cos_data->data[1].pausable = false; + if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, + pg_help_data->data[0].pg_priority)) { + /* 0 is pauseable */ + cos_data->data[0].pri_join_mask = + pg_help_data->data[0].pg_priority; + pg[0] = pg_help_data->data[0].pg; + cos_data->data[1].pri_join_mask = + pg_help_data->data[1].pg_priority; + pg[1] = pg_help_data->data[1].pg; + } else {/* 1 is pauseable */ + cos_data->data[0].pri_join_mask = + pg_help_data->data[1].pg_priority; + pg[0] = pg_help_data->data[1].pg; + cos_data->data[1].pri_join_mask = + pg_help_data->data[0].pg_priority; + pg[1] = pg_help_data->data[0].pg; + } + } else { + /* If there are only pauseable priorities or + * only non-pauseable, each PG goes to a queue. + */ + cos_data->data[0].pausable = cos_data->data[1].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + cos_data->data[0].pri_join_mask = + pg_help_data->data[0].pg_priority; + pg[0] = pg_help_data->data[0].pg; + cos_data->data[1].pri_join_mask = + pg_help_data->data[1].pg_priority; + pg[1] = pg_help_data->data[1].pg; + } + + /* There can be only one strict pg */ + for (i = 0 ; i < E2_NUM_OF_COS; i++) { + if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES) + cos_data->data[i].cos_bw = + DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]); + else + cos_data->data[i].strict = BNX2X_DCBX_COS_HIGH_STRICT; + } +} + +/******************************************************************************* + * Description: Still + * + * Return: + ******************************************************************************/ +static void bnx2x_dcbx_three_pg_to_cos_params( + struct bnx2x *bp, + struct pg_help_data *pg_help_data, + struct dcbx_ets_feature *ets, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + u32 pri_join_mask, + u8 num_of_dif_pri) +{ + u8 i = 0; + u32 pri_tested = 0; + u8 entry = 0; + u8 pg_entry = 0; + bool b_found_strict = false; + u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX; + + cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0; + /* If there are both pauseable and non-pauseable priorities, + * the pauseable priorities go to the first queue and the + * non-pauseable priorities go to the second queue. + */ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) + bnx2x_dcbx_separate_pauseable_from_non(bp, + cos_data, pg_pri_orginal_spread, ets); + else { + /* If two BW-limited PG-s were combined to one queue, + * the BW is their sum. + * + * If there are only pauseable priorities or only non-pauseable, + * and there are both BW-limited and non-BW-limited PG-s, + * the BW-limited PG/s go to one queue and the non-BW-limited + * PG/s go to the second queue. + * + * If there are only pauseable priorities or only non-pauseable + * and all are BW limited, then two priorities go to the first + * queue and one priority goes to the second queue. + * + * We will join this two cases: + * if one is BW limited it will go to the secoend queue + * otherwise the last priority will get it + */ + + cos_data->data[0].pausable = cos_data->data[1].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + + for (i = 0 ; i < num_of_pri; i++) { + pri_tested = 1 << bp->dcbx_port_params. + app.traffic_type_priority[i]; + pg_entry = (u8)pg_pri_orginal_spread[bp-> + dcbx_port_params.app.traffic_type_priority[i]]; + + if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) { + entry = 0; + + if (i == (num_of_pri-1) && + false == b_found_strict) + /* last entry will be handled separately + * If no priority is strict than last + * enty goes to last queue.*/ + entry = 1; + cos_data->data[entry].pri_join_mask |= + pri_tested; + bnx2x_dcbx_add_to_cos_bw(bp, + &cos_data->data[entry], + DCBX_PG_BW_GET(ets->pg_bw_tbl, + pg_entry)); + } else { + b_found_strict = true; + cos_data->data[1].pri_join_mask |= pri_tested; + /* If we join a group and one is strict + * than the bw rulls */ + cos_data->data[1].strict = + BNX2X_DCBX_COS_HIGH_STRICT; + } + } + } +} + + +static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp, + struct pg_help_data *help_data, + struct dcbx_ets_feature *ets, + u32 *pg_pri_orginal_spread) +{ + struct cos_help_data cos_data ; + u8 i = 0; + u32 pri_join_mask = 0; + u8 num_of_dif_pri = 0; + + memset(&cos_data, 0, sizeof(cos_data)); + /* Validate the pg value */ + for (i = 0; i < help_data->num_of_pg ; i++) { + if (DCBX_STRICT_PRIORITY != help_data->data[i].pg && + DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg) + BNX2X_ERR("Invalid pg[%d] data %x\n", i, + help_data->data[i].pg); + pri_join_mask |= help_data->data[i].pg_priority; + num_of_dif_pri += help_data->data[i].num_of_dif_pri; + } + + /* default settings */ + cos_data.num_of_cos = 2; + for (i = 0; i < E2_NUM_OF_COS ; i++) { + cos_data.data[i].pri_join_mask = pri_join_mask; + cos_data.data[i].pausable = false; + cos_data.data[i].strict = BNX2X_DCBX_COS_NOT_STRICT; + cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW; + } + + switch (help_data->num_of_pg) { + case 1: + + bxn2x_dcbx_single_pg_to_cos_params( + bp, + help_data, + &cos_data, + pri_join_mask, + num_of_dif_pri); + break; + case 2: + bnx2x_dcbx_two_pg_to_cos_params( + bp, + help_data, + ets, + &cos_data, + pg_pri_orginal_spread, + pri_join_mask, + num_of_dif_pri); + break; + + case 3: + bnx2x_dcbx_three_pg_to_cos_params( + bp, + help_data, + ets, + &cos_data, + pg_pri_orginal_spread, + pri_join_mask, + num_of_dif_pri); + + break; + default: + BNX2X_ERR("Wrong pg_help_data.num_of_pg\n"); + bnx2x_dcbx_ets_disabled_entry_data(bp, + &cos_data, pri_join_mask); + } + + for (i = 0; i < cos_data.num_of_cos ; i++) { + struct bnx2x_dcbx_cos_params *params = + &bp->dcbx_port_params.ets.cos_params[i]; + + params->pauseable = cos_data.data[i].pausable; + params->strict = cos_data.data[i].strict; + params->bw_tbl = cos_data.data[i].cos_bw; + if (params->pauseable) { + params->pri_bitmask = + DCBX_PFC_PRI_GET_PAUSE(bp, + cos_data.data[i].pri_join_mask); + DP(NETIF_MSG_LINK, "COS %d PAUSABLE prijoinmask 0x%x\n", + i, cos_data.data[i].pri_join_mask); + } else { + params->pri_bitmask = + DCBX_PFC_PRI_GET_NON_PAUSE(bp, + cos_data.data[i].pri_join_mask); + DP(NETIF_MSG_LINK, "COS %d NONPAUSABLE prijoinmask " + "0x%x\n", + i, cos_data.data[i].pri_join_mask); + } + } + + bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ; +} + +static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, + u32 *set_configuration_ets_pg, + u32 *pri_pg_tbl) +{ + int i; + + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) { + set_configuration_ets_pg[i] = DCBX_PRI_PG_GET(pri_pg_tbl, i); + + DP(NETIF_MSG_LINK, "set_configuration_ets_pg[%d] = 0x%x\n", + i, set_configuration_ets_pg[i]); + } +} + +/******************************************************************************* + * Description: Fill pfc_config struct that will be sent in DCBX start ramrod + * + * Return: + ******************************************************************************/ +static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp) +{ + struct flow_control_configuration *pfc_fw_cfg = NULL; + u16 pri_bit = 0; + u8 cos = 0, pri = 0; + struct priority_cos *tt2cos; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + + pfc_fw_cfg = (struct flow_control_configuration *) + bnx2x_sp(bp, pfc_config); + memset(pfc_fw_cfg, 0, sizeof(struct flow_control_configuration)); + + /*shortcut*/ + tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos; + + /* Fw version should be incremented each update */ + pfc_fw_cfg->dcb_version = ++bp->dcb_version; + pfc_fw_cfg->dcb_enabled = DCB_ENABLED; + + /* Default initialization */ + for (pri = 0; pri < MAX_PFC_TRAFFIC_TYPES ; pri++) { + tt2cos[pri].priority = LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED; + tt2cos[pri].cos = 0; + } + + /* Fill priority parameters */ + for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) { + tt2cos[pri].priority = ttp[pri]; + pri_bit = 1 << tt2cos[pri].priority; + + /* Fill COS parameters based on COS calculated to + * make it more generally for future use */ + for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) + if (bp->dcbx_port_params.ets.cos_params[cos]. + pri_bitmask & pri_bit) + tt2cos[pri].cos = cos; + } + bnx2x_dcbx_print_cos_params(bp, pfc_fw_cfg); +} +/* DCB netlink */ +#ifdef BCM_DCB +#include <linux/dcbnl.h> + +#define BNX2X_DCBX_CAPS (DCB_CAP_DCBX_LLD_MANAGED | \ + DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_STATIC) + +static inline bool bnx2x_dcbnl_set_valid(struct bnx2x *bp) +{ + /* validate dcbnl call that may change HW state: + * DCB is on and DCBX mode was SUCCESSFULLY set by the user. + */ + return bp->dcb_state && bp->dcbx_mode_uset; +} + +static u8 bnx2x_dcbnl_get_state(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %d\n", bp->dcb_state); + return bp->dcb_state; +} + +static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off"); + + bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled); + return 0; +} + +static void bnx2x_dcbnl_get_perm_hw_addr(struct net_device *netdev, + u8 *perm_addr) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "GET-PERM-ADDR\n"); + + /* first the HW mac address */ + memcpy(perm_addr, netdev->dev_addr, netdev->addr_len); + +#ifdef BCM_CNIC + /* second SAN address */ + memcpy(perm_addr+netdev->addr_len, bp->fip_mac, netdev->addr_len); +#endif +} + +static void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio, + u8 prio_type, u8 pgid, u8 bw_pct, + u8 up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, pgid); + if (!bnx2x_dcbnl_set_valid(bp) || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES) + return; + + /** + * bw_pct ingnored - band-width percentage devision between user + * priorities within the same group is not + * standard and hence not supported + * + * prio_type igonred - priority levels within the same group are not + * standard and hence are not supported. According + * to the standard pgid 15 is dedicated to strict + * prioirty traffic (on the port level). + * + * up_map ignored + */ + + bp->dcbx_config_params.admin_configuration_ets_pg[prio] = pgid; + bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; +} + +static void bnx2x_dcbnl_set_pg_bwgcfg_tx(struct net_device *netdev, + int pgid, u8 bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "pgid[%d] = %d\n", pgid, bw_pct); + + if (!bnx2x_dcbnl_set_valid(bp) || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES) + return; + + bp->dcbx_config_params.admin_configuration_bw_precentage[pgid] = bw_pct; + bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; +} + +static void bnx2x_dcbnl_set_pg_tccfg_rx(struct net_device *netdev, int prio, + u8 prio_type, u8 pgid, u8 bw_pct, + u8 up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n"); +} + +static void bnx2x_dcbnl_set_pg_bwgcfg_rx(struct net_device *netdev, + int pgid, u8 bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n"); +} + +static void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio, + u8 *prio_type, u8 *pgid, u8 *bw_pct, + u8 *up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "prio = %d\n", prio); + + /** + * bw_pct ingnored - band-width percentage devision between user + * priorities within the same group is not + * standard and hence not supported + * + * prio_type igonred - priority levels within the same group are not + * standard and hence are not supported. According + * to the standard pgid 15 is dedicated to strict + * prioirty traffic (on the port level). + * + * up_map ignored + */ + *up_map = *bw_pct = *prio_type = *pgid = 0; + + if (!bp->dcb_state || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES) + return; + + *pgid = DCBX_PRI_PG_GET(bp->dcbx_local_feat.ets.pri_pg_tbl, prio); +} + +static void bnx2x_dcbnl_get_pg_bwgcfg_tx(struct net_device *netdev, + int pgid, u8 *bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "pgid = %d\n", pgid); + + *bw_pct = 0; + + if (!bp->dcb_state || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES) + return; + + *bw_pct = DCBX_PG_BW_GET(bp->dcbx_local_feat.ets.pg_bw_tbl, pgid); +} + +static void bnx2x_dcbnl_get_pg_tccfg_rx(struct net_device *netdev, int prio, + u8 *prio_type, u8 *pgid, u8 *bw_pct, + u8 *up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n"); + + *prio_type = *pgid = *bw_pct = *up_map = 0; +} + +static void bnx2x_dcbnl_get_pg_bwgcfg_rx(struct net_device *netdev, + int pgid, u8 *bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n"); + + *bw_pct = 0; +} + +static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, + u8 setting) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, setting); + + if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES) + return; + + bp->dcbx_config_params.admin_pfc_bitmap |= ((setting ? 1 : 0) << prio); + + if (setting) + bp->dcbx_config_params.admin_pfc_tx_enable = 1; +} + +static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio, + u8 *setting) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "prio = %d\n", prio); + + *setting = 0; + + if (!bp->dcb_state || prio >= MAX_PFC_PRIORITIES) + return; + + *setting = (bp->dcbx_local_feat.pfc.pri_en_bitmap >> prio) & 0x1; +} + +static u8 bnx2x_dcbnl_set_all(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + int rc = 0; + + DP(NETIF_MSG_LINK, "SET-ALL\n"); + + if (!bnx2x_dcbnl_set_valid(bp)) + return 1; + + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { + netdev_err(bp->dev, "Handling parity error recovery. " + "Try again later\n"); + return 1; + } + if (netif_running(bp->dev)) { + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + rc = bnx2x_nic_load(bp, LOAD_NORMAL); + } + DP(NETIF_MSG_LINK, "set_dcbx_params done (%d)\n", rc); + if (rc) + return 1; + + return 0; +} + +static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + if (bp->dcb_state) { + switch (capid) { + case DCB_CAP_ATTR_PG: + *cap = true; + break; + case DCB_CAP_ATTR_PFC: + *cap = true; + break; + case DCB_CAP_ATTR_UP2TC: + *cap = false; + break; + case DCB_CAP_ATTR_PG_TCS: + *cap = 0x80; /* 8 priorities for PGs */ + break; + case DCB_CAP_ATTR_PFC_TCS: + *cap = 0x80; /* 8 priorities for PFC */ + break; + case DCB_CAP_ATTR_GSP: + *cap = true; + break; + case DCB_CAP_ATTR_BCN: + *cap = false; + break; + case DCB_CAP_ATTR_DCBX: + *cap = BNX2X_DCBX_CAPS; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + DP(NETIF_MSG_LINK, "capid %d:%x\n", capid, *cap); + return rval; +} + +static u8 bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + DP(NETIF_MSG_LINK, "tcid %d\n", tcid); + + if (bp->dcb_state) { + switch (tcid) { + case DCB_NUMTCS_ATTR_PG: + *num = E2_NUM_OF_COS; + break; + case DCB_NUMTCS_ATTR_PFC: + *num = E2_NUM_OF_COS; + break; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + return rval; +} + +static u8 bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "num tcs = %d; Not supported\n", num); + return -EINVAL; +} + +static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %d\n", bp->dcbx_local_feat.pfc.enabled); + + if (!bp->dcb_state) + return 0; + + return bp->dcbx_local_feat.pfc.enabled; +} + +static void bnx2x_dcbnl_set_pfc_state(struct net_device *netdev, u8 state) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off"); + + if (!bnx2x_dcbnl_set_valid(bp)) + return; + + bp->dcbx_config_params.admin_pfc_tx_enable = + bp->dcbx_config_params.admin_pfc_enable = (state ? 1 : 0); +} + +static bool bnx2x_app_is_equal(struct dcbx_app_priority_entry *app_ent, + u8 idtype, u16 idval) +{ + if (!(app_ent->appBitfield & DCBX_APP_ENTRY_VALID)) + return false; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: + if ((app_ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) != + DCBX_APP_SF_ETH_TYPE) + return false; + break; + case DCB_APP_IDTYPE_PORTNUM: + if ((app_ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) != + DCBX_APP_SF_PORT) + return false; + break; + default: + return false; + } + if (app_ent->app_id != idval) + return false; + + return true; +} + +static void bnx2x_admin_app_set_ent( + struct bnx2x_admin_priority_app_table *app_ent, + u8 idtype, u16 idval, u8 up) +{ + app_ent->valid = 1; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: + app_ent->traffic_type = TRAFFIC_TYPE_ETH; + break; + case DCB_APP_IDTYPE_PORTNUM: + app_ent->traffic_type = TRAFFIC_TYPE_PORT; + break; + default: + break; /* never gets here */ + } + app_ent->app_id = idval; + app_ent->priority = up; +} + +static bool bnx2x_admin_app_is_equal( + struct bnx2x_admin_priority_app_table *app_ent, + u8 idtype, u16 idval) +{ + if (!app_ent->valid) + return false; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: + if (app_ent->traffic_type != TRAFFIC_TYPE_ETH) + return false; + break; + case DCB_APP_IDTYPE_PORTNUM: + if (app_ent->traffic_type != TRAFFIC_TYPE_PORT) + return false; + break; + default: + return false; + } + if (app_ent->app_id != idval) + return false; + + return true; +} + +static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up) +{ + int i, ff; + + /* iterate over the app entries looking for idtype and idval */ + for (i = 0, ff = -1; i < 4; i++) { + struct bnx2x_admin_priority_app_table *app_ent = + &bp->dcbx_config_params.admin_priority_app_table[i]; + if (bnx2x_admin_app_is_equal(app_ent, idtype, idval)) + break; + + if (ff < 0 && !app_ent->valid) + ff = i; + } + if (i < 4) + /* if found overwrite up */ + bp->dcbx_config_params. + admin_priority_app_table[i].priority = up; + else if (ff >= 0) + /* not found use first-free */ + bnx2x_admin_app_set_ent( + &bp->dcbx_config_params.admin_priority_app_table[ff], + idtype, idval, up); + else + /* app table is full */ + return -EBUSY; + + /* up configured, if not 0 make sure feature is enabled */ + if (up) + bp->dcbx_config_params.admin_application_priority_tx_enable = 1; + + return 0; +} + +static u8 bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype, + u16 idval, u8 up) +{ + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "app_type %d, app_id %x, prio bitmap %d\n", + idtype, idval, up); + + if (!bnx2x_dcbnl_set_valid(bp)) + return -EINVAL; + + /* verify idtype */ + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: + case DCB_APP_IDTYPE_PORTNUM: + break; + default: + return -EINVAL; + } + return bnx2x_set_admin_app_up(bp, idtype, idval, up); +} + +static u8 bnx2x_dcbnl_get_app_up(struct net_device *netdev, u8 idtype, + u16 idval) +{ + int i; + u8 up = 0; + + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "app_type %d, app_id 0x%x\n", idtype, idval); + + /* iterate over the app entries looking for idtype and idval */ + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) + if (bnx2x_app_is_equal(&bp->dcbx_local_feat.app.app_pri_tbl[i], + idtype, idval)) + break; + + if (i < DCBX_MAX_APP_PROTOCOL) + /* if found return up */ + up = bp->dcbx_local_feat.app.app_pri_tbl[i].pri_bitmap; + else + DP(NETIF_MSG_LINK, "app not found\n"); + + return up; +} + +static u8 bnx2x_dcbnl_get_dcbx(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 state; + + state = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE; + + if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF) + state |= DCB_CAP_DCBX_STATIC; + + return state; +} + +static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %02x\n", state); + + /* set dcbx mode */ + + if ((state & BNX2X_DCBX_CAPS) != state) { + BNX2X_ERR("Requested DCBX mode %x is beyond advertised " + "capabilities\n", state); + return 1; + } + + if (bp->dcb_state != BNX2X_DCB_STATE_ON) { + BNX2X_ERR("DCB turned off, DCBX configuration is invalid\n"); + return 1; + } + + if (state & DCB_CAP_DCBX_STATIC) + bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_OFF; + else + bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_ON; + + bp->dcbx_mode_uset = true; + return 0; +} + + +static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, + u8 *flags) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + DP(NETIF_MSG_LINK, "featid %d\n", featid); + + if (bp->dcb_state) { + *flags = 0; + switch (featid) { + case DCB_FEATCFG_ATTR_PG: + if (bp->dcbx_local_feat.ets.enabled) + *flags |= DCB_FEATCFG_ENABLE; + if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR) + *flags |= DCB_FEATCFG_ERROR; + break; + case DCB_FEATCFG_ATTR_PFC: + if (bp->dcbx_local_feat.pfc.enabled) + *flags |= DCB_FEATCFG_ENABLE; + if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR | + DCBX_LOCAL_PFC_MISMATCH)) + *flags |= DCB_FEATCFG_ERROR; + break; + case DCB_FEATCFG_ATTR_APP: + if (bp->dcbx_local_feat.app.enabled) + *flags |= DCB_FEATCFG_ENABLE; + if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR | + DCBX_LOCAL_APP_MISMATCH)) + *flags |= DCB_FEATCFG_ERROR; + break; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + return rval; +} + +static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid, + u8 flags) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + DP(NETIF_MSG_LINK, "featid = %d flags = %02x\n", featid, flags); + + /* ignore the 'advertise' flag */ + if (bnx2x_dcbnl_set_valid(bp)) { + switch (featid) { + case DCB_FEATCFG_ATTR_PG: + bp->dcbx_config_params.admin_ets_enable = + flags & DCB_FEATCFG_ENABLE ? 1 : 0; + bp->dcbx_config_params.admin_ets_willing = + flags & DCB_FEATCFG_WILLING ? 1 : 0; + break; + case DCB_FEATCFG_ATTR_PFC: + bp->dcbx_config_params.admin_pfc_enable = + flags & DCB_FEATCFG_ENABLE ? 1 : 0; + bp->dcbx_config_params.admin_pfc_willing = + flags & DCB_FEATCFG_WILLING ? 1 : 0; + break; + case DCB_FEATCFG_ATTR_APP: + /* ignore enable, always enabled */ + bp->dcbx_config_params.admin_app_priority_willing = + flags & DCB_FEATCFG_WILLING ? 1 : 0; + break; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + return rval; +} + +const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = { + .getstate = bnx2x_dcbnl_get_state, + .setstate = bnx2x_dcbnl_set_state, + .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr, + .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx, + .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx, + .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx, + .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx, + .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx, + .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx, + .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx, + .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx, + .setpfccfg = bnx2x_dcbnl_set_pfc_cfg, + .getpfccfg = bnx2x_dcbnl_get_pfc_cfg, + .setall = bnx2x_dcbnl_set_all, + .getcap = bnx2x_dcbnl_get_cap, + .getnumtcs = bnx2x_dcbnl_get_numtcs, + .setnumtcs = bnx2x_dcbnl_set_numtcs, + .getpfcstate = bnx2x_dcbnl_get_pfc_state, + .setpfcstate = bnx2x_dcbnl_set_pfc_state, + .getapp = bnx2x_dcbnl_get_app_up, + .setapp = bnx2x_dcbnl_set_app_up, + .getdcbx = bnx2x_dcbnl_get_dcbx, + .setdcbx = bnx2x_dcbnl_set_dcbx, + .getfeatcfg = bnx2x_dcbnl_get_featcfg, + .setfeatcfg = bnx2x_dcbnl_set_featcfg, +}; + +#endif /* BCM_DCB */ diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h new file mode 100644 index 00000000000..f650f98e409 --- /dev/null +++ b/drivers/net/bnx2x/bnx2x_dcb.h @@ -0,0 +1,196 @@ +/* bnx2x_dcb.h: Broadcom Everest network driver. + * + * Copyright 2009-2010 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Maintained by: Eilon Greenstein <eilong@broadcom.com> + * Written by: Dmitry Kravkov + * + */ +#ifndef BNX2X_DCB_H +#define BNX2X_DCB_H + +#include "bnx2x_hsi.h" + +#define LLFC_DRIVER_TRAFFIC_TYPE_MAX 3 /* NW, iSCSI, FCoE */ +struct bnx2x_dcbx_app_params { + u32 enabled; + u32 traffic_type_priority[LLFC_DRIVER_TRAFFIC_TYPE_MAX]; +}; + +#define E2_NUM_OF_COS 2 +#define BNX2X_DCBX_COS_NOT_STRICT 0 +#define BNX2X_DCBX_COS_LOW_STRICT 1 +#define BNX2X_DCBX_COS_HIGH_STRICT 2 + +struct bnx2x_dcbx_cos_params { + u32 bw_tbl; + u32 pri_bitmask; + u8 strict; + u8 pauseable; +}; + +struct bnx2x_dcbx_pg_params { + u32 enabled; + u8 num_of_cos; /* valid COS entries */ + struct bnx2x_dcbx_cos_params cos_params[E2_NUM_OF_COS]; +}; + +struct bnx2x_dcbx_pfc_params { + u32 enabled; + u32 priority_non_pauseable_mask; +}; + +struct bnx2x_dcbx_port_params { + struct bnx2x_dcbx_pfc_params pfc; + struct bnx2x_dcbx_pg_params ets; + struct bnx2x_dcbx_app_params app; +}; + +#define BNX2X_DCBX_CONFIG_INV_VALUE (0xFFFFFFFF) +#define BNX2X_DCBX_OVERWRITE_SETTINGS_DISABLE 0 +#define BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE 1 +#define BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID (BNX2X_DCBX_CONFIG_INV_VALUE) + +/******************************************************************************* + * LLDP protocol configuration parameters. + ******************************************************************************/ +struct bnx2x_config_lldp_params { + u32 overwrite_settings; + u32 msg_tx_hold; + u32 msg_fast_tx; + u32 tx_credit_max; + u32 msg_tx_interval; + u32 tx_fast; +}; + +struct bnx2x_admin_priority_app_table { + u32 valid; + u32 priority; +#define INVALID_TRAFFIC_TYPE_PRIORITY (0xFFFFFFFF) + u32 traffic_type; +#define TRAFFIC_TYPE_ETH 0 +#define TRAFFIC_TYPE_PORT 1 + u32 app_id; +}; + +/******************************************************************************* + * DCBX protocol configuration parameters. + ******************************************************************************/ +struct bnx2x_config_dcbx_params { + u32 overwrite_settings; + u32 admin_dcbx_version; + u32 admin_ets_enable; + u32 admin_pfc_enable; + u32 admin_tc_supported_tx_enable; + u32 admin_ets_configuration_tx_enable; + u32 admin_ets_recommendation_tx_enable; + u32 admin_pfc_tx_enable; + u32 admin_application_priority_tx_enable; + u32 admin_ets_willing; + u32 admin_ets_reco_valid; + u32 admin_pfc_willing; + u32 admin_app_priority_willing; + u32 admin_configuration_bw_precentage[8]; + u32 admin_configuration_ets_pg[8]; + u32 admin_recommendation_bw_precentage[8]; + u32 admin_recommendation_ets_pg[8]; + u32 admin_pfc_bitmap; + struct bnx2x_admin_priority_app_table admin_priority_app_table[4]; + u32 admin_default_priority; +}; + +#define GET_FLAGS(flags, bits) ((flags) & (bits)) +#define SET_FLAGS(flags, bits) ((flags) |= (bits)) +#define RESET_FLAGS(flags, bits) ((flags) &= ~(bits)) + +enum { + DCBX_READ_LOCAL_MIB, + DCBX_READ_REMOTE_MIB +}; + +#define ETH_TYPE_FCOE (0x8906) +#define TCP_PORT_ISCSI (0xCBC) + +#define PFC_VALUE_FRAME_SIZE (512) +#define PFC_QUANTA_IN_NANOSEC_FROM_SPEED_MEGA(mega_speed) \ + ((1000 * PFC_VALUE_FRAME_SIZE)/(mega_speed)) + +#define PFC_BRB1_REG_HIGH_LLFC_LOW_THRESHOLD 130 +#define PFC_BRB1_REG_HIGH_LLFC_HIGH_THRESHOLD 170 + + + +struct cos_entry_help_data { + u32 pri_join_mask; + u32 cos_bw; + u8 strict; + bool pausable; +}; + +struct cos_help_data { + struct cos_entry_help_data data[E2_NUM_OF_COS]; + u8 num_of_cos; +}; + +#define DCBX_ILLEGAL_PG (0xFF) +#define DCBX_PFC_PRI_MASK (0xFF) +#define DCBX_STRICT_PRIORITY (15) +#define DCBX_INVALID_COS_BW (0xFFFFFFFF) +#define DCBX_PFC_PRI_NON_PAUSE_MASK(bp) \ + ((bp)->dcbx_port_params.pfc.priority_non_pauseable_mask) +#define DCBX_PFC_PRI_PAUSE_MASK(bp) \ + ((u8)~DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) +#define DCBX_PFC_PRI_GET_PAUSE(bp, pg_pri) \ + ((pg_pri) & (DCBX_PFC_PRI_PAUSE_MASK(bp))) +#define DCBX_PFC_PRI_GET_NON_PAUSE(bp, pg_pri) \ + (DCBX_PFC_PRI_NON_PAUSE_MASK(bp) & (pg_pri)) +#define IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pg_pri) \ + (pg_pri == DCBX_PFC_PRI_GET_PAUSE((bp), (pg_pri))) +#define IS_DCBX_PFC_PRI_ONLY_NON_PAUSE(bp, pg_pri)\ + ((pg_pri) == DCBX_PFC_PRI_GET_NON_PAUSE((bp), (pg_pri))) +#define IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pg_pri) \ + (!(IS_DCBX_PFC_PRI_ONLY_NON_PAUSE((bp), (pg_pri)) || \ + IS_DCBX_PFC_PRI_ONLY_PAUSE((bp), (pg_pri)))) + + +struct pg_entry_help_data { + u8 num_of_dif_pri; + u8 pg; + u32 pg_priority; +}; + +struct pg_help_data { + struct pg_entry_help_data data[LLFC_DRIVER_TRAFFIC_TYPE_MAX]; + u8 num_of_pg; +}; + +/* forward DCB/PFC related declarations */ +struct bnx2x; +void bnx2x_dcb_init_intmem_pfc(struct bnx2x *bp); +void bnx2x_dcbx_update(struct work_struct *work); +void bnx2x_dcbx_init_params(struct bnx2x *bp); +void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled); + +enum { + BNX2X_DCBX_STATE_NEG_RECEIVED = 0x1, + BNX2X_DCBX_STATE_TX_PAUSED = 0x2, + BNX2X_DCBX_STATE_TX_RELEASED = 0x4 +}; +void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state); + +/* DCB netlink */ +#ifdef BCM_DCB +extern const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops; +#endif /* BCM_DCB */ + +#endif /* BNX2X_DCB_H */ diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index d02ffbdc9f0..99c672d894c 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -25,6 +25,143 @@ #include "bnx2x_cmn.h" #include "bnx2x_dump.h" +/* Note: in the format strings below %s is replaced by the queue-name which is + * either its index or 'fcoe' for the fcoe queue. Make sure the format string + * length does not exceed ETH_GSTRING_LEN - MAX_QUEUE_NAME_LEN + 2 + */ +#define MAX_QUEUE_NAME_LEN 4 +static const struct { + long offset; + int size; + char string[ETH_GSTRING_LEN]; +} bnx2x_q_stats_arr[] = { +/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%s]: rx_bytes" }, + { Q_STATS_OFFSET32(error_bytes_received_hi), + 8, "[%s]: rx_error_bytes" }, + { Q_STATS_OFFSET32(total_unicast_packets_received_hi), + 8, "[%s]: rx_ucast_packets" }, + { Q_STATS_OFFSET32(total_multicast_packets_received_hi), + 8, "[%s]: rx_mcast_packets" }, + { Q_STATS_OFFSET32(total_broadcast_packets_received_hi), + 8, "[%s]: rx_bcast_packets" }, + { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%s]: rx_discards" }, + { Q_STATS_OFFSET32(rx_err_discard_pkt), + 4, "[%s]: rx_phy_ip_err_discards"}, + { Q_STATS_OFFSET32(rx_skb_alloc_failed), + 4, "[%s]: rx_skb_alloc_discard" }, + { Q_STATS_OFFSET32(hw_csum_err), 4, "[%s]: rx_csum_offload_errors" }, + +/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%s]: tx_bytes" }, + { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi), + 8, "[%s]: tx_ucast_packets" }, + { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi), + 8, "[%s]: tx_mcast_packets" }, + { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi), + 8, "[%s]: tx_bcast_packets" } +}; + +#define BNX2X_NUM_Q_STATS ARRAY_SIZE(bnx2x_q_stats_arr) + +static const struct { + long offset; + int size; + u32 flags; +#define STATS_FLAGS_PORT 1 +#define STATS_FLAGS_FUNC 2 +#define STATS_FLAGS_BOTH (STATS_FLAGS_FUNC | STATS_FLAGS_PORT) + char string[ETH_GSTRING_LEN]; +} bnx2x_stats_arr[] = { +/* 1 */ { STATS_OFFSET32(total_bytes_received_hi), + 8, STATS_FLAGS_BOTH, "rx_bytes" }, + { STATS_OFFSET32(error_bytes_received_hi), + 8, STATS_FLAGS_BOTH, "rx_error_bytes" }, + { STATS_OFFSET32(total_unicast_packets_received_hi), + 8, STATS_FLAGS_BOTH, "rx_ucast_packets" }, + { STATS_OFFSET32(total_multicast_packets_received_hi), + 8, STATS_FLAGS_BOTH, "rx_mcast_packets" }, + { STATS_OFFSET32(total_broadcast_packets_received_hi), + 8, STATS_FLAGS_BOTH, "rx_bcast_packets" }, + { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi), + 8, STATS_FLAGS_PORT, "rx_crc_errors" }, + { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi), + 8, STATS_FLAGS_PORT, "rx_align_errors" }, + { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi), + 8, STATS_FLAGS_PORT, "rx_undersize_packets" }, + { STATS_OFFSET32(etherstatsoverrsizepkts_hi), + 8, STATS_FLAGS_PORT, "rx_oversize_packets" }, +/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi), + 8, STATS_FLAGS_PORT, "rx_fragments" }, + { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi), + 8, STATS_FLAGS_PORT, "rx_jabbers" }, + { STATS_OFFSET32(no_buff_discard_hi), + 8, STATS_FLAGS_BOTH, "rx_discards" }, + { STATS_OFFSET32(mac_filter_discard), + 4, STATS_FLAGS_PORT, "rx_filtered_packets" }, + { STATS_OFFSET32(xxoverflow_discard), + 4, STATS_FLAGS_PORT, "rx_fw_discards" }, + { STATS_OFFSET32(brb_drop_hi), + 8, STATS_FLAGS_PORT, "rx_brb_discard" }, + { STATS_OFFSET32(brb_truncate_hi), + 8, STATS_FLAGS_PORT, "rx_brb_truncate" }, + { STATS_OFFSET32(pause_frames_received_hi), + 8, STATS_FLAGS_PORT, "rx_pause_frames" }, + { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi), + 8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" }, + { STATS_OFFSET32(nig_timer_max), + 4, STATS_FLAGS_PORT, "rx_constant_pause_events" }, +/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt), + 4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"}, + { STATS_OFFSET32(rx_skb_alloc_failed), + 4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" }, + { STATS_OFFSET32(hw_csum_err), + 4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" }, + + { STATS_OFFSET32(total_bytes_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_bytes" }, + { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi), + 8, STATS_FLAGS_PORT, "tx_error_bytes" }, + { STATS_OFFSET32(total_unicast_packets_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_ucast_packets" }, + { STATS_OFFSET32(total_multicast_packets_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_mcast_packets" }, + { STATS_OFFSET32(total_broadcast_packets_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_bcast_packets" }, + { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi), + 8, STATS_FLAGS_PORT, "tx_mac_errors" }, + { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi), + 8, STATS_FLAGS_PORT, "tx_carrier_errors" }, +/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi), + 8, STATS_FLAGS_PORT, "tx_single_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi), + 8, STATS_FLAGS_PORT, "tx_multi_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi), + 8, STATS_FLAGS_PORT, "tx_deferred" }, + { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi), + 8, STATS_FLAGS_PORT, "tx_excess_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi), + 8, STATS_FLAGS_PORT, "tx_late_collisions" }, + { STATS_OFFSET32(tx_stat_etherstatscollisions_hi), + 8, STATS_FLAGS_PORT, "tx_total_collisions" }, + { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi), + 8, STATS_FLAGS_PORT, "tx_64_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi), + 8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi), + 8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi), + 8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" }, +/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi), + 8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" }, + { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi), + 8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" }, + { STATS_OFFSET32(etherstatspktsover1522octets_hi), + 8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" }, + { STATS_OFFSET32(pause_frames_sent_hi), + 8, STATS_FLAGS_PORT, "tx_pause_frames" } +}; + +#define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr) + static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); @@ -45,14 +182,9 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->speed = bp->link_params.req_line_speed[cfg_idx]; cmd->duplex = bp->link_params.req_duplex[cfg_idx]; } - if (IS_MF(bp)) { - u16 vn_max_rate = ((bp->mf_config[BP_VN(bp)] & - FUNC_MF_CFG_MAX_BW_MASK) >> FUNC_MF_CFG_MAX_BW_SHIFT) * - 100; - if (vn_max_rate < cmd->speed) - cmd->speed = vn_max_rate; - } + if (IS_MF(bp)) + cmd->speed = bnx2x_get_mf_speed(bp); if (bp->port.supported[cfg_idx] & SUPPORTED_TP) cmd->port = PORT_TP; @@ -87,18 +219,57 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config; + u32 speed; - if (IS_MF(bp)) + if (IS_MF_SD(bp)) return 0; DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" - DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" - DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" - DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", + " supported 0x%x advertising 0x%x speed %d speed_hi %d\n" + " duplex %d port %d phy_address %d transceiver %d\n" + " autoneg %d maxtxpkt %d maxrxpkt %d\n", cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->speed_hi, cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + speed = cmd->speed; + speed |= (cmd->speed_hi << 16); + + if (IS_MF_SI(bp)) { + u32 param = 0; + u32 line_speed = bp->link_vars.line_speed; + + /* use 10G if no link detected */ + if (!line_speed) + line_speed = 10000; + + if (bp->common.bc_ver < REQ_BC_VER_4_SET_MF_BW) { + BNX2X_DEV_INFO("To set speed BC %X or higher " + "is required, please upgrade BC\n", + REQ_BC_VER_4_SET_MF_BW); + return -EINVAL; + } + if (line_speed < speed) { + BNX2X_DEV_INFO("New speed should be less or equal " + "to actual line speed\n"); + return -EINVAL; + } + /* load old values */ + param = bp->mf_config[BP_VN(bp)]; + + /* leave only MIN value */ + param &= FUNC_MF_CFG_MIN_BW_MASK; + + /* set new MAX value */ + param |= (((speed * 100) / line_speed) + << FUNC_MF_CFG_MAX_BW_SHIFT) + & FUNC_MF_CFG_MAX_BW_MASK; + + bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, param); + return 0; + } + cfg_idx = bnx2x_get_link_cfg_idx(bp); old_multi_phy_config = bp->link_params.multi_phy_config; switch (cmd->port) { @@ -168,8 +339,6 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else { /* forced speed */ /* advertise the requested speed and duplex if supported */ - u32 speed = cmd->speed; - speed |= (cmd->speed_hi << 16); switch (speed) { case SPEED_10: if (cmd->duplex == DUPLEX_FULL) { @@ -1286,7 +1455,7 @@ static int bnx2x_test_registers(struct bnx2x *bp) save_val = REG_RD(bp, offset); - REG_WR(bp, offset, (wr_val & mask)); + REG_WR(bp, offset, wr_val & mask); val = REG_RD(bp, offset); @@ -1499,8 +1668,15 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) * updates that have been performed while interrupts were * disabled. */ - if (bp->common.int_block == INT_BLOCK_IGU) + if (bp->common.int_block == INT_BLOCK_IGU) { + /* Disable local BHes to prevent a dead-lock situation between + * sch_direct_xmit() and bnx2x_run_loopback() (calling + * bnx2x_tx_int()), as both are taking netif_tx_lock(). + */ + local_bh_disable(); bnx2x_tx_int(fp_tx); + local_bh_enable(); + } rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb); if (rx_idx != rx_start_idx + num_pkts) @@ -1650,7 +1826,7 @@ static int bnx2x_test_intr(struct bnx2x *bp) config->hdr.client_id = bp->fp->cl_id; config->hdr.reserved1 = 0; - bp->set_mac_pending++; + bp->set_mac_pending = 1; smp_wmb(); rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_MAC, 0, U64_HI(bnx2x_sp_mapping(bp, mac_config)), @@ -1748,134 +1924,6 @@ static void bnx2x_self_test(struct net_device *dev, #endif } -static const struct { - long offset; - int size; - u8 string[ETH_GSTRING_LEN]; -} bnx2x_q_stats_arr[BNX2X_NUM_Q_STATS] = { -/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" }, - { Q_STATS_OFFSET32(error_bytes_received_hi), - 8, "[%d]: rx_error_bytes" }, - { Q_STATS_OFFSET32(total_unicast_packets_received_hi), - 8, "[%d]: rx_ucast_packets" }, - { Q_STATS_OFFSET32(total_multicast_packets_received_hi), - 8, "[%d]: rx_mcast_packets" }, - { Q_STATS_OFFSET32(total_broadcast_packets_received_hi), - 8, "[%d]: rx_bcast_packets" }, - { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%d]: rx_discards" }, - { Q_STATS_OFFSET32(rx_err_discard_pkt), - 4, "[%d]: rx_phy_ip_err_discards"}, - { Q_STATS_OFFSET32(rx_skb_alloc_failed), - 4, "[%d]: rx_skb_alloc_discard" }, - { Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" }, - -/* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%d]: tx_bytes" }, - { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi), - 8, "[%d]: tx_ucast_packets" }, - { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi), - 8, "[%d]: tx_mcast_packets" }, - { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi), - 8, "[%d]: tx_bcast_packets" } -}; - -static const struct { - long offset; - int size; - u32 flags; -#define STATS_FLAGS_PORT 1 -#define STATS_FLAGS_FUNC 2 -#define STATS_FLAGS_BOTH (STATS_FLAGS_FUNC | STATS_FLAGS_PORT) - u8 string[ETH_GSTRING_LEN]; -} bnx2x_stats_arr[BNX2X_NUM_STATS] = { -/* 1 */ { STATS_OFFSET32(total_bytes_received_hi), - 8, STATS_FLAGS_BOTH, "rx_bytes" }, - { STATS_OFFSET32(error_bytes_received_hi), - 8, STATS_FLAGS_BOTH, "rx_error_bytes" }, - { STATS_OFFSET32(total_unicast_packets_received_hi), - 8, STATS_FLAGS_BOTH, "rx_ucast_packets" }, - { STATS_OFFSET32(total_multicast_packets_received_hi), - 8, STATS_FLAGS_BOTH, "rx_mcast_packets" }, - { STATS_OFFSET32(total_broadcast_packets_received_hi), - 8, STATS_FLAGS_BOTH, "rx_bcast_packets" }, - { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi), - 8, STATS_FLAGS_PORT, "rx_crc_errors" }, - { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi), - 8, STATS_FLAGS_PORT, "rx_align_errors" }, - { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi), - 8, STATS_FLAGS_PORT, "rx_undersize_packets" }, - { STATS_OFFSET32(etherstatsoverrsizepkts_hi), - 8, STATS_FLAGS_PORT, "rx_oversize_packets" }, -/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi), - 8, STATS_FLAGS_PORT, "rx_fragments" }, - { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi), - 8, STATS_FLAGS_PORT, "rx_jabbers" }, - { STATS_OFFSET32(no_buff_discard_hi), - 8, STATS_FLAGS_BOTH, "rx_discards" }, - { STATS_OFFSET32(mac_filter_discard), - 4, STATS_FLAGS_PORT, "rx_filtered_packets" }, - { STATS_OFFSET32(xxoverflow_discard), - 4, STATS_FLAGS_PORT, "rx_fw_discards" }, - { STATS_OFFSET32(brb_drop_hi), - 8, STATS_FLAGS_PORT, "rx_brb_discard" }, - { STATS_OFFSET32(brb_truncate_hi), - 8, STATS_FLAGS_PORT, "rx_brb_truncate" }, - { STATS_OFFSET32(pause_frames_received_hi), - 8, STATS_FLAGS_PORT, "rx_pause_frames" }, - { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi), - 8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" }, - { STATS_OFFSET32(nig_timer_max), - 4, STATS_FLAGS_PORT, "rx_constant_pause_events" }, -/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt), - 4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"}, - { STATS_OFFSET32(rx_skb_alloc_failed), - 4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" }, - { STATS_OFFSET32(hw_csum_err), - 4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" }, - - { STATS_OFFSET32(total_bytes_transmitted_hi), - 8, STATS_FLAGS_BOTH, "tx_bytes" }, - { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi), - 8, STATS_FLAGS_PORT, "tx_error_bytes" }, - { STATS_OFFSET32(total_unicast_packets_transmitted_hi), - 8, STATS_FLAGS_BOTH, "tx_ucast_packets" }, - { STATS_OFFSET32(total_multicast_packets_transmitted_hi), - 8, STATS_FLAGS_BOTH, "tx_mcast_packets" }, - { STATS_OFFSET32(total_broadcast_packets_transmitted_hi), - 8, STATS_FLAGS_BOTH, "tx_bcast_packets" }, - { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi), - 8, STATS_FLAGS_PORT, "tx_mac_errors" }, - { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi), - 8, STATS_FLAGS_PORT, "tx_carrier_errors" }, -/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi), - 8, STATS_FLAGS_PORT, "tx_single_collisions" }, - { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi), - 8, STATS_FLAGS_PORT, "tx_multi_collisions" }, - { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi), - 8, STATS_FLAGS_PORT, "tx_deferred" }, - { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi), - 8, STATS_FLAGS_PORT, "tx_excess_collisions" }, - { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi), - 8, STATS_FLAGS_PORT, "tx_late_collisions" }, - { STATS_OFFSET32(tx_stat_etherstatscollisions_hi), - 8, STATS_FLAGS_PORT, "tx_total_collisions" }, - { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi), - 8, STATS_FLAGS_PORT, "tx_64_byte_packets" }, - { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi), - 8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" }, - { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi), - 8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" }, - { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi), - 8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" }, -/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi), - 8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" }, - { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi), - 8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" }, - { STATS_OFFSET32(etherstatspktsover1522octets_hi), - 8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" }, - { STATS_OFFSET32(pause_frames_sent_hi), - 8, STATS_FLAGS_PORT, "tx_pause_frames" } -}; - #define IS_PORT_STAT(i) \ ((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT) #define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC) @@ -1890,7 +1938,8 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset) switch (stringset) { case ETH_SS_STATS: if (is_multi(bp)) { - num_stats = BNX2X_NUM_Q_STATS * bp->num_queues; + num_stats = BNX2X_NUM_STAT_QUEUES(bp) * + BNX2X_NUM_Q_STATS; if (!IS_MF_MODE_STAT(bp)) num_stats += BNX2X_NUM_STATS; } else { @@ -1916,15 +1965,25 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) { struct bnx2x *bp = netdev_priv(dev); int i, j, k; + char queue_name[MAX_QUEUE_NAME_LEN+1]; switch (stringset) { case ETH_SS_STATS: if (is_multi(bp)) { k = 0; - for_each_queue(bp, i) { + for_each_napi_queue(bp, i) { + memset(queue_name, 0, sizeof(queue_name)); + + if (IS_FCOE_IDX(i)) + sprintf(queue_name, "fcoe"); + else + sprintf(queue_name, "%d", i); + for (j = 0; j < BNX2X_NUM_Q_STATS; j++) - sprintf(buf + (k + j)*ETH_GSTRING_LEN, - bnx2x_q_stats_arr[j].string, i); + snprintf(buf + (k + j)*ETH_GSTRING_LEN, + ETH_GSTRING_LEN, + bnx2x_q_stats_arr[j].string, + queue_name); k += BNX2X_NUM_Q_STATS; } if (IS_MF_MODE_STAT(bp)) @@ -1958,7 +2017,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, if (is_multi(bp)) { k = 0; - for_each_queue(bp, i) { + for_each_napi_queue(bp, i) { hw_stats = (u32 *)&bp->fp[i].eth_q_stats; for (j = 0; j < BNX2X_NUM_Q_STATS; j++) { if (bnx2x_q_stats_arr[j].size == 0) { diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index 4cfd4e9b558..6238d4f6398 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -434,7 +434,12 @@ struct shared_feat_cfg { /* NVRAM Offset */ #define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_DISABLED 0x00000000 #define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_ENABLED 0x00000002 -#define SHARED_FEATURE_MF_MODE_DISABLED 0x00000100 +#define SHARED_FEAT_CFG_FORCE_SF_MODE_MASK 0x00000700 +#define SHARED_FEAT_CFG_FORCE_SF_MODE_SHIFT 8 +#define SHARED_FEAT_CFG_FORCE_SF_MODE_MF_ALLOWED 0x00000000 +#define SHARED_FEAT_CFG_FORCE_SF_MODE_FORCED_SF 0x00000100 +#define SHARED_FEAT_CFG_FORCE_SF_MODE_SPIO4 0x00000200 +#define SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT 0x00000300 }; @@ -679,7 +684,7 @@ struct shm_dev_info { /* size */ #define E1VN_MAX 1 #define E1HVN_MAX 4 - +#define E2_VF_MAX 64 /* This value (in milliseconds) determines the frequency of the driver * issuing the PULSE message code. The firmware monitors this periodic * pulse to determine when to switch to an OS-absent mode. */ @@ -815,6 +820,11 @@ struct drv_func_mb { #define DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL 0xa1000000 #define REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL 0x00050234 +#define DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG 0xb0000000 +#define DRV_MSG_CODE_DCBX_PMF_DRV_OK 0xb2000000 +#define DRV_MSG_CODE_SET_MF_BW 0xe0000000 +#define REQ_BC_VER_4_SET_MF_BW 0x00060202 +#define DRV_MSG_CODE_SET_MF_BW_ACK 0xe1000000 #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 #define BIOS_MSG_CODE_VIRT_MAC_PRIM 0xff030000 @@ -888,6 +898,7 @@ struct drv_func_mb { u32 drv_status; #define DRV_STATUS_PMF 0x00000001 +#define DRV_STATUS_SET_MF_BW 0x00000004 #define DRV_STATUS_DCC_EVENT_MASK 0x0000ff00 #define DRV_STATUS_DCC_DISABLE_ENABLE_PF 0x00000100 @@ -896,6 +907,8 @@ struct drv_func_mb { #define DRV_STATUS_DCC_RESERVED1 0x00000800 #define DRV_STATUS_DCC_SET_PROTOCOL 0x00001000 #define DRV_STATUS_DCC_SET_PRIORITY 0x00002000 +#define DRV_STATUS_DCBX_EVENT_MASK 0x000f0000 +#define DRV_STATUS_DCBX_NEGOTIATION_RESULTS 0x00010000 u32 virt_mac_upper; #define VIRT_MAC_SIGN_MASK 0xffff0000 @@ -988,12 +1001,43 @@ struct func_mf_cfg { }; +/* This structure is not applicable and should not be accessed on 57711 */ +struct func_ext_cfg { + u32 func_cfg; +#define MACP_FUNC_CFG_FLAGS_MASK 0x000000FF +#define MACP_FUNC_CFG_FLAGS_SHIFT 0 +#define MACP_FUNC_CFG_FLAGS_ENABLED 0x00000001 +#define MACP_FUNC_CFG_FLAGS_ETHERNET 0x00000002 +#define MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD 0x00000004 +#define MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD 0x00000008 + + u32 iscsi_mac_addr_upper; + u32 iscsi_mac_addr_lower; + + u32 fcoe_mac_addr_upper; + u32 fcoe_mac_addr_lower; + + u32 fcoe_wwn_port_name_upper; + u32 fcoe_wwn_port_name_lower; + + u32 fcoe_wwn_node_name_upper; + u32 fcoe_wwn_node_name_lower; + + u32 preserve_data; +#define MF_FUNC_CFG_PRESERVE_L2_MAC (1<<0) +#define MF_FUNC_CFG_PRESERVE_ISCSI_MAC (1<<1) +#define MF_FUNC_CFG_PRESERVE_FCOE_MAC (1<<2) +#define MF_FUNC_CFG_PRESERVE_FCOE_WWN_P (1<<3) +#define MF_FUNC_CFG_PRESERVE_FCOE_WWN_N (1<<4) +}; + struct mf_cfg { struct shared_mf_cfg shared_mf_config; struct port_mf_cfg port_mf_config[PORT_MAX]; struct func_mf_cfg func_mf_config[E1H_FUNC_MAX]; + struct func_ext_cfg func_ext_config[E1H_FUNC_MAX]; }; @@ -1049,6 +1093,251 @@ struct fw_flr_mb { struct fw_flr_ack ack; }; +/**** SUPPORT FOR SHMEM ARRRAYS *** + * The SHMEM HSI is aligned on 32 bit boundaries which makes it difficult to + * define arrays with storage types smaller then unsigned dwords. + * The macros below add generic support for SHMEM arrays with numeric elements + * that can span 2,4,8 or 16 bits. The array underlying type is a 32 bit dword + * array with individual bit-filed elements accessed using shifts and masks. + * + */ + +/* eb is the bitwidth of a single element */ +#define SHMEM_ARRAY_MASK(eb) ((1<<(eb))-1) +#define SHMEM_ARRAY_ENTRY(i, eb) ((i)/(32/(eb))) + +/* the bit-position macro allows the used to flip the order of the arrays + * elements on a per byte or word boundary. + * + * example: an array with 8 entries each 4 bit wide. This array will fit into + * a single dword. The diagrmas below show the array order of the nibbles. + * + * SHMEM_ARRAY_BITPOS(i, 4, 4) defines the stadard ordering: + * + * | | | | + * 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | | | | + * + * SHMEM_ARRAY_BITPOS(i, 4, 8) defines a flip ordering per byte: + * + * | | | | + * 1 | 0 | 3 | 2 | 5 | 4 | 7 | 6 | + * | | | | + * + * SHMEM_ARRAY_BITPOS(i, 4, 16) defines a flip ordering per word: + * + * | | | | + * 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | + * | | | | + */ +#define SHMEM_ARRAY_BITPOS(i, eb, fb) \ + ((((32/(fb)) - 1 - ((i)/((fb)/(eb))) % (32/(fb))) * (fb)) + \ + (((i)%((fb)/(eb))) * (eb))) + +#define SHMEM_ARRAY_GET(a, i, eb, fb) \ + ((a[SHMEM_ARRAY_ENTRY(i, eb)] >> SHMEM_ARRAY_BITPOS(i, eb, fb)) & \ + SHMEM_ARRAY_MASK(eb)) + +#define SHMEM_ARRAY_SET(a, i, eb, fb, val) \ +do { \ + a[SHMEM_ARRAY_ENTRY(i, eb)] &= ~(SHMEM_ARRAY_MASK(eb) << \ + SHMEM_ARRAY_BITPOS(i, eb, fb)); \ + a[SHMEM_ARRAY_ENTRY(i, eb)] |= (((val) & SHMEM_ARRAY_MASK(eb)) << \ + SHMEM_ARRAY_BITPOS(i, eb, fb)); \ +} while (0) + + +/****START OF DCBX STRUCTURES DECLARATIONS****/ +#define DCBX_MAX_NUM_PRI_PG_ENTRIES 8 +#define DCBX_PRI_PG_BITWIDTH 4 +#define DCBX_PRI_PG_FBITS 8 +#define DCBX_PRI_PG_GET(a, i) \ + SHMEM_ARRAY_GET(a, i, DCBX_PRI_PG_BITWIDTH, DCBX_PRI_PG_FBITS) +#define DCBX_PRI_PG_SET(a, i, val) \ + SHMEM_ARRAY_SET(a, i, DCBX_PRI_PG_BITWIDTH, DCBX_PRI_PG_FBITS, val) +#define DCBX_MAX_NUM_PG_BW_ENTRIES 8 +#define DCBX_BW_PG_BITWIDTH 8 +#define DCBX_PG_BW_GET(a, i) \ + SHMEM_ARRAY_GET(a, i, DCBX_BW_PG_BITWIDTH, DCBX_BW_PG_BITWIDTH) +#define DCBX_PG_BW_SET(a, i, val) \ + SHMEM_ARRAY_SET(a, i, DCBX_BW_PG_BITWIDTH, DCBX_BW_PG_BITWIDTH, val) +#define DCBX_STRICT_PRI_PG 15 +#define DCBX_MAX_APP_PROTOCOL 16 +#define FCOE_APP_IDX 0 +#define ISCSI_APP_IDX 1 +#define PREDEFINED_APP_IDX_MAX 2 + +struct dcbx_ets_feature { + u32 enabled; + u32 pg_bw_tbl[2]; + u32 pri_pg_tbl[1]; +}; + +struct dcbx_pfc_feature { +#ifdef __BIG_ENDIAN + u8 pri_en_bitmap; +#define DCBX_PFC_PRI_0 0x01 +#define DCBX_PFC_PRI_1 0x02 +#define DCBX_PFC_PRI_2 0x04 +#define DCBX_PFC_PRI_3 0x08 +#define DCBX_PFC_PRI_4 0x10 +#define DCBX_PFC_PRI_5 0x20 +#define DCBX_PFC_PRI_6 0x40 +#define DCBX_PFC_PRI_7 0x80 + u8 pfc_caps; + u8 reserved; + u8 enabled; +#elif defined(__LITTLE_ENDIAN) + u8 enabled; + u8 reserved; + u8 pfc_caps; + u8 pri_en_bitmap; +#define DCBX_PFC_PRI_0 0x01 +#define DCBX_PFC_PRI_1 0x02 +#define DCBX_PFC_PRI_2 0x04 +#define DCBX_PFC_PRI_3 0x08 +#define DCBX_PFC_PRI_4 0x10 +#define DCBX_PFC_PRI_5 0x20 +#define DCBX_PFC_PRI_6 0x40 +#define DCBX_PFC_PRI_7 0x80 +#endif +}; + +struct dcbx_app_priority_entry { +#ifdef __BIG_ENDIAN + u16 app_id; + u8 pri_bitmap; + u8 appBitfield; +#define DCBX_APP_ENTRY_VALID 0x01 +#define DCBX_APP_ENTRY_SF_MASK 0x30 +#define DCBX_APP_ENTRY_SF_SHIFT 4 +#define DCBX_APP_SF_ETH_TYPE 0x10 +#define DCBX_APP_SF_PORT 0x20 +#elif defined(__LITTLE_ENDIAN) + u8 appBitfield; +#define DCBX_APP_ENTRY_VALID 0x01 +#define DCBX_APP_ENTRY_SF_MASK 0x30 +#define DCBX_APP_ENTRY_SF_SHIFT 4 +#define DCBX_APP_SF_ETH_TYPE 0x10 +#define DCBX_APP_SF_PORT 0x20 + u8 pri_bitmap; + u16 app_id; +#endif +}; + +struct dcbx_app_priority_feature { +#ifdef __BIG_ENDIAN + u8 reserved; + u8 default_pri; + u8 tc_supported; + u8 enabled; +#elif defined(__LITTLE_ENDIAN) + u8 enabled; + u8 tc_supported; + u8 default_pri; + u8 reserved; +#endif + struct dcbx_app_priority_entry app_pri_tbl[DCBX_MAX_APP_PROTOCOL]; +}; + +struct dcbx_features { + struct dcbx_ets_feature ets; + struct dcbx_pfc_feature pfc; + struct dcbx_app_priority_feature app; +}; + +struct lldp_params { +#ifdef __BIG_ENDIAN + u8 msg_fast_tx_interval; + u8 msg_tx_hold; + u8 msg_tx_interval; + u8 admin_status; +#define LLDP_TX_ONLY 0x01 +#define LLDP_RX_ONLY 0x02 +#define LLDP_TX_RX 0x03 +#define LLDP_DISABLED 0x04 + u8 reserved1; + u8 tx_fast; + u8 tx_crd_max; + u8 tx_crd; +#elif defined(__LITTLE_ENDIAN) + u8 admin_status; +#define LLDP_TX_ONLY 0x01 +#define LLDP_RX_ONLY 0x02 +#define LLDP_TX_RX 0x03 +#define LLDP_DISABLED 0x04 + u8 msg_tx_interval; + u8 msg_tx_hold; + u8 msg_fast_tx_interval; + u8 tx_crd; + u8 tx_crd_max; + u8 tx_fast; + u8 reserved1; +#endif +#define REM_CHASSIS_ID_STAT_LEN 4 +#define REM_PORT_ID_STAT_LEN 4 + u32 peer_chassis_id[REM_CHASSIS_ID_STAT_LEN]; + u32 peer_port_id[REM_PORT_ID_STAT_LEN]; +}; + +struct lldp_dcbx_stat { +#define LOCAL_CHASSIS_ID_STAT_LEN 2 +#define LOCAL_PORT_ID_STAT_LEN 2 + u32 local_chassis_id[LOCAL_CHASSIS_ID_STAT_LEN]; + u32 local_port_id[LOCAL_PORT_ID_STAT_LEN]; + u32 num_tx_dcbx_pkts; + u32 num_rx_dcbx_pkts; +}; + +struct lldp_admin_mib { + u32 ver_cfg_flags; +#define DCBX_ETS_CONFIG_TX_ENABLED 0x00000001 +#define DCBX_PFC_CONFIG_TX_ENABLED 0x00000002 +#define DCBX_APP_CONFIG_TX_ENABLED 0x00000004 +#define DCBX_ETS_RECO_TX_ENABLED 0x00000008 +#define DCBX_ETS_RECO_VALID 0x00000010 +#define DCBX_ETS_WILLING 0x00000020 +#define DCBX_PFC_WILLING 0x00000040 +#define DCBX_APP_WILLING 0x00000080 +#define DCBX_VERSION_CEE 0x00000100 +#define DCBX_VERSION_IEEE 0x00000200 +#define DCBX_DCBX_ENABLED 0x00000400 +#define DCBX_CEE_VERSION_MASK 0x0000f000 +#define DCBX_CEE_VERSION_SHIFT 12 +#define DCBX_CEE_MAX_VERSION_MASK 0x000f0000 +#define DCBX_CEE_MAX_VERSION_SHIFT 16 + struct dcbx_features features; +}; + +struct lldp_remote_mib { + u32 prefix_seq_num; + u32 flags; +#define DCBX_ETS_TLV_RX 0x00000001 +#define DCBX_PFC_TLV_RX 0x00000002 +#define DCBX_APP_TLV_RX 0x00000004 +#define DCBX_ETS_RX_ERROR 0x00000010 +#define DCBX_PFC_RX_ERROR 0x00000020 +#define DCBX_APP_RX_ERROR 0x00000040 +#define DCBX_ETS_REM_WILLING 0x00000100 +#define DCBX_PFC_REM_WILLING 0x00000200 +#define DCBX_APP_REM_WILLING 0x00000400 +#define DCBX_REMOTE_ETS_RECO_VALID 0x00001000 + struct dcbx_features features; + u32 suffix_seq_num; +}; + +struct lldp_local_mib { + u32 prefix_seq_num; + u32 error; +#define DCBX_LOCAL_ETS_ERROR 0x00000001 +#define DCBX_LOCAL_PFC_ERROR 0x00000002 +#define DCBX_LOCAL_APP_ERROR 0x00000004 +#define DCBX_LOCAL_PFC_MISMATCH 0x00000010 +#define DCBX_LOCAL_APP_MISMATCH 0x00000020 + struct dcbx_features features; + u32 suffix_seq_num; +}; +/***END OF DCBX STRUCTURES DECLARATIONS***/ struct shmem2_region { @@ -1072,7 +1361,12 @@ struct shmem2_region { #define SHMEM_MF_CFG_ADDR_NONE 0x00000000 struct fw_flr_mb flr_mb; - u32 reserved[3]; + u32 dcbx_lldp_params_offset; +#define SHMEM_LLDP_DCBX_PARAMS_NONE 0x00000000 + u32 dcbx_neg_res_offset; +#define SHMEM_DCBX_NEG_RES_NONE 0x00000000 + u32 dcbx_remote_mib_offset; +#define SHMEM_DCBX_REMOTE_MIB_NONE 0x00000000 /* * The other shmemX_base_addr holds the other path's shmem address * required for example in case of common phy init, or for path1 to know @@ -1081,6 +1375,10 @@ struct shmem2_region { */ u32 other_shmem_base_addr; u32 other_shmem2_base_addr; + u32 reserved1[E2_VF_MAX / 32]; + u32 reserved2[E2_FUNC_MAX][E2_VF_MAX / 32]; + u32 dcbx_lldp_dcbx_stat_offset; +#define SHMEM_LLDP_DCBX_STAT_NONE 0x00000000 }; @@ -1534,8 +1832,8 @@ struct host_func_stats { #define BCM_5710_FW_MAJOR_VERSION 6 -#define BCM_5710_FW_MINOR_VERSION 0 -#define BCM_5710_FW_REVISION_VERSION 34 +#define BCM_5710_FW_MINOR_VERSION 2 +#define BCM_5710_FW_REVISION_VERSION 5 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 @@ -2983,6 +3281,25 @@ struct fairness_vars_per_vn { /* + * The data for flow control configuration + */ +struct flow_control_configuration { + struct priority_cos + traffic_type_to_priority_cos[MAX_PFC_TRAFFIC_TYPES]; +#if defined(__BIG_ENDIAN) + u16 reserved1; + u8 dcb_version; + u8 dcb_enabled; +#elif defined(__LITTLE_ENDIAN) + u8 dcb_enabled; + u8 dcb_version; + u16 reserved1; +#endif + u32 reserved2; +}; + + +/* * FW version stored in the Xstorm RAM */ struct fw_version { diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h index a306b0e46b6..66df29fcf75 100644 --- a/drivers/net/bnx2x/bnx2x_init_ops.h +++ b/drivers/net/bnx2x/bnx2x_init_ops.h @@ -838,7 +838,7 @@ static void bnx2x_qm_init_ptr_table(struct bnx2x *bp, int qm_cid_count, /**************************************************************************** * SRC initializations ****************************************************************************/ - +#ifdef BCM_CNIC /* called during init func stage */ static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2, dma_addr_t t2_mapping, int src_cid_count) @@ -862,5 +862,5 @@ static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2, U64_HI((u64)t2_mapping + (src_cid_count-1) * sizeof(struct src_ent))); } - +#endif #endif /* BNX2X_INIT_OPS_H */ diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index 58091961925..43b0de24f39 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -164,7 +164,8 @@ #define EDC_MODE_PASSIVE_DAC 0x0055 - +#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000) +#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000) /**********************************************************/ /* INTERFACE */ /**********************************************************/ @@ -205,6 +206,270 @@ static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits) return val; } +/******************************************************************/ +/* ETS section */ +/******************************************************************/ +void bnx2x_ets_disabled(struct link_params *params) +{ + /* ETS disabled configuration*/ + struct bnx2x *bp = params->bp; + + DP(NETIF_MSG_LINK, "ETS disabled configuration\n"); + + /** + * mapping between entry priority to client number (0,1,2 -debug and + * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST) + * 3bits client num. + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000 + */ + + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688); + /** + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, 3 - + * COS0 entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ + + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); + /* defines which entries (clients) are subjected to WFQ arbitration */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0); + /** + * For strict priority entries defines the number of consecutive + * slots for the highest priority. + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + /** + * mapping between the CREDIT_WEIGHT registers and actual client + * numbers + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0); + + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0); + REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0); + /* ETS mode disable */ + REG_WR(bp, PBF_REG_ETS_ENABLED, 0); + /** + * If ETS mode is enabled (there is no strict priority) defines a WFQ + * weight for COS0/COS1. + */ + REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710); + REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710); + /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */ + REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680); + REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680); + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); +} + +void bnx2x_ets_bw_limit_common(const struct link_params *params) +{ + /* ETS disabled configuration */ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n"); + /** + * defines which entries (clients) are subjected to WFQ arbitration + * COS0 0x8 + * COS1 0x10 + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18); + /** + * mapping between the ARB_CREDIT_WEIGHT registers and actual + * client numbers (WEIGHT_0 does not actually have to represent + * client 0) + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010 + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A); + + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); + + /* ETS mode enabled*/ + REG_WR(bp, PBF_REG_ETS_ENABLED, 1); + + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); + /** + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0 + * entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); + + /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/ + REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); + REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); +} + +void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, + const u32 cos1_bw) +{ + /* ETS disabled configuration*/ + struct bnx2x *bp = params->bp; + const u32 total_bw = cos0_bw + cos1_bw; + u32 cos0_credit_weight = 0; + u32 cos1_credit_weight = 0; + + DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n"); + + if ((0 == total_bw) || + (0 == cos0_bw) || + (0 == cos1_bw)) { + DP(NETIF_MSG_LINK, + "bnx2x_ets_bw_limit: Total BW can't be zero\n"); + return; + } + + cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/ + total_bw; + cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/ + total_bw; + + bnx2x_ets_bw_limit_common(params); + + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight); + + REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight); + REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight); +} + +u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) +{ + /* ETS disabled configuration*/ + struct bnx2x *bp = params->bp; + u32 val = 0; + + DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n"); + /** + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, + * 3 - COS0 entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F); + /** + * For strict priority entries defines the number of consecutive slots + * for the highest priority. + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + /* ETS mode disable */ + REG_WR(bp, PBF_REG_ETS_ENABLED, 0); + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100); + + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos); + + /** + * mapping between entry priority to client number (0,1,2 -debug and + * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST) + * 3bits client num. + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000 + * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000 + */ + val = (0 == strict_cos) ? 0x2318 : 0x22E0; + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val); + + return 0; +} +/******************************************************************/ +/* ETS section */ +/******************************************************************/ + +static void bnx2x_bmac2_get_pfc_stat(struct link_params *params, + u32 pfc_frames_sent[2], + u32 pfc_frames_received[2]) +{ + /* Read pfc statistic */ + struct bnx2x *bp = params->bp; + u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + + DP(NETIF_MSG_LINK, "pfc statistic read from BMAC\n"); + + REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_STAT_GTPP, + pfc_frames_sent, 2); + + REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_STAT_GRPP, + pfc_frames_received, 2); + +} +static void bnx2x_emac_get_pfc_stat(struct link_params *params, + u32 pfc_frames_sent[2], + u32 pfc_frames_received[2]) +{ + /* Read pfc statistic */ + struct bnx2x *bp = params->bp; + u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val_xon = 0; + u32 val_xoff = 0; + + DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n"); + + /* PFC received frames */ + val_xoff = REG_RD(bp, emac_base + + EMAC_REG_RX_PFC_STATS_XOFF_RCVD); + val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT; + val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD); + val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT; + + pfc_frames_received[0] = val_xon + val_xoff; + + /* PFC received sent */ + val_xoff = REG_RD(bp, emac_base + + EMAC_REG_RX_PFC_STATS_XOFF_SENT); + val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT; + val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT); + val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT; + + pfc_frames_sent[0] = val_xon + val_xoff; +} + +void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, + u32 pfc_frames_sent[2], + u32 pfc_frames_received[2]) +{ + /* Read pfc statistic */ + struct bnx2x *bp = params->bp; + u32 val = 0; + DP(NETIF_MSG_LINK, "pfc statistic\n"); + + if (!vars->link_up) + return; + + val = REG_RD(bp, MISC_REG_RESET_REG_2); + if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) + == 0) { + DP(NETIF_MSG_LINK, "About to read stats from EMAC\n"); + bnx2x_emac_get_pfc_stat(params, pfc_frames_sent, + pfc_frames_received); + } else { + DP(NETIF_MSG_LINK, "About to read stats from BMAC\n"); + bnx2x_bmac2_get_pfc_stat(params, pfc_frames_sent, + pfc_frames_received); + } +} +/******************************************************************/ +/* MAC/PBF section */ +/******************************************************************/ static void bnx2x_emac_init(struct link_params *params, struct link_vars *vars) { @@ -315,24 +580,55 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* pause enable/disable */ bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, EMAC_RX_MODE_FLOW_EN); - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) - bnx2x_bits_en(bp, emac_base + - EMAC_REG_EMAC_RX_MODE, - EMAC_RX_MODE_FLOW_EN); bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, - (EMAC_TX_MODE_EXT_PAUSE_EN | - EMAC_TX_MODE_FLOW_EN)); - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) - bnx2x_bits_en(bp, emac_base + - EMAC_REG_EMAC_TX_MODE, - (EMAC_TX_MODE_EXT_PAUSE_EN | - EMAC_TX_MODE_FLOW_EN)); + (EMAC_TX_MODE_EXT_PAUSE_EN | + EMAC_TX_MODE_FLOW_EN)); + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) { + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_TX_MODE, + (EMAC_TX_MODE_EXT_PAUSE_EN | + EMAC_TX_MODE_FLOW_EN)); + } else + bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_FLOW_EN); } /* KEEP_VLAN_TAG, promiscuous */ val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE); val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS; + + /** + * Setting this bit causes MAC control frames (except for pause + * frames) to be passed on for processing. This setting has no + * affect on the operation of the pause frames. This bit effects + * all packets regardless of RX Parser packet sorting logic. + * Turn the PFC off to make sure we are in Xon state before + * enabling it. + */ + EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0); + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) { + DP(NETIF_MSG_LINK, "PFC is enabled\n"); + /* Enable PFC again */ + EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, + EMAC_REG_RX_PFC_MODE_RX_EN | + EMAC_REG_RX_PFC_MODE_TX_EN | + EMAC_REG_RX_PFC_MODE_PRIORITIES); + + EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM, + ((0x0101 << + EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) | + (0x00ff << + EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT))); + val |= EMAC_RX_MODE_KEEP_MAC_CONTROL; + } EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val); /* Set Loopback */ @@ -362,7 +658,9 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* enable the NIG in/out to the emac */ REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1); val = 0; - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + if ((params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) || + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) val = 1; REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); @@ -383,9 +681,38 @@ static u8 bnx2x_emac_enable(struct link_params *params, return 0; } -static void bnx2x_update_bmac2(struct link_params *params, - struct link_vars *vars, - u8 is_lb) +static void bnx2x_update_pfc_bmac1(struct link_params *params, + struct link_vars *vars) +{ + u32 wb_data[2]; + struct bnx2x *bp = params->bp; + u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + + u32 val = 0x14; + if ((!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) + /* Enable BigMAC to react on received Pause packets */ + val |= (1<<5); + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2); + + /* tx control */ + val = 0xc0; + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val |= 0x800000; + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2); +} + +static void bnx2x_update_pfc_bmac2(struct link_params *params, + struct link_vars *vars, + u8 is_lb) { /* * Set rx control: Strip CRC and enable BigMAC to relay @@ -397,7 +724,9 @@ static void bnx2x_update_bmac2(struct link_params *params, NIG_REG_INGRESS_BMAC0_MEM; u32 val = 0x14; - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) + if ((!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) /* Enable BigMAC to react on received Pause packets */ val |= (1<<5); wb_data[0] = val; @@ -408,14 +737,47 @@ static void bnx2x_update_bmac2(struct link_params *params, /* Tx control */ val = 0xc0; - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) val |= 0x800000; wb_data[0] = val; wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, - wb_data, 2); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2); + + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) { + DP(NETIF_MSG_LINK, "PFC is enabled\n"); + /* Enable PFC RX & TX & STATS and set 8 COS */ + wb_data[0] = 0x0; + wb_data[0] |= (1<<0); /* RX */ + wb_data[0] |= (1<<1); /* TX */ + wb_data[0] |= (1<<2); /* Force initial Xon */ + wb_data[0] |= (1<<3); /* 8 cos */ + wb_data[0] |= (1<<5); /* STATS */ + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, + wb_data, 2); + /* Clear the force Xon */ + wb_data[0] &= ~(1<<2); + } else { + DP(NETIF_MSG_LINK, "PFC is disabled\n"); + /* disable PFC RX & TX & STATS and set 8 COS */ + wb_data[0] = 0x8; + wb_data[1] = 0; + } + + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2); + /** + * Set Time (based unit is 512 bit time) between automatic + * re-sending of PP packets amd enable automatic re-send of + * Per-Priroity Packet as long as pp_gen is asserted and + * pp_disable is low. + */ val = 0x8000; + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) + val |= (1<<16); /* enable automatic re-send */ + wb_data[0] = val; wb_data[1] = 0; REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL, @@ -427,6 +789,9 @@ static void bnx2x_update_bmac2(struct link_params *params, val |= 0x4; /* Local loopback */ DP(NETIF_MSG_LINK, "enable bmac loopback\n"); } + /* When PFC enabled, Pass pause frames towards the NIG. */ + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) + val |= ((1<<6)|(1<<5)); wb_data[0] = val; wb_data[1] = 0; @@ -434,6 +799,239 @@ static void bnx2x_update_bmac2(struct link_params *params, wb_data, 2); } +static void bnx2x_update_pfc_brb(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params *pfc_params) +{ + struct bnx2x *bp = params->bp; + int set_pfc = params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED; + + /* default - pause configuration */ + u32 pause_xoff_th = PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE; + u32 pause_xon_th = PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE; + u32 full_xoff_th = PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE; + u32 full_xon_th = PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE; + + if (set_pfc && pfc_params) + /* First COS */ + if (!pfc_params->cos0_pauseable) { + pause_xoff_th = + PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE; + pause_xon_th = + PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE; + full_xoff_th = + PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE; + full_xon_th = + PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE; + } + /* The number of free blocks below which the pause signal to class 0 + of MAC #n is asserted. n=0,1 */ + REG_WR(bp, BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , pause_xoff_th); + /* The number of free blocks above which the pause signal to class 0 + of MAC #n is de-asserted. n=0,1 */ + REG_WR(bp, BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , pause_xon_th); + /* The number of free blocks below which the full signal to class 0 + of MAC #n is asserted. n=0,1 */ + REG_WR(bp, BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , full_xoff_th); + /* The number of free blocks above which the full signal to class 0 + of MAC #n is de-asserted. n=0,1 */ + REG_WR(bp, BRB1_REG_FULL_0_XON_THRESHOLD_0 , full_xon_th); + + if (set_pfc && pfc_params) { + /* Second COS */ + if (pfc_params->cos1_pauseable) { + pause_xoff_th = + PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE; + pause_xon_th = + PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE; + full_xoff_th = + PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE; + full_xon_th = + PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE; + } else { + pause_xoff_th = + PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE; + pause_xon_th = + PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE; + full_xoff_th = + PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE; + full_xon_th = + PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE; + } + /** + * The number of free blocks below which the pause signal to + * class 1 of MAC #n is asserted. n=0,1 + **/ + REG_WR(bp, BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, pause_xoff_th); + /** + * The number of free blocks above which the pause signal to + * class 1 of MAC #n is de-asserted. n=0,1 + **/ + REG_WR(bp, BRB1_REG_PAUSE_1_XON_THRESHOLD_0, pause_xon_th); + /** + * The number of free blocks below which the full signal to + * class 1 of MAC #n is asserted. n=0,1 + **/ + REG_WR(bp, BRB1_REG_FULL_1_XOFF_THRESHOLD_0, full_xoff_th); + /** + * The number of free blocks above which the full signal to + * class 1 of MAC #n is de-asserted. n=0,1 + **/ + REG_WR(bp, BRB1_REG_FULL_1_XON_THRESHOLD_0, full_xon_th); + } +} + +static void bnx2x_update_pfc_nig(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params *nig_params) +{ + u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0; + u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0; + u32 pkt_priority_to_cos = 0; + u32 val; + struct bnx2x *bp = params->bp; + int port = params->port; + int set_pfc = params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED; + DP(NETIF_MSG_LINK, "updating pfc nig parameters\n"); + + /** + * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set + * MAC control frames (that are not pause packets) + * will be forwarded to the XCM. + */ + xcm_mask = REG_RD(bp, + port ? NIG_REG_LLH1_XCM_MASK : + NIG_REG_LLH0_XCM_MASK); + /** + * nig params will override non PFC params, since it's possible to + * do transition from PFC to SAFC + */ + if (set_pfc) { + pause_enable = 0; + llfc_out_en = 0; + llfc_enable = 0; + ppp_enable = 1; + xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN : + NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN); + xcm0_out_en = 0; + p0_hwpfc_enable = 1; + } else { + if (nig_params) { + llfc_out_en = nig_params->llfc_out_en; + llfc_enable = nig_params->llfc_enable; + pause_enable = nig_params->pause_enable; + } else /*defaul non PFC mode - PAUSE */ + pause_enable = 1; + + xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN : + NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN); + xcm0_out_en = 1; + } + + REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 : + NIG_REG_LLFC_OUT_EN_0, llfc_out_en); + REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 : + NIG_REG_LLFC_ENABLE_0, llfc_enable); + REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 : + NIG_REG_PAUSE_ENABLE_0, pause_enable); + + REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 : + NIG_REG_PPP_ENABLE_0, ppp_enable); + + REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK : + NIG_REG_LLH0_XCM_MASK, xcm_mask); + + REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7); + + /* output enable for RX_XCM # IF */ + REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en); + + /* HW PFC TX enable */ + REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable); + + /* 0x2 = BMAC, 0x1= EMAC */ + switch (vars->mac_type) { + case MAC_TYPE_EMAC: + val = 1; + break; + case MAC_TYPE_BMAC: + val = 0; + break; + default: + val = 0; + break; + } + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT, val); + + if (nig_params) { + pkt_priority_to_cos = nig_params->pkt_priority_to_cos; + + REG_WR(bp, port ? NIG_REG_P1_RX_COS0_PRIORITY_MASK : + NIG_REG_P0_RX_COS0_PRIORITY_MASK, + nig_params->rx_cos0_priority_mask); + + REG_WR(bp, port ? NIG_REG_P1_RX_COS1_PRIORITY_MASK : + NIG_REG_P0_RX_COS1_PRIORITY_MASK, + nig_params->rx_cos1_priority_mask); + + REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 : + NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0, + nig_params->llfc_high_priority_classes); + + REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 : + NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0, + nig_params->llfc_low_priority_classes); + } + REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS : + NIG_REG_P0_PKT_PRIORITY_TO_COS, + pkt_priority_to_cos); +} + + +void bnx2x_update_pfc(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params *pfc_params) +{ + /** + * The PFC and pause are orthogonal to one another, meaning when + * PFC is enabled, the pause are disabled, and when PFC is + * disabled, pause are set according to the pause result. + */ + u32 val; + struct bnx2x *bp = params->bp; + + /* update NIG params */ + bnx2x_update_pfc_nig(params, vars, pfc_params); + + /* update BRB params */ + bnx2x_update_pfc_brb(params, vars, pfc_params); + + if (!vars->link_up) + return; + + val = REG_RD(bp, MISC_REG_RESET_REG_2); + if ((val & (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) + == 0) { + DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n"); + bnx2x_emac_enable(params, vars, 0); + return; + } + + DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n"); + if (CHIP_IS_E2(bp)) + bnx2x_update_pfc_bmac2(params, vars, 0); + else + bnx2x_update_pfc_bmac1(params, vars); + + val = 0; + if ((params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) || + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val = 1; + REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val); +} static u8 bnx2x_bmac1_enable(struct link_params *params, struct link_vars *vars, @@ -465,15 +1063,6 @@ static u8 bnx2x_bmac1_enable(struct link_params *params, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2); - /* tx control */ - val = 0xc0; - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) - val |= 0x800000; - wb_data[0] = val; - wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, - wb_data, 2); - /* mac control */ val = 0x3; if (is_lb) { @@ -491,14 +1080,7 @@ static u8 bnx2x_bmac1_enable(struct link_params *params, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2); - /* rx control set to don't strip crc */ - val = 0x14; - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) - val |= 0x20; - wb_data[0] = val; - wb_data[1] = 0; - REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, - wb_data, 2); + bnx2x_update_pfc_bmac1(params, vars); /* set tx mtu */ wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; @@ -595,7 +1177,7 @@ static u8 bnx2x_bmac2_enable(struct link_params *params, REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2); udelay(30); - bnx2x_update_bmac2(params, vars, is_lb); + bnx2x_update_pfc_bmac2(params, vars, is_lb); return 0; } @@ -627,7 +1209,9 @@ static u8 bnx2x_bmac_enable(struct link_params *params, REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); val = 0; - if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + if ((params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) || + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) val = 1; REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); @@ -3904,7 +4488,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) - return 0;; + return 0; msleep(1); } return -EINVAL; @@ -3988,7 +4572,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) - return 0;; + return 0; msleep(1); } diff --git a/drivers/net/bnx2x/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h index 171abf8097e..bedab1a942c 100644 --- a/drivers/net/bnx2x/bnx2x_link.h +++ b/drivers/net/bnx2x/bnx2x_link.h @@ -65,6 +65,22 @@ #define FW_PARAM_MDIO_CTRL_OFFSET 16 #define FW_PARAM_SET(phy_addr, phy_type, mdio_access) \ (phy_addr | phy_type | mdio_access << FW_PARAM_MDIO_CTRL_OFFSET) + +#define PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_PAUSEABLE 170 +#define PFC_BRB_MAC_PAUSE_XOFF_THRESHOLD_NON_PAUSEABLE 0 + +#define PFC_BRB_MAC_PAUSE_XON_THRESHOLD_PAUSEABLE 250 +#define PFC_BRB_MAC_PAUSE_XON_THRESHOLD_NON_PAUSEABLE 0 + +#define PFC_BRB_MAC_FULL_XOFF_THRESHOLD_PAUSEABLE 10 +#define PFC_BRB_MAC_FULL_XOFF_THRESHOLD_NON_PAUSEABLE 90 + +#define PFC_BRB_MAC_FULL_XON_THRESHOLD_PAUSEABLE 50 +#define PFC_BRB_MAC_FULL_XON_THRESHOLD_NON_PAUSEABLE 250 + +#define PFC_BRB_FULL_LB_XOFF_THRESHOLD 170 +#define PFC_BRB_FULL_LB_XON_THRESHOLD 250 + /***********************************************************/ /* Structs */ /***********************************************************/ @@ -216,6 +232,7 @@ struct link_params { u32 feature_config_flags; #define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) +#define FEATURE_CONFIG_PFC_ENABLED (1<<1) #define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) #define FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY (1<<3) /* Will be populated during common init */ @@ -332,4 +349,43 @@ u8 bnx2x_phy_probe(struct link_params *params); u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base, u8 port); +/* PFC port configuration params */ +struct bnx2x_nig_brb_pfc_port_params { + /* NIG */ + u32 pause_enable; + u32 llfc_out_en; + u32 llfc_enable; + u32 pkt_priority_to_cos; + u32 rx_cos0_priority_mask; + u32 rx_cos1_priority_mask; + u32 llfc_high_priority_classes; + u32 llfc_low_priority_classes; + /* BRB */ + u32 cos0_pauseable; + u32 cos1_pauseable; +}; + +/** + * Used to update the PFC attributes in EMAC, BMAC, NIG and BRB + * when link is already up + */ +void bnx2x_update_pfc(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params *pfc_params); + + +/* Used to configure the ETS to disable */ +void bnx2x_ets_disabled(struct link_params *params); + +/* Used to configure the ETS to BW limited */ +void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, + const u32 cos1_bw); + +/* Used to configure the ETS to strict */ +u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos); + +/* Read pfc statistic*/ +void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, + u32 pfc_frames_sent[2], + u32 pfc_frames_received[2]); #endif /* BNX2X_LINK_H */ diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 9709b856966..489a5512a04 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -55,6 +55,7 @@ #include "bnx2x_init.h" #include "bnx2x_init_ops.h" #include "bnx2x_cmn.h" +#include "bnx2x_dcb.h" #include <linux/firmware.h> #include "bnx2x_fw_file_hdr.h" @@ -121,6 +122,10 @@ MODULE_PARM_DESC(debug, " Default debug msglevel"); static struct workqueue_struct *bnx2x_wq; +#ifdef BCM_CNIC +static u8 ALL_ENODE_MACS[] = {0x01, 0x10, 0x18, 0x01, 0x00, 0x01}; +#endif + enum bnx2x_board_type { BCM57710 = 0, BCM57711 = 1, @@ -921,7 +926,7 @@ void bnx2x_panic_dump(struct bnx2x *bp) sp_sb_data.p_func.vf_valid); - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; int loop; struct hc_status_block_data_e2 sb_data_e2; @@ -961,6 +966,10 @@ void bnx2x_panic_dump(struct bnx2x *bp) /* host sb data */ +#ifdef BCM_CNIC + if (IS_FCOE_FP(fp)) + continue; +#endif BNX2X_ERR(" run indexes ("); for (j = 0; j < HC_SB_MAX_SM; j++) pr_cont("0x%x%s", @@ -1029,7 +1038,7 @@ void bnx2x_panic_dump(struct bnx2x *bp) #ifdef BNX2X_STOP_ON_ERROR /* Rings */ /* Rx */ - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10); @@ -1063,7 +1072,7 @@ void bnx2x_panic_dump(struct bnx2x *bp) } /* Tx */ - for_each_queue(bp, i) { + for_each_tx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10); @@ -1298,7 +1307,7 @@ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) #ifdef BCM_CNIC offset++; #endif - for_each_queue(bp, i) + for_each_eth_queue(bp, i) synchronize_irq(bp->msix_table[i + offset].vector); } else synchronize_irq(bp->pdev->irq); @@ -1420,7 +1429,7 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; #endif - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; mask = 0x2 << (fp->index + CNIC_CONTEXT_USE); @@ -2026,13 +2035,28 @@ static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp) static void bnx2x_read_mf_cfg(struct bnx2x *bp) { - int vn; + int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1); if (BP_NOMCP(bp)) return; /* what should be the default bvalue in this case */ + /* For 2 port configuration the absolute function number formula + * is: + * abs_func = 2 * vn + BP_PORT + BP_PATH + * + * and there are 4 functions per port + * + * For 4 port configuration it is + * abs_func = 4 * vn + 2 * BP_PORT + BP_PATH + * + * and there are 2 functions per port + */ for (vn = VN_0; vn < E1HVN_MAX; vn++) { - int /*abs*/func = 2*vn + BP_PORT(bp); + int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp); + + if (func >= E1H_FUNC_MAX) + break; + bp->mf_config[vn] = MF_CFG_RD(bp, func_mf_config[func].config); } @@ -2238,6 +2262,15 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param) return rc; } +static u8 stat_counter_valid(struct bnx2x *bp, struct bnx2x_fastpath *fp) +{ +#ifdef BCM_CNIC + if (IS_FCOE_FP(fp) && IS_MF(bp)) + return false; +#endif + return true; +} + /* must be called under rtnl_lock */ static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters) { @@ -2248,10 +2281,21 @@ static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters) u8 accp_all_ucast = 0, accp_all_bcast = 0, accp_all_mcast = 0; u8 unmatched_unicast = 0; + if (filters & BNX2X_ACCEPT_UNMATCHED_UCAST) + unmatched_unicast = 1; + if (filters & BNX2X_PROMISCUOUS_MODE) { /* promiscious - accept all, drop none */ drop_all_ucast = drop_all_bcast = drop_all_mcast = 0; accp_all_ucast = accp_all_bcast = accp_all_mcast = 1; + if (IS_MF_SI(bp)) { + /* + * SI mode defines to accept in promiscuos mode + * only unmatched packets + */ + unmatched_unicast = 1; + accp_all_ucast = 0; + } } if (filters & BNX2X_ACCEPT_UNICAST) { /* accept matched ucast */ @@ -2260,6 +2304,11 @@ static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters) if (filters & BNX2X_ACCEPT_MULTICAST) { /* accept matched mcast */ drop_all_mcast = 0; + if (IS_MF_SI(bp)) + /* since mcast addresses won't arrive with ovlan, + * fw needs to accept all of them in + * switch-independent mode */ + accp_all_mcast = 1; } if (filters & BNX2X_ACCEPT_ALL_UNICAST) { /* accept all mcast */ @@ -2372,7 +2421,7 @@ static inline u16 bnx2x_get_cl_flags(struct bnx2x *bp, /* calculate queue flags */ flags |= QUEUE_FLG_CACHE_ALIGN; flags |= QUEUE_FLG_HC; - flags |= IS_MF(bp) ? QUEUE_FLG_OV : 0; + flags |= IS_MF_SD(bp) ? QUEUE_FLG_OV : 0; flags |= QUEUE_FLG_VLAN; DP(NETIF_MSG_IFUP, "vlan removal enabled\n"); @@ -2380,7 +2429,8 @@ static inline u16 bnx2x_get_cl_flags(struct bnx2x *bp, if (!fp->disable_tpa) flags |= QUEUE_FLG_TPA; - flags |= QUEUE_FLG_STATS; + flags = stat_counter_valid(bp, fp) ? + (flags | QUEUE_FLG_STATS) : (flags & ~QUEUE_FLG_STATS); return flags; } @@ -2440,7 +2490,10 @@ static void bnx2x_pf_rx_cl_prep(struct bnx2x *bp, rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT; rxq_init->fw_sb_id = fp->fw_sb_id; - rxq_init->sb_cq_index = U_SB_ETH_RX_CQ_INDEX; + if (IS_FCOE_FP(fp)) + rxq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS; + else + rxq_init->sb_cq_index = U_SB_ETH_RX_CQ_INDEX; rxq_init->cid = HW_CID(bp, fp->cid); @@ -2460,6 +2513,12 @@ static void bnx2x_pf_tx_cl_prep(struct bnx2x *bp, txq_init->sb_cq_index = C_SB_ETH_TX_CQ_INDEX; txq_init->traffic_type = LLFC_TRAFFIC_TYPE_NW; txq_init->fw_sb_id = fp->fw_sb_id; + + if (IS_FCOE_FP(fp)) { + txq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS; + txq_init->traffic_type = LLFC_TRAFFIC_TYPE_FCOE; + } + txq_init->hc_rate = bp->tx_ticks ? (1000000 / bp->tx_ticks) : 0; } @@ -2573,6 +2632,26 @@ static void bnx2x_e1h_enable(struct bnx2x *bp) */ } +/* called due to MCP event (on pmf): + * reread new bandwidth configuration + * configure FW + * notify others function about the change + */ +static inline void bnx2x_config_mf_bw(struct bnx2x *bp) +{ + if (bp->link_vars.link_up) { + bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX); + bnx2x_link_sync_notify(bp); + } + storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp)); +} + +static inline void bnx2x_set_mf_bw(struct bnx2x *bp) +{ + bnx2x_config_mf_bw(bp); + bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW_ACK, 0); +} + static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event) { DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event); @@ -2598,10 +2677,7 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event) dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF; } if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) { - - bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX); - bnx2x_link_sync_notify(bp); - storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp)); + bnx2x_config_mf_bw(bp); dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION; } @@ -3022,10 +3098,20 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) if (val & DRV_STATUS_DCC_EVENT_MASK) bnx2x_dcc_event(bp, (val & DRV_STATUS_DCC_EVENT_MASK)); + + if (val & DRV_STATUS_SET_MF_BW) + bnx2x_set_mf_bw(bp); + bnx2x__link_status_update(bp); if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF)) bnx2x_pmf_update(bp); + if (bp->port.pmf && + (val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) && + bp->dcbx_enabled > 0) + /* start dcbx state machine */ + bnx2x_dcbx_set_params(bp, + BNX2X_DCBX_STATE_NEG_RECEIVED); } else if (attn & BNX2X_MC_ASSERT_BITS) { BNX2X_ERR("MC assert!\n"); @@ -3637,11 +3723,23 @@ static void bnx2x_eq_int(struct bnx2x *bp) #ifdef BCM_CNIC if (!bnx2x_cnic_handle_cfc_del(bp, cid, elem)) goto next_spqe; + if (cid == BNX2X_FCOE_ETH_CID) + bnx2x_fcoe(bp, state) = BNX2X_FP_STATE_CLOSED; + else #endif - bnx2x_fp(bp, cid, state) = + bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED; goto next_spqe; + + case EVENT_RING_OPCODE_STOP_TRAFFIC: + DP(NETIF_MSG_IFUP, "got STOP TRAFFIC\n"); + bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_PAUSED); + goto next_spqe; + case EVENT_RING_OPCODE_START_TRAFFIC: + DP(NETIF_MSG_IFUP, "got START TRAFFIC\n"); + bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_RELEASED); + goto next_spqe; } switch (opcode | bp->state) { @@ -3714,7 +3812,13 @@ static void bnx2x_sp_task(struct work_struct *work) /* SP events: STAT_QUERY and others */ if (status & BNX2X_DEF_SB_IDX) { +#ifdef BCM_CNIC + struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp); + if ((!NO_FCOE(bp)) && + (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) + napi_schedule(&bnx2x_fcoe(bp, napi)); +#endif /* Handle EQ completions */ bnx2x_eq_int(bp); @@ -4097,7 +4201,7 @@ void bnx2x_update_coalesce(struct bnx2x *bp) { int i; - for_each_queue(bp, i) + for_each_eth_queue(bp, i) bnx2x_update_coalesce_sb(bp, bp->fp[i].fw_sb_id, bp->rx_ticks, bp->tx_ticks); } @@ -4145,13 +4249,16 @@ static void bnx2x_init_ind_table(struct bnx2x *bp) for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_INDIRECTION_TABLE_OFFSET(func) + i, - bp->fp->cl_id + (i % bp->num_queues)); + bp->fp->cl_id + (i % (bp->num_queues - + NONE_ETH_CONTEXT_USE))); } void bnx2x_set_storm_rx_mode(struct bnx2x *bp) { int mode = bp->rx_mode; + int port = BP_PORT(bp); u16 cl_id; + u32 def_q_filters = 0; /* All but management unicast packets should pass to the host as well */ u32 llh_mask = @@ -4162,30 +4269,42 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp) switch (mode) { case BNX2X_RX_MODE_NONE: /* no Rx */ - cl_id = BP_L_ID(bp); - bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_NONE); + def_q_filters = BNX2X_ACCEPT_NONE; +#ifdef BCM_CNIC + if (!NO_FCOE(bp)) { + cl_id = bnx2x_fcoe(bp, cl_id); + bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_NONE); + } +#endif break; case BNX2X_RX_MODE_NORMAL: - cl_id = BP_L_ID(bp); - bnx2x_rxq_set_mac_filters(bp, cl_id, - BNX2X_ACCEPT_UNICAST | - BNX2X_ACCEPT_BROADCAST | - BNX2X_ACCEPT_MULTICAST); + def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST | + BNX2X_ACCEPT_MULTICAST; +#ifdef BCM_CNIC + cl_id = bnx2x_fcoe(bp, cl_id); + bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST | + BNX2X_ACCEPT_MULTICAST); +#endif break; case BNX2X_RX_MODE_ALLMULTI: - cl_id = BP_L_ID(bp); - bnx2x_rxq_set_mac_filters(bp, cl_id, - BNX2X_ACCEPT_UNICAST | - BNX2X_ACCEPT_BROADCAST | - BNX2X_ACCEPT_ALL_MULTICAST); + def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST | + BNX2X_ACCEPT_ALL_MULTICAST; +#ifdef BCM_CNIC + cl_id = bnx2x_fcoe(bp, cl_id); + bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST | + BNX2X_ACCEPT_MULTICAST); +#endif break; case BNX2X_RX_MODE_PROMISC: - cl_id = BP_L_ID(bp); - bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_PROMISCUOUS_MODE); - + def_q_filters |= BNX2X_PROMISCUOUS_MODE; +#ifdef BCM_CNIC + cl_id = bnx2x_fcoe(bp, cl_id); + bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST | + BNX2X_ACCEPT_MULTICAST); +#endif /* pass management unicast packets as well */ llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST; break; @@ -4195,20 +4314,24 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp) break; } + cl_id = BP_L_ID(bp); + bnx2x_rxq_set_mac_filters(bp, cl_id, def_q_filters); + REG_WR(bp, - BP_PORT(bp) ? NIG_REG_LLH1_BRB1_DRV_MASK : - NIG_REG_LLH0_BRB1_DRV_MASK, - llh_mask); + (port ? NIG_REG_LLH1_BRB1_DRV_MASK : + NIG_REG_LLH0_BRB1_DRV_MASK), llh_mask); DP(NETIF_MSG_IFUP, "rx mode %d\n" "drop_ucast 0x%x\ndrop_mcast 0x%x\ndrop_bcast 0x%x\n" - "accp_ucast 0x%x\naccp_mcast 0x%x\naccp_bcast 0x%x\n", mode, + "accp_ucast 0x%x\naccp_mcast 0x%x\naccp_bcast 0x%x\n" + "unmatched_ucast 0x%x\n", mode, bp->mac_filters.ucast_drop_all, bp->mac_filters.mcast_drop_all, bp->mac_filters.bcast_drop_all, bp->mac_filters.ucast_accept_all, bp->mac_filters.mcast_accept_all, - bp->mac_filters.bcast_accept_all + bp->mac_filters.bcast_accept_all, + bp->mac_filters.unmatched_unicast ); storm_memset_mac_filters(bp, &bp->mac_filters, BP_FUNC(bp)); @@ -4232,6 +4355,15 @@ static void bnx2x_init_internal_common(struct bnx2x *bp) bp->mf_mode); } + if (IS_MF_SI(bp)) + /* + * In switch independent mode, the TSTORM needs to accept + * packets that failed classification, since approximate match + * mac addresses aren't written to NIG LLH + */ + REG_WR8(bp, BAR_TSTRORM_INTMEM + + TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 2); + /* Zero this manually as its initialization is currently missing in the initTool */ for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++) @@ -4247,6 +4379,7 @@ static void bnx2x_init_internal_common(struct bnx2x *bp) static void bnx2x_init_internal_port(struct bnx2x *bp) { /* port */ + bnx2x_dcb_init_intmem_pfc(bp); } static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code) @@ -4308,9 +4441,11 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) { int i; - for_each_queue(bp, i) + for_each_eth_queue(bp, i) bnx2x_init_fp_sb(bp, i); #ifdef BCM_CNIC + if (!NO_FCOE(bp)) + bnx2x_init_fcoe_fp(bp); bnx2x_init_sb(bp, bp->cnic_sb_mapping, BNX2X_VF_ID_INVALID, false, @@ -5048,12 +5183,12 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code) REG_WR(bp, PRS_REG_NIC_MODE, 1); #endif if (!CHIP_IS_E1(bp)) - REG_WR(bp, PRS_REG_E1HOV_MODE, IS_MF(bp)); + REG_WR(bp, PRS_REG_E1HOV_MODE, IS_MF_SD(bp)); if (CHIP_IS_E2(bp)) { /* Bit-map indicating which L2 hdrs may appear after the basic Ethernet header */ - int has_ovlan = IS_MF(bp); + int has_ovlan = IS_MF_SD(bp); REG_WR(bp, PRS_REG_HDRS_AFTER_BASIC, (has_ovlan ? 7 : 6)); REG_WR(bp, PRS_REG_MUST_HAVE_HDRS, (has_ovlan ? 1 : 0)); } @@ -5087,7 +5222,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code) bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE); if (CHIP_IS_E2(bp)) { - int has_ovlan = IS_MF(bp); + int has_ovlan = IS_MF_SD(bp); REG_WR(bp, PBF_REG_HDRS_AFTER_BASIC, (has_ovlan ? 7 : 6)); REG_WR(bp, PBF_REG_MUST_HAVE_HDRS, (has_ovlan ? 1 : 0)); } @@ -5164,12 +5299,12 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code) bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE); if (!CHIP_IS_E1(bp)) { REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_MF(bp)); - REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_MF(bp)); + REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_MF_SD(bp)); } if (CHIP_IS_E2(bp)) { /* Bit-map indicating which L2 hdrs may appear after the basic Ethernet header */ - REG_WR(bp, NIG_REG_P0_HDRS_AFTER_BASIC, (IS_MF(bp) ? 7 : 6)); + REG_WR(bp, NIG_REG_P0_HDRS_AFTER_BASIC, (IS_MF_SD(bp) ? 7 : 6)); } if (CHIP_REV_IS_SLOW(bp)) @@ -5370,8 +5505,10 @@ static int bnx2x_init_hw_port(struct bnx2x *bp) * - SF mode: bits 3-7 are masked. only bits 0-2 are in use * - MF mode: bit 3 is masked. bits 0-2 are in use as in SF * bits 4-7 are used for "per vn group attention" */ - REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, - (IS_MF(bp) ? 0xF7 : 0x7)); + val = IS_MF(bp) ? 0xF7 : 0x7; + /* Enable DCBX attention for all but E1 */ + val |= CHIP_IS_E1(bp) ? 0 : 0x10; + REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, val); bnx2x_init_block(bp, PXPCS_BLOCK, init_stage); bnx2x_init_block(bp, EMAC0_BLOCK, init_stage); @@ -5386,7 +5523,7 @@ static int bnx2x_init_hw_port(struct bnx2x *bp) if (!CHIP_IS_E1(bp)) { /* 0x2 disable mf_ov, 0x1 enable */ REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4, - (IS_MF(bp) ? 0x1 : 0x2)); + (IS_MF_SD(bp) ? 0x1 : 0x2)); if (CHIP_IS_E2(bp)) { val = 0; @@ -5816,6 +5953,15 @@ void bnx2x_free_mem(struct bnx2x *bp) /* fastpath */ /* Common */ for_each_queue(bp, i) { +#ifdef BCM_CNIC + /* FCoE client uses default status block */ + if (IS_FCOE_IDX(i)) { + union host_hc_status_block *sb = + &bnx2x_fp(bp, i, status_blk); + memset(sb, 0, sizeof(union host_hc_status_block)); + bnx2x_fp(bp, i, status_blk_mapping) = 0; + } else { +#endif /* status blocks */ if (CHIP_IS_E2(bp)) BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e2_sb), @@ -5825,9 +5971,12 @@ void bnx2x_free_mem(struct bnx2x *bp) BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e1x_sb), bnx2x_fp(bp, i, status_blk_mapping), sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif } /* Rx */ - for_each_queue(bp, i) { + for_each_rx_queue(bp, i) { /* fastpath rx rings: rx_buf rx_desc rx_comp */ BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring)); @@ -5847,7 +5996,7 @@ void bnx2x_free_mem(struct bnx2x *bp) BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); } /* Tx */ - for_each_queue(bp, i) { + for_each_tx_queue(bp, i) { /* fastpath tx rings: tx_buf tx_desc */ BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); @@ -5931,15 +6080,20 @@ int bnx2x_alloc_mem(struct bnx2x *bp) union host_hc_status_block *sb = &bnx2x_fp(bp, i, status_blk); bnx2x_fp(bp, i, bp) = bp; /* status blocks */ - if (CHIP_IS_E2(bp)) - BNX2X_PCI_ALLOC(sb->e2_sb, - &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e2)); - else - BNX2X_PCI_ALLOC(sb->e1x_sb, - &bnx2x_fp(bp, i, status_blk_mapping), - sizeof(struct host_hc_status_block_e1x)); - +#ifdef BCM_CNIC + if (!IS_FCOE_IDX(i)) { +#endif + if (CHIP_IS_E2(bp)) + BNX2X_PCI_ALLOC(sb->e2_sb, + &bnx2x_fp(bp, i, status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_ALLOC(sb->e1x_sb, + &bnx2x_fp(bp, i, status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif set_sb_shortcuts(bp, i); } /* Rx */ @@ -6055,7 +6209,7 @@ static int bnx2x_func_stop(struct bnx2x *bp) * @param cam_offset offset in a CAM to use * @param is_bcast is the set MAC a broadcast address (for E1 only) */ -static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, u8 *mac, +static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, const u8 *mac, u32 cl_bit_vec, u8 cam_offset, u8 is_bcast) { @@ -6170,6 +6324,70 @@ static u8 bnx2x_e1h_cam_offset(struct bnx2x *bp, u8 rel_offset) return BP_VN(bp) * 32 + rel_offset; } +/** + * LLH CAM line allocations: currently only iSCSI and ETH macs are + * relevant. In addition, current implementation is tuned for a + * single ETH MAC. + * + * When multiple unicast ETH MACs PF configuration in switch + * independent mode is required (NetQ, multiple netdev MACs, + * etc.), consider better utilisation of 16 per function MAC + * entries in the LLH memory. + */ +enum { + LLH_CAM_ISCSI_ETH_LINE = 0, + LLH_CAM_ETH_LINE, + LLH_CAM_MAX_PF_LINE = NIG_REG_LLH1_FUNC_MEM_SIZE +}; + +static void bnx2x_set_mac_in_nig(struct bnx2x *bp, + int set, + unsigned char *dev_addr, + int index) +{ + u32 wb_data[2]; + u32 mem_offset, ena_offset, mem_index; + /** + * indexes mapping: + * 0..7 - goes to MEM + * 8..15 - goes to MEM2 + */ + + if (!IS_MF_SI(bp) || index > LLH_CAM_MAX_PF_LINE) + return; + + /* calculate memory start offset according to the mapping + * and index in the memory */ + if (index < NIG_LLH_FUNC_MEM_MAX_OFFSET) { + mem_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM : + NIG_REG_LLH0_FUNC_MEM; + ena_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM_ENABLE : + NIG_REG_LLH0_FUNC_MEM_ENABLE; + mem_index = index; + } else { + mem_offset = BP_PORT(bp) ? NIG_REG_P1_LLH_FUNC_MEM2 : + NIG_REG_P0_LLH_FUNC_MEM2; + ena_offset = BP_PORT(bp) ? NIG_REG_P1_LLH_FUNC_MEM2_ENABLE : + NIG_REG_P0_LLH_FUNC_MEM2_ENABLE; + mem_index = index - NIG_LLH_FUNC_MEM_MAX_OFFSET; + } + + if (set) { + /* LLH_FUNC_MEM is a u64 WB register */ + mem_offset += 8*mem_index; + + wb_data[0] = ((dev_addr[2] << 24) | (dev_addr[3] << 16) | + (dev_addr[4] << 8) | dev_addr[5]); + wb_data[1] = ((dev_addr[0] << 8) | dev_addr[1]); + + REG_WR_DMAE(bp, mem_offset, wb_data, 2); + } + + /* enable/disable the entry */ + REG_WR(bp, ena_offset + 4*mem_index, set); + +} + void bnx2x_set_eth_mac(struct bnx2x *bp, int set) { u8 cam_offset = (CHIP_IS_E1(bp) ? (BP_PORT(bp) ? 32 : 0) : @@ -6179,9 +6397,13 @@ void bnx2x_set_eth_mac(struct bnx2x *bp, int set) bnx2x_set_mac_addr_gen(bp, set, bp->dev->dev_addr, (1 << bp->fp->cl_id), cam_offset , 0); + bnx2x_set_mac_in_nig(bp, set, bp->dev->dev_addr, LLH_CAM_ETH_LINE); + if (CHIP_IS_E1(bp)) { /* broadcast MAC */ - u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + static const u8 bcast[ETH_ALEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; bnx2x_set_mac_addr_gen(bp, set, bcast, 0, cam_offset + 1, 1); } } @@ -6283,12 +6505,59 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set) { u8 cam_offset = (CHIP_IS_E1(bp) ? ((BP_PORT(bp) ? 32 : 0) + 2) : bnx2x_e1h_cam_offset(bp, CAM_ISCSI_ETH_LINE)); - u32 iscsi_l2_cl_id = BNX2X_ISCSI_ETH_CL_ID; + u32 iscsi_l2_cl_id = BNX2X_ISCSI_ETH_CL_ID + + BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE; u32 cl_bit_vec = (1 << iscsi_l2_cl_id); /* Send a SET_MAC ramrod */ bnx2x_set_mac_addr_gen(bp, set, bp->iscsi_mac, cl_bit_vec, cam_offset, 0); + + bnx2x_set_mac_in_nig(bp, set, bp->iscsi_mac, LLH_CAM_ISCSI_ETH_LINE); + + return 0; +} + +/** + * Set FCoE L2 MAC(s) at the next enties in the CAM after the + * ETH MAC(s). This function will wait until the ramdord + * completion returns. + * + * @param bp driver handle + * @param set set or clear the CAM entry + * + * @return 0 if cussess, -ENODEV if ramrod doesn't return. + */ +int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set) +{ + u32 cl_bit_vec = (1 << bnx2x_fcoe(bp, cl_id)); + /** + * CAM allocation for E1H + * eth unicasts: by func number + * iscsi: by func number + * fip unicast: by func number + * fip multicast: by func number + */ + bnx2x_set_mac_addr_gen(bp, set, bp->fip_mac, + cl_bit_vec, bnx2x_e1h_cam_offset(bp, CAM_FIP_ETH_LINE), 0); + + return 0; +} + +int bnx2x_set_all_enode_macs(struct bnx2x *bp, int set) +{ + u32 cl_bit_vec = (1 << bnx2x_fcoe(bp, cl_id)); + + /** + * CAM allocation for E1H + * eth unicasts: by func number + * iscsi: by func number + * fip unicast: by func number + * fip multicast: by func number + */ + bnx2x_set_mac_addr_gen(bp, set, ALL_ENODE_MACS, cl_bit_vec, + bnx2x_e1h_cam_offset(bp, CAM_FIP_MCAST_LINE), 0); + return 0; } #endif @@ -6306,6 +6575,8 @@ static void bnx2x_fill_cl_init_data(struct bnx2x *bp, data->general.statistics_counter_id = params->rxq_params.stat_id; data->general.statistics_en_flg = (params->rxq_params.flags & QUEUE_FLG_STATS) ? 1 : 0; + data->general.is_fcoe_flg = + (params->ramrod_params.flags & CLIENT_IS_FCOE) ? 1 : 0; data->general.activate_flg = activate; data->general.sp_client_id = params->rxq_params.spcl_id; @@ -6374,7 +6645,9 @@ static void bnx2x_fill_cl_init_data(struct bnx2x *bp, data->fc.safc_group_num = params->txq_params.cos; data->fc.safc_group_en_flg = (params->txq_params.flags & QUEUE_FLG_COS) ? 1 : 0; - data->fc.traffic_type = LLFC_TRAFFIC_TYPE_NW; + data->fc.traffic_type = + (params->ramrod_params.flags & CLIENT_IS_FCOE) ? + LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW; } static inline void bnx2x_set_ctx_validation(struct eth_context *cxt, u32 cid) @@ -6473,7 +6746,7 @@ static int __devinit bnx2x_set_int_mode(struct bnx2x *bp) bnx2x_enable_msi(bp); /* falling through... */ case INT_MODE_INTx: - bp->num_queues = 1; + bp->num_queues = 1 + NONE_ETH_CONTEXT_USE; DP(NETIF_MSG_IFUP, "set number of queues to 1\n"); break; default: @@ -6496,8 +6769,8 @@ static int __devinit bnx2x_set_int_mode(struct bnx2x *bp) "enable MSI-X (%d), " "set number of queues to %d\n", bp->num_queues, - 1); - bp->num_queues = 1; + 1 + NONE_ETH_CONTEXT_USE); + bp->num_queues = 1 + NONE_ETH_CONTEXT_USE; if (!(bp->flags & DISABLE_MSI_FLAG)) bnx2x_enable_msi(bp); @@ -6618,7 +6891,9 @@ int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp, struct bnx2x_client_init_params params = { {0} }; int rc; - bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, + /* reset IGU state skip FCoE L2 queue */ + if (!IS_FCOE_FP(fp)) + bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_ENABLE, 0); params.ramrod_params.pstate = &fp->state; @@ -6626,6 +6901,12 @@ int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp, params.ramrod_params.index = fp->index; params.ramrod_params.cid = fp->cid; +#ifdef BCM_CNIC + if (IS_FCOE_FP(fp)) + params.ramrod_params.flags |= CLIENT_IS_FCOE; + +#endif + if (is_leading) params.ramrod_params.flags |= CLIENT_IS_LEADING_RSS; @@ -6710,7 +6991,7 @@ static void bnx2x_reset_func(struct bnx2x *bp) REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(func), 0); /* FP SBs */ - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; REG_WR8(bp, BAR_CSTRORM_INTMEM + @@ -6830,6 +7111,20 @@ static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code) } } +#ifdef BCM_CNIC +static inline void bnx2x_del_fcoe_eth_macs(struct bnx2x *bp) +{ + if (bp->flags & FCOE_MACS_SET) { + if (!IS_MF_SD(bp)) + bnx2x_set_fip_eth_mac_addr(bp, 0); + + bnx2x_set_all_enode_macs(bp, 0); + + bp->flags &= ~FCOE_MACS_SET; + } +} +#endif + void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode) { int port = BP_PORT(bp); @@ -6837,7 +7132,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode) int i, cnt, rc; /* Wait until tx fastpath tasks complete */ - for_each_queue(bp, i) { + for_each_tx_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; cnt = 1000; @@ -6877,13 +7172,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode) } #ifdef BCM_CNIC - /* Clear iSCSI L2 MAC */ - mutex_lock(&bp->cnic_mutex); - if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) { - bnx2x_set_iscsi_eth_mac_addr(bp, 0); - bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET; - } - mutex_unlock(&bp->cnic_mutex); + bnx2x_del_fcoe_eth_macs(bp); #endif if (unload_mode == UNLOAD_NORMAL) @@ -7736,7 +8025,7 @@ static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp) bp->igu_sb_cnt = 0; if (CHIP_INT_MODE_IS_BC(bp)) { bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x, - bp->l2_cid_count); + NUM_IGU_SB_REQUIRED(bp->l2_cid_count)); bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) * FP_SB_MAX_E1x; @@ -7767,7 +8056,8 @@ static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp) } } } - bp->igu_sb_cnt = min_t(u8, bp->igu_sb_cnt, bp->l2_cid_count); + bp->igu_sb_cnt = min_t(u8, bp->igu_sb_cnt, + NUM_IGU_SB_REQUIRED(bp->l2_cid_count)); if (bp->igu_sb_cnt == 0) BNX2X_ERR("CAM configuration error\n"); } @@ -8076,9 +8366,8 @@ static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi) static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) { int port = BP_PORT(bp); - u32 val, val2; u32 config; - u32 ext_phy_type, ext_phy_config;; + u32 ext_phy_type, ext_phy_config; bp->link_params.bp = bp; bp->link_params.port = port; @@ -8135,25 +8424,73 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) bp->mdio.prtad = XGXS_EXT_PHY_ADDR(ext_phy_config); +} + +static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) +{ + u32 val, val2; + int func = BP_ABS_FUNC(bp); + int port = BP_PORT(bp); + + if (BP_NOMCP(bp)) { + BNX2X_ERROR("warning: random MAC workaround active\n"); + random_ether_addr(bp->dev->dev_addr); + } else if (IS_MF(bp)) { + val2 = MF_CFG_RD(bp, func_mf_config[func].mac_upper); + val = MF_CFG_RD(bp, func_mf_config[func].mac_lower); + if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) && + (val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) + bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2); + +#ifdef BCM_CNIC + /* iSCSI NPAR MAC */ + if (IS_MF_SI(bp)) { + u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg); + if (cfg & MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD) { + val2 = MF_CFG_RD(bp, func_ext_config[func]. + iscsi_mac_addr_upper); + val = MF_CFG_RD(bp, func_ext_config[func]. + iscsi_mac_addr_lower); + bnx2x_set_mac_buf(bp->iscsi_mac, val, val2); + } + } +#endif + } else { + /* in SF read MACs from port configuration */ + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); + val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); + bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2); + +#ifdef BCM_CNIC + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port]. + iscsi_mac_upper); + val = SHMEM_RD(bp, dev_info.port_hw_config[port]. + iscsi_mac_lower); + bnx2x_set_mac_buf(bp->iscsi_mac, val, val2); +#endif + } - val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); - val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); - bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2); memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN); memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN); #ifdef BCM_CNIC - val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_upper); - val = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_lower); - bnx2x_set_mac_buf(bp->iscsi_mac, val, val2); + /* Inform the upper layers about FCoE MAC */ + if (!CHIP_IS_E1x(bp)) { + if (IS_MF_SD(bp)) + memcpy(bp->fip_mac, bp->dev->dev_addr, + sizeof(bp->fip_mac)); + else + memcpy(bp->fip_mac, bp->iscsi_mac, + sizeof(bp->fip_mac)); + } #endif } static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) { - int func = BP_ABS_FUNC(bp); - int vn; - u32 val, val2; + int /*abs*/func = BP_ABS_FUNC(bp); + int vn, port; + u32 val = 0; int rc = 0; bnx2x_get_common_hwinfo(bp); @@ -8163,7 +8500,8 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->igu_dsb_id = DEF_SB_IGU_ID; bp->igu_base_sb = 0; - bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x, bp->l2_cid_count); + bp->igu_sb_cnt = min_t(u8, FP_SB_MAX_E1x, + NUM_IGU_SB_REQUIRED(bp->l2_cid_count)); } else { bp->common.int_block = INT_BLOCK_IGU; val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION); @@ -8186,44 +8524,99 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_ov = 0; bp->mf_mode = 0; vn = BP_E1HVN(bp); + port = BP_PORT(bp); + if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { + DP(NETIF_MSG_PROBE, + "shmem2base 0x%x, size %d, mfcfg offset %d\n", + bp->common.shmem2_base, SHMEM2_RD(bp, size), + (u32)offsetof(struct shmem2_region, mf_cfg_addr)); if (SHMEM2_HAS(bp, mf_cfg_addr)) bp->common.mf_cfg_base = SHMEM2_RD(bp, mf_cfg_addr); else bp->common.mf_cfg_base = bp->common.shmem_base + offsetof(struct shmem_region, func_mb) + E1H_FUNC_MAX * sizeof(struct drv_func_mb); - bp->mf_config[vn] = - MF_CFG_RD(bp, func_mf_config[func].config); + /* + * get mf configuration: + * 1. existance of MF configuration + * 2. MAC address must be legal (check only upper bytes) + * for Switch-Independent mode; + * OVLAN must be legal for Switch-Dependent mode + * 3. SF_MODE configures specific MF mode + */ + if (bp->common.mf_cfg_base != SHMEM_MF_CFG_ADDR_NONE) { + /* get mf configuration */ + val = SHMEM_RD(bp, + dev_info.shared_feature_config.config); + val &= SHARED_FEAT_CFG_FORCE_SF_MODE_MASK; + + switch (val) { + case SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT: + val = MF_CFG_RD(bp, func_mf_config[func]. + mac_upper); + /* check for legal mac (upper bytes)*/ + if (val != 0xffff) { + bp->mf_mode = MULTI_FUNCTION_SI; + bp->mf_config[vn] = MF_CFG_RD(bp, + func_mf_config[func].config); + } else + DP(NETIF_MSG_PROBE, "illegal MAC " + "address for SI\n"); + break; + case SHARED_FEAT_CFG_FORCE_SF_MODE_MF_ALLOWED: + /* get OV configuration */ + val = MF_CFG_RD(bp, + func_mf_config[FUNC_0].e1hov_tag); + val &= FUNC_MF_CFG_E1HOV_TAG_MASK; + + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { + bp->mf_mode = MULTI_FUNCTION_SD; + bp->mf_config[vn] = MF_CFG_RD(bp, + func_mf_config[func].config); + } else + DP(NETIF_MSG_PROBE, "illegal OV for " + "SD\n"); + break; + default: + /* Unknown configuration: reset mf_config */ + bp->mf_config[vn] = 0; + DP(NETIF_MSG_PROBE, "Unkown MF mode 0x%x\n", + val); + } + } - val = (MF_CFG_RD(bp, func_mf_config[FUNC_0].e1hov_tag) & - FUNC_MF_CFG_E1HOV_TAG_MASK); - if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) - bp->mf_mode = 1; BNX2X_DEV_INFO("%s function mode\n", IS_MF(bp) ? "multi" : "single"); - if (IS_MF(bp)) { - val = (MF_CFG_RD(bp, func_mf_config[func]. - e1hov_tag) & - FUNC_MF_CFG_E1HOV_TAG_MASK); + switch (bp->mf_mode) { + case MULTI_FUNCTION_SD: + val = MF_CFG_RD(bp, func_mf_config[func].e1hov_tag) & + FUNC_MF_CFG_E1HOV_TAG_MASK; if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { bp->mf_ov = val; - BNX2X_DEV_INFO("MF OV for func %d is %d " - "(0x%04x)\n", - func, bp->mf_ov, bp->mf_ov); + BNX2X_DEV_INFO("MF OV for func %d is %d" + " (0x%04x)\n", func, + bp->mf_ov, bp->mf_ov); } else { - BNX2X_ERROR("No valid MF OV for func %d," - " aborting\n", func); + BNX2X_ERR("No valid MF OV for func %d," + " aborting\n", func); rc = -EPERM; } - } else { - if (BP_VN(bp)) { - BNX2X_ERROR("VN %d in single function mode," - " aborting\n", BP_E1HVN(bp)); + break; + case MULTI_FUNCTION_SI: + BNX2X_DEV_INFO("func %d is in MF " + "switch-independent mode\n", func); + break; + default: + if (vn) { + BNX2X_ERR("VN %d in single function mode," + " aborting\n", vn); rc = -EPERM; } + break; } + } /* adjust igu_sb_cnt to MF for E1x */ @@ -8248,32 +8641,8 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); } - if (IS_MF(bp)) { - val2 = MF_CFG_RD(bp, func_mf_config[func].mac_upper); - val = MF_CFG_RD(bp, func_mf_config[func].mac_lower); - if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) && - (val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) { - bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); - bp->dev->dev_addr[1] = (u8)(val2 & 0xff); - bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff); - bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff); - bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff); - bp->dev->dev_addr[5] = (u8)(val & 0xff); - memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, - ETH_ALEN); - memcpy(bp->dev->perm_addr, bp->dev->dev_addr, - ETH_ALEN); - } - - return rc; - } - - if (BP_NOMCP(bp)) { - /* only supposed to happen on emulation/FPGA */ - BNX2X_ERROR("warning: random MAC workaround active\n"); - random_ether_addr(bp->dev->dev_addr); - memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN); - } + /* Get MAC addresses */ + bnx2x_get_mac_hwinfo(bp); return rc; } @@ -8427,6 +8796,9 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) bp->timer.data = (unsigned long) bp; bp->timer.function = bnx2x_timer; + bnx2x_dcbx_set_state(bp, true, BNX2X_DCBX_ENABLED_ON_NEG_ON); + bnx2x_dcbx_init_params(bp); + return rc; } @@ -8629,6 +9001,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_open = bnx2x_open, .ndo_stop = bnx2x_close, .ndo_start_xmit = bnx2x_start_xmit, + .ndo_select_queue = bnx2x_select_queue, .ndo_set_multicast_list = bnx2x_set_rx_mode, .ndo_set_mac_address = bnx2x_change_mac_addr, .ndo_validate_addr = eth_validate_addr, @@ -8761,7 +9134,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->netdev_ops = &bnx2x_netdev_ops; bnx2x_set_ethtool_ops(dev); dev->features |= NETIF_F_SG; - dev->features |= NETIF_F_HW_CSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; if (bp->flags & USING_DAC_FLAG) dev->features |= NETIF_F_HIGHDMA; dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); @@ -8769,12 +9142,16 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); dev->vlan_features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_HW_CSUM; + dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; if (bp->flags & USING_DAC_FLAG) dev->vlan_features |= NETIF_F_HIGHDMA; dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); dev->vlan_features |= NETIF_F_TSO6; +#ifdef BCM_DCB + dev->dcbnl_ops = &bnx2x_dcbnl_ops; +#endif + /* get_port_hwinfo() will set prtad and mmds properly */ bp->mdio.prtad = MDIO_PRTAD_NONE; bp->mdio.mmds = 0; @@ -9067,7 +9444,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, return -ENODEV; } - cid_count += CNIC_CONTEXT_USE; + cid_count += NONE_ETH_CONTEXT_USE + CNIC_CONTEXT_USE; /* dev zeroed in init_etherdev */ dev = alloc_etherdev_mq(sizeof(*bp), cid_count); @@ -9096,11 +9473,12 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, /* calc qm_cid_count */ bp->qm_cid_count = bnx2x_set_qm_cid_count(bp, cid_count); - rc = register_netdev(dev); - if (rc) { - dev_err(&pdev->dev, "Cannot register net device\n"); - goto init_one_exit; - } +#ifdef BCM_CNIC + /* disable FCOE L2 queue for E1x*/ + if (CHIP_IS_E1x(bp)) + bp->flags |= NO_FCOE_FLAG; + +#endif /* Configure interupt mode: try to enable MSI-X/MSI if * needed, set bp->num_queues appropriately. @@ -9110,6 +9488,21 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, /* Add all NAPI objects */ bnx2x_add_all_napi(bp); + rc = register_netdev(dev); + if (rc) { + dev_err(&pdev->dev, "Cannot register net device\n"); + goto init_one_exit; + } + +#ifdef BCM_CNIC + if (!NO_FCOE(bp)) { + /* Add storage MAC address */ + rtnl_lock(); + dev_addr_add(bp->dev, bp->fip_mac, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } +#endif + bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed); netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx," @@ -9153,6 +9546,15 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev) } bp = netdev_priv(dev); +#ifdef BCM_CNIC + /* Delete storage MAC address */ + if (!NO_FCOE(bp)) { + rtnl_lock(); + dev_addr_del(bp->dev, bp->fip_mac, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } +#endif + unregister_netdev(dev); /* Delete all NAPI objects */ @@ -9202,7 +9604,7 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp) /* Free SKBs, SGEs, TPA pool and driver internals */ bnx2x_free_skbs(bp); - for_each_queue(bp, i) + for_each_rx_queue(bp, i) bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); bnx2x_free_mem(bp); @@ -9429,7 +9831,8 @@ static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count) break; else atomic_dec(&bp->spq_left); - } else if (type == ISCSI_CONNECTION_TYPE) { + } else if ((type == ISCSI_CONNECTION_TYPE) || + (type == FCOE_CONNECTION_TYPE)) { if (bp->cnic_spq_pending >= bp->cnic_eth_dev.max_kwqe_pending) break; @@ -9576,6 +9979,9 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) case DRV_CTL_START_L2_CMD: { u32 cli = ctl->data.ring.client_id; + /* Clear FCoE FIP and ALL ENODE MACs addresses first */ + bnx2x_del_fcoe_eth_macs(bp); + /* Set iSCSI MAC address */ bnx2x_set_iscsi_eth_mac_addr(bp, 1); @@ -9697,10 +10103,6 @@ static int bnx2x_unregister_cnic(struct net_device *dev) struct cnic_eth_dev *cp = &bp->cnic_eth_dev; mutex_lock(&bp->cnic_mutex); - if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) { - bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET; - bnx2x_set_iscsi_eth_mac_addr(bp, 0); - } cp->drv_state = 0; rcu_assign_pointer(bp->cnic_ops, NULL); mutex_unlock(&bp->cnic_mutex); @@ -9731,7 +10133,9 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) cp->drv_ctl = bnx2x_drv_ctl; cp->drv_register_cnic = bnx2x_register_cnic; cp->drv_unregister_cnic = bnx2x_unregister_cnic; - cp->iscsi_l2_client_id = BNX2X_ISCSI_ETH_CL_ID; + cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID; + cp->iscsi_l2_client_id = BNX2X_ISCSI_ETH_CL_ID + + BP_E1HVN(bp) * NONE_ETH_CONTEXT_USE; cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID; DP(BNX2X_MSG_SP, "page_size %d, tbl_offset %d, tbl_lines %d, " diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 1cefe489a95..bfd875b7290 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -1615,6 +1615,8 @@ #define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4) #define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2) #define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3) +#define NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN (0x1<<0) +#define NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN (0x1<<0) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9) #define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15) @@ -1744,12 +1746,16 @@ ~ppp_enable.ppp_enable = 0 and pause_enable.pause_enable =0 for the same port */ #define NIG_REG_LLFC_ENABLE_0 0x16208 +#define NIG_REG_LLFC_ENABLE_1 0x1620c /* [RW 16] classes are high-priority for port0 */ #define NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0 0x16058 +#define NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 0x1605c /* [RW 16] classes are low-priority for port0 */ #define NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0 0x16060 +#define NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 0x16064 /* [RW 1] Output enable of message to LLFC BMAC IF for port0 */ #define NIG_REG_LLFC_OUT_EN_0 0x160c8 +#define NIG_REG_LLFC_OUT_EN_1 0x160cc #define NIG_REG_LLH0_ACPI_PAT_0_CRC 0x1015c #define NIG_REG_LLH0_ACPI_PAT_6_LEN 0x10154 #define NIG_REG_LLH0_BRB1_DRV_MASK 0x10244 @@ -1774,6 +1780,8 @@ /* [RW 8] event id for llh0 */ #define NIG_REG_LLH0_EVENT_ID 0x10084 #define NIG_REG_LLH0_FUNC_EN 0x160fc +#define NIG_REG_LLH0_FUNC_MEM 0x16180 +#define NIG_REG_LLH0_FUNC_MEM_ENABLE 0x16140 #define NIG_REG_LLH0_FUNC_VLAN_ID 0x16100 /* [RW 1] Determine the IP version to look for in ~nig_registers_llh0_dest_ip_0.llh0_dest_ip_0. 0 - IPv6; 1-IPv4 */ @@ -1797,6 +1805,9 @@ #define NIG_REG_LLH1_ERROR_MASK 0x10090 /* [RW 8] event id for llh1 */ #define NIG_REG_LLH1_EVENT_ID 0x10088 +#define NIG_REG_LLH1_FUNC_MEM 0x161c0 +#define NIG_REG_LLH1_FUNC_MEM_ENABLE 0x16160 +#define NIG_REG_LLH1_FUNC_MEM_SIZE 16 /* [RW 8] init credit counter for port1 in LLH */ #define NIG_REG_LLH1_XCM_INIT_CREDIT 0x10564 #define NIG_REG_LLH1_XCM_MASK 0x10134 @@ -1907,11 +1918,17 @@ ~safc_enable.safc_enable = 0 and ppp_enable.ppp_enable =0 for the same port */ #define NIG_REG_PAUSE_ENABLE_0 0x160c0 +#define NIG_REG_PAUSE_ENABLE_1 0x160c4 /* [RW 1] Input enable for RX PBF LP IF */ #define NIG_REG_PBF_LB_IN_EN 0x100b4 /* [RW 1] Value of this register will be transmitted to port swap when ~nig_registers_strap_override.strap_override =1 */ #define NIG_REG_PORT_SWAP 0x10394 +/* [RW 1] PPP enable for port0. This register may get 1 only when + * ~safc_enable.safc_enable = 0 and pause_enable.pause_enable =0 for the + * same port */ +#define NIG_REG_PPP_ENABLE_0 0x160b0 +#define NIG_REG_PPP_ENABLE_1 0x160b4 /* [RW 1] output enable for RX parser descriptor IF */ #define NIG_REG_PRS_EOP_OUT_EN 0x10104 /* [RW 1] Input enable for RX parser request IF */ @@ -1978,6 +1995,14 @@ #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G (0x1<<15) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS (0xf<<18) #define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE 18 +/* [RW 31] The upper bound of the weight of COS0 in the ETS command arbiter. */ +#define PBF_REG_COS0_UPPER_BOUND 0x15c05c +/* [RW 31] The weight of COS0 in the ETS command arbiter. */ +#define PBF_REG_COS0_WEIGHT 0x15c054 +/* [RW 31] The upper bound of the weight of COS1 in the ETS command arbiter. */ +#define PBF_REG_COS1_UPPER_BOUND 0x15c060 +/* [RW 31] The weight of COS1 in the ETS command arbiter. */ +#define PBF_REG_COS1_WEIGHT 0x15c058 /* [RW 1] Disable processing further tasks from port 0 (after ending the current task in process). */ #define PBF_REG_DISABLE_NEW_TASK_PROC_P0 0x14005c @@ -1988,9 +2013,16 @@ current task in process). */ #define PBF_REG_DISABLE_NEW_TASK_PROC_P4 0x14006c #define PBF_REG_DISABLE_PF 0x1402e8 +/* [RW 1] Indicates that ETS is performed between the COSes in the command + * arbiter. If reset strict priority w/ anti-starvation will be performed + * w/o WFQ. */ +#define PBF_REG_ETS_ENABLED 0x15c050 /* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic * Ethernet header. */ #define PBF_REG_HDRS_AFTER_BASIC 0x15c0a8 +/* [RW 1] Indicates which COS is conncted to the highest priority in the + * command arbiter. */ +#define PBF_REG_HIGH_PRIORITY_COS_NUM 0x15c04c #define PBF_REG_IF_ENABLE_REG 0x140044 /* [RW 1] Init bit. When set the initial credits are copied to the credit registers (except the port credits). Should be set and then reset after @@ -2016,6 +2048,10 @@ #define PBF_REG_MAC_LB_ENABLE 0x140040 /* [RW 6] Bit-map indicating which headers must appear in the packet */ #define PBF_REG_MUST_HAVE_HDRS 0x15c0c4 +/* [RW 16] The number of strict priority arbitration slots between 2 RR + * arbitration slots. A value of 0 means no strict priority cycles; i.e. the + * strict-priority w/ anti-starvation arbiter is a RR arbiter. */ +#define PBF_REG_NUM_STRICT_ARB_SLOTS 0x15c064 /* [RW 10] Port 0 threshold used by arbiter in 16 byte lines used when pause not suppoterd. */ #define PBF_REG_P0_ARB_THRSH 0x1400e4 @@ -4970,7 +5006,23 @@ #define EMAC_REG_EMAC_TX_MODE 0xbc #define EMAC_REG_EMAC_TX_STAT_AC 0x280 #define EMAC_REG_EMAC_TX_STAT_AC_COUNT 22 +#define EMAC_REG_RX_PFC_MODE 0x320 +#define EMAC_REG_RX_PFC_MODE_PRIORITIES (1L<<2) +#define EMAC_REG_RX_PFC_MODE_RX_EN (1L<<1) +#define EMAC_REG_RX_PFC_MODE_TX_EN (1L<<0) +#define EMAC_REG_RX_PFC_PARAM 0x324 +#define EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT 0 +#define EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT 16 +#define EMAC_REG_RX_PFC_STATS_XOFF_RCVD 0x328 +#define EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT (0xffff<<0) +#define EMAC_REG_RX_PFC_STATS_XOFF_SENT 0x330 +#define EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT (0xffff<<0) +#define EMAC_REG_RX_PFC_STATS_XON_RCVD 0x32c +#define EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT (0xffff<<0) +#define EMAC_REG_RX_PFC_STATS_XON_SENT 0x334 +#define EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT (0xffff<<0) #define EMAC_RX_MODE_FLOW_EN (1L<<2) +#define EMAC_RX_MODE_KEEP_MAC_CONTROL (1L<<3) #define EMAC_RX_MODE_KEEP_VLAN_TAG (1L<<10) #define EMAC_RX_MODE_PROMISCUOUS (1L<<8) #define EMAC_RX_MODE_RESET (1L<<0) diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c index 4733c835dad..6e4d9b144cc 100644 --- a/drivers/net/bnx2x/bnx2x_stats.c +++ b/drivers/net/bnx2x/bnx2x_stats.c @@ -160,7 +160,7 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp) ramrod_data.drv_counter = bp->stats_counter++; ramrod_data.collect_port = bp->port.pmf ? 1 : 0; - for_each_queue(bp, i) + for_each_eth_queue(bp, i) ramrod_data.ctr_id_vector |= (1 << bp->fp[i].cl_id); rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0, @@ -766,7 +766,7 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp) estats->no_buff_discard_hi = 0; estats->no_buff_discard_lo = 0; - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; int cl_id = fp->cl_id; struct tstorm_per_client_stats *tclient = @@ -996,7 +996,7 @@ static void bnx2x_net_stats_update(struct bnx2x *bp) nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi); tmp = estats->mac_discard; - for_each_queue(bp, i) + for_each_rx_queue(bp, i) tmp += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard); nstats->rx_dropped = tmp; @@ -1087,7 +1087,7 @@ static void bnx2x_stats_update(struct bnx2x *bp) bp->dev->name, estats->brb_drop_lo, estats->brb_truncate_lo); - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats; @@ -1101,7 +1101,7 @@ static void bnx2x_stats_update(struct bnx2x *bp) fp->rx_calls, fp->rx_pkt); } - for_each_queue(bp, i) { + for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats; struct netdev_queue *txq = @@ -1381,7 +1381,8 @@ void bnx2x_stats_init(struct bnx2x *bp) memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats)); } - for_each_queue(bp, i) { + /* FW stats are currently collected for ETH clients only */ + for_each_eth_queue(bp, i) { /* Set initial stats counter in the stats ramrod data to -1 */ int cl_id = bp->fp[i].cl_id; diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h index afd15efa429..596798c4745 100644 --- a/drivers/net/bnx2x/bnx2x_stats.h +++ b/drivers/net/bnx2x/bnx2x_stats.h @@ -53,7 +53,6 @@ struct bnx2x_eth_q_stats { u32 hw_csum_err; }; -#define BNX2X_NUM_Q_STATS 13 #define Q_STATS_OFFSET32(stat_name) \ (offsetof(struct bnx2x_eth_q_stats, stat_name) / 4) @@ -225,7 +224,6 @@ struct bnx2x_eth_stats { u32 nig_timer_max; }; -#define BNX2X_NUM_STATS 43 #define STATS_OFFSET32(stat_name) \ (offsetof(struct bnx2x_eth_stats, stat_name) / 4) |