resubmit as attachments: bnx2x.c
Subsystems (2)
PATCH 2/8 resubmit as attachments: bnx2x.c
bnx2x.c - main .c file
From 967cea1c88d229776da5a3a78cdc7ac82f1196a7 Mon Sep 17 00:00:00 2001
From: Eliezer Tamir <[email protected]>
Date: Mon, 8 Oct 2007 11:53:12 +0200
Subject: [PATCH 2/8] add bnx2x.c
Signed-off-by Eliezer Tamir <[email protected]>
--- drivers/net/bnx2x.c | 8879 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 8879 insertions(+), 0 deletions(-)
drivers/net/bnx2x.c new file +8879 -0
@@ -0,0 +1,8879 @@ +/* bnx2x.c: Broadcom Everest network driver. +* +* Copyright (c) 2007 Broadcom Corporation +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation. +* +* Written by: Eliezer Tamir <[email protected]> +* Based on code from Michael Chan's bnx2 driver +* UDP CSUM errata workaround by Arik Gendelman +* Slowpath rework by Vladislav Zolotarov +* Statistics and Link managment by Yitchak Gertner +* +*/ + +/* define this to make the driver freeze on error +* -for now this is the defualt. +*/ +#define BNX2X_STOP_ON_ERROR + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/device.h> /* for dev_info() */ +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/dma-mapping.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <asm/byteorder.h> +#include <linux/time.h> +#include <linux/ethtool.h> +#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/workqueue.h> +#include <linux/crc32.h> +#include <linux/prefetch.h> +#include <linux/zlib.h> + +#include "bnx2x_hsi.h" +#include "bnx2x.h" +#include "bnx2x_init.h" +#include "bnx2x_self_test.h" + + +#define DRV_MODULE_VERSION "0.40.10" +#define DRV_MODULE_RELDATE "$DateTime: 2007/09/24 08:56:36 $" +#define BNX2X_BC_VER 0x040004 + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (5*HZ) + +static const char version[]__devinitdata = +"Broadcom NetXtreme II 577xx 10Gigabit Ethernet Driver " +DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n" ; + +MODULE_AUTHOR ("Eliezer Tamir <[email protected]>" ); +MODULE_DESCRIPTION ("Broadcom NetXtreme II BCM57710 Driver" ); +MODULE_LICENSE ("GPL" ); +MODULE_VERSION (DRV_MODULE_VERSION ); +MODULE_INFO (cvs_version,"$Revision: #302 $" ); + +static int use_inta; +static int poll; +static int onefunc; +static int nomcp; +static int debug; +module_param (use_inta, int,0 ); +module_param (poll, int,0 ); +module_param (onefunc, int,0 ); +module_param (debug, 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 managment CPU (Implies onefunc)" ); +MODULE_PARM_DESC (debug,"defualt debug msglevel" ); + +enum bnx2x_board_type { +BCM57710 =0 , +}; + +/* indexed by board_t, above */ +static const struct { +char *name; +} board_info[]__devinitdata = { + {"Broadcom NetXtreme II BCM57710 XGb" }, +}; + +#ifndef PCI_DEVICE_ID_NX2_57710 +#define PCI_DEVICE_ID_NX2_57710 0x164e +#endif + +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 }, + {0 } +}; + +MODULE_DEVICE_TABLE (pci, bnx2x_pci_tbl); + +/**************************************************************************** +* General service functions +****************************************************************************/ + +/* does not need locking since it is used only at init */ +static void bnx2x_reg_wr_ind (struct bnx2x *bp,u32 addr,u32 val) +{ +pci_write_config_dword (bp->pdev,PCICFG_GRC_ADDRESS , addr); +pci_write_config_dword (bp->pdev,PCICFG_GRC_DATA , val); +pci_write_config_dword (bp->pdev,PCICFG_GRC_ADDRESS , +PCICFG_VENDOR_ID_OFFSET ); +} + +#ifdef BNX2X_IND_RD +static u32 bnx2x_reg_rd_ind (struct bnx2x *bp,u32 addr) +{ +u32 val; + +pci_write_config_dword (bp->pdev,PCICFG_GRC_ADDRESS , addr); +pci_read_config_dword (bp->pdev,PCICFG_GRC_DATA , &val); +pci_write_config_dword (bp->pdev,PCICFG_GRC_ADDRESS , +PCICFG_VENDOR_ID_OFFSET ); + +return val; +} +#endif + +/* copy command into DMAE command memory */ +static void bnx2x_post_dmae (struct bnx2x *bp,int idx) +{ +struct dmae_command *dmae = &bp->dmae; +u32 cmd_offset; +int i; + + cmd_offset = (DMAE_REGISTERS_CMD_MEM + +sizeof (struct dmae_command ) * idx); +for (i =0 ; i < (sizeof (struct dmae_command )/4 ); i++) { +REG_WR32 (bp,GRCBASE_DMAE , cmd_offset + i*4 , + *(((u32 *)dmae) + i)); + +/* DP(NETIF_MSG_DMAE, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n", +idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i)); */ + } +} + +/* DMAE command positions used +* Port0 14 +* Port1 15 +*/ +static void bnx2x_write_dmae (struct bnx2x *bp,dma_addr_t dma_addr, +u32 wb_addr,u32 wb_len) +{ +struct dmae_command *dmae = &bp->dmae; +int port = bp->port; +u32 *wb_comp =bnx2x_sp (bp, wb_comp); +int timeout =200 ; + +memset (dmae,0 ,sizeof (struct dmae_command )); + + dmae->opcode = (DMAE_CMD_SRC_PCI |DMAE_CMD_DST_GRC | +DMAE_CMD_C_DST_PCI |DMAE_CMD_C_ENABLE | +DMAE_CMD_SRC_RESET |DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN +DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else +DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ?DMAE_CMD_PORT_1 :DMAE_CMD_PORT_0 )); + dmae->src_addr_lo =U64_LO (dma_addr); + dmae->src_addr_hi =U64_HI (dma_addr); + dmae->dst_addr_lo = wb_addr >>2 ; + dmae->dst_addr_hi =0 ; + dmae->len = wb_len; + dmae->comp_addr_lo =U64_LO (bnx2x_sp_mapping (bp, wb_comp)); + dmae->comp_addr_hi =U64_HI (bnx2x_sp_mapping (bp, wb_comp)); + dmae->comp_val =BNX2X_WB_COMP_VAL ; + +/* +DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n" +DP_LEVEL "src_addr [%x:%08x] len [%d *4] " +"dst_addr [%x:%08x (%08x)]\n" +DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", +dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, +dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, wb_addr, +dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); +*/ +/* +DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", +bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], +bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); +*/ + + *wb_comp =0 ; + +bnx2x_post_dmae (bp, port ?15 :14 ); + +REG_WR32 (bp,GRCBASE_DMAE , + (bp->port ?DMAE_REGISTERS_GO_C15 : +DMAE_REGISTERS_GO_C14 ),1 ); +udelay (5 ); +while (*wb_comp !=BNX2X_WB_COMP_VAL ) { +/* DP(NETIF_MSG_DMAE, "wb_comp 0x%08x\n", *wb_comp); */ +udelay (5 ); +if (!timeout) { +BNX2X_ERR ("dmae timeout!\n" ); +break ; + } + timeout--; + } +} + +#ifdef BNX2X_DMAE_RD +static void bnx2x_read_dmae (struct bnx2x *bp,u32 wb_addr,u32 wb_len) +{ +struct dmae_command *dmae = &bp->dmae; +int port = bp->port; +u32 *wb_comp =bnx2x_sp (bp, wb_comp); +int timeout =200 ; + +memset (bnx2x_sp (bp, wb_data[0 ]),0 ,sizeof (u32) *4 ); +memset (dmae,0 ,sizeof (struct dmae_command )); + + dmae->opcode = (DMAE_CMD_SRC_GRC |DMAE_CMD_DST_PCI | +DMAE_CMD_C_DST_PCI |DMAE_CMD_C_ENABLE | +DMAE_CMD_SRC_RESET |DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN +DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else +DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ?DMAE_CMD_PORT_1 :DMAE_CMD_PORT_0 )); + dmae->src_addr_lo = wb_addr >>2 ; + dmae->src_addr_hi =0 ; + dmae->dst_addr_lo =U64_LO (bnx2x_sp_mapping (bp, wb_data)); + dmae->dst_addr_hi =U64_HI (bnx2x_sp_mapping (bp, wb_data)); + dmae->len = wb_len; + dmae->comp_addr_lo =U64_LO (bnx2x_sp_mapping (bp, wb_comp)); + dmae->comp_addr_hi =U64_HI (bnx2x_sp_mapping (bp, wb_comp)); + dmae->comp_val =BNX2X_WB_COMP_VAL ; + +/* +DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n" +DP_LEVEL "src_addr [%x:%08x] len [%d *4] " +"dst_addr [%x:%08x (%08x)]\n" +DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", +dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, +dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, wb_addr, +dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); +*/ + + *wb_comp =0 ; + +bnx2x_post_dmae (bp, port ?15 :14 ); + +REG_WR32 (bp,GRCBASE_DMAE , + (bp->port ?DMAE_REGISTERS_GO_C15 : +DMAE_REGISTERS_GO_C14 ),1 ); +udelay (5 ); +while (*wb_comp !=BNX2X_WB_COMP_VAL ) { +udelay (5 ); +if (!timeout) { +BNX2X_ERR ("dmae timeout!\n" ); +break ; + } + timeout--; + } +/* +DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", +bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], +bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); +*/ +} +#endif + +static void bnx2x_panic_dump (struct bnx2x *bp) +{ +int i; +u16 j, start, end; + +BNX2X_ERR ("begin crash dump -----------------\n" ); + +for_each_queue (bp, i) { +struct bnx2x_fastpath *fp = &bp->fp[i]; +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" , + 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, + hw_prods->bds_prod); + + start =TX_BD (*fp->tx_cons_sb -10 ); + end =TX_BD (*fp->tx_cons_sb +245 ); +for (j = start; j < end; j++) { +struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j]; + +BNX2X_ERR ("packet[%x]=[%p,%x]\n" , j, + sw_bd->skb, sw_bd->first_bd); + } + + start =TX_BD (fp->tx_bd_cons -10 ); + end =TX_BD (fp->tx_bd_cons +254 ); +for (j = start; j < end; j++) { +u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j]; + +BNX2X_ERR ("tx_bd[%x]=[%x:%x:%x:%x]\n" , + j, tx_bd[0 ], tx_bd[1 ], tx_bd[2 ], tx_bd[3 ]); + } + + start =RX_BD (*fp->rx_cons_sb -10 ); + end =RX_BD (*fp->rx_cons_sb +503 ); +for (j = start; j < end; j++) { +u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j]; +struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j]; + +BNX2X_ERR ("rx_bd[%x]=[%x:%x:%x:%x] sw_bd=[%p]\n" , + j, rx_bd[0 ], rx_bd[1 ], rx_bd[2 ], rx_bd[3 ], + sw_bd->skb); + } + + start =RX_BD (fp->rx_comp_cons -10 ); + end =RX_BD (fp->rx_comp_cons +503 ); +for (j = start; j < end; j++) { +u32 *cqe = (u32 *)&fp->rx_comp_ring[j]; + +BNX2X_ERR ("cqe[%x]=[%x:%x:%x:%x]\n" , + j, cqe[0 ], cqe[1 ], cqe[2 ], cqe[3 ]); + } + } + +BNX2X_ERR ("def_c_idx(%u) def_u_idx(%u) def_t_idx(%u)" +" def_x_idx(%u) def_att_idx(%u) attn_state(%u)" +" spq_prod_idx(%u) spq_con_idx(%u)\n" , + bp->def_c_idx, bp->def_u_idx, bp->def_t_idx, bp->def_x_idx, + bp->def_att_idx, bp->attn_state, bp->spq_prod_idx, + bp->spq_con_idx); + +bnx2x_idle_chk (bp); +bnx2x_mc_assert (bp); +BNX2X_ERR ("end crash dump -----------------\n" ); + + bp->stats_state =STATS_STATE_DISABLE ; +DP (BNX2X_MSG_STATS ,"stats_state - DISABLE\n" ); +} + +static void bnx2x_enable_int (struct bnx2x *bp) +{ +int port = bp->port; +u32 addr = port ?HC_REGISTERS_CONFIG_1 :HC_REGISTERS_CONFIG_0 ; +u32 val =REG_RD (bp,GRCBASE_HC , addr); +int msix = (bp->flags &USING_MSIX_FLAG ) ?1 :0 ; + +if (msix) { + val &= ~HC_CONFIG_0_REGISTERS_SINGLE_ISR_EN_0 ; + val |= (HC_CONFIG_0_REGISTERS_MSI_MSIX_INT_EN_0 | +HC_CONFIG_0_REGISTERS_ATTN_BIT_EN_0 ); + }else { + val |= (HC_CONFIG_0_REGISTERS_SINGLE_ISR_EN_0 | +HC_CONFIG_0_REGISTERS_INT_LINE_EN_0 | +HC_CONFIG_0_REGISTERS_ATTN_BIT_EN_0 ); + val &= ~HC_CONFIG_0_REGISTERS_MSI_MSIX_INT_EN_0 ; + } + +DP (NETIF_MSG_INTR ,"write %x to HC %d (addr 0x%x) msi %d\n" , + val, port,GRCBASE_HC + addr, msix); + +REG_WR (bp,GRCBASE_HC , addr, val); +} + +static void bnx2x_disable_int (struct bnx2x *bp) +{ +int port = bp->port; +u32 addr = port ?HC_REGISTERS_CONFIG_1 :HC_REGISTERS_CONFIG_0 ; +u32 val =REG_RD (bp,GRCBASE_HC , addr); + + val &= ~(HC_CONFIG_0_REGISTERS_SINGLE_ISR_EN_0 | +HC_CONFIG_0_REGISTERS_MSI_MSIX_INT_EN_0 | +HC_CONFIG_0_REGISTERS_INT_LINE_EN_0 | +HC_CONFIG_0_REGISTERS_ATTN_BIT_EN_0 ); + +DP (NETIF_MSG_INTR ,"write %x to HC %d (addr 0x%x)\n" , + val, port,GRCBASE_HC + addr); + +REG_WR (bp,GRCBASE_HC , addr, val); +if (REG_RD (bp,GRCBASE_HC , addr) != val) { +BNX2X_ERR ("BUG! proper val not read from IGU!\n" ); + } +} + +static void bnx2x_disable_int_sync (struct bnx2x *bp) +{ +int msix = (bp->flags &USING_MSIX_FLAG ) ?1 :0 ; +int i; + +atomic_inc (&bp->intr_sem); +bnx2x_disable_int (bp); + +/* Disable SP tasklet */ +tasklet_disable (&bp->sp_task); + +if (msix) { +for_each_queue (bp, i) { +synchronize_irq (bp->msix_table[i].vector); + } +/* one more for the Slow Path IRQ */ +synchronize_irq (bp->msix_table[i].vector); + }else { +synchronize_irq (bp->pdev->irq); + } +} + +/* fast path */ + +/**************************************************************************** +* General service functions +****************************************************************************/ + +static inline void bnx2x_ack_sb (struct bnx2x *bp,u8 id, +u8 storm,u16 index,u8 op,u8 update) +{ +u16 flags; +u32 igu_addr = (IGU_ADDR_INT_ACK +IGU_PORT_BASE * bp->port) *8 ; +u32 command; + + flags = ((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 )); + + command = (flags <<16 ) | index; + +REG_WR (bp,BAR_IGU_INTMEM , igu_addr, command); +} + +static inline u16 bnx2x_update_fpsb_idx (struct bnx2x_fastpath *fp) +{ +struct host_status_block *fpsb = fp->status_blk; +u16 rc =0 ; + +if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) { + fp->fp_c_idx = fpsb->c_status_block.status_block_index; + rc |=1 ; + } +if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) { + fp->fp_u_idx = fpsb->u_status_block.status_block_index; + rc |=2 ; + } +rmb ();/* TBD chack this */ +return rc; +} + +static inline int bnx2x_has_work (struct bnx2x_fastpath *fp) +{ +u16 rx_cons_sb = *fp->rx_cons_sb; + +if ((rx_cons_sb &MAX_RX_DESC_CNT ) ==MAX_RX_DESC_CNT ) + rx_cons_sb++; + +if ((rx_cons_sb != fp->rx_comp_cons) || + (*fp->tx_cons_sb != fp->tx_pkt_cons)) +return 1 ; + +return 0 ; +} + +static u16 bnx2x_ack_int (struct bnx2x *bp) +{ +u32 igu_addr = (IGU_ADDR_SIMD_MASK +IGU_PORT_BASE * bp->port) *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); */ + +#ifdef IGU_DEBUG +#warning IGU_DEBUG active +if (result ==0 ) { +BNX2X_ERR ("read %x from IGU\n" , result); +REG_WR (bp,GRCBASE_TIMERS ,TM_REGISTERS_TIMER_SOFT_RST ,0 ); + } +#endif +return result; +} + + +/**************************************************************************** +* fast path service functions +****************************************************************************/ + +/* free skb in the packet ring at pos idx +return idx of last bd freed */ +static u16 bnx2x_free_tx_pkt (struct bnx2x *bp,struct bnx2x_fastpath *fp, +u16 idx) +{ +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; +int nbd; + +DP (BNX2X_MSG_OFF ,"pkt_idx %d buff @(%p)->skb %p\n" , + idx, tx_buf, skb); + +/* unmap first bd */ +DP (BNX2X_MSG_OFF ,"free bd_idx %d\n" , bd_idx); + tx_bd = &fp->tx_desc_ring[bd_idx]; +pci_unmap_single (bp->pdev,BD_UNMAP_ADDR (tx_bd), +BD_UNMAP_LEN (tx_bd),PCI_DMA_TODEVICE ); + + nbd = tx_bd->nbd -1 ; + +#ifdef BNX2X_STOP_ON_ERROR +if (nbd > (MAX_SKB_FRAGS +2 )) { +BNX2X_ERR ("bad nbd!\n" ); +bnx2x_panic (); + } +#endif + +/* Skip a parse bd and the TSO split header bd +since they have no mapping */ +if (nbd) + bd_idx =TX_BD (NEXT_TX_IDX (bd_idx)); + +if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM | +ETH_TX_BD_FLAGS_TCP_CSUM | +ETH_TX_BD_FLAGS_SW_LSO )) { +if (--nbd) + bd_idx =TX_BD (NEXT_TX_IDX (bd_idx)); + tx_bd = &fp->tx_desc_ring[bd_idx]; +/* is this a TSO heder split bd? */ +if (tx_bd->bd_flags.as_bitfield Ð_TX_BD_FLAGS_SW_LSO ) { +if (--nbd) + bd_idx =TX_BD (NEXT_TX_IDX (bd_idx)); + } + } + +/* now free frags */ +while (nbd >0 ) { + +DP (BNX2X_MSG_OFF ,"free frag bd_idx %d\n" , bd_idx); + tx_bd = &fp->tx_desc_ring[bd_idx]; +pci_unmap_page (bp->pdev,BD_UNMAP_ADDR (tx_bd), +BD_UNMAP_LEN (tx_bd),PCI_DMA_TODEVICE ); +if (--nbd) + bd_idx =TX_BD (NEXT_TX_IDX (bd_idx)); + } + +/* release skb */ +BUG_TRAP (skb); +dev_kfree_skb (skb); + tx_buf->first_bd =0 ; + tx_buf->skb =NULL ; + +return bd_idx; +} + +static inline u32 bnx2x_tx_avail (struct bnx2x_fastpath *fp) +{ +u16 used; +u32 prod; +u32 cons; + +/* Tell compiler that prod and cons can change. */ +barrier (); + 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 ; + } + +BUG_TRAP (used <= fp->bp->tx_ring_size); +BUG_TRAP ((fp->bp->tx_ring_size - used) <=MAX_TX_AVAIL ); + +return (fp->bp->tx_ring_size - used); +} + +static void bnx2x_tx_int (struct bnx2x_fastpath *fp,int work) +{ +struct bnx2x *bp = fp->bp; +u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons; +int done =0 ; + +#ifdef BNX2X_STOP_ON_ERROR +if (unlikely (bp->panic)) { +return ; + } +#endif + + hw_cons = *fp->tx_cons_sb; + sw_cons = fp->tx_pkt_cons; + +while (sw_cons != hw_cons) { +u16 pkt_cons; + + pkt_cons =TX_BD (sw_cons); + +/* prefetch(bp->tx_buf_ring[pkt_cons].skb); */ + +DP (NETIF_MSG_TX_DONE ,"hw_cons %u sw_cons %u pkt_cons %d\n" , + hw_cons, sw_cons, pkt_cons); + +/* if (NEXT_TX_IDX(sw_cons) != hw_cons) { +rmb(); +prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb); +} +*/ + bd_cons =bnx2x_free_tx_pkt (bp, fp, pkt_cons); + sw_cons++; + done++; + +if (done == work) { +break ; + } + } + + fp->tx_pkt_cons = sw_cons; + fp->tx_bd_cons = bd_cons; + +/* Need to make the tx_cons update visible to start_xmit() +* before checking for netif_queue_stopped(). Without the +* memory barrier, there is a small possibility that start_xmit() +* will miss it and cause the queue to be stopped forever. +*/ +smp_mb (); + +/* TBD need a thresh? */ +if (unlikely (netif_queue_stopped (bp->dev))) { +netif_tx_lock (bp->dev); +if ((netif_queue_stopped (bp->dev)) && + (bnx2x_tx_avail (fp) >=MAX_SKB_FRAGS +3 )) { +netif_wake_queue (bp->dev); + } +netif_tx_unlock (bp->dev); + } +} + +static void bnx2x_sp_event (struct bnx2x_fastpath *fp, +union eth_rx_cqe *rr_cqe) +{ +struct bnx2x *bp = fp->bp; +int cid =SW_CID (rr_cqe->ramrod_cqe.conn_and_cmd_data); +int command = ((rr_cqe->ramrod_cqe.conn_and_cmd_data) >> +COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT ); + +DP (NETIF_MSG_RX_STATUS , +"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); + + bp->spq_left++; + +switch (command | bp->state) { +case (RAMROD_CMD_ID_ETH_PORT_SETUP |BNX2X_STATE_OPENING_WAIT4_PORT ): +DP (NETIF_MSG_IFUP ,"got setup ramrod\n" ); + bp->state =BNX2X_STATE_OPEN ; +break ; + +case (RAMROD_CMD_ID_ETH_HALT |BNX2X_STATE_CLOSING_WAIT4_HALT ): +DP (NETIF_MSG_IFDOWN ,"got halt ramrod\n" ); + bp->state =BNX2X_STATE_CLOSING_WAIT4_DELETE ; + fp->state =BNX2X_FP_STATE_HALTED ; +break ; + +case (RAMROD_CMD_ID_ETH_PORT_DEL |BNX2X_STATE_CLOSING_WAIT4_DELETE ): +DP (NETIF_MSG_IFDOWN ,"got delete ramrod\n" ); + bp->state =BNX2X_STATE_CLOSING_WAIT4_UNLOAD ; +break ; + +case (RAMROD_CMD_ID_ETH_SET_MAC |BNX2X_STATE_OPEN ): +DP (NETIF_MSG_IFUP ,"got set mac ramrod\n" ); +break ; + +default : +BNX2X_ERR ("unexpected ramrod (%d) state is %x\n" , + command, bp->state); + } +} + +static inline int bnx2x_alloc_rx_skb (struct bnx2x *bp, +struct bnx2x_fastpath *fp,u16 index) +{ +struct sk_buff *skb; +struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index]; +struct eth_rx_bd *rxbd = &fp->rx_desc_ring[index]; +dma_addr_t mapping; + + skb =netdev_alloc_skb (bp->dev, bp->rx_buf_size); +if (unlikely (skb ==NULL )) { +return -ENOMEM ; + } + + 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 ; + } + + rx_buf->skb = skb; +pci_unmap_addr_set (rx_buf, mapping, mapping); +#ifdef BNX2X_STOP_ON_ERROR + rxbd->reserved = fp->last_alloc++; +#else + rxbd->reserved =0 ; +#endif + rxbd->len = bp->rx_buf_use_size; + rxbd->addr_hi =U64_HI (mapping); + rxbd->addr_lo =U64_LO (mapping); + +return 0 ; +} + +/* note that we are not allocating a new skb, +* we are just moving one from cons to prod +* we are not creating a new mapping, +* so there is no need to check for dma_mapping_error(). +*/ +static void bnx2x_reuse_rx_skb (struct bnx2x_fastpath *fp, +struct sk_buff *skb,u16 cons,u16 prod) +{ +struct bnx2x *bp = fp->bp; +struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; +struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; +struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons]; +struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; + +pci_dma_sync_single_for_device (bp->pdev, +pci_unmap_addr (cons_rx_buf, mapping), + bp->rx_offset +RX_COPY_THRESH , +PCI_DMA_FROMDEVICE ); + + prod_rx_buf->skb = cons_rx_buf->skb; +pci_unmap_addr_set (prod_rx_buf, mapping, +pci_unmap_addr (cons_rx_buf, mapping)); + *prod_bd = *cons_bd; +#ifdef BNX2X_STOP_ON_ERROR + prod_bd->reserved = fp->last_alloc++; +#endif +} + +static int bnx2x_rx_int (struct bnx2x_fastpath *fp,int budget) +{ +struct bnx2x *bp = fp->bp; +u16 bd_cons, bd_prod, comp_ring_prod, comp_ring_cons; +u16 hw_comp_cons, sw_comp_cons, sw_comp_prod; +int rx_pkt =0 ; + +#ifdef BNX2X_STOP_ON_ERROR +if (unlikely (bp->panic)) { +return 0 ; + } +#endif + + hw_comp_cons = *fp->rx_cons_sb; +if ((hw_comp_cons &MAX_RX_DESC_CNT ) ==MAX_RX_DESC_CNT ) { + hw_comp_cons++; + } + + bd_cons = fp->rx_bd_cons; + bd_prod = fp->rx_bd_prod; + sw_comp_cons = fp->rx_comp_cons; + sw_comp_prod = fp->rx_comp_prod; + +/* Memory barrier necessary as speculative reads of the rx +* buffer can be ahead of the index in the status block +*/ +rmb (); + +DP (NETIF_MSG_RX_STATUS , +"queue[%d]: hw_comp_cons %u sw_comp_cons %u\n" , + fp->index, hw_comp_cons, sw_comp_cons); + +while (sw_comp_cons != hw_comp_cons) { +unsigned int len, pad; +struct sw_rx_bd *rx_buf; +struct sk_buff *skb; +union eth_rx_cqe *cqe; + + comp_ring_prod =RX_BD (sw_comp_prod); + comp_ring_cons =RX_BD (sw_comp_cons); + bd_prod =RX_BD (bd_prod); + bd_cons =RX_BD (bd_cons); + + cqe = &fp->rx_comp_ring[comp_ring_cons]; + +DP (NETIF_MSG_RX_STATUS ,"hw_comp_cons %u sw_comp_cons %u" +" comp_ring (%u,%u) bd_ring (%u,%u)\n" , + hw_comp_cons, sw_comp_cons, comp_ring_prod, + 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 csum %x\n" , + cqe->fast_path_cqe.type, cqe->fast_path_cqe.error_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, cqe->fast_path_cqe.l4_csum); + +/* is this a slowpath msg? */ +if (unlikely (cqe->fast_path_cqe.type)) { +bnx2x_sp_event (fp, cqe); + goto next_cqe; + +/* this is an rx packet */ + }else { + rx_buf = &fp->rx_buf_ring[bd_cons]; + skb = rx_buf->skb; + + len = cqe->fast_path_cqe.pkt_len; + pad = cqe->fast_path_cqe.placement_offset; + +pci_dma_sync_single_for_device (bp->pdev, +pci_unmap_addr (rx_buf, mapping), + pad +RX_COPY_THRESH , +PCI_DMA_FROMDEVICE ); +prefetch (skb); +prefetch (((char *)(skb)) +128 ); + +#ifdef BNX2X_STOP_ON_ERROR +BUG_TRAP (fp->rx_desc_ring[bd_cons].reserved == + fp->next_free); + fp->next_free++; +#endif +/* is this an error packet? */ +if (unlikely (cqe->fast_path_cqe.error_flags)) { +/* do we sometimes forward error packets anyway? */ +DP (NETIF_MSG_RX_ERR , +"ERROR flags(%u) Rx packet(%u)\n" , + cqe->fast_path_cqe.error_flags, + sw_comp_cons); +/* TBD make sure MC counts this as a drop */ + goto reuse_rx; + } + +/* Since we don't have a jumbo ring +* copy small packets if mtu > 1500 +*/ +if ((bp->dev->mtu >1500 ) && + (len <=RX_COPY_THRESH )) { +struct sk_buff *new_skb; + + new_skb =netdev_alloc_skb (bp->dev, + len + pad); +if (new_skb ==NULL ) { +DP (NETIF_MSG_RX_ERR , +"ERROR packet dropped " +"because of alloc failure\n" ); +/* TBD count this as a drop? */ + goto reuse_rx; + } + +/* aligned copy */ +skb_copy_from_linear_data_offset (skb, pad, + new_skb->data + + pad, len); + +skb_reserve (new_skb, pad); +skb_put (new_skb, len); + +bnx2x_reuse_rx_skb (fp, skb, bd_cons, bd_prod); + + skb = new_skb; + + }else if (bnx2x_alloc_rx_skb (bp, fp, bd_prod) ==0 ) { +pci_unmap_single (bp->pdev, +pci_unmap_addr (rx_buf, + mapping), + bp->rx_buf_use_size, +PCI_DMA_FROMDEVICE ); +skb_reserve (skb, pad); +skb_put (skb, len); + + }else { +DP (NETIF_MSG_RX_ERR , +"ERROR packet dropped because " +"of alloc failure\n" ); +reuse_rx: +bnx2x_reuse_rx_skb (fp, skb, bd_cons, bd_prod); + goto next_rx; + } + + skb->protocol =eth_type_trans (skb, bp->dev); + + skb->ip_summed =CHECKSUM_NONE ; +if (bp->rx_csum &&BNX2X_RX_SUM_OK (cqe)) + skb->ip_summed =CHECKSUM_UNNECESSARY ; + +/* TBD do we pass bad csum packets on promisc? +* if (unlikely(cqe->fast_path_cqe.error_flags)) +* skb->ip_summed = CHECKSUM_NONE; +*/ + } + +#ifdef BCM_VLAN +if ((cqe->fast_path_cqe.pars_flags.flags + &PARSING_FLAGS_NUMBER_OF_NESTED_VLANS ) + && (bp->vlgrp !=0 )) { +vlan_hwaccel_receive_skb (skb, bp->vlgrp, + cqe->fast_path_cqe.vlan_tag); + } else +#endif +netif_receive_skb (skb); + + bp->dev->last_rx = jiffies; + +next_rx: + rx_buf->skb =NULL ; + + bd_cons =NEXT_RX_IDX (bd_cons); + bd_prod =NEXT_RX_IDX (bd_prod); +next_cqe: + sw_comp_prod =NEXT_RX_IDX (sw_comp_prod); + sw_comp_cons =NEXT_RX_IDX (sw_comp_cons); + rx_pkt++; + +if ((rx_pkt == budget)) +break ; + }/* while */ + + fp->rx_bd_cons = bd_cons; + fp->rx_bd_prod = bd_prod; + 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); + +mmiowb (); + + fp->rx_pkt += rx_pkt; + fp->rx_calls++; + +return rx_pkt; +} + +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; + +DP (NETIF_MSG_INTR ,"got an msix interrupt on [%d]\n" , fp->index); +bnx2x_ack_sb (bp, fp->index,USTORM_ID ,0 ,IGU_INT_DISABLE ,0 ); + +#ifdef BNX2X_STOP_ON_ERROR +if (unlikely (bp->panic)) { +return IRQ_HANDLED ; + } +#endif + +prefetch (fp->rx_cons_sb); +prefetch (fp->tx_cons_sb); +prefetch (&fp->status_blk->c_status_block.status_block_index); +prefetch (&fp->status_blk->u_status_block.status_block_index); +netif_rx_schedule (dev, &bnx2x_fp (bp,0 , napi)); +return IRQ_HANDLED ; +} + +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); + +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); + +#ifdef BNX2X_STOP_ON_ERROR +if (unlikely (bp->panic)) { +return IRQ_HANDLED ; + } +#endif + +/* Return here if interrupt is shared and 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 ) { +struct bnx2x_fastpath *fp = &bp->fp[0 ]; + +prefetch (fp->rx_cons_sb); +prefetch (fp->tx_cons_sb); +prefetch (&fp->status_blk->c_status_block.status_block_index); +prefetch (&fp->status_blk->u_status_block.status_block_index); + +netif_rx_schedule (dev, &bnx2x_fp (bp,0 , napi)); + + status &= ~0x2 ; +if (!status) { +return IRQ_HANDLED ; + } + } + +if (unlikely (status &0x1 )) { +tasklet_schedule (&bp->sp_task); + + status &= ~0x1 ; +if (!status) { +return IRQ_HANDLED ; + } + } + +DP (NETIF_MSG_INTR ,"got an unknown interrupt! (status is %u)\n" , + status); + +return IRQ_HANDLED ; +} + +/* end of fast path */ + +/* PHY/MAC */ + +/**************************************************************************** +* General service functions +****************************************************************************/ + +static void bnx2x_leds_set (struct bnx2x *bp,unsigned int speed) +{ +u32 val; +int port = bp->port; + +NIG_WR (NIG_REGISTERS_LED_MODE_P0 + port*4 , + ((bp->hw_config &SHARED_HW_CFG_LED_MODE_MASK ) >> +SHARED_HW_CFG_LED_MODE_SHIFT )); +NIG_WR (NIG_REGISTERS_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4 ,0 ); + +switch (speed) { +case SPEED_1000 : + val =0x3ff ; +break ; + +case SPEED_100 : + val =0x7ff ; +break ; + +case SPEED_10 : + val =0xfff ; +break ; + +default :/* 2.5G and up */ + val =0xff ; +break ; + } +NIG_WR (NIG_REGISTERS_LED_CONTROL_BLINK_RATE_P0 + port*4 , val); +NIG_WR (NIG_REGISTERS_LED_CONTROL_BLINK_RATE_ENA_P0 + port*4 ,1 ); +} + +static void bnx2x_leds_unset (struct bnx2x *bp) +{ +int port = bp->port; + +NIG_WR (NIG_REGISTERS_LED_10G_P0 + port*4 ,0 ); + +NIG_WR (NIG_REGISTERS_LED_MODE_P0 + port*4 ,SHARED_HW_CFG_LED_MAC1 ); +} + +static u32 bnx2x_bits_en (struct bnx2x *bp,u32 block,u32 reg, +u32 bits) +{ +u32 val =REG_RD (bp, block, reg); + + val |= bits; +REG_WR (bp, block, reg, val); +return val; +} + +static u32 bnx2x_bits_dis (struct bnx2x *bp,u32 block,u32 reg, +u32 bits) +{ +u32 val =REG_RD (bp, block, reg); + + val &= ~bits; +REG_WR (bp, block, reg, val); +return val; +} + +static int bnx2x_mdio22_write (struct bnx2x *bp,u32 reg,u32 val) +{ +int rc; +u32 tmp, i; +int port = bp->port; +u32 emac_base = port ?GRCBASE_EMAC1 :GRCBASE_EMAC0 ; + +/* DP(NETIF_MSG_HW, "phy_addr 0x%x reg 0x%x val 0x%08x\n", +bp->phy_addr, reg, val); */ + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + tmp &= ~EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , tmp); +REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); +udelay (40 ); + } + + tmp = ((bp->phy_addr <<21 ) | (reg <<16 ) | + (val &EMAC_MDIO_COMM_DATA ) | +EMAC_MDIO_COMM_COMMAND_WRITE_22 | +EMAC_MDIO_COMM_START_BUSY ); +EMAC_WR (EMAC_REG_EMAC_MDIO_COMM , tmp); + +for (i =0 ; i <50 ; i++) { +udelay (10 ); + + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_COMM ); +if (!(tmp &EMAC_MDIO_COMM_START_BUSY )) { +udelay (5 ); +break ; + } + } + +if (tmp &EMAC_MDIO_COMM_START_BUSY ) { +BNX2X_ERR ("write phy register failed\n" ); + + rc = -EBUSY ; + }else { + rc =0 ; + } + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + tmp |=EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , tmp); + } + +return rc; +} + +static int bnx2x_mdio22_read (struct bnx2x *bp,u32 reg,u32 *ret_val) +{ +int rc; +u32 val, i; +int port = bp->port; +u32 emac_base = port ?GRCBASE_EMAC1 :GRCBASE_EMAC0 ; + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + val &= ~EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , val); +REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); +udelay (40 ); + } + + val = ((bp->phy_addr <<21 ) | (reg <<16 ) | +EMAC_MDIO_COMM_COMMAND_READ_22 | +EMAC_MDIO_COMM_START_BUSY ); +EMAC_WR (EMAC_REG_EMAC_MDIO_COMM , val); + +for (i =0 ; i <50 ; i++) { +udelay (10 ); + + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_COMM ); +if (!(val &EMAC_MDIO_COMM_START_BUSY )) { + val &=EMAC_MDIO_COMM_DATA ; +break ; + } + } + +if (val &EMAC_MDIO_COMM_START_BUSY ) { +BNX2X_ERR ("read phy register failed\n" ); + + *ret_val =0x0 ; + rc = -EBUSY ; + }else { + *ret_val = val; + rc =0 ; + } + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + val |=EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , val); + } + +/* DP(NETIF_MSG_HW, "phy_addr 0x%x reg 0x%x ret_val 0x%08x\n", +bp->phy_addr, reg, *ret_val); */ + +return rc; +} + +static int bnx2x_mdio45_write (struct bnx2x *bp,u32 reg,u32 addr,u32 val) +{ +int rc =0 ; +u32 tmp, i; +int port = bp->port; +u32 emac_base = port ?GRCBASE_EMAC1 :GRCBASE_EMAC0 ; + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + tmp &= ~EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , tmp); +REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); +udelay (40 ); + } + +/* set clause 45 mode */ + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + tmp |=EMAC_MDIO_MODE_CLAUSE_45 ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , tmp); + +/* address */ + tmp = ((bp->phy_addr <<21 ) | (reg <<16 ) | addr | +EMAC_MDIO_COMM_COMMAND_ADDRESS | +EMAC_MDIO_COMM_START_BUSY ); +EMAC_WR (EMAC_REG_EMAC_MDIO_COMM , tmp); + +for (i =0 ; i <50 ; i++) { +udelay (10 ); + + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_COMM ); +if (!(tmp &EMAC_MDIO_COMM_START_BUSY )) { +udelay (5 ); +break ; + } + } + +if (tmp &EMAC_MDIO_COMM_START_BUSY ) { +BNX2X_ERR ("write phy register failed\n" ); + + rc = -EBUSY ; + }else { +/* data */ + tmp = ((bp->phy_addr <<21 ) | (reg <<16 ) | val | +EMAC_MDIO_COMM_COMMAND_WRITE_45 | +EMAC_MDIO_COMM_START_BUSY ); +EMAC_WR (EMAC_REG_EMAC_MDIO_COMM , tmp); + +for (i =0 ; i <50 ; i++) { +udelay (10 ); + + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_COMM ); +if (!(tmp &EMAC_MDIO_COMM_START_BUSY )) { +udelay (5 ); +break ; + } + } + +if (tmp &EMAC_MDIO_COMM_START_BUSY ) { +BNX2X_ERR ("write phy register failed\n" ); + + rc = -EBUSY ; + } + } + +/* unset clause 45 mode */ + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + tmp &= ~EMAC_MDIO_MODE_CLAUSE_45 ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , tmp); + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + tmp =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + tmp |=EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , tmp); + } + +return rc; +} + +static int bnx2x_mdio45_read (struct bnx2x *bp,u32 reg,u32 addr, +u32 *ret_val) +{ +int rc =0 ; +u32 val, i; +int port = bp->port; +u32 emac_base = port ?GRCBASE_EMAC1 :GRCBASE_EMAC0 ; + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + val &= ~EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , val); +REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); +udelay (40 ); + } + +/* set clause 45 mode */ + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + val |=EMAC_MDIO_MODE_CLAUSE_45 ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , val); + +/* address */ + val = ((bp->phy_addr <<21 ) | (reg <<16 ) | addr | +EMAC_MDIO_COMM_COMMAND_ADDRESS | +EMAC_MDIO_COMM_START_BUSY ); +EMAC_WR (EMAC_REG_EMAC_MDIO_COMM , val); + +for (i =0 ; i <50 ; i++) { +udelay (10 ); + + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_COMM ); +if (!(val &EMAC_MDIO_COMM_START_BUSY )) { +udelay (5 ); +break ; + } + } + +if (val &EMAC_MDIO_COMM_START_BUSY ) { +BNX2X_ERR ("read phy register failed\n" ); + + *ret_val =0 ; + rc = -EBUSY ; + }else { +/* data */ + val = ((bp->phy_addr <<21 ) | (reg <<16 ) | +EMAC_MDIO_COMM_COMMAND_READ_45 | +EMAC_MDIO_COMM_START_BUSY ); +EMAC_WR (EMAC_REG_EMAC_MDIO_COMM , val); + +for (i =0 ; i <50 ; i++) { +udelay (10 ); + + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_COMM ); +if (!(val &EMAC_MDIO_COMM_START_BUSY )) { + val &=EMAC_MDIO_COMM_DATA ; +break ; + } + } + +if (val &EMAC_MDIO_COMM_START_BUSY ) { +BNX2X_ERR ("read phy register failed\n" ); + + val =0 ; + rc = -EBUSY ; + } + + *ret_val = val; + } + +/* unset clause 45 mode */ + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + val &= ~EMAC_MDIO_MODE_CLAUSE_45 ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , val); + +if (bp->phy_flags &PHY_INT_MODE_AUTO_POLLING_FLAG ) { + + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MDIO_MODE ); + val |=EMAC_MDIO_MODE_AUTO_POLL ; +EMAC_WR (EMAC_REG_EMAC_MDIO_MODE , val); + } + +return rc; +} + +static int bnx2x_mdio45_vwrite (struct bnx2x *bp,u32 reg,u32 addr,u32 val) +{ +int i; +u32 rd_val; + +for (i =0 ; i <10 ; i++) { +bnx2x_mdio45_write (bp, reg, addr, val); +mdelay (5 ); +bnx2x_mdio45_read (bp, reg, addr, &rd_val); +/* if the read value is not the same as the value we wrote, +we should write it again */ +if (rd_val == val) { +return 0 ; + } + } +BNX2X_ERR ("MDIO write in CL45 failed\n" ); +return -EBUSY ; +} + +/**************************************************************************** +* Deferred Interrupt service functions +****************************************************************************/ + +static void bnx2x_flow_ctrl_resolve (struct bnx2x *bp,u32 gp_status) +{ +u32 ld_pause;/* local driver */ +u32 lp_pause;/* link partner */ +u32 pause_result; + + bp->flow_ctrl =0 ; + +/* reolve from gp_status in case of AN complete and not sgmii */ +if ((bp->req_autoneg &AUTONEG_FLOW_CTRL ) && + (gp_status &MDIO_AN_CL73_OR_37_COMPLETE ) && + (!(bp->phy_flags &PHY_SGMII_FLAG )) && + (XGXS_EXT_PHY_TYPE (bp) ==PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT )) { + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_read (bp,MDIO_COMBO_IEEE0_AUTO_NEG_ADV , + &ld_pause); +bnx2x_mdio22_read (bp, +MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1 , + &lp_pause); + pause_result = (ld_pause & +MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK )>>5 ; + pause_result |= (lp_pause & +MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK )>>7 ; +DP (NETIF_MSG_LINK ,"pause_result 0x%x\n" , pause_result); + +switch (pause_result) {/* ASYM P ASYM P */ +case 0xb :/* 1 0 1 1 */ + bp->flow_ctrl =FLOW_CTRL_TX ; +break ; + +case 0xe :/* 1 1 1 0 */ + bp->flow_ctrl =FLOW_CTRL_RX ; +break ; + +case 0x5 :/* 0 1 0 1 */ +case 0x7 :/* 0 1 1 1 */ +case 0xd :/* 1 1 0 1 */ +case 0xf :/* 1 1 1 1 */ + bp->flow_ctrl =FLOW_CTRL_BOTH ; +break ; + +default : +break ; + } + + }else {/* forced mode */ + bp->flow_ctrl = bp->req_flow_ctrl; +if (bp->req_flow_ctrl ==FLOW_CTRL_AUTO ) { + bp->flow_ctrl =FLOW_CTRL_BOTH ; + } + } +DP (NETIF_MSG_LINK ,"flow_ctrl 0x%x\n" , bp->flow_ctrl); +} + +static void bnx2x_link_settings_status (struct bnx2x *bp,u32 gp_status) +{ + bp->link_status =0 ; + +if (gp_status &MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS ) { +DP (NETIF_MSG_LINK ,"link up\n" ); + + bp->link_up =1 ; + bp->link_status |=LINK_STATUS_LINK_UP ; + +if (gp_status &MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS ) { + bp->duplex =DUPLEX_FULL ; + }else { + bp->duplex =DUPLEX_HALF ; + } + +bnx2x_flow_ctrl_resolve (bp, gp_status); + +switch (gp_status &GP_STATUS_SPEED_MASK ) { +case GP_STATUS_10M : + bp->line_speed =SPEED_10 ; +if (bp->duplex ==DUPLEX_FULL ) { + bp->link_status |=LINK_10TFD ; + }else { + bp->link_status |=LINK_10THD ; + } +break ; + +case GP_STATUS_100M : + bp->line_speed =SPEED_100 ; +if (bp->duplex ==DUPLEX_FULL ) { + bp->link_status |=LINK_100TXFD ; + }else { + bp->link_status |=LINK_100TXHD ; + } +break ; + +case GP_STATUS_1G : +case GP_STATUS_1G_KX : + bp->line_speed =SPEED_1000 ; +if (bp->duplex ==DUPLEX_FULL ) { + bp->link_status |=LINK_1000TFD ; + }else { + bp->link_status |=LINK_1000THD ; + } +break ; + +case GP_STATUS_2_5G : + bp->line_speed =SPEED_2500 ; +if (bp->duplex ==DUPLEX_FULL ) { + bp->link_status |=LINK_2500TFD ; + }else { + bp->link_status |=LINK_2500THD ; + } +break ; + +case GP_STATUS_5G : +case GP_STATUS_6G : +BNX2X_ERR ("link speed unsupported gp_status 0x%x\n" , + gp_status); +break ; + +case GP_STATUS_10G_KX4 : +case GP_STATUS_10G_HIG : +case GP_STATUS_10G_CX4 : + bp->line_speed =SPEED_10000 ; + bp->link_status |=LINK_10GTFD ; +break ; + +case GP_STATUS_12G_HIG : + bp->line_speed =SPEED_12000 ; + bp->link_status |=LINK_12GTFD ; +break ; + +case GP_STATUS_12_5G : + bp->line_speed =SPEED_12500 ; + bp->link_status |=LINK_12_5GTFD ; +break ; + +case GP_STATUS_13G : + bp->line_speed =SPEED_13000 ; + bp->link_status |=LINK_13GTFD ; +break ; + +case GP_STATUS_15G : + bp->line_speed =SPEED_15000 ; + bp->link_status |=LINK_15GTFD ; +break ; + +case GP_STATUS_16G : + bp->line_speed =SPEED_16000 ; + bp->link_status |=LINK_16GTFD ; +break ; + +default : +BNX2X_ERR ("link speed unsupported gp_status 0x%x\n" , + gp_status); +break ; + } + + bp->link_status |=LINK_STATUS_SERDES_LINK ; + +if (bp->req_autoneg &AUTONEG_SPEED ) { + bp->link_status |=LINK_STATUS_AUTO_NEGOTIATE_ENABLED ; + +if (gp_status &MDIO_AN_CL73_OR_37_COMPLETE ) { + bp->link_status |= +LINK_STATUS_AUTO_NEGOTIATE_COMPLETE ; + } +if (bp->autoneg &AUTONEG_PARALLEL ) { + bp->link_status |= +LINK_STATUS_PARALLEL_DETECTION_USED ; + } + } + +if (bp->flow_ctrl &FLOW_CTRL_TX ) { + bp->link_status |=LINK_STATUS_TX_FLOW_CONTROL_ENABLED ; + } +if (bp->flow_ctrl &FLOW_CTRL_RX ) { + bp->link_status |=LINK_STATUS_RX_FLOW_CONTROL_ENABLED ; + } + + }else {/* link_down */ +DP (NETIF_MSG_LINK ,"link down\n" ); + + bp->link_up =0 ; + + bp->line_speed =0 ; + bp->duplex =DUPLEX_FULL ; + bp->flow_ctrl =0 ; + } + +DP (NETIF_MSG_LINK ,"gp_status 0x%x link_up %d\n" +DP_LEVEL " line_speed %d duplex %d flow_ctrl 0x%x" +" link_status 0x%x\n" , + gp_status, bp->link_up, bp->line_speed, bp->duplex, bp->flow_ctrl, + bp->link_status); +} + +static void bnx2x_link_int_ack (struct bnx2x *bp,int is_10g) +{ +int port = bp->port; + +/* first reset all status +* we asume only one line will be change at a time */ +bnx2x_bits_dis (bp,GRCBASE_NIG , +NIG_REGISTERS_STATUS_INTERRUPT_PORT0 + port*4 , + (NIG_XGXS0_LINK_STATUS | +NIG_SERDES0_LINK_STATUS | +NIG_STATUS_INTERRUPT_XGXS0_LINK10G )); +if (bp->link_up) { +if (is_10g) { +/* Disable the 10G link interrupt +* by writing 1 to the status register +*/ +DP (NETIF_MSG_LINK ,"10G XGXS link up\n" ); +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_STATUS_INTERRUPT_PORT0 + + port*4 , +NIG_STATUS_INTERRUPT_XGXS0_LINK10G ); + + }else if (bp->phy_flags &PHY_XGXS_FLAG ) { +/* Disable the link interrupt +* by writing 1 to the relevant lane +* in the status register +*/ +DP (NETIF_MSG_LINK ,"1G XGXS link up\n" ); +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_STATUS_INTERRUPT_PORT0 + + port*4 , ((1 << bp->ser_lane) << +NIG_XGXS0_LINK_STATUS_SIZE )); + + }else {/* SerDes */ +DP (NETIF_MSG_LINK ,"SerDes link up\n" ); +/* Disable the link interrupt +* by writing 1 to the status register +*/ +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_STATUS_INTERRUPT_PORT0 + + port*4 ,NIG_SERDES0_LINK_STATUS ); + } + + }else {/* link_down */ + } +} + +static int bnx2x_ext_phy_is_link_up (struct bnx2x *bp) +{ +u32 ext_phy_type; +u32 ext_phy_addr; +u32 local_phy; +u32 val =0 ; +u32 rx_sd, pcs_status; + +if (bp->phy_flags &PHY_XGXS_FLAG ) { + local_phy = bp->phy_addr; + ext_phy_addr = ((bp->ext_phy_config & +PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK ) >> +PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT ); + bp->phy_addr = (u8 )ext_phy_addr; + + ext_phy_type =XGXS_EXT_PHY_TYPE (bp); +switch (ext_phy_type) { +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT : +DP (NETIF_MSG_LINK ,"XGXS Direct\n" ); + val =1 ; +break ; + +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705 : +DP (NETIF_MSG_LINK ,"XGXS 8705\n" ); +bnx2x_mdio45_read (bp,EXT_PHY_OPT_WIS_DEVAD , +EXT_PHY_OPT_LASI_STATUS , &val); +DP (NETIF_MSG_LINK ,"8705 LASI status is %d\n" , val); + +bnx2x_mdio45_read (bp,EXT_PHY_OPT_WIS_DEVAD , +EXT_PHY_OPT_LASI_STATUS , &val); +DP (NETIF_MSG_LINK ,"8705 LASI status is %d\n" , val); + +bnx2x_mdio45_read (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_PMD_RX_SD , &rx_sd); + val = (rx_sd &0x1 ); +break ; + +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 : +DP (NETIF_MSG_LINK ,"XGXS 8706\n" ); +bnx2x_mdio45_read (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_LASI_STATUS , &val); +DP (NETIF_MSG_LINK ,"8706 LASI status is %d\n" , val); + +bnx2x_mdio45_read (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_LASI_STATUS , &val); +DP (NETIF_MSG_LINK ,"8706 LASI status is %d\n" , val); + +bnx2x_mdio45_read (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_PMD_RX_SD , &rx_sd); +bnx2x_mdio45_read (bp,EXT_PHY_OPT_PCS_DEVAD , +EXT_PHY_OPT_PCS_STATUS , &pcs_status); +DP (NETIF_MSG_LINK ,"8706 rx_sd 0x%x" +" pcs_status 0x%x\n" , rx_sd, pcs_status); +/* link is up if both bit 0 of pmd_rx and +* bit 0 of pcs_status are set +*/ + val = (rx_sd & pcs_status); +break ; + +default : +DP (NETIF_MSG_LINK ,"BAD XGXS ext_phy_config 0x%x\n" , + bp->ext_phy_config); + val =0 ; +break ; + } + bp->phy_addr = local_phy; + + }else {/* SerDes */ + ext_phy_type =SERDES_EXT_PHY_TYPE (bp); +switch (ext_phy_type) { +case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT : +DP (NETIF_MSG_LINK ,"SerDes Direct\n" ); + val =1 ; +break ; + +case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482 : +DP (NETIF_MSG_LINK ,"SerDes 5482\n" ); + val =1 ; +break ; + +default : +DP (NETIF_MSG_LINK ,"BAD SerDes ext_phy_config 0x%x\n" , + bp->ext_phy_config); + val =0 ; +break ; + } + } + +return val; +} + +static void bnx2x_bmac_enable (struct bnx2x *bp,int is_lb) +{ +int port = bp->port; +u32 bmac_addr = port ?NIG_REGISTERS_INGRESS_BMAC1_MEM : +NIG_REGISTERS_INGRESS_BMAC0_MEM ; +u32 wb_write[2 ]; +u32 val; + +DP (NETIF_MSG_LINK ,"enableing BigMAC\n" ); +/* reset and unreset the BigMac */ +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_2_CLEAR , + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); +mdelay (5 ); +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_2_SET , + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + +/* enable access for bmac registers */ +NIG_WR (NIG_REGISTERS_BMAC0_REGS_OUT_EN + port*4 ,0x1 ); + +/* XGXS control */ + wb_write[0 ] =0x3c ; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_BMAC_XGXS_CONTROL , + wb_write,2 ); + +/* tx MAC SA */ + wb_write[0 ] = ((bp->dev->dev_addr[2 ] <<24 ) | + (bp->dev->dev_addr[3 ] <<16 ) | + (bp->dev->dev_addr[4 ] <<8 ) | + bp->dev->dev_addr[5 ]); + wb_write[1 ] = ((bp->dev->dev_addr[0 ] <<8 ) | + bp->dev->dev_addr[1 ]); +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_TX_SOURCE_ADDR , wb_write,2 ); + +/* tx control */ + val =0xc0 ; +if (bp->flow_ctrl &FLOW_CTRL_TX ) { + val |=0x800000 ; + } + wb_write[0 ] = val; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_TX_CONTROL , wb_write,2 ); + +/* set tx mtu */ + wb_write[0 ] = bp->rx_buf_use_size; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_TX_MAX_SIZE , wb_write,2 ); + +/* mac control */ + val =0x3 ; +if (is_lb) { + val |=0x4 ; +DP (NETIF_MSG_LINK ,"enable bmac loopback\n" ); + } + wb_write[0 ] = val; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_BMAC_CONTROL , wb_write,2 ); + +/* rx control set to don't strip crc */ + val =0x14 ; +if (bp->flow_ctrl &FLOW_CTRL_RX ) { + val |=0x20 ; + } + wb_write[0 ] = val; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_RX_CONTROL , wb_write,2 ); + +/* set rx mtu */ + wb_write[0 ] = bp->rx_buf_use_size; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_RX_MAX_SIZE , wb_write,2 ); + +/* set cnt max size */ + wb_write[0 ] = bp->rx_buf_use_size; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_CNT_MAX_SIZE , wb_write,2 ); + +/* configure safc */ + wb_write[0 ] =0x1000200 ; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_RX_LLFC_MSG_FLDS , + wb_write,2 ); + +/* fix for emulation */ +if (CHIP_REV (bp) ==CHIP_REV_EMUL ) { + wb_write[0 ] =0xf000 ; + wb_write[1 ] =0 ; +REG_WR_DMAE (bp,GRCBASE_NIG , + bmac_addr +BIGMAC_REGISTER_TX_PAUSE_THRESHOLD , + wb_write,2 ); + } + +/* reset old bmac stats */ +memset (&bp->old_bmac,0 ,sizeof (struct bmac_stats )); + +NIG_WR (NIG_REGISTERS_XCM0_OUT_EN + port*4 ,0x0 ); + +/* select XGXS */ +NIG_WR (NIG_REGISTERS_XGXS_SERDES0_MODE_SEL + port*4 ,0x1 ); +NIG_WR (NIG_REGISTERS_XGXS_LANE_SEL_P0 + port*4 ,0x0 ); + +/* disable the NIG in/out to the emac */ +NIG_WR (NIG_REGISTERS_EMAC0_IN_EN + port*4 ,0x0 ); +NIG_WR (NIG_REGISTERS_EMAC0_PAUSE_OUT_EN + port*4 ,0x0 ); +NIG_WR (NIG_REGISTERS_EGRESS_EMAC0_OUT_EN + port*4 ,0x0 ); + +/* enable the NIG in/out to the bmac */ +NIG_WR (NIG_REGISTERS_EGRESS_EMAC0_PORT + port*4 ,0x0 ); + +NIG_WR (NIG_REGISTERS_BMAC0_IN_EN + port*4 ,0x1 ); + val =0 ; +if (bp->flow_ctrl &FLOW_CTRL_TX ) { + val =1 ; + } +NIG_WR (NIG_REGISTERS_BMAC0_PAUSE_OUT_EN + port*4 , val); +NIG_WR (NIG_REGISTERS_BMAC0_OUT_EN + port*4 ,0x1 ); + + bp->phy_flags |=PHY_BMAC_FLAG ; + + bp->stats_state =STATS_STATE_ENABLE ; +} + +static void bnx2x_emac_enable (struct bnx2x *bp) +{ +u32 val; +int port = bp->port; +u32 emac_base = port ?GRCBASE_EMAC1 :GRCBASE_EMAC0 ; +int timeout =200 ; + +DP (NETIF_MSG_LINK ,"enableing EMAC\n" ); +/* reset and unreset the emac core */ +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_2_CLEAR , + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); +mdelay (5 ); +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_2_SET , + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + +/* enable emac and not bmac */ +NIG_WR (NIG_REGISTERS_EGRESS_EMAC0_PORT + port*4 ,1 ); + +/* for paladium */ +if (CHIP_REV (bp) ==CHIP_REV_EMUL ) { +/* Use lane 1 (of lanes 0-3) */ +NIG_WR (NIG_REGISTERS_XGXS_LANE_SEL_P0 + port*4 ,1 ); +NIG_WR (NIG_REGISTERS_XGXS_SERDES0_MODE_SEL + port*4 ,1 ); + } +/* for fpga */ +else if (CHIP_REV (bp) ==CHIP_REV_FPGA ) { +/* Use lane 1 (of lanes 0-3) */ +NIG_WR (NIG_REGISTERS_XGXS_LANE_SEL_P0 + port*4 ,1 ); +NIG_WR (NIG_REGISTERS_XGXS_SERDES0_MODE_SEL + port*4 ,0 ); + } +/* ASIC */ +else { +if (bp->phy_flags &PHY_XGXS_FLAG ) { +DP (NETIF_MSG_LINK ,"XGXS\n" ); +/* select the master lanes (out of 0-3) */ +NIG_WR (NIG_REGISTERS_XGXS_LANE_SEL_P0 + port*4 , + bp->ser_lane); +/* select XGXS */ +NIG_WR (NIG_REGISTERS_XGXS_SERDES0_MODE_SEL + port*4 , +1 ); + + }else {/* SerDes */ +DP (NETIF_MSG_LINK ,"SerDes\n" ); +/* select SerDes */ +NIG_WR (NIG_REGISTERS_XGXS_SERDES0_MODE_SEL + port*4 , +0 ); + } + } + +/* enable emac */ +NIG_WR (NIG_REGISTERS_NIG_EMAC0_EN + port*4 ,1 ); + +/* init emac - use read-modify-write */ +/* self clear reset */ + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MODE ); +EMAC_WR (EMAC_REG_EMAC_MODE , (val |EMAC_MODE_RESET )); + +while (val &EMAC_MODE_RESET ) { + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MODE ); +DP (NETIF_MSG_LINK ,"EMAC reset reg is %u\n" , val); +if (!timeout) { +BNX2X_ERR ("EMAC timeout!\n" ); +break ; + } + timeout--; + } + +/* reset tx part */ +EMAC_WR (EMAC_REG_EMAC_TX_MODE ,EMAC_TX_MODE_RESET ); + +while (val &EMAC_TX_MODE_RESET ) { + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_TX_MODE ); +DP (NETIF_MSG_LINK ,"EMAC reset reg is %u\n" , val); +if (!timeout) { +BNX2X_ERR ("EMAC timeout!\n" ); +break ; + } + timeout--; + } + +if (CHIP_REV_IS_SLOW (bp)) { +/* config GMII mode */ + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MODE ); +EMAC_WR (EMAC_REG_EMAC_MODE , (val |EMAC_MODE_PORT_GMII )); + + }else {/* ASIC */ +/* pause enable/disable */ +bnx2x_bits_dis (bp, emac_base,EMAC_REG_EMAC_RX_MODE , +EMAC_RX_MODE_FLOW_EN ); +if (bp->flow_ctrl &FLOW_CTRL_RX ) { +bnx2x_bits_en (bp, emac_base,EMAC_REG_EMAC_RX_MODE , +EMAC_RX_MODE_FLOW_EN ); + } + +bnx2x_bits_dis (bp, emac_base,EMAC_REG_EMAC_TX_MODE , +EMAC_TX_MODE_EXT_PAUSE_EN ); +if (bp->flow_ctrl &FLOW_CTRL_TX ) { +bnx2x_bits_en (bp, emac_base,EMAC_REG_EMAC_TX_MODE , +EMAC_TX_MODE_EXT_PAUSE_EN ); + } + } + +/* KEEP_VLAN_TAG, promiscous */ + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_RX_MODE ); + val |=EMAC_RX_MODE_KEEP_VLAN_TAG |EMAC_RX_MODE_PROMISCUOUS ; +EMAC_WR (EMAC_REG_EMAC_RX_MODE , val); + +/* identify magic packets */ + val =REG_RD (bp, emac_base,EMAC_REG_EMAC_MODE ); +EMAC_WR (EMAC_REG_EMAC_MODE , (val |EMAC_MODE_MPKT )); + +/* enable emac for jumbo packets */ +EMAC_WR (EMAC_REG_EMAC_RX_MTU_SIZE , + (EMAC_RX_MTU_SIZE_JUMBO_ENA | (bp->rx_buf_use_size))); + +/* strip CRC */ +NIG_WR (NIG_REGISTERS_NIG_INGRESS_EMAC0_NO_CRC + port*4 ,0x1 ); + + val = ((bp->dev->dev_addr[0 ] <<8 ) | + bp->dev->dev_addr[1 ]); +EMAC_WR (EMAC_REG_EMAC_MAC_MATCH , val); + + val = ((bp->dev->dev_addr[2 ] <<24 ) | + (bp->dev->dev_addr[3 ] <<16 ) | + (bp->dev->dev_addr[4 ] <<8 ) | + bp->dev->dev_addr[5 ]); +EMAC_WR (EMAC_REG_EMAC_MAC_MATCH +4 , val); + +/* disable the NIG in/out to the bmac */ +NIG_WR (NIG_REGISTERS_BMAC0_IN_EN + port*4 ,0x0 ); +NIG_WR (NIG_REGISTERS_BMAC0_PAUSE_OUT_EN + port*4 ,0x0 ); +NIG_WR (NIG_REGISTERS_BMAC0_OUT_EN + port*4 ,0x0 ); + +/* enable the NIG in/out to the emac */ +NIG_WR (NIG_REGISTERS_EMAC0_IN_EN + port*4 ,0x1 ); + val =0 ; +if (bp->flow_ctrl &FLOW_CTRL_TX ) { + val =1 ; + } +NIG_WR (NIG_REGISTERS_EMAC0_PAUSE_OUT_EN + port*4 , val); +NIG_WR (NIG_REGISTERS_EGRESS_EMAC0_OUT_EN + port*4 ,0x1 ); + +if (CHIP_REV (bp) ==CHIP_REV_FPGA ) { +/* take the BigMac out of reset */ +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_2_SET , + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + +/* enable access for bmac registers */ +NIG_WR (NIG_REGISTERS_BMAC0_REGS_OUT_EN + port*4 ,0x1 ); + } + + bp->phy_flags |=PHY_EMAC_FLAG ; + + bp->stats_state =STATS_STATE_ENABLE ; +} + +static void bnx2x_emac_program (struct bnx2x *bp) +{ +u16 mode =0 ; +int port = bp->port; + +DP (NETIF_MSG_LINK ,"setting link speed & duplex\n" ); +bnx2x_bits_dis (bp,GRCBASE_EMAC0 + port*0x400 ,EMAC_REG_EMAC_MODE , + (EMAC_MODE_25G_MODE | +EMAC_MODE_PORT_MII_10M | +EMAC_MODE_HALF_DUPLEX )); +switch (bp->line_speed) { +case SPEED_10 : + mode |=EMAC_MODE_PORT_MII_10M ; +break ; + +case SPEED_100 : + mode |=EMAC_MODE_PORT_MII ; +break ; + +case SPEED_1000 : + mode |=EMAC_MODE_PORT_GMII ; +break ; + +case SPEED_2500 : + mode |= (EMAC_MODE_25G_MODE |EMAC_MODE_PORT_GMII ); +break ; + +default : +/* 10G not valid for EMAC */ +BNX2X_ERR ("Invalid line_speed 0x%x\n" , bp->line_speed); +break ; + } + +if (bp->duplex ==DUPLEX_HALF ) { + mode |=EMAC_MODE_HALF_DUPLEX ; + } +bnx2x_bits_en (bp,GRCBASE_EMAC0 + port*0x400 , +EMAC_REG_EMAC_MODE , mode); + +bnx2x_leds_set (bp, bp->line_speed); +} + +static void bnx2x_set_sgmii_tx_driver (struct bnx2x *bp) +{ +u32 lp_up2; +u32 tx_driver; + +/* read precomp */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_OVER_1G ); +bnx2x_mdio22_read (bp,MDIO_OVER_1G_LP_UP2 , &lp_up2); + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_TX0 ); +bnx2x_mdio22_read (bp,MDIO_TX0_TX_DRIVER , &tx_driver); + +/* bits [10:7] at lp_up2, positioned at [15:12] */ + lp_up2 = (((lp_up2 &MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK ) >> +MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT ) << +MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT ); + +if ((lp_up2 !=0 ) && + (lp_up2 != (tx_driver &MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK ))) { +/* replace tx_driver bits [15:12] */ + tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK ; + tx_driver |= lp_up2; +bnx2x_mdio22_write (bp,MDIO_TX0_TX_DRIVER , tx_driver); + } +} + +static void bnx2x_pbf_update (struct bnx2x *bp) +{ +int port = bp->port; +u32 init_crd, crd; +u32 count =1000 ; +u32 pause =0 ; + +/* disable port */ +REG_WR (bp,GRCBASE_PBF , +PBF_REGISTERS_DISABLE_NEW_TASK_PROC_P0 + port*4 ,0x1 ); + +/* wait for init credit */ + init_crd =REG_RD (bp,GRCBASE_PBF , +PBF_REGISTERS_P0_INIT_CRD + port*4 ); + crd =REG_RD (bp,GRCBASE_PBF ,PBF_REGISTERS_P0_CREDIT + port*8 ); +DP (NETIF_MSG_LINK ,"init_crd 0x%x crd 0x%x\n" , init_crd, crd); + +while ((init_crd != crd) && count) { +mdelay (5 ); + + crd =REG_RD (bp,GRCBASE_PBF , +PBF_REGISTERS_P0_CREDIT + port*8 ); + count--; + } + crd =REG_RD (bp,GRCBASE_PBF ,PBF_REGISTERS_P0_CREDIT + port*8 ); +if (init_crd != crd) { +/* TBD? Assert if still init_crd != crd */ +BNX2X_ERR ("BUG! init_crd 0x%x != crd 0x%x\n" , init_crd, crd); + } + +if (bp->flow_ctrl &FLOW_CTRL_RX ) { + pause =1 ; + } +REG_WR (bp,GRCBASE_PBF , +PBF_REGISTERS_P0_PAUSE_ENABLE + port*4 , pause); +if (pause) { +/* update threshold */ +REG_WR (bp,GRCBASE_PBF , +PBF_REGISTERS_P0_ARB_THRSH + port*4 ,0 ); +/* update init credit */ + init_crd =778 ;/* (800-18-4) */ + + }else { +/* update threshold */ +REG_WR (bp,GRCBASE_PBF , +PBF_REGISTERS_P0_ARB_THRSH + port*4 , + bp->rx_buf_use_size/16 ); +/* update init credit */ +switch (bp->line_speed) { +case SPEED_10 : +case SPEED_100 : +case SPEED_1000 : + init_crd = bp->rx_buf_use_size/16 +55 -22 ; +break ; + +case SPEED_2500 : + init_crd = bp->rx_buf_use_size/16 +138 -22 ; +break ; + +case SPEED_10000 : + init_crd = bp->rx_buf_use_size/16 +553 -22 ; +break ; + +default : +BNX2X_ERR ("Invalid line_speed 0x%x\n" , + bp->line_speed); +break ; + } + } +REG_WR (bp,GRCBASE_PBF ,PBF_REGISTERS_P0_INIT_CRD + port*4 , init_crd); +DP (NETIF_MSG_LINK ,"PBF updated to speed %d credit %d\n" , + bp->line_speed, init_crd); + +/* probe the credit changes */ +REG_WR (bp,GRCBASE_PBF ,PBF_REGISTERS_INIT_P0 + port*4 ,0x1 ); +mdelay (5 ); +REG_WR (bp,GRCBASE_PBF ,PBF_REGISTERS_INIT_P0 + port*4 ,0x0 ); + +/* enable port */ +REG_WR (bp,GRCBASE_PBF , +PBF_REGISTERS_DISABLE_NEW_TASK_PROC_P0 + port*4 ,0x0 ); +} + +static void bnx2x_update_mng (struct bnx2x *bp) +{ +if (!nomcp) { +SHMEM_WR (bp, drv_fw_mb[bp->port].link_status, + bp->link_status); + } +} + +static void bnx2x_link_report (struct bnx2x *bp) +{ +if (bp->link_up) { +netif_carrier_on (bp->dev); + printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name); + +printk ("%d Mbps " , bp->line_speed); + +if (bp->duplex ==DUPLEX_FULL ) +printk ("full duplex" ); +else +printk ("half duplex" ); + +if (bp->flow_ctrl) { +if (bp->flow_ctrl &FLOW_CTRL_RX ) { +printk (", receive " ); +if (bp->flow_ctrl &FLOW_CTRL_TX ) +printk ("& transmit " ); + }else { +printk (", transmit " ); + } +printk ("flow control ON" ); + } +printk ("\n" ); + + }else {/* link_down */ +netif_carrier_off (bp->dev); + printk(KERN_INFO PFX "%s NIC Link is Down\n", bp->dev->name); + } +} + +static void bnx2x_link_up (struct bnx2x *bp) +{ +int port = bp->port; + +/* PBF - link up */ +bnx2x_pbf_update (bp); + +/* disable drain */ +NIG_WR (NIG_REGISTERS_EGRESS_DRAIN0_MODE + port*4 ,0 ); + +/* update share memory */ +bnx2x_update_mng (bp); + +/* indicate link up */ +bnx2x_link_report (bp); +} + +static void bnx2x_link_down (struct bnx2x *bp) +{ +int port = bp->port; + +/* notify stats */ +if (bp->stats_state !=STATS_STATE_DISABLE ) { + bp->stats_state =STATS_STATE_STOP ; +DP (BNX2X_MSG_STATS ,"stats_state - STOP\n" ); + } + +/* indicate link down */ + bp->phy_flags &= ~(PHY_BMAC_FLAG |PHY_EMAC_FLAG ); + +/* reset BigMac */ +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_2_CLEAR , + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + +/* ignore drain flag interrupt */ +/* activate nig drain */ +NIG_WR (NIG_REGISTERS_EGRESS_DRAIN0_MODE + port*4 ,1 ); + +/* update share memory */ +bnx2x_update_mng (bp); + +/* indicate link down */ +bnx2x_link_report (bp); +} + +/* This function is called upon link interrupt */ +static void bnx2x_link_update (struct bnx2x *bp) +{ +u32 gp_status; +int port = bp->port; +int i; +int link_10g; + +DP (NETIF_MSG_LINK ,"port %x, is xgxs %x, stat_mask 0x%x, " +"int_mask 0x%x, saved_mask 0x%x, MI_INT %x, SERDES_LINK %x," +" 10G %x, XGXS_LINK %x\n" , + port, (bp->phy_flags &PHY_XGXS_FLAG ), +REG_RD (bp,GRCBASE_NIG , +NIG_REGISTERS_STATUS_INTERRUPT_PORT0 + port*4 ), +REG_RD (bp,GRCBASE_NIG , +NIG_REGISTERS_MASK_INTERRUPT_PORT0 + port*4 ), + bp->nig_mask, +REG_RD (bp,GRCBASE_NIG , +NIG_REGISTERS_EMAC0_STATUS_MISC_MI_INT + port*0x18 ), +REG_RD (bp,GRCBASE_NIG , +NIG_REGISTERS_SERDES0_STATUS_LINK_STATUS + port*0x3c ), +REG_RD (bp,GRCBASE_NIG , +NIG_REGISTERS_XGXS0_STATUS_LINK10G + port*0x68 ), +REG_RD (bp,GRCBASE_NIG , +NIG_REGISTERS_XGXS0_STATUS_LINK_STATUS + port*0x68 ) + ); + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_GP_STATUS ); +/* avoid fast toggling */ +for (i =0 ; i <10 ; i++) { +mdelay (10 ); +bnx2x_mdio22_read (bp,MDIO_GP_STATUS_TOP_AN_STATUS1 , + &gp_status); + } + +bnx2x_link_settings_status (bp, gp_status); + +/* anything 10 and over uses the bmac */ + link_10g = ((bp->line_speed >=SPEED_10000 ) && + (bp->line_speed <=SPEED_16000 )); + +bnx2x_link_int_ack (bp, link_10g); + +/* link is up only if both local phy and external phy are up */ +if (bp->link_up &&bnx2x_ext_phy_is_link_up (bp)) { +if (link_10g) { +bnx2x_bmac_enable (bp,0 ); +bnx2x_leds_set (bp,SPEED_10000 ); + + }else { +bnx2x_emac_enable (bp); +bnx2x_emac_program (bp); + +/* AN complete? */ +if (gp_status &MDIO_AN_CL73_OR_37_COMPLETE ) { +if (!(bp->phy_flags &PHY_SGMII_FLAG )) { +bnx2x_set_sgmii_tx_driver (bp); + }/* Not SGMII */ + } + } +bnx2x_link_up (bp); + + }else {/* link down */ +bnx2x_leds_unset (bp); +bnx2x_link_down (bp); + } +} + +/**************************************************************************** +* Init service functions +****************************************************************************/ + +static void bnx2x_set_aer_mmd (struct bnx2x *bp) +{ +u16 offset = (bp->phy_flags &PHY_XGXS_FLAG ) ? + (bp->phy_addr + bp->ser_lane) :0 ; + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_AER_BLOCK ); +bnx2x_mdio22_write (bp,MDIO_AER_BLOCK_AER_REG ,0x3800 + offset); +} + +static void bnx2x_set_master_ln (struct bnx2x *bp) +{ +u32 new_master_ln; + +/* set the master_ln for AN */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_XGXS_BLOCK2 ); +bnx2x_mdio22_read (bp,MDIO_XGXS_BLOCK2_TEST_MODE_LANE , + &new_master_ln); +bnx2x_mdio22_write (bp,MDIO_XGXS_BLOCK2_TEST_MODE_LANE , + (new_master_ln | bp->ser_lane)); +} + +static void bnx2x_reset_unicore (struct bnx2x *bp) +{ +u32 mii_control; +int i; + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_read (bp,MDIO_COMBO_IEEE0_MII_CONTROL , &mii_control); +/* reset the unicore */ +bnx2x_mdio22_write (bp,MDIO_COMBO_IEEE0_MII_CONTROL , + (mii_control |MDIO_COMBO_IEEO_MII_CONTROL_RESET )); + +/* wait for the reset to self clear */ +for (i =0 ; i <MDIO_ACCESS_TIMEOUT ; i++) { +udelay (5 ); + +/* the reset erased the previous bank value */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_read (bp,MDIO_COMBO_IEEE0_MII_CONTROL , + &mii_control); + +if (!(mii_control &MDIO_COMBO_IEEO_MII_CONTROL_RESET )) { +udelay (5 ); +return ; + } + } + +/* TBD? Assert if the control is still in reset */ +BNX2X_ERR ("BUG! unicore is still in reset!\n" ); +} + +static void bnx2x_set_swap_lanes (struct bnx2x *bp) +{ +/* Each two bits represents a lane number: +No swap is 0123 => 0x1b no need to enable the swap */ + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_XGXS_BLOCK2 ); +if (bp->rx_lane_swap !=0x1b ) { +bnx2x_mdio22_write (bp,MDIO_XGXS_BLOCK2_RX_LN_SWAP , + (bp->rx_lane_swap | +MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE | +MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE )); + }else { +bnx2x_mdio22_write (bp,MDIO_XGXS_BLOCK2_RX_LN_SWAP ,0 ); + } + +if (bp->tx_lane_swap !=0x1b ) { +bnx2x_mdio22_write (bp,MDIO_XGXS_BLOCK2_TX_LN_SWAP , + (bp->tx_lane_swap | +MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE )); + }else { +bnx2x_mdio22_write (bp,MDIO_XGXS_BLOCK2_TX_LN_SWAP ,0 ); + } +} + +static void bnx2x_set_parallel_detection (struct bnx2x *bp) +{ +u32 control2; + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_SERDES_DIGITAL ); +bnx2x_mdio22_read (bp,MDIO_SERDES_DIGITAL_A_1000X_CONTROL2 , + &control2); + +if (bp->autoneg &AUTONEG_PARALLEL ) { + control2 |=MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN ; + }else { + control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN ; + } +bnx2x_mdio22_write (bp,MDIO_SERDES_DIGITAL_A_1000X_CONTROL2 , + control2); + +if (bp->phy_flags &PHY_XGXS_FLAG ) { +DP (NETIF_MSG_LINK ,"XGXS\n" ); +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_10G_PARALLEL_DETECT ); + +bnx2x_mdio22_write (bp, +MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK , +MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT ); + +bnx2x_mdio22_read (bp, +MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL , + &control2); + +if (bp->autoneg &AUTONEG_PARALLEL ) { + control2 |= +MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN ; + }else { + control2 &= + ~MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN ; + } +bnx2x_mdio22_write (bp, +MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL , + control2); + } +} + +static void bnx2x_set_autoneg (struct bnx2x *bp) +{ +u32 reg_val; + +/* CL37 Autoneg */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_read (bp,MDIO_COMBO_IEEE0_MII_CONTROL , ®_val); +if ((bp->req_autoneg &AUTONEG_SPEED ) && + (bp->autoneg &AUTONEG_CL37 )) { +/* CL37 Autoneg Enabled */ + reg_val |=MDIO_COMBO_IEEO_MII_CONTROL_AN_EN ; + }else { +/* CL37 Autoneg Disabled */ + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | +MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN ); + } +bnx2x_mdio22_write (bp,MDIO_COMBO_IEEE0_MII_CONTROL , reg_val); + +/* Enable/Disable Autodetection */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_SERDES_DIGITAL ); +bnx2x_mdio22_read (bp,MDIO_SERDES_DIGITAL_A_1000X_CONTROL1 , ®_val); + reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN ; + +if ((bp->req_autoneg &AUTONEG_SPEED ) && + (bp->autoneg &AUTONEG_SGMII_FIBER_AUTODET )) { + reg_val |=MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET ; + }else { + reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET ; + } +bnx2x_mdio22_write (bp,MDIO_SERDES_DIGITAL_A_1000X_CONTROL1 , reg_val); + +/* Enable TetonII and BAM autoneg */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_BAM_NEXT_PAGE ); +bnx2x_mdio22_read (bp,MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL , + ®_val); +if ((bp->req_autoneg &AUTONEG_SPEED ) && + (bp->autoneg &AUTONEG_CL37 ) && (bp->autoneg &AUTONEG_BAM )) { +/* Enable BAM aneg Mode and TetonII aneg Mode */ + reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | +MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN ); + }else { +/* TetonII and BAM Autoneg Disabled */ + reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | +MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN ); + } +bnx2x_mdio22_write (bp,MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL , + reg_val); + +/* Enable Clause 73 Aneg */ +if ((bp->req_autoneg &AUTONEG_SPEED ) && + (bp->autoneg &AUTONEG_CL73 )) { +/* Enable BAM Station Manager */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_CL73_USERB0 ); +bnx2x_mdio22_write (bp,MDIO_CL73_USERB0_CL73_BAM_CTRL1 , + (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | +MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | +MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN )); + +/* Merge CL73 and CL37 aneg resolution */ +bnx2x_mdio22_read (bp,MDIO_CL73_USERB0_CL73_BAM_CTRL3 , + ®_val); +bnx2x_mdio22_write (bp,MDIO_CL73_USERB0_CL73_BAM_CTRL3 , + (reg_val | +MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR )); + +/* Set the CL73 AN speed */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_CL73_IEEEB1 ); +bnx2x_mdio22_read (bp,MDIO_CL73_IEEEB1_AN_ADV2 , ®_val); +/* In the SerDes we support only the 1G. +In the XGXS we support the 10G KX4 +but we currently do not support the KR */ +if (bp->phy_flags &PHY_XGXS_FLAG ) { +DP (NETIF_MSG_LINK ,"XGXS\n" ); +/* 10G KX4 */ + reg_val |=MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 ; + }else { +DP (NETIF_MSG_LINK ,"SerDes\n" ); +/* 1000M KX */ + reg_val |=MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX ; + } +bnx2x_mdio22_write (bp,MDIO_CL73_IEEEB1_AN_ADV2 , reg_val); + +/* CL73 Autoneg Enabled */ + reg_val =MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN ; + }else { +/* CL73 Autoneg Disabled */ + reg_val =0 ; + } +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_CL73_IEEEB0 ); +bnx2x_mdio22_write (bp,MDIO_CL73_IEEEB0_CL73_AN_CONTROL , reg_val); +} + +/* program SerDes, forced modes */ +static void bnx2x_program_serdes (struct bnx2x *bp) +{ +u32 reg_val; + +/* program duplex, disable autoneg */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_read (bp,MDIO_COMBO_IEEE0_MII_CONTROL , ®_val); + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | +MDIO_COMBO_IEEO_MII_CONTROL_AN_EN ); +if (bp->req_duplex ==DUPLEX_FULL ) { + reg_val |=MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX ; + } +bnx2x_mdio22_write (bp,MDIO_COMBO_IEEE0_MII_CONTROL , reg_val); + +/* program speed +- needed only if the speed is greater than 1G (2.5G or 10G) */ +if (bp->req_line_speed >SPEED_1000 ) { +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_SERDES_DIGITAL ); +bnx2x_mdio22_read (bp,MDIO_SERDES_DIGITAL_MISC1 , ®_val); +/* clearing the speed value before setting the right speed */ + reg_val &= ~MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK ; + reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M | +MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL ); +if (bp->req_line_speed ==SPEED_10000 ) { + reg_val |= +MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4 ; + } +bnx2x_mdio22_write (bp,MDIO_SERDES_DIGITAL_MISC1 , reg_val); + } +} + +static void bnx2x_set_brcm_cl37_advertisment (struct bnx2x *bp) +{ +u32 val =0 ; + +/* configure the 48 bits for BAM AN */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_OVER_1G ); + +/* set extended capabilities */ +if (bp->advertising & ADVERTISED_2500baseT_Full) { + val |=MDIO_OVER_1G_UP1_2_5G ; + } +if (bp->advertising & ADVERTISED_10000baseT_Full) { + val |=MDIO_OVER_1G_UP1_10G ; + } +bnx2x_mdio22_write (bp,MDIO_OVER_1G_UP1 , val); + +bnx2x_mdio22_write (bp,MDIO_OVER_1G_UP3 ,0 ); +} + +static void bnx2x_set_ieee_aneg_advertisment (struct bnx2x *bp) +{ +u32 an_adv; + +/* for AN, we are always publishing full duplex */ + an_adv =MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX ; + +/* set pause */ +switch (bp->pause_mode) { +case PAUSE_SYMMETRIC : + an_adv |=MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC ; +break ; +case PAUSE_ASYMMETRIC : + an_adv |=MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC ; +break ; +case PAUSE_BOTH : + an_adv |=MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH ; +break ; +case PAUSE_NONE : + an_adv |=MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE ; +break ; + } + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_write (bp,MDIO_COMBO_IEEE0_AUTO_NEG_ADV , an_adv); +} + +static void bnx2x_restart_autoneg (struct bnx2x *bp) +{ +if (bp->autoneg &AUTONEG_CL73 ) { +/* enable and restart clause 73 aneg */ +u32 an_ctrl; + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_CL73_IEEEB0 ); +bnx2x_mdio22_read (bp,MDIO_CL73_IEEEB0_CL73_AN_CONTROL , + &an_ctrl); +bnx2x_mdio22_write (bp,MDIO_CL73_IEEEB0_CL73_AN_CONTROL , + (an_ctrl | +MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | +MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN )); + + }else { +/* Enable and restart BAM/CL37 aneg */ +u32 mii_control; + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_read (bp,MDIO_COMBO_IEEE0_MII_CONTROL , + &mii_control); +bnx2x_mdio22_write (bp,MDIO_COMBO_IEEE0_MII_CONTROL , + (mii_control | +MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | +MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN )); + } +} + +static void bnx2x_initialize_sgmii_process (struct bnx2x *bp) +{ +u32 control1; + +/* in SGMII mode, the unicore is always slave */ +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_SERDES_DIGITAL ); +bnx2x_mdio22_read (bp,MDIO_SERDES_DIGITAL_A_1000X_CONTROL1 , + &control1); + control1 |=MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT ; +/* set sgmii mode (and not fiber) */ + control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE | +MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET | +MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE ); +bnx2x_mdio22_write (bp,MDIO_SERDES_DIGITAL_A_1000X_CONTROL1 , + control1); + +/* if forced mode */ +if (!(bp->req_autoneg &AUTONEG_SPEED )) { +/* set speed, disable autoneg */ +u32 mii_control; + +MDIO_SET_REG_BANK (bp,MDIO_REG_BANK_COMBO_IEEE0 ); +bnx2x_mdio22_read (bp,MDIO_COMBO_IEEE0_MII_CONTROL , + &mii_control); + mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | +MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK | +MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX ); + +switch (bp->req_line_speed) { +case SPEED_100 : + mii_control |= +MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100 ; +break ; +case SPEED_1000 : + mii_control |= +MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000 ; +break ; +case SPEED_10 : +/* there is nothing to set for 10M */ +break ; +default : +/* invalid speed for SGMII */ +DP (NETIF_MSG_LINK ,"Invalid req_line_speed 0x%x\n" , + bp->req_line_speed); +break ; + } + +/* setting the full duplex */ +if (bp->req_duplex ==DUPLEX_FULL ) { + mii_control |= +MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX ; + } +bnx2x_mdio22_write (bp,MDIO_COMBO_IEEE0_MII_CONTROL , + mii_control); + + }else {/* AN mode */ +/* enable and restart AN */ +bnx2x_restart_autoneg (bp); + } +} + +static void bnx2x_link_int_enable (struct bnx2x *bp) +{ +int port = bp->port; + +/* setting the status to report on link up +for either XGXS or SerDes */ +bnx2x_bits_dis (bp,GRCBASE_NIG , +NIG_REGISTERS_STATUS_INTERRUPT_PORT0 + port*4 , + (NIG_XGXS0_LINK_STATUS | +NIG_STATUS_INTERRUPT_XGXS0_LINK10G | +NIG_SERDES0_LINK_STATUS )); + +if (bp->phy_flags &PHY_XGXS_FLAG ) { +/* TBD - +* in force mode (not AN) we can enable just the relevant +* interrupt +* Even in AN we might enable only one according to the AN +* speed mask +*/ +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_MASK_INTERRUPT_PORT0 + port*4 , + (NIG_MASK_XGXS0_LINK_STATUS | +NIG_MASK_XGXS0_LINK10G )); +DP (NETIF_MSG_LINK ,"enable XGXS interrupt\n" ); + + }else {/* SerDes */ +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_MASK_INTERRUPT_PORT0 + port*4 , +NIG_MASK_SERDES0_LINK_STATUS ); +DP (NETIF_MSG_LINK ,"enable SerDes interrupt\n" ); + } +} + +static void bnx2x_ext_phy_init (struct bnx2x *bp) +{ +int port = bp->port; +u32 ext_phy_type; +u32 ext_phy_addr; +u32 local_phy; + +if (bp->phy_flags &PHY_XGXS_FLAG ) { + local_phy = bp->phy_addr; + ext_phy_addr = ((bp->ext_phy_config & +PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK ) >> +PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT ); + + ext_phy_type =XGXS_EXT_PHY_TYPE (bp); +switch (ext_phy_type) { +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT : +DP (NETIF_MSG_LINK ,"XGXS Direct\n" ); +break ; + +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705 : +DP (NETIF_MSG_LINK ,"XGXS 8705\n" ); +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_MASK_INTERRUPT_PORT0 + + port*4 ,NIG_MASK_MI_INT ); +DP (NETIF_MSG_LINK ,"enabled extenal phy int\n" ); + + bp->phy_addr = ext_phy_type; +bnx2x_mdio45_vwrite (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_PMD_MISC_CNTL , +0x8288 ); +bnx2x_mdio45_vwrite (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_PHY_IDENTIFIER , +0x7fbf ); +bnx2x_mdio45_vwrite (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_CMU_PLL_BYPASS , +0x0100 ); +bnx2x_mdio45_vwrite (bp,EXT_PHY_OPT_WIS_DEVAD , +EXT_PHY_OPT_LASI_CNTL ,0x1 ); +break ; + +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 : +DP (NETIF_MSG_LINK ,"XGXS 8706\n" ); +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_MASK_INTERRUPT_PORT0 + + port*4 ,NIG_MASK_MI_INT ); +DP (NETIF_MSG_LINK ,"enabled extenal phy int\n" ); + + bp->phy_addr = ext_phy_type; +bnx2x_mdio45_vwrite (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_PMD_DIGITAL_CNT , +0x400 ); +bnx2x_mdio45_vwrite (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_LASI_CNTL ,0x1 ); +break ; + +default : +DP (NETIF_MSG_LINK ,"BAD XGXS ext_phy_config 0x%x\n" , + bp->ext_phy_config); +break ; + } + bp->phy_addr = local_phy; + + }else {/* SerDes */ +/* ext_phy_addr = ((bp->ext_phy_config & +PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >> +PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT); +*/ + ext_phy_type =SERDES_EXT_PHY_TYPE (bp); +switch (ext_phy_type) { +case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT : +DP (NETIF_MSG_LINK ,"SerDes Direct\n" ); +break ; + +case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482 : +DP (NETIF_MSG_LINK ,"SerDes 5482\n" ); +bnx2x_bits_en (bp,GRCBASE_NIG , +NIG_REGISTERS_MASK_INTERRUPT_PORT0 + + port*4 ,NIG_MASK_MI_INT ); +DP (NETIF_MSG_LINK ,"enabled extenal phy int\n" ); +break ; + +default : +DP (NETIF_MSG_LINK ,"BAD SerDes ext_phy_config 0x%x\n" , + bp->ext_phy_config); +break ; + } + } +} + +static void bnx2x_ext_phy_reset (struct bnx2x *bp) +{ +u32 ext_phy_type; +u32 ext_phy_addr; +u32 local_phy; + +if (bp->phy_flags &PHY_XGXS_FLAG ) { + ext_phy_type =XGXS_EXT_PHY_TYPE (bp); +switch (ext_phy_type) { +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT : +DP (NETIF_MSG_LINK ,"XGXS Direct\n" ); +break ; + +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705 : +case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 : +DP (NETIF_MSG_LINK ,"XGXS 8705/6\n" ); + local_phy = bp->phy_addr; + ext_phy_addr = ((bp->ext_phy_config & +PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK ) >> +PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT ); + bp->phy_addr = (u8 )ext_phy_addr; +bnx2x_mdio45_write (bp,EXT_PHY_OPT_PMA_PMD_DEVAD , +EXT_PHY_OPT_CNTL ,0xa040 ); + bp->phy_addr = local_phy; +break ; + +default : +DP (NETIF_MSG_LINK ,"BAD XGXS ext_phy_config 0x%x\n" , + bp->ext_phy_config); +break ; + } + + }else {/* SerDes */ + ext_phy_type =SERDES_EXT_PHY_TYPE (bp); +switch (ext_phy_type) { +case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT : +DP (NETIF_MSG_LINK ,"SerDes Direct\n" ); +break ; + +case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482 : +DP (NETIF_MSG_LINK ,"SerDes 5482\n" ); +break ; + +default : +DP (NETIF_MSG_LINK ,"BAD SerDes ext_phy_config 0x%x\n" , + bp->ext_phy_config); +break ; + } + } +} + +static void bnx2x_link_initialize (struct bnx2x *bp) +{ +int port = bp->port; + +/* disable attentions */ +bnx2x_bits_dis (bp,GRCBASE_NIG , +NIG_REGISTERS_MASK_INTERRUPT_PORT0 + port*4 , + (NIG_MASK_XGXS0_LINK_STATUS | +NIG_MASK_XGXS0_LINK10G | +NIG_MASK_SERDES0_LINK_STATUS | +NIG_MASK_MI_INT )); + +bnx2x_ext_phy_reset (bp); + +bnx2x_set_aer_mmd (bp); + +if (bp->phy_flags &PHY_XGXS_FLAG ) { +bnx2x_set_master_ln (bp); + } + +/* reset the SerDes and wait for reset bit return low */ +bnx2x_reset_unicore (bp); + +bnx2x_set_aer_mmd (bp); + +/* setting the masterLn_def again after the reset */ +if (bp->phy_flags &PHY_XGXS_FLAG ) { +bnx2x_set_master_ln (bp); +bnx2x_set_swap_lanes (bp); + } + +/* Set Parallel Detect */ +if (bp->req_autoneg &AUTONEG_SPEED ) { +bnx2x_set_parallel_detection (bp); + } + +if (bp->phy_flags &PHY_XGXS_FLAG ) { +if (bp->req_line_speed && + bp->req_line_speed <SPEED_1000 ) { + bp->phy_flags |=PHY_SGMII_FLAG ; + }else { + bp->phy_flags &= ~PHY_SGMII_FLAG ; + } + } + +if (!(bp->phy_flags &PHY_SGMII_FLAG )) { +u16 bank, rx_eq; + + rx_eq = ((bp->serdes_config & +PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK ) >> +PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT ); + +DP (NETIF_MSG_LINK ,"setting rx eq to %d\n" , rx_eq); +for (bank =MDIO_REG_BANK_RX0 ; bank <=MDIO_REG_BANK_RX_ALL ; + bank += (MDIO_REG_BANK_RX1 -MDIO_REG_BANK_RX0 )) { +MDIO_SET_REG_BANK (bp, bank); +bnx2x_mdio22_write (bp,MDIO_RX0_RX_EQ_BOOST , + ((rx_eq & +MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK ) | +MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL )); + } + +/* forced speed requested? */ +if (!(bp->req_autoneg &AUTONEG_SPEED )) { +DP (NETIF_MSG_LINK ,"not SGMII, no AN\n" ); + +/* disable autoneg */ +bnx2x_set_autoneg (bp); + +/* program speed and duplex */ +bnx2x_program_serdes (bp); + + }else {/* AN_mode */ +DP (NETIF_MSG_LINK ,"not SGNII, AN\n" ); + +/* AN enabled */ +bnx2x_set_brcm_cl37_advertisment (bp); + +/* program duplex & pause advertisment (for aneg) */ +bnx2x_set_ieee_aneg_advertisment (bp); + +/* enable autoneg */ +bnx2x_set_autoneg (bp); + +/* enalbe and restart AN */ +bnx2x_restart_autoneg (bp); + } + + }else {/* SGMII mode */ +DP (NETIF_MSG_LINK ,"SGMII\n" ); + +bnx2x_initialize_sgmii_process (bp); + } + +/* enable the interrupt */ +bnx2x_link_int_enable (bp); + +/* init ext phy and enable link state int */ +bnx2x_ext_phy_init (bp); +} + +static void bnx2x_phy_deassert (struct bnx2x *bp) +{ +int port = bp->port; +u32 val; + +if (bp->phy_flags &PHY_XGXS_FLAG ) { +DP (NETIF_MSG_LINK ,"XGXS\n" ); + val =XGXS_RESET_BITS ; + + }else {/* SerDes */ +DP (NETIF_MSG_LINK ,"SerDes\n" ); + val =SERDES_RESET_BITS ; + } + + val = val << (port*16 ); + +/* reset and unreset the SerDes/XGXS */ +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_3_CLEAR , val); +msleep (5 ); +REG_WR (bp,GRCBASE_MISC ,MISC_REGISTERS_RESET_REG_3_SET , val); +} + +static int bnx2x_phy_init (struct bnx2x *bp)
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.4.2
Part of the diff is not shown here. View the raw message.