/*
* QLogic QLA3xxx NIC HBA Driver
* Copyright (c) 2003-2006 QLogic Corporation
*
* See LICENSE.qla3xxx for copyright and licensing details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.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 <linux/prefetch.h>
#include "qla3xxx.h"
#define DRV_NAME "qla3xxx"
#define DRV_STRING "QLogic ISP3XXX Network Driver"
#define DRV_VERSION "v2.03.00-k5"
static const char ql3xxx_driver_name[] = DRV_NAME;
static const char ql3xxx_driver_version[] = DRV_VERSION;
#define TIMED_OUT_MSG \
"Timed out waiting for management port to get free before issuing command\n"
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 const struct pci_device_id ql3xxx_pci_tbl[] = {
{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
*/
enum PHY_DEVICE_TYPE {
PHY_TYPE_UNKNOWN = 0,
PHY_VITESSE_VSC8211,
PHY_AGERE_ET1011C,
MAX_PHY_DEV_TYPES
};
struct PHY_DEVICE_INFO {
const enum PHY_DEVICE_TYPE phyDevice;
const u32 phyIdOUI;
const u16 phyIdModel;
const char *name;
};
static const struct PHY_DEVICE_INFO 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 (i < 10) {
if (i)
ssleep(1);
if (ql_sem_lock(qdev,
QL_DRVR_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
* 2) << 1)) {
netdev_printk(KERN_DEBUG, qdev->ndev,
"driver lock acquired\n");
return 1;
}
}
netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n");
return 0;
}
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);
}
static void ql_write_common_reg(struct ql3_adapter *qdev,
u32 __iomem *reg, u32 value)
{
writel(value, reg);
readl(reg);
}
static void ql_write_nvram_reg(struct ql3_adapter *qdev,
u32 __iomem *reg, u32 value)
{
writel(value, reg);
readl(reg);
udelay(1);
}
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);
}
/*
* 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);
}
/*
* 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);
}
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)) {
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(qdev->pdev, map);
if (err) {
netdev_err(qdev->ndev,
评论0