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 + -
显示快捷键?