qla3xxx.c

来自「linux 内核源代码」· C语言 代码 · 共 2,557 行 · 第 1/5 页

C
2,557
字号
/* * QLogic QLA3xxx NIC HBA Driver * Copyright (c)  2003-2006 QLogic Corporation * * See LICENSE.qla3xxx for copyright and licensing details. */#include <linux/kernel.h>#include <linux/init.h>#include <linux/types.h>#include <linux/module.h>#include <linux/list.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/dmapool.h>#include <linux/mempool.h>#include <linux/spinlock.h>#include <linux/kthread.h>#include <linux/interrupt.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/ip.h>#include <linux/in.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/skbuff.h>#include <linux/rtnetlink.h>#include <linux/if_vlan.h>#include <linux/delay.h>#include <linux/mm.h>#include "qla3xxx.h"#define DRV_NAME  	"qla3xxx"#define DRV_STRING 	"QLogic ISP3XXX Network Driver"#define DRV_VERSION	"v2.03.00-k4"#define PFX		DRV_NAME " "static const char ql3xxx_driver_name[] = DRV_NAME;static const char ql3xxx_driver_version[] = DRV_VERSION;MODULE_AUTHOR("QLogic Corporation");MODULE_DESCRIPTION("QLogic ISP3XXX Network Driver " DRV_VERSION " ");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);static const u32 default_msg    = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK    | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;static int debug = -1;		/* defaults above */module_param(debug, int, 0);MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");static int msi;module_param(msi, int, 0);MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},	{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},	/* required last entry */	{0,}};MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);/* *  These are the known PHY's which are used */typedef enum {   PHY_TYPE_UNKNOWN   = 0,   PHY_VITESSE_VSC8211,   PHY_AGERE_ET1011C,   MAX_PHY_DEV_TYPES} PHY_DEVICE_et;typedef struct {	PHY_DEVICE_et phyDevice;	u32		phyIdOUI;	u16		phyIdModel;	char 		*name;} PHY_DEVICE_INFO_t;static const PHY_DEVICE_INFO_t PHY_DEVICES[] =	{{PHY_TYPE_UNKNOWN,    0x000000, 0x0, "PHY_TYPE_UNKNOWN"},	 {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},	 {PHY_AGERE_ET1011C,   0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},};/* * Caller must take hw_lock. */static int ql_sem_spinlock(struct ql3_adapter *qdev,			    u32 sem_mask, u32 sem_bits){	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;	u32 value;	unsigned int seconds = 3;	do {		writel((sem_mask | sem_bits),		       &port_regs->CommonRegs.semaphoreReg);		value = readl(&port_regs->CommonRegs.semaphoreReg);		if ((value & (sem_mask >> 16)) == sem_bits)			return 0;		ssleep(1);	} while(--seconds);	return -1;}static void ql_sem_unlock(struct ql3_adapter *qdev, u32 sem_mask){	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;	writel(sem_mask, &port_regs->CommonRegs.semaphoreReg);	readl(&port_regs->CommonRegs.semaphoreReg);}static int ql_sem_lock(struct ql3_adapter *qdev, u32 sem_mask, u32 sem_bits){	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;	u32 value;	writel((sem_mask | sem_bits), &port_regs->CommonRegs.semaphoreReg);	value = readl(&port_regs->CommonRegs.semaphoreReg);	return ((value & (sem_mask >> 16)) == sem_bits);}/* * Caller holds hw_lock. */static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev){	int i = 0;	while (1) {		if (!ql_sem_lock(qdev,				 QL_DRVR_SEM_MASK,				 (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)				  * 2) << 1)) {			if (i < 10) {				ssleep(1);				i++;			} else {				printk(KERN_ERR PFX "%s: Timed out waiting for "				       "driver lock...\n",				       qdev->ndev->name);				return 0;			}		} else {			printk(KERN_DEBUG PFX			       "%s: driver lock acquired.\n",			       qdev->ndev->name);			return 1;		}	}}static void ql_set_register_page(struct ql3_adapter *qdev, u32 page){	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;	writel(((ISP_CONTROL_NP_MASK << 16) | page),			&port_regs->CommonRegs.ispControlStatus);	readl(&port_regs->CommonRegs.ispControlStatus);	qdev->current_page = page;}static u32 ql_read_common_reg_l(struct ql3_adapter *qdev,			      u32 __iomem * reg){	u32 value;	unsigned long hw_flags;	spin_lock_irqsave(&qdev->hw_lock, hw_flags);	value = readl(reg);	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);	return value;}static u32 ql_read_common_reg(struct ql3_adapter *qdev,			      u32 __iomem * reg){	return readl(reg);}static u32 ql_read_page0_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg){	u32 value;	unsigned long hw_flags;	spin_lock_irqsave(&qdev->hw_lock, hw_flags);	if (qdev->current_page != 0)		ql_set_register_page(qdev,0);	value = readl(reg);	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);	return value;}static u32 ql_read_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg){	if (qdev->current_page != 0)		ql_set_register_page(qdev,0);	return readl(reg);}static void ql_write_common_reg_l(struct ql3_adapter *qdev,				u32 __iomem *reg, u32 value){	unsigned long hw_flags;	spin_lock_irqsave(&qdev->hw_lock, hw_flags);	writel(value, reg);	readl(reg);	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);	return;}static void ql_write_common_reg(struct ql3_adapter *qdev,				u32 __iomem *reg, u32 value){	writel(value, reg);	readl(reg);	return;}static void ql_write_nvram_reg(struct ql3_adapter *qdev,				u32 __iomem *reg, u32 value){	writel(value, reg);	readl(reg);	udelay(1);	return;}static void ql_write_page0_reg(struct ql3_adapter *qdev,			       u32 __iomem *reg, u32 value){	if (qdev->current_page != 0)		ql_set_register_page(qdev,0);	writel(value, reg);	readl(reg);	return;}/* * Caller holds hw_lock. Only called during init. */static void ql_write_page1_reg(struct ql3_adapter *qdev,			       u32 __iomem *reg, u32 value){	if (qdev->current_page != 1)		ql_set_register_page(qdev,1);	writel(value, reg);	readl(reg);	return;}/* * Caller holds hw_lock. Only called during init. */static void ql_write_page2_reg(struct ql3_adapter *qdev,			       u32 __iomem *reg, u32 value){	if (qdev->current_page != 2)		ql_set_register_page(qdev,2);	writel(value, reg);	readl(reg);	return;}static void ql_disable_interrupts(struct ql3_adapter *qdev){	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;	ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,			    (ISP_IMR_ENABLE_INT << 16));}static void ql_enable_interrupts(struct ql3_adapter *qdev){	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;	ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,			    ((0xff << 16) | ISP_IMR_ENABLE_INT));}static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,					    struct ql_rcv_buf_cb *lrg_buf_cb){	dma_addr_t map;	int err;	lrg_buf_cb->next = NULL;	if (qdev->lrg_buf_free_tail == NULL) {	/* The list is empty  */		qdev->lrg_buf_free_head = qdev->lrg_buf_free_tail = lrg_buf_cb;	} else {		qdev->lrg_buf_free_tail->next = lrg_buf_cb;		qdev->lrg_buf_free_tail = lrg_buf_cb;	}	if (!lrg_buf_cb->skb) {		lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,						   qdev->lrg_buffer_len);		if (unlikely(!lrg_buf_cb->skb)) {			printk(KERN_ERR PFX "%s: failed netdev_alloc_skb().\n",			       qdev->ndev->name);			qdev->lrg_buf_skb_check++;		} else {			/*			 * We save some space to copy the ethhdr from first			 * buffer			 */			skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);			map = pci_map_single(qdev->pdev,					     lrg_buf_cb->skb->data,					     qdev->lrg_buffer_len -					     QL_HEADER_SPACE,					     PCI_DMA_FROMDEVICE);			err = pci_dma_mapping_error(map);			if(err) {				printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",				       qdev->ndev->name, err);				dev_kfree_skb(lrg_buf_cb->skb);				lrg_buf_cb->skb = NULL;				qdev->lrg_buf_skb_check++;				return;			}			lrg_buf_cb->buf_phy_addr_low =			    cpu_to_le32(LS_64BITS(map));			lrg_buf_cb->buf_phy_addr_high =			    cpu_to_le32(MS_64BITS(map));			pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);			pci_unmap_len_set(lrg_buf_cb, maplen,					  qdev->lrg_buffer_len -					  QL_HEADER_SPACE);		}	}	qdev->lrg_buf_free_count++;}static struct ql_rcv_buf_cb *ql_get_from_lrg_buf_free_list(struct ql3_adapter							   *qdev){	struct ql_rcv_buf_cb *lrg_buf_cb;	if ((lrg_buf_cb = qdev->lrg_buf_free_head) != NULL) {		if ((qdev->lrg_buf_free_head = lrg_buf_cb->next) == NULL)			qdev->lrg_buf_free_tail = NULL;		qdev->lrg_buf_free_count--;	}	return lrg_buf_cb;}static u32 addrBits = EEPROM_NO_ADDR_BITS;static u32 dataBits = EEPROM_NO_DATA_BITS;static void fm93c56a_deselect(struct ql3_adapter *qdev);static void eeprom_readword(struct ql3_adapter *qdev, u32 eepromAddr,			    unsigned short *value);/* * Caller holds hw_lock. */static void fm93c56a_select(struct ql3_adapter *qdev){	struct ql3xxx_port_registers __iomem *port_regs =	    		qdev->mem_map_registers;	qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data);	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,			    ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));}/* * Caller holds hw_lock. */static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr){	int i;	u32 mask;	u32 dataBit;	u32 previousBit;	struct ql3xxx_port_registers __iomem *port_regs =	    		qdev->mem_map_registers;	/* Clock in a zero, then do the start bit */	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data |			    AUBURN_EEPROM_DO_1);	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,			    ISP_NVRAM_MASK | qdev->			    eeprom_cmd_data | AUBURN_EEPROM_DO_1 |			    AUBURN_EEPROM_CLK_RISE);	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,			    ISP_NVRAM_MASK | qdev->			    eeprom_cmd_data | AUBURN_EEPROM_DO_1 |			    AUBURN_EEPROM_CLK_FALL);	mask = 1 << (FM93C56A_CMD_BITS - 1);	/* Force the previous data bit to be different */	previousBit = 0xffff;	for (i = 0; i < FM93C56A_CMD_BITS; i++) {		dataBit =		    (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;		if (previousBit != dataBit) {			/*			 * If the bit changed, then change the DO state to			 * match			 */			ql_write_nvram_reg(qdev,					    &port_regs->CommonRegs.					    serialPortInterfaceReg,					    ISP_NVRAM_MASK | qdev->					    eeprom_cmd_data | dataBit);			previousBit = dataBit;		}		ql_write_nvram_reg(qdev,				    &port_regs->CommonRegs.				    serialPortInterfaceReg,				    ISP_NVRAM_MASK | qdev->				    eeprom_cmd_data | dataBit |				    AUBURN_EEPROM_CLK_RISE);		ql_write_nvram_reg(qdev,				    &port_regs->CommonRegs.				    serialPortInterfaceReg,				    ISP_NVRAM_MASK | qdev->				    eeprom_cmd_data | dataBit |				    AUBURN_EEPROM_CLK_FALL);		cmd = cmd << 1;	}	mask = 1 << (addrBits - 1);	/* Force the previous data bit to be different */	previousBit = 0xffff;	for (i = 0; i < addrBits; i++) {		dataBit =		    (eepromAddr & mask) ? AUBURN_EEPROM_DO_1 :		    AUBURN_EEPROM_DO_0;		if (previousBit != dataBit) {			/*			 * If the bit changed, then change the DO state to			 * match			 */			ql_write_nvram_reg(qdev,					    &port_regs->CommonRegs.					    serialPortInterfaceReg,					    ISP_NVRAM_MASK | qdev->					    eeprom_cmd_data | dataBit);			previousBit = dataBit;		}		ql_write_nvram_reg(qdev,				    &port_regs->CommonRegs.				    serialPortInterfaceReg,				    ISP_NVRAM_MASK | qdev->				    eeprom_cmd_data | dataBit |				    AUBURN_EEPROM_CLK_RISE);		ql_write_nvram_reg(qdev,				    &port_regs->CommonRegs.				    serialPortInterfaceReg,				    ISP_NVRAM_MASK | qdev->				    eeprom_cmd_data | dataBit |				    AUBURN_EEPROM_CLK_FALL);		eepromAddr = eepromAddr << 1;	}}/* * Caller holds hw_lock. */static void fm93c56a_deselect(struct ql3_adapter *qdev){	struct ql3xxx_port_registers __iomem *port_regs =	    		qdev->mem_map_registers;	qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0;	ql_write_nvram_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,			    ISP_NVRAM_MASK | qdev->eeprom_cmd_data);}/* * Caller holds hw_lock. */static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value){	int i;	u32 data = 0;	u32 dataBit;	struct ql3xxx_port_registers __iomem *port_regs =	    		qdev->mem_map_registers;	/* Read the data bits */	/* The first bit is a dummy.  Clock right over it. */	for (i = 0; i < dataBits; i++) {		ql_write_nvram_reg(qdev,				    &port_regs->CommonRegs.

⌨️ 快捷键说明

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