diff options
Diffstat (limited to 'drivers/net/bnx2x_main.c')
-rw-r--r-- | drivers/net/bnx2x_main.c | 3875 |
1 files changed, 2423 insertions, 1452 deletions
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index efa942688f84..90b54e4c5c3b 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1,4 +1,4 @@ -/* bnx2x.c: Broadcom Everest network driver. +/* bnx2x_main.c: Broadcom Everest network driver. * * Copyright (c) 2007-2008 Broadcom Corporation * @@ -15,12 +15,6 @@ * */ -/* define this to make the driver freeze on error - * to allow getting debug info - * (you will need to reboot afterwards) - */ -/*#define BNX2X_STOP_ON_ERROR*/ - #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -46,16 +40,17 @@ #include <linux/mii.h> #ifdef NETIF_F_HW_VLAN_TX #include <linux/if_vlan.h> - #define BCM_VLAN 1 #endif #include <net/ip.h> #include <net/tcp.h> #include <net/checksum.h> +#include <linux/version.h> +#include <net/ip6_checksum.h> #include <linux/workqueue.h> #include <linux/crc32.h> +#include <linux/crc32c.h> #include <linux/prefetch.h> #include <linux/zlib.h> -#include <linux/version.h> #include <linux/io.h> #include "bnx2x_reg.h" @@ -67,13 +62,13 @@ #define DRV_MODULE_VERSION "1.42.4" #define DRV_MODULE_RELDATE "2008/4/9" -#define BNX2X_BC_VER 0x040200 +#define BNX2X_BC_VER 0x040200 -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (5*HZ) +/* Time in jiffies before concluding the transmitter is hung */ +#define TX_TIMEOUT (5*HZ) static char version[] __devinitdata = - "Broadcom NetXtreme II 5771X 10Gigabit Ethernet Driver " + "Broadcom NetXtreme II 5771x 10Gigabit Ethernet Driver " DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Eliezer Tamir"); @@ -83,20 +78,19 @@ MODULE_VERSION(DRV_MODULE_VERSION); static int use_inta; static int poll; -static int onefunc; -static int nomcp; static int debug; +static int nomcp; +static int load_count[3]; /* 0-common, 1-port0, 2-port1 */ static int use_multi; module_param(use_inta, int, 0); module_param(poll, int, 0); -module_param(onefunc, int, 0); module_param(debug, int, 0); +module_param(nomcp, int, 0); MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X"); MODULE_PARM_DESC(poll, "use polling (for debug)"); -MODULE_PARM_DESC(onefunc, "enable only first function"); -MODULE_PARM_DESC(nomcp, "ignore management CPU (Implies onefunc)"); MODULE_PARM_DESC(debug, "default debug msglevel"); +MODULE_PARM_DESC(nomcp, "ignore management CPU"); #ifdef BNX2X_MULTI module_param(use_multi, int, 0); @@ -105,18 +99,27 @@ MODULE_PARM_DESC(use_multi, "use per-CPU queues"); enum bnx2x_board_type { BCM57710 = 0, + BCM57711 = 1, + BCM57711E = 2, }; -/* indexed by board_t, above */ +/* indexed by board_type, above */ static struct { char *name; } board_info[] __devinitdata = { - { "Broadcom NetXtreme II BCM57710 XGb" } + { "Broadcom NetXtreme II BCM57710 XGb" }, + { "Broadcom NetXtreme II BCM57711 XGb" }, + { "Broadcom NetXtreme II BCM57711E XGb" } }; + static const struct pci_device_id bnx2x_pci_tbl[] = { { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711 }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711E }, { 0 } }; @@ -201,7 +204,8 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, #else DMAE_CMD_ENDIANITY_DW_SWAP | #endif - (bp->port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); dmae->src_addr_lo = U64_LO(dma_addr); dmae->src_addr_hi = U64_HI(dma_addr); dmae->dst_addr_lo = dst_addr >> 2; @@ -224,7 +228,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, *wb_comp = 0; - bnx2x_post_dmae(bp, dmae, (bp->port)*MAX_DMAE_C_PER_PORT); + bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); udelay(5); @@ -277,7 +281,8 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) #else DMAE_CMD_ENDIANITY_DW_SWAP | #endif - (bp->port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) | + (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT)); dmae->src_addr_lo = src_addr >> 2; dmae->src_addr_hi = 0; dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); @@ -297,7 +302,7 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) *wb_comp = 0; - bnx2x_post_dmae(bp, dmae, (bp->port)*MAX_DMAE_C_PER_PORT); + bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); udelay(5); @@ -345,47 +350,122 @@ static u64 bnx2x_wb_rd(struct bnx2x *bp, int reg) static int bnx2x_mc_assert(struct bnx2x *bp) { - int i, j, rc = 0; char last_idx; - const char storm[] = {"XTCU"}; - const u32 intmem_base[] = { - BAR_XSTRORM_INTMEM, - BAR_TSTRORM_INTMEM, - BAR_CSTRORM_INTMEM, - BAR_USTRORM_INTMEM - }; - - /* Go through all instances of all SEMIs */ - for (i = 0; i < 4; i++) { - last_idx = REG_RD8(bp, XSTORM_ASSERT_LIST_INDEX_OFFSET + - intmem_base[i]); - if (last_idx) - BNX2X_LOG("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n", - storm[i], last_idx); - - /* print the asserts */ - for (j = 0; j < STROM_ASSERT_ARRAY_SIZE; j++) { - u32 row0, row1, row2, row3; - - row0 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + - intmem_base[i]); - row1 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 4 + - intmem_base[i]); - row2 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 8 + - intmem_base[i]); - row3 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 12 + - intmem_base[i]); - - if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { - BNX2X_LOG("DATA %cSTORM_ASSERT_INDEX 0x%x =" - " 0x%08x 0x%08x 0x%08x 0x%08x\n", - storm[i], j, row3, row2, row1, row0); - rc++; - } else { - break; - } + int i, rc = 0; + u32 row0, row1, row2, row3; + + /* XSTORM */ + last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* TSTORM */ + last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* CSTORM */ + last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; } } + + /* USTORM */ + last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + return rc; } @@ -428,14 +508,16 @@ static void bnx2x_panic_dump(struct bnx2x *bp) struct eth_tx_db_data *hw_prods = fp->hw_tx_prods; BNX2X_ERR("queue[%d]: tx_pkt_prod(%x) tx_pkt_cons(%x)" - " tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)" - " *rx_cons_sb(%x) rx_comp_prod(%x)" - " rx_comp_cons(%x) fp_c_idx(%x) fp_u_idx(%x)" - " bd data(%x,%x)\n", + " tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)\n", i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod, - fp->tx_bd_cons, *fp->tx_cons_sb, *fp->rx_cons_sb, - fp->rx_comp_prod, fp->rx_comp_cons, fp->fp_c_idx, - fp->fp_u_idx, hw_prods->packets_prod, + fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb)); + BNX2X_ERR(" rx_comp_prod(%x) rx_comp_cons(%x)" + " *rx_cons_sb(%x)\n", + fp->rx_comp_prod, fp->rx_comp_cons, + le16_to_cpu(*fp->rx_cons_sb)); + BNX2X_ERR(" fp_c_idx(%x) fp_u_idx(%x)" + " bd data(%x,%x)\n", + fp->fp_c_idx, fp->fp_u_idx, hw_prods->packets_prod, hw_prods->bds_prod); start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10); @@ -463,7 +545,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp) struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j]; BNX2X_ERR("rx_bd[%x]=[%x:%x] sw_bd=[%p]\n", - j, rx_bd[0], rx_bd[1], sw_bd->skb); + j, rx_bd[1], rx_bd[0], sw_bd->skb); } start = RCQ_BD(fp->rx_comp_cons - 10); @@ -482,7 +564,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp) bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx, bp->def_att_idx, bp->attn_state, bp->spq_prod_idx); - + bnx2x_fw_dump(bp); bnx2x_mc_assert(bp); BNX2X_ERR("end crash dump -----------------\n"); @@ -492,7 +574,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp) static void bnx2x_int_enable(struct bnx2x *bp) { - int port = bp->port; + int port = BP_PORT(bp); u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; u32 val = REG_RD(bp, addr); int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; @@ -507,7 +589,6 @@ static void bnx2x_int_enable(struct bnx2x *bp) HC_CONFIG_0_REG_INT_LINE_EN_0 | HC_CONFIG_0_REG_ATTN_BIT_EN_0); - /* Errata A0.158 workaround */ DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) MSI-X %d\n", val, port, addr, msix); @@ -520,11 +601,25 @@ static void bnx2x_int_enable(struct bnx2x *bp) val, port, addr, msix); REG_WR(bp, addr, val); + + if (CHIP_IS_E1H(bp)) { + /* init leading/trailing edge */ + if (IS_E1HMF(bp)) { + val = (0xfe0f | (1 << (BP_E1HVN(bp) + 4))); + if (bp->port.pmf) + /* enable nig attention */ + val |= 0x0100; + } else + val = 0xffff; + + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); + } } static void bnx2x_int_disable(struct bnx2x *bp) { - int port = bp->port; + int port = BP_PORT(bp); u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; u32 val = REG_RD(bp, addr); @@ -543,10 +638,10 @@ static void bnx2x_int_disable(struct bnx2x *bp) static void bnx2x_int_disable_sync(struct bnx2x *bp) { - int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; int i; + /* disable interrupt handling */ atomic_inc(&bp->intr_sem); /* prevent the HW from sending interrupts */ bnx2x_int_disable(bp); @@ -563,30 +658,29 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp) /* make sure sp_task is not running */ cancel_work_sync(&bp->sp_task); - } -/* fast path code */ +/* fast path */ /* - * general service functions + * General service functions */ -static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 id, +static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id, u8 storm, u16 index, u8 op, u8 update) { - u32 igu_addr = (IGU_ADDR_INT_ACK + IGU_PORT_BASE * bp->port) * 8; + u32 igu_addr = (IGU_ADDR_INT_ACK + IGU_FUNC_BASE * BP_FUNC(bp)) * 8; struct igu_ack_register igu_ack; igu_ack.status_block_index = index; igu_ack.sb_id_and_flags = - ((id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) | + ((sb_id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) | (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) | (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) | (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT)); -/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", - (*(u32 *)&igu_ack), BAR_IGU_INTMEM + igu_addr); */ + DP(BNX2X_MSG_OFF, "write 0x%08x to IGU addr 0x%x\n", + (*(u32 *)&igu_ack), BAR_IGU_INTMEM + igu_addr); REG_WR(bp, BAR_IGU_INTMEM + igu_addr, (*(u32 *)&igu_ack)); } @@ -614,8 +708,9 @@ static inline int bnx2x_has_work(struct bnx2x_fastpath *fp) if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) rx_cons_sb++; - if ((rx_cons_sb != fp->rx_comp_cons) || - (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons)) + if ((fp->rx_comp_cons != rx_cons_sb) || + (fp->tx_pkt_prod != le16_to_cpu(*fp->tx_cons_sb)) || + (fp->tx_pkt_prod != fp->tx_pkt_cons)) return 1; return 0; @@ -623,11 +718,11 @@ static inline int bnx2x_has_work(struct bnx2x_fastpath *fp) static u16 bnx2x_ack_int(struct bnx2x *bp) { - u32 igu_addr = (IGU_ADDR_SIMD_MASK + IGU_PORT_BASE * bp->port) * 8; + u32 igu_addr = (IGU_ADDR_SIMD_MASK + IGU_FUNC_BASE * BP_FUNC(bp)) * 8; u32 result = REG_RD(bp, BAR_IGU_INTMEM + igu_addr); -/* DP(NETIF_MSG_INTR, "read 0x%08x from IGU addr 0x%x\n", - result, BAR_IGU_INTMEM + igu_addr); */ + DP(BNX2X_MSG_OFF, "read 0x%08x from IGU addr 0x%x\n", + result, BAR_IGU_INTMEM + igu_addr); #ifdef IGU_DEBUG #warning IGU_DEBUG active @@ -653,7 +748,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx]; struct eth_tx_bd *tx_bd; struct sk_buff *skb = tx_buf->skb; - u16 bd_idx = tx_buf->first_bd; + u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons; int nbd; DP(BNX2X_MSG_OFF, "pkt_idx %d buff @(%p)->skb %p\n", @@ -666,9 +761,10 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); nbd = le16_to_cpu(tx_bd->nbd) - 1; + new_cons = nbd + tx_buf->first_bd; #ifdef BNX2X_STOP_ON_ERROR if (nbd > (MAX_SKB_FRAGS + 2)) { - BNX2X_ERR("bad nbd!\n"); + BNX2X_ERR("BAD nbd!\n"); bnx2x_panic(); } #endif @@ -708,32 +804,30 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, tx_buf->first_bd = 0; tx_buf->skb = NULL; - return bd_idx; + return new_cons; } -static inline u32 bnx2x_tx_avail(struct bnx2x_fastpath *fp) +static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp) { - u16 used; - u32 prod; - u32 cons; + s16 used; + u16 prod; + u16 cons; - /* Tell compiler that prod and cons can change */ - barrier(); + barrier(); /* Tell compiler that prod and cons can change */ prod = fp->tx_bd_prod; cons = fp->tx_bd_cons; - used = (NUM_TX_BD - NUM_TX_RINGS + prod - cons + - (cons / TX_DESC_CNT) - (prod / TX_DESC_CNT)); - - if (prod >= cons) { - /* used = prod - cons - prod/size + cons/size */ - used -= NUM_TX_BD - NUM_TX_RINGS; - } + /* NUM_TX_RINGS = number of "next-page" entries + It will be used as a threshold */ + used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS; +#ifdef BNX2X_STOP_ON_ERROR + BUG_TRAP(used >= 0); BUG_TRAP(used <= fp->bp->tx_ring_size); BUG_TRAP((fp->bp->tx_ring_size - used) <= MAX_TX_AVAIL); +#endif - return (fp->bp->tx_ring_size - used); + return (s16)(fp->bp->tx_ring_size) - used; } static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work) @@ -757,10 +851,10 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work) /* prefetch(bp->tx_buf_ring[pkt_cons].skb); */ - DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %d\n", + DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %u\n", hw_cons, sw_cons, pkt_cons); -/* if (NEXT_TX_IDX(sw_cons) != hw_cons) { +/* if (NEXT_TX_IDX(sw_cons) != hw_cons) { rmb(); prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb); } @@ -793,7 +887,6 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work) netif_wake_queue(bp->dev); netif_tx_unlock(bp->dev); - } } @@ -804,13 +897,14 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp, int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data); int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data); - DP(NETIF_MSG_RX_STATUS, + DP(BNX2X_MSG_SP, "fp %d cid %d got ramrod #%d state is %x type is %d\n", - fp->index, cid, command, bp->state, rr_cqe->ramrod_cqe.type); + FP_IDX(fp), cid, command, bp->state, + rr_cqe->ramrod_cqe.ramrod_type); bp->spq_left++; - if (fp->index) { + if (FP_IDX(fp)) { switch (command | fp->state) { case (RAMROD_CMD_ID_ETH_CLIENT_SETUP | BNX2X_FP_STATE_OPENING): @@ -826,10 +920,11 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp, break; default: - BNX2X_ERR("unexpected MC reply(%d) state is %x\n", - command, fp->state); + BNX2X_ERR("unexpected MC reply (%d) " + "fp->state is %x\n", command, fp->state); + break; } - mb(); /* force bnx2x_wait_ramrod to see the change */ + mb(); /* force bnx2x_wait_ramrod() to see the change */ return; } @@ -846,25 +941,25 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp, break; case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT): - DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", - cid); + DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid); bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED; break; case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN): + case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG): DP(NETIF_MSG_IFUP, "got set mac ramrod\n"); break; case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT): - DP(NETIF_MSG_IFUP, "got (un)set mac ramrod\n"); + DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n"); break; default: - BNX2X_ERR("unexpected ramrod (%d) state is %x\n", + BNX2X_ERR("unexpected MC reply (%d) bp->state is %x\n", command, bp->state); + break; } - - mb(); /* force bnx2x_wait_ramrod to see the change */ + mb(); /* force bnx2x_wait_ramrod() to see the change */ } static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, @@ -882,7 +977,6 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); if (unlikely(dma_mapping_error(mapping))) { - dev_kfree_skb(skb); return -ENOMEM; } @@ -924,7 +1018,7 @@ static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp, static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) { struct bnx2x *bp = fp->bp; - u16 bd_cons, bd_prod, comp_ring_cons; + u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons; u16 hw_comp_cons, sw_comp_cons, sw_comp_prod; int rx_pkt = 0; @@ -933,12 +1027,15 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) return 0; #endif + /* CQ "next element" is of the size of the regular element, + that's why it's ok here */ hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb); if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) hw_comp_cons++; bd_cons = fp->rx_bd_cons; bd_prod = fp->rx_bd_prod; + bd_prod_fw = bd_prod; sw_comp_cons = fp->rx_comp_cons; sw_comp_prod = fp->rx_comp_prod; @@ -949,34 +1046,31 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) DP(NETIF_MSG_RX_STATUS, "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n", - fp->index, hw_comp_cons, sw_comp_cons); + FP_IDX(fp), hw_comp_cons, sw_comp_cons); while (sw_comp_cons != hw_comp_cons) { - unsigned int len, pad; - struct sw_rx_bd *rx_buf; + struct sw_rx_bd *rx_buf = NULL; struct sk_buff *skb; union eth_rx_cqe *cqe; + u8 cqe_fp_flags; + u16 len, pad; comp_ring_cons = RCQ_BD(sw_comp_cons); bd_prod = RX_BD(bd_prod); bd_cons = RX_BD(bd_cons); cqe = &fp->rx_comp_ring[comp_ring_cons]; + cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; - DP(NETIF_MSG_RX_STATUS, "hw_comp_cons %u sw_comp_cons %u" - " comp_ring (%u) bd_ring (%u,%u)\n", - hw_comp_cons, sw_comp_cons, - comp_ring_cons, bd_prod, bd_cons); DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x" - " queue %x vlan %x len %x\n", - cqe->fast_path_cqe.type, - cqe->fast_path_cqe.error_type_flags, - cqe->fast_path_cqe.status_flags, + " queue %x vlan %x len %u\n", CQE_TYPE(cqe_fp_flags), + cqe_fp_flags, cqe->fast_path_cqe.status_flags, cqe->fast_path_cqe.rss_hash_result, - cqe->fast_path_cqe.vlan_tag, cqe->fast_path_cqe.pkt_len); + le16_to_cpu(cqe->fast_path_cqe.vlan_tag), + le16_to_cpu(cqe->fast_path_cqe.pkt_len)); /* is this a slowpath msg? */ - if (unlikely(cqe->fast_path_cqe.type)) { + if (unlikely(CQE_TYPE(cqe_fp_flags))) { bnx2x_sp_event(fp, cqe); goto next_cqe; @@ -984,7 +1078,6 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) } else { rx_buf = &fp->rx_buf_ring[bd_cons]; skb = rx_buf->skb; - len = le16_to_cpu(cqe->fast_path_cqe.pkt_len); pad = cqe->fast_path_cqe.placement_offset; @@ -996,13 +1089,11 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) prefetch(((char *)(skb)) + 128); /* is this an error packet? */ - if (unlikely(cqe->fast_path_cqe.error_type_flags & - ETH_RX_ERROR_FALGS)) { + if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) { /* do we sometimes forward error packets anyway? */ DP(NETIF_MSG_RX_ERR, - "ERROR flags(%u) Rx packet(%u)\n", - cqe->fast_path_cqe.error_type_flags, - sw_comp_cons); + "ERROR flags %x rx packet %u\n", + cqe_fp_flags, sw_comp_cons); /* TBD make sure MC counts this as a drop */ goto reuse_rx; } @@ -1018,7 +1109,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) len + pad); if (new_skb == NULL) { DP(NETIF_MSG_RX_ERR, - "ERROR packet dropped " + "ERROR packet dropped " "because of alloc failure\n"); /* TBD count this as a drop? */ goto reuse_rx; @@ -1044,7 +1135,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) } else { DP(NETIF_MSG_RX_ERR, - "ERROR packet dropped because " + "ERROR packet dropped because " "of alloc failure\n"); reuse_rx: bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod); @@ -1061,14 +1152,14 @@ reuse_rx: } #ifdef BCM_VLAN - if ((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) - & PARSING_FLAGS_NUMBER_OF_NESTED_VLANS) - && (bp->vlgrp != NULL)) + if ((bp->vlgrp != NULL) && + (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & + PARSING_FLAGS_VLAN)) vlan_hwaccel_receive_skb(skb, bp->vlgrp, le16_to_cpu(cqe->fast_path_cqe.vlan_tag)); else #endif - netif_receive_skb(skb); + netif_receive_skb(skb); bp->dev->last_rx = jiffies; @@ -1077,22 +1168,25 @@ next_rx: bd_cons = NEXT_RX_IDX(bd_cons); bd_prod = NEXT_RX_IDX(bd_prod); + bd_prod_fw = NEXT_RX_IDX(bd_prod_fw); + rx_pkt++; next_cqe: sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod); sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons); - rx_pkt++; - if ((rx_pkt == budget)) + if (rx_pkt == budget) break; } /* while */ fp->rx_bd_cons = bd_cons; - fp->rx_bd_prod = bd_prod; + fp->rx_bd_prod = bd_prod_fw; fp->rx_comp_cons = sw_comp_cons; fp->rx_comp_prod = sw_comp_prod; REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_RCQ_PROD_OFFSET(bp->port, fp->index), sw_comp_prod); + TSTORM_RX_PRODS_OFFSET(BP_PORT(bp), FP_CL_ID(fp)), + sw_comp_prod); + mmiowb(); /* keep prod updates ordered */ @@ -1107,10 +1201,11 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) struct bnx2x_fastpath *fp = fp_cookie; struct bnx2x *bp = fp->bp; struct net_device *dev = bp->dev; - int index = fp->index; + int index = FP_IDX(fp); - DP(NETIF_MSG_INTR, "got an msix interrupt on [%d]\n", index); - bnx2x_ack_sb(bp, index, USTORM_ID, 0, IGU_INT_DISABLE, 0); + DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n", + index, FP_SB_ID(fp)); + bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID, 0, IGU_INT_DISABLE, 0); #ifdef BNX2X_STOP_ON_ERROR if (unlikely(bp->panic)) @@ -1123,6 +1218,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) prefetch(&fp->status_blk->u_status_block.status_block_index); netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi)); + return IRQ_HANDLED; } @@ -1131,26 +1227,28 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) struct net_device *dev = dev_instance; struct bnx2x *bp = netdev_priv(dev); u16 status = bnx2x_ack_int(bp); + u16 mask; + /* Return here if interrupt is shared and it's not for us */ if (unlikely(status == 0)) { DP(NETIF_MSG_INTR, "not our interrupt!\n"); return IRQ_NONE; } - - DP(NETIF_MSG_INTR, "got an interrupt status is %u\n", status); + DP(NETIF_MSG_INTR, "got an interrupt status %u\n", status); #ifdef BNX2X_STOP_ON_ERROR if (unlikely(bp->panic)) return IRQ_HANDLED; #endif - /* Return here if interrupt is shared and is disabled */ + /* Return here if interrupt is disabled */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) { DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); return IRQ_HANDLED; } - if (status & 0x2) { + mask = 0x2 << bp->fp[0].sb_id; + if (status & mask) { struct bnx2x_fastpath *fp = &bp->fp[0]; prefetch(fp->rx_cons_sb); @@ -1160,13 +1258,11 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi)); - status &= ~0x2; - if (!status) - return IRQ_HANDLED; + status &= ~mask; } - if (unlikely(status & 0x1)) { + if (unlikely(status & 0x1)) { schedule_work(&bp->sp_task); status &= ~0x1; @@ -1174,8 +1270,9 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) return IRQ_HANDLED; } - DP(NETIF_MSG_INTR, "got an unknown interrupt! (status is %u)\n", - status); + if (status) + DP(NETIF_MSG_INTR, "got an unknown interrupt! (status %u)\n", + status); return IRQ_HANDLED; } @@ -1193,7 +1290,7 @@ static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource) { u32 lock_status; u32 resource_bit = (1 << resource); - u8 port = bp->port; + u8 port = BP_PORT(bp); int cnt; /* Validating that the resource is within range */ @@ -1231,7 +1328,7 @@ static int bnx2x_hw_unlock(struct bnx2x *bp, u32 resource) { u32 lock_status; u32 resource_bit = (1 << resource); - u8 port = bp->port; + u8 port = BP_PORT(bp); /* Validating that the resource is within range */ if (resource > HW_LOCK_MAX_RESOURCE_VALUE) { @@ -1258,7 +1355,7 @@ static void bnx2x_phy_hw_lock(struct bnx2x *bp) { u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); - mutex_lock(&bp->phy_mutex); + mutex_lock(&bp->port.phy_mutex); if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072) || (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) @@ -1273,14 +1370,14 @@ static void bnx2x_phy_hw_unlock(struct bnx2x *bp) (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)) bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO); - mutex_unlock(&bp->phy_mutex); + mutex_unlock(&bp->port.phy_mutex); } int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode) { /* The GPIO should be swapped if swap register is set and active */ int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) && - REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ bp->port; + REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ BP_PORT(bp); int gpio_shift = gpio_num + (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0); u32 gpio_mask = (1 << gpio_shift); @@ -1379,18 +1476,18 @@ static void bnx2x_calc_fc_adv(struct bnx2x *bp) { switch (bp->link_vars.ieee_fc) { case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE: - bp->advertising &= ~(ADVERTISED_Asym_Pause | + bp->port.advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); break; case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH: - bp->advertising |= (ADVERTISED_Asym_Pause | + bp->port.advertising |= (ADVERTISED_Asym_Pause | ADVERTISED_Pause); break; case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC: - bp->advertising |= ADVERTISED_Asym_Pause; + bp->port.advertising |= ADVERTISED_Asym_Pause; break; default: - bp->advertising &= ~(ADVERTISED_Asym_Pause | + bp->port.advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); break; } @@ -1443,6 +1540,7 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp) bnx2x_link_report(bp); bnx2x_calc_fc_adv(bp); + return rc; } @@ -1473,15 +1571,261 @@ static u8 bnx2x_link_test(struct bnx2x *bp) return rc; } +/* Calculates the sum of vn_min_rates. + It's needed for further normalizing of the min_rates. + + Returns: + sum of vn_min_rates + or + 0 - if all the min_rates are 0. + In the later case fainess algorithm should be deactivated. + If not all min_rates are zero then those that are zeroes will + be set to 1. + */ +static u32 bnx2x_calc_vn_wsum(struct bnx2x *bp) +{ + int i, port = BP_PORT(bp); + u32 wsum = 0; + int all_zero = 1; + + for (i = 0; i < E1HVN_MAX; i++) { + u32 vn_cfg = + SHMEM_RD(bp, mf_cfg.func_mf_config[2*i + port].config); + u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + if (!(vn_cfg & FUNC_MF_CFG_FUNC_HIDE)) { + /* If min rate is zero - set it to 1 */ + if (!vn_min_rate) + vn_min_rate = DEF_MIN_RATE; + else + all_zero = 0; + + wsum += vn_min_rate; + } + } + + /* ... only if all min rates are zeros - disable FAIRNESS */ + if (all_zero) + return 0; + + return wsum; +} + +static void bnx2x_init_port_minmax(struct bnx2x *bp, + int en_fness, + u16 port_rate, + struct cmng_struct_per_port *m_cmng_port) +{ + u32 r_param = port_rate / 8; + int port = BP_PORT(bp); + int i; + + memset(m_cmng_port, 0, sizeof(struct cmng_struct_per_port)); + + /* Enable minmax only if we are in e1hmf mode */ + if (IS_E1HMF(bp)) { + u32 fair_periodic_timeout_usec; + u32 t_fair; + + /* Enable rate shaping and fairness */ + m_cmng_port->flags.cmng_vn_enable = 1; + m_cmng_port->flags.fairness_enable = en_fness ? 1 : 0; + m_cmng_port->flags.rate_shaping_enable = 1; + + if (!en_fness) + DP(NETIF_MSG_IFUP, "All MIN values are zeroes" + " fairness will be disabled\n"); + + /* 100 usec in SDM ticks = 25 since each tick is 4 usec */ + m_cmng_port->rs_vars.rs_periodic_timeout = + RS_PERIODIC_TIMEOUT_USEC / 4; + + /* this is the threshold below which no timer arming will occur + 1.25 coefficient is for the threshold to be a little bigger + than the real time, to compensate for timer in-accuracy */ + m_cmng_port->rs_vars.rs_threshold = + (RS_PERIODIC_TIMEOUT_USEC * r_param * 5) / 4; + + /* resolution of fairness timer */ + fair_periodic_timeout_usec = QM_ARB_BYTES / r_param; + /* for 10G it is 1000usec. for 1G it is 10000usec. */ + t_fair = T_FAIR_COEF / port_rate; + + /* this is the threshold below which we won't arm + the timer anymore */ + m_cmng_port->fair_vars.fair_threshold = QM_ARB_BYTES; + + /* we multiply by 1e3/8 to get bytes/msec. + We don't want the credits to pass a credit + of the T_FAIR*FAIR_MEM (algorithm resolution) */ + m_cmng_port->fair_vars.upper_bound = + r_param * t_fair * FAIR_MEM; + /* since each tick is 4 usec */ + m_cmng_port->fair_vars.fairness_timeout = + fair_periodic_timeout_usec / 4; + + } else { + /* Disable rate shaping and fairness */ + m_cmng_port->flags.cmng_vn_enable = 0; + m_cmng_port->flags.fairness_enable = 0; + m_cmng_port->flags.rate_shaping_enable = 0; + + DP(NETIF_MSG_IFUP, + "Single function mode minmax will be disabled\n"); + } + + /* Store it to internal memory */ + for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i * 4, + ((u32 *)(m_cmng_port))[i]); +} + +static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func, + u32 wsum, u16 port_rate, + struct cmng_struct_per_port *m_cmng_port) +{ + struct rate_shaping_vars_per_vn m_rs_vn; + struct fairness_vars_per_vn m_fair_vn; + u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); + u16 vn_min_rate, vn_max_rate; + int i; + + /* If function is hidden - set min and max to zeroes */ + if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) { + vn_min_rate = 0; + vn_max_rate = 0; + + } else { + vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + /* If FAIRNESS is enabled (not all min rates are zeroes) and + if current min rate is zero - set it to 1. + This is a requirment of the algorithm. */ + if ((vn_min_rate == 0) && wsum) + vn_min_rate = DEF_MIN_RATE; + vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >> + FUNC_MF_CFG_MAX_BW_SHIFT) * 100; + } + + DP(NETIF_MSG_IFUP, "func %d: vn_min_rate=%d vn_max_rate=%d " + "wsum=%d\n", func, vn_min_rate, vn_max_rate, wsum); + + memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn)); + memset(&m_fair_vn, 0, sizeof(struct fairness_vars_per_vn)); + + /* global vn counter - maximal Mbps for this vn */ + m_rs_vn.vn_counter.rate = vn_max_rate; + + /* quota - number of bytes transmitted in this period */ + m_rs_vn.vn_counter.quota = + (vn_max_rate * RS_PERIODIC_TIMEOUT_USEC) / 8; + +#ifdef BNX2X_PER_PROT_QOS + /* per protocol counter */ + for (protocol = 0; protocol < NUM_OF_PROTOCOLS; protocol++) { + /* maximal Mbps for this protocol */ + m_rs_vn.protocol_counters[protocol].rate = + protocol_max_rate[protocol]; + /* the quota in each timer period - + number of bytes transmitted in this period */ + m_rs_vn.protocol_counters[protocol].quota = + (u32)(rs_periodic_timeout_usec * + ((double)m_rs_vn. + protocol_counters[protocol].rate/8)); + } +#endif + + if (wsum) { + /* credit for each period of the fairness algorithm: + number of bytes in T_FAIR (the vn share the port rate). + wsum should not be larger than 10000, thus + T_FAIR_COEF / (8 * wsum) will always be grater than zero */ + m_fair_vn.vn_credit_delta = + max((u64)(vn_min_rate * (T_FAIR_COEF / (8 * wsum))), + (u64)(m_cmng_port->fair_vars.fair_threshold * 2)); + DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta=%d\n", + m_fair_vn.vn_credit_delta); + } + +#ifdef BNX2X_PER_PROT_QOS + do { + u32 protocolWeightSum = 0; + + for (protocol = 0; protocol < NUM_OF_PROTOCOLS; protocol++) + protocolWeightSum += + drvInit.protocol_min_rate[protocol]; + /* per protocol counter - + NOT NEEDED IF NO PER-PROTOCOL CONGESTION MANAGEMENT */ + if (protocolWeightSum > 0) { + for (protocol = 0; + protocol < NUM_OF_PROTOCOLS; protocol++) + /* credit for each period of the + fairness algorithm - number of bytes in + T_FAIR (the protocol share the vn rate) */ + m_fair_vn.protocol_credit_delta[protocol] = + (u32)((vn_min_rate / 8) * t_fair * + protocol_min_rate / protocolWeightSum); + } + } while (0); +#endif + + /* Store it to internal memory */ + for (i = 0; i < sizeof(struct rate_shaping_vars_per_vn)/4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(func) + i * 4, + ((u32 *)(&m_rs_vn))[i]); + + for (i = 0; i < sizeof(struct fairness_vars_per_vn)/4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(func) + i * 4, + ((u32 *)(&m_fair_vn))[i]); +} + /* This function is called upon link interrupt */ static void bnx2x_link_attn(struct bnx2x *bp) { + int vn; + bnx2x_phy_hw_lock(bp); bnx2x_link_update(&bp->link_params, &bp->link_vars); bnx2x_phy_hw_unlock(bp); /* indicate link status */ bnx2x_link_report(bp); + + if (IS_E1HMF(bp)) { + int func; + + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + if (vn == BP_E1HVN(bp)) + continue; + + func = ((vn << 1) | BP_PORT(bp)); + + /* Set the attention towards other drivers + on the same port */ + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); + } + } + + if (CHIP_IS_E1H(bp) && (bp->link_vars.line_speed > 0)) { + struct cmng_struct_per_port m_cmng_port; + u32 wsum; + int port = BP_PORT(bp); + + /* Init RATE SHAPING and FAIRNESS contexts */ + wsum = bnx2x_calc_vn_wsum(bp); + bnx2x_init_port_minmax(bp, (int)wsum, + bp->link_vars.line_speed, + &m_cmng_port); + if (IS_E1HMF(bp)) + for (vn = VN_0; vn < E1HVN_MAX; vn++) + bnx2x_init_vn_minmax(bp, 2*vn + port, + wsum, bp->link_vars.line_speed, + &m_cmng_port); + } } static void bnx2x__link_status_update(struct bnx2x *bp) @@ -1495,6 +1839,20 @@ static void bnx2x__link_status_update(struct bnx2x *bp) bnx2x_link_report(bp); } +static void bnx2x_pmf_update(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; + + bp->port.pmf = 1; + DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); + + /* enable nig attention */ + val = (0xff0f | (1 << (BP_E1HVN(bp) + 4))); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); +} + /* end of Link */ /* slow path */ @@ -1507,10 +1865,10 @@ static void bnx2x__link_status_update(struct bnx2x *bp) static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, u32 data_hi, u32 data_lo, int common) { - int port = bp->port; + int func = BP_FUNC(bp); - DP(NETIF_MSG_TIMER, - "spe (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n", + DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/, + "SPQE (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n", (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) + (void *)bp->spq_prod_bd - (void *)bp->spq), command, HW_CID(bp, cid), data_hi, data_lo, bp->spq_left); @@ -1520,11 +1878,11 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, return -EIO; #endif - spin_lock(&bp->spq_lock); + spin_lock_bh(&bp->spq_lock); if (!bp->spq_left) { BNX2X_ERR("BUG! SPQ ring full!\n"); - spin_unlock(&bp->spq_lock); + spin_unlock_bh(&bp->spq_lock); bnx2x_panic(); return -EBUSY; } @@ -1553,18 +1911,18 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, bp->spq_prod_idx++; } - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(port), + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func), bp->spq_prod_idx); - spin_unlock(&bp->spq_lock); + spin_unlock_bh(&bp->spq_lock); return 0; } /* acquire split MCP access lock register */ static int bnx2x_lock_alr(struct bnx2x *bp) { - int rc = 0; u32 i, j, val; + int rc = 0; might_sleep(); i = 100; @@ -1577,10 +1935,8 @@ static int bnx2x_lock_alr(struct bnx2x *bp) msleep(5); } - if (!(val & (1L << 31))) { BNX2X_ERR("Cannot acquire nvram interface\n"); - rc = -EBUSY; } @@ -1631,8 +1987,9 @@ static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp) static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) { - int port = bp->port; - u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8; + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_FUNC_BASE * func) * 8; u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : MISC_REG_AEU_MASK_ATTN_FUNC_0; u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 : @@ -1716,14 +2073,14 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) { - int port = bp->port; + int port = BP_PORT(bp); int reg_offset; u32 val; - if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) { + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); - reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : - MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) { val = REG_RD(bp, reg_offset); val &= ~AEU_INPUTS_ATTN_BITS_SPIO5; @@ -1731,7 +2088,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) BNX2X_ERR("SPIO5 hw attention\n"); - switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) { + switch (bp->common.board & SHARED_HW_CFG_BOARD_TYPE_MASK) { case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: /* Fan failure attention */ @@ -1762,6 +2119,17 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) break; } } + + if (attn & HW_INTERRUT_ASSERT_SET_0) { + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_0); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set0 0x%x\n", + (attn & HW_INTERRUT_ASSERT_SET_0)); + bnx2x_panic(); + } } static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) @@ -1776,6 +2144,23 @@ static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) if (val & 0x2) BNX2X_ERR("FATAL error from DORQ\n"); } + + if (attn & HW_INTERRUT_ASSERT_SET_1) { + + int port = BP_PORT(bp); + int reg_offset; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1); + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_1); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set1 0x%x\n", + (attn & HW_INTERRUT_ASSERT_SET_1)); + bnx2x_panic(); + } } static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) @@ -1799,13 +2184,41 @@ static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) if (val & 0x18000) BNX2X_ERR("FATAL error from PXP\n"); } + + if (attn & HW_INTERRUT_ASSERT_SET_2) { + + int port = BP_PORT(bp); + int reg_offset; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2); + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_2); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set2 0x%x\n", + (attn & HW_INTERRUT_ASSERT_SET_2)); + bnx2x_panic(); + } } static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) { + u32 val; + if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) { - if (attn & BNX2X_MC_ASSERT_BITS) { + if (attn & BNX2X_PMF_LINK_ASSERT) { + int func = BP_FUNC(bp); + + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + bnx2x__link_status_update(bp); + if (SHMEM_RD(bp, func_mb[func].drv_status) & + DRV_STATUS_PMF) + bnx2x_pmf_update(bp); + + } else if (attn & BNX2X_MC_ASSERT_BITS) { BNX2X_ERR("MC assert!\n"); REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0); @@ -1818,16 +2231,25 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) BNX2X_ERR("MCP assert!\n"); REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0); - bnx2x_mc_assert(bp); + bnx2x_fw_dump(bp); } else BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn); } if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) { - + BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn); + if (attn & BNX2X_GRC_TIMEOUT) { + val = CHIP_IS_E1H(bp) ? + REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN) : 0; + BNX2X_ERR("GRC time-out 0x%08x\n", val); + } + if (attn & BNX2X_GRC_RSV) { + val = CHIP_IS_E1H(bp) ? + REG_RD(bp, MISC_REG_GRC_RSV_ATTN) : 0; + BNX2X_ERR("GRC reserved 0x%08x\n", val); + } REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff); - BNX2X_ERR("LATCHED attention 0x%x (masked)\n", attn); } } @@ -1835,7 +2257,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) { struct attn_route attn; struct attn_route group_mask; - int port = bp->port; + int port = BP_PORT(bp); int index; u32 reg_addr; u32 val; @@ -1848,14 +2270,16 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4); attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4); attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4); - DP(NETIF_MSG_HW, "attn %llx\n", (unsigned long long)attn.sig[0]); + DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x\n", + attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3]); for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { if (deasserted & (1 << index)) { group_mask = bp->attn_group[index]; - DP(NETIF_MSG_HW, "group[%d]: %llx\n", index, - (unsigned long long)group_mask.sig[0]); + DP(NETIF_MSG_HW, "group[%d]: %08x %08x %08x %08x\n", + index, group_mask.sig[0], group_mask.sig[1], + group_mask.sig[2], group_mask.sig[3]); bnx2x_attn_int_deasserted3(bp, attn.sig[3] & group_mask.sig[3]); @@ -1867,22 +2291,6 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) attn.sig[0] & group_mask.sig[0]); if ((attn.sig[0] & group_mask.sig[0] & - HW_INTERRUT_ASSERT_SET_0) || - (attn.sig[1] & group_mask.sig[1] & - HW_INTERRUT_ASSERT_SET_1) || - (attn.sig[2] & group_mask.sig[2] & - HW_INTERRUT_ASSERT_SET_2)) - BNX2X_ERR("FATAL HW block attention" - " set0 0x%x set1 0x%x" - " set2 0x%x\n", - (attn.sig[0] & group_mask.sig[0] & - HW_INTERRUT_ASSERT_SET_0), - (attn.sig[1] & group_mask.sig[1] & - HW_INTERRUT_ASSERT_SET_1), - (attn.sig[2] & group_mask.sig[2] & - HW_INTERRUT_ASSERT_SET_2)); - - if ((attn.sig[0] & group_mask.sig[0] & HW_PRTY_ASSERT_SET_0) || (attn.sig[1] & group_mask.sig[1] & HW_PRTY_ASSERT_SET_1) || @@ -1894,17 +2302,17 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) bnx2x_unlock_alr(bp); - reg_addr = (IGU_ADDR_ATTN_BITS_CLR + IGU_PORT_BASE * port) * 8; + reg_addr = (IGU_ADDR_ATTN_BITS_CLR + IGU_FUNC_BASE * BP_FUNC(bp)) * 8; val = ~deasserted; -/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", +/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", val, BAR_IGU_INTMEM + reg_addr); */ REG_WR(bp, BAR_IGU_INTMEM + reg_addr, val); if (bp->aeu_mask & (deasserted & 0xff)) - BNX2X_ERR("IGU BUG\n"); + BNX2X_ERR("IGU BUG!\n"); if (~bp->attn_state & deasserted) - BNX2X_ERR("IGU BUG\n"); + BNX2X_ERR("IGU BUG!\n"); reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : MISC_REG_AEU_MASK_ATTN_FUNC_0; @@ -1936,7 +2344,7 @@ static void bnx2x_attn_int(struct bnx2x *bp) attn_bits, attn_ack, asserted, deasserted); if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state)) - BNX2X_ERR("bad attention state\n"); + BNX2X_ERR("BAD attention state\n"); /* handle bits that were raised */ if (asserted) @@ -1951,6 +2359,7 @@ static void bnx2x_sp_task(struct work_struct *work) struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); u16 status; + /* Return here if interrupt is disabled */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) { DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n"); @@ -1958,19 +2367,15 @@ static void bnx2x_sp_task(struct work_struct *work) } status = bnx2x_update_dsb_idx(bp); - if (status == 0) - BNX2X_ERR("spurious slowpath interrupt!\n"); +/* if (status == 0) */ +/* BNX2X_ERR("spurious slowpath interrupt!\n"); */ - DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status); + DP(BNX2X_MSG_SP, "got a slowpath interrupt (updated %x)\n", status); /* HW attentions */ if (status & 0x1) bnx2x_attn_int(bp); - /* CStorm events: query_stats, port delete ramrod */ - if (status & 0x2) - bp->stat_pending = 0; - bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, bp->def_att_idx, IGU_INT_NOP, 1); bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx), @@ -2109,13 +2514,13 @@ static inline long bnx2x_hilo(u32 *hiref) static void bnx2x_init_mac_stats(struct bnx2x *bp) { struct dmae_command *dmae; - int port = bp->port; + int port = BP_PORT(bp); int loader_idx = port * 8; u32 opcode; u32 mac_addr; bp->executer_idx = 0; - if (bp->fw_mb) { + if (bp->func_stx) { /* MCP */ opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | @@ -2135,7 +2540,7 @@ static void bnx2x_init_mac_stats(struct bnx2x *bp) sizeof(u32)); dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, eth_stats) + sizeof(u32)); - dmae->dst_addr_lo = bp->fw_mb >> 2; + dmae->dst_addr_lo = bp->func_stx >> 2; dmae->dst_addr_hi = 0; dmae->len = (offsetof(struct bnx2x_eth_stats, mac_stx_end) - sizeof(u32)) >> 2; @@ -2280,7 +2685,7 @@ static void bnx2x_init_mac_stats(struct bnx2x *bp) static void bnx2x_init_stats(struct bnx2x *bp) { - int port = bp->port; + int port = BP_PORT(bp); bp->stats_state = STATS_STATE_DISABLE; bp->executer_idx = 0; @@ -2641,8 +3046,6 @@ static void bnx2x_update_net_stats(struct bnx2x *bp) static void bnx2x_update_stats(struct bnx2x *bp) { - int i; - if (!bnx2x_update_storm_stats(bp)) { if (bp->link_vars.mac_type == MAC_TYPE_BMAC) { @@ -2662,6 +3065,7 @@ static void bnx2x_update_stats(struct bnx2x *bp) if (bp->msglevel & NETIF_MSG_TIMER) { struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); struct net_device_stats *nstats = &bp->dev->stats; + int i; printk(KERN_DEBUG "%s:\n", bp->dev->name); printk(KERN_DEBUG " tx avail (%4x) tx hc idx (%x)" @@ -2707,7 +3111,7 @@ static void bnx2x_update_stats(struct bnx2x *bp) /* loader */ if (bp->executer_idx) { struct dmae_command *dmae = &bp->dmae; - int port = bp->port; + int port = BP_PORT(bp); int loader_idx = port * 8; memset(dmae, 0, sizeof(struct dmae_command)); @@ -2766,8 +3170,8 @@ static void bnx2x_timer(unsigned long data) rc = bnx2x_rx_int(fp, 1000); } - if (!nomcp) { - int port = bp->port; + if (!BP_NOMCP(bp)) { + int func = BP_FUNC(bp); u32 drv_pulse; u32 mcp_pulse; @@ -2775,9 +3179,9 @@ static void bnx2x_timer(unsigned long data) bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK; /* TBD - add SYSTEM_TIME */ drv_pulse = bp->fw_drv_pulse_wr_seq; - SHMEM_WR(bp, func_mb[port].drv_pulse_mb, drv_pulse); + SHMEM_WR(bp, func_mb[func].drv_pulse_mb, drv_pulse); - mcp_pulse = (SHMEM_RD(bp, func_mb[port].mcp_pulse_mb) & + mcp_pulse = (SHMEM_RD(bp, func_mb[func].mcp_pulse_mb) & MCP_PULSE_SEQ_MASK); /* The delta between driver pulse and mcp response * should be 1 (before mcp response) or 0 (after mcp response) @@ -2807,58 +3211,89 @@ timer_restart: * nic init service functions */ -static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, - dma_addr_t mapping, int id) +static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id) { - int port = bp->port; - u64 section; + int port = BP_PORT(bp); + + bnx2x_init_fill(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, + sizeof(struct ustorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0, + sizeof(struct cstorm_def_status_block)/4); +} + +static void bnx2x_init_sb(struct bnx2x *bp, int sb_id, + struct host_status_block *sb, dma_addr_t mapping) +{ + int port = BP_PORT(bp); int index; + u64 section; /* USTORM */ section = ((u64)mapping) + offsetof(struct host_status_block, u_status_block); - sb->u_status_block.status_block_id = id; + sb->u_status_block.status_block_id = sb_id; REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section)); + USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4), + ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), U64_HI(section)); for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1); + USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); /* CSTORM */ section = ((u64)mapping) + offsetof(struct host_status_block, c_status_block); - sb->c_status_block.status_block_id = id; + sb->c_status_block.status_block_id = sb_id; REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section)); + CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section)); REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4), + ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4), U64_HI(section)); for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1); + CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1); - bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); +} + +static void bnx2x_zero_def_sb(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + + bnx2x_init_fill(bp, BAR_USTRORM_INTMEM + + USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct ustorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct cstorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_XSTRORM_INTMEM + + XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct xstorm_def_status_block)/4); + bnx2x_init_fill(bp, BAR_TSTRORM_INTMEM + + TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0, + sizeof(struct tstorm_def_status_block)/4); } static void bnx2x_init_def_sb(struct bnx2x *bp, struct host_def_status_block *def_sb, - dma_addr_t mapping, int id) + dma_addr_t mapping, int sb_id) { - int port = bp->port; + int port = BP_PORT(bp); + int func = BP_FUNC(bp); int index, val, reg_offset; u64 section; /* ATTN */ section = ((u64)mapping) + offsetof(struct host_def_status_block, atten_status_block); - def_sb->atten_status_block.status_block_id = id; + def_sb->atten_status_block.status_block_id = sb_id; bp->def_att_idx = 0; bp->attn_state = 0; @@ -2866,7 +3301,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp, reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); - for (index = 0; index < 3; index++) { + for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { bp->attn_group[index].sig[0] = REG_RD(bp, reg_offset + 0x10*index); bp->attn_group[index].sig[1] = REG_RD(bp, @@ -2889,116 +3324,123 @@ static void bnx2x_init_def_sb(struct bnx2x *bp, reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0); val = REG_RD(bp, reg_offset); - val |= id; + val |= sb_id; REG_WR(bp, reg_offset, val); /* USTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, u_def_status_block); - def_sb->u_def_status_block.status_block_id = id; + def_sb->u_def_status_block.status_block_id = sb_id; bp->def_u_idx = 0; REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); REG_WR(bp, BAR_USTRORM_INTMEM + - ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), U64_HI(section)); - REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(port), + REG_WR8(bp, BAR_USTRORM_INTMEM + DEF_USB_FUNC_OFF + + USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(func), BNX2X_BTR); for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + USTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); /* CSTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, c_def_status_block); - def_sb->c_def_status_block.status_block_id = id; + def_sb->c_def_status_block.status_block_id = sb_id; bp->def_c_idx = 0; REG_WR(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); REG_WR(bp, BAR_CSTRORM_INTMEM + - ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), U64_HI(section)); - REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(port), + REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF + + CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(func), BNX2X_BTR); for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + CSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); /* TSTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, t_def_status_block); - def_sb->t_def_status_block.status_block_id = id; + def_sb->t_def_status_block.status_block_id = sb_id; bp->def_t_idx = 0; REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); REG_WR(bp, BAR_TSTRORM_INTMEM + - ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), U64_HI(section)); - REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), + REG_WR8(bp, BAR_TSTRORM_INTMEM + DEF_TSB_FUNC_OFF + + TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(func), BNX2X_BTR); for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_TSTRORM_INTMEM + - TSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + TSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); /* XSTORM */ section = ((u64)mapping) + offsetof(struct host_def_status_block, x_def_status_block); - def_sb->x_def_status_block.status_block_id = id; + def_sb->x_def_status_block.status_block_id = sb_id; bp->def_x_idx = 0; REG_WR(bp, BAR_XSTRORM_INTMEM + - XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section)); REG_WR(bp, BAR_XSTRORM_INTMEM + - ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4), U64_HI(section)); - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), + REG_WR8(bp, BAR_XSTRORM_INTMEM + DEF_XSB_FUNC_OFF + + XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(func), BNX2X_BTR); for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++) REG_WR16(bp, BAR_XSTRORM_INTMEM + - XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + XSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1); - bp->stat_pending = 0; - - bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); } static void bnx2x_update_coalesce(struct bnx2x *bp) { - int port = bp->port; + int port = BP_PORT(bp); int i; for_each_queue(bp, i) { + int sb_id = bp->fp[i].sb_id; /* HC_INDEX_U_ETH_RX_CQ_CONS */ REG_WR8(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_TIMEOUT_OFFSET(port, i, + USTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, HC_INDEX_U_ETH_RX_CQ_CONS), - bp->rx_ticks_int/12); + bp->rx_ticks/12); REG_WR16(bp, BAR_USTRORM_INTMEM + - USTORM_SB_HC_DISABLE_OFFSET(port, i, + USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, HC_INDEX_U_ETH_RX_CQ_CONS), - bp->rx_ticks_int ? 0 : 1); + bp->rx_ticks ? 0 : 1); /* HC_INDEX_C_ETH_TX_CQ_CONS */ REG_WR8(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_TIMEOUT_OFFSET(port, i, + CSTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id, HC_INDEX_C_ETH_TX_CQ_CONS), - bp->tx_ticks_int/12); + bp->tx_ticks/12); REG_WR16(bp, BAR_CSTRORM_INTMEM + - CSTORM_SB_HC_DISABLE_OFFSET(port, i, + CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, HC_INDEX_C_ETH_TX_CQ_CONS), - bp->tx_ticks_int ? 0 : 1); + bp->tx_ticks ? 0 : 1); } } @@ -3006,7 +3448,6 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) { u16 ring_prod; int i, j; - int port = bp->port; bp->rx_buf_use_size = bp->dev->mtu; @@ -3025,13 +3466,13 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2]; rx_bd->addr_hi = cpu_to_le32(U64_HI(fp->rx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); rx_bd->addr_lo = cpu_to_le32(U64_LO(fp->rx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); - + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); } + /* CQ ring */ for (i = 1; i <= NUM_RCQ_RINGS; i++) { struct eth_rx_cqe_next_page *nextpg; @@ -3039,10 +3480,10 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1]; nextpg->addr_hi = cpu_to_le32(U64_HI(fp->rx_comp_mapping + - BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); nextpg->addr_lo = cpu_to_le32(U64_LO(fp->rx_comp_mapping + - BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); } /* rx completion queue */ @@ -3064,15 +3505,16 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp) /* Warning! this will generate an interrupt (to the TSTORM) */ /* must only be done when chip is initialized */ REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_RCQ_PROD_OFFSET(port, j), ring_prod); + TSTORM_RX_PRODS_OFFSET(BP_PORT(bp), FP_CL_ID(fp)), + ring_prod); if (j != 0) continue; REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port), + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(BP_PORT(bp)), U64_LO(fp->rx_comp_mapping)); REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port) + 4, + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(BP_PORT(bp)) + 4, U64_HI(fp->rx_comp_mapping)); } } @@ -3090,10 +3532,10 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp) tx_bd->addr_hi = cpu_to_le32(U64_HI(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); tx_bd->addr_lo = cpu_to_le32(U64_LO(fp->tx_desc_mapping + - BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); } fp->tx_pkt_prod = 0; @@ -3107,7 +3549,7 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp) static void bnx2x_init_sp_ring(struct bnx2x *bp) { - int port = bp->port; + int func = BP_FUNC(bp); spin_lock_init(&bp->spq_lock); @@ -3117,12 +3559,13 @@ static void bnx2x_init_sp_ring(struct bnx2x *bp) bp->spq_prod_bd = bp->spq; bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT; - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port), + REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func), U64_LO(bp->spq_mapping)); - REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port) + 4, + REG_WR(bp, + XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PAGE_BASE_OFFSET(func) + 4, U64_HI(bp->spq_mapping)); - REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(port), + REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(func), bp->spq_prod_idx); } @@ -3133,6 +3576,7 @@ static void bnx2x_init_context(struct bnx2x *bp) for_each_queue(bp, i) { struct eth_context *context = bnx2x_sp(bp, context[i].eth); struct bnx2x_fastpath *fp = &bp->fp[i]; + u8 sb_id = FP_SB_ID(fp); context->xstorm_st_context.tx_bd_page_base_hi = U64_HI(fp->tx_desc_mapping); @@ -3142,26 +3586,25 @@ static void bnx2x_init_context(struct bnx2x *bp) U64_HI(fp->tx_prods_mapping); context->xstorm_st_context.db_data_addr_lo = U64_LO(fp->tx_prods_mapping); - - context->ustorm_st_context.rx_bd_page_base_hi = + context->xstorm_st_context.statistics_data = (BP_CL_ID(bp) | + XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE); + + context->ustorm_st_context.common.sb_index_numbers = + BNX2X_RX_SB_INDEX_NUM; + context->ustorm_st_context.common.clientId = FP_CL_ID(fp); + context->ustorm_st_context.common.status_block_id = sb_id; + context->ustorm_st_context.common.flags = + USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT; + context->ustorm_st_context.common.mc_alignment_size = 64; + context->ustorm_st_context.common.bd_buff_size = + bp->rx_buf_use_size; + context->ustorm_st_context.common.bd_page_base_hi = U64_HI(fp->rx_desc_mapping); - context->ustorm_st_context.rx_bd_page_base_lo = + context->ustorm_st_context.common.bd_page_base_lo = U64_LO(fp->rx_desc_mapping); - context->ustorm_st_context.status_block_id = i; - context->ustorm_st_context.sb_index_number = - HC_INDEX_U_ETH_RX_CQ_CONS; - context->ustorm_st_context.rcq_base_address_hi = - U64_HI(fp->rx_comp_mapping); - context->ustorm_st_context.rcq_base_address_lo = - U64_LO(fp->rx_comp_mapping); - context->ustorm_st_context.flags = - USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT; - context->ustorm_st_context.mc_alignment_size = 64; - context->ustorm_st_context.num_rss = bp->num_queues; - context->cstorm_st_context.sb_index_number = HC_INDEX_C_ETH_TX_CQ_CONS; - context->cstorm_st_context.status_block_id = i; + context->cstorm_st_context.status_block_id = sb_id; context->xstorm_ag_context.cdu_reserved = CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), @@ -3176,14 +3619,16 @@ static void bnx2x_init_context(struct bnx2x *bp) static void bnx2x_init_ind_table(struct bnx2x *bp) { - int port = bp->port; + int port = BP_PORT(bp); int i; if (!is_multi(bp)) return; + DP(NETIF_MSG_IFUP, "Initializing indirection table\n"); for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) - REG_WR8(bp, TSTORM_INDIRECTION_TABLE_OFFSET(port) + i, + REG_WR8(bp, BAR_TSTRORM_INTMEM + + TSTORM_INDIRECTION_TABLE_OFFSET(port) + i, i % bp->num_queues); REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); @@ -3191,77 +3636,74 @@ static void bnx2x_init_ind_table(struct bnx2x *bp) static void bnx2x_set_client_config(struct bnx2x *bp) { -#ifdef BCM_VLAN - int mode = bp->rx_mode; -#endif - int i, port = bp->port; struct tstorm_eth_client_config tstorm_client = {0}; + int port = BP_PORT(bp); + int i; - tstorm_client.mtu = bp->dev->mtu; + tstorm_client.mtu = bp->dev->mtu + ETH_OVREHEAD; tstorm_client.statistics_counter_id = 0; tstorm_client.config_flags = TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; #ifdef BCM_VLAN - if (mode && bp->vlgrp) { + if (bp->rx_mode && bp->vlgrp) { tstorm_client.config_flags |= TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE; DP(NETIF_MSG_IFUP, "vlan removal enabled\n"); } #endif - if (mode != BNX2X_RX_MODE_PROMISC) - tstorm_client.drop_flags = - TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR; for_each_queue(bp, i) { REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_CLIENT_CONFIG_OFFSET(port, i), + TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id), ((u32 *)&tstorm_client)[0]); REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_CLIENT_CONFIG_OFFSET(port, i) + 4, + TSTORM_CLIENT_CONFIG_OFFSET(port, bp->fp[i].cl_id) + 4, ((u32 *)&tstorm_client)[1]); } -/* DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n", - ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */ + DP(BNX2X_MSG_OFF, "tstorm_client: 0x%08x 0x%08x\n", + ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); } static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) { - int mode = bp->rx_mode; - int port = bp->port; struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0}; + int mode = bp->rx_mode; + int mask = (1 << BP_L_ID(bp)); + int func = BP_FUNC(bp); int i; DP(NETIF_MSG_RX_STATUS, "rx mode is %d\n", mode); switch (mode) { case BNX2X_RX_MODE_NONE: /* no Rx */ - tstorm_mac_filter.ucast_drop_all = 1; - tstorm_mac_filter.mcast_drop_all = 1; - tstorm_mac_filter.bcast_drop_all = 1; + tstorm_mac_filter.ucast_drop_all = mask; + tstorm_mac_filter.mcast_drop_all = mask; + tstorm_mac_filter.bcast_drop_all = mask; break; case BNX2X_RX_MODE_NORMAL: - tstorm_mac_filter.bcast_accept_all = 1; + tstorm_mac_filter.bcast_accept_all = mask; break; case BNX2X_RX_MODE_ALLMULTI: - tstorm_mac_filter.mcast_accept_all = 1; - tstorm_mac_filter.bcast_accept_all = 1; + tstorm_mac_filter.mcast_accept_all = mask; + tstorm_mac_filter.bcast_accept_all = mask; break; case BNX2X_RX_MODE_PROMISC: - tstorm_mac_filter.ucast_accept_all = 1; - tstorm_mac_filter.mcast_accept_all = 1; - tstorm_mac_filter.bcast_accept_all = 1; + tstorm_mac_filter.ucast_accept_all = mask; + tstorm_mac_filter.mcast_accept_all = mask; + tstorm_mac_filter.bcast_accept_all = mask; break; default: - BNX2X_ERR("bad rx mode (%d)\n", mode); + BNX2X_ERR("BAD rx mode (%d)\n", mode); + break; } for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) { REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_MAC_FILTER_CONFIG_OFFSET(port) + i * 4, + TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4, ((u32 *)&tstorm_mac_filter)[i]); -/* DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i, +/* DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i, ((u32 *)&tstorm_mac_filter)[i]); */ } @@ -3271,26 +3713,30 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) static void bnx2x_init_internal(struct bnx2x *bp) { - int port = bp->port; struct tstorm_eth_function_common_config tstorm_config = {0}; struct stats_indication_flags stats_flags = {0}; + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int i; if (is_multi(bp)) { tstorm_config.config_flags = MULTI_FLAGS; tstorm_config.rss_result_mask = MULTI_MASK; } + tstorm_config.leading_client_id = BP_L_ID(bp); + REG_WR(bp, BAR_TSTRORM_INTMEM + - TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(port), + TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(func), (*(u32 *)&tstorm_config)); -/* DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n", +/* DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n", (*(u32 *)&tstorm_config)); */ bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */ bnx2x_set_storm_rx_mode(bp); - stats_flags.collect_eth = cpu_to_le32(1); + stats_flags.collect_eth = 1; REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port), ((u32 *)&stats_flags)[0]); @@ -3307,8 +3753,28 @@ static void bnx2x_init_internal(struct bnx2x *bp) REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port) + 4, ((u32 *)&stats_flags)[1]); -/* DP(NETIF_MSG_IFUP, "stats_flags: 0x%08x 0x%08x\n", +/* DP(NETIF_MSG_IFUP, "stats_flags: 0x%08x 0x%08x\n", ((u32 *)&stats_flags)[0], ((u32 *)&stats_flags)[1]); */ + + if (CHIP_IS_E1H(bp)) { + REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNCTION_MODE_OFFSET, + IS_E1HMF(bp)); + + REG_WR16(bp, BAR_XSTRORM_INTMEM + + XSTORM_E1HOV_OFFSET(func), bp->e1hov); + } + + /* Zero this manualy as its initialization is + currently missing in the initTool */ + for (i = 0; i < USTORM_AGG_DATA_SIZE >> 2; i++) + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_AGG_DATA_OFFSET + 4*i, 0); } static void bnx2x_nic_init(struct bnx2x *bp) @@ -3318,15 +3784,20 @@ static void bnx2x_nic_init(struct bnx2x *bp) for_each_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; + fp->bp = bp; fp->state = BNX2X_FP_STATE_CLOSED; - DP(NETIF_MSG_IFUP, "bnx2x_init_sb(%p,%p,%d);\n", - bp, fp->status_blk, i); fp->index = i; - bnx2x_init_sb(bp, fp->status_blk, fp->status_blk_mapping, i); + fp->cl_id = BP_L_ID(bp) + i; + fp->sb_id = fp->cl_id; + DP(NETIF_MSG_IFUP, + "bnx2x_init_sb(%p,%p) index %d cl_id %d sb %d\n", + bp, fp->status_blk, i, FP_CL_ID(fp), FP_SB_ID(fp)); + bnx2x_init_sb(bp, FP_SB_ID(fp), fp->status_blk, + fp->status_blk_mapping); } bnx2x_init_def_sb(bp, bp->def_status_blk, - bp->def_status_blk_mapping, 0x10); + bp->def_status_blk_mapping, DEF_SB_ID); bnx2x_update_coalesce(bp); bnx2x_init_rx_rings(bp); bnx2x_init_tx_ring(bp); @@ -3336,7 +3807,6 @@ static void bnx2x_nic_init(struct bnx2x *bp) bnx2x_init_stats(bp); bnx2x_init_ind_table(bp); bnx2x_int_enable(bp); - } /* end of nic init */ @@ -3374,7 +3844,7 @@ gunzip_nomem2: gunzip_nomem1: printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for" - " uncompression\n", bp->dev->name); + " un-compression\n", bp->dev->name); return -ENOMEM; } @@ -3402,7 +3872,7 @@ static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) n = 10; -#define FNAME 0x8 +#define FNAME 0x8 if (zbuf[3] & FNAME) while ((zbuf[n++] != 0) && (n < len)); @@ -3439,41 +3909,25 @@ static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) /* nic load/unload */ /* - * general service functions + * General service functions */ /* send a NIG loopback debug packet */ static void bnx2x_lb_pckt(struct bnx2x *bp) { -#ifdef USE_DMAE u32 wb_write[3]; -#endif /* Ethernet source and destination addresses */ -#ifdef USE_DMAE wb_write[0] = 0x55555555; wb_write[1] = 0x55555555; - wb_write[2] = 0x20; /* SOP */ + wb_write[2] = 0x20; /* SOP */ REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); -#else - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x55555555); - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555); - /* SOP */ - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x20); -#endif /* NON-IP protocol */ -#ifdef USE_DMAE wb_write[0] = 0x09000000; wb_write[1] = 0x55555555; - wb_write[2] = 0x10; /* EOP, eop_bvalid = 0 */ + wb_write[2] = 0x10; /* EOP, eop_bvalid = 0 */ REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); -#else - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x09000000); - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555); - /* EOP, eop_bvalid = 0 */ - REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x10); -#endif } /* some of the internal memories @@ -3511,13 +3965,9 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) /* Wait until NIG register shows 1 packet of size 0x10 */ count = 1000 * factor; while (count) { -#ifdef BNX2X_DMAE_RD + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); val = *bnx2x_sp(bp, wb_data[0]); -#else - val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); - REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); -#endif if (val == 0x10) break; @@ -3533,7 +3983,6 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) count = 1000 * factor; while (count) { val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); - if (val == 1) break; @@ -3546,9 +3995,9 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) } /* Reset and init BRB, PRS */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x3); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03); msleep(50); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x3); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); msleep(50); bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); @@ -3572,13 +4021,9 @@ static int bnx2x_int_mem_test(struct bnx2x *bp) packets of size 11*0x10 = 0xb0 */ count = 1000 * factor; while (count) { -#ifdef BNX2X_DMAE_RD + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); val = *bnx2x_sp(bp, wb_data[0]); -#else - val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); - REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); -#endif if (val == 0xb0) break; @@ -3648,85 +4093,75 @@ static void enable_blocks_attention(struct bnx2x *bp) REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0); REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0); REG_WR(bp, XCM_REG_XCM_INT_MASK, 0); -/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */ -/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */ +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */ REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0); REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0); REG_WR(bp, UCM_REG_UCM_INT_MASK, 0); -/* REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */ -/* REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */ +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */ +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */ REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0); REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0); REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0); REG_WR(bp, CCM_REG_CCM_INT_MASK, 0); -/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */ -/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */ - REG_WR(bp, PXP2_REG_PXP2_INT_MASK, 0x480000); +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */ + if (CHIP_REV_IS_FPGA(bp)) + REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x580000); + else + REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x480000); REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0); REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0); REG_WR(bp, TCM_REG_TCM_INT_MASK, 0); -/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */ -/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */ +/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */ REG_WR(bp, CDU_REG_CDU_INT_MASK, 0); REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0); -/* REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */ - REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18); /* bit 3,4 masked */ +/* REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */ + REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18); /* bit 3,4 masked */ } -static int bnx2x_function_init(struct bnx2x *bp, int mode) + +static int bnx2x_init_common(struct bnx2x *bp) { - int func = bp->port; - int port = func ? PORT1 : PORT0; u32 val, i; -#ifdef USE_DMAE - u32 wb_write[2]; -#endif - - DP(BNX2X_MSG_MCP, "function is %d mode is %x\n", func, mode); - if ((func != 0) && (func != 1)) { - BNX2X_ERR("BAD function number (%d)\n", func); - return -ENODEV; - } - bnx2x_gunzip_init(bp); + DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_FUNC(bp)); - if (mode & 0x1) { /* init common */ - DP(BNX2X_MSG_MCP, "starting common init func %d mode %x\n", - func, mode); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, - 0xffffffff); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, - 0xfffc); - bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, 0xfffc); - REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100); - msleep(30); - REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0); + bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END); + if (CHIP_IS_E1H(bp)) + REG_WR(bp, MISC_REG_E1HMF_MODE, IS_E1HMF(bp)); - bnx2x_init_block(bp, PXP_COMMON_START, PXP_COMMON_END); - bnx2x_init_block(bp, PXP2_COMMON_START, PXP2_COMMON_END); + REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100); + msleep(30); + REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0); - bnx2x_init_pxp(bp); + bnx2x_init_block(bp, PXP_COMMON_START, PXP_COMMON_END); + if (CHIP_IS_E1(bp)) { + /* enable HW interrupt from PXP on USDM overflow + bit 16 on INT_MASK_0 */ + REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); + } - if (CHIP_REV(bp) == CHIP_REV_Ax) { - /* enable HW interrupt from PXP on USDM - overflow bit 16 on INT_MASK_0 */ - REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); - } + bnx2x_init_block(bp, PXP2_COMMON_START, PXP2_COMMON_END); + bnx2x_init_pxp(bp); #ifdef __BIG_ENDIAN - REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1); - REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 1); - -/* REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */ - REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1); - REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1); - REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1); - REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 1); + +/* REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */ + REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1); #endif #ifndef BCM_ISCSI @@ -3734,92 +4169,105 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode) REG_WR(bp, PRS_REG_NIC_MODE, 1); #endif - REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2); #ifdef BCM_ISCSI - REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5); - REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5); - REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5); #endif - bnx2x_init_block(bp, DMAE_COMMON_START, DMAE_COMMON_END); + if (CHIP_REV_IS_FPGA(bp) && CHIP_IS_E1H(bp)) + REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x1); - /* let the HW do it's magic ... */ - msleep(100); - /* finish PXP init - (can be moved up if we want to use the DMAE) */ - val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE); - if (val != 1) { - BNX2X_ERR("PXP2 CFG failed\n"); - return -EBUSY; - } + /* let the HW do it's magic ... */ + msleep(100); + /* finish PXP init */ + val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 CFG failed\n"); + return -EBUSY; + } + val = REG_RD(bp, PXP2_REG_RD_INIT_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 RD_INIT failed\n"); + return -EBUSY; + } - val = REG_RD(bp, PXP2_REG_RD_INIT_DONE); - if (val != 1) { - BNX2X_ERR("PXP2 RD_INIT failed\n"); - return -EBUSY; - } + REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0); + REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0); - REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0); - REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0); + bnx2x_init_block(bp, DMAE_COMMON_START, DMAE_COMMON_END); - bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8); + /* clean the DMAE memory */ + bp->dmae_ready = 1; + bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8); - bnx2x_init_block(bp, TCM_COMMON_START, TCM_COMMON_END); - bnx2x_init_block(bp, UCM_COMMON_START, UCM_COMMON_END); - bnx2x_init_block(bp, CCM_COMMON_START, CCM_COMMON_END); - bnx2x_init_block(bp, XCM_COMMON_START, XCM_COMMON_END); + bnx2x_init_block(bp, TCM_COMMON_START, TCM_COMMON_END); + bnx2x_init_block(bp, UCM_COMMON_START, UCM_COMMON_END); + bnx2x_init_block(bp, CCM_COMMON_START, CCM_COMMON_END); + bnx2x_init_block(bp, XCM_COMMON_START, XCM_COMMON_END); -#ifdef BNX2X_DMAE_RD - bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3); - bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3); - bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3); - bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3); -#else - REG_RD(bp, XSEM_REG_PASSIVE_BUFFER); - REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 8); - REG_RD(bp, CSEM_REG_PASSIVE_BUFFER); - REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 8); - REG_RD(bp, TSEM_REG_PASSIVE_BUFFER); - REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 8); - REG_RD(bp, USEM_REG_PASSIVE_BUFFER); - REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 4); - REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 8); -#endif - bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END); - /* soft reset pulse */ - REG_WR(bp, QM_REG_SOFT_RESET, 1); - REG_WR(bp, QM_REG_SOFT_RESET, 0); + bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3); + + bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END); + /* soft reset pulse */ + REG_WR(bp, QM_REG_SOFT_RESET, 1); + REG_WR(bp, QM_REG_SOFT_RESET, 0); #ifdef BCM_ISCSI - bnx2x_init_block(bp, TIMERS_COMMON_START, TIMERS_COMMON_END); + bnx2x_init_block(bp, TIMERS_COMMON_START, TIMERS_COMMON_END); #endif - bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END); - REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_BITS); - if (CHIP_REV(bp) == CHIP_REV_Ax) { - /* enable hw interrupt from doorbell Q */ - REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); - } - bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); + bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END); + REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_SHIFT); + if (!CHIP_REV_IS_SLOW(bp)) { + /* enable hw interrupt from doorbell Q */ + REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); + } - if (CHIP_REV_IS_SLOW(bp)) { - /* fix for emulation and FPGA for no pause */ - REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 513); - REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 513); - REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0); - REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0); - } + bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); + if (CHIP_REV_IS_SLOW(bp)) { + /* fix for emulation and FPGA for no pause */ + REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 513); + REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 513); + REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0); + REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0); + } - bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + if (CHIP_IS_E1H(bp)) + REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp)); - bnx2x_init_block(bp, TSDM_COMMON_START, TSDM_COMMON_END); - bnx2x_init_block(bp, CSDM_COMMON_START, CSDM_COMMON_END); - bnx2x_init_block(bp, USDM_COMMON_START, USDM_COMMON_END); - bnx2x_init_block(bp, XSDM_COMMON_START, XSDM_COMMON_END); + bnx2x_init_block(bp, TSDM_COMMON_START, TSDM_COMMON_END); + bnx2x_init_block(bp, CSDM_COMMON_START, CSDM_COMMON_END); + bnx2x_init_block(bp, USDM_COMMON_START, USDM_COMMON_END); + bnx2x_init_block(bp, XSDM_COMMON_START, XSDM_COMMON_END); + if (CHIP_IS_E1H(bp)) { + bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + TSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + CSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + XSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, + STORM_INTMEM_SIZE_E1H/2); + bnx2x_init_fill(bp, + USTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2, + 0, STORM_INTMEM_SIZE_E1H/2); + } else { /* E1 */ bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE_E1); bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, @@ -3828,157 +4276,141 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode) STORM_INTMEM_SIZE_E1); bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE_E1); + } - bnx2x_init_block(bp, TSEM_COMMON_START, TSEM_COMMON_END); - bnx2x_init_block(bp, USEM_COMMON_START, USEM_COMMON_END); - bnx2x_init_block(bp, CSEM_COMMON_START, CSEM_COMMON_END); - bnx2x_init_block(bp, XSEM_COMMON_START, XSEM_COMMON_END); - - /* sync semi rtc */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, - 0x80000000); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, - 0x80000000); - - bnx2x_init_block(bp, UPB_COMMON_START, UPB_COMMON_END); - bnx2x_init_block(bp, XPB_COMMON_START, XPB_COMMON_END); - bnx2x_init_block(bp, PBF_COMMON_START, PBF_COMMON_END); - - REG_WR(bp, SRC_REG_SOFT_RST, 1); - for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) { - REG_WR(bp, i, 0xc0cac01a); - /* TODO: replace with something meaningful */ - } - /* SRCH COMMON comes here */ - REG_WR(bp, SRC_REG_SOFT_RST, 0); - - if (sizeof(union cdu_context) != 1024) { - /* we currently assume that a context is 1024 bytes */ - printk(KERN_ALERT PFX "please adjust the size of" - " cdu_context(%ld)\n", - (long)sizeof(union cdu_context)); - } - val = (4 << 24) + (0 << 12) + 1024; - REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); - bnx2x_init_block(bp, CDU_COMMON_START, CDU_COMMON_END); - - bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END); - REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); - - bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END); - bnx2x_init_block(bp, MISC_AEU_COMMON_START, - MISC_AEU_COMMON_END); - /* RXPCS COMMON comes here */ - /* EMAC0 COMMON comes here */ - /* EMAC1 COMMON comes here */ - /* DBU COMMON comes here */ - /* DBG COMMON comes here */ - bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END); + bnx2x_init_block(bp, TSEM_COMMON_START, TSEM_COMMON_END); + bnx2x_init_block(bp, USEM_COMMON_START, USEM_COMMON_END); + bnx2x_init_block(bp, CSEM_COMMON_START, CSEM_COMMON_END); + bnx2x_init_block(bp, XSEM_COMMON_START, XSEM_COMMON_END); - if (CHIP_REV_IS_SLOW(bp)) - msleep(200); + /* sync semi rtc */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0x80000000); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, + 0x80000000); - /* finish CFC init */ - val = REG_RD(bp, CFC_REG_LL_INIT_DONE); - if (val != 1) { - BNX2X_ERR("CFC LL_INIT failed\n"); - return -EBUSY; - } + bnx2x_init_block(bp, UPB_COMMON_START, UPB_COMMON_END); + bnx2x_init_block(bp, XPB_COMMON_START, XPB_COMMON_END); + bnx2x_init_block(bp, PBF_COMMON_START, PBF_COMMON_END); - val = REG_RD(bp, CFC_REG_AC_INIT_DONE); - if (val != 1) { - BNX2X_ERR("CFC AC_INIT failed\n"); - return -EBUSY; - } + REG_WR(bp, SRC_REG_SOFT_RST, 1); + for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) { + REG_WR(bp, i, 0xc0cac01a); + /* TODO: replace with something meaningful */ + } + if (CHIP_IS_E1H(bp)) + bnx2x_init_block(bp, SRCH_COMMON_START, SRCH_COMMON_END); + REG_WR(bp, SRC_REG_SOFT_RST, 0); - val = REG_RD(bp, CFC_REG_CAM_INIT_DONE); - if (val != 1) { - BNX2X_ERR("CFC CAM_INIT failed\n"); - return -EBUSY; - } + if (sizeof(union cdu_context) != 1024) + /* we currently assume that a context is 1024 bytes */ + printk(KERN_ALERT PFX "please adjust the size of" + " cdu_context(%ld)\n", (long)sizeof(union cdu_context)); - REG_WR(bp, CFC_REG_DEBUG0, 0); + bnx2x_init_block(bp, CDU_COMMON_START, CDU_COMMON_END); + val = (4 << 24) + (0 << 12) + 1024; + REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); + if (CHIP_IS_E1(bp)) { + /* !!! fix pxp client crdit until excel update */ + REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264); + REG_WR(bp, CDU_REG_CDU_DEBUG, 0); + } - /* read NIG statistic - to see if this is our first up since powerup */ -#ifdef BNX2X_DMAE_RD - bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); - val = *bnx2x_sp(bp, wb_data[0]); -#else - val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); - REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); -#endif - /* do internal memory self test */ - if ((val == 0) && bnx2x_int_mem_test(bp)) { - BNX2X_ERR("internal mem selftest failed\n"); - return -EBUSY; - } + bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END); + REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); - /* clear PXP2 attentions */ - REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR); + bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END); + bnx2x_init_block(bp, MISC_AEU_COMMON_START, MISC_AEU_COMMON_END); - enable_blocks_attention(bp); - /* enable_blocks_parity(bp); */ + /* PXPCS COMMON comes here */ + /* Reset PCIE errors for debug */ + REG_WR(bp, 0x2814, 0xffffffff); + REG_WR(bp, 0x3820, 0xffffffff); - switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) { - case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: - /* Fan failure is indicated by SPIO 5 */ - bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, - MISC_REGISTERS_SPIO_INPUT_HI_Z); + /* EMAC0 COMMON comes here */ + /* EMAC1 COMMON comes here */ + /* DBU COMMON comes here */ + /* DBG COMMON comes here */ - /* set to active low mode */ - val = REG_RD(bp, MISC_REG_SPIO_INT); - val |= ((1 << MISC_REGISTERS_SPIO_5) << + bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END); + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_E1HMF(bp)); + REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_E1HMF(bp)); + } + + if (CHIP_REV_IS_SLOW(bp)) + msleep(200); + + /* finish CFC init */ + val = reg_poll(bp, CFC_REG_LL_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC LL_INIT failed\n"); + return -EBUSY; + } + val = reg_poll(bp, CFC_REG_AC_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC AC_INIT failed\n"); + return -EBUSY; + } + val = reg_poll(bp, CFC_REG_CAM_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC CAM_INIT failed\n"); + return -EBUSY; + } + REG_WR(bp, CFC_REG_DEBUG0, 0); + + /* read NIG statistic + to see if this is our first up since powerup */ + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); + + /* do internal memory self test */ + if ((CHIP_IS_E1(bp)) && (val == 0) && bnx2x_int_mem_test(bp)) { + BNX2X_ERR("internal mem self test failed\n"); + return -EBUSY; + } + + switch (bp->common.board & SHARED_HW_CFG_BOARD_TYPE_MASK) { + case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: + /* Fan failure is indicated by SPIO 5 */ + bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, + MISC_REGISTERS_SPIO_INPUT_HI_Z); + + /* set to active low mode */ + val = REG_RD(bp, MISC_REG_SPIO_INT); + val |= ((1 << MISC_REGISTERS_SPIO_5) << MISC_REGISTERS_SPIO_INT_OLD_SET_POS); - REG_WR(bp, MISC_REG_SPIO_INT, val); + REG_WR(bp, MISC_REG_SPIO_INT, val); - /* enable interrupt to signal the IGU */ - val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); - val |= (1 << MISC_REGISTERS_SPIO_5); - REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); - break; + /* enable interrupt to signal the IGU */ + val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); + val |= (1 << MISC_REGISTERS_SPIO_5); + REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); + break; - default: - break; - } + default: + break; + } - } /* end of common init */ + /* clear PXP2 attentions */ + REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0); - /* per port init */ + enable_blocks_attention(bp); - /* the phys address is shifted right 12 bits and has an added - 1=valid bit added to the 53rd bit - then since this is a wide register(TM) - we split it into two 32 bit writes - */ -#define RQ_ONCHIP_AT_PORT_SIZE 384 -#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF)) -#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44))) -#define PXP_ONE_ILT(x) ((x << 10) | x) + return 0; +} - DP(BNX2X_MSG_MCP, "starting per-function init port is %x\n", func); +static int bnx2x_init_port(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; - REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + func*4, 0); + DP(BNX2X_MSG_MCP, "starting port init port %x\n", port); + + REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); /* Port PXP comes here */ /* Port PXP2 comes here */ - - /* Offset is - * Port0 0 - * Port1 384 */ - i = func * RQ_ONCHIP_AT_PORT_SIZE; -#ifdef USE_DMAE - wb_write[0] = ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context)); - wb_write[1] = ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context)); - REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); -#else - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, - ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context))); - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8 + 4, - ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context))); -#endif - REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4, PXP_ONE_ILT(i)); - #ifdef BCM_ISCSI /* Port0 1 * Port1 385 */ @@ -4004,30 +4436,9 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode) REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); #endif - - /* Port TCM comes here */ - /* Port UCM comes here */ - /* Port CCM comes here */ - bnx2x_init_block(bp, func ? XCM_PORT1_START : XCM_PORT0_START, - func ? XCM_PORT1_END : XCM_PORT0_END); - -#ifdef USE_DMAE - wb_write[0] = 0; - wb_write[1] = 0; -#endif - for (i = 0; i < 32; i++) { - REG_WR(bp, QM_REG_BASEADDR + (func*32 + i)*4, 1024 * 4 * i); -#ifdef USE_DMAE - REG_WR_DMAE(bp, QM_REG_PTRTBL + (func*32 + i)*8, wb_write, 2); -#else - REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8, 0); - REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8 + 4, 0); -#endif - } - REG_WR(bp, QM_REG_CONNNUM_0 + func*4, 1024/16 - 1); + /* Port CMs come here */ /* Port QM comes here */ - #ifdef BCM_ISCSI REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20); REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31); @@ -4042,31 +4453,32 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode) /* Port CSDM comes here */ /* Port USDM comes here */ /* Port XSDM comes here */ - bnx2x_init_block(bp, func ? TSEM_PORT1_START : TSEM_PORT0_START, - func ? TSEM_PORT1_END : TSEM_PORT0_END); - bnx2x_init_block(bp, func ? USEM_PORT1_START : USEM_PORT0_START, - func ? USEM_PORT1_END : USEM_PORT0_END); - bnx2x_init_block(bp, func ? CSEM_PORT1_START : CSEM_PORT0_START, - func ? CSEM_PORT1_END : CSEM_PORT0_END); - bnx2x_init_block(bp, func ? XSEM_PORT1_START : XSEM_PORT0_START, - func ? XSEM_PORT1_END : XSEM_PORT0_END); + bnx2x_init_block(bp, port ? TSEM_PORT1_START : TSEM_PORT0_START, + port ? TSEM_PORT1_END : TSEM_PORT0_END); + bnx2x_init_block(bp, port ? USEM_PORT1_START : USEM_PORT0_START, + port ? USEM_PORT1_END : USEM_PORT0_END); + bnx2x_init_block(bp, port ? CSEM_PORT1_START : CSEM_PORT0_START, + port ? CSEM_PORT1_END : CSEM_PORT0_END); + bnx2x_init_block(bp, port ? XSEM_PORT1_START : XSEM_PORT0_START, + port ? XSEM_PORT1_END : XSEM_PORT0_END); /* Port UPB comes here */ - /* Port XSDM comes here */ - bnx2x_init_block(bp, func ? PBF_PORT1_START : PBF_PORT0_START, - func ? PBF_PORT1_END : PBF_PORT0_END); + /* Port XPB comes here */ + + bnx2x_init_block(bp, port ? PBF_PORT1_START : PBF_PORT0_START, + port ? PBF_PORT1_END : PBF_PORT0_END); /* configure PBF to work without PAUSE mtu 9000 */ - REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + func*4, 0); + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0); /* update threshold */ - REG_WR(bp, PBF_REG_P0_ARB_THRSH + func*4, (9040/16)); + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, (9040/16)); /* update init credit */ - REG_WR(bp, PBF_REG_P0_INIT_CRD + func*4, (9040/16) + 553 - 22); + REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, (9040/16) + 553 - 22); /* probe changes */ - REG_WR(bp, PBF_REG_INIT_P0 + func*4, 1); + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 1); msleep(5); - REG_WR(bp, PBF_REG_INIT_P0 + func*4, 0); + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0); #ifdef BCM_ISCSI /* tell the searcher where the T2 table is */ @@ -4084,23 +4496,57 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode) #endif /* Port CDU comes here */ /* Port CFC comes here */ - bnx2x_init_block(bp, func ? HC_PORT1_START : HC_PORT0_START, - func ? HC_PORT1_END : HC_PORT0_END); - bnx2x_init_block(bp, func ? MISC_AEU_PORT1_START : + + if (CHIP_IS_E1(bp)) { + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); + } + bnx2x_init_block(bp, port ? HC_PORT1_START : HC_PORT0_START, + port ? HC_PORT1_END : HC_PORT0_END); + + bnx2x_init_block(bp, port ? MISC_AEU_PORT1_START : MISC_AEU_PORT0_START, - func ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END); + port ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END); + /* init aeu_mask_attn_func_0/1: + * - 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_E1HMF(bp) ? 0xF7 : 0x7)); + /* Port PXPCS comes here */ /* Port EMAC0 comes here */ /* Port EMAC1 comes here */ /* Port DBU comes here */ /* Port DBG comes here */ - bnx2x_init_block(bp, func ? NIG_PORT1_START : NIG_PORT0_START, - func ? NIG_PORT1_END : NIG_PORT0_END); - REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + func*4, 1); + bnx2x_init_block(bp, port ? NIG_PORT1_START : NIG_PORT0_START, + port ? NIG_PORT1_END : NIG_PORT0_END); + + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); + + if (CHIP_IS_E1H(bp)) { + u32 wsum; + struct cmng_struct_per_port m_cmng_port; + int vn; + + /* 0x2 disable e1hov, 0x1 enable */ + REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4, + (IS_E1HMF(bp) ? 0x1 : 0x2)); + + /* Init RATE SHAPING and FAIRNESS contexts. + Initialize as if there is 10G link. */ + wsum = bnx2x_calc_vn_wsum(bp); + bnx2x_init_port_minmax(bp, (int)wsum, 10000, &m_cmng_port); + if (IS_E1HMF(bp)) + for (vn = VN_0; vn < E1HVN_MAX; vn++) + bnx2x_init_vn_minmax(bp, 2*vn + port, + wsum, 10000, &m_cmng_port); + } + /* Port MCP comes here */ /* Port DMAE comes here */ - switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) { + switch (bp->common.board & SHARED_HW_CFG_BOARD_TYPE_MASK) { case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G: /* add SPIO 5 to group 0 */ val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); @@ -4114,48 +4560,150 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode) bnx2x__link_reset(bp); + return 0; +} + +#define ILT_PER_FUNC (768/2) +#define FUNC_ILT_BASE(func) (func * ILT_PER_FUNC) +/* the phys address is shifted right 12 bits and has an added + 1=valid bit added to the 53rd bit + then since this is a wide register(TM) + we split it into two 32 bit writes + */ +#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF)) +#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44))) +#define PXP_ONE_ILT(x) (((x) << 10) | x) +#define PXP_ILT_RANGE(f, l) (((l) << 10) | f) + +#define CNIC_ILT_LINES 0 + +static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr) +{ + int reg; + + if (CHIP_IS_E1H(bp)) + reg = PXP2_REG_RQ_ONCHIP_AT_B0 + index*8; + else /* E1 */ + reg = PXP2_REG_RQ_ONCHIP_AT + index*8; + + bnx2x_wb_wr(bp, reg, ONCHIP_ADDR1(addr), ONCHIP_ADDR2(addr)); +} + +static int bnx2x_init_func(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int i; + + DP(BNX2X_MSG_MCP, "starting func init func %x\n", func); + + i = FUNC_ILT_BASE(func); + + bnx2x_ilt_wr(bp, i, bnx2x_sp_mapping(bp, context)); + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, PXP2_REG_RQ_CDU_FIRST_ILT, i); + REG_WR(bp, PXP2_REG_RQ_CDU_LAST_ILT, i + CNIC_ILT_LINES); + } else /* E1 */ + REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4, + PXP_ILT_RANGE(i, i + CNIC_ILT_LINES)); + + + if (CHIP_IS_E1H(bp)) { + for (i = 0; i < 9; i++) + bnx2x_init_block(bp, + cm_start[func][i], cm_end[func][i]); + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); + REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov); + } + + /* HC init per function */ + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); + } + bnx2x_init_block(bp, hc_limits[func][0], hc_limits[func][1]); + + if (CHIP_IS_E1H(bp)) + REG_WR(bp, HC_REG_FUNC_NUM_P0 + port*4, func); + /* Reset PCIE errors for debug */ REG_WR(bp, 0x2114, 0xffffffff); REG_WR(bp, 0x2120, 0xffffffff); - REG_WR(bp, 0x2814, 0xffffffff); - /* !!! move to init_values.h */ - REG_WR(bp, XSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); - REG_WR(bp, USDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); - REG_WR(bp, CSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); - REG_WR(bp, TSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); + return 0; +} + +static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) +{ + int i, rc = 0; - REG_WR(bp, DBG_REG_PCI_REQ_CREDIT, 0x1); - REG_WR(bp, TM_REG_PCIARB_CRDCNT_VAL, 0x1); - REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264); - REG_WR(bp, CDU_REG_CDU_DEBUG, 0x0); + DP(BNX2X_MSG_MCP, "function %d load_code %x\n", + BP_FUNC(bp), load_code); - bnx2x_gunzip_end(bp); + bp->dmae_ready = 0; + mutex_init(&bp->dmae_mutex); + bnx2x_gunzip_init(bp); - if (!nomcp) { - port = bp->port; + switch (load_code) { + case FW_MSG_CODE_DRV_LOAD_COMMON: + rc = bnx2x_init_common(bp); + if (rc) + goto init_hw_err; + /* no break */ + + case FW_MSG_CODE_DRV_LOAD_PORT: + bp->dmae_ready = 1; + rc = bnx2x_init_port(bp); + if (rc) + goto init_hw_err; + /* no break */ + + case FW_MSG_CODE_DRV_LOAD_FUNCTION: + bp->dmae_ready = 1; + rc = bnx2x_init_func(bp); + if (rc) + goto init_hw_err; + break; + + default: + BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code); + break; + } + + if (!BP_NOMCP(bp)) { + int func = BP_FUNC(bp); bp->fw_drv_pulse_wr_seq = - (SHMEM_RD(bp, func_mb[port].drv_pulse_mb) & + (SHMEM_RD(bp, func_mb[func].drv_pulse_mb) & DRV_PULSE_SEQ_MASK); - bp->fw_mb = SHMEM_RD(bp, func_mb[port].fw_mb_param); - DP(BNX2X_MSG_MCP, "drv_pulse 0x%x fw_mb 0x%x\n", - bp->fw_drv_pulse_wr_seq, bp->fw_mb); - } else { - bp->fw_mb = 0; - } + bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param); + DP(BNX2X_MSG_MCP, "drv_pulse 0x%x func_stx 0x%x\n", + bp->fw_drv_pulse_wr_seq, bp->func_stx); + } else + bp->func_stx = 0; - return 0; + /* this needs to be done before gunzip end */ + bnx2x_zero_def_sb(bp); + for_each_queue(bp, i) + bnx2x_zero_sb(bp, BP_L_ID(bp) + i); + +init_hw_err: + bnx2x_gunzip_end(bp); + + return rc; } /* send the MCP a request, block until there is a reply */ static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) { - int port = bp->port; + int func = BP_FUNC(bp); u32 seq = ++bp->fw_seq; u32 rc = 0; - SHMEM_WR(bp, func_mb[port].drv_mb_header, (command | seq)); + SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq)); DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq)); /* let the FW do it's magic ... */ @@ -4164,7 +4712,7 @@ static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) if (CHIP_REV_IS_SLOW(bp)) msleep(900); - rc = SHMEM_RD(bp, func_mb[port].fw_mb_header); + rc = SHMEM_RD(bp, func_mb[func].fw_mb_header); DP(BNX2X_MSG_MCP, "read (%x) seq is (%x) from FW MB\n", rc, seq); /* is this a reply to our command? */ @@ -4229,15 +4777,13 @@ static void bnx2x_free_mem(struct bnx2x *bp) NUM_RCQ_BD); } - BNX2X_FREE(bp->fp); - /* end of fastpath */ BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping, - (sizeof(struct host_def_status_block))); + sizeof(struct host_def_status_block)); BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping, - (sizeof(struct bnx2x_slowpath))); + sizeof(struct bnx2x_slowpath)); #ifdef BCM_ISCSI BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024); @@ -4273,8 +4819,6 @@ static int bnx2x_alloc_mem(struct bnx2x *bp) int i; /* fastpath */ - BNX2X_ALLOC(bp->fp, sizeof(struct bnx2x_fastpath) * bp->num_queues); - for_each_queue(bp, i) { bnx2x_fp(bp, i, bp) = bp; @@ -4370,8 +4914,6 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp) u16 sw_prod = fp->tx_pkt_prod; u16 sw_cons = fp->tx_pkt_cons; - BUG_TRAP(fp->tx_buf_ring != NULL); - while (sw_cons != sw_prod) { bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons)); sw_cons++; @@ -4386,8 +4928,6 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp) for_each_queue(bp, j) { struct bnx2x_fastpath *fp = &bp->fp[j]; - BUG_TRAP(fp->rx_buf_ring != NULL); - for (i = 0; i < NUM_RX_BD; i++) { struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; struct sk_buff *skb = rx_buf->skb; @@ -4414,7 +4954,7 @@ static void bnx2x_free_skbs(struct bnx2x *bp) static void bnx2x_free_msix_irqs(struct bnx2x *bp) { - int i; + int i, offset = 1; free_irq(bp->msix_table[0].vector, bp->dev); DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n", @@ -4422,26 +4962,22 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp) for_each_queue(bp, i) { DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq " - "state(%x)\n", i, bp->msix_table[i + 1].vector, + "state %x\n", i, bp->msix_table[i + offset].vector, bnx2x_fp(bp, i, state)); if (bnx2x_fp(bp, i, state) != BNX2X_FP_STATE_CLOSED) BNX2X_ERR("IRQ of fp #%d being freed while " "state != closed\n", i); - free_irq(bp->msix_table[i + 1].vector, &bp->fp[i]); + free_irq(bp->msix_table[i + offset].vector, &bp->fp[i]); } - } static void bnx2x_free_irq(struct bnx2x *bp) { - if (bp->flags & USING_MSIX_FLAG) { - bnx2x_free_msix_irqs(bp); pci_disable_msix(bp->pdev); - bp->flags &= ~USING_MSIX_FLAG; } else @@ -4450,87 +4986,87 @@ static void bnx2x_free_irq(struct bnx2x *bp) static int bnx2x_enable_msix(struct bnx2x *bp) { - - int i; + int i, rc, offset; bp->msix_table[0].entry = 0; - for_each_queue(bp, i) - bp->msix_table[i + 1].entry = i + 1; + offset = 1; + DP(NETIF_MSG_IFUP, "msix_table[0].entry = 0 (slowpath)\n"); - if (pci_enable_msix(bp->pdev, &bp->msix_table[0], - bp->num_queues + 1)){ - BNX2X_LOG("failed to enable MSI-X\n"); - return -1; + for_each_queue(bp, i) { + int igu_vec = offset + i + BP_L_ID(bp); + bp->msix_table[i + offset].entry = igu_vec; + DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d " + "(fastpath #%u)\n", i + offset, igu_vec, i); } + rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], + bp->num_queues + offset); + if (rc) { + DP(NETIF_MSG_IFUP, "MSI-X is not attainable\n"); + return -1; + } bp->flags |= USING_MSIX_FLAG; return 0; - } - static int bnx2x_req_msix_irqs(struct bnx2x *bp) { - - int i, rc; + int i, rc, offset = 1; rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0, bp->dev->name, bp->dev); - if (rc) { BNX2X_ERR("request sp irq failed\n"); return -EBUSY; } for_each_queue(bp, i) { - rc = request_irq(bp->msix_table[i + 1].vector, + rc = request_irq(bp->msix_table[i + offset].vector, bnx2x_msix_fp_int, 0, bp->dev->name, &bp->fp[i]); - if (rc) { - BNX2X_ERR("request fp #%d irq failed " - "rc %d\n", i, rc); + BNX2X_ERR("request fp #%d irq failed rc %d\n", + i + offset, rc); bnx2x_free_msix_irqs(bp); return -EBUSY; } bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_IRQ; - } return 0; - } static int bnx2x_req_irq(struct bnx2x *bp) { + int rc; - int rc = request_irq(bp->pdev->irq, bnx2x_interrupt, - IRQF_SHARED, bp->dev->name, bp->dev); + rc = request_irq(bp->pdev->irq, bnx2x_interrupt, IRQF_SHARED, + bp->dev->name, bp->dev); if (!rc) bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ; return rc; - } /* * Init service functions */ -static void bnx2x_set_mac_addr(struct bnx2x *bp) +static void bnx2x_set_mac_addr_e1(struct bnx2x *bp) { struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config); + int port = BP_PORT(bp); /* CAM allocation * unicasts 0-31:port0 32-63:port1 * multicast 64-127:port0 128-191:port1 */ config->hdr.length_6b = 2; - config->hdr.offset = bp->port ? 31 : 0; - config->hdr.reserved0 = 0; + config->hdr.offset = port ? 31 : 0; + config->hdr.client_id = BP_CL_ID(bp); config->hdr.reserved1 = 0; /* primary MAC */ @@ -4540,7 +5076,7 @@ static void bnx2x_set_mac_addr(struct bnx2x *bp) swab16(*(u16 *)&bp->dev->dev_addr[2]); config->config_table[0].cam_entry.lsb_mac_addr = swab16(*(u16 *)&bp->dev->dev_addr[4]); - config->config_table[0].cam_entry.flags = cpu_to_le16(bp->port); + config->config_table[0].cam_entry.flags = cpu_to_le16(port); config->config_table[0].target_table_entry.flags = 0; config->config_table[0].target_table_entry.client_id = 0; config->config_table[0].target_table_entry.vlan_id = 0; @@ -4554,7 +5090,7 @@ static void bnx2x_set_mac_addr(struct bnx2x *bp) config->config_table[1].cam_entry.msb_mac_addr = 0xffff; config->config_table[1].cam_entry.middle_mac_addr = 0xffff; config->config_table[1].cam_entry.lsb_mac_addr = 0xffff; - config->config_table[1].cam_entry.flags = cpu_to_le16(bp->port); + config->config_table[1].cam_entry.flags = cpu_to_le16(port); config->config_table[1].target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST; config->config_table[1].target_table_entry.client_id = 0; @@ -4565,64 +5101,105 @@ static void bnx2x_set_mac_addr(struct bnx2x *bp) U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); } +static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp) +{ + struct mac_configuration_cmd_e1h *config = + (struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config); + + if (bp->state != BNX2X_STATE_OPEN) { + DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); + return; + } + + /* CAM allocation for E1H + * unicasts: by func number + * multicast: 20+FUNC*20, 20 each + */ + config->hdr.length_6b = 1; + config->hdr.offset = BP_FUNC(bp); + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + + /* primary MAC */ + config->config_table[0].msb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[0]); + config->config_table[0].middle_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[2]); + config->config_table[0].lsb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[4]); + config->config_table[0].client_id = BP_L_ID(bp); + config->config_table[0].vlan_id = 0; + config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov); + config->config_table[0].flags = BP_PORT(bp); + + DP(NETIF_MSG_IFUP, "setting MAC (%04x:%04x:%04x) E1HOV %d CLID %d\n", + config->config_table[0].msb_mac_addr, + config->config_table[0].middle_mac_addr, + config->config_table[0].lsb_mac_addr, bp->e1hov, BP_L_ID(bp)); + + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mac_config)), + U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); +} + static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx, int *state_p, int poll) { /* can take a while if any port is running */ - int timeout = 500; + int cnt = 500; DP(NETIF_MSG_IFUP, "%s for state to become %x on IDX [%d]\n", poll ? "polling" : "waiting", state, idx); might_sleep(); - - while (timeout) { - + while (cnt--) { if (poll) { bnx2x_rx_int(bp->fp, 10); - /* If index is different from 0 - * The reply for some commands will + /* if index is different from 0 + * the reply for some commands will * be on the none default queue */ if (idx) bnx2x_rx_int(&bp->fp[idx], 10); } - - mb(); /* state is changed by bnx2x_sp_event()*/ + mb(); /* state is changed by bnx2x_sp_event() */ if (*state_p == state) return 0; - timeout--; msleep(1); - } /* timeout! */ BNX2X_ERR("timeout %s for state %x on IDX [%d]\n", poll ? "polling" : "waiting", state, idx); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); +#endif return -EBUSY; } static int bnx2x_setup_leading(struct bnx2x *bp) { + int rc; /* reset IGU state */ - bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + bnx2x_ack_sb(bp, bp->fp[0].sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); /* SETUP ramrod */ bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0); - return bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0); + /* Wait for completion */ + rc = bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0); + return rc; } static int bnx2x_setup_multi(struct bnx2x *bp, int index) { - /* reset IGU state */ - bnx2x_ack_sb(bp, index, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + bnx2x_ack_sb(bp, bp->fp[index].sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); /* SETUP ramrod */ bp->fp[index].state = BNX2X_FP_STATE_OPENING; @@ -4631,82 +5208,107 @@ static int bnx2x_setup_multi(struct bnx2x *bp, int index) /* Wait for completion */ return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index, &(bp->fp[index].state), 0); - } - static int bnx2x_poll(struct napi_struct *napi, int budget); static void bnx2x_set_rx_mode(struct net_device *dev); -static int bnx2x_nic_load(struct bnx2x *bp, int req_irq) +/* must be called with rtnl_lock */ +static int bnx2x_nic_load(struct bnx2x *bp, int load_mode) { u32 load_code; - int i; + int i, rc; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EPERM; +#endif bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; - /* Send LOAD_REQUEST command to MCP. - Returns the type of LOAD command: if it is the - first port to be initialized common blocks should be - initialized, otherwise - not. + /* Send LOAD_REQUEST command to MCP + Returns the type of LOAD command: + if it is the first port to be initialized + common blocks should be initialized, otherwise - not */ - if (!nomcp) { + if (!BP_NOMCP(bp)) { load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ); if (!load_code) { BNX2X_ERR("MCP response failure, unloading\n"); return -EBUSY; } - if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) { - BNX2X_ERR("MCP refused load request, unloading\n"); + if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) return -EBUSY; /* other port in diagnostic mode */ - } + } else { - load_code = FW_MSG_CODE_DRV_LOAD_COMMON; + DP(NETIF_MSG_IFUP, "NO MCP load counts before us %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + load_count[0]++; + load_count[1 + BP_PORT(bp)]++; + DP(NETIF_MSG_IFUP, "NO MCP new load counts %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + if (load_count[0] == 1) + load_code = FW_MSG_CODE_DRV_LOAD_COMMON; + else if (load_count[1 + BP_PORT(bp)] == 1) + load_code = FW_MSG_CODE_DRV_LOAD_PORT; + else + load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION; } - /* if we can't use msix we only need one fp, - * so try to enable msix with the requested number of fp's + if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || + (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) + bp->port.pmf = 1; + else + bp->port.pmf = 0; + DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); + + /* if we can't use MSI-X we only need one fp, + * so try to enable MSI-X with the requested number of fp's * and fallback to inta with one fp */ - if (req_irq) { - if (use_inta) { + if (use_inta) { + bp->num_queues = 1; + + } else { + if ((use_multi > 1) && (use_multi <= BP_MAX_QUEUES(bp))) + /* user requested number */ + bp->num_queues = use_multi; + + else if (use_multi) + bp->num_queues = min_t(u32, num_online_cpus(), + BP_MAX_QUEUES(bp)); + else bp->num_queues = 1; - } else { - if ((use_multi > 1) && (use_multi <= 16)) - /* user requested number */ - bp->num_queues = use_multi; - else if (use_multi == 1) - bp->num_queues = num_online_cpus(); - else - bp->num_queues = 1; - - if (bnx2x_enable_msix(bp)) { - /* failed to enable msix */ - bp->num_queues = 1; - if (use_multi) - BNX2X_ERR("Multi requested but failed" - " to enable MSI-X\n"); - } + + if (bnx2x_enable_msix(bp)) { + /* failed to enable MSI-X */ + bp->num_queues = 1; + if (use_multi) + BNX2X_ERR("Multi requested but failed" + " to enable MSI-X\n"); } } - - DP(NETIF_MSG_IFUP, "set number of queues to %d\n", bp->num_queues); + DP(NETIF_MSG_IFUP, + "set number of queues to %d\n", bp->num_queues); if (bnx2x_alloc_mem(bp)) return -ENOMEM; - if (req_irq) { - if (bp->flags & USING_MSIX_FLAG) { - if (bnx2x_req_msix_irqs(bp)) { - pci_disable_msix(bp->pdev); - goto load_error; - } + /* Disable interrupt handling until HW is initialized */ + atomic_set(&bp->intr_sem, 1); - } else { - if (bnx2x_req_irq(bp)) { - BNX2X_ERR("IRQ request failed, aborting\n"); - goto load_error; - } + if (bp->flags & USING_MSIX_FLAG) { + rc = bnx2x_req_msix_irqs(bp); + if (rc) { + pci_disable_msix(bp->pdev); + goto load_error; + } + } else { + bnx2x_ack_int(bp); + rc = bnx2x_req_irq(bp); + if (rc) { + BNX2X_ERR("IRQ request failed, aborting\n"); + goto load_error; } } @@ -4714,26 +5316,25 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq) netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), bnx2x_poll, 128); - /* Initialize HW */ - if (bnx2x_function_init(bp, - (load_code == FW_MSG_CODE_DRV_LOAD_COMMON))) { + rc = bnx2x_init_hw(bp, load_code); + if (rc) { BNX2X_ERR("HW init failed, aborting\n"); goto load_error; } - + /* Enable interrupt handling */ atomic_set(&bp->intr_sem, 0); - /* Setup NIC internals and enable interrupts */ bnx2x_nic_init(bp); /* Send LOAD_DONE command to MCP */ - if (!nomcp) { + if (!BP_NOMCP(bp)) { load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); if (!load_code) { BNX2X_ERR("MCP response failure, unloading\n"); + rc = -EBUSY; goto load_int_disable; } } @@ -4745,33 +5346,68 @@ static int bnx2x_nic_load(struct bnx2x *bp, int req_irq) for_each_queue(bp, i) napi_enable(&bnx2x_fp(bp, i, napi)); - if (bnx2x_setup_leading(bp)) + rc = bnx2x_setup_leading(bp); + if (rc) { +#ifdef BNX2X_STOP_ON_ERROR + bp->panic = 1; +#endif goto load_stop_netif; + } - for_each_nondefault_queue(bp, i) - if (bnx2x_setup_multi(bp, i)) - goto load_stop_netif; + if (CHIP_IS_E1H(bp)) + if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) { + BNX2X_ERR("!!! mf_cfg function disabled\n"); + bp->state = BNX2X_STATE_DISABLED; + } - bnx2x_set_mac_addr(bp); + if (bp->state == BNX2X_STATE_OPEN) + for_each_nondefault_queue(bp, i) { + rc = bnx2x_setup_multi(bp, i); + if (rc) + goto load_stop_netif; + } + + if (CHIP_IS_E1(bp)) + bnx2x_set_mac_addr_e1(bp); + else + bnx2x_set_mac_addr_e1h(bp); - bnx2x_initial_phy_init(bp); + if (bp->port.pmf) + bnx2x_initial_phy_init(bp); /* Start fast path */ - if (req_irq) { /* IRQ is only requested from bnx2x_open */ + switch (load_mode) { + case LOAD_NORMAL: + /* Tx queue should be only reenabled */ + netif_wake_queue(bp->dev); + bnx2x_set_rx_mode(bp->dev); + break; + + case LOAD_OPEN: + /* IRQ is only requested from bnx2x_open */ netif_start_queue(bp->dev); + bnx2x_set_rx_mode(bp->dev); if (bp->flags & USING_MSIX_FLAG) printk(KERN_INFO PFX "%s: using MSI-X\n", bp->dev->name); + break; - /* Otherwise Tx queue should be only reenabled */ - } else if (netif_running(bp->dev)) { - netif_wake_queue(bp->dev); + case LOAD_DIAG: bnx2x_set_rx_mode(bp->dev); + bp->state = BNX2X_STATE_DIAG; + break; + + default: + break; } + if (!bp->port.pmf) + bnx2x__link_status_update(bp); + /* start the timer */ mod_timer(&bp->timer, jiffies + bp->current_interval); + return 0; load_stop_netif: @@ -4781,7 +5417,7 @@ load_stop_netif: load_int_disable: bnx2x_int_disable_sync(bp); - bnx2x_free_skbs(bp); + /* Release IRQs */ bnx2x_free_irq(bp); load_error: @@ -4789,95 +5425,50 @@ load_error: /* TBD we really need to reset the chip if we want to recover from this */ - return -EBUSY; -} - - -static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code) -{ - int port = bp->port; -#ifdef USE_DMAE - u32 wb_write[2]; -#endif - int base, i; - - DP(NETIF_MSG_IFDOWN, "reset called with code %x\n", reset_code); - - /* Do not rcv packets to BRB */ - REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0); - /* Do not direct rcv packets that are not for MCP to the BRB */ - REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : - NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); - - /* Configure IGU and AEU */ - REG_WR(bp, HC_REG_CONFIG_0 + port*4, 0x1000); - REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0); - - /* TODO: Close Doorbell port? */ - - /* Clear ILT */ -#ifdef USE_DMAE - wb_write[0] = 0; - wb_write[1] = 0; -#endif - base = port * RQ_ONCHIP_AT_PORT_SIZE; - for (i = base; i < base + RQ_ONCHIP_AT_PORT_SIZE; i++) { -#ifdef USE_DMAE - REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); -#else - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT, 0); - REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + 4, 0); -#endif - } - - if (reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) { - /* reset_common */ - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, - 0xd3ffff7f); - REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, - 0x1403); - } + return rc; } static int bnx2x_stop_multi(struct bnx2x *bp, int index) { - int rc; /* halt the connection */ bp->fp[index].state = BNX2X_FP_STATE_HALTING; bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, 0, 0); - + /* Wait for completion */ rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index, - &(bp->fp[index].state), 1); + &(bp->fp[index].state), 1); if (rc) /* timeout */ return rc; /* delete cfc entry */ bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1); - return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index, - &(bp->fp[index].state), 1); - + /* Wait for completion */ + rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_CLOSED, index, + &(bp->fp[index].state), 1); + return rc; } - static void bnx2x_stop_leading(struct bnx2x *bp) { u16 dsb_sp_prod_idx; /* if the other port is handling traffic, this can take a lot of time */ - int timeout = 500; + int cnt = 500; + int rc; might_sleep(); /* Send HALT ramrod */ bp->fp[0].state = BNX2X_FP_STATE_HALTING; - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, 0, 0); + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, BP_CL_ID(bp), 0); - if (bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0, - &(bp->fp[0].state), 1)) + /* Wait for completion */ + rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0, + &(bp->fp[0].state), 1); + if (rc) /* timeout */ return; dsb_sp_prod_idx = *bp->dsb_sp_prod; @@ -4889,29 +5480,110 @@ static void bnx2x_stop_leading(struct bnx2x *bp) we are going to reset the chip anyway so there is not much to do if this times out */ - while ((dsb_sp_prod_idx == *bp->dsb_sp_prod) && timeout) { - timeout--; + while (dsb_sp_prod_idx == *bp->dsb_sp_prod) { msleep(1); - } - if (!timeout) { - DP(NETIF_MSG_IFDOWN, "timeout polling for completion " - "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n", - *bp->dsb_sp_prod, dsb_sp_prod_idx); + if (!cnt) { + DP(NETIF_MSG_IFDOWN, "timeout waiting for port del " + "dsb_sp_prod 0x%x != dsb_sp_prod_idx 0x%x\n", + *bp->dsb_sp_prod, dsb_sp_prod_idx); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); +#endif + break; + } + cnt--; } bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD; bp->fp[0].state = BNX2X_FP_STATE_CLOSED; } +static void bnx2x_reset_func(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int base, i; + + /* Configure IGU */ + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); + + REG_WR(bp, HC_REG_CONFIG_0 + port*4, 0x1000); + + /* Clear ILT */ + base = FUNC_ILT_BASE(func); + for (i = base; i < base + ILT_PER_FUNC; i++) + bnx2x_ilt_wr(bp, i, 0); +} + +static void bnx2x_reset_port(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; + + REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); + + /* Do not rcv packets to BRB */ + REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0); + /* Do not direct rcv packets that are not for MCP to the BRB */ + REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : + NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); + + /* Configure AEU */ + REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0); + + msleep(100); + /* Check for BRB port occupancy */ + val = REG_RD(bp, BRB1_REG_PORT_NUM_OCC_BLOCKS_0 + port*4); + if (val) + DP(NETIF_MSG_IFDOWN, + "BRB1 is not empty %d blooks are occupied\n", val); + + /* TODO: Close Doorbell port? */ +} + +static void bnx2x_reset_common(struct bnx2x *bp) +{ + /* reset_common */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0xd3ffff7f); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403); +} -static int bnx2x_nic_unload(struct bnx2x *bp, int free_irq) +static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code) +{ + DP(BNX2X_MSG_MCP, "function %d reset_code %x\n", + BP_FUNC(bp), reset_code); + + switch (reset_code) { + case FW_MSG_CODE_DRV_UNLOAD_COMMON: + bnx2x_reset_port(bp); + bnx2x_reset_func(bp); + bnx2x_reset_common(bp); + break; + + case FW_MSG_CODE_DRV_UNLOAD_PORT: + bnx2x_reset_port(bp); + bnx2x_reset_func(bp); + break; + + case FW_MSG_CODE_DRV_UNLOAD_FUNCTION: + bnx2x_reset_func(bp); + break; + + default: + BNX2X_ERR("Unknown reset_code (0x%x) from MCP\n", reset_code); + break; + } +} + +/* msut be called with rtnl_lock */ +static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) { u32 reset_code = 0; - int i, timeout; + int i, cnt; bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; - del_timer_sync(&bp->timer); - bp->rx_mode = BNX2X_RX_MODE_NONE; bnx2x_set_storm_rx_mode(bp); @@ -4920,21 +5592,44 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int free_irq) bp->dev->trans_start = jiffies; /* prevent tx timeout */ } + del_timer_sync(&bp->timer); + SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb, + (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq)); + /* Wait until all fast path tasks complete */ for_each_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; - timeout = 1000; - while (bnx2x_has_work(fp) && (timeout--)) +#ifdef BNX2X_STOP_ON_ERROR +#ifdef __powerpc64__ + DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n", +#else + DP(NETIF_MSG_IFDOWN, "fp->tpa_queue_used = 0x%llx\n", +#endif + fp->tpa_queue_used); +#endif + cnt = 1000; + smp_rmb(); + while (bnx2x_has_work(fp)) { msleep(1); - if (!timeout) - BNX2X_ERR("timeout waiting for queue[%d]\n", i); + if (!cnt) { + BNX2X_ERR("timeout waiting for queue[%d]\n", + i); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); + return -EBUSY; +#else + break; +#endif + } + cnt--; + smp_rmb(); + } } - /* Wait until stat ramrod returns and all SP tasks complete */ - timeout = 1000; - while ((bp->stat_pending || (bp->spq_left != MAX_SPQ_PENDING)) && - (timeout--)) + /* Wait until all slow path tasks complete */ + cnt = 1000; + while ((bp->spq_left != MAX_SPQ_PENDING) && cnt--) msleep(1); for_each_queue(bp, i) @@ -4942,59 +5637,84 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int free_irq) /* Disable interrupts after Tx and Rx are disabled on stack level */ bnx2x_int_disable_sync(bp); + /* Release IRQs */ + bnx2x_free_irq(bp); + if (bp->flags & NO_WOL_FLAG) reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP; else if (bp->wol) { - u32 emac_base = bp->port ? GRCBASE_EMAC0 : GRCBASE_EMAC1; + u32 emac_base = BP_PORT(bp) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; u8 *mac_addr = bp->dev->dev_addr; - u32 val = (EMAC_MODE_MPKT | EMAC_MODE_MPKT_RCVD | - EMAC_MODE_ACPI_RCVD); - - EMAC_WR(EMAC_REG_EMAC_MODE, val); + u32 val; + /* The mac address is written to entries 1-4 to + preserve entry 0 which is used by the PMF */ val = (mac_addr[0] << 8) | mac_addr[1]; - EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val); + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + (BP_E1HVN(bp) + 1)*8, val); val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | (mac_addr[4] << 8) | mac_addr[5]; - EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val); + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + (BP_E1HVN(bp) + 1)*8 + 4, + val); reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN; } else reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; - /* Close multi and leading connections */ + /* Close multi and leading connections + Completions for ramrods are collected in a synchronous way */ for_each_nondefault_queue(bp, i) if (bnx2x_stop_multi(bp, i)) goto unload_error; + if (CHIP_IS_E1H(bp)) + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + BP_PORT(bp)*8, 0); + bnx2x_stop_leading(bp); +#ifdef BNX2X_STOP_ON_ERROR + /* If ramrod completion timed out - break here! */ + if (bp->panic) { + BNX2X_ERR("Stop leading failed!\n"); + return -EBUSY; + } +#endif + if ((bp->state != BNX2X_STATE_CLOSING_WAIT4_UNLOAD) || (bp->fp[0].state != BNX2X_FP_STATE_CLOSED)) { - DP(NETIF_MSG_IFDOWN, "failed to close leading properly!" - "state 0x%x fp[0].state 0x%x", + DP(NETIF_MSG_IFDOWN, "failed to close leading properly! " + "state 0x%x fp[0].state 0x%x\n", bp->state, bp->fp[0].state); } unload_error: - bnx2x__link_reset(bp); - - if (!nomcp) + if (!BP_NOMCP(bp)) reset_code = bnx2x_fw_command(bp, reset_code); - else - reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON; + else { + DP(NETIF_MSG_IFDOWN, "NO MCP load counts %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + load_count[0]--; + load_count[1 + BP_PORT(bp)]--; + DP(NETIF_MSG_IFDOWN, "NO MCP new load counts %d, %d, %d\n", + load_count[0], load_count[1], load_count[2]); + if (load_count[0] == 0) + reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON; + else if (load_count[1 + BP_PORT(bp)] == 0) + reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT; + else + reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION; + } - /* Release IRQs */ - if (free_irq) - bnx2x_free_irq(bp); + if ((reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) || + (reset_code == FW_MSG_CODE_DRV_UNLOAD_PORT)) + bnx2x__link_reset(bp); /* Reset the chip */ bnx2x_reset_chip(bp, reset_code); /* Report UNLOAD_DONE to MCP */ - if (!nomcp) + if (!BP_NOMCP(bp)) bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); /* Free SKBs and driver internals */ @@ -5008,6 +5728,29 @@ unload_error: return 0; } +static void bnx2x_reset_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, reset_task); + +#ifdef BNX2X_STOP_ON_ERROR + BNX2X_ERR("reset task called but STOP_ON_ERROR defined" + " so reset not done to allow debug dump,\n" + KERN_ERR " you will need to reboot when done\n"); + return; +#endif + + rtnl_lock(); + + if (!netif_running(bp->dev)) + goto reset_task_exit; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + bnx2x_nic_load(bp, LOAD_NORMAL); + +reset_task_exit: + rtnl_unlock(); +} + /* end of nic load/unload */ /* ethtool_ops */ @@ -5016,9 +5759,139 @@ unload_error: * Init service functions */ -static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) +static void __devinit bnx2x_undi_unload(struct bnx2x *bp) +{ + u32 val; + + /* Check if there is any driver already loaded */ + val = REG_RD(bp, MISC_REG_UNPREPARED); + if (val == 0x1) { + /* Check if it is the UNDI driver + * UNDI driver initializes CID offset for normal bell to 0x7 + */ + val = REG_RD(bp, DORQ_REG_NORM_CID_OFST); + if (val == 0x7) { + u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + /* save our func and fw_seq */ + int func = BP_FUNC(bp); + u16 fw_seq = bp->fw_seq; + + BNX2X_DEV_INFO("UNDI is active! reset device\n"); + + /* try unload UNDI on port 0 */ + bp->func = 0; + bp->fw_seq = (SHMEM_RD(bp, + func_mb[bp->func].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + + reset_code = bnx2x_fw_command(bp, reset_code); + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); + + /* if UNDI is loaded on the other port */ + if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) { + + bp->func = 1; + bp->fw_seq = (SHMEM_RD(bp, + func_mb[bp->func].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + + bnx2x_fw_command(bp, + DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS); + bnx2x_fw_command(bp, + DRV_MSG_CODE_UNLOAD_DONE); + + /* restore our func and fw_seq */ + bp->func = func; + bp->fw_seq = fw_seq; + } + + /* reset device */ + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0xd3ffff7f); + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + 0x1403); + } + } +} + +static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) +{ + u32 val, val2, val3, val4, id; + + /* Get the chip revision id and number. */ + /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ + val = REG_RD(bp, MISC_REG_CHIP_NUM); + id = ((val & 0xffff) << 16); + val = REG_RD(bp, MISC_REG_CHIP_REV); + id |= ((val & 0xf) << 12); + val = REG_RD(bp, MISC_REG_CHIP_METAL); + id |= ((val & 0xff) << 4); + REG_RD(bp, MISC_REG_BOND_ID); + id |= (val & 0xf); + bp->common.chip_id = id; + bp->link_params.chip_id = bp->common.chip_id; + BNX2X_DEV_INFO("chip ID is 0x%x\n", id); + + val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4); + bp->common.flash_size = (NVRAM_1MB_SIZE << + (val & MCPR_NVM_CFG4_FLASH_SIZE)); + BNX2X_DEV_INFO("flash_size 0x%x (%d)\n", + bp->common.flash_size, bp->common.flash_size); + + bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + bp->link_params.shmem_base = bp->common.shmem_base; + BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); + + if (!bp->common.shmem_base || + (bp->common.shmem_base < 0xA0000) || + (bp->common.shmem_base >= 0xC0000)) { + BNX2X_DEV_INFO("MCP not active\n"); + bp->flags |= NO_MCP_FLAG; + return; + } + + val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); + if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + BNX2X_ERR("BAD MCP validity signature\n"); + + bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config); + bp->common.board = SHMEM_RD(bp, dev_info.shared_hw_config.board); + + BNX2X_DEV_INFO("hw_config 0x%08x board 0x%08x\n", + bp->common.hw_config, bp->common.board); + + bp->link_params.hw_led_mode = ((bp->common.hw_config & + SHARED_HW_CFG_LED_MODE_MASK) >> + SHARED_HW_CFG_LED_MODE_SHIFT); + + val = SHMEM_RD(bp, dev_info.bc_rev) >> 8; + bp->common.bc_ver = val; + BNX2X_DEV_INFO("bc_ver %X\n", val); + if (val < BNX2X_BC_VER) { + /* for now only warn + * later we might need to enforce this */ + BNX2X_ERR("This driver needs bc_ver %X but found %X," + " please upgrade BC\n", BNX2X_BC_VER, val); + } + BNX2X_DEV_INFO("%sWoL Capable\n", + (bp->flags & NO_WOL_FLAG)? "Not " : ""); + + val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num); + val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]); + val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]); + val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]); + + printk(KERN_INFO PFX "part number %X-%X-%X-%X\n", + val, val2, val3, val4); +} + +static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, + u32 switch_cfg) { - int port = bp->port; + int port = BP_PORT(bp); u32 ext_phy_type; switch (switch_cfg) { @@ -5032,31 +5905,33 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", ext_phy_type); - bp->supported |= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_2500baseX_Full | - SUPPORTED_TP | SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n", ext_phy_type); - bp->supported |= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_TP | SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; default: @@ -5066,9 +5941,9 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) return; } - bp->phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR + - port*0x10); - BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr); + bp->port.phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR + + port*0x10); + BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr); break; case SWITCH_CFG_10G: @@ -5081,75 +5956,75 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", ext_phy_type); - bp->supported |= (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_2500baseX_Full | - SUPPORTED_10000baseT_Full | - SUPPORTED_TP | SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: BNX2X_DEV_INFO("ext_phy_type 0x%x (8705)\n", - ext_phy_type); + ext_phy_type); - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_FIBRE | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: BNX2X_DEV_INFO("ext_phy_type 0x%x (8706)\n", ext_phy_type); - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_FIBRE | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: BNX2X_DEV_INFO("ext_phy_type 0x%x (8072)\n", ext_phy_type); - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: BNX2X_DEV_INFO("ext_phy_type 0x%x (8073)\n", ext_phy_type); - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_2500baseX_Full | - SUPPORTED_1000baseT_Full | - SUPPORTED_FIBRE | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n", ext_phy_type); - bp->supported |= (SUPPORTED_10000baseT_Full | - SUPPORTED_TP | - SUPPORTED_Autoneg | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + bp->port.supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: @@ -5164,61 +6039,61 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) return; } - bp->phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR + - port*0x18); - BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr); + bp->port.phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR + + port*0x18); + BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr); break; default: BNX2X_ERR("BAD switch_cfg link_config 0x%x\n", - bp->link_config); + bp->port.link_config); return; } - bp->link_params.phy_addr = bp->phy_addr; + bp->link_params.phy_addr = bp->port.phy_addr; /* mask what we support according to speed_cap_mask */ if (!(bp->link_params.speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) - bp->supported &= ~SUPPORTED_10baseT_Half; + bp->port.supported &= ~SUPPORTED_10baseT_Half; if (!(bp->link_params.speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL)) - bp->supported &= ~SUPPORTED_10baseT_Full; + bp->port.supported &= ~SUPPORTED_10baseT_Full; if (!(bp->link_params.speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) - bp->supported &= ~SUPPORTED_100baseT_Half; + bp->port.supported &= ~SUPPORTED_100baseT_Half; if (!(bp->link_params.speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL)) - bp->supported &= ~SUPPORTED_100baseT_Full; + bp->port.supported &= ~SUPPORTED_100baseT_Full; if (!(bp->link_params.speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) - bp->supported &= ~(SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full); + bp->port.supported &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); if (!(bp->link_params.speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) - bp->supported &= ~SUPPORTED_2500baseX_Full; + bp->port.supported &= ~SUPPORTED_2500baseX_Full; if (!(bp->link_params.speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) - bp->supported &= ~SUPPORTED_10000baseT_Full; + bp->port.supported &= ~SUPPORTED_10000baseT_Full; - BNX2X_DEV_INFO("supported 0x%x\n", bp->supported); + BNX2X_DEV_INFO("supported 0x%x\n", bp->port.supported); } -static void bnx2x_link_settings_requested(struct bnx2x *bp) +static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp) { bp->link_params.req_duplex = DUPLEX_FULL; - switch (bp->link_config & PORT_FEATURE_LINK_SPEED_MASK) { + switch (bp->port.link_config & PORT_FEATURE_LINK_SPEED_MASK) { case PORT_FEATURE_LINK_SPEED_AUTO: - if (bp->supported & SUPPORTED_Autoneg) { + if (bp->port.supported & SUPPORTED_Autoneg) { bp->link_params.req_line_speed = SPEED_AUTO_NEG; - bp->advertising = bp->supported; + bp->port.advertising = bp->port.supported; } else { u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config); @@ -5229,7 +6104,7 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp) PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) { /* force 10G, no AN */ bp->link_params.req_line_speed = SPEED_10000; - bp->advertising = + bp->port.advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); break; @@ -5237,98 +6112,98 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp) BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " Autoneg not supported\n", - bp->link_config); + bp->port.link_config); return; } break; case PORT_FEATURE_LINK_SPEED_10M_FULL: - if (bp->supported & SUPPORTED_10baseT_Full) { + if (bp->port.supported & SUPPORTED_10baseT_Full) { bp->link_params.req_line_speed = SPEED_10; - bp->advertising = (ADVERTISED_10baseT_Full | - ADVERTISED_TP); + bp->port.advertising = (ADVERTISED_10baseT_Full | + ADVERTISED_TP); } else { BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " speed_cap_mask 0x%x\n", - bp->link_config, + bp->port.link_config, bp->link_params.speed_cap_mask); return; } break; case PORT_FEATURE_LINK_SPEED_10M_HALF: - if (bp->supported & SUPPORTED_10baseT_Half) { + if (bp->port.supported & SUPPORTED_10baseT_Half) { bp->link_params.req_line_speed = SPEED_10; bp->link_params.req_duplex = DUPLEX_HALF; - bp->advertising = (ADVERTISED_10baseT_Half | - ADVERTISED_TP); + bp->port.advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_TP); } else { BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " speed_cap_mask 0x%x\n", - bp->link_config, + bp->port.link_config, bp->link_params.speed_cap_mask); return; } break; case PORT_FEATURE_LINK_SPEED_100M_FULL: - if (bp->supported & SUPPORTED_100baseT_Full) { + if (bp->port.supported & SUPPORTED_100baseT_Full) { bp->link_params.req_line_speed = SPEED_100; - bp->advertising = (ADVERTISED_100baseT_Full | - ADVERTISED_TP); + bp->port.advertising = (ADVERTISED_100baseT_Full | + ADVERTISED_TP); } else { BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " speed_cap_mask 0x%x\n", - bp->link_config, + bp->port.link_config, bp->link_params.speed_cap_mask); return; } break; case PORT_FEATURE_LINK_SPEED_100M_HALF: - if (bp->supported & SUPPORTED_100baseT_Half) { + if (bp->port.supported & SUPPORTED_100baseT_Half) { bp->link_params.req_line_speed = SPEED_100; bp->link_params.req_duplex = DUPLEX_HALF; - bp->advertising = (ADVERTISED_100baseT_Half | - ADVERTISED_TP); + bp->port.advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_TP); } else { BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " speed_cap_mask 0x%x\n", - bp->link_config, + bp->port.link_config, bp->link_params.speed_cap_mask); return; } break; case PORT_FEATURE_LINK_SPEED_1G: - if (bp->supported & SUPPORTED_1000baseT_Full) { + if (bp->port.supported & SUPPORTED_1000baseT_Full) { bp->link_params.req_line_speed = SPEED_1000; - bp->advertising = (ADVERTISED_1000baseT_Full | - ADVERTISED_TP); + bp->port.advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_TP); } else { BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " speed_cap_mask 0x%x\n", - bp->link_config, + bp->port.link_config, bp->link_params.speed_cap_mask); return; } break; case PORT_FEATURE_LINK_SPEED_2_5G: - if (bp->supported & SUPPORTED_2500baseX_Full) { + if (bp->port.supported & SUPPORTED_2500baseX_Full) { bp->link_params.req_line_speed = SPEED_2500; - bp->advertising = (ADVERTISED_2500baseX_Full | - ADVERTISED_TP); + bp->port.advertising = (ADVERTISED_2500baseX_Full | + ADVERTISED_TP); } else { BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " speed_cap_mask 0x%x\n", - bp->link_config, + bp->port.link_config, bp->link_params.speed_cap_mask); return; } @@ -5337,15 +6212,15 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp) case PORT_FEATURE_LINK_SPEED_10G_CX4: case PORT_FEATURE_LINK_SPEED_10G_KX4: case PORT_FEATURE_LINK_SPEED_10G_KR: - if (bp->supported & SUPPORTED_10000baseT_Full) { + if (bp->port.supported & SUPPORTED_10000baseT_Full) { bp->link_params.req_line_speed = SPEED_10000; - bp->advertising = (ADVERTISED_10000baseT_Full | - ADVERTISED_FIBRE); + bp->port.advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); } else { BNX2X_ERR("NVRAM config error. " "Invalid link_config 0x%x" " speed_cap_mask 0x%x\n", - bp->link_config, + bp->port.link_config, bp->link_params.speed_cap_mask); return; } @@ -5354,64 +6229,33 @@ static void bnx2x_link_settings_requested(struct bnx2x *bp) default: BNX2X_ERR("NVRAM config error. " "BAD link speed link_config 0x%x\n", - bp->link_config); + bp->port.link_config); bp->link_params.req_line_speed = SPEED_AUTO_NEG; - bp->advertising = bp->supported; + bp->port.advertising = bp->port.supported; break; } - bp->link_params.req_flow_ctrl = (bp->link_config & - PORT_FEATURE_FLOW_CONTROL_MASK); + bp->link_params.req_flow_ctrl = (bp->port.link_config & + PORT_FEATURE_FLOW_CONTROL_MASK); if ((bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) && - (!bp->supported & SUPPORTED_Autoneg)) + (!bp->port.supported & SUPPORTED_Autoneg)) bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; BNX2X_DEV_INFO("req_line_speed %d req_duplex %d req_flow_ctrl 0x%x" " advertising 0x%x\n", bp->link_params.req_line_speed, bp->link_params.req_duplex, - bp->link_params.req_flow_ctrl, bp->advertising); + bp->link_params.req_flow_ctrl, bp->port.advertising); } -static void bnx2x_get_hwinfo(struct bnx2x *bp) +static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) { - u32 val, val2, val3, val4, id; - int port = bp->port; - - bp->shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); - BNX2X_DEV_INFO("shmem offset is %x\n", bp->shmem_base); - - /* Get the chip revision id and number. */ - /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ - val = REG_RD(bp, MISC_REG_CHIP_NUM); - id = ((val & 0xffff) << 16); - val = REG_RD(bp, MISC_REG_CHIP_REV); - id |= ((val & 0xf) << 12); - val = REG_RD(bp, MISC_REG_CHIP_METAL); - id |= ((val & 0xff) << 4); - REG_RD(bp, MISC_REG_BOND_ID); - id |= (val & 0xf); - bp->chip_id = id; - BNX2X_DEV_INFO("chip ID is %x\n", id); + int port = BP_PORT(bp); + u32 val, val2; bp->link_params.bp = bp; + bp->link_params.port = port; - if (!bp->shmem_base || (bp->shmem_base != 0xAF900)) { - BNX2X_DEV_INFO("MCP not active\n"); - nomcp = 1; - goto set_mac; - } - - val = SHMEM_RD(bp, validity_map[port]); - if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) - != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) - BNX2X_ERR("BAD MCP validity signature\n"); - - bp->fw_seq = (SHMEM_RD(bp, func_mb[port].drv_mb_header) & - DRV_MSG_SEQ_NUMBER_MASK); - - bp->hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config); - bp->board = SHMEM_RD(bp, dev_info.shared_hw_config.board); bp->link_params.serdes_config = SHMEM_RD(bp, dev_info.port_hw_config[port].serdes_config); bp->link_params.lane_config = @@ -5423,19 +6267,18 @@ static void bnx2x_get_hwinfo(struct bnx2x *bp) SHMEM_RD(bp, dev_info.port_hw_config[port].speed_capability_mask); - bp->link_config = + bp->port.link_config = SHMEM_RD(bp, dev_info.port_feature_config[port].link_config); - BNX2X_DEV_INFO("serdes_config (%08x) lane_config (%08x)\n" - KERN_INFO " ext_phy_config (%08x) speed_cap_mask (%08x)" - " link_config (%08x)\n", + BNX2X_DEV_INFO("serdes_config 0x%08x lane_config 0x%08x\n" + KERN_INFO " ext_phy_config 0x%08x speed_cap_mask 0x%08x" + " link_config 0x%08x\n", bp->link_params.serdes_config, bp->link_params.lane_config, bp->link_params.ext_phy_config, - bp->link_params.speed_cap_mask, - bp->link_config); + bp->link_params.speed_cap_mask, bp->port.link_config); - bp->link_params.switch_cfg = (bp->link_config & + bp->link_params.switch_cfg = (bp->port.link_config & PORT_FEATURE_CONNECTED_SWITCH_MASK); bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg); @@ -5451,43 +6294,126 @@ static void bnx2x_get_hwinfo(struct bnx2x *bp) 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); +} +static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + u32 val, val2; + int rc = 0; + bnx2x_get_common_hwinfo(bp); - val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num); - val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]); - val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]); - val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]); + bp->e1hov = 0; + bp->e1hmf = 0; + if (CHIP_IS_E1H(bp)) { + bp->mf_config = + SHMEM_RD(bp, mf_cfg.func_mf_config[func].config); - printk(KERN_INFO PFX "part number %X-%X-%X-%X\n", - val, val2, val3, val4); + val = + (SHMEM_RD(bp, mf_cfg.func_mf_config[func].e1hov_tag) & + FUNC_MF_CFG_E1HOV_TAG_MASK); + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { - /* bc ver */ - if (!nomcp) { - bp->bc_ver = val = ((SHMEM_RD(bp, dev_info.bc_rev)) >> 8); - BNX2X_DEV_INFO("bc_ver %X\n", val); - if (val < BNX2X_BC_VER) { - /* for now only warn - * later we might need to enforce this */ - BNX2X_ERR("This driver needs bc_ver %X but found %X," - " please upgrade BC\n", BNX2X_BC_VER, val); + bp->e1hov = val; + bp->e1hmf = 1; + BNX2X_DEV_INFO("MF mode E1HOV for func %d is %d " + "(0x%04x)\n", + func, bp->e1hov, bp->e1hov); + } else { + BNX2X_DEV_INFO("Single function mode\n"); + if (BP_E1HVN(bp)) { + BNX2X_ERR("!!! No valid E1HOV for func %d," + " aborting\n", func); + rc = -EPERM; + } } - } else { - bp->bc_ver = 0; } - val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4); - bp->flash_size = (NVRAM_1MB_SIZE << (val & MCPR_NVM_CFG4_FLASH_SIZE)); - BNX2X_DEV_INFO("flash_size 0x%x (%d)\n", - bp->flash_size, bp->flash_size); + if (!BP_NOMCP(bp)) { + bnx2x_get_port_hwinfo(bp); + + bp->fw_seq = (SHMEM_RD(bp, func_mb[func].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); + } + + if (IS_E1HMF(bp)) { + val2 = SHMEM_RD(bp, mf_cfg.func_mf_config[func].mac_upper); + val = SHMEM_RD(bp, mf_cfg.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; + return rc; + } + + if (BP_NOMCP(bp)) { + /* only supposed to happen on emulation/FPGA */ + BNX2X_ERR("warning rendom MAC workaround active\n"); + random_ether_addr(bp->dev->dev_addr); + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN); + } + + return rc; +} + +static int __devinit bnx2x_init_bp(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + int rc; + + if (nomcp) + bp->flags |= NO_MCP_FLAG; + + mutex_init(&bp->port.phy_mutex); + + INIT_WORK(&bp->sp_task, bnx2x_sp_task); + INIT_WORK(&bp->reset_task, bnx2x_reset_task); + + rc = bnx2x_get_hwinfo(bp); + + /* need to reset chip if undi was active */ + if (!BP_NOMCP(bp)) + bnx2x_undi_unload(bp); + + if (CHIP_REV_IS_FPGA(bp)) + printk(KERN_ERR PFX "FPGA detected\n"); -set_mac: /* only supposed to happen on emulation/FPGA */ - BNX2X_ERR("warning rendom MAC workaround active\n"); - random_ether_addr(bp->dev->dev_addr); - memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6); + if (BP_NOMCP(bp) && (func == 0)) + printk(KERN_ERR PFX + "MCP disabled, must load devices in order!\n"); + bp->tx_ring_size = MAX_TX_AVAIL; + bp->rx_ring_size = MAX_RX_AVAIL; + + bp->rx_csum = 1; + bp->rx_offset = 0; + + bp->tx_ticks = 50; + bp->rx_ticks = 25; + + bp->stats_ticks = 1000000 & 0xffff00; + + bp->timer_interval = (CHIP_REV_IS_SLOW(bp) ? 5*HZ : HZ); + bp->current_interval = (poll ? poll : bp->timer_interval); + + init_timer(&bp->timer); + bp->timer.expires = jiffies + bp->current_interval; + bp->timer.data = (unsigned long) bp; + bp->timer.function = bnx2x_timer; + + return rc; } /* @@ -5500,8 +6426,8 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct bnx2x *bp = netdev_priv(dev); - cmd->supported = bp->supported; - cmd->advertising = bp->advertising; + cmd->supported = bp->port.supported; + cmd->advertising = bp->port.advertising; if (netif_carrier_ok(dev)) { cmd->speed = bp->link_vars.line_speed; @@ -5510,6 +6436,14 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->speed = bp->link_params.req_line_speed; cmd->duplex = bp->link_params.req_duplex; } + if (IS_E1HMF(bp)) { + u16 vn_max_rate; + + vn_max_rate = ((bp->mf_config & 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 (bp->link_params.switch_cfg == SWITCH_CFG_10G) { u32 ext_phy_type = @@ -5541,7 +6475,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) } else cmd->port = PORT_TP; - cmd->phy_address = bp->phy_addr; + cmd->phy_address = bp->port.phy_addr; cmd->transceiver = XCVR_INTERNAL; if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) @@ -5568,6 +6502,9 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct bnx2x *bp = netdev_priv(dev); u32 advertising; + if (IS_E1HMF(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" @@ -5577,24 +6514,25 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); if (cmd->autoneg == AUTONEG_ENABLE) { - if (!(bp->supported & SUPPORTED_Autoneg)) { - DP(NETIF_MSG_LINK, "Aotoneg not supported\n"); + if (!(bp->port.supported & SUPPORTED_Autoneg)) { + DP(NETIF_MSG_LINK, "Autoneg not supported\n"); return -EINVAL; } /* advertise the requested speed and duplex if supported */ - cmd->advertising &= bp->supported; + cmd->advertising &= bp->port.supported; bp->link_params.req_line_speed = SPEED_AUTO_NEG; bp->link_params.req_duplex = DUPLEX_FULL; - bp->advertising |= (ADVERTISED_Autoneg | cmd->advertising); + bp->port.advertising |= (ADVERTISED_Autoneg | + cmd->advertising); } else { /* forced speed */ /* advertise the requested speed and duplex if supported */ switch (cmd->speed) { case SPEED_10: if (cmd->duplex == DUPLEX_FULL) { - if (!(bp->supported & + if (!(bp->port.supported & SUPPORTED_10baseT_Full)) { DP(NETIF_MSG_LINK, "10M full not supported\n"); @@ -5604,7 +6542,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising = (ADVERTISED_10baseT_Full | ADVERTISED_TP); } else { - if (!(bp->supported & + if (!(bp->port.supported & SUPPORTED_10baseT_Half)) { DP(NETIF_MSG_LINK, "10M half not supported\n"); @@ -5618,7 +6556,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) case SPEED_100: if (cmd->duplex == DUPLEX_FULL) { - if (!(bp->supported & + if (!(bp->port.supported & SUPPORTED_100baseT_Full)) { DP(NETIF_MSG_LINK, "100M full not supported\n"); @@ -5628,7 +6566,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising = (ADVERTISED_100baseT_Full | ADVERTISED_TP); } else { - if (!(bp->supported & + if (!(bp->port.supported & SUPPORTED_100baseT_Half)) { DP(NETIF_MSG_LINK, "100M half not supported\n"); @@ -5646,7 +6584,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; } - if (!(bp->supported & SUPPORTED_1000baseT_Full)) { + if (!(bp->port.supported & SUPPORTED_1000baseT_Full)) { DP(NETIF_MSG_LINK, "1G full not supported\n"); return -EINVAL; } @@ -5662,7 +6600,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; } - if (!(bp->supported & SUPPORTED_2500baseX_Full)) { + if (!(bp->port.supported & SUPPORTED_2500baseX_Full)) { DP(NETIF_MSG_LINK, "2.5G full not supported\n"); return -EINVAL; @@ -5678,7 +6616,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; } - if (!(bp->supported & SUPPORTED_10000baseT_Full)) { + if (!(bp->port.supported & SUPPORTED_10000baseT_Full)) { DP(NETIF_MSG_LINK, "10G full not supported\n"); return -EINVAL; } @@ -5694,16 +6632,18 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) bp->link_params.req_line_speed = cmd->speed; bp->link_params.req_duplex = cmd->duplex; - bp->advertising = advertising; + bp->port.advertising = advertising; } DP(NETIF_MSG_LINK, "req_line_speed %d\n" DP_LEVEL " req_duplex %d advertising 0x%x\n", bp->link_params.req_line_speed, bp->link_params.req_duplex, - bp->advertising); + bp->port.advertising); - bnx2x_stop_stats(bp); - bnx2x_link_set(bp); + if (netif_running(dev)) { + bnx2x_stop_stats(bp); + bnx2x_link_set(bp); + } return 0; } @@ -5720,21 +6660,23 @@ static void bnx2x_get_drvinfo(struct net_device *dev, strcpy(info->version, DRV_MODULE_VERSION); phy_fw_ver[0] = '\0'; - bnx2x_phy_hw_lock(bp); - bnx2x_get_ext_phy_fw_version(&bp->link_params, - (bp->state != BNX2X_STATE_CLOSED), - phy_fw_ver, PHY_FW_VER_LEN); - bnx2x_phy_hw_unlock(bp); + if (bp->port.pmf) { + bnx2x_phy_hw_lock(bp); + bnx2x_get_ext_phy_fw_version(&bp->link_params, + (bp->state != BNX2X_STATE_CLOSED), + phy_fw_ver, PHY_FW_VER_LEN); + bnx2x_phy_hw_unlock(bp); + } snprintf(info->fw_version, 32, "%d.%d.%d:%d BC:%x%s%s", BCM_5710_FW_MAJOR_VERSION, BCM_5710_FW_MINOR_VERSION, BCM_5710_FW_REVISION_VERSION, - BCM_5710_FW_COMPILE_FLAGS, bp->bc_ver, + BCM_5710_FW_COMPILE_FLAGS, bp->common.bc_ver, ((phy_fw_ver[0] != '\0')? " PHY:":""), phy_fw_ver); strcpy(info->bus_info, pci_name(bp->pdev)); info->n_stats = BNX2X_NUM_STATS; info->testinfo_len = BNX2X_NUM_TESTS; - info->eedump_len = bp->flash_size; + info->eedump_len = bp->common.flash_size; info->regdump_len = 0; } @@ -5767,9 +6709,9 @@ static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return -EINVAL; bp->wol = 1; - } else { + } else bp->wol = 0; - } + return 0; } @@ -5792,13 +6734,13 @@ static int bnx2x_nway_reset(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); - if (bp->state != BNX2X_STATE_OPEN) { - DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state); - return -EAGAIN; - } + if (!bp->port.pmf) + return 0; - bnx2x_stop_stats(bp); - bnx2x_link_set(bp); + if (netif_running(dev)) { + bnx2x_stop_stats(bp); + bnx2x_link_set(bp); + } return 0; } @@ -5807,12 +6749,12 @@ static int bnx2x_get_eeprom_len(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); - return bp->flash_size; + return bp->common.flash_size; } static int bnx2x_acquire_nvram_lock(struct bnx2x *bp) { - int port = bp->port; + int port = BP_PORT(bp); int count, i; u32 val = 0; @@ -5834,7 +6776,7 @@ static int bnx2x_acquire_nvram_lock(struct bnx2x *bp) } if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) { - DP(NETIF_MSG_NVM, "cannot get access to nvram interface\n"); + DP(BNX2X_MSG_NVM, "cannot get access to nvram interface\n"); return -EBUSY; } @@ -5843,7 +6785,7 @@ static int bnx2x_acquire_nvram_lock(struct bnx2x *bp) static int bnx2x_release_nvram_lock(struct bnx2x *bp) { - int port = bp->port; + int port = BP_PORT(bp); int count, i; u32 val = 0; @@ -5865,7 +6807,7 @@ static int bnx2x_release_nvram_lock(struct bnx2x *bp) } if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) { - DP(NETIF_MSG_NVM, "cannot free access to nvram interface\n"); + DP(BNX2X_MSG_NVM, "cannot free access to nvram interface\n"); return -EBUSY; } @@ -5929,7 +6871,6 @@ static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, u32 *ret_val, if (val & MCPR_NVM_COMMAND_DONE) { val = REG_RD(bp, MCP_REG_MCPR_NVM_READ); - DP(NETIF_MSG_NVM, "val 0x%08x\n", val); /* we read nvram data in cpu order * but ethtool sees it as an array of bytes * converting to big-endian will do the work */ @@ -5951,16 +6892,16 @@ static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, u32 val; if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { - DP(NETIF_MSG_NVM, + DP(BNX2X_MSG_NVM, "Invalid parameter: offset 0x%x buf_size 0x%x\n", offset, buf_size); return -EINVAL; } - if (offset + buf_size > bp->flash_size) { - DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +" + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" " buf_size (0x%x) > flash_size (0x%x)\n", - offset, buf_size, bp->flash_size); + offset, buf_size, bp->common.flash_size); return -EINVAL; } @@ -6004,7 +6945,7 @@ static int bnx2x_get_eeprom(struct net_device *dev, struct bnx2x *bp = netdev_priv(dev); int rc; - DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, eeprom->len, eeprom->len); @@ -6066,10 +7007,10 @@ static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf, u32 align_offset; u32 val; - if (offset + buf_size > bp->flash_size) { - DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +" + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" " buf_size (0x%x) > flash_size (0x%x)\n", - offset, buf_size, bp->flash_size); + offset, buf_size, bp->common.flash_size); return -EINVAL; } @@ -6093,8 +7034,6 @@ static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf, * convert it back to cpu order */ val = be32_to_cpu(val); - DP(NETIF_MSG_NVM, "val 0x%08x\n", val); - rc = bnx2x_nvram_write_dword(bp, align_offset, val, cmd_flags); } @@ -6114,21 +7053,20 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, u32 val; u32 written_so_far; - if (buf_size == 1) { /* ethtool */ + if (buf_size == 1) /* ethtool */ return bnx2x_nvram_write1(bp, offset, data_buf, buf_size); - } if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { - DP(NETIF_MSG_NVM, + DP(BNX2X_MSG_NVM, "Invalid parameter: offset 0x%x buf_size 0x%x\n", offset, buf_size); return -EINVAL; } - if (offset + buf_size > bp->flash_size) { - DP(NETIF_MSG_NVM, "Invalid parameter: offset (0x%x) +" + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" " buf_size (0x%x) > flash_size (0x%x)\n", - offset, buf_size, bp->flash_size); + offset, buf_size, bp->common.flash_size); return -EINVAL; } @@ -6151,7 +7089,6 @@ static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, cmd_flags |= MCPR_NVM_COMMAND_FIRST; memcpy(&val, data_buf, 4); - DP(NETIF_MSG_NVM, "val 0x%08x\n", val); rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags); @@ -6175,7 +7112,7 @@ static int bnx2x_set_eeprom(struct net_device *dev, struct bnx2x *bp = netdev_priv(dev); int rc; - DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, eeprom->len, eeprom->len); @@ -6183,20 +7120,23 @@ static int bnx2x_set_eeprom(struct net_device *dev, /* parameters already validated in ethtool_set_eeprom */ /* If the magic number is PHY (0x00504859) upgrade the PHY FW */ - if (eeprom->magic == 0x00504859) { - - bnx2x_phy_hw_lock(bp); - rc = bnx2x_flash_download(bp, bp->port, - bp->link_params.ext_phy_config, - (bp->state != BNX2X_STATE_CLOSED), - eebuf, eeprom->len); - rc |= bnx2x_link_reset(&bp->link_params, - &bp->link_vars); - rc |= bnx2x_phy_init(&bp->link_params, - &bp->link_vars); - bnx2x_phy_hw_unlock(bp); - - } else + if (eeprom->magic == 0x00504859) + if (bp->port.pmf) { + + bnx2x_phy_hw_lock(bp); + rc = bnx2x_flash_download(bp, BP_PORT(bp), + bp->link_params.ext_phy_config, + (bp->state != BNX2X_STATE_CLOSED), + eebuf, eeprom->len); + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars); + rc |= bnx2x_phy_init(&bp->link_params, + &bp->link_vars); + bnx2x_phy_hw_unlock(bp); + + } else /* Only the PMF can access the PHY */ + return -EINVAL; + else rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); return rc; @@ -6234,7 +7174,7 @@ static int bnx2x_set_coalesce(struct net_device *dev, bp->stats_ticks = 0xffff00; bp->stats_ticks &= 0xffff00; - if (netif_running(bp->dev)) + if (netif_running(dev)) bnx2x_update_coalesce(bp); return 0; @@ -6261,6 +7201,7 @@ static int bnx2x_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct bnx2x *bp = netdev_priv(dev); + int rc = 0; if ((ering->rx_pending > MAX_RX_AVAIL) || (ering->tx_pending > MAX_TX_AVAIL) || @@ -6270,12 +7211,12 @@ static int bnx2x_set_ringparam(struct net_device *dev, bp->rx_ring_size = ering->rx_pending; bp->tx_ring_size = ering->tx_pending; - if (netif_running(bp->dev)) { - bnx2x_nic_unload(bp, 0); - bnx2x_nic_load(bp, 0); + if (netif_running(dev)) { + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + rc = bnx2x_nic_load(bp, LOAD_NORMAL); } - return 0; + return rc; } static void bnx2x_get_pauseparam(struct net_device *dev, @@ -6301,6 +7242,9 @@ static int bnx2x_set_pauseparam(struct net_device *dev, { struct bnx2x *bp = netdev_priv(dev); + if (IS_E1HMF(bp)) + return 0; + DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); @@ -6317,7 +7261,7 @@ static int bnx2x_set_pauseparam(struct net_device *dev, bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; if (epause->autoneg) { - if (!(bp->supported & SUPPORTED_Autoneg)) { + if (!(bp->port.supported & SUPPORTED_Autoneg)) { DP(NETIF_MSG_LINK, "Autoneg not supported\n"); return -EINVAL; } @@ -6328,8 +7272,11 @@ static int bnx2x_set_pauseparam(struct net_device *dev, DP(NETIF_MSG_LINK, "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl); - bnx2x_stop_stats(bp); - bnx2x_link_set(bp); + + if (netif_running(dev)) { + bnx2x_stop_stats(bp); + bnx2x_link_set(bp); + } return 0; } @@ -6531,18 +7478,25 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev, static int bnx2x_phys_id(struct net_device *dev, u32 data) { struct bnx2x *bp = netdev_priv(dev); + int port = BP_PORT(bp); int i; + if (!netif_running(dev)) + return 0; + + if (!bp->port.pmf) + return 0; + if (data == 0) data = 2; for (i = 0; i < (data * 2); i++) { if ((i % 2) == 0) - bnx2x_set_led(bp, bp->port, LED_MODE_OPER, SPEED_1000, + bnx2x_set_led(bp, port, LED_MODE_OPER, SPEED_1000, bp->link_params.hw_led_mode, bp->link_params.chip_id); else - bnx2x_set_led(bp, bp->port, LED_MODE_OFF, 0, + bnx2x_set_led(bp, port, LED_MODE_OFF, 0, bp->link_params.hw_led_mode, bp->link_params.chip_id); @@ -6552,7 +7506,7 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data) } if (bp->link_vars.link_up) - bnx2x_set_led(bp, bp->port, LED_MODE_OPER, + bnx2x_set_led(bp, port, LED_MODE_OPER, bp->link_vars.line_speed, bp->link_params.hw_led_mode, bp->link_params.chip_id); @@ -6609,8 +7563,7 @@ static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) switch (state) { case PCI_D0: - pci_write_config_word(bp->pdev, - bp->pm_cap + PCI_PM_CTRL, + pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) | PCI_PM_CTRL_PME_STATUS)); @@ -6644,82 +7597,6 @@ static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) * net_device service functions */ -/* called with netif_tx_lock from set_multicast */ -static void bnx2x_set_rx_mode(struct net_device *dev) -{ - struct bnx2x *bp = netdev_priv(dev); - u32 rx_mode = BNX2X_RX_MODE_NORMAL; - - DP(NETIF_MSG_IFUP, "called dev->flags = %x\n", dev->flags); - - if (dev->flags & IFF_PROMISC) - rx_mode = BNX2X_RX_MODE_PROMISC; - - else if ((dev->flags & IFF_ALLMULTI) || - (dev->mc_count > BNX2X_MAX_MULTICAST)) - rx_mode = BNX2X_RX_MODE_ALLMULTI; - - else { /* some multicasts */ - int i, old, offset; - struct dev_mc_list *mclist; - struct mac_configuration_cmd *config = - bnx2x_sp(bp, mcast_config); - - for (i = 0, mclist = dev->mc_list; - mclist && (i < dev->mc_count); - i++, mclist = mclist->next) { - - config->config_table[i].cam_entry.msb_mac_addr = - swab16(*(u16 *)&mclist->dmi_addr[0]); - config->config_table[i].cam_entry.middle_mac_addr = - swab16(*(u16 *)&mclist->dmi_addr[2]); - config->config_table[i].cam_entry.lsb_mac_addr = - swab16(*(u16 *)&mclist->dmi_addr[4]); - config->config_table[i].cam_entry.flags = - cpu_to_le16(bp->port); - config->config_table[i].target_table_entry.flags = 0; - config->config_table[i].target_table_entry. - client_id = 0; - config->config_table[i].target_table_entry. - vlan_id = 0; - - DP(NETIF_MSG_IFUP, - "setting MCAST[%d] (%04x:%04x:%04x)\n", - i, config->config_table[i].cam_entry.msb_mac_addr, - config->config_table[i].cam_entry.middle_mac_addr, - config->config_table[i].cam_entry.lsb_mac_addr); - } - old = config->hdr.length_6b; - if (old > i) { - for (; i < old; i++) { - if (CAM_IS_INVALID(config->config_table[i])) { - i--; /* already invalidated */ - break; - } - /* invalidate */ - CAM_INVALIDATE(config->config_table[i]); - } - } - - if (CHIP_REV_IS_SLOW(bp)) - offset = BNX2X_MAX_EMUL_MULTI*(1 + bp->port); - else - offset = BNX2X_MAX_MULTICAST*(1 + bp->port); - - config->hdr.length_6b = i; - config->hdr.offset = offset; - config->hdr.reserved0 = 0; - config->hdr.reserved1 = 0; - - bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, - U64_HI(bnx2x_sp_mapping(bp, mcast_config)), - U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0); - } - - bp->rx_mode = rx_mode; - bnx2x_set_storm_rx_mode(bp); -} - static int bnx2x_poll(struct napi_struct *napi, int budget) { struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath, @@ -6729,7 +7606,7 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) #ifdef BNX2X_STOP_ON_ERROR if (unlikely(bp->panic)) - goto out_panic; + goto poll_panic; #endif prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb); @@ -6738,30 +7615,28 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) bnx2x_update_fpsb_idx(fp); - if (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons) + if ((fp->tx_pkt_prod != le16_to_cpu(*fp->tx_cons_sb)) || + (fp->tx_pkt_prod != fp->tx_pkt_cons)) bnx2x_tx_int(fp, budget); - if (le16_to_cpu(*fp->rx_cons_sb) != fp->rx_comp_cons) work_done = bnx2x_rx_int(fp, budget); - rmb(); /* bnx2x_has_work() reads the status block */ /* must not complete if we consumed full budget */ if ((work_done < budget) && !bnx2x_has_work(fp)) { #ifdef BNX2X_STOP_ON_ERROR -out_panic: +poll_panic: #endif netif_rx_complete(bp->dev, napi); - bnx2x_ack_sb(bp, fp->index, USTORM_ID, + bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID, le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); - bnx2x_ack_sb(bp, fp->index, CSTORM_ID, + bnx2x_ack_sb(bp, FP_SB_ID(fp), CSTORM_ID, le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1); } - return work_done; } @@ -7055,18 +7930,145 @@ static int bnx2x_close(struct net_device *dev) return 0; } -/* Called with rtnl_lock */ +/* called with netif_tx_lock from set_multicast */ +static void bnx2x_set_rx_mode(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 rx_mode = BNX2X_RX_MODE_NORMAL; + int port = BP_PORT(bp); + + if (bp->state != BNX2X_STATE_OPEN) { + DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); + return; + } + + DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags); + + if (dev->flags & IFF_PROMISC) + rx_mode = BNX2X_RX_MODE_PROMISC; + + else if ((dev->flags & IFF_ALLMULTI) || + ((dev->mc_count > BNX2X_MAX_MULTICAST) && CHIP_IS_E1(bp))) + rx_mode = BNX2X_RX_MODE_ALLMULTI; + + else { /* some multicasts */ + if (CHIP_IS_E1(bp)) { + int i, old, offset; + struct dev_mc_list *mclist; + struct mac_configuration_cmd *config = + bnx2x_sp(bp, mcast_config); + + for (i = 0, mclist = dev->mc_list; + mclist && (i < dev->mc_count); + i++, mclist = mclist->next) { + + config->config_table[i]. + cam_entry.msb_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[0]); + config->config_table[i]. + cam_entry.middle_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[2]); + config->config_table[i]. + cam_entry.lsb_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[4]); + config->config_table[i].cam_entry.flags = + cpu_to_le16(port); + config->config_table[i]. + target_table_entry.flags = 0; + config->config_table[i]. + target_table_entry.client_id = 0; + config->config_table[i]. + target_table_entry.vlan_id = 0; + + DP(NETIF_MSG_IFUP, + "setting MCAST[%d] (%04x:%04x:%04x)\n", i, + config->config_table[i]. + cam_entry.msb_mac_addr, + config->config_table[i]. + cam_entry.middle_mac_addr, + config->config_table[i]. + cam_entry.lsb_mac_addr); + } + old = config->hdr.length_6b; + if (old > i) { + for (; i < old; i++) { + if (CAM_IS_INVALID(config-> + config_table[i])) { + i--; /* already invalidated */ + break; + } + /* invalidate */ + CAM_INVALIDATE(config-> + config_table[i]); + } + } + + if (CHIP_REV_IS_SLOW(bp)) + offset = BNX2X_MAX_EMUL_MULTI*(1 + port); + else + offset = BNX2X_MAX_MULTICAST*(1 + port); + + config->hdr.length_6b = i; + config->hdr.offset = offset; + config->hdr.client_id = BP_CL_ID(bp); + config->hdr.reserved1 = 0; + + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mcast_config)), + U64_LO(bnx2x_sp_mapping(bp, mcast_config)), + 0); + } else { /* E1H */ + /* Accept one or more multicasts */ + struct dev_mc_list *mclist; + u32 mc_filter[MC_HASH_SIZE]; + u32 crc, bit, regidx; + int i; + + memset(mc_filter, 0, 4 * MC_HASH_SIZE); + + for (i = 0, mclist = dev->mc_list; + mclist && (i < dev->mc_count); + i++, mclist = mclist->next) { + + DP(NETIF_MSG_IFUP, "Adding mcast MAC: " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + mclist->dmi_addr[0], mclist->dmi_addr[1], + mclist->dmi_addr[2], mclist->dmi_addr[3], + mclist->dmi_addr[4], mclist->dmi_addr[5]); + + crc = crc32c_le(0, mclist->dmi_addr, ETH_ALEN); + bit = (crc >> 24) & 0xff; + regidx = bit >> 5; + bit &= 0x1f; + mc_filter[regidx] |= (1 << bit); + } + + for (i = 0; i < MC_HASH_SIZE; i++) + REG_WR(bp, MC_HASH_OFFSET(bp, i), + mc_filter[i]); + } + } + + bp->rx_mode = rx_mode; + bnx2x_set_storm_rx_mode(bp); +} + +/* called with rtnl_lock */ static int bnx2x_change_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; struct bnx2x *bp = netdev_priv(dev); - if (!is_valid_ether_addr(addr->sa_data)) + if (!is_valid_ether_addr((u8 *)(addr->sa_data))) return -EINVAL; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - if (netif_running(dev)) - bnx2x_set_mac_addr(bp); + if (netif_running(dev)) { + if (CHIP_IS_E1(bp)) + bnx2x_set_mac_addr_e1(bp); + else + bnx2x_set_mac_addr_e1h(bp); + } return 0; } @@ -7080,7 +8082,7 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGMIIPHY: - data->phy_id = bp->phy_addr; + data->phy_id = bp->port.phy_addr; /* fallthrough */ @@ -7090,12 +8092,12 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!netif_running(dev)) return -EAGAIN; - mutex_lock(&bp->phy_mutex); - err = bnx2x_cl45_read(bp, bp->port, 0, bp->phy_addr, + mutex_lock(&bp->port.phy_mutex); + err = bnx2x_cl45_read(bp, BP_PORT(bp), 0, bp->port.phy_addr, DEFAULT_PHY_DEV_ADDR, (data->reg_num & 0x1f), &mii_regval); data->val_out = mii_regval; - mutex_unlock(&bp->phy_mutex); + mutex_unlock(&bp->port.phy_mutex); return err; } @@ -7106,11 +8108,11 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!netif_running(dev)) return -EAGAIN; - mutex_lock(&bp->phy_mutex); - err = bnx2x_cl45_write(bp, bp->port, 0, bp->phy_addr, + mutex_lock(&bp->port.phy_mutex); + err = bnx2x_cl45_write(bp, BP_PORT(bp), 0, bp->port.phy_addr, DEFAULT_PHY_DEV_ADDR, (data->reg_num & 0x1f), data->val_in); - mutex_unlock(&bp->phy_mutex); + mutex_unlock(&bp->port.phy_mutex); return err; default: @@ -7121,10 +8123,11 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } -/* Called with rtnl_lock */ +/* called with rtnl_lock */ static int bnx2x_change_mtu(struct net_device *dev, int new_mtu) { struct bnx2x *bp = netdev_priv(dev); + int rc = 0; if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) || ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE)) @@ -7137,10 +8140,11 @@ static int bnx2x_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; if (netif_running(dev)) { - bnx2x_nic_unload(bp, 0); - bnx2x_nic_load(bp, 0); + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + rc = bnx2x_nic_load(bp, LOAD_NORMAL); } - return 0; + + return rc; } static void bnx2x_tx_timeout(struct net_device *dev) @@ -7156,7 +8160,7 @@ static void bnx2x_tx_timeout(struct net_device *dev) } #ifdef BCM_VLAN -/* Called with rtnl_lock */ +/* called with rtnl_lock */ static void bnx2x_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) { @@ -7166,6 +8170,7 @@ static void bnx2x_vlan_rx_register(struct net_device *dev, if (netif_running(dev)) bnx2x_set_client_config(bp); } + #endif #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) @@ -7179,36 +8184,8 @@ static void poll_bnx2x(struct net_device *dev) } #endif -static void bnx2x_reset_task(struct work_struct *work) -{ - struct bnx2x *bp = container_of(work, struct bnx2x, reset_task); - -#ifdef BNX2X_STOP_ON_ERROR - BNX2X_ERR("reset task called but STOP_ON_ERROR defined" - " so reset not done to allow debug dump,\n" - KERN_ERR " you will need to reboot when done\n"); - return; -#endif - - if (!netif_running(bp->dev)) - return; - - rtnl_lock(); - - if (bp->state != BNX2X_STATE_OPEN) { - DP(NETIF_MSG_TX_ERR, "state is %x, returning\n", bp->state); - goto reset_task_exit; - } - - bnx2x_nic_unload(bp, 0); - bnx2x_nic_load(bp, 0); - -reset_task_exit: - rtnl_unlock(); -} - -static int __devinit bnx2x_init_board(struct pci_dev *pdev, - struct net_device *dev) +static int __devinit bnx2x_init_dev(struct pci_dev *pdev, + struct net_device *dev) { struct bnx2x *bp; int rc; @@ -7216,8 +8193,10 @@ static int __devinit bnx2x_init_board(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); bp = netdev_priv(dev); + bp->dev = dev; + bp->pdev = pdev; bp->flags = 0; - bp->port = PCI_FUNC(pdev->devfn); + bp->func = PCI_FUNC(pdev->devfn); rc = pci_enable_device(pdev); if (rc) { @@ -7239,14 +8218,17 @@ static int __devinit bnx2x_init_board(struct pci_dev *pdev, goto err_out_disable; } - rc = pci_request_regions(pdev, DRV_MODULE_NAME); - if (rc) { - printk(KERN_ERR PFX "Cannot obtain PCI resources," - " aborting\n"); - goto err_out_disable; - } + if (atomic_read(&pdev->enable_cnt) == 1) { + rc = pci_request_regions(pdev, DRV_MODULE_NAME); + if (rc) { + printk(KERN_ERR PFX "Cannot obtain PCI resources," + " aborting\n"); + goto err_out_disable; + } - pci_set_master(pdev); + pci_set_master(pdev); + pci_save_state(pdev); + } bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); if (bp->pm_cap == 0) { @@ -7280,13 +8262,9 @@ static int __devinit bnx2x_init_board(struct pci_dev *pdev, goto err_out_release; } - bp->dev = dev; - bp->pdev = pdev; - - INIT_WORK(&bp->reset_task, bnx2x_reset_task); - INIT_WORK(&bp->sp_task, bnx2x_sp_task); - - dev->base_addr = pci_resource_start(pdev, 0); + dev->mem_start = pci_resource_start(pdev, 0); + dev->base_addr = dev->mem_start; + dev->mem_end = pci_resource_end(pdev, 0); dev->irq = pdev->irq; @@ -7298,8 +8276,9 @@ static int __devinit bnx2x_init_board(struct pci_dev *pdev, goto err_out_release; } - bp->doorbells = ioremap_nocache(pci_resource_start(pdev , 2), - pci_resource_len(pdev, 2)); + bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2), + min_t(u64, BNX2X_DB_SIZE, + pci_resource_len(pdev, 2))); if (!bp->doorbells) { printk(KERN_ERR PFX "Cannot map doorbell space, aborting\n"); rc = -ENOMEM; @@ -7308,47 +8287,43 @@ static int __devinit bnx2x_init_board(struct pci_dev *pdev, bnx2x_set_power_state(bp, PCI_D0); - bnx2x_get_hwinfo(bp); - - - if (nomcp) { - printk(KERN_ERR PFX "MCP disabled, will only" - " init first device\n"); - onefunc = 1; - } - - if (onefunc && bp->port) { - printk(KERN_ERR PFX "Second device disabled, exiting\n"); - rc = -ENODEV; - goto err_out_unmap; - } - - bp->tx_ring_size = MAX_TX_AVAIL; - bp->rx_ring_size = MAX_RX_AVAIL; - - bp->rx_csum = 1; - - bp->rx_offset = 0; - - bp->tx_quick_cons_trip_int = 0xff; - bp->tx_quick_cons_trip = 0xff; - bp->tx_ticks_int = 50; - bp->tx_ticks = 50; + /* clean indirect addresses */ + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); + REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0); - bp->rx_quick_cons_trip_int = 0xff; - bp->rx_quick_cons_trip = 0xff; - bp->rx_ticks_int = 25; - bp->rx_ticks = 25; + dev->hard_start_xmit = bnx2x_start_xmit; + dev->watchdog_timeo = TX_TIMEOUT; - bp->stats_ticks = 1000000 & 0xffff00; + dev->ethtool_ops = &bnx2x_ethtool_ops; + dev->open = bnx2x_open; + dev->stop = bnx2x_close; + dev->set_multicast_list = bnx2x_set_rx_mode; + dev->set_mac_address = bnx2x_change_mac_addr; + dev->do_ioctl = bnx2x_ioctl; + dev->change_mtu = bnx2x_change_mtu; + dev->tx_timeout = bnx2x_tx_timeout; +#ifdef BCM_VLAN + dev->vlan_rx_register = bnx2x_vlan_rx_register; +#endif +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + dev->poll_controller = poll_bnx2x; +#endif + dev->features |= NETIF_F_SG; + dev->features |= NETIF_F_HW_CSUM; + if (bp->flags & USING_DAC_FLAG) + dev->features |= NETIF_F_HIGHDMA; +#ifdef BCM_VLAN + dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); +#endif + dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); bp->timer_interval = HZ; bp->current_interval = (poll ? poll : HZ); - init_timer(&bp->timer); - bp->timer.expires = jiffies + bp->current_interval; - bp->timer.data = (unsigned long) bp; - bp->timer.function = bnx2x_timer; return 0; @@ -7357,14 +8332,14 @@ err_out_unmap: iounmap(bp->regview); bp->regview = NULL; } - if (bp->doorbells) { iounmap(bp->doorbells); bp->doorbells = NULL; } err_out_release: - pci_release_regions(pdev); + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); err_out_disable: pci_disable_device(pdev); @@ -7398,7 +8373,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, struct net_device *dev = NULL; struct bnx2x *bp; int rc; - int port = PCI_FUNC(pdev->devfn); DECLARE_MAC_BUF(mac); if (version_printed++ == 0) @@ -7406,78 +8380,62 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, /* dev zeroed in init_etherdev */ dev = alloc_etherdev(sizeof(*bp)); - if (!dev) + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate net device\n"); return -ENOMEM; + } netif_carrier_off(dev); bp = netdev_priv(dev); bp->msglevel = debug; - if (port && onefunc) { - printk(KERN_ERR PFX "second function disabled. exiting\n"); - free_netdev(dev); - return 0; - } - - rc = bnx2x_init_board(pdev, dev); + rc = bnx2x_init_dev(pdev, dev); if (rc < 0) { free_netdev(dev); return rc; } - dev->hard_start_xmit = bnx2x_start_xmit; - dev->watchdog_timeo = TX_TIMEOUT; - - dev->ethtool_ops = &bnx2x_ethtool_ops; - dev->open = bnx2x_open; - dev->stop = bnx2x_close; - dev->set_multicast_list = bnx2x_set_rx_mode; - dev->set_mac_address = bnx2x_change_mac_addr; - dev->do_ioctl = bnx2x_ioctl; - dev->change_mtu = bnx2x_change_mtu; - dev->tx_timeout = bnx2x_tx_timeout; -#ifdef BCM_VLAN - dev->vlan_rx_register = bnx2x_vlan_rx_register; -#endif -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) - dev->poll_controller = poll_bnx2x; -#endif - dev->features |= NETIF_F_SG; - if (bp->flags & USING_DAC_FLAG) - dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_IP_CSUM; -#ifdef BCM_VLAN - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; -#endif - dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; - rc = register_netdev(dev); if (rc) { dev_err(&pdev->dev, "Cannot register net device\n"); - if (bp->regview) - iounmap(bp->regview); - if (bp->doorbells) - iounmap(bp->doorbells); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - free_netdev(dev); - return rc; + goto init_one_exit; } pci_set_drvdata(pdev, dev); - bp->name = board_info[ent->driver_data].name; + rc = bnx2x_init_bp(bp); + if (rc) { + unregister_netdev(dev); + goto init_one_exit; + } + + bp->common.name = board_info[ent->driver_data].name; printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx," - " IRQ %d, ", dev->name, bp->name, - ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', - ((CHIP_ID(bp) & 0x0ff0) >> 4), + " IRQ %d, ", dev->name, bp->common.name, + (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4), bnx2x_get_pcie_width(bp), (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz", dev->base_addr, bp->pdev->irq); printk(KERN_CONT "node addr %s\n", print_mac(mac, dev->dev_addr)); return 0; + +init_one_exit: + if (bp->regview) + iounmap(bp->regview); + + if (bp->doorbells) + iounmap(bp->doorbells); + + free_netdev(dev); + + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + return rc; } static void __devexit bnx2x_remove_one(struct pci_dev *pdev) @@ -7486,11 +8444,9 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev) struct bnx2x *bp; if (!dev) { - /* we get here if init_one() fails */ printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); return; } - bp = netdev_priv(dev); unregister_netdev(dev); @@ -7502,7 +8458,10 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev) iounmap(bp->doorbells); free_netdev(dev); - pci_release_regions(pdev); + + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -7512,21 +8471,29 @@ static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state) struct net_device *dev = pci_get_drvdata(pdev); struct bnx2x *bp; - if (!dev) - return 0; + if (!dev) { + printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); + return -ENODEV; + } + bp = netdev_priv(dev); - if (!netif_running(dev)) - return 0; + rtnl_lock(); - bp = netdev_priv(dev); + pci_save_state(pdev); - bnx2x_nic_unload(bp, 0); + if (!netif_running(dev)) { + rtnl_unlock(); + return 0; + } netif_device_detach(dev); - pci_save_state(pdev); + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + bnx2x_set_power_state(bp, pci_choose_state(pdev, state)); + rtnl_unlock(); + return 0; } @@ -7540,21 +8507,25 @@ static int bnx2x_resume(struct pci_dev *pdev) printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n"); return -ENODEV; } - - if (!netif_running(dev)) - return 0; - bp = netdev_priv(dev); + rtnl_lock(); + pci_restore_state(pdev); + + if (!netif_running(dev)) { + rtnl_unlock(); + return 0; + } + bnx2x_set_power_state(bp, PCI_D0); netif_device_attach(dev); - rc = bnx2x_nic_load(bp, 0); - if (rc) - return rc; + rc = bnx2x_nic_load(bp, LOAD_NORMAL); - return 0; + rtnl_unlock(); + + return rc; } static struct pci_driver bnx2x_pci_driver = { |