⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bnx2.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* bnx2.c: Broadcom NX2 network driver. * * Copyright (c) 2004-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: Michael Chan  (mchan@broadcom.com) */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#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 <asm/io.h>#include <asm/irq.h>#include <linux/delay.h>#include <asm/byteorder.h>#include <asm/page.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/cache.h>#include <linux/zlib.h>#include "bnx2.h"#include "bnx2_fw.h"#include "bnx2_fw2.h"#define FW_BUF_SIZE		0x8000#define DRV_MODULE_NAME		"bnx2"#define PFX DRV_MODULE_NAME	": "#define DRV_MODULE_VERSION	"1.6.9"#define DRV_MODULE_RELDATE	"December 8, 2007"#define RUN_AT(x) (jiffies + (x))/* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT  (5*HZ)static const char version[] __devinitdata =	"Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_MODULE_VERSION);static int disable_msi = 0;module_param(disable_msi, int, 0);MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");typedef enum {	BCM5706 = 0,	NC370T,	NC370I,	BCM5706S,	NC370F,	BCM5708,	BCM5708S,	BCM5709,	BCM5709S,} board_t;/* indexed by board_t, above */static const struct {	char *name;} board_info[] __devinitdata = {	{ "Broadcom NetXtreme II BCM5706 1000Base-T" },	{ "HP NC370T Multifunction Gigabit Server Adapter" },	{ "HP NC370i Multifunction Gigabit Server Adapter" },	{ "Broadcom NetXtreme II BCM5706 1000Base-SX" },	{ "HP NC370F Multifunction Gigabit Server Adapter" },	{ "Broadcom NetXtreme II BCM5708 1000Base-T" },	{ "Broadcom NetXtreme II BCM5708 1000Base-SX" },	{ "Broadcom NetXtreme II BCM5709 1000Base-T" },	{ "Broadcom NetXtreme II BCM5709 1000Base-SX" },	};static struct pci_device_id bnx2_pci_tbl[] = {	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,	  PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,	  PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,	  PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },	{ 0, }};static struct flash_spec flash_table[] ={#define BUFFERED_FLAGS		(BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)#define NONBUFFERED_FLAGS	(BNX2_NV_WREN)	/* Slow EEPROM */	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,	 "EEPROM - slow"},	/* Expansion entry 0001 */	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,	 "Entry 0001"},	/* Saifun SA25F010 (non-buffered flash) */	/* strap, cfg1, & write1 need updates */	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,	 "Non-buffered flash (128kB)"},	/* Saifun SA25F020 (non-buffered flash) */	/* strap, cfg1, & write1 need updates */	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,	 "Non-buffered flash (256kB)"},	/* Expansion entry 0100 */	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,	 "Entry 0100"},	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},	/* Entry 0110: ST M45PE20 (non-buffered flash)*/	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},	/* Saifun SA25F005 (non-buffered flash) */	/* strap, cfg1, & write1 need updates */	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,	 "Non-buffered flash (64kB)"},	/* Fast EEPROM */	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,	 "EEPROM - fast"},	/* Expansion entry 1001 */	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,	 "Entry 1001"},	/* Expansion entry 1010 */	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,	 "Entry 1010"},	/* ATMEL AT45DB011B (buffered flash) */	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,	 "Buffered flash (128kB)"},	/* Expansion entry 1100 */	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,	 "Entry 1100"},	/* Expansion entry 1101 */	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,	 "Entry 1101"},	/* Ateml Expansion entry 1110 */	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,	 "Entry 1110 (Atmel)"},	/* ATMEL AT45DB021B (buffered flash) */	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,	 "Buffered flash (256kB)"},};static struct flash_spec flash_5709 = {	.flags		= BNX2_NV_BUFFERED,	.page_bits	= BCM5709_FLASH_PAGE_BITS,	.page_size	= BCM5709_FLASH_PAGE_SIZE,	.addr_mask	= BCM5709_FLASH_BYTE_ADDR_MASK,	.total_size	= BUFFERED_FLASH_TOTAL_SIZE*2,	.name		= "5709 Buffered flash (256kB)",};MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);static inline u32 bnx2_tx_avail(struct bnx2 *bp){	u32 diff;	smp_mb();	/* The ring uses 256 indices for 255 entries, one of them	 * needs to be skipped.	 */	diff = bp->tx_prod - bp->tx_cons;	if (unlikely(diff >= TX_DESC_CNT)) {		diff &= 0xffff;		if (diff == TX_DESC_CNT)			diff = MAX_TX_DESC_CNT;	}	return (bp->tx_ring_size - diff);}static u32bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset){	u32 val;	spin_lock_bh(&bp->indirect_lock);	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);	val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);	spin_unlock_bh(&bp->indirect_lock);	return val;}static voidbnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val){	spin_lock_bh(&bp->indirect_lock);	REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);	REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);	spin_unlock_bh(&bp->indirect_lock);}static voidbnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val){	offset += cid_addr;	spin_lock_bh(&bp->indirect_lock);	if (CHIP_NUM(bp) == CHIP_NUM_5709) {		int i;		REG_WR(bp, BNX2_CTX_CTX_DATA, val);		REG_WR(bp, BNX2_CTX_CTX_CTRL,		       offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);		for (i = 0; i < 5; i++) {			u32 val;			val = REG_RD(bp, BNX2_CTX_CTX_CTRL);			if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)				break;			udelay(5);		}	} else {		REG_WR(bp, BNX2_CTX_DATA_ADR, offset);		REG_WR(bp, BNX2_CTX_DATA, val);	}	spin_unlock_bh(&bp->indirect_lock);}static intbnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val){	u32 val1;	int i, ret;	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);		REG_RD(bp, BNX2_EMAC_MDIO_MODE);		udelay(40);	}	val1 = (bp->phy_addr << 21) | (reg << 16) |		BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |		BNX2_EMAC_MDIO_COMM_START_BUSY;	REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);	for (i = 0; i < 50; i++) {		udelay(10);		val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {			udelay(5);			val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);			val1 &= BNX2_EMAC_MDIO_COMM_DATA;			break;		}	}	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {		*val = 0x0;		ret = -EBUSY;	}	else {		*val = val1;		ret = 0;	}	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);		REG_RD(bp, BNX2_EMAC_MDIO_MODE);		udelay(40);	}	return ret;}static intbnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val){	u32 val1;	int i, ret;	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);		REG_RD(bp, BNX2_EMAC_MDIO_MODE);		udelay(40);	}	val1 = (bp->phy_addr << 21) | (reg << 16) | val |		BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |		BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;	REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);	for (i = 0; i < 50; i++) {		udelay(10);		val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);		if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {			udelay(5);			break;		}	}	if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)        	ret = -EBUSY;	else		ret = 0;	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;		REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);		REG_RD(bp, BNX2_EMAC_MDIO_MODE);		udelay(40);	}	return ret;}static voidbnx2_disable_int(struct bnx2 *bp){	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT);	REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);}static voidbnx2_enable_int(struct bnx2 *bp){	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx);	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx);	REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);}static voidbnx2_disable_int_sync(struct bnx2 *bp){	atomic_inc(&bp->intr_sem);	bnx2_disable_int(bp);	synchronize_irq(bp->pdev->irq);}static voidbnx2_netif_stop(struct bnx2 *bp){	bnx2_disable_int_sync(bp);	if (netif_running(bp->dev)) {		napi_disable(&bp->napi);		netif_tx_disable(bp->dev);		bp->dev->trans_start = jiffies;	/* prevent tx timeout */	}}static voidbnx2_netif_start(struct bnx2 *bp){	if (atomic_dec_and_test(&bp->intr_sem)) {		if (netif_running(bp->dev)) {			netif_wake_queue(bp->dev);			napi_enable(&bp->napi);			bnx2_enable_int(bp);		}	}}static voidbnx2_free_mem(struct bnx2 *bp){	int i;	for (i = 0; i < bp->ctx_pages; i++) {		if (bp->ctx_blk[i]) {			pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,					    bp->ctx_blk[i],					    bp->ctx_blk_mapping[i]);			bp->ctx_blk[i] = NULL;		}	}	if (bp->status_blk) {		pci_free_consistent(bp->pdev, bp->status_stats_size,				    bp->status_blk, bp->status_blk_mapping);		bp->status_blk = NULL;		bp->stats_blk = NULL;	}	if (bp->tx_desc_ring) {		pci_free_consistent(bp->pdev,				    sizeof(struct tx_bd) * TX_DESC_CNT,				    bp->tx_desc_ring, bp->tx_desc_mapping);		bp->tx_desc_ring = NULL;	}	kfree(bp->tx_buf_ring);	bp->tx_buf_ring = NULL;	for (i = 0; i < bp->rx_max_ring; i++) {		if (bp->rx_desc_ring[i])			pci_free_consistent(bp->pdev,					    sizeof(struct rx_bd) * RX_DESC_CNT,					    bp->rx_desc_ring[i],					    bp->rx_desc_mapping[i]);		bp->rx_desc_ring[i] = NULL;	}	vfree(bp->rx_buf_ring);	bp->rx_buf_ring = NULL;}static intbnx2_alloc_mem(struct bnx2 *bp){	int i, status_blk_size;	bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT,				  GFP_KERNEL);	if (bp->tx_buf_ring == NULL)		return -ENOMEM;	bp->tx_desc_ring = pci_alloc_consistent(bp->pdev,					        sizeof(struct tx_bd) *						TX_DESC_CNT,						&bp->tx_desc_mapping);	if (bp->tx_desc_ring == NULL)		goto alloc_mem_err;	bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *				  bp->rx_max_ring);	if (bp->rx_buf_ring == NULL)		goto alloc_mem_err;	memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *				   bp->rx_max_ring);	for (i = 0; i < bp->rx_max_ring; i++) {		bp->rx_desc_ring[i] =			pci_alloc_consistent(bp->pdev,					     sizeof(struct rx_bd) * RX_DESC_CNT,					     &bp->rx_desc_mapping[i]);		if (bp->rx_desc_ring[i] == NULL)			goto alloc_mem_err;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -