aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/isdn/i4l/Kconfig1
-rw-r--r--drivers/net/3c501.c1
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/8139cp.c2
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/8390.c10
-rw-r--r--drivers/net/Kconfig33
-rw-r--r--drivers/net/Makefile11
-rw-r--r--drivers/net/acenic.c2
-rw-r--r--drivers/net/amd8111e.c2
-rw-r--r--drivers/net/arcnet/com20020-pci.c2
-rw-r--r--drivers/net/b44.c2
-rw-r--r--drivers/net/bnx2.c2
-rw-r--r--drivers/net/cassini.c2
-rw-r--r--drivers/net/chelsio/cxgb2.c2
-rw-r--r--drivers/net/defxx.c2
-rw-r--r--drivers/net/dl2k.c2
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000/e1000_main.c2
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/epic100.c2
-rw-r--r--drivers/net/fealnx.c2
-rw-r--r--drivers/net/forcedeth.c463
-rw-r--r--drivers/net/hp100.c1
-rw-r--r--drivers/net/irda/mcs7780.c1
-rw-r--r--drivers/net/irda/w83977af_ir.c1
-rw-r--r--drivers/net/ixgb/ixgb_main.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c54
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp.h14
-rw-r--r--drivers/net/natsemi.c2
-rw-r--r--drivers/net/ne2k-pci.c2
-rw-r--r--drivers/net/netx-eth.c1
-rw-r--r--drivers/net/ns83820.c2
-rw-r--r--drivers/net/pci-skeleton.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c3
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c15
-rw-r--r--drivers/net/pcnet32.c2
-rw-r--r--drivers/net/phy/smsc.c1
-rw-r--r--drivers/net/phy/vitesse.c1
-rw-r--r--drivers/net/qla3xxx.c3537
-rw-r--r--drivers/net/qla3xxx.h1194
-rw-r--r--drivers/net/r8169.c2
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/s2io.c2
-rw-r--r--drivers/net/saa9730.c2
-rw-r--r--drivers/net/sis190.c2
-rw-r--r--drivers/net/sis900.c3
-rw-r--r--drivers/net/sk98lin/skge.c2
-rw-r--r--drivers/net/skfp/skfddi.c2
-rw-r--r--drivers/net/skge.c2
-rw-r--r--drivers/net/sky2.c35
-rw-r--r--drivers/net/slhc.c28
-rw-r--r--drivers/net/smc911x.c2
-rw-r--r--drivers/net/starfire.c2
-rw-r--r--drivers/net/sundance.c15
-rw-r--r--drivers/net/sungem.c2
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/tg3.c2
-rw-r--r--drivers/net/tokenring/3c359.c2
-rw-r--r--drivers/net/tokenring/lanstreamer.c2
-rw-r--r--drivers/net/tulip/de2104x.c2
-rw-r--r--drivers/net/tulip/de4x5.c2
-rw-r--r--drivers/net/tulip/dmfe.c2
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/tulip/uli526x.c12
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c2
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/via-rhine.c2
-rw-r--r--drivers/net/via-velocity.c2
-rw-r--r--drivers/net/via-velocity.h19
-rw-r--r--drivers/net/wan/cycx_main.c1
-rw-r--r--drivers/net/wan/dlci.c1
-rw-r--r--drivers/net/wan/dscc4.c2
-rw-r--r--drivers/net/wan/farsync.c2
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2
-rw-r--r--drivers/net/wan/pc300_drv.c2
-rw-r--r--drivers/net/wan/pci200syn.c2
-rw-r--r--drivers/net/wan/sdla.c1
-rw-r--r--drivers/net/wan/wanxl.c2
-rw-r--r--drivers/net/wireless/airo.c12
-rw-r--r--drivers/net/wireless/atmel_pci.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h116
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c80
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c10
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c743
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h3
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c33
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c104
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c166
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c5
-rw-r--r--drivers/net/wireless/ipw2100.c2
-rw-r--r--drivers/net/wireless/ipw2200.c31
-rw-r--r--drivers/net/wireless/orinoco_nortel.c2
-rw-r--r--drivers/net/wireless/orinoco_pci.c2
-rw-r--r--drivers/net/wireless/orinoco_plx.c2
-rw-r--r--drivers/net/wireless/orinoco_tmd.c2
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c573
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.h6
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c4
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c2
-rw-r--r--drivers/net/wireless/ray_cs.c2
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c62
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h15
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c17
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c7
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c155
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c274
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c122
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h1
-rw-r--r--drivers/net/yellowfin.c2
119 files changed, 7113 insertions, 1030 deletions
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index a4f7288a1fc..3ef567b99c7 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -5,6 +5,7 @@
config ISDN_PPP
bool "Support synchronous PPP"
depends on INET
+ select SLHC
help
Over digital connections such as ISDN, there is no need to
synchronize sender and recipient's clocks with start and stop bits
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 07136ec423b..d7b115a3596 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -120,7 +120,6 @@ static const char version[] =
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/config.h> /* for CONFIG_IP_MULTICAST */
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80e8ca013e4..7c23813bb09 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -3169,7 +3169,7 @@ static int __init vortex_init(void)
{
int pci_rc, eisa_rc;
- pci_rc = pci_module_init(&vortex_driver);
+ pci_rc = pci_register_driver(&vortex_driver);
eisa_rc = vortex_eisa_init();
if (pci_rc == 0)
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 1428bb7715a..4c2e76326c4 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -2098,7 +2098,7 @@ static int __init cp_init (void)
#ifdef MODULE
printk("%s", version);
#endif
- return pci_module_init (&cp_driver);
+ return pci_register_driver(&cp_driver);
}
static void __exit cp_exit (void)
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index e4f4eaff767..2a707747ed8 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -2629,7 +2629,7 @@ static int __init rtl8139_init_module (void)
printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
#endif
- return pci_module_init (&rtl8139_pci_driver);
+ return pci_register_driver(&rtl8139_pci_driver);
}
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index d2935ae3981..3eb7048684a 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -299,7 +299,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* Slow phase with lock held.
*/
- disable_irq_nosync(dev->irq);
+ disable_irq_nosync_lockdep(dev->irq);
spin_lock(&ei_local->page_lock);
@@ -338,7 +338,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
- enable_irq(dev->irq);
+ enable_irq_lockdep(dev->irq);
ei_local->stat.tx_errors++;
return 1;
}
@@ -379,7 +379,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
- enable_irq(dev->irq);
+ enable_irq_lockdep(dev->irq);
dev_kfree_skb (skb);
ei_local->stat.tx_bytes += send_length;
@@ -505,9 +505,9 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifdef CONFIG_NET_POLL_CONTROLLER
void ei_poll(struct net_device *dev)
{
- disable_irq(dev->irq);
+ disable_irq_lockdep(dev->irq);
ei_interrupt(dev->irq, dev, NULL);
- enable_irq(dev->irq);
+ enable_irq_lockdep(dev->irq);
}
#endif
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 30b3671d833..6f388d9e9be 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1411,6 +1411,22 @@ config FORCEDETH
<file:Documentation/networking/net-modules.txt>. The module will be
called forcedeth.
+config FORCEDETH_NAPI
+ bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
+ depends on FORCEDETH && EXPERIMENTAL
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
config CS89x0
tristate "CS89x0 support"
@@ -2290,6 +2306,15 @@ config MV643XX_ETH_2
This enables support for Port 2 of the Marvell MV643XX Gigabit
Ethernet.
+config QLA3XXX
+ tristate "QLogic QLA3XXX Network Driver Support"
+ depends on PCI
+ help
+ This driver supports QLogic ISP3XXX gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called qla3xxx.
+
endmenu
#
@@ -2550,6 +2575,7 @@ config PLIP
config PPP
tristate "PPP (point-to-point protocol) support"
+ select SLHC
---help---
PPP (Point to Point Protocol) is a newer and better SLIP. It serves
the same purpose: sending Internet traffic over telephone (and other
@@ -2730,6 +2756,7 @@ config SLIP
config SLIP_COMPRESSED
bool "CSLIP compressed headers"
depends on SLIP
+ select SLHC
---help---
This protocol is faster than SLIP because it uses compression on the
TCP/IP headers (not on the data itself), but it has to be supported
@@ -2742,6 +2769,12 @@ config SLIP_COMPRESSED
<http://www.tldp.org/docs.html#howto>, explains how to configure
CSLIP. This won't enlarge your kernel.
+config SLHC
+ tristate
+ help
+ This option enables Van Jacobsen serial line header compression
+ routines.
+
config SLIP_SMART
bool "Keepalive and linefill"
depends on SLIP
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 8427bf9dec9..6ff17649c0f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -2,10 +2,6 @@
# Makefile for the Linux network (ethercard) device drivers.
#
-ifeq ($(CONFIG_ISDN_PPP),y)
- obj-$(CONFIG_ISDN) += slhc.o
-endif
-
obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
@@ -113,8 +109,9 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
+obj-$(CONFIG_QLA3XXX) += qla3xxx.o
-obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
+obj-$(CONFIG_PPP) += ppp_generic.o
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
@@ -123,9 +120,7 @@ obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
obj-$(CONFIG_SLIP) += slip.o
-ifeq ($(CONFIG_SLIP_COMPRESSED),y)
- obj-$(CONFIG_SLIP) += slhc.o
-endif
+obj-$(CONFIG_SLHC) += slhc.o
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 1c01e9b3d07..c0f3574b470 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -725,7 +725,7 @@ static struct pci_driver acenic_pci_driver = {
static int __init acenic_init(void)
{
- return pci_module_init(&acenic_pci_driver);
+ return pci_register_driver(&acenic_pci_driver);
}
static void __exit acenic_exit(void)
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index ed322a76980..2ef8e554263 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -2158,7 +2158,7 @@ static struct pci_driver amd8111e_driver = {
static int __init amd8111e_init(void)
{
- return pci_module_init(&amd8111e_driver);
+ return pci_register_driver(&amd8111e_driver);
}
static void __exit amd8111e_cleanup(void)
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index 979a33df0a8..fc256c197cd 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -177,7 +177,7 @@ static struct pci_driver com20020pci_driver = {
static int __init com20020pci_init(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
- return pci_module_init(&com20020pci_driver);
+ return pci_register_driver(&com20020pci_driver);
}
static void __exit com20020pci_cleanup(void)
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index bea0fc0ede2..17eb2912971 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -2354,7 +2354,7 @@ static int __init b44_init(void)
dma_desc_align_mask = ~(dma_desc_align_size - 1);
dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
- return pci_module_init(&b44_driver);
+ return pci_register_driver(&b44_driver);
}
static void __exit b44_cleanup(void)
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 652eb05a6c2..654b903985c 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -6016,7 +6016,7 @@ static struct pci_driver bnx2_pci_driver = {
static int __init bnx2_init(void)
{
- return pci_module_init(&bnx2_pci_driver);
+ return pci_register_driver(&bnx2_pci_driver);
}
static void __exit bnx2_cleanup(void)
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index a31544ccb3c..26040abfef6 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -5245,7 +5245,7 @@ static int __init cas_init(void)
else
link_transition_timeout = 0;
- return pci_module_init(&cas_driver);
+ return pci_register_driver(&cas_driver);
}
static void __exit cas_cleanup(void)
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index e67872433e9..b6de184e469 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -1243,7 +1243,7 @@ static struct pci_driver driver = {
static int __init t1_init_module(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit t1_cleanup_module(void)
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 91cc8cbdd44..7d06dedbfb2 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3444,7 +3444,7 @@ static int __init dfx_init(void)
{
int rc_pci, rc_eisa;
- rc_pci = pci_module_init(&dfx_driver);
+ rc_pci = pci_register_driver(&dfx_driver);
if (rc_pci >= 0) dfx_have_pci = 1;
rc_eisa = dfx_eisa_init();
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 402961e68c8..a572c297056 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1815,7 +1815,7 @@ static struct pci_driver rio_driver = {
static int __init
rio_init (void)
{
- return pci_module_init (&rio_driver);
+ return pci_register_driver(&rio_driver);
}
static void __exit
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 91ef5f2fd76..5f68cb8eb33 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2873,7 +2873,7 @@ static int __init e100_init_module(void)
printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
}
- return pci_module_init(&e100_driver);
+ return pci_register_driver(&e100_driver);
}
static void __exit e100_cleanup_module(void)
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 726f43d5593..336435d81ec 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -245,7 +245,7 @@ e1000_init_module(void)
printk(KERN_INFO "%s\n", e1000_copyright);
- ret = pci_module_init(&e1000_driver);
+ ret = pci_register_driver(&e1000_driver);
return ret;
}
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index e445988c92e..a3d515def10 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -2385,7 +2385,7 @@ static int __init eepro100_init_module(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&eepro100_driver);
+ return pci_register_driver(&eepro100_driver);
}
static void __exit eepro100_cleanup_module(void)
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index a67650ccf08..25c4619d842 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1604,7 +1604,7 @@ static int __init epic_init (void)
version, version2, version3);
#endif
- return pci_module_init (&epic_driver);
+ return pci_register_driver(&epic_driver);
}
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 567e27413cf..a2121faa610 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1984,7 +1984,7 @@ static int __init fealnx_init(void)
printk(version);
#endif
- return pci_module_init(&fealnx_driver);
+ return pci_register_driver(&fealnx_driver);
}
static void __exit fealnx_exit(void)
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 11b8f1b43dd..8c8f7cf0e95 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -109,6 +109,7 @@
* 0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.
* 0.55: 22 Mar 2006: Add flow control (pause frame).
* 0.56: 22 Mar 2006: Additional ethtool config and moduleparam support.
+ * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -120,7 +121,12 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.56"
+#ifdef CONFIG_FORCEDETH_NAPI
+#define DRIVERNAPI "-NAPI"
+#else
+#define DRIVERNAPI
+#endif
+#define FORCEDETH_VERSION "0.57"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -262,7 +268,8 @@ enum {
NvRegRingSizes = 0x108,
#define NVREG_RINGSZ_TXSHIFT 0
#define NVREG_RINGSZ_RXSHIFT 16
- NvRegUnknownTransmitterReg = 0x10c,
+ NvRegTransmitPoll = 0x10c,
+#define NVREG_TRANSMITPOLL_MAC_ADDR_REV 0x00008000
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
#define NVREG_LINKSPEED_10 1000
@@ -381,21 +388,21 @@ enum {
/* Big endian: should work, but is untested */
struct ring_desc {
- u32 PacketBuffer;
- u32 FlagLen;
+ __le32 buf;
+ __le32 flaglen;
};
struct ring_desc_ex {
- u32 PacketBufferHigh;
- u32 PacketBufferLow;
- u32 TxVlan;
- u32 FlagLen;
+ __le32 bufhigh;
+ __le32 buflow;
+ __le32 txvlan;
+ __le32 flaglen;
};
-typedef union _ring_type {
+union ring_type {
struct ring_desc* orig;
struct ring_desc_ex* ex;
-} ring_type;
+};
#define FLAG_MASK_V1 0xffff0000
#define FLAG_MASK_V2 0xffffc000
@@ -653,8 +660,8 @@ static const struct nv_ethtool_str nv_etests_str[] = {
};
struct register_test {
- u32 reg;
- u32 mask;
+ __le32 reg;
+ __le32 mask;
};
static const struct register_test nv_registers_test[] = {
@@ -713,7 +720,7 @@ struct fe_priv {
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
- ring_type rx_ring;
+ union ring_type rx_ring;
unsigned int cur_rx, refill_rx;
struct sk_buff **rx_skbuff;
dma_addr_t *rx_dma;
@@ -733,7 +740,7 @@ struct fe_priv {
/*
* tx specific fields.
*/
- ring_type tx_ring;
+ union ring_type tx_ring;
unsigned int next_tx, nic_tx;
struct sk_buff **tx_skbuff;
dma_addr_t *tx_dma;
@@ -826,13 +833,13 @@ static inline void pci_push(u8 __iomem *base)
static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
{
- return le32_to_cpu(prd->FlagLen)
+ return le32_to_cpu(prd->flaglen)
& ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
}
static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
{
- return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
+ return le32_to_cpu(prd->flaglen) & LEN_MASK_V2;
}
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
@@ -885,7 +892,7 @@ static void free_rings(struct net_device *dev)
struct fe_priv *np = get_nvpriv(dev);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if(np->rx_ring.orig)
+ if (np->rx_ring.orig)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
np->rx_ring.orig, np->ring_addr);
} else {
@@ -1178,7 +1185,7 @@ static void nv_stop_tx(struct net_device *dev)
KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
udelay(NV_TXSTOP_DELAY2);
- writel(0, base + NvRegUnknownTransmitterReg);
+ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
}
static void nv_txrx_reset(struct net_device *dev)
@@ -1258,14 +1265,14 @@ static int nv_alloc_rx(struct net_device *dev)
np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
skb->end-skb->data, PCI_DMA_FROMDEVICE);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
+ np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
wmb();
- np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
} else {
- np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
- np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+ np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+ np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
wmb();
- np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
}
dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
dev->name, refill_rx);
@@ -1277,6 +1284,16 @@ static int nv_alloc_rx(struct net_device *dev)
return 0;
}
+/* If rx bufs are exhausted called after 50ms to attempt to refresh */
+#ifdef CONFIG_FORCEDETH_NAPI
+static void nv_do_rx_refill(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *) data;
+
+ /* Just reschedule NAPI rx processing */
+ netif_rx_schedule(dev);
+}
+#else
static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
@@ -1305,6 +1322,7 @@ static void nv_do_rx_refill(unsigned long data)
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
}
+#endif
static void nv_init_rx(struct net_device *dev)
{
@@ -1315,9 +1333,9 @@ static void nv_init_rx(struct net_device *dev)
np->refill_rx = 0;
for (i = 0; i < np->rx_ring_size; i++)
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->rx_ring.orig[i].FlagLen = 0;
+ np->rx_ring.orig[i].flaglen = 0;
else
- np->rx_ring.ex[i].FlagLen = 0;
+ np->rx_ring.ex[i].flaglen = 0;
}
static void nv_init_tx(struct net_device *dev)
@@ -1328,9 +1346,9 @@ static void nv_init_tx(struct net_device *dev)
np->next_tx = np->nic_tx = 0;
for (i = 0; i < np->tx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->tx_ring.orig[i].FlagLen = 0;
+ np->tx_ring.orig[i].flaglen = 0;
else
- np->tx_ring.ex[i].FlagLen = 0;
+ np->tx_ring.ex[i].flaglen = 0;
np->tx_skbuff[i] = NULL;
np->tx_dma[i] = 0;
}
@@ -1373,9 +1391,9 @@ static void nv_drain_tx(struct net_device *dev)
for (i = 0; i < np->tx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->tx_ring.orig[i].FlagLen = 0;
+ np->tx_ring.orig[i].flaglen = 0;
else
- np->tx_ring.ex[i].FlagLen = 0;
+ np->tx_ring.ex[i].flaglen = 0;
if (nv_release_txskb(dev, i))
np->stats.tx_dropped++;
}
@@ -1387,9 +1405,9 @@ static void nv_drain_rx(struct net_device *dev)
int i;
for (i = 0; i < np->rx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->rx_ring.orig[i].FlagLen = 0;
+ np->rx_ring.orig[i].flaglen = 0;
else
- np->rx_ring.ex[i].FlagLen = 0;
+ np->rx_ring.ex[i].flaglen = 0;
wmb();
if (np->rx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->rx_dma[i],
@@ -1450,17 +1468,17 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
np->tx_dma_len[nr] = bcnt;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
} else {
- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
}
tx_flags = np->tx_flags;
offset += bcnt;
size -= bcnt;
- } while(size);
+ } while (size);
/* setup the fragments */
for (i = 0; i < fragments; i++) {
@@ -1477,12 +1495,12 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
np->tx_dma_len[nr] = bcnt;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
} else {
- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
}
offset += bcnt;
size -= bcnt;
@@ -1491,9 +1509,9 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set last fragment flag */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+ np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
} else {
- np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+ np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
}
np->tx_skbuff[nr] = skb;
@@ -1512,10 +1530,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set tx flags */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
} else {
- np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan);
- np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
+ np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
}
dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
@@ -1547,7 +1565,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void nv_tx_done(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- u32 Flags;
+ u32 flags;
unsigned int i;
struct sk_buff *skb;
@@ -1555,22 +1573,22 @@ static void nv_tx_done(struct net_device *dev)
i = np->nic_tx % np->tx_ring_size;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
+ flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
else
- Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
+ flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
- dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
- dev->name, np->nic_tx, Flags);
- if (Flags & NV_TX_VALID)
+ dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
+ dev->name, np->nic_tx, flags);
+ if (flags & NV_TX_VALID)
break;
if (np->desc_ver == DESC_VER_1) {
- if (Flags & NV_TX_LASTPACKET) {
+ if (flags & NV_TX_LASTPACKET) {
skb = np->tx_skbuff[i];
- if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+ if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
NV_TX_UNDERFLOW|NV_TX_ERROR)) {
- if (Flags & NV_TX_UNDERFLOW)
+ if (flags & NV_TX_UNDERFLOW)
np->stats.tx_fifo_errors++;
- if (Flags & NV_TX_CARRIERLOST)
+ if (flags & NV_TX_CARRIERLOST)
np->stats.tx_carrier_errors++;
np->stats.tx_errors++;
} else {
@@ -1579,13 +1597,13 @@ static void nv_tx_done(struct net_device *dev)
}
}
} else {
- if (Flags & NV_TX2_LASTPACKET) {
+ if (flags & NV_TX2_LASTPACKET) {
skb = np->tx_skbuff[i];
- if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+ if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
- if (Flags & NV_TX2_UNDERFLOW)
+ if (flags & NV_TX2_UNDERFLOW)
np->stats.tx_fifo_errors++;
- if (Flags & NV_TX2_CARRIERLOST)
+ if (flags & NV_TX2_CARRIERLOST)
np->stats.tx_carrier_errors++;
np->stats.tx_errors++;
} else {
@@ -1638,29 +1656,29 @@ static void nv_tx_timeout(struct net_device *dev)
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
i,
- le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i].FlagLen),
- le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
- le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
- le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
+ le32_to_cpu(np->tx_ring.orig[i].buf),
+ le32_to_cpu(np->tx_ring.orig[i].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+1].buf),
+ le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+2].buf),
+ le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+3].buf),
+ le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
} else {
printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
i,
- le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i].FlagLen),
- le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
- le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
- le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
+ le32_to_cpu(np->tx_ring.ex[i].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i].buflow),
+ le32_to_cpu(np->tx_ring.ex[i].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+1].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+2].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+3].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
}
}
}
@@ -1697,7 +1715,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
int protolen; /* length as stored in the proto field */
/* 1) calculate len according to header */
- if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+ if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) {
protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
hdrlen = VLAN_HLEN;
} else {
@@ -1740,13 +1758,14 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
}
}
-static void nv_rx_process(struct net_device *dev)
+static int nv_rx_process(struct net_device *dev, int limit)
{
struct fe_priv *np = netdev_priv(dev);
- u32 Flags;
+ u32 flags;
u32 vlanflags = 0;
+ int count;
- for (;;) {
+ for (count = 0; count < limit; ++count) {
struct sk_buff *skb;
int len;
int i;
@@ -1755,18 +1774,18 @@ static void nv_rx_process(struct net_device *dev)
i = np->cur_rx % np->rx_ring_size;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
} else {
- Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
- vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow);
+ vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
}
- dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
- dev->name, np->cur_rx, Flags);
+ dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
+ dev->name, np->cur_rx, flags);
- if (Flags & NV_RX_AVAIL)
+ if (flags & NV_RX_AVAIL)
break; /* still owned by hardware, */
/*
@@ -1780,7 +1799,7 @@ static void nv_rx_process(struct net_device *dev)
{
int j;
- dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags);
+ dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
@@ -1790,30 +1809,30 @@ static void nv_rx_process(struct net_device *dev)
}
/* look at what we actually got: */
if (np->desc_ver == DESC_VER_1) {
- if (!(Flags & NV_RX_DESCRIPTORVALID))
+ if (!(flags & NV_RX_DESCRIPTORVALID))
goto next_pkt;
- if (Flags & NV_RX_ERROR) {
- if (Flags & NV_RX_MISSEDFRAME) {
+ if (flags & NV_RX_ERROR) {
+ if (flags & NV_RX_MISSEDFRAME) {
np->stats.rx_missed_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
+ if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX_CRCERR) {
+ if (flags & NV_RX_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX_OVERFLOW) {
+ if (flags & NV_RX_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX_ERROR4) {
+ if (flags & NV_RX_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
@@ -1821,32 +1840,32 @@ static void nv_rx_process(struct net_device *dev)
}
}
/* framing errors are soft errors. */
- if (Flags & NV_RX_FRAMINGERR) {
- if (Flags & NV_RX_SUBSTRACT1) {
+ if (flags & NV_RX_FRAMINGERR) {
+ if (flags & NV_RX_SUBSTRACT1) {
len--;
}
}
}
} else {
- if (!(Flags & NV_RX2_DESCRIPTORVALID))
+ if (!(flags & NV_RX2_DESCRIPTORVALID))
goto next_pkt;
- if (Flags & NV_RX2_ERROR) {
- if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
+ if (flags & NV_RX2_ERROR) {
+ if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX2_CRCERR) {
+ if (flags & NV_RX2_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX2_OVERFLOW) {
+ if (flags & NV_RX2_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX2_ERROR4) {
+ if (flags & NV_RX2_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
@@ -1854,17 +1873,17 @@ static void nv_rx_process(struct net_device *dev)
}
}
/* framing errors are soft errors */
- if (Flags & NV_RX2_FRAMINGERR) {
- if (Flags & NV_RX2_SUBSTRACT1) {
+ if (flags & NV_RX2_FRAMINGERR) {
+ if (flags & NV_RX2_SUBSTRACT1) {
len--;
}
}
}
if (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) {
- Flags &= NV_RX2_CHECKSUMMASK;
- if (Flags == NV_RX2_CHECKSUMOK1 ||
- Flags == NV_RX2_CHECKSUMOK2 ||
- Flags == NV_RX2_CHECKSUMOK3) {
+ flags &= NV_RX2_CHECKSUMMASK;
+ if (flags == NV_RX2_CHECKSUMOK1 ||
+ flags == NV_RX2_CHECKSUMOK2 ||
+ flags == NV_RX2_CHECKSUMOK3) {
dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
} else {
@@ -1880,17 +1899,27 @@ static void nv_rx_process(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
dev->name, np->cur_rx, len, skb->protocol);
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) {
- vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK);
- } else {
+#ifdef CONFIG_FORCEDETH_NAPI
+ if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+ vlan_hwaccel_receive_skb(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+ else
+ netif_receive_skb(skb);
+#else
+ if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+ vlan_hwaccel_rx(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+ else
netif_rx(skb);
- }
+#endif
dev->last_rx = jiffies;
np->stats.rx_packets++;
np->stats.rx_bytes += len;
next_pkt:
np->cur_rx++;
}
+
+ return count;
}
static void set_bufsize(struct net_device *dev)
@@ -1990,7 +2019,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
struct fe_priv *np = netdev_priv(dev);
struct sockaddr *macaddr = (struct sockaddr*)addr;
- if(!is_valid_ether_addr(macaddr->sa_data))
+ if (!is_valid_ether_addr(macaddr->sa_data))
return -EADDRNOTAVAIL;
/* synchronized against open : rtnl_lock() held by caller */
@@ -2283,20 +2312,20 @@ set_speed:
lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM);
switch (adv_pause) {
- case (ADVERTISE_PAUSE_CAP):
+ case ADVERTISE_PAUSE_CAP:
if (lpa_pause & LPA_PAUSE_CAP) {
pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
}
break;
- case (ADVERTISE_PAUSE_ASYM):
+ case ADVERTISE_PAUSE_ASYM:
if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM))
{
pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
}
break;
- case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM):
+ case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM:
if (lpa_pause & LPA_PAUSE_CAP)
{
pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
@@ -2376,14 +2405,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
nv_tx_done(dev);
spin_unlock(&np->lock);
- nv_rx_process(dev);
- if (nv_alloc_rx(dev)) {
- spin_lock(&np->lock);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock(&np->lock);
- }
-
if (events & NVREG_IRQ_LINK) {
spin_lock(&np->lock);
nv_link_irq(dev);
@@ -2403,6 +2424,29 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
+#ifdef CONFIG_FORCEDETH_NAPI
+ if (events & NVREG_IRQ_RX_ALL) {
+ netif_rx_schedule(dev);
+
+ /* Disable furthur receive irq's */
+ spin_lock(&np->lock);
+ np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ spin_unlock(&np->lock);
+ }
+#else
+ nv_rx_process(dev, dev->weight);
+ if (nv_alloc_rx(dev)) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+#endif
if (i > max_interrupt_work) {
spin_lock(&np->lock);
/* disable interrupts on the nic */
@@ -2474,6 +2518,63 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
return IRQ_RETVAL(i);
}
+#ifdef CONFIG_FORCEDETH_NAPI
+static int nv_napi_poll(struct net_device *dev, int *budget)
+{
+ int pkts, limit = min(*budget, dev->quota);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ pkts = nv_rx_process(dev, limit);
+
+ if (nv_alloc_rx(dev)) {
+ spin_lock_irq(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock_irq(&np->lock);
+ }
+
+ if (pkts < limit) {
+ /* all done, no more packets present */
+ netif_rx_complete(dev);
+
+ /* re-enable receive interrupts */
+ spin_lock_irq(&np->lock);
+ np->irqmask |= NVREG_IRQ_RX_ALL;
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ spin_unlock_irq(&np->lock);
+ return 0;
+ } else {
+ /* used up our quantum, so reschedule */
+ dev->quota -= pkts;
+ *budget -= pkts;
+ return 1;
+ }
+}
+#endif
+
+#ifdef CONFIG_FORCEDETH_NAPI
+static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) data;
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+
+ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
+ writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
+
+ if (events) {
+ netif_rx_schedule(dev);
+ /* disable receive interrupts on the nic */
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ pci_push(base);
+ }
+ return IRQ_HANDLED;
+}
+#else
static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) data;
@@ -2492,7 +2593,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
if (!(events & np->irqmask))
break;
- nv_rx_process(dev);
+ nv_rx_process(dev, dev->weight);
if (nv_alloc_rx(dev)) {
spin_lock_irq(&np->lock);
if (!np->in_shutdown)
@@ -2514,12 +2615,12 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
spin_unlock_irq(&np->lock);
break;
}
-
}
dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name);
return IRQ_RETVAL(i);
}
+#endif
static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
{
@@ -3245,7 +3346,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
/* fall back to old rings */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if(rxtx_ring)
+ if (rxtx_ring)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
rxtx_ring, ring_addr);
} else {
@@ -3481,7 +3582,7 @@ static int nv_get_stats_count(struct net_device *dev)
struct fe_priv *np = netdev_priv(dev);
if (np->driver_data & DEV_HAS_STATISTICS)
- return (sizeof(struct nv_ethtool_stats)/sizeof(u64));
+ return sizeof(struct nv_ethtool_stats)/sizeof(u64);
else
return 0;
}
@@ -3619,7 +3720,7 @@ static int nv_loopback_test(struct net_device *dev)
struct sk_buff *tx_skb, *rx_skb;
dma_addr_t test_dma_addr;
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
- u32 Flags;
+ u32 flags;
int len, i, pkt_len;
u8 *pkt_data;
u32 filter_flags = 0;
@@ -3663,12 +3764,12 @@ static int nv_loopback_test(struct net_device *dev)
tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[0].PacketBuffer = cpu_to_le32(test_dma_addr);
- np->tx_ring.orig[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr);
+ np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
} else {
- np->tx_ring.ex[0].PacketBufferHigh = cpu_to_le64(test_dma_addr) >> 32;
- np->tx_ring.ex[0].PacketBufferLow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
- np->tx_ring.ex[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32;
+ np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
+ np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
}
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
pci_push(get_hwbase(dev));
@@ -3677,21 +3778,21 @@ static int nv_loopback_test(struct net_device *dev)
/* check for rx of the packet */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- Flags = le32_to_cpu(np->rx_ring.orig[0].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.orig[0].flaglen);
len = nv_descr_getlength(&np->rx_ring.orig[0], np->desc_ver);
} else {
- Flags = le32_to_cpu(np->rx_ring.ex[0].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.ex[0].flaglen);
len = nv_descr_getlength_ex(&np->rx_ring.ex[0], np->desc_ver);
}
- if (Flags & NV_RX_AVAIL) {
+ if (flags & NV_RX_AVAIL) {
ret = 0;
} else if (np->desc_ver == DESC_VER_1) {
- if (Flags & NV_RX_ERROR)
+ if (flags & NV_RX_ERROR)
ret = 0;
} else {
- if (Flags & NV_RX2_ERROR) {
+ if (flags & NV_RX2_ERROR) {
ret = 0;
}
}
@@ -3753,6 +3854,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (netif_running(dev)) {
netif_stop_queue(dev);
+ netif_poll_disable(dev);
netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
nv_disable_hw_interrupts(dev, np->irqmask);
@@ -3811,6 +3913,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
+ netif_poll_enable(dev);
nv_enable_hw_interrupts(dev, np->irqmask);
}
}
@@ -3895,10 +3998,9 @@ static int nv_open(struct net_device *dev)
dprintk(KERN_DEBUG "nv_open: begin\n");
- /* 1) erase previous misconfiguration */
+ /* erase previous misconfiguration */
if (np->driver_data & DEV_HAS_POWER_CNTRL)
nv_mac_reset(dev);
- /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
writel(0, base + NvRegMulticastMaskA);
@@ -3913,26 +4015,22 @@ static int nv_open(struct net_device *dev)
if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)
writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame);
- /* 2) initialize descriptor rings */
+ /* initialize descriptor rings */
set_bufsize(dev);
oom = nv_init_ring(dev);
writel(0, base + NvRegLinkSpeed);
- writel(0, base + NvRegUnknownTransmitterReg);
+ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
nv_txrx_reset(dev);
writel(0, base + NvRegUnknownSetupReg6);
np->in_shutdown = 0;
- /* 3) set mac address */
- nv_copy_mac_to_hw(dev);
-
- /* 4) give hw rings */
+ /* give hw rings */
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
- /* 5) continue setup */
writel(np->linkspeed, base + NvRegLinkSpeed);
if (np->desc_ver == DESC_VER_1)
writel(NVREG_TX_WM_DESC1_DEFAULT, base + NvRegTxWatermark);
@@ -3950,7 +4048,6 @@ static int nv_open(struct net_device *dev)
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
- /* 6) continue setup */
writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
@@ -4020,6 +4117,8 @@ static int nv_open(struct net_device *dev)
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
+ netif_poll_enable(dev);
+
if (ret) {
netif_carrier_on(dev);
} else {
@@ -4049,6 +4148,7 @@ static int nv_close(struct net_device *dev)
spin_lock_irq(&np->lock);
np->in_shutdown = 1;
spin_unlock_irq(&np->lock);
+ netif_poll_disable(dev);
synchronize_irq(dev->irq);
del_timer_sync(&np->oom_kick);
@@ -4076,12 +4176,6 @@ static int nv_close(struct net_device *dev)
if (np->wolenabled)
nv_start_rx(dev);
- /* special op: write back the misordered MAC address - otherwise
- * the next nv_probe would see a wrong address.
- */
- writel(np->orig_mac[0], base + NvRegMacAddrA);
- writel(np->orig_mac[1], base + NvRegMacAddrB);
-
/* FIXME: power down nic */
return 0;
@@ -4094,7 +4188,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
unsigned long addr;
u8 __iomem *base;
int err, i;
- u32 powerstate;
+ u32 powerstate, txreg;
dev = alloc_etherdev(sizeof(struct fe_priv));
err = -ENOMEM;
@@ -4270,6 +4364,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
+ dev->weight = 64;
+#ifdef CONFIG_FORCEDETH_NAPI
+ dev->poll = nv_napi_poll;
+#endif
SET_ETHTOOL_OPS(dev, &ops);
dev->tx_timeout = nv_tx_timeout;
dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
@@ -4281,12 +4379,30 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->orig_mac[0] = readl(base + NvRegMacAddrA);
np->orig_mac[1] = readl(base + NvRegMacAddrB);
- dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
- dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff;
- dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
- dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
- dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
- dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
+ /* check the workaround bit for correct mac address order */
+ txreg = readl(base + NvRegTransmitPoll);
+ if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
+ /* mac address is already in correct order */
+ dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff;
+ dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff;
+ dev->dev_addr[2] = (np->orig_mac[0] >> 16) & 0xff;
+ dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff;
+ dev->dev_addr[4] = (np->orig_mac[1] >> 0) & 0xff;
+ dev->dev_addr[5] = (np->orig_mac[1] >> 8) & 0xff;
+ } else {
+ /* need to reverse mac address to correct order */
+ dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
+ dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff;
+ dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
+ dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
+ dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
+ dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
+ /* set permanent address to be correct aswell */
+ np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
+ (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
+ np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
+ writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+ }
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
if (!is_valid_ether_addr(dev->perm_addr)) {
@@ -4309,6 +4425,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ /* set mac address */
+ nv_copy_mac_to_hw(dev);
+
/* disable WOL */
writel(0, base + NvRegWakeUpFlags);
np->wolenabled = 0;
@@ -4421,9 +4540,17 @@ out:
static void __devexit nv_remove(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
unregister_netdev(dev);
+ /* special op: write back the misordered MAC address - otherwise
+ * the next nv_probe would see a wrong address.
+ */
+ writel(np->orig_mac[0], base + NvRegMacAddrA);
+ writel(np->orig_mac[1], base + NvRegMacAddrB);
+
/* free all structures */
free_rings(dev);
iounmap(get_hwbase(dev));
@@ -4540,7 +4667,7 @@ static struct pci_driver driver = {
static int __init init_nic(void)
{
printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION);
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit exit_nic(void)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index e7d9bf33028..ff5a67d619b 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -111,7 +111,6 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/types.h>
-#include <linux/config.h> /* for CONFIG_PCI */
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/bitops.h>
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 47f6f64d604..415ba8dc94c 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -45,7 +45,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 0ea65c4c6f8..b69776e0095 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -40,7 +40,6 @@
********************************************************************/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/skbuff.h>
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 7bbd447289b..5bff05f9757 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -162,7 +162,7 @@ ixgb_init_module(void)
printk(KERN_INFO "%s\n", ixgb_copyright);
- return pci_module_init(&ixgb_driver);
+ return pci_register_driver(&ixgb_driver);
}
module_init(ixgb_init_module);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 9bdd43ab357..c0c41ca688e 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -271,7 +271,7 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
struct mcp_cmd *buf;
char buf_bytes[sizeof(*buf) + 8];
struct mcp_cmd_response *response = mgp->cmd;
- char __iomem *cmd_addr = mgp->sram + MXGEFW_CMD_OFFSET;
+ char __iomem *cmd_addr = mgp->sram + MXGEFW_ETH_CMD;
u32 dma_low, dma_high, result, value;
int sleep_total = 0;
@@ -404,7 +404,7 @@ static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
buf[4] = htonl(dma_low); /* dummy addr LSW */
buf[5] = htonl(enable); /* enable? */
- submit = mgp->sram + 0xfc01c0;
+ submit = mgp->sram + MXGEFW_BOOT_DUMMY_RDMA;
myri10ge_pio_copy(submit, &buf, sizeof(buf));
for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++)
@@ -600,7 +600,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
buf[5] = htonl(8); /* where to copy to */
buf[6] = htonl(0); /* where to jump to */
- submit = mgp->sram + 0xfc0000;
+ submit = mgp->sram + MXGEFW_BOOT_HANDOFF;
myri10ge_pio_copy(submit, &buf, sizeof(buf));
mb();
@@ -798,12 +798,13 @@ myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
* pages directly and building a fraglist in the near future.
*/
-static inline struct sk_buff *myri10ge_alloc_big(int bytes)
+static inline struct sk_buff *myri10ge_alloc_big(struct net_device *dev,
+ int bytes)
{
struct sk_buff *skb;
unsigned long data, roundup;
- skb = dev_alloc_skb(bytes + 4096 + MXGEFW_PAD);
+ skb = netdev_alloc_skb(dev, bytes + 4096 + MXGEFW_PAD);
if (skb == NULL)
return NULL;
@@ -821,12 +822,13 @@ static inline struct sk_buff *myri10ge_alloc_big(int bytes)
/* Allocate 2x as much space as required and use whichever portion
* does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes)
+static inline struct sk_buff *myri10ge_alloc_small_safe(struct net_device *dev,
+ unsigned int bytes)
{
struct sk_buff *skb;
unsigned long data, boundary;
- skb = dev_alloc_skb(2 * (bytes + MXGEFW_PAD) - 1);
+ skb = netdev_alloc_skb(dev, 2 * (bytes + MXGEFW_PAD) - 1);
if (unlikely(skb == NULL))
return NULL;
@@ -847,12 +849,13 @@ static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes)
/* Allocate just enough space, and verify that the allocated
* space does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small(int bytes)
+static inline struct sk_buff *myri10ge_alloc_small(struct net_device *dev,
+ int bytes)
{
struct sk_buff *skb;
unsigned long roundup, data, end;
- skb = dev_alloc_skb(bytes + 16 + MXGEFW_PAD);
+ skb = netdev_alloc_skb(dev, bytes + 16 + MXGEFW_PAD);
if (unlikely(skb == NULL))
return NULL;
@@ -868,15 +871,17 @@ static inline struct sk_buff *myri10ge_alloc_small(int bytes)
"myri10ge_alloc_small: small skb crossed 4KB boundary\n");
myri10ge_skb_cross_4k = 1;
dev_kfree_skb_any(skb);
- skb = myri10ge_alloc_small_safe(bytes);
+ skb = myri10ge_alloc_small_safe(dev, bytes);
}
return skb;
}
static inline int
-myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes,
- int idx)
+myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct myri10ge_priv *mgp,
+ int bytes, int idx)
{
+ struct net_device *dev = mgp->dev;
+ struct pci_dev *pdev = mgp->pdev;
struct sk_buff *skb;
dma_addr_t bus;
int len, retval = 0;
@@ -884,11 +889,11 @@ myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes,
bytes += VLAN_HLEN; /* account for 802.1q vlan tag */
if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ )
- skb = myri10ge_alloc_big(bytes);
+ skb = myri10ge_alloc_big(dev, bytes);
else if (myri10ge_skb_cross_4k)
- skb = myri10ge_alloc_small_safe(bytes);
+ skb = myri10ge_alloc_small_safe(dev, bytes);
else
- skb = myri10ge_alloc_small(bytes);
+ skb = myri10ge_alloc_small(dev, bytes);
if (unlikely(skb == NULL)) {
rx->alloc_fail++;
@@ -951,7 +956,7 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
unmap_len = pci_unmap_len(&rx->info[idx], len);
/* try to replace the received skb */
- if (myri10ge_getbuf(rx, mgp->pdev, bytes, idx)) {
+ if (myri10ge_getbuf(rx, mgp, bytes, idx)) {
/* drop the frame -- the old skbuf is re-cycled */
mgp->stats.rx_dropped += 1;
return 0;
@@ -968,7 +973,6 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, mgp->dev);
- skb->dev = mgp->dev;
if (mgp->csum_flag) {
if ((skb->protocol == ntohs(ETH_P_IP)) ||
(skb->protocol == ntohs(ETH_P_IPV6))) {
@@ -1439,7 +1443,7 @@ static int myri10ge_allocate_rings(struct net_device *dev)
/* Fill the receive rings */
for (i = 0; i <= mgp->rx_small.mask; i++) {
- status = myri10ge_getbuf(&mgp->rx_small, mgp->pdev,
+ status = myri10ge_getbuf(&mgp->rx_small, mgp,
mgp->small_bytes, i);
if (status) {
printk(KERN_ERR
@@ -1451,8 +1455,7 @@ static int myri10ge_allocate_rings(struct net_device *dev)
for (i = 0; i <= mgp->rx_big.mask; i++) {
status =
- myri10ge_getbuf(&mgp->rx_big, mgp->pdev,
- dev->mtu + ETH_HLEN, i);
+ myri10ge_getbuf(&mgp->rx_big, mgp, dev->mtu + ETH_HLEN, i);
if (status) {
printk(KERN_ERR
"myri10ge: %s: alloced only %d big bufs\n",
@@ -1648,9 +1651,11 @@ static int myri10ge_open(struct net_device *dev)
}
if (mgp->mtrr >= 0) {
- mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + 0x200000;
- mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + 0x300000;
- mgp->rx_big.wc_fifo = (u8 __iomem *) mgp->sram + 0x340000;
+ mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
+ mgp->rx_small.wc_fifo =
+ (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
+ mgp->rx_big.wc_fifo =
+ (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG;
} else {
mgp->tx.wc_fifo = NULL;
mgp->rx_small.wc_fifo = NULL;
@@ -1841,7 +1846,8 @@ myri10ge_submit_req_wc(struct myri10ge_tx_buf *tx,
if (cnt > 0) {
/* pad it to 64 bytes. The src is 64 bytes bigger than it
* needs to be so that we don't overrun it */
- myri10ge_pio_copy(tx->wc_fifo + (cnt << 18), src, 64);
+ myri10ge_pio_copy(tx->wc_fifo + MXGEFW_ETH_SEND_OFFSET(cnt),
+ src, 64);
mb();
}
}
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index 0a6cae6cb18..d7dfaa5f64a 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -91,7 +91,19 @@ struct mcp_kreq_ether_recv {
/* Commands */
-#define MXGEFW_CMD_OFFSET 0xf80000
+#define MXGEFW_BOOT_HANDOFF 0xfc0000
+#define MXGEFW_BOOT_DUMMY_RDMA 0xfc01c0
+
+#define MXGEFW_ETH_CMD 0xf80000
+#define MXGEFW_ETH_SEND_4 0x200000
+#define MXGEFW_ETH_SEND_1 0x240000
+#define MXGEFW_ETH_SEND_2 0x280000
+#define MXGEFW_ETH_SEND_3 0x2c0000
+#define MXGEFW_ETH_RECV_SMALL 0x300000
+#define MXGEFW_ETH_RECV_BIG 0x340000
+
+#define MXGEFW_ETH_SEND(n) (0x200000 + (((n) & 0x03) * 0x40000))
+#define MXGEFW_ETH_SEND_OFFSET(n) (MXGEFW_ETH_SEND(n) - MXGEFW_ETH_SEND_4)
enum myri10ge_mcp_cmd_type {
MXGEFW_CMD_NONE = 0,
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index db0475a1102..9510030feeb 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -3246,7 +3246,7 @@ static int __init natsemi_init_mod (void)
printk(version);
#endif
- return pci_module_init (&natsemi_driver);
+ return pci_register_driver(&natsemi_driver);
}
static void __exit natsemi_exit_mod (void)
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 34bdba9eec7..654b477b570 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -702,7 +702,7 @@ static int __init ne2k_pci_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init (&ne2k_driver);
+ return pci_register_driver(&ne2k_driver);
}
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index b1311ae8267..30ed9a5a40e 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 0e76859c90a..0dedd34804c 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -2178,7 +2178,7 @@ static struct pci_driver driver = {
static int __init ns83820_init(void)
{
printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n");
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit ns83820_exit(void)
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index e0e29396404..e6347620529 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1963,7 +1963,7 @@ static int __init netdrv_init_module (void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init (&netdrv_pci_driver);
+ return pci_register_driver(&netdrv_pci_driver);
}
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 297e9f80536..c54f6a7ebf3 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -771,6 +771,7 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
+ PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202),
PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
@@ -786,8 +787,6 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6, 0xab9be5ef),
- /* this is not specific enough */
- /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 0ecebfc31f0..cc0dcc9bf63 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -654,11 +654,8 @@ static int pcnet_config(struct pcmcia_device *link)
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
if (info->flags & (IS_DL10019|IS_DL10022)) {
- u_char id = inb(dev->base_addr + 0x1a);
dev->do_ioctl = &ei_ioctl;
mii_phy_probe(dev);
- if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
- info->eth_phy = 0;
}
link->dev_node = &info->node;
@@ -821,15 +818,6 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
}
}
-static void mdio_reset(kio_addr_t addr, int phy_id)
-{
- outb_p(0x08, addr);
- outb_p(0x0c, addr);
- outb_p(0x08, addr);
- outb_p(0x0c, addr);
- outb_p(0x00, addr);
-}
-
/*======================================================================
EEPROM access routines for DL10019 and DL10022 based cards
@@ -942,7 +930,8 @@ static void set_misc_reg(struct net_device *dev)
}
if (info->flags & IS_DL10022) {
if (info->flags & HAS_MII) {
- mdio_reset(nic_base + DLINK_GPIO, info->eth_phy);
+ /* Advertise 100F, 100H, 10F, 10H */
+ mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
/* Restart MII autonegotiation */
mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index d50bcb89dd2..5e26fe806e2 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -2978,7 +2978,7 @@ static int __init pcnet32_init_module(void)
tx_start = tx_start_pt;
/* find the PCI devices */
- if (!pci_module_init(&pcnet32_driver))
+ if (!pci_register_driver(&pcnet32_driver))
pcnet32_have_pci = 1;
/* should we find any remaining VLbus devices ? */
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 25e31fb5cb3..b1d8ed40ad9 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index ffd215d9a9b..792716beb05 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
new file mode 100644
index 00000000000..c729aeeb469
--- /dev/null
+++ b/drivers/net/qla3xxx.c
@@ -0,0 +1,3537 @@
+/*
+ * 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/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/init.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.02.00-k36"
+#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)},
+ /* required last entry */
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
+
+/*
+ * 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 * reg, u32 value)
+{
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ writel(value, (u32 *) reg);
+ readl(reg);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return;
+}
+
+static void ql_write_common_reg(struct ql3_adapter *qdev,
+ u32 * reg, u32 value)
+{
+ writel(value, (u32 *) reg);
+ readl(reg);
+ return;
+}
+
+static void ql_write_page0_reg(struct ql3_adapter *qdev,
+ u32 * reg, u32 value)
+{
+ if (qdev->current_page != 0)
+ ql_set_register_page(qdev,0);
+ writel(value, (u32 *) reg);
+ readl(reg);
+ return;
+}
+
+/*
+ * Caller holds hw_lock. Only called during init.
+ */
+static void ql_write_page1_reg(struct ql3_adapter *qdev,
+ u32 * reg, u32 value)
+{
+ if (qdev->current_page != 1)
+ ql_set_register_page(qdev,1);
+ writel(value, (u32 *) reg);
+ readl(reg);
+ return;
+}
+
+/*
+ * Caller holds hw_lock. Only called during init.
+ */
+static void ql_write_page2_reg(struct ql3_adapter *qdev,
+ u32 * reg, u32 value)
+{
+ if (qdev->current_page != 2)
+ ql_set_register_page(qdev,2);
+ writel(value, (u32 *) 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)
+{
+ u64 map;
+ 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 = dev_alloc_skb(qdev->lrg_buffer_len);
+ if (unlikely(!lrg_buf_cb->skb)) {
+ printk(KERN_ERR PFX "%s: failed dev_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);
+ 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_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+ ql_write_common_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_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_DO_1);
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_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_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit);
+ previousBit = dataBit;
+ }
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_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_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit);
+ previousBit = dataBit;
+ }
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_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_common_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_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_FALL);
+ dataBit =
+ (ql_read_common_reg
+ (qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+ data = (data << 1) | dataBit;
+ }
+ *value = (u16) data;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void eeprom_readword(struct ql3_adapter *qdev,
+ u32 eepromAddr, unsigned short *value)
+{
+ fm93c56a_select(qdev);
+ fm93c56a_cmd(qdev, (int)FM93C56A_READ, eepromAddr);
+ fm93c56a_datain(qdev, value);
+ fm93c56a_deselect(qdev);
+}
+
+static void ql_swap_mac_addr(u8 * macAddress)
+{
+#ifdef __BIG_ENDIAN
+ u8 temp;
+ temp = macAddress[0];
+ macAddress[0] = macAddress[1];
+ macAddress[1] = temp;
+ temp = macAddress[2];
+ macAddress[2] = macAddress[3];
+ macAddress[3] = temp;
+ temp = macAddress[4];
+ macAddress[4] = macAddress[5];
+ macAddress[5] = temp;
+#endif
+}
+
+static int ql_get_nvram_params(struct ql3_adapter *qdev)
+{
+ u16 *pEEPROMData;
+ u16 checksum = 0;
+ u32 index;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ pEEPROMData = (u16 *) & qdev->nvram_data;
+ qdev->eeprom_cmd_data = 0;
+ if(ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 10)) {
+ printk(KERN_ERR PFX"%s: Failed ql_sem_spinlock().\n",
+ __func__);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return -1;
+ }
+
+ for (index = 0; index < EEPROM_SIZE; index++) {
+ eeprom_readword(qdev, index, pEEPROMData);
+ checksum += *pEEPROMData;
+ pEEPROMData++;
+ }
+ ql_sem_unlock(qdev, QL_NVRAM_SEM_MASK);
+
+ if (checksum != 0) {
+ printk(KERN_ERR PFX "%s: checksum should be zero, is %x!!\n",
+ qdev->ndev->name, checksum);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return -1;
+ }
+
+ /*
+ * We have a problem with endianness for the MAC addresses
+ * and the two 8-bit values version, and numPorts. We
+ * have to swap them on big endian systems.
+ */
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn0.macAddress);
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn1.macAddress);
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn2.macAddress);
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn3.macAddress);
+ pEEPROMData = (u16 *) & qdev->nvram_data.version;
+ *pEEPROMData = le16_to_cpu(*pEEPROMData);
+
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return checksum;
+}
+
+static const u32 PHYAddr[2] = {
+ PORT0_PHY_ADDRESS, PORT1_PHY_ADDRESS
+};
+
+static int ql_wait_for_mii_ready(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 temp;
+ int count = 1000;
+
+ while (count) {
+ temp = ql_read_page0_reg(qdev, &port_regs->macMIIStatusReg);
+ if (!(temp & MAC_MII_STATUS_BSY))
+ return 0;
+ udelay(10);
+ count--;
+ }
+ return -1;
+}
+
+static void ql_mii_enable_scan_mode(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 scanControl;
+
+ if (qdev->numPorts > 1) {
+ /* Auto scan will cycle through multiple ports */
+ scanControl = MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC;
+ } else {
+ scanControl = MAC_MII_CONTROL_SC;
+ }
+
+ /*
+ * Scan register 1 of PHY/PETBI,
+ * Set up to scan both devices
+ * The autoscan starts from the first register, completes
+ * the last one before rolling over to the first
+ */
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[0] | MII_SCAN_REGISTER);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (scanControl) |
+ ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS) << 16));
+}
+
+static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
+{
+ u8 ret;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ /* See if scan mode is enabled before we turn it off */
+ if (ql_read_page0_reg(qdev, &port_regs->macMIIMgmtControlReg) &
+ (MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC)) {
+ /* Scan is enabled */
+ ret = 1;
+ } else {
+ /* Scan is disabled */
+ ret = 0;
+ }
+
+ /*
+ * When disabling scan mode you must first change the MII register
+ * address
+ */
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[0] | MII_SCAN_REGISTER);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS |
+ MAC_MII_CONTROL_RC) << 16));
+
+ return ret;
+}
+
+static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
+ u16 regAddr, u16 value, u32 mac_index)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u8 scanWasEnabled;
+
+ scanWasEnabled = ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[mac_index] | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
+
+ /* Wait for write to complete 9/10/04 SJP */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to"
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ if (scanWasEnabled)
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
+ u16 * value, u32 mac_index)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u8 scanWasEnabled;
+ u32 temp;
+
+ scanWasEnabled = ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[mac_index] | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16));
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
+
+ /* Wait for the read to complete */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free after issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
+ *value = (u16) temp;
+
+ if (scanWasEnabled)
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ qdev->PHYAddr | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
+
+ /* Wait for write to complete. */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static int ql_mii_read_reg(struct ql3_adapter *qdev, u16 regAddr, u16 *value)
+{
+ u32 temp;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ qdev->PHYAddr | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16));
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
+
+ /* Wait for the read to complete */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
+ *value = (u16) temp;
+
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static void ql_petbi_reset(struct ql3_adapter *qdev)
+{
+ ql_mii_write_reg(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET);
+}
+
+static void ql_petbi_start_neg(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ /* Enable Auto-negotiation sense */
+ ql_mii_read_reg(qdev, PETBI_TBI_CTRL, &reg);
+ reg |= PETBI_TBI_AUTO_SENSE;
+ ql_mii_write_reg(qdev, PETBI_TBI_CTRL, reg);
+
+ ql_mii_write_reg(qdev, PETBI_NEG_ADVER,
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX);
+
+ ql_mii_write_reg(qdev, PETBI_CONTROL_REG,
+ PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
+ PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000);
+
+}
+
+static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
+ mac_index);
+}
+
+static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ u16 reg;
+
+ /* Enable Auto-negotiation sense */
+ ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, mac_index);
+ reg |= PETBI_TBI_AUTO_SENSE;
+ ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index);
+
+ ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
+
+ ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
+ PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
+ PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000,
+ mac_index);
+}
+
+static void ql_petbi_init(struct ql3_adapter *qdev)
+{
+ ql_petbi_reset(qdev);
+ ql_petbi_start_neg(qdev);
+}
+
+static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_petbi_reset_ex(qdev, mac_index);
+ ql_petbi_start_neg_ex(qdev, mac_index);
+}
+
+static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, PETBI_NEG_PARTNER, &reg) < 0)
+ return 0;
+
+ return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
+}
+
+static int ql_phy_get_speed(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+ return 0;
+
+ reg = (((reg & 0x18) >> 3) & 3);
+
+ if (reg == 2)
+ return SPEED_1000;
+ else if (reg == 1)
+ return SPEED_100;
+ else if (reg == 0)
+ return SPEED_10;
+ else
+ return -1;
+}
+
+static int ql_is_full_dup(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+ return 0;
+
+ return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+}
+
+static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, PHY_NEG_PARTNER, &reg) < 0)
+ return 0;
+
+ return (reg & PHY_NEG_PAUSE) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_PE | (MAC_CONFIG_REG_PE << 16));
+ else
+ value = (MAC_CONFIG_REG_PE << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_SR | (MAC_CONFIG_REG_SR << 16));
+ else
+ value = (MAC_CONFIG_REG_SR << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_GM | (MAC_CONFIG_REG_GM << 16));
+ else
+ value = (MAC_CONFIG_REG_GM << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_FD | (MAC_CONFIG_REG_FD << 16));
+ else
+ value = (MAC_CONFIG_REG_FD << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value =
+ ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) |
+ ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16));
+ else
+ value = ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_is_fiber(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_SM0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_SM1;
+ break;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ return (temp & bitToCheck) != 0;
+}
+
+static int ql_is_auto_cfg(struct ql3_adapter *qdev)
+{
+ u16 reg;
+ ql_mii_read_reg(qdev, 0x00, &reg);
+ return (reg & 0x1000) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_is_auto_neg_complete(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_AC0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_AC1;
+ break;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (temp & bitToCheck) {
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX
+ "%s: Auto-Negotiate complete.\n",
+ qdev->ndev->name);
+ return 1;
+ } else {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Auto-Negotiate incomplete.\n",
+ qdev->ndev->name);
+ return 0;
+ }
+}
+
+/*
+ * ql_is_neg_pause() returns 1 if pause was negotiated to be on
+ */
+static int ql_is_neg_pause(struct ql3_adapter *qdev)
+{
+ if (ql_is_fiber(qdev))
+ return ql_is_petbi_neg_pause(qdev);
+ else
+ return ql_is_phy_neg_pause(qdev);
+}
+
+static int ql_auto_neg_error(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_AE0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_AE1;
+ break;
+ }
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ return (temp & bitToCheck) != 0;
+}
+
+static u32 ql_get_link_speed(struct ql3_adapter *qdev)
+{
+ if (ql_is_fiber(qdev))
+ return SPEED_1000;
+ else
+ return ql_phy_get_speed(qdev);
+}
+
+static int ql_is_link_full_dup(struct ql3_adapter *qdev)
+{
+ if (ql_is_fiber(qdev))
+ return 1;
+ else
+ return ql_is_full_dup(qdev);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_link_down_detect(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = ISP_CONTROL_LINK_DN_0;
+ break;
+ case 1:
+ bitToCheck = ISP_CONTROL_LINK_DN_1;
+ break;
+ }
+
+ temp =
+ ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
+ return (temp & bitToCheck) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ switch (qdev->mac_index) {
+ case 0:
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.ispControlStatus,
+ (ISP_CONTROL_LINK_DN_0) |
+ (ISP_CONTROL_LINK_DN_0 << 16));
+ break;
+
+ case 1:
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.ispControlStatus,
+ (ISP_CONTROL_LINK_DN_1) |
+ (ISP_CONTROL_LINK_DN_1 << 16));
+ break;
+
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
+ u32 mac_index)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_F1_ENABLED;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_F3_ENABLED;
+ break;
+ default:
+ break;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (temp & bitToCheck) {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: is not link master.\n", qdev->ndev->name);
+ return 0;
+ } else {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: is link master.\n", qdev->ndev->name);
+ return 1;
+ }
+}
+
+static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
+}
+
+static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ u16 reg;
+
+ ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
+ PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
+
+ ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, mac_index);
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
+ mac_index);
+}
+
+static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_phy_reset_ex(qdev, mac_index);
+ ql_phy_start_neg_ex(qdev, mac_index);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static u32 ql_get_link_state(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp, linkState;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_UP0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_UP1;
+ break;
+ }
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (temp & bitToCheck) {
+ linkState = LS_UP;
+ } else {
+ linkState = LS_DOWN;
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Link is down.\n", qdev->ndev->name);
+ }
+ return linkState;
+}
+
+static int ql_port_start(struct ql3_adapter *qdev)
+{
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return -1;
+
+ if (ql_is_fiber(qdev)) {
+ ql_petbi_init(qdev);
+ } else {
+ /* Copper port */
+ ql_phy_init_ex(qdev, qdev->mac_index);
+ }
+
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ return 0;
+}
+
+static int ql_finish_auto_neg(struct ql3_adapter *qdev)
+{
+
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return -1;
+
+ if (!ql_auto_neg_error(qdev)) {
+ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ /* configure the MAC */
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Configuring link.\n",
+ qdev->ndev->
+ name);
+ ql_mac_cfg_soft_reset(qdev, 1);
+ ql_mac_cfg_gig(qdev,
+ (ql_get_link_speed
+ (qdev) ==
+ SPEED_1000));
+ ql_mac_cfg_full_dup(qdev,
+ ql_is_link_full_dup
+ (qdev));
+ ql_mac_cfg_pause(qdev,
+ ql_is_neg_pause
+ (qdev));
+ ql_mac_cfg_soft_reset(qdev, 0);
+
+ /* enable the MAC */
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Enabling mac.\n",
+ qdev->ndev->
+ name);
+ ql_mac_enable(qdev, 1);
+ }
+
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Change port_link_state LS_DOWN to LS_UP.\n",
+ qdev->ndev->name);
+ qdev->port_link_state = LS_UP;
+ netif_start_queue(qdev->ndev);
+ netif_carrier_on(qdev->ndev);
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX
+ "%s: Link is up at %d Mbps, %s duplex.\n",
+ qdev->ndev->name,
+ ql_get_link_speed(qdev),
+ ql_is_link_full_dup(qdev)
+ ? "full" : "half");
+
+ } else { /* Remote error detected */
+
+ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Remote error detected. "
+ "Calling ql_port_start().\n",
+ qdev->ndev->
+ name);
+ /*
+ * ql_port_start() is shared code and needs
+ * to lock the PHY on it's own.
+ */
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ if(ql_port_start(qdev)) {/* Restart port */
+ return -1;
+ } else
+ return 0;
+ }
+ }
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ return 0;
+}
+
+static void ql_link_state_machine(struct ql3_adapter *qdev)
+{
+ u32 curr_link_state;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ curr_link_state = ql_get_link_state(qdev);
+
+ if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX
+ "%s: Reset in progress, skip processing link "
+ "state.\n", qdev->ndev->name);
+ return;
+ }
+
+ switch (qdev->port_link_state) {
+ default:
+ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ ql_port_start(qdev);
+ }
+ qdev->port_link_state = LS_DOWN;
+ /* Fall Through */
+
+ case LS_DOWN:
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: port_link_state = LS_DOWN.\n",
+ qdev->ndev->name);
+ if (curr_link_state == LS_UP) {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: curr_link_state = LS_UP.\n",
+ qdev->ndev->name);
+ if (ql_is_auto_neg_complete(qdev))
+ ql_finish_auto_neg(qdev);
+
+ if (qdev->port_link_state == LS_UP)
+ ql_link_down_detect_clear(qdev);
+
+ }
+ break;
+
+ case LS_UP:
+ /*
+ * See if the link is currently down or went down and came
+ * back up
+ */
+ if ((curr_link_state == LS_DOWN) || ql_link_down_detect(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX "%s: Link is down.\n",
+ qdev->ndev->name);
+ qdev->port_link_state = LS_DOWN;
+ }
+ break;
+ }
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+}
+
+/*
+ * Caller must take hw_lock and QL_PHY_GIO_SEM.
+ */
+static void ql_get_phy_owner(struct ql3_adapter *qdev)
+{
+ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ set_bit(QL_LINK_MASTER,&qdev->flags);
+ else
+ clear_bit(QL_LINK_MASTER,&qdev->flags);
+}
+
+/*
+ * Caller must take hw_lock and QL_PHY_GIO_SEM.
+ */
+static void ql_init_scan_mode(struct ql3_adapter *qdev)
+{
+ ql_mii_enable_scan_mode(qdev);
+
+ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ ql_petbi_init_ex(qdev, qdev->mac_index);
+ } else {
+ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ ql_phy_init_ex(qdev, qdev->mac_index);
+ }
+}
+
+/*
+ * MII_Setup needs to be called before taking the PHY out of reset so that the
+ * management interface clock speed can be set properly. It would be better if
+ * we had a way to disable MDC until after the PHY is out of reset, but we
+ * don't have that capability.
+ */
+static int ql_mii_setup(struct ql3_adapter *qdev)
+{
+ u32 reg;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return -1;
+
+ /* Divide 125MHz clock by 28 to meet PHY timing requirements */
+ reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ reg | ((MAC_MII_CONTROL_CLK_SEL_MASK) << 16));
+
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ return 0;
+}
+
+static u32 ql_supported_modes(struct ql3_adapter *qdev)
+{
+ u32 supported;
+
+ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+ | SUPPORTED_Autoneg;
+ } else {
+ supported = SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_TP;
+ }
+
+ return supported;
+}
+
+static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
+{
+ int status;
+ unsigned long hw_flags;
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return 0;
+ status = ql_is_auto_cfg(qdev);
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return status;
+}
+
+static u32 ql_get_speed(struct ql3_adapter *qdev)
+{
+ u32 status;
+ unsigned long hw_flags;
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return 0;
+ status = ql_get_link_speed(qdev);
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return status;
+}
+
+static int ql_get_full_dup(struct ql3_adapter *qdev)
+{
+ int status;
+ unsigned long hw_flags;
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return 0;
+ status = ql_is_link_full_dup(qdev);
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return status;
+}
+
+
+static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = ql_supported_modes(qdev);
+
+ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ ecmd->port = PORT_FIBRE;
+ } else {
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = qdev->PHYAddr;
+ }
+ ecmd->advertising = ql_supported_modes(qdev);
+ ecmd->autoneg = ql_get_auto_cfg_status(qdev);
+ ecmd->speed = ql_get_speed(qdev);
+ ecmd->duplex = ql_get_full_dup(qdev);
+ return 0;
+}
+
+static void ql_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ strncpy(drvinfo->driver, ql3xxx_driver_name, 32);
+ strncpy(drvinfo->version, ql3xxx_driver_version, 32);
+ strncpy(drvinfo->fw_version, "N/A", 32);
+ strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+ drvinfo->n_stats = 0;
+ drvinfo->testinfo_len = 0;
+ drvinfo->regdump_len = 0;
+ drvinfo->eedump_len = 0;
+}
+
+static u32 ql_get_msglevel(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ return qdev->msg_enable;
+}
+
+static void ql_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ qdev->msg_enable = value;
+}
+
+static struct ethtool_ops ql3xxx_ethtool_ops = {
+ .get_settings = ql_get_settings,
+ .get_drvinfo = ql_get_drvinfo,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = ql_get_msglevel,
+ .set_msglevel = ql_set_msglevel,
+};
+
+static int ql_populate_free_queue(struct ql3_adapter *qdev)
+{
+ struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
+ u64 map;
+
+ while (lrg_buf_cb) {
+ if (!lrg_buf_cb->skb) {
+ lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ if (unlikely(!lrg_buf_cb->skb)) {
+ printk(KERN_DEBUG PFX
+ "%s: Failed dev_alloc_skb().\n",
+ qdev->ndev->name);
+ break;
+ } 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);
+ 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_skb_check;
+ if (!qdev->lrg_buf_skb_check)
+ return 1;
+ }
+ }
+ lrg_buf_cb = lrg_buf_cb->next;
+ }
+ return 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
+{
+ struct bufq_addr_element *lrg_buf_q_ele;
+ int i;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+ if ((qdev->lrg_buf_free_count >= 8)
+ && (qdev->lrg_buf_release_cnt >= 16)) {
+
+ if (qdev->lrg_buf_skb_check)
+ if (!ql_populate_free_queue(qdev))
+ return;
+
+ lrg_buf_q_ele = qdev->lrg_buf_next_free;
+
+ while ((qdev->lrg_buf_release_cnt >= 16)
+ && (qdev->lrg_buf_free_count >= 8)) {
+
+ for (i = 0; i < 8; i++) {
+ lrg_buf_cb =
+ ql_get_from_lrg_buf_free_list(qdev);
+ lrg_buf_q_ele->addr_high =
+ lrg_buf_cb->buf_phy_addr_high;
+ lrg_buf_q_ele->addr_low =
+ lrg_buf_cb->buf_phy_addr_low;
+ lrg_buf_q_ele++;
+
+ qdev->lrg_buf_release_cnt--;
+ }
+
+ qdev->lrg_buf_q_producer_index++;
+
+ if (qdev->lrg_buf_q_producer_index == NUM_LBUFQ_ENTRIES)
+ qdev->lrg_buf_q_producer_index = 0;
+
+ if (qdev->lrg_buf_q_producer_index ==
+ (NUM_LBUFQ_ENTRIES - 1)) {
+ lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr;
+ }
+ }
+
+ qdev->lrg_buf_next_free = lrg_buf_q_ele;
+
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.
+ rxLargeQProducerIndex,
+ qdev->lrg_buf_q_producer_index);
+ }
+}
+
+static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
+ struct ob_mac_iocb_rsp *mac_rsp)
+{
+ struct ql_tx_buf_cb *tx_cb;
+
+ tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(tx_cb, mapaddr),
+ pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(tx_cb->skb);
+ qdev->stats.tx_packets++;
+ qdev->stats.tx_bytes += tx_cb->skb->len;
+ tx_cb->skb = NULL;
+ atomic_inc(&qdev->tx_count);
+}
+
+static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
+ struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
+{
+ long int offset;
+ u32 lrg_buf_phy_addr_low = 0;
+ struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
+ struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
+ u32 *curr_ial_ptr;
+ struct sk_buff *skb;
+ u16 length = le16_to_cpu(ib_mac_rsp_ptr->length);
+
+ /*
+ * Get the inbound address list (small buffer).
+ */
+ offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
+ if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
+ qdev->small_buf_index = 0;
+
+ curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
+ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
+ qdev->small_buf_release_cnt++;
+
+ /* start of first buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+
+ /* start of second buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
+
+ /*
+ * Second buffer gets sent up the stack.
+ */
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ skb = lrg_buf_cb2->skb;
+
+ qdev->stats.rx_packets++;
+ qdev->stats.rx_bytes += length;
+
+ skb_put(skb, length);
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(lrg_buf_cb2, mapaddr),
+ pci_unmap_len(lrg_buf_cb2, maplen),
+ PCI_DMA_FROMDEVICE);
+ prefetch(skb->data);
+ skb->dev = qdev->ndev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->protocol = eth_type_trans(skb, qdev->ndev);
+
+ netif_receive_skb(skb);
+ qdev->ndev->last_rx = jiffies;
+ lrg_buf_cb2->skb = NULL;
+
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
+}
+
+static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
+ struct ib_ip_iocb_rsp *ib_ip_rsp_ptr)
+{
+ long int offset;
+ u32 lrg_buf_phy_addr_low = 0;
+ struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
+ struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
+ u32 *curr_ial_ptr;
+ struct sk_buff *skb1, *skb2;
+ struct net_device *ndev = qdev->ndev;
+ u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
+ u16 size = 0;
+
+ /*
+ * Get the inbound address list (small buffer).
+ */
+
+ offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
+ if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
+ qdev->small_buf_index = 0;
+ curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
+ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
+ qdev->small_buf_release_cnt++;
+
+ /* start of first buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ skb1 = lrg_buf_cb1->skb;
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+
+ /* start of second buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ skb2 = lrg_buf_cb2->skb;
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+
+ qdev->stats.rx_packets++;
+ qdev->stats.rx_bytes += length;
+
+ /*
+ * Copy the ethhdr from first buffer to second. This
+ * is necessary for IP completions.
+ */
+ if (*((u16 *) skb1->data) != 0xFFFF)
+ size = VLAN_ETH_HLEN;
+ else
+ size = ETH_HLEN;
+
+ skb_put(skb2, length); /* Just the second buffer length here. */
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(lrg_buf_cb2, mapaddr),
+ pci_unmap_len(lrg_buf_cb2, maplen),
+ PCI_DMA_FROMDEVICE);
+ prefetch(skb2->data);
+
+ memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+ skb2->dev = qdev->ndev;
+ skb2->ip_summed = CHECKSUM_NONE;
+ skb2->protocol = eth_type_trans(skb2, qdev->ndev);
+
+ netif_receive_skb(skb2);
+ ndev->last_rx = jiffies;
+ lrg_buf_cb2->skb = NULL;
+
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
+}
+
+static int ql_tx_rx_clean(struct ql3_adapter *qdev,
+ int *tx_cleaned, int *rx_cleaned, int work_to_do)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct net_rsp_iocb *net_rsp;
+ struct net_device *ndev = qdev->ndev;
+ unsigned long hw_flags;
+
+ /* While there are entries in the completion queue. */
+ while ((cpu_to_le32(*(qdev->prsp_producer_index)) !=
+ qdev->rsp_consumer_index) && (*rx_cleaned < work_to_do)) {
+
+ net_rsp = qdev->rsp_current;
+ switch (net_rsp->opcode) {
+
+ case OPCODE_OB_MAC_IOCB_FN0:
+ case OPCODE_OB_MAC_IOCB_FN2:
+ ql_process_mac_tx_intr(qdev, (struct ob_mac_iocb_rsp *)
+ net_rsp);
+ (*tx_cleaned)++;
+ break;
+
+ case OPCODE_IB_MAC_IOCB:
+ ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
+ net_rsp);
+ (*rx_cleaned)++;
+ break;
+
+ case OPCODE_IB_IP_IOCB:
+ ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
+ net_rsp);
+ (*rx_cleaned)++;
+ break;
+ default:
+ {
+ u32 *tmp = (u32 *) net_rsp;
+ printk(KERN_ERR PFX
+ "%s: Hit default case, not "
+ "handled!\n"
+ " dropping the packet, opcode = "
+ "%x.\n",
+ ndev->name, net_rsp->opcode);
+ printk(KERN_ERR PFX
+ "0x%08lx 0x%08lx 0x%08lx 0x%08lx \n",
+ (unsigned long int)tmp[0],
+ (unsigned long int)tmp[1],
+ (unsigned long int)tmp[2],
+ (unsigned long int)tmp[3]);
+ }
+ }
+
+ qdev->rsp_consumer_index++;
+
+ if (qdev->rsp_consumer_index == NUM_RSP_Q_ENTRIES) {
+ qdev->rsp_consumer_index = 0;
+ qdev->rsp_current = qdev->rsp_q_virt_addr;
+ } else {
+ qdev->rsp_current++;
+ }
+ }
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ ql_update_lrg_bufq_prod_index(qdev);
+
+ if (qdev->small_buf_release_cnt >= 16) {
+ while (qdev->small_buf_release_cnt >= 16) {
+ qdev->small_buf_q_producer_index++;
+
+ if (qdev->small_buf_q_producer_index ==
+ NUM_SBUFQ_ENTRIES)
+ qdev->small_buf_q_producer_index = 0;
+ qdev->small_buf_release_cnt -= 8;
+ }
+
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.
+ rxSmallQProducerIndex,
+ qdev->small_buf_q_producer_index);
+ }
+
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.rspQConsumerIndex,
+ qdev->rsp_consumer_index);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ if (unlikely(netif_queue_stopped(qdev->ndev))) {
+ if (netif_queue_stopped(qdev->ndev) &&
+ (atomic_read(&qdev->tx_count) > (NUM_REQ_Q_ENTRIES / 4)))
+ netif_wake_queue(qdev->ndev);
+ }
+
+ return *tx_cleaned + *rx_cleaned;
+}
+
+static int ql_poll(struct net_device *ndev, int *budget)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ int work_to_do = min(*budget, ndev->quota);
+ int rx_cleaned = 0, tx_cleaned = 0;
+
+ if (!netif_carrier_ok(ndev))
+ goto quit_polling;
+
+ ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do);
+ *budget -= rx_cleaned;
+ ndev->quota -= rx_cleaned;
+
+ if ((!tx_cleaned && !rx_cleaned) || !netif_running(ndev)) {
+quit_polling:
+ netif_rx_complete(ndev);
+ ql_enable_interrupts(qdev);
+ return 0;
+ }
+ return 1;
+}
+
+static irqreturn_t ql3xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+ struct net_device *ndev = dev_id;
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value;
+ int handled = 1;
+ u32 var;
+
+ port_regs = qdev->mem_map_registers;
+
+ value =
+ ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+
+ if (value & (ISP_CONTROL_FE | ISP_CONTROL_RI)) {
+ spin_lock(&qdev->adapter_lock);
+ netif_stop_queue(qdev->ndev);
+ netif_carrier_off(qdev->ndev);
+ ql_disable_interrupts(qdev);
+ qdev->port_link_state = LS_DOWN;
+ set_bit(QL_RESET_ACTIVE,&qdev->flags) ;
+
+ if (value & ISP_CONTROL_FE) {
+ /*
+ * Chip Fatal Error.
+ */
+ var =
+ ql_read_page0_reg_l(qdev,
+ &port_regs->PortFatalErrStatus);
+ printk(KERN_WARNING PFX
+ "%s: Resetting chip. PortFatalErrStatus "
+ "register = 0x%x\n", ndev->name, var);
+ set_bit(QL_RESET_START,&qdev->flags) ;
+ } else {
+ /*
+ * Soft Reset Requested.
+ */
+ set_bit(QL_RESET_PER_SCSI,&qdev->flags) ;
+ printk(KERN_ERR PFX
+ "%s: Another function issued a reset to the "
+ "chip. ISR value = %x.\n", ndev->name, value);
+ }
+ queue_work(qdev->workqueue, &qdev->reset_work);
+ spin_unlock(&qdev->adapter_lock);
+ } else if (value & ISP_IMR_DISABLE_CMPL_INT) {
+ ql_disable_interrupts(qdev);
+ if (likely(netif_rx_schedule_prep(ndev)))
+ __netif_rx_schedule(ndev);
+ else
+ ql_enable_interrupts(qdev);
+ } else {
+ return IRQ_NONE;
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql_tx_buf_cb *tx_cb;
+ struct ob_mac_iocb_req *mac_iocb_ptr;
+ u64 map;
+
+ if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
+ if (!netif_queue_stopped(ndev))
+ netif_stop_queue(ndev);
+ return NETDEV_TX_BUSY;
+ }
+ tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+ mac_iocb_ptr = tx_cb->queue_entry;
+ memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
+ mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
+ mac_iocb_ptr->flags |= qdev->mb_bit_mask;
+ mac_iocb_ptr->transaction_id = qdev->req_producer_index;
+ mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+ tx_cb->skb = skb;
+ map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
+ mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
+ mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
+ pci_unmap_addr_set(tx_cb, mapaddr, map);
+ pci_unmap_len_set(tx_cb, maplen, skb->len);
+ atomic_dec(&qdev->tx_count);
+
+ qdev->req_producer_index++;
+ if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
+ qdev->req_producer_index = 0;
+ wmb();
+ ql_write_common_reg_l(qdev,
+ (u32 *) & port_regs->CommonRegs.reqQProducerIndex,
+ qdev->req_producer_index);
+
+ ndev->trans_start = jiffies;
+ if (netif_msg_tx_queued(qdev))
+ printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
+ ndev->name, qdev->req_producer_index, skb->len);
+
+ return NETDEV_TX_OK;
+}
+static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
+{
+ qdev->req_q_size =
+ (u32) (NUM_REQ_Q_ENTRIES * sizeof(struct ob_mac_iocb_req));
+
+ qdev->req_q_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ (size_t) qdev->req_q_size,
+ &qdev->req_q_phy_addr);
+
+ if ((qdev->req_q_virt_addr == NULL) ||
+ LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) {
+ printk(KERN_ERR PFX "%s: reqQ failed.\n",
+ qdev->ndev->name);
+ return -ENOMEM;
+ }
+
+ qdev->rsp_q_size = NUM_RSP_Q_ENTRIES * sizeof(struct net_rsp_iocb);
+
+ qdev->rsp_q_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ (size_t) qdev->rsp_q_size,
+ &qdev->rsp_q_phy_addr);
+
+ if ((qdev->rsp_q_virt_addr == NULL) ||
+ LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) {
+ printk(KERN_ERR PFX
+ "%s: rspQ allocation failed\n",
+ qdev->ndev->name);
+ pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size,
+ qdev->req_q_virt_addr,
+ qdev->req_q_phy_addr);
+ return -ENOMEM;
+ }
+
+ set_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+
+ return 0;
+}
+
+static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev)
+{
+ if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: Already done.\n", qdev->ndev->name);
+ return;
+ }
+
+ pci_free_consistent(qdev->pdev,
+ qdev->req_q_size,
+ qdev->req_q_virt_addr, qdev->req_q_phy_addr);
+
+ qdev->req_q_virt_addr = NULL;
+
+ pci_free_consistent(qdev->pdev,
+ qdev->rsp_q_size,
+ qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr);
+
+ qdev->rsp_q_virt_addr = NULL;
+
+ clear_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+}
+
+static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
+{
+ /* Create Large Buffer Queue */
+ qdev->lrg_buf_q_size =
+ NUM_LBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+ if (qdev->lrg_buf_q_size < PAGE_SIZE)
+ qdev->lrg_buf_q_alloc_size = PAGE_SIZE;
+ else
+ qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
+
+ qdev->lrg_buf_q_alloc_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ qdev->lrg_buf_q_alloc_size,
+ &qdev->lrg_buf_q_alloc_phy_addr);
+
+ if (qdev->lrg_buf_q_alloc_virt_addr == NULL) {
+ printk(KERN_ERR PFX
+ "%s: lBufQ failed\n", qdev->ndev->name);
+ return -ENOMEM;
+ }
+ qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr;
+ qdev->lrg_buf_q_phy_addr = qdev->lrg_buf_q_alloc_phy_addr;
+
+ /* Create Small Buffer Queue */
+ qdev->small_buf_q_size =
+ NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+ if (qdev->small_buf_q_size < PAGE_SIZE)
+ qdev->small_buf_q_alloc_size = PAGE_SIZE;
+ else
+ qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2;
+
+ qdev->small_buf_q_alloc_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ qdev->small_buf_q_alloc_size,
+ &qdev->small_buf_q_alloc_phy_addr);
+
+ if (qdev->small_buf_q_alloc_virt_addr == NULL) {
+ printk(KERN_ERR PFX
+ "%s: Small Buffer Queue allocation failed.\n",
+ qdev->ndev->name);
+ pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size,
+ qdev->lrg_buf_q_alloc_virt_addr,
+ qdev->lrg_buf_q_alloc_phy_addr);
+ return -ENOMEM;
+ }
+
+ qdev->small_buf_q_virt_addr = qdev->small_buf_q_alloc_virt_addr;
+ qdev->small_buf_q_phy_addr = qdev->small_buf_q_alloc_phy_addr;
+ set_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+ return 0;
+}
+
+static void ql_free_buffer_queues(struct ql3_adapter *qdev)
+{
+ if (!test_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: Already done.\n", qdev->ndev->name);
+ return;
+ }
+
+ pci_free_consistent(qdev->pdev,
+ qdev->lrg_buf_q_alloc_size,
+ qdev->lrg_buf_q_alloc_virt_addr,
+ qdev->lrg_buf_q_alloc_phy_addr);
+
+ qdev->lrg_buf_q_virt_addr = NULL;
+
+ pci_free_consistent(qdev->pdev,
+ qdev->small_buf_q_alloc_size,
+ qdev->small_buf_q_alloc_virt_addr,
+ qdev->small_buf_q_alloc_phy_addr);
+
+ qdev->small_buf_q_virt_addr = NULL;
+
+ clear_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+}
+
+static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
+{
+ int i;
+ struct bufq_addr_element *small_buf_q_entry;
+
+ /* Currently we allocate on one of memory and use it for smallbuffers */
+ qdev->small_buf_total_size =
+ (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
+ QL_SMALL_BUFFER_SIZE);
+
+ qdev->small_buf_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ qdev->small_buf_total_size,
+ &qdev->small_buf_phy_addr);
+
+ if (qdev->small_buf_virt_addr == NULL) {
+ printk(KERN_ERR PFX
+ "%s: Failed to get small buffer memory.\n",
+ qdev->ndev->name);
+ return -ENOMEM;
+ }
+
+ qdev->small_buf_phy_addr_low = LS_64BITS(qdev->small_buf_phy_addr);
+ qdev->small_buf_phy_addr_high = MS_64BITS(qdev->small_buf_phy_addr);
+
+ small_buf_q_entry = qdev->small_buf_q_virt_addr;
+
+ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low;
+
+ /* Initialize the small buffer queue. */
+ for (i = 0; i < (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES); i++) {
+ small_buf_q_entry->addr_high =
+ cpu_to_le32(qdev->small_buf_phy_addr_high);
+ small_buf_q_entry->addr_low =
+ cpu_to_le32(qdev->small_buf_phy_addr_low +
+ (i * QL_SMALL_BUFFER_SIZE));
+ small_buf_q_entry++;
+ }
+ qdev->small_buf_index = 0;
+ set_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags);
+ return 0;
+}
+
+static void ql_free_small_buffers(struct ql3_adapter *qdev)
+{
+ if (!test_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: Already done.\n", qdev->ndev->name);
+ return;
+ }
+ if (qdev->small_buf_virt_addr != NULL) {
+ pci_free_consistent(qdev->pdev,
+ qdev->small_buf_total_size,
+ qdev->small_buf_virt_addr,
+ qdev->small_buf_phy_addr);
+
+ qdev->small_buf_virt_addr = NULL;
+ }
+}
+
+static void ql_free_large_buffers(struct ql3_adapter *qdev)
+{
+ int i = 0;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+
+ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ lrg_buf_cb = &qdev->lrg_buf[i];
+ if (lrg_buf_cb->skb) {
+ dev_kfree_skb(lrg_buf_cb->skb);
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(lrg_buf_cb, mapaddr),
+ pci_unmap_len(lrg_buf_cb, maplen),
+ PCI_DMA_FROMDEVICE);
+ memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+ } else {
+ break;
+ }
+ }
+}
+
+static void ql_init_large_buffers(struct ql3_adapter *qdev)
+{
+ int i;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+ struct bufq_addr_element *buf_addr_ele = qdev->lrg_buf_q_virt_addr;
+
+ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ lrg_buf_cb = &qdev->lrg_buf[i];
+ buf_addr_ele->addr_high = lrg_buf_cb->buf_phy_addr_high;
+ buf_addr_ele->addr_low = lrg_buf_cb->buf_phy_addr_low;
+ buf_addr_ele++;
+ }
+ qdev->lrg_buf_index = 0;
+ qdev->lrg_buf_skb_check = 0;
+}
+
+static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
+{
+ int i;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+ struct sk_buff *skb;
+ u64 map;
+
+ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ printk(KERN_ERR PFX
+ "%s: large buff alloc failed, "
+ "for %d bytes at index %d.\n",
+ qdev->ndev->name,
+ qdev->lrg_buffer_len * 2, i);
+ ql_free_large_buffers(qdev);
+ return -ENOMEM;
+ } else {
+
+ lrg_buf_cb = &qdev->lrg_buf[i];
+ memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+ lrg_buf_cb->index = i;
+ lrg_buf_cb->skb = skb;
+ /*
+ * We save some space to copy the ethhdr from first
+ * buffer
+ */
+ skb_reserve(skb, QL_HEADER_SPACE);
+ map = pci_map_single(qdev->pdev,
+ skb->data,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE,
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+ pci_unmap_len_set(lrg_buf_cb, maplen,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE);
+ 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));
+ }
+ }
+ return 0;
+}
+
+static void ql_create_send_free_list(struct ql3_adapter *qdev)
+{
+ struct ql_tx_buf_cb *tx_cb;
+ int i;
+ struct ob_mac_iocb_req *req_q_curr =
+ qdev->req_q_virt_addr;
+
+ /* Create free list of transmit buffers */
+ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ tx_cb = &qdev->tx_buf[i];
+ tx_cb->skb = NULL;
+ tx_cb->queue_entry = req_q_curr;
+ req_q_curr++;
+ }
+}
+
+static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
+{
+ if (qdev->ndev->mtu == NORMAL_MTU_SIZE)
+ qdev->lrg_buffer_len = NORMAL_MTU_SIZE;
+ else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
+ qdev->lrg_buffer_len = JUMBO_MTU_SIZE;
+ } else {
+ printk(KERN_ERR PFX
+ "%s: Invalid mtu size. Only 1500 and 9000 are accepted.\n",
+ qdev->ndev->name);
+ return -ENOMEM;
+ }
+ qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE;
+ qdev->max_frame_size =
+ (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
+
+ /*
+ * First allocate a page of shared memory and use it for shadow
+ * locations of Network Request Queue Consumer Address Register and
+ * Network Completion Queue Producer Index Register
+ */
+ qdev->shadow_reg_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ PAGE_SIZE, &qdev->shadow_reg_phy_addr);
+
+ if (qdev->shadow_reg_virt_addr != NULL) {
+ qdev->preq_consumer_index = (u16 *) qdev->shadow_reg_virt_addr;
+ qdev->req_consumer_index_phy_addr_high =
+ MS_64BITS(qdev->shadow_reg_phy_addr);
+ qdev->req_consumer_index_phy_addr_low =
+ LS_64BITS(qdev->shadow_reg_phy_addr);
+
+ qdev->prsp_producer_index =
+ (u32 *) (((u8 *) qdev->preq_consumer_index) + 8);
+ qdev->rsp_producer_index_phy_addr_high =
+ qdev->req_consumer_index_phy_addr_high;
+ qdev->rsp_producer_index_phy_addr_low =
+ qdev->req_consumer_index_phy_addr_low + 8;
+ } else {
+ printk(KERN_ERR PFX
+ "%s: shadowReg Alloc failed.\n", qdev->ndev->name);
+ return -ENOMEM;
+ }
+
+ if (ql_alloc_net_req_rsp_queues(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_net_req_rsp_queues failed.\n",
+ qdev->ndev->name);
+ goto err_req_rsp;
+ }
+
+ if (ql_alloc_buffer_queues(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_buffer_queues failed.\n",
+ qdev->ndev->name);
+ goto err_buffer_queues;
+ }
+
+ if (ql_alloc_small_buffers(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_small_buffers failed\n", qdev->ndev->name);
+ goto err_small_buffers;
+ }
+
+ if (ql_alloc_large_buffers(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_large_buffers failed\n", qdev->ndev->name);
+ goto err_small_buffers;
+ }
+
+ /* Initialize the large buffer queue. */
+ ql_init_large_buffers(qdev);
+ ql_create_send_free_list(qdev);
+
+ qdev->rsp_current = qdev->rsp_q_virt_addr;
+
+ return 0;
+
+err_small_buffers:
+ ql_free_buffer_queues(qdev);
+err_buffer_queues:
+ ql_free_net_req_rsp_queues(qdev);
+err_req_rsp:
+ pci_free_consistent(qdev->pdev,
+ PAGE_SIZE,
+ qdev->shadow_reg_virt_addr,
+ qdev->shadow_reg_phy_addr);
+
+ return -ENOMEM;
+}
+
+static void ql_free_mem_resources(struct ql3_adapter *qdev)
+{
+ ql_free_large_buffers(qdev);
+ ql_free_small_buffers(qdev);
+ ql_free_buffer_queues(qdev);
+ ql_free_net_req_rsp_queues(qdev);
+ if (qdev->shadow_reg_virt_addr != NULL) {
+ pci_free_consistent(qdev->pdev,
+ PAGE_SIZE,
+ qdev->shadow_reg_virt_addr,
+ qdev->shadow_reg_phy_addr);
+ qdev->shadow_reg_virt_addr = NULL;
+ }
+}
+
+static int ql_init_misc_registers(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_local_ram_registers *local_ram =
+ (struct ql3xxx_local_ram_registers *)qdev->mem_map_registers;
+
+ if(ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 4))
+ return -1;
+
+ ql_write_page2_reg(qdev,
+ &local_ram->bufletSize, qdev->nvram_data.bufletSize);
+
+ ql_write_page2_reg(qdev,
+ &local_ram->maxBufletCount,
+ qdev->nvram_data.bufletCount);
+
+ ql_write_page2_reg(qdev,
+ &local_ram->freeBufletThresholdLow,
+ (qdev->nvram_data.tcpWindowThreshold25 << 16) |
+ (qdev->nvram_data.tcpWindowThreshold0));
+
+ ql_write_page2_reg(qdev,
+ &local_ram->freeBufletThresholdHigh,
+ qdev->nvram_data.tcpWindowThreshold50);
+
+ ql_write_page2_reg(qdev,
+ &local_ram->ipHashTableBase,
+ (qdev->nvram_data.ipHashTableBaseHi << 16) |
+ qdev->nvram_data.ipHashTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->ipHashTableCount,
+ qdev->nvram_data.ipHashTableSize);
+ ql_write_page2_reg(qdev,
+ &local_ram->tcpHashTableBase,
+ (qdev->nvram_data.tcpHashTableBaseHi << 16) |
+ qdev->nvram_data.tcpHashTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->tcpHashTableCount,
+ qdev->nvram_data.tcpHashTableSize);
+ ql_write_page2_reg(qdev,
+ &local_ram->ncbBase,
+ (qdev->nvram_data.ncbTableBaseHi << 16) |
+ qdev->nvram_data.ncbTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->maxNcbCount,
+ qdev->nvram_data.ncbTableSize);
+ ql_write_page2_reg(qdev,
+ &local_ram->drbBase,
+ (qdev->nvram_data.drbTableBaseHi << 16) |
+ qdev->nvram_data.drbTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->maxDrbCount,
+ qdev->nvram_data.drbTableSize);
+ ql_sem_unlock(qdev, QL_DDR_RAM_SEM_MASK);
+ return 0;
+}
+
+static int ql_adapter_initialize(struct ql3_adapter *qdev)
+{
+ u32 value;
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_host_memory_registers __iomem *hmem_regs =
+ (struct ql3xxx_host_memory_registers *)port_regs;
+ u32 delay = 10;
+ int status = 0;
+
+ if(ql_mii_setup(qdev))
+ return -1;
+
+ /* Bring out PHY out of reset */
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ (ISP_SERIAL_PORT_IF_WE |
+ (ISP_SERIAL_PORT_IF_WE << 16)));
+
+ qdev->port_link_state = LS_DOWN;
+ netif_carrier_off(qdev->ndev);
+
+ /* V2 chip fix for ARS-39168. */
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ (ISP_SERIAL_PORT_IF_SDE |
+ (ISP_SERIAL_PORT_IF_SDE << 16)));
+
+ /* Request Queue Registers */
+ *((u32 *) (qdev->preq_consumer_index)) = 0;
+ atomic_set(&qdev->tx_count,NUM_REQ_Q_ENTRIES);
+ qdev->req_producer_index = 0;
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqConsumerIndexAddrHigh,
+ qdev->req_consumer_index_phy_addr_high);
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqConsumerIndexAddrLow,
+ qdev->req_consumer_index_phy_addr_low);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqBaseAddrHigh,
+ MS_64BITS(qdev->req_q_phy_addr));
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqBaseAddrLow,
+ LS_64BITS(qdev->req_q_phy_addr));
+ ql_write_page1_reg(qdev, &hmem_regs->reqLength, NUM_REQ_Q_ENTRIES);
+
+ /* Response Queue Registers */
+ *((u16 *) (qdev->prsp_producer_index)) = 0;
+ qdev->rsp_consumer_index = 0;
+ qdev->rsp_current = qdev->rsp_q_virt_addr;
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspProducerIndexAddrHigh,
+ qdev->rsp_producer_index_phy_addr_high);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspProducerIndexAddrLow,
+ qdev->rsp_producer_index_phy_addr_low);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspBaseAddrHigh,
+ MS_64BITS(qdev->rsp_q_phy_addr));
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspBaseAddrLow,
+ LS_64BITS(qdev->rsp_q_phy_addr));
+
+ ql_write_page1_reg(qdev, &hmem_regs->rspLength, NUM_RSP_Q_ENTRIES);
+
+ /* Large Buffer Queue */
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxLargeQBaseAddrHigh,
+ MS_64BITS(qdev->lrg_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxLargeQBaseAddrLow,
+ LS_64BITS(qdev->lrg_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, NUM_LBUFQ_ENTRIES);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxLargeBufferLength,
+ qdev->lrg_buffer_len);
+
+ /* Small Buffer Queue */
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxSmallQBaseAddrHigh,
+ MS_64BITS(qdev->small_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxSmallQBaseAddrLow,
+ LS_64BITS(qdev->small_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev, &hmem_regs->rxSmallQLength, NUM_SBUFQ_ENTRIES);
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxSmallBufferLength,
+ QL_SMALL_BUFFER_SIZE);
+
+ qdev->small_buf_q_producer_index = NUM_SBUFQ_ENTRIES - 1;
+ qdev->small_buf_release_cnt = 8;
+ qdev->lrg_buf_q_producer_index = NUM_LBUFQ_ENTRIES - 1;
+ qdev->lrg_buf_release_cnt = 8;
+ qdev->lrg_buf_next_free =
+ (struct bufq_addr_element *)qdev->lrg_buf_q_virt_addr;
+ qdev->small_buf_index = 0;
+ qdev->lrg_buf_index = 0;
+ qdev->lrg_buf_free_count = 0;
+ qdev->lrg_buf_free_head = NULL;
+ qdev->lrg_buf_free_tail = NULL;
+
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.
+ rxSmallQProducerIndex,
+ qdev->small_buf_q_producer_index);
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.
+ rxLargeQProducerIndex,
+ qdev->lrg_buf_q_producer_index);
+
+ /*
+ * Find out if the chip has already been initialized. If it has, then
+ * we skip some of the initialization.
+ */
+ clear_bit(QL_LINK_MASTER, &qdev->flags);
+ value = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if ((value & PORT_STATUS_IC) == 0) {
+
+ /* Chip has not been configured yet, so let it rip. */
+ if(ql_init_misc_registers(qdev)) {
+ status = -1;
+ goto out;
+ }
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev,
+ &port_regs->mac1MaxFrameLengthReg,
+ qdev->max_frame_size);
+ else
+ ql_write_page0_reg(qdev,
+ &port_regs->mac0MaxFrameLengthReg,
+ qdev->max_frame_size);
+
+ value = qdev->nvram_data.tcpMaxWindowSize;
+ ql_write_page0_reg(qdev, &port_regs->tcpMaxWindow, value);
+
+ value = (0xFFFF << 16) | qdev->nvram_data.extHwConfig;
+
+ if(ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
+ * 2) << 13)) {
+ status = -1;
+ goto out;
+ }
+ ql_write_page0_reg(qdev, &port_regs->ExternalHWConfig, value);
+ ql_write_page0_reg(qdev, &port_regs->InternalChipConfig,
+ (((INTERNAL_CHIP_SD | INTERNAL_CHIP_WE) <<
+ 16) | (INTERNAL_CHIP_SD |
+ INTERNAL_CHIP_WE)));
+ ql_sem_unlock(qdev, QL_FLASH_SEM_MASK);
+ }
+
+
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7)) {
+ status = -1;
+ goto out;
+ }
+
+ ql_init_scan_mode(qdev);
+ ql_get_phy_owner(qdev);
+
+ /* Load the MAC Configuration */
+
+ /* Program lower 32 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((qdev->ndev->dev_addr[2] << 24)
+ | (qdev->ndev->dev_addr[3] << 16)
+ | (qdev->ndev->dev_addr[4] << 8)
+ | qdev->ndev->dev_addr[5]));
+
+ /* Program top 16 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((qdev->ndev->dev_addr[0] << 8)
+ | qdev->ndev->dev_addr[1]));
+
+ /* Enable Primary MAC */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ ((MAC_ADDR_INDIRECT_PTR_REG_PE << 16) |
+ MAC_ADDR_INDIRECT_PTR_REG_PE));
+
+ /* Clear Primary and Secondary IP addresses */
+ ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
+ ((IP_ADDR_INDEX_REG_MASK << 16) |
+ (qdev->mac_index << 2)));
+ ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
+
+ ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
+ ((IP_ADDR_INDEX_REG_MASK << 16) |
+ ((qdev->mac_index << 2) + 1)));
+ ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
+
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+
+ /* Indicate Configuration Complete */
+ ql_write_page0_reg(qdev,
+ &port_regs->portControl,
+ ((PORT_CONTROL_CC << 16) | PORT_CONTROL_CC));
+
+ do {
+ value = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (value & PORT_STATUS_IC)
+ break;
+ msleep(500);
+ } while (--delay);
+
+ if (delay == 0) {
+ printk(KERN_ERR PFX
+ "%s: Hw Initialization timeout.\n", qdev->ndev->name);
+ status = -1;
+ goto out;
+ }
+
+ /* Enable Ethernet Function */
+ value =
+ (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+ PORT_CONTROL_HH);
+ ql_write_page0_reg(qdev, &port_regs->portControl,
+ ((value << 16) | value));
+
+out:
+ return status;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_adapter_reset(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ int status = 0;
+ u16 value;
+ int max_wait_time;
+
+ set_bit(QL_RESET_ACTIVE, &qdev->flags);
+ clear_bit(QL_RESET_DONE, &qdev->flags);
+
+ /*
+ * Issue soft reset to chip.
+ */
+ printk(KERN_DEBUG PFX
+ "%s: Issue soft reset to chip.\n",
+ qdev->ndev->name);
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.ispControlStatus,
+ ((ISP_CONTROL_SR << 16) | ISP_CONTROL_SR));
+
+ /* Wait 3 seconds for reset to complete. */
+ printk(KERN_DEBUG PFX
+ "%s: Wait 10 milliseconds for reset to complete.\n",
+ qdev->ndev->name);
+
+ /* Wait until the firmware tells us the Soft Reset is done */
+ max_wait_time = 5;
+ do {
+ value =
+ ql_read_common_reg(qdev,
+ &port_regs->CommonRegs.ispControlStatus);
+ if ((value & ISP_CONTROL_SR) == 0)
+ break;
+
+ ssleep(1);
+ } while ((--max_wait_time));
+
+ /*
+ * Also, make sure that the Network Reset Interrupt bit has been
+ * cleared after the soft reset has taken place.
+ */
+ value =
+ ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
+ if (value & ISP_CONTROL_RI) {
+ printk(KERN_DEBUG PFX
+ "ql_adapter_reset: clearing RI after reset.\n");
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
+ }
+
+ if (max_wait_time == 0) {
+ /* Issue Force Soft Reset */
+ ql_write_common_reg(qdev,
+ (u32 *) & port_regs->CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_FSR << 16) |
+ ISP_CONTROL_FSR));
+ /*
+ * Wait until the firmware tells us the Force Soft Reset is
+ * done
+ */
+ max_wait_time = 5;
+ do {
+ value =
+ ql_read_common_reg(qdev,
+ &port_regs->CommonRegs.
+ ispControlStatus);
+ if ((value & ISP_CONTROL_FSR) == 0) {
+ break;
+ }
+ ssleep(1);
+ } while ((--max_wait_time));
+ }
+ if (max_wait_time == 0)
+ status = 1;
+
+ clear_bit(QL_RESET_ACTIVE, &qdev->flags);
+ set_bit(QL_RESET_DONE, &qdev->flags);
+ return status;
+}
+
+static void ql_set_mac_info(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value, port_status;
+ u8 func_number;
+
+ /* Get the function number */
+ value =
+ ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+ func_number = (u8) ((value >> 4) & OPCODE_FUNC_ID_MASK);
+ port_status = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ switch (value & ISP_CONTROL_FN_MASK) {
+ case ISP_CONTROL_FN0_NET:
+ qdev->mac_index = 0;
+ qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
+ qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
+ qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
+ qdev->mb_bit_mask = FN0_MA_BITS_MASK;
+ qdev->PHYAddr = PORT0_PHY_ADDRESS;
+ if (port_status & PORT_STATUS_SM0)
+ set_bit(QL_LINK_OPTICAL,&qdev->flags);
+ else
+ clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+ break;
+
+ case ISP_CONTROL_FN1_NET:
+ qdev->mac_index = 1;
+ qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
+ qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
+ qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
+ qdev->mb_bit_mask = FN1_MA_BITS_MASK;
+ qdev->PHYAddr = PORT1_PHY_ADDRESS;
+ if (port_status & PORT_STATUS_SM1)
+ set_bit(QL_LINK_OPTICAL,&qdev->flags);
+ else
+ clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+ break;
+
+ case ISP_CONTROL_FN0_SCSI:
+ case ISP_CONTROL_FN1_SCSI:
+ default:
+ printk(KERN_DEBUG PFX
+ "%s: Invalid function number, ispControlStatus = 0x%x\n",
+ qdev->ndev->name,value);
+ break;
+ }
+ qdev->numPorts = qdev->nvram_data.numPorts;
+}
+
+static void ql_display_dev_info(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct pci_dev *pdev = qdev->pdev;
+
+ printk(KERN_INFO PFX
+ "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
+ DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+ printk(KERN_INFO PFX
+ "%s Interface.\n",
+ test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
+
+ /*
+ * Print PCI bus width/type.
+ */
+ printk(KERN_INFO PFX
+ "Bus interface is %s %s.\n",
+ ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
+ ((qdev->pci_x) ? "PCI-X" : "PCI"));
+
+ printk(KERN_INFO PFX
+ "mem IO base address adjusted = 0x%p\n",
+ qdev->mem_map_registers);
+ printk(KERN_INFO PFX "Interrupt number = %d\n", pdev->irq);
+
+ if (netif_msg_probe(qdev))
+ printk(KERN_INFO PFX
+ "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name, ndev->dev_addr[0], ndev->dev_addr[1],
+ ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
+ ndev->dev_addr[5]);
+}
+
+static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
+{
+ struct net_device *ndev = qdev->ndev;
+ int retval = 0;
+
+ netif_stop_queue(ndev);
+ netif_carrier_off(ndev);
+
+ clear_bit(QL_ADAPTER_UP,&qdev->flags);
+ clear_bit(QL_LINK_MASTER,&qdev->flags);
+
+ ql_disable_interrupts(qdev);
+
+ free_irq(qdev->pdev->irq, ndev);
+
+ if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: calling pci_disable_msi().\n", qdev->ndev->name);
+ clear_bit(QL_MSI_ENABLED,&qdev->flags);
+ pci_disable_msi(qdev->pdev);
+ }
+
+ del_timer_sync(&qdev->adapter_timer);
+
+ netif_poll_disable(ndev);
+
+ if (do_reset) {
+ int soft_reset;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if (ql_wait_for_drvr_lock(qdev)) {
+ if ((soft_reset = ql_adapter_reset(qdev))) {
+ printk(KERN_ERR PFX
+ "%s: ql_adapter_reset(%d) FAILED!\n",
+ ndev->name, qdev->index);
+ }
+ printk(KERN_ERR PFX
+ "%s: Releaseing driver lock via chip reset.\n",ndev->name);
+ } else {
+ printk(KERN_ERR PFX
+ "%s: Could not acquire driver lock to do "
+ "reset!\n", ndev->name);
+ retval = -1;
+ }
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ }
+ ql_free_mem_resources(qdev);
+ return retval;
+}
+
+static int ql_adapter_up(struct ql3_adapter *qdev)
+{
+ struct net_device *ndev = qdev->ndev;
+ int err;
+ unsigned long irq_flags = SA_SAMPLE_RANDOM | SA_SHIRQ;
+ unsigned long hw_flags;
+
+ if (ql_alloc_mem_resources(qdev)) {
+ printk(KERN_ERR PFX
+ "%s Unable to allocate buffers.\n", ndev->name);
+ return -ENOMEM;
+ }
+
+ if (qdev->msi) {
+ if (pci_enable_msi(qdev->pdev)) {
+ printk(KERN_ERR PFX
+ "%s: User requested MSI, but MSI failed to "
+ "initialize. Continuing without MSI.\n",
+ qdev->ndev->name);
+ qdev->msi = 0;
+ } else {
+ printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name);
+ set_bit(QL_MSI_ENABLED,&qdev->flags);
+ irq_flags &= ~SA_SHIRQ;
+ }
+ }
+
+ if ((err = request_irq(qdev->pdev->irq,
+ ql3xxx_isr,
+ irq_flags, ndev->name, ndev))) {
+ printk(KERN_ERR PFX
+ "%s: Failed to reserve interrupt %d already in use.\n",
+ ndev->name, qdev->pdev->irq);
+ goto err_irq;
+ }
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ if ((err = ql_wait_for_drvr_lock(qdev))) {
+ if ((err = ql_adapter_initialize(qdev))) {
+ printk(KERN_ERR PFX
+ "%s: Unable to initialize adapter.\n",
+ ndev->name);
+ goto err_init;
+ }
+ printk(KERN_ERR PFX
+ "%s: Releaseing driver lock.\n",ndev->name);
+ ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+ } else {
+ printk(KERN_ERR PFX
+ "%s: Could not aquire driver lock.\n",
+ ndev->name);
+ goto err_lock;
+ }
+
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ set_bit(QL_ADAPTER_UP,&qdev->flags);
+
+ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
+
+ netif_poll_enable(ndev);
+ ql_enable_interrupts(qdev);
+ return 0;
+
+err_init:
+ ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+err_lock:
+ free_irq(qdev->pdev->irq, ndev);
+err_irq:
+ if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: calling pci_disable_msi().\n",
+ qdev->ndev->name);
+ clear_bit(QL_MSI_ENABLED,&qdev->flags);
+ pci_disable_msi(qdev->pdev);
+ }
+ return err;
+}
+
+static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
+{
+ if( ql_adapter_down(qdev,reset) || ql_adapter_up(qdev)) {
+ printk(KERN_ERR PFX
+ "%s: Driver up/down cycle failed, "
+ "closing device\n",qdev->ndev->name);
+ dev_close(qdev->ndev);
+ return -1;
+ }
+ return 0;
+}
+
+static int ql3xxx_close(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+
+ /*
+ * Wait for device to recover from a reset.
+ * (Rarely happens, but possible.)
+ */
+ while (!test_bit(QL_ADAPTER_UP,&qdev->flags))
+ msleep(50);
+
+ ql_adapter_down(qdev,QL_DO_RESET);
+ return 0;
+}
+
+static int ql3xxx_open(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ return (ql_adapter_up(qdev));
+}
+
+static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv;
+ return &qdev->stats;
+}
+
+static int ql3xxx_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ printk(KERN_ERR PFX "%s: new mtu size = %d.\n", ndev->name, new_mtu);
+ if (new_mtu != NORMAL_MTU_SIZE && new_mtu != JUMBO_MTU_SIZE) {
+ printk(KERN_ERR PFX
+ "%s: mtu size of %d is not valid. Use exactly %d or "
+ "%d.\n", ndev->name, new_mtu, NORMAL_MTU_SIZE,
+ JUMBO_MTU_SIZE);
+ return -EINVAL;
+ }
+
+ if (!netif_running(ndev)) {
+ ndev->mtu = new_mtu;
+ return 0;
+ }
+
+ ndev->mtu = new_mtu;
+ return ql_cycle_adapter(qdev,QL_DO_RESET);
+}
+
+static void ql3xxx_set_multicast_list(struct net_device *ndev)
+{
+ /*
+ * We are manually parsing the list in the net_device structure.
+ */
+ return;
+}
+
+static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ struct sockaddr *addr = p;
+ unsigned long hw_flags;
+
+ if (netif_running(ndev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ /* Program lower 32 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((ndev->dev_addr[2] << 24) | (ndev->
+ dev_addr[3] << 16) |
+ (ndev->dev_addr[4] << 8) | ndev->dev_addr[5]));
+
+ /* Program top 16 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((ndev->dev_addr[0] << 8) | ndev->dev_addr[1]));
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ return 0;
+}
+
+static void ql3xxx_tx_timeout(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+
+ printk(KERN_ERR PFX "%s: Resetting...\n", ndev->name);
+ /*
+ * Stop the queues, we've got a problem.
+ */
+ netif_stop_queue(ndev);
+
+ /*
+ * Wake up the worker to process this event.
+ */
+ queue_work(qdev->workqueue, &qdev->tx_timeout_work);
+}
+
+static void ql_reset_work(struct ql3_adapter *qdev)
+{
+ struct net_device *ndev = qdev->ndev;
+ u32 value;
+ struct ql_tx_buf_cb *tx_cb;
+ int max_wait_time, i;
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ unsigned long hw_flags;
+
+ if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START),&qdev->flags)) {
+ clear_bit(QL_LINK_MASTER,&qdev->flags);
+
+ /*
+ * Loop through the active list and return the skb.
+ */
+ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ tx_cb = &qdev->tx_buf[i];
+ if (tx_cb->skb) {
+
+ printk(KERN_DEBUG PFX
+ "%s: Freeing lost SKB.\n",
+ qdev->ndev->name);
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(tx_cb, mapaddr),
+ pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+ dev_kfree_skb(tx_cb->skb);
+ tx_cb->skb = NULL;
+ }
+ }
+
+ printk(KERN_ERR PFX
+ "%s: Clearing NRI after reset.\n", qdev->ndev->name);
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
+ /*
+ * Wait the for Soft Reset to Complete.
+ */
+ max_wait_time = 10;
+ do {
+ value = ql_read_common_reg(qdev,
+ &port_regs->CommonRegs.
+
+ ispControlStatus);
+ if ((value & ISP_CONTROL_SR) == 0) {
+ printk(KERN_DEBUG PFX
+ "%s: reset completed.\n",
+ qdev->ndev->name);
+ break;
+ }
+
+ if (value & ISP_CONTROL_RI) {
+ printk(KERN_DEBUG PFX
+ "%s: clearing NRI after reset.\n",
+ qdev->ndev->name);
+ ql_write_common_reg(qdev,
+ (u32 *) &
+ port_regs->
+ CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_RI <<
+ 16) | ISP_CONTROL_RI));
+ }
+
+ ssleep(1);
+ } while (--max_wait_time);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ if (value & ISP_CONTROL_SR) {
+
+ /*
+ * Set the reset flags and clear the board again.
+ * Nothing else to do...
+ */
+ printk(KERN_ERR PFX
+ "%s: Timed out waiting for reset to "
+ "complete.\n", ndev->name);
+ printk(KERN_ERR PFX
+ "%s: Do a reset.\n", ndev->name);
+ clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
+ clear_bit(QL_RESET_START,&qdev->flags);
+ ql_cycle_adapter(qdev,QL_DO_RESET);
+ return;
+ }
+
+ clear_bit(QL_RESET_ACTIVE,&qdev->flags);
+ clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
+ clear_bit(QL_RESET_START,&qdev->flags);
+ ql_cycle_adapter(qdev,QL_NO_RESET);
+ }
+}
+
+static void ql_tx_timeout_work(struct ql3_adapter *qdev)
+{
+ ql_cycle_adapter(qdev,QL_DO_RESET);
+}
+
+static void ql_get_board_info(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value;
+
+ value = ql_read_page0_reg_l(qdev, &port_regs->portStatus);
+
+ qdev->chip_rev_id = ((value & PORT_STATUS_REV_ID_MASK) >> 12);
+ if (value & PORT_STATUS_64)
+ qdev->pci_width = 64;
+ else
+ qdev->pci_width = 32;
+ if (value & PORT_STATUS_X)
+ qdev->pci_x = 1;
+ else
+ qdev->pci_x = 0;
+ qdev->pci_slot = (u8) PCI_SLOT(qdev->pdev->devfn);
+}
+
+static void ql3xxx_timer(unsigned long ptr)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)ptr;
+
+ if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
+ printk(KERN_DEBUG PFX
+ "%s: Reset in progress.\n",
+ qdev->ndev->name);
+ goto end;
+ }
+
+ ql_link_state_machine(qdev);
+
+ /* Restart timer on 2 second interval. */
+end:
+ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
+}
+
+static int __devinit ql3xxx_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_entry)
+{
+ struct net_device *ndev = NULL;
+ struct ql3_adapter *qdev = NULL;
+ static int cards_found = 0;
+ int pci_using_dac, err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR PFX "%s cannot enable PCI device\n",
+ pci_name(pdev));
+ goto err_out;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
+ pci_name(pdev));
+ goto err_out_disable_pdev;
+ }
+
+ pci_set_master(pdev);
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ } else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+ pci_using_dac = 0;
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ }
+
+ if (err) {
+ printk(KERN_ERR PFX "%s no usable DMA configuration\n",
+ pci_name(pdev));
+ goto err_out_free_regions;
+ }
+
+ ndev = alloc_etherdev(sizeof(struct ql3_adapter));
+ if (!ndev)
+ goto err_out_free_regions;
+
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ ndev->features = NETIF_F_LLTX;
+ if (pci_using_dac)
+ ndev->features |= NETIF_F_HIGHDMA;
+
+ pci_set_drvdata(pdev, ndev);
+
+ qdev = netdev_priv(ndev);
+ qdev->index = cards_found;
+ qdev->ndev = ndev;
+ qdev->pdev = pdev;
+ qdev->port_link_state = LS_DOWN;
+ if (msi)
+ qdev->msi = 1;
+
+ qdev->msg_enable = netif_msg_init(debug, default_msg);
+
+ qdev->mem_map_registers =
+ ioremap_nocache(pci_resource_start(pdev, 1),
+ pci_resource_len(qdev->pdev, 1));
+ if (!qdev->mem_map_registers) {
+ printk(KERN_ERR PFX "%s: cannot map device registers\n",
+ pci_name(pdev));
+ goto err_out_free_ndev;
+ }
+
+ spin_lock_init(&qdev->adapter_lock);
+ spin_lock_init(&qdev->hw_lock);
+
+ /* Set driver entry points */
+ ndev->open = ql3xxx_open;
+ ndev->hard_start_xmit = ql3xxx_send;
+ ndev->stop = ql3xxx_close;
+ ndev->get_stats = ql3xxx_get_stats;
+ ndev->change_mtu = ql3xxx_change_mtu;
+ ndev->set_multicast_list = ql3xxx_set_multicast_list;
+ SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
+ ndev->set_mac_address = ql3xxx_set_mac_address;
+ ndev->tx_timeout = ql3xxx_tx_timeout;
+ ndev->watchdog_timeo = 5 * HZ;
+
+ ndev->poll = &ql_poll;
+ ndev->weight = 64;
+
+ ndev->irq = pdev->irq;
+
+ /* make sure the EEPROM is good */
+ if (ql_get_nvram_params(qdev)) {
+ printk(KERN_ALERT PFX
+ "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n",
+ qdev->index);
+ goto err_out_iounmap;
+ }
+
+ ql_set_mac_info(qdev);
+
+ /* Validate and set parameters */
+ if (qdev->mac_index) {
+ memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress,
+ ETH_ALEN);
+ } else {
+ memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress,
+ ETH_ALEN);
+ }
+ memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
+
+ ndev->tx_queue_len = NUM_REQ_Q_ENTRIES;
+
+ /* Turn off support for multicasting */
+ ndev->flags &= ~IFF_MULTICAST;
+
+ /* Record PCI bus information. */
+ ql_get_board_info(qdev);
+
+ /*
+ * Set the Maximum Memory Read Byte Count value. We do this to handle
+ * jumbo frames.
+ */
+ if (qdev->pci_x) {
+ pci_write_config_word(pdev, (int)0x4e, (u16) 0x0036);
+ }
+
+ err = register_netdev(ndev);
+ if (err) {
+ printk(KERN_ERR PFX "%s: cannot register net device\n",
+ pci_name(pdev));
+ goto err_out_iounmap;
+ }
+
+ /* we're going to reset, so assume we have no link for now */
+
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+
+ qdev->workqueue = create_singlethread_workqueue(ndev->name);
+ INIT_WORK(&qdev->reset_work, (void (*)(void *))ql_reset_work, qdev);
+ INIT_WORK(&qdev->tx_timeout_work,
+ (void (*)(void *))ql_tx_timeout_work, qdev);
+
+ init_timer(&qdev->adapter_timer);
+ qdev->adapter_timer.function = ql3xxx_timer;
+ qdev->adapter_timer.expires = jiffies + HZ * 2; /* two second delay */
+ qdev->adapter_timer.data = (unsigned long)qdev;
+
+ if(!cards_found) {
+ printk(KERN_ALERT PFX "%s\n", DRV_STRING);
+ printk(KERN_ALERT PFX "Driver name: %s, Version: %s.\n",
+ DRV_NAME, DRV_VERSION);
+ }
+ ql_display_dev_info(ndev);
+
+ cards_found++;
+ return 0;
+
+err_out_iounmap:
+ iounmap(qdev->mem_map_registers);
+err_out_free_ndev:
+ free_netdev(ndev);
+err_out_free_regions:
+ pci_release_regions(pdev);
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+err_out:
+ return err;
+}
+
+static void __devexit ql3xxx_remove(struct pci_dev *pdev)
+{
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+ qdev = netdev_priv(ndev);
+
+ ql_disable_interrupts(qdev);
+
+ if (qdev->workqueue) {
+ cancel_delayed_work(&qdev->reset_work);
+ cancel_delayed_work(&qdev->tx_timeout_work);
+ destroy_workqueue(qdev->workqueue);
+ qdev->workqueue = NULL;
+ }
+
+ iounmap((void *)qdev->mmap_virt_base);
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+}
+
+static struct pci_driver ql3xxx_driver = {
+
+ .name = DRV_NAME,
+ .id_table = ql3xxx_pci_tbl,
+ .probe = ql3xxx_probe,
+ .remove = __devexit_p(ql3xxx_remove),
+};
+
+static int __init ql3xxx_init_module(void)
+{
+ return pci_register_driver(&ql3xxx_driver);
+}
+
+static void __exit ql3xxx_exit(void)
+{
+ pci_unregister_driver(&ql3xxx_driver);
+}
+
+module_init(ql3xxx_init_module);
+module_exit(ql3xxx_exit);
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
new file mode 100644
index 00000000000..9492cee6b08
--- /dev/null
+++ b/drivers/net/qla3xxx.h
@@ -0,0 +1,1194 @@
+/*
+ * QLogic QLA3xxx NIC HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla3xxx for copyright and licensing details.
+ */
+#ifndef _QLA3XXX_H_
+#define _QLA3XXX_H_
+
+/*
+ * IOCB Definitions...
+ */
+#pragma pack(1)
+
+#define OPCODE_OB_MAC_IOCB_FN0 0x01
+#define OPCODE_OB_MAC_IOCB_FN2 0x21
+#define OPCODE_OB_TCP_IOCB_FN0 0x03
+#define OPCODE_OB_TCP_IOCB_FN2 0x23
+#define OPCODE_UPDATE_NCB_IOCB_FN0 0x00
+#define OPCODE_UPDATE_NCB_IOCB_FN2 0x20
+
+#define OPCODE_UPDATE_NCB_IOCB 0xF0
+#define OPCODE_IB_MAC_IOCB 0xF9
+#define OPCODE_IB_IP_IOCB 0xFA
+#define OPCODE_IB_TCP_IOCB 0xFB
+#define OPCODE_DUMP_PROTO_IOCB 0xFE
+#define OPCODE_BUFFER_ALERT_IOCB 0xFB
+
+#define OPCODE_FUNC_ID_MASK 0x30
+#define OUTBOUND_MAC_IOCB 0x01 /* plus function bits */
+#define OUTBOUND_TCP_IOCB 0x03 /* plus function bits */
+#define UPDATE_NCB_IOCB 0x00 /* plus function bits */
+
+#define FN0_MA_BITS_MASK 0x00
+#define FN1_MA_BITS_MASK 0x80
+
+struct ob_mac_iocb_req {
+ u8 opcode;
+ u8 flags;
+#define OB_MAC_IOCB_REQ_MA 0xC0
+#define OB_MAC_IOCB_REQ_F 0x20
+#define OB_MAC_IOCB_REQ_X 0x10
+#define OB_MAC_IOCB_REQ_D 0x02
+#define OB_MAC_IOCB_REQ_I 0x01
+ __le16 reserved0;
+
+ __le32 transaction_id;
+ __le16 data_len;
+ __le16 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
+ __le32 buf_addr0_low;
+ __le32 buf_addr0_high;
+ __le32 buf_0_len;
+ __le32 buf_addr1_low;
+ __le32 buf_addr1_high;
+ __le32 buf_1_len;
+ __le32 buf_addr2_low;
+ __le32 buf_addr2_high;
+ __le32 buf_2_len;
+ __le32 reserved4;
+ __le32 reserved5;
+};
+/*
+ * The following constants define control bits for buffer
+ * length fields for all IOCB's.
+ */
+#define OB_MAC_IOCB_REQ_E 0x80000000 /* Last valid buffer in list. */
+#define OB_MAC_IOCB_REQ_C 0x40000000 /* points to an OAL. (continuation) */
+#define OB_MAC_IOCB_REQ_L 0x20000000 /* Auburn local address pointer. */
+#define OB_MAC_IOCB_REQ_R 0x10000000 /* 32-bit address pointer. */
+
+struct ob_mac_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define OB_MAC_IOCB_RSP_P 0x08
+#define OB_MAC_IOCB_RSP_S 0x02
+#define OB_MAC_IOCB_RSP_I 0x01
+
+ __le16 reserved0;
+ __le32 transaction_id;
+ __le32 reserved1;
+ __le32 reserved2;
+};
+
+struct ib_mac_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define IB_MAC_IOCB_RSP_S 0x80
+#define IB_MAC_IOCB_RSP_H1 0x40
+#define IB_MAC_IOCB_RSP_H0 0x20
+#define IB_MAC_IOCB_RSP_B 0x10
+#define IB_MAC_IOCB_RSP_M 0x08
+#define IB_MAC_IOCB_RSP_MA 0x07
+
+ __le16 length;
+ __le32 reserved;
+ __le32 ial_low;
+ __le32 ial_high;
+
+};
+
+struct ob_ip_iocb_req {
+ u8 opcode;
+ __le16 flags;
+#define OB_IP_IOCB_REQ_O 0x100
+#define OB_IP_IOCB_REQ_H 0x008
+#define OB_IP_IOCB_REQ_U 0x004
+#define OB_IP_IOCB_REQ_D 0x002
+#define OB_IP_IOCB_REQ_I 0x001
+
+ u8 reserved0;
+
+ __le32 transaction_id;
+ __le16 data_len;
+ __le16 reserved1;
+ __le32 hncb_ptr_low;
+ __le32 hncb_ptr_high;
+ __le32 buf_addr0_low;
+ __le32 buf_addr0_high;
+ __le32 buf_0_len;
+ __le32 buf_addr1_low;
+ __le32 buf_addr1_high;
+ __le32 buf_1_len;
+ __le32 buf_addr2_low;
+ __le32 buf_addr2_high;
+ __le32 buf_2_len;
+ __le32 reserved2;
+ __le32 reserved3;
+};
+
+/* defines for BufferLength fields above */
+#define OB_IP_IOCB_REQ_E 0x80000000
+#define OB_IP_IOCB_REQ_C 0x40000000
+#define OB_IP_IOCB_REQ_L 0x20000000
+#define OB_IP_IOCB_REQ_R 0x10000000
+
+struct ob_ip_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define OB_MAC_IOCB_RSP_E 0x08
+#define OB_MAC_IOCB_RSP_L 0x04
+#define OB_MAC_IOCB_RSP_S 0x02
+#define OB_MAC_IOCB_RSP_I 0x01
+
+ __le16 reserved0;
+ __le32 transaction_id;
+ __le32 reserved1;
+ __le32 reserved2;
+};
+
+struct ob_tcp_iocb_req {
+ u8 opcode;
+
+ u8 flags0;
+#define OB_TCP_IOCB_REQ_P 0x80
+#define OB_TCP_IOCB_REQ_CI 0x20
+#define OB_TCP_IOCB_REQ_H 0x10
+#define OB_TCP_IOCB_REQ_LN 0x08
+#define OB_TCP_IOCB_REQ_K 0x04
+#define OB_TCP_IOCB_REQ_D 0x02
+#define OB_TCP_IOCB_REQ_I 0x01
+
+ u8 flags1;
+#define OB_TCP_IOCB_REQ_OSM 0x40
+#define OB_TCP_IOCB_REQ_URG 0x20
+#define OB_TCP_IOCB_REQ_ACK 0x10
+#define OB_TCP_IOCB_REQ_PSH 0x08
+#define OB_TCP_IOCB_REQ_RST 0x04
+#define OB_TCP_IOCB_REQ_SYN 0x02
+#define OB_TCP_IOCB_REQ_FIN 0x01
+
+ u8 options_len;
+#define OB_TCP_IOCB_REQ_OMASK 0xF0
+#define OB_TCP_IOCB_REQ_SHIFT 4
+
+ __le32 transaction_id;
+ __le32 data_len;
+ __le32 hncb_ptr_low;
+ __le32 hncb_ptr_high;
+ __le32 buf_addr0_low;
+ __le32 buf_addr0_high;
+ __le32 buf_0_len;
+ __le32 buf_addr1_low;
+ __le32 buf_addr1_high;
+ __le32 buf_1_len;
+ __le32 buf_addr2_low;
+ __le32 buf_addr2_high;
+ __le32 buf_2_len;
+ __le32 time_stamp;
+ __le32 reserved1;
+};
+
+struct ob_tcp_iocb_rsp {
+ u8 opcode;
+
+ u8 flags0;
+#define OB_TCP_IOCB_RSP_C 0x20
+#define OB_TCP_IOCB_RSP_H 0x10
+#define OB_TCP_IOCB_RSP_LN 0x08
+#define OB_TCP_IOCB_RSP_K 0x04
+#define OB_TCP_IOCB_RSP_D 0x02
+#define OB_TCP_IOCB_RSP_I 0x01
+
+ u8 flags1;
+#define OB_TCP_IOCB_RSP_E 0x10
+#define OB_TCP_IOCB_RSP_W 0x08
+#define OB_TCP_IOCB_RSP_P 0x04
+#define OB_TCP_IOCB_RSP_T 0x02
+#define OB_TCP_IOCB_RSP_F 0x01
+
+ u8 state;
+#define OB_TCP_IOCB_RSP_SMASK 0xF0
+#define OB_TCP_IOCB_RSP_SHIFT 4
+
+ __le32 transaction_id;
+ __le32 local_ncb_ptr;
+ __le32 reserved0;
+};
+
+struct ib_ip_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define IB_IP_IOCB_RSP_S 0x80
+#define IB_IP_IOCB_RSP_H1 0x40
+#define IB_IP_IOCB_RSP_H0 0x20
+#define IB_IP_IOCB_RSP_B 0x10
+#define IB_IP_IOCB_RSP_M 0x08
+#define IB_IP_IOCB_RSP_MA 0x07
+
+ __le16 length;
+ __le16 checksum;
+ __le16 reserved;
+#define IB_IP_IOCB_RSP_R 0x01
+ __le32 ial_low;
+ __le32 ial_high;
+};
+
+struct ib_tcp_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define IB_TCP_IOCB_RSP_P 0x80
+#define IB_TCP_IOCB_RSP_T 0x40
+#define IB_TCP_IOCB_RSP_D 0x20
+#define IB_TCP_IOCB_RSP_N 0x10
+#define IB_TCP_IOCB_RSP_IP 0x03
+#define IB_TCP_FLAG_MASK 0xf0
+#define IB_TCP_FLAG_IOCB_SYN 0x00
+
+#define TCP_IB_RSP_FLAGS(x) (x->flags & ~IB_TCP_FLAG_MASK)
+
+ __le16 length;
+ __le32 hncb_ref_num;
+ __le32 ial_low;
+ __le32 ial_high;
+};
+
+struct net_rsp_iocb {
+ u8 opcode;
+ u8 flags;
+ __le16 reserved0;
+ __le32 reserved[3];
+};
+#pragma pack()
+
+/*
+ * Register Definitions...
+ */
+#define PORT0_PHY_ADDRESS 0x1e00
+#define PORT1_PHY_ADDRESS 0x1f00
+
+#define ETHERNET_CRC_SIZE 4
+
+#define MII_SCAN_REGISTER 0x00000001
+
+/* 32-bit ispControlStatus */
+enum {
+ ISP_CONTROL_NP_MASK = 0x0003,
+ ISP_CONTROL_NP_PCSR = 0x0000,
+ ISP_CONTROL_NP_HMCR = 0x0001,
+ ISP_CONTROL_NP_LRAMCR = 0x0002,
+ ISP_CONTROL_NP_PSR = 0x0003,
+ ISP_CONTROL_RI = 0x0008,
+ ISP_CONTROL_CI = 0x0010,
+ ISP_CONTROL_PI = 0x0020,
+ ISP_CONTROL_IN = 0x0040,
+ ISP_CONTROL_BE = 0x0080,
+ ISP_CONTROL_FN_MASK = 0x0700,
+ ISP_CONTROL_FN0_NET = 0x0400,
+ ISP_CONTROL_FN0_SCSI = 0x0500,
+ ISP_CONTROL_FN1_NET = 0x0600,
+ ISP_CONTROL_FN1_SCSI = 0x0700,
+ ISP_CONTROL_LINK_DN_0 = 0x0800,
+ ISP_CONTROL_LINK_DN_1 = 0x1000,
+ ISP_CONTROL_FSR = 0x2000,
+ ISP_CONTROL_FE = 0x4000,
+ ISP_CONTROL_SR = 0x8000,
+};
+
+/* 32-bit ispInterruptMaskReg */
+enum {
+ ISP_IMR_ENABLE_INT = 0x0004,
+ ISP_IMR_DISABLE_RESET_INT = 0x0008,
+ ISP_IMR_DISABLE_CMPL_INT = 0x0010,
+ ISP_IMR_DISABLE_PROC_INT = 0x0020,
+};
+
+/* 32-bit serialPortInterfaceReg */
+enum {
+ ISP_SERIAL_PORT_IF_CLK = 0x0001,
+ ISP_SERIAL_PORT_IF_CS = 0x0002,
+ ISP_SERIAL_PORT_IF_D0 = 0x0004,
+ ISP_SERIAL_PORT_IF_DI = 0x0008,
+ ISP_NVRAM_MASK = (0x000F << 16),
+ ISP_SERIAL_PORT_IF_WE = 0x0010,
+ ISP_SERIAL_PORT_IF_NVR_MASK = 0x001F,
+ ISP_SERIAL_PORT_IF_SCI = 0x0400,
+ ISP_SERIAL_PORT_IF_SC0 = 0x0800,
+ ISP_SERIAL_PORT_IF_SCE = 0x1000,
+ ISP_SERIAL_PORT_IF_SDI = 0x2000,
+ ISP_SERIAL_PORT_IF_SDO = 0x4000,
+ ISP_SERIAL_PORT_IF_SDE = 0x8000,
+ ISP_SERIAL_PORT_IF_I2C_MASK = 0xFC00,
+};
+
+/* semaphoreReg */
+enum {
+ QL_RESOURCE_MASK_BASE_CODE = 0x7,
+ QL_RESOURCE_BITS_BASE_CODE = 0x4,
+ QL_DRVR_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 1),
+ QL_DDR_RAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 4),
+ QL_PHY_GIO_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 7),
+ QL_NVRAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 10),
+ QL_FLASH_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 13),
+ QL_DRVR_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (1 + 16)),
+ QL_DDR_RAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (4 + 16)),
+ QL_PHY_GIO_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (7 + 16)),
+ QL_NVRAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (10 + 16)),
+ QL_FLASH_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (13 + 16)),
+};
+
+ /*
+ * QL3XXX memory-mapped registers
+ * QL3XXX has 4 "pages" of registers, each page occupying
+ * 256 bytes. Each page has a "common" area at the start and then
+ * page-specific registers after that.
+ */
+struct ql3xxx_common_registers {
+ u32 MB0; /* Offset 0x00 */
+ u32 MB1; /* Offset 0x04 */
+ u32 MB2; /* Offset 0x08 */
+ u32 MB3; /* Offset 0x0c */
+ u32 MB4; /* Offset 0x10 */
+ u32 MB5; /* Offset 0x14 */
+ u32 MB6; /* Offset 0x18 */
+ u32 MB7; /* Offset 0x1c */
+ u32 flashBiosAddr;
+ u32 flashBiosData;
+ u32 ispControlStatus;
+ u32 ispInterruptMaskReg;
+ u32 serialPortInterfaceReg;
+ u32 semaphoreReg;
+ u32 reqQProducerIndex;
+ u32 rspQConsumerIndex;
+
+ u32 rxLargeQProducerIndex;
+ u32 rxSmallQProducerIndex;
+ u32 arcMadiCommand;
+ u32 arcMadiData;
+};
+
+enum {
+ EXT_HW_CONFIG_SP_MASK = 0x0006,
+ EXT_HW_CONFIG_SP_NONE = 0x0000,
+ EXT_HW_CONFIG_SP_BYTE_PARITY = 0x0002,
+ EXT_HW_CONFIG_SP_ECC = 0x0004,
+ EXT_HW_CONFIG_SP_ECCx = 0x0006,
+ EXT_HW_CONFIG_SIZE_MASK = 0x0060,
+ EXT_HW_CONFIG_SIZE_128M = 0x0000,
+ EXT_HW_CONFIG_SIZE_256M = 0x0020,
+ EXT_HW_CONFIG_SIZE_512M = 0x0040,
+ EXT_HW_CONFIG_SIZE_INVALID = 0x0060,
+ EXT_HW_CONFIG_PD = 0x0080,
+ EXT_HW_CONFIG_FW = 0x0200,
+ EXT_HW_CONFIG_US = 0x0400,
+ EXT_HW_CONFIG_DCS_MASK = 0x1800,
+ EXT_HW_CONFIG_DCS_9MA = 0x0000,
+ EXT_HW_CONFIG_DCS_15MA = 0x0800,
+ EXT_HW_CONFIG_DCS_18MA = 0x1000,
+ EXT_HW_CONFIG_DCS_24MA = 0x1800,
+ EXT_HW_CONFIG_DDS_MASK = 0x6000,
+ EXT_HW_CONFIG_DDS_9MA = 0x0000,
+ EXT_HW_CONFIG_DDS_15MA = 0x2000,
+ EXT_HW_CONFIG_DDS_18MA = 0x4000,
+ EXT_HW_CONFIG_DDS_24MA = 0x6000,
+};
+
+/* InternalChipConfig */
+enum {
+ INTERNAL_CHIP_DM = 0x0001,
+ INTERNAL_CHIP_SD = 0x0002,
+ INTERNAL_CHIP_RAP_MASK = 0x000C,
+ INTERNAL_CHIP_RAP_RR = 0x0000,
+ INTERNAL_CHIP_RAP_NRM = 0x0004,
+ INTERNAL_CHIP_RAP_ERM = 0x0008,
+ INTERNAL_CHIP_RAP_ERMx = 0x000C,
+ INTERNAL_CHIP_WE = 0x0010,
+ INTERNAL_CHIP_EF = 0x0020,
+ INTERNAL_CHIP_FR = 0x0040,
+ INTERNAL_CHIP_FW = 0x0080,
+ INTERNAL_CHIP_FI = 0x0100,
+ INTERNAL_CHIP_FT = 0x0200,
+};
+
+/* portControl */
+enum {
+ PORT_CONTROL_DS = 0x0001,
+ PORT_CONTROL_HH = 0x0002,
+ PORT_CONTROL_EI = 0x0004,
+ PORT_CONTROL_ET = 0x0008,
+ PORT_CONTROL_EF = 0x0010,
+ PORT_CONTROL_DRM = 0x0020,
+ PORT_CONTROL_RLB = 0x0040,
+ PORT_CONTROL_RCB = 0x0080,
+ PORT_CONTROL_MAC = 0x0100,
+ PORT_CONTROL_IPV = 0x0200,
+ PORT_CONTROL_IFP = 0x0400,
+ PORT_CONTROL_ITP = 0x0800,
+ PORT_CONTROL_FI = 0x1000,
+ PORT_CONTROL_DFP = 0x2000,
+ PORT_CONTROL_OI = 0x4000,
+ PORT_CONTROL_CC = 0x8000,
+};
+
+/* portStatus */
+enum {
+ PORT_STATUS_SM0 = 0x0001,
+ PORT_STATUS_SM1 = 0x0002,
+ PORT_STATUS_X = 0x0008,
+ PORT_STATUS_DL = 0x0080,
+ PORT_STATUS_IC = 0x0200,
+ PORT_STATUS_MRC = 0x0400,
+ PORT_STATUS_NL = 0x0800,
+ PORT_STATUS_REV_ID_MASK = 0x7000,
+ PORT_STATUS_REV_ID_1 = 0x1000,
+ PORT_STATUS_REV_ID_2 = 0x2000,
+ PORT_STATUS_REV_ID_3 = 0x3000,
+ PORT_STATUS_64 = 0x8000,
+ PORT_STATUS_UP0 = 0x10000,
+ PORT_STATUS_AC0 = 0x20000,
+ PORT_STATUS_AE0 = 0x40000,
+ PORT_STATUS_UP1 = 0x100000,
+ PORT_STATUS_AC1 = 0x200000,
+ PORT_STATUS_AE1 = 0x400000,
+ PORT_STATUS_F0_ENABLED = 0x1000000,
+ PORT_STATUS_F1_ENABLED = 0x2000000,
+ PORT_STATUS_F2_ENABLED = 0x4000000,
+ PORT_STATUS_F3_ENABLED = 0x8000000,
+};
+
+/* macMIIMgmtControlReg */
+enum {
+ MAC_ADDR_INDIRECT_PTR_REG_RP_MASK = 0x0003,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_LWR = 0x0000,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_UPR = 0x0001,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_LWR = 0x0002,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_UPR = 0x0003,
+ MAC_ADDR_INDIRECT_PTR_REG_PR = 0x0008,
+ MAC_ADDR_INDIRECT_PTR_REG_SS = 0x0010,
+ MAC_ADDR_INDIRECT_PTR_REG_SE = 0x0020,
+ MAC_ADDR_INDIRECT_PTR_REG_SP = 0x0040,
+ MAC_ADDR_INDIRECT_PTR_REG_PE = 0x0080,
+};
+
+/* macMIIMgmtControlReg */
+enum {
+ MAC_MII_CONTROL_RC = 0x0001,
+ MAC_MII_CONTROL_SC = 0x0002,
+ MAC_MII_CONTROL_AS = 0x0004,
+ MAC_MII_CONTROL_NP = 0x0008,
+ MAC_MII_CONTROL_CLK_SEL_MASK = 0x0070,
+ MAC_MII_CONTROL_CLK_SEL_DIV2 = 0x0000,
+ MAC_MII_CONTROL_CLK_SEL_DIV4 = 0x0010,
+ MAC_MII_CONTROL_CLK_SEL_DIV6 = 0x0020,
+ MAC_MII_CONTROL_CLK_SEL_DIV8 = 0x0030,
+ MAC_MII_CONTROL_CLK_SEL_DIV10 = 0x0040,
+ MAC_MII_CONTROL_CLK_SEL_DIV14 = 0x0050,
+ MAC_MII_CONTROL_CLK_SEL_DIV20 = 0x0060,
+ MAC_MII_CONTROL_CLK_SEL_DIV28 = 0x0070,
+ MAC_MII_CONTROL_RM = 0x8000,
+};
+
+/* macMIIStatusReg */
+enum {
+ MAC_MII_STATUS_BSY = 0x0001,
+ MAC_MII_STATUS_SC = 0x0002,
+ MAC_MII_STATUS_NV = 0x0004,
+};
+
+enum {
+ MAC_CONFIG_REG_PE = 0x0001,
+ MAC_CONFIG_REG_TF = 0x0002,
+ MAC_CONFIG_REG_RF = 0x0004,
+ MAC_CONFIG_REG_FD = 0x0008,
+ MAC_CONFIG_REG_GM = 0x0010,
+ MAC_CONFIG_REG_LB = 0x0020,
+ MAC_CONFIG_REG_SR = 0x8000,
+};
+
+enum {
+ MAC_HALF_DUPLEX_REG_ED = 0x10000,
+ MAC_HALF_DUPLEX_REG_NB = 0x20000,
+ MAC_HALF_DUPLEX_REG_BNB = 0x40000,
+ MAC_HALF_DUPLEX_REG_ALT = 0x80000,
+};
+
+enum {
+ IP_ADDR_INDEX_REG_MASK = 0x000f,
+ IP_ADDR_INDEX_REG_FUNC_0_PRI = 0x0000,
+ IP_ADDR_INDEX_REG_FUNC_0_SEC = 0x0001,
+ IP_ADDR_INDEX_REG_FUNC_1_PRI = 0x0002,
+ IP_ADDR_INDEX_REG_FUNC_1_SEC = 0x0003,
+ IP_ADDR_INDEX_REG_FUNC_2_PRI = 0x0004,
+ IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
+ IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
+ IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+};
+
+enum {
+ PROBE_MUX_ADDR_REG_MUX_SEL_MASK = 0x003f,
+ PROBE_MUX_ADDR_REG_SYSCLK = 0x0000,
+ PROBE_MUX_ADDR_REG_PCICLK = 0x0040,
+ PROBE_MUX_ADDR_REG_NRXCLK = 0x0080,
+ PROBE_MUX_ADDR_REG_CPUCLK = 0x00C0,
+ PROBE_MUX_ADDR_REG_MODULE_SEL_MASK = 0x3f00,
+ PROBE_MUX_ADDR_REG_UP = 0x4000,
+ PROBE_MUX_ADDR_REG_RE = 0x8000,
+};
+
+enum {
+ STATISTICS_INDEX_REG_MASK = 0x01ff,
+ STATISTICS_INDEX_REG_MAC0_TX_FRAME = 0x0000,
+ STATISTICS_INDEX_REG_MAC0_TX_BYTES = 0x0001,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT1 = 0x0002,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT2 = 0x0003,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT3 = 0x0004,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT4 = 0x0005,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT5 = 0x0006,
+ STATISTICS_INDEX_REG_MAC0_RX_FRAME = 0x0007,
+ STATISTICS_INDEX_REG_MAC0_RX_BYTES = 0x0008,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT1 = 0x0009,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT2 = 0x000a,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT3 = 0x000b,
+ STATISTICS_INDEX_REG_MAC0_RX_ERR_CRC = 0x000c,
+ STATISTICS_INDEX_REG_MAC0_RX_ERR_ENC = 0x000d,
+ STATISTICS_INDEX_REG_MAC0_RX_ERR_LEN = 0x000e,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT4 = 0x000f,
+ STATISTICS_INDEX_REG_MAC1_TX_FRAME = 0x0010,
+ STATISTICS_INDEX_REG_MAC1_TX_BYTES = 0x0011,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT1 = 0x0012,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT2 = 0x0013,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT3 = 0x0014,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT4 = 0x0015,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT5 = 0x0016,
+ STATISTICS_INDEX_REG_MAC1_RX_FRAME = 0x0017,
+ STATISTICS_INDEX_REG_MAC1_RX_BYTES = 0x0018,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT1 = 0x0019,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT2 = 0x001a,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT3 = 0x001b,
+ STATISTICS_INDEX_REG_MAC1_RX_ERR_CRC = 0x001c,
+ STATISTICS_INDEX_REG_MAC1_RX_ERR_ENC = 0x001d,
+ STATISTICS_INDEX_REG_MAC1_RX_ERR_LEN = 0x001e,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT4 = 0x001f,
+ STATISTICS_INDEX_REG_IP_TX_PKTS = 0x0020,
+ STATISTICS_INDEX_REG_IP_TX_BYTES = 0x0021,
+ STATISTICS_INDEX_REG_IP_TX_FRAG = 0x0022,
+ STATISTICS_INDEX_REG_IP_RX_PKTS = 0x0023,
+ STATISTICS_INDEX_REG_IP_RX_BYTES = 0x0024,
+ STATISTICS_INDEX_REG_IP_RX_FRAG = 0x0025,
+ STATISTICS_INDEX_REG_IP_DGRM_REASSEMBLY = 0x0026,
+ STATISTICS_INDEX_REG_IP_V6_RX_PKTS = 0x0027,
+ STATISTICS_INDEX_REG_IP_RX_PKTERR = 0x0028,
+ STATISTICS_INDEX_REG_IP_REASSEMBLY_ERR = 0x0029,
+ STATISTICS_INDEX_REG_TCP_TX_SEG = 0x0030,
+ STATISTICS_INDEX_REG_TCP_TX_BYTES = 0x0031,
+ STATISTICS_INDEX_REG_TCP_RX_SEG = 0x0032,
+ STATISTICS_INDEX_REG_TCP_RX_BYTES = 0x0033,
+ STATISTICS_INDEX_REG_TCP_TIMER_EXP = 0x0034,
+ STATISTICS_INDEX_REG_TCP_RX_ACK = 0x0035,
+ STATISTICS_INDEX_REG_TCP_TX_ACK = 0x0036,
+ STATISTICS_INDEX_REG_TCP_RX_ERR = 0x0037,
+ STATISTICS_INDEX_REG_TCP_RX_WIN_PROBE = 0x0038,
+ STATISTICS_INDEX_REG_TCP_ECC_ERR_CORR = 0x003f,
+};
+
+enum {
+ PORT_FATAL_ERROR_STATUS_OFB_RE_MAC0 = 0x00000001,
+ PORT_FATAL_ERROR_STATUS_OFB_RE_MAC1 = 0x00000002,
+ PORT_FATAL_ERROR_STATUS_OFB_WE = 0x00000004,
+ PORT_FATAL_ERROR_STATUS_IFB_RE = 0x00000008,
+ PORT_FATAL_ERROR_STATUS_IFB_WE_MAC0 = 0x00000010,
+ PORT_FATAL_ERROR_STATUS_IFB_WE_MAC1 = 0x00000020,
+ PORT_FATAL_ERROR_STATUS_ODE_RE = 0x00000040,
+ PORT_FATAL_ERROR_STATUS_ODE_WE = 0x00000080,
+ PORT_FATAL_ERROR_STATUS_IDE_RE = 0x00000100,
+ PORT_FATAL_ERROR_STATUS_IDE_WE = 0x00000200,
+ PORT_FATAL_ERROR_STATUS_SDE_RE = 0x00000400,
+ PORT_FATAL_ERROR_STATUS_SDE_WE = 0x00000800,
+ PORT_FATAL_ERROR_STATUS_BLE = 0x00001000,
+ PORT_FATAL_ERROR_STATUS_SPE = 0x00002000,
+ PORT_FATAL_ERROR_STATUS_EP0 = 0x00004000,
+ PORT_FATAL_ERROR_STATUS_EP1 = 0x00008000,
+ PORT_FATAL_ERROR_STATUS_ICE = 0x00010000,
+ PORT_FATAL_ERROR_STATUS_ILE = 0x00020000,
+ PORT_FATAL_ERROR_STATUS_OPE = 0x00040000,
+ PORT_FATAL_ERROR_STATUS_TA = 0x00080000,
+ PORT_FATAL_ERROR_STATUS_MA = 0x00100000,
+ PORT_FATAL_ERROR_STATUS_SCE = 0x00200000,
+ PORT_FATAL_ERROR_STATUS_RPE = 0x00400000,
+ PORT_FATAL_ERROR_STATUS_MPE = 0x00800000,
+ PORT_FATAL_ERROR_STATUS_OCE = 0x01000000,
+};
+
+/*
+ * port control and status page - page 0
+ */
+
+struct ql3xxx_port_registers {
+ struct ql3xxx_common_registers CommonRegs;
+
+ u32 ExternalHWConfig;
+ u32 InternalChipConfig;
+ u32 portControl;
+ u32 portStatus;
+ u32 macAddrIndirectPtrReg;
+ u32 macAddrDataReg;
+ u32 macMIIMgmtControlReg;
+ u32 macMIIMgmtAddrReg;
+ u32 macMIIMgmtDataReg;
+ u32 macMIIStatusReg;
+ u32 mac0ConfigReg;
+ u32 mac0IpgIfgReg;
+ u32 mac0HalfDuplexReg;
+ u32 mac0MaxFrameLengthReg;
+ u32 mac0PauseThresholdReg;
+ u32 mac1ConfigReg;
+ u32 mac1IpgIfgReg;
+ u32 mac1HalfDuplexReg;
+ u32 mac1MaxFrameLengthReg;
+ u32 mac1PauseThresholdReg;
+ u32 ipAddrIndexReg;
+ u32 ipAddrDataReg;
+ u32 ipReassemblyTimeout;
+ u32 tcpMaxWindow;
+ u32 currentTcpTimestamp[2];
+ u32 internalRamRWAddrReg;
+ u32 internalRamWDataReg;
+ u32 reclaimedBufferAddrRegLow;
+ u32 reclaimedBufferAddrRegHigh;
+ u32 reserved[2];
+ u32 fpgaRevID;
+ u32 localRamAddr;
+ u32 localRamDataAutoIncr;
+ u32 localRamDataNonIncr;
+ u32 gpOutput;
+ u32 gpInput;
+ u32 probeMuxAddr;
+ u32 probeMuxData;
+ u32 statisticsIndexReg;
+ u32 statisticsReadDataRegAutoIncr;
+ u32 statisticsReadDataRegNoIncr;
+ u32 PortFatalErrStatus;
+};
+
+/*
+ * port host memory config page - page 1
+ */
+struct ql3xxx_host_memory_registers {
+ struct ql3xxx_common_registers CommonRegs;
+
+ u32 reserved[12];
+
+ /* Network Request Queue */
+ u32 reqConsumerIndex;
+ u32 reqConsumerIndexAddrLow;
+ u32 reqConsumerIndexAddrHigh;
+ u32 reqBaseAddrLow;
+ u32 reqBaseAddrHigh;
+ u32 reqLength;
+
+ /* Network Completion Queue */
+ u32 rspProducerIndex;
+ u32 rspProducerIndexAddrLow;
+ u32 rspProducerIndexAddrHigh;
+ u32 rspBaseAddrLow;
+ u32 rspBaseAddrHigh;
+ u32 rspLength;
+
+ /* RX Large Buffer Queue */
+ u32 rxLargeQConsumerIndex;
+ u32 rxLargeQBaseAddrLow;
+ u32 rxLargeQBaseAddrHigh;
+ u32 rxLargeQLength;
+ u32 rxLargeBufferLength;
+
+ /* RX Small Buffer Queue */
+ u32 rxSmallQConsumerIndex;
+ u32 rxSmallQBaseAddrLow;
+ u32 rxSmallQBaseAddrHigh;
+ u32 rxSmallQLength;
+ u32 rxSmallBufferLength;
+
+};
+
+/*
+ * port local RAM page - page 2
+ */
+struct ql3xxx_local_ram_registers {
+ struct ql3xxx_common_registers CommonRegs;
+ u32 bufletSize;
+ u32 maxBufletCount;
+ u32 currentBufletCount;
+ u32 reserved;
+ u32 freeBufletThresholdLow;
+ u32 freeBufletThresholdHigh;
+ u32 ipHashTableBase;
+ u32 ipHashTableCount;
+ u32 tcpHashTableBase;
+ u32 tcpHashTableCount;
+ u32 ncbBase;
+ u32 maxNcbCount;
+ u32 currentNcbCount;
+ u32 drbBase;
+ u32 maxDrbCount;
+ u32 currentDrbCount;
+};
+
+/*
+ * definitions for Semaphore bits in Semaphore/Serial NVRAM interface register
+ */
+
+#define LS_64BITS(x) (u32)(0xffffffff & ((u64)x))
+#define MS_64BITS(x) (u32)(0xffffffff & (((u64)x)>>16>>16) )
+
+/*
+ * I/O register
+ */
+
+enum {
+ CONTROL_REG = 0,
+ STATUS_REG = 1,
+ PHY_STAT_LINK_UP = 0x0004,
+ PHY_CTRL_LOOPBACK = 0x4000,
+
+ PETBI_CONTROL_REG = 0x00,
+ PETBI_CTRL_SOFT_RESET = 0x8000,
+ PETBI_CTRL_AUTO_NEG = 0x1000,
+ PETBI_CTRL_RESTART_NEG = 0x0200,
+ PETBI_CTRL_FULL_DUPLEX = 0x0100,
+ PETBI_CTRL_SPEED_1000 = 0x0040,
+
+ PETBI_STATUS_REG = 0x01,
+ PETBI_STAT_NEG_DONE = 0x0020,
+ PETBI_STAT_LINK_UP = 0x0004,
+
+ PETBI_NEG_ADVER = 0x04,
+ PETBI_NEG_PAUSE = 0x0080,
+ PETBI_NEG_PAUSE_MASK = 0x0180,
+ PETBI_NEG_DUPLEX = 0x0020,
+ PETBI_NEG_DUPLEX_MASK = 0x0060,
+
+ PETBI_NEG_PARTNER = 0x05,
+ PETBI_NEG_ERROR_MASK = 0x3000,
+
+ PETBI_EXPANSION_REG = 0x06,
+ PETBI_EXP_PAGE_RX = 0x0002,
+
+ PETBI_TBI_CTRL = 0x11,
+ PETBI_TBI_RESET = 0x8000,
+ PETBI_TBI_AUTO_SENSE = 0x0100,
+ PETBI_TBI_SERDES_MODE = 0x0010,
+ PETBI_TBI_SERDES_WRAP = 0x0002,
+
+ AUX_CONTROL_STATUS = 0x1c,
+ PHY_AUX_NEG_DONE = 0x8000,
+ PHY_NEG_PARTNER = 5,
+ PHY_AUX_DUPLEX_STAT = 0x0020,
+ PHY_AUX_SPEED_STAT = 0x0018,
+ PHY_AUX_NO_HW_STRAP = 0x0004,
+ PHY_AUX_RESET_STICK = 0x0002,
+ PHY_NEG_PAUSE = 0x0400,
+ PHY_CTRL_SOFT_RESET = 0x8000,
+ PHY_NEG_ADVER = 4,
+ PHY_NEG_ADV_SPEED = 0x01e0,
+ PHY_CTRL_RESTART_NEG = 0x0200,
+};
+enum {
+/* AM29LV Flash definitions */
+ FM93C56A_START = 0x1,
+/* Commands */
+ FM93C56A_READ = 0x2,
+ FM93C56A_WEN = 0x0,
+ FM93C56A_WRITE = 0x1,
+ FM93C56A_WRITE_ALL = 0x0,
+ FM93C56A_WDS = 0x0,
+ FM93C56A_ERASE = 0x3,
+ FM93C56A_ERASE_ALL = 0x0,
+/* Command Extentions */
+ FM93C56A_WEN_EXT = 0x3,
+ FM93C56A_WRITE_ALL_EXT = 0x1,
+ FM93C56A_WDS_EXT = 0x0,
+ FM93C56A_ERASE_ALL_EXT = 0x2,
+/* Special Bits */
+ FM93C56A_READ_DUMMY_BITS = 1,
+ FM93C56A_READY = 0,
+ FM93C56A_BUSY = 1,
+ FM93C56A_CMD_BITS = 2,
+/* AM29LV Flash definitions */
+ FM93C56A_SIZE_8 = 0x100,
+ FM93C56A_SIZE_16 = 0x80,
+ FM93C66A_SIZE_8 = 0x200,
+ FM93C66A_SIZE_16 = 0x100,
+ FM93C86A_SIZE_16 = 0x400,
+/* Address Bits */
+ FM93C56A_NO_ADDR_BITS_16 = 8,
+ FM93C56A_NO_ADDR_BITS_8 = 9,
+ FM93C86A_NO_ADDR_BITS_16 = 10,
+/* Data Bits */
+ FM93C56A_DATA_BITS_16 = 16,
+ FM93C56A_DATA_BITS_8 = 8,
+};
+enum {
+/* Auburn Bits */
+ AUBURN_EEPROM_DI = 0x8,
+ AUBURN_EEPROM_DI_0 = 0x0,
+ AUBURN_EEPROM_DI_1 = 0x8,
+ AUBURN_EEPROM_DO = 0x4,
+ AUBURN_EEPROM_DO_0 = 0x0,
+ AUBURN_EEPROM_DO_1 = 0x4,
+ AUBURN_EEPROM_CS = 0x2,
+ AUBURN_EEPROM_CS_0 = 0x0,
+ AUBURN_EEPROM_CS_1 = 0x2,
+ AUBURN_EEPROM_CLK_RISE = 0x1,
+ AUBURN_EEPROM_CLK_FALL = 0x0,
+};
+enum {EEPROM_SIZE = FM93C86A_SIZE_16,
+ EEPROM_NO_ADDR_BITS = FM93C86A_NO_ADDR_BITS_16,
+ EEPROM_NO_DATA_BITS = FM93C56A_DATA_BITS_16,
+};
+
+/*
+ * MAC Config data structure
+ */
+ struct eeprom_port_cfg {
+ u16 etherMtu_mac;
+ u16 pauseThreshold_mac;
+ u16 resumeThreshold_mac;
+ u16 portConfiguration;
+#define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000
+#define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000
+#define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000
+#define PORT_CONFIG_HALF_DUPLEX_ENABLED 0x1000
+#define PORT_CONFIG_1000MB_SPEED 0x0400
+#define PORT_CONFIG_100MB_SPEED 0x0200
+#define PORT_CONFIG_10MB_SPEED 0x0100
+#define PORT_CONFIG_LINK_SPEED_MASK 0x0F00
+ u16 reserved[12];
+
+};
+
+/*
+ * BIOS data structure
+ */
+struct eeprom_bios_cfg {
+ u16 SpinDlyEn:1, disBios:1, EnMemMap:1, EnSelectBoot:1, Reserved:12;
+
+ u8 bootID0:7, boodID0Valid:1;
+ u8 bootLun0[8];
+
+ u8 bootID1:7, boodID1Valid:1;
+ u8 bootLun1[8];
+
+ u16 MaxLunsTrgt;
+ u8 reserved[10];
+};
+
+/*
+ * Function Specific Data structure
+ */
+struct eeprom_function_cfg {
+ u8 reserved[30];
+ u8 macAddress[6];
+ u8 macAddressSecondary[6];
+
+ u16 subsysVendorId;
+ u16 subsysDeviceId;
+};
+
+/*
+ * EEPROM format
+ */
+struct eeprom_data {
+ u8 asicId[4];
+ u8 version;
+ u8 numPorts;
+ u16 boardId;
+
+#define EEPROM_BOARDID_STR_SIZE 16
+#define EEPROM_SERIAL_NUM_SIZE 16
+
+ u8 boardIdStr[16];
+ u8 serialNumber[16];
+ u16 extHwConfig;
+ struct eeprom_port_cfg macCfg_port0;
+ struct eeprom_port_cfg macCfg_port1;
+ u16 bufletSize;
+ u16 bufletCount;
+ u16 tcpWindowThreshold50;
+ u16 tcpWindowThreshold25;
+ u16 tcpWindowThreshold0;
+ u16 ipHashTableBaseHi;
+ u16 ipHashTableBaseLo;
+ u16 ipHashTableSize;
+ u16 tcpHashTableBaseHi;
+ u16 tcpHashTableBaseLo;
+ u16 tcpHashTableSize;
+ u16 ncbTableBaseHi;
+ u16 ncbTableBaseLo;
+ u16 ncbTableSize;
+ u16 drbTableBaseHi;
+ u16 drbTableBaseLo;
+ u16 drbTableSize;
+ u16 reserved_142[4];
+ u16 ipReassemblyTimeout;
+ u16 tcpMaxWindowSize;
+ u16 ipSecurity;
+#define IPSEC_CONFIG_PRESENT 0x0001
+ u8 reserved_156[294];
+ u16 qDebug[8];
+ struct eeprom_function_cfg funcCfg_fn0;
+ u16 reserved_510;
+ u8 oemSpace[432];
+ struct eeprom_bios_cfg biosCfg_fn1;
+ struct eeprom_function_cfg funcCfg_fn1;
+ u16 reserved_1022;
+ u8 reserved_1024[464];
+ struct eeprom_function_cfg funcCfg_fn2;
+ u16 reserved_1534;
+ u8 reserved_1536[432];
+ struct eeprom_bios_cfg biosCfg_fn3;
+ struct eeprom_function_cfg funcCfg_fn3;
+ u16 checksum;
+};
+
+/*
+ * General definitions...
+ */
+
+/*
+ * Below are a number compiler switches for controlling driver behavior.
+ * Some are not supported under certain conditions and are notated as such.
+ */
+
+#define QL3XXX_VENDOR_ID 0x1077
+#define QL3022_DEVICE_ID 0x3022
+
+/* MTU & Frame Size stuff */
+#define NORMAL_MTU_SIZE ETH_DATA_LEN
+#define JUMBO_MTU_SIZE 9000
+#define VLAN_ID_LEN 2
+
+/* Request Queue Related Definitions */
+#define NUM_REQ_Q_ENTRIES 256 /* so that 64 * 64 = 4096 (1 page) */
+
+/* Response Queue Related Definitions */
+#define NUM_RSP_Q_ENTRIES 256 /* so that 256 * 16 = 4096 (1 page) */
+
+/* Transmit and Receive Buffers */
+#define NUM_LBUFQ_ENTRIES 128
+#define NUM_SBUFQ_ENTRIES 64
+#define QL_SMALL_BUFFER_SIZE 32
+#define QL_ADDR_ELE_PER_BUFQ_ENTRY \
+(sizeof(struct lrg_buf_q_entry) / sizeof(struct bufq_addr_element))
+ /* Each send has at least control block. This is how many we keep. */
+#define NUM_SMALL_BUFFERS NUM_SBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
+#define NUM_LARGE_BUFFERS NUM_LBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
+#define QL_HEADER_SPACE 32 /* make header space at top of skb. */
+/*
+ * Large & Small Buffers for Receives
+ */
+struct lrg_buf_q_entry {
+
+ u32 addr0_lower;
+#define IAL_LAST_ENTRY 0x00000001
+#define IAL_CONT_ENTRY 0x00000002
+#define IAL_FLAG_MASK 0x00000003
+ u32 addr0_upper;
+ u32 addr1_lower;
+ u32 addr1_upper;
+ u32 addr2_lower;
+ u32 addr2_upper;
+ u32 addr3_lower;
+ u32 addr3_upper;
+ u32 addr4_lower;
+ u32 addr4_upper;
+ u32 addr5_lower;
+ u32 addr5_upper;
+ u32 addr6_lower;
+ u32 addr6_upper;
+ u32 addr7_lower;
+ u32 addr7_upper;
+
+};
+
+struct bufq_addr_element {
+ u32 addr_low;
+ u32 addr_high;
+};
+
+#define QL_NO_RESET 0
+#define QL_DO_RESET 1
+
+enum link_state_t {
+ LS_UNKNOWN = 0,
+ LS_DOWN,
+ LS_DEGRADE,
+ LS_RECOVER,
+ LS_UP,
+};
+
+struct ql_rcv_buf_cb {
+ struct ql_rcv_buf_cb *next;
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+ DECLARE_PCI_UNMAP_LEN(maplen);
+ __le32 buf_phy_addr_low;
+ __le32 buf_phy_addr_high;
+ int index;
+};
+
+struct ql_tx_buf_cb {
+ struct sk_buff *skb;
+ struct ob_mac_iocb_req *queue_entry ;
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+ DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
+/* definitions for type field */
+#define QL_BUF_TYPE_MACIOCB 0x01
+#define QL_BUF_TYPE_IPIOCB 0x02
+#define QL_BUF_TYPE_TCPIOCB 0x03
+
+/* qdev->flags definitions. */
+enum { QL_RESET_DONE = 1, /* Reset finished. */
+ QL_RESET_ACTIVE = 2, /* Waiting for reset to finish. */
+ QL_RESET_START = 3, /* Please reset the chip. */
+ QL_RESET_PER_SCSI = 4, /* SCSI driver requests reset. */
+ QL_TX_TIMEOUT = 5, /* Timeout in progress. */
+ QL_LINK_MASTER = 6, /* This driver controls the link. */
+ QL_ADAPTER_UP = 7, /* Adapter has been brought up. */
+ QL_THREAD_UP = 8, /* This flag is available. */
+ QL_LINK_UP = 9, /* Link Status. */
+ QL_ALLOC_REQ_RSP_Q_DONE = 10,
+ QL_ALLOC_BUFQS_DONE = 11,
+ QL_ALLOC_SMALL_BUF_DONE = 12,
+ QL_LINK_OPTICAL = 13,
+ QL_MSI_ENABLED = 14,
+};
+
+/*
+ * ql3_adapter - The main Adapter structure definition.
+ * This structure has all fields relevant to the hardware.
+ */
+
+struct ql3_adapter {
+ u32 reserved_00;
+ unsigned long flags;
+
+ /* PCI Configuration information for this device */
+ struct pci_dev *pdev;
+ struct net_device *ndev; /* Parent NET device */
+
+ /* Hardware information */
+ u8 chip_rev_id;
+ u8 pci_slot;
+ u8 pci_width;
+ u8 pci_x;
+ u32 msi;
+ int index;
+ struct timer_list adapter_timer; /* timer used for various functions */
+
+ spinlock_t adapter_lock;
+ spinlock_t hw_lock;
+
+ /* PCI Bus Relative Register Addresses */
+ u8 *mmap_virt_base; /* stores return value from ioremap() */
+ struct ql3xxx_port_registers __iomem *mem_map_registers;
+ u32 current_page; /* tracks current register page */
+
+ u32 msg_enable;
+ u8 reserved_01[2];
+ u8 reserved_02[2];
+
+ /* Page for Shadow Registers */
+ void *shadow_reg_virt_addr;
+ dma_addr_t shadow_reg_phy_addr;
+
+ /* Net Request Queue */
+ u32 req_q_size;
+ u32 reserved_03;
+ struct ob_mac_iocb_req *req_q_virt_addr;
+ dma_addr_t req_q_phy_addr;
+ u16 req_producer_index;
+ u16 reserved_04;
+ u16 *preq_consumer_index;
+ u32 req_consumer_index_phy_addr_high;
+ u32 req_consumer_index_phy_addr_low;
+ atomic_t tx_count;
+ struct ql_tx_buf_cb tx_buf[NUM_REQ_Q_ENTRIES];
+
+ /* Net Response Queue */
+ u32 rsp_q_size;
+ u32 eeprom_cmd_data;
+ struct net_rsp_iocb *rsp_q_virt_addr;
+ dma_addr_t rsp_q_phy_addr;
+ struct net_rsp_iocb *rsp_current;
+ u16 rsp_consumer_index;
+ u16 reserved_06;
+ u32 *prsp_producer_index;
+ u32 rsp_producer_index_phy_addr_high;
+ u32 rsp_producer_index_phy_addr_low;
+
+ /* Large Buffer Queue */
+ u32 lrg_buf_q_alloc_size;
+ u32 lrg_buf_q_size;
+ void *lrg_buf_q_alloc_virt_addr;
+ void *lrg_buf_q_virt_addr;
+ dma_addr_t lrg_buf_q_alloc_phy_addr;
+ dma_addr_t lrg_buf_q_phy_addr;
+ u32 lrg_buf_q_producer_index;
+ u32 lrg_buf_release_cnt;
+ struct bufq_addr_element *lrg_buf_next_free;
+
+ /* Large (Receive) Buffers */
+ struct ql_rcv_buf_cb lrg_buf[NUM_LARGE_BUFFERS];
+ struct ql_rcv_buf_cb *lrg_buf_free_head;
+ struct ql_rcv_buf_cb *lrg_buf_free_tail;
+ u32 lrg_buf_free_count;
+ u32 lrg_buffer_len;
+ u32 lrg_buf_index;
+ u32 lrg_buf_skb_check;
+
+ /* Small Buffer Queue */
+ u32 small_buf_q_alloc_size;
+ u32 small_buf_q_size;
+ u32 small_buf_q_producer_index;
+ void *small_buf_q_alloc_virt_addr;
+ void *small_buf_q_virt_addr;
+ dma_addr_t small_buf_q_alloc_phy_addr;
+ dma_addr_t small_buf_q_phy_addr;
+ u32 small_buf_index;
+
+ /* Small (Receive) Buffers */
+ void *small_buf_virt_addr;
+ dma_addr_t small_buf_phy_addr;
+ u32 small_buf_phy_addr_low;
+ u32 small_buf_phy_addr_high;
+ u32 small_buf_release_cnt;
+ u32 small_buf_total_size;
+
+ /* ISR related, saves status for DPC. */
+ u32 control_status;
+
+ struct eeprom_data nvram_data;
+ struct timer_list ioctl_timer;
+ u32 port_link_state;
+ u32 last_rsp_offset;
+
+ /* 4022 specific */
+ u32 mac_index; /* Driver's MAC number can be 0 or 1 for first and second networking functions respectively */
+ u32 PHYAddr; /* Address of PHY 0x1e00 Port 0 and 0x1f00 Port 1 */
+ u32 mac_ob_opcode; /* Opcode to use on mac transmission */
+ u32 tcp_ob_opcode; /* Opcode to use on tcp transmission */
+ u32 update_ob_opcode; /* Opcode to use for updating NCB */
+ u32 mb_bit_mask; /* MA Bits mask to use on transmission */
+ u32 numPorts;
+ struct net_device_stats stats;
+ struct workqueue_struct *workqueue;
+ struct work_struct reset_work;
+ struct work_struct tx_timeout_work;
+ u32 max_frame_size;
+};
+
+#endif /* _QLA3XXX_H_ */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 4c2f575faad..5722a5638ff 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2809,7 +2809,7 @@ static struct pci_driver rtl8169_pci_driver = {
static int __init
rtl8169_init_module(void)
{
- return pci_module_init(&rtl8169_pci_driver);
+ return pci_register_driver(&rtl8169_pci_driver);
}
static void __exit
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index c3ed734cbe3..31bcdad5471 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1736,7 +1736,7 @@ static struct pci_driver rr_driver = {
static int __init rr_init_module(void)
{
- return pci_module_init(&rr_driver);
+ return pci_register_driver(&rr_driver);
}
static void __exit rr_cleanup_module(void)
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index e72e0e09906..c16f9156c98 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -7233,7 +7233,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
int __init s2io_starter(void)
{
- return pci_module_init(&s2io_driver);
+ return pci_register_driver(&s2io_driver);
}
/**
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index b2acedbefa8..c479b07be78 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -1131,7 +1131,7 @@ static struct pci_driver saa9730_driver = {
static int __init saa9730_init(void)
{
- return pci_module_init(&saa9730_driver);
+ return pci_register_driver(&saa9730_driver);
}
static void __exit saa9730_cleanup(void)
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index df0cbebb327..16e30d523fc 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1871,7 +1871,7 @@ static struct pci_driver sis190_pci_driver = {
static int __init sis190_init_module(void)
{
- return pci_module_init(&sis190_pci_driver);
+ return pci_register_driver(&sis190_pci_driver);
}
static void __exit sis190_cleanup_module(void)
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 29ee7ffedff..6af50286349 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -134,6 +134,7 @@ static const struct mii_chip_info {
{ "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN },
{ "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME},
{ "ICS LAN PHY", 0x0015, 0xF440, LAN },
+ { "ICS LAN PHY", 0x0143, 0xBC70, LAN },
{ "NS 83851 PHY", 0x2000, 0x5C20, MIX },
{ "NS 83847 PHY", 0x2000, 0x5C30, MIX },
{ "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN },
@@ -2495,7 +2496,7 @@ static int __init sis900_init_module(void)
printk(version);
#endif
- return pci_module_init(&sis900_pci_driver);
+ return pci_register_driver(&sis900_pci_driver);
}
static void __exit sis900_cleanup_module(void)
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index ee62845d3ac..49e76c7f10d 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -5133,7 +5133,7 @@ static struct pci_driver skge_driver = {
static int __init skge_init(void)
{
- return pci_module_init(&skge_driver);
+ return pci_register_driver(&skge_driver);
}
static void __exit skge_exit(void)
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index b5714a60237..8e4d18440a5 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -2280,7 +2280,7 @@ static struct pci_driver skfddi_pci_driver = {
static int __init skfd_init(void)
{
- return pci_module_init(&skfddi_pci_driver);
+ return pci_register_driver(&skfddi_pci_driver);
}
static void __exit skfd_exit(void)
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index ad878dfddef..1b752141a4f 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3510,7 +3510,7 @@ static struct pci_driver skge_driver = {
static int __init skge_init_module(void)
{
- return pci_module_init(&skge_driver);
+ return pci_register_driver(&skge_driver);
}
static void __exit skge_cleanup_module(void)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 933e87f1cc6..805a7dcf550 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -50,7 +50,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.5"
+#define DRV_VERSION "1.6"
#define PFX DRV_NAME " "
/*
@@ -121,6 +121,11 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) },
{ 0 }
};
@@ -1926,12 +1931,6 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
}
}
-/* Is status ring empty or is there more to do? */
-static inline int sky2_more_work(const struct sky2_hw *hw)
-{
- return (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX));
-}
-
/* Process status response ring */
static int sky2_status_intr(struct sky2_hw *hw, int to_do)
{
@@ -2022,6 +2021,9 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
}
}
+ /* Fully processed status ring so clear irq */
+ sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+
exit_loop:
if (buf_write[0]) {
sky2 = netdev_priv(hw->dev[0]);
@@ -2231,19 +2233,16 @@ static int sky2_poll(struct net_device *dev0, int *budget)
sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
work_done = sky2_status_intr(hw, work_limit);
- *budget -= work_done;
- dev0->quota -= work_done;
-
- if (status & Y2_IS_STAT_BMU)
- sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+ if (work_done < work_limit) {
+ netif_rx_complete(dev0);
- if (sky2_more_work(hw))
+ sky2_read32(hw, B0_Y2_SP_LISR);
+ return 0;
+ } else {
+ *budget -= work_done;
+ dev0->quota -= work_done;
return 1;
-
- netif_rx_complete(dev0);
-
- sky2_read32(hw, B0_Y2_SP_LISR);
- return 0;
+ }
}
static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
index 3a1b7131681..9a540e2092b 100644
--- a/drivers/net/slhc.c
+++ b/drivers/net/slhc.c
@@ -94,27 +94,23 @@ slhc_init(int rslots, int tslots)
register struct cstate *ts;
struct slcompress *comp;
- comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
- GFP_KERNEL);
+ comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
if (! comp)
goto out_fail;
- memset(comp, 0, sizeof(struct slcompress));
if ( rslots > 0 && rslots < 256 ) {
size_t rsize = rslots * sizeof(struct cstate);
- comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL);
+ comp->rstate = kzalloc(rsize, GFP_KERNEL);
if (! comp->rstate)
goto out_free;
- memset(comp->rstate, 0, rsize);
comp->rslot_limit = rslots - 1;
}
if ( tslots > 0 && tslots < 256 ) {
size_t tsize = tslots * sizeof(struct cstate);
- comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL);
+ comp->tstate = kzalloc(tsize, GFP_KERNEL);
if (! comp->tstate)
goto out_free2;
- memset(comp->tstate, 0, tsize);
comp->tslot_limit = tslots - 1;
}
@@ -141,9 +137,9 @@ slhc_init(int rslots, int tslots)
return comp;
out_free2:
- kfree((unsigned char *)comp->rstate);
+ kfree(comp->rstate);
out_free:
- kfree((unsigned char *)comp);
+ kfree(comp);
out_fail:
return NULL;
}
@@ -700,20 +696,6 @@ EXPORT_SYMBOL(slhc_compress);
EXPORT_SYMBOL(slhc_uncompress);
EXPORT_SYMBOL(slhc_toss);
-#ifdef MODULE
-
-int init_module(void)
-{
- printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n");
- return 0;
-}
-
-void cleanup_module(void)
-{
- return;
-}
-
-#endif /* MODULE */
#else /* CONFIG_INET */
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 0b15290df27..4438fe8c949 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -55,8 +55,6 @@ static const char version[] =
)
#endif
-
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index c0a62b00ffc..8e1f6206b7d 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -2053,7 +2053,7 @@ static int __init starfire_init (void)
return -ENODEV;
}
- return pci_module_init (&starfire_driver);
+ return pci_register_driver(&starfire_driver);
}
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 698568e751d..c243a80f400 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -17,6 +17,8 @@
Support and updates available at
http://www.scyld.com/network/sundance.html
[link no longer provides useful info -jgarzik]
+ Archives of the mailing list are still available at
+ http://www.beowulf.org/pipermail/netdrivers/
*/
@@ -646,7 +648,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
/* Reset the chip to erase previous misconfiguration. */
if (netif_msg_hw(np))
printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
- iowrite16(0x00ff, ioaddr + ASICCtrl + 2);
+ sundance_reset(dev, 0x00ff << 16);
if (netif_msg_hw(np))
printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
@@ -1075,13 +1077,8 @@ reset_tx (struct net_device *dev)
/* Reset tx logic, TxListPtr will be cleaned */
iowrite16 (TxDisable, ioaddr + MACCtrl1);
- iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset,
- ioaddr + ASICCtrl + 2);
- for (i=50; i > 0; i--) {
- if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
- break;
- mdelay(1);
- }
+ sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16);
+
/* free all tx skbuff */
for (i = 0; i < TX_RING_SIZE; i++) {
skb = np->tx_skbuff[i];
@@ -1736,7 +1733,7 @@ static int __init sundance_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&sundance_driver);
+ return pci_register_driver(&sundance_driver);
}
static void __exit sundance_exit(void)
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index b70bbd74897..1a441a8a2ad 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -3194,7 +3194,7 @@ static struct pci_driver gem_driver = {
static int __init gem_init(void)
{
- return pci_module_init(&gem_driver);
+ return pci_register_driver(&gem_driver);
}
static void __exit gem_cleanup(void)
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 8b53ded66d3..39460fa916f 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1725,7 +1725,7 @@ static struct pci_driver tc35815_driver = {
static int __init tc35815_init_module(void)
{
- return pci_module_init(&tc35815_driver);
+ return pci_register_driver(&tc35815_driver);
}
static void __exit tc35815_cleanup_module(void)
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index eafabb253f0..d6e2a6869f2 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -11819,7 +11819,7 @@ static struct pci_driver tg3_driver = {
static int __init tg3_init(void)
{
- return pci_module_init(&tg3_driver);
+ return pci_register_driver(&tg3_driver);
}
static void __exit tg3_cleanup(void)
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 465921e3874..412390ba142 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -1815,7 +1815,7 @@ static struct pci_driver xl_3c359_driver = {
static int __init xl_pci_init (void)
{
- return pci_module_init (&xl_3c359_driver);
+ return pci_register_driver(&xl_3c359_driver);
}
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 28d968ffd5d..0d66700c6ce 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -1998,7 +1998,7 @@ static struct pci_driver streamer_pci_driver = {
};
static int __init streamer_init_module(void) {
- return pci_module_init(&streamer_pci_driver);
+ return pci_register_driver(&streamer_pci_driver);
}
static void __exit streamer_cleanup_module(void) {
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index d05c5aa254e..350a73e99a8 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -2172,7 +2172,7 @@ static int __init de_init (void)
#ifdef MODULE
printk("%s", version);
#endif
- return pci_module_init (&de_driver);
+ return pci_register_driver(&de_driver);
}
static void __exit de_exit (void)
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 75ff14a5523..e661d0a9cc6 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -5754,7 +5754,7 @@ static int __init de4x5_module_init (void)
int err = 0;
#ifdef CONFIG_PCI
- err = pci_module_init (&de4x5_pci_driver);
+ err = pci_register_driver(&de4x5_pci_driver);
#endif
#ifdef CONFIG_EISA
err |= eisa_driver_register (&de4x5_eisa_driver);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 4e5b0f2acc3..66dade55682 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -2039,7 +2039,7 @@ static int __init dmfe_init_module(void)
if (HPNA_NoiseFloor > 15)
HPNA_NoiseFloor = 0;
- rc = pci_module_init(&dmfe_driver);
+ rc = pci_register_driver(&dmfe_driver);
if (rc < 0)
return rc;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 7351831f57c..e1987ec493c 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1849,7 +1849,7 @@ static int __init tulip_init (void)
tulip_max_interrupt_work = max_interrupt_work;
/* probe for and init boards */
- return pci_module_init (&tulip_driver);
+ return pci_register_driver(&tulip_driver);
}
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index fd64b2b3e99..c4c720e2d4c 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -1702,7 +1702,6 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8
static int __init uli526x_init_module(void)
{
- int rc;
printk(version);
printed_version = 1;
@@ -1714,22 +1713,19 @@ static int __init uli526x_init_module(void)
if (cr6set)
uli526x_cr6_user_set = cr6set;
- switch(mode) {
+ switch (mode) {
case ULI526X_10MHF:
case ULI526X_100MHF:
case ULI526X_10MFD:
case ULI526X_100MFD:
uli526x_media_mode = mode;
break;
- default:uli526x_media_mode = ULI526X_AUTO;
+ default:
+ uli526x_media_mode = ULI526X_AUTO;
break;
}
- rc = pci_module_init(&uli526x_driver);
- if (rc < 0)
- return rc;
-
- return 0;
+ return pci_register_driver(&uli526x_driver);
}
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index eba9083da14..6b82d149822 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1689,7 +1689,7 @@ static struct pci_driver w840_driver = {
static int __init w840_init(void)
{
printk(version);
- return pci_module_init(&w840_driver);
+ return pci_register_driver(&w840_driver);
}
static void __exit w840_exit(void)
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index 17ca7dc42e6..d797b7b2e35 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -1707,7 +1707,7 @@ static int __init xircom_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&xircom_driver);
+ return pci_register_driver(&xircom_driver);
}
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 4103c37172f..1014461178c 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -2660,7 +2660,7 @@ static struct pci_driver typhoon_driver = {
static int __init
typhoon_init(void)
{
- return pci_module_init(&typhoon_driver);
+ return pci_register_driver(&typhoon_driver);
}
static void __exit
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index ae971080e2e..efeb10b9c61 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -2005,7 +2005,7 @@ static int __init rhine_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&rhine_driver);
+ return pci_register_driver(&rhine_driver);
}
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index aa9cd92f46b..e266db1518e 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -2250,7 +2250,7 @@ static int __init velocity_init_module(void)
int ret;
velocity_register_notifier();
- ret = pci_module_init(&velocity_driver);
+ ret = pci_register_driver(&velocity_driver);
if (ret < 0)
velocity_unregister_notifier();
return ret;
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 496c3d59744..4665ef2c63d 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -262,25 +262,6 @@ struct velocity_rd_info {
dma_addr_t skb_dma;
};
-/**
- * alloc_rd_info - allocate an rd info block
- *
- * Alocate and initialize a receive info structure used for keeping
- * track of kernel side information related to each receive
- * descriptor we are using
- */
-
-static inline struct velocity_rd_info *alloc_rd_info(void)
-{
- struct velocity_rd_info *ptr;
- if ((ptr = kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL)
- return NULL;
- else {
- memset(ptr, 0, sizeof(struct velocity_rd_info));
- return ptr;
- }
-}
-
/*
* Used to track transmit side buffers.
*/
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 430b1f630fb..a5e7ce1bd16 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -40,7 +40,6 @@
* 1998/08/08 acme Initial version.
*/
-#include <linux/config.h> /* OS configuration options */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
#include <linux/string.h> /* inline memset(), etc. */
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 6e1ec5bf22f..73698755943 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -28,7 +28,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h> /* for CONFIG_DLCI_COUNT */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 684af4316ff..af4d4155905 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -2062,7 +2062,7 @@ static struct pci_driver dscc4_driver = {
static int __init dscc4_init_module(void)
{
- return pci_module_init(&dscc4_driver);
+ return pci_register_driver(&dscc4_driver);
}
static void __exit dscc4_cleanup_module(void)
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 3705db04a34..564351aafa4 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2697,7 +2697,7 @@ fst_init(void)
for (i = 0; i < FST_MAX_CARDS; i++)
fst_card_array[i] = NULL;
spin_lock_init(&fst_work_q_lock);
- return pci_module_init(&fst_driver);
+ return pci_register_driver(&fst_driver);
}
static void __exit
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 39f44241a72..7b5d81deb02 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1790,7 +1790,7 @@ static struct pci_driver lmc_driver = {
static int __init init_lmc(void)
{
- return pci_module_init(&lmc_driver);
+ return pci_register_driver(&lmc_driver);
}
static void __exit exit_lmc(void)
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 567effff4a3..56e69403d17 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -3677,7 +3677,7 @@ static struct pci_driver cpc_driver = {
static int __init cpc_init(void)
{
- return pci_module_init(&cpc_driver);
+ return pci_register_driver(&cpc_driver);
}
static void __exit cpc_cleanup_module(void)
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index 4df61fa3214..a6b9c33b68e 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -476,7 +476,7 @@ static int __init pci200_init_module(void)
printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n");
return -EINVAL;
}
- return pci_module_init(&pci200_pci_driver);
+ return pci_register_driver(&pci200_pci_driver);
}
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 7628c2d81f4..0ba018f8382 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -32,7 +32,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h> /* for CONFIG_DLCI_MAX */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index b2031dfc4bb..ec68f7dfd93 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -837,7 +837,7 @@ static int __init wanxl_init_module(void)
#ifdef MODULE
printk(KERN_INFO "%s\n", version);
#endif
- return pci_module_init(&wanxl_pci_driver);
+ return pci_register_driver(&wanxl_pci_driver);
}
static void __exit wanxl_cleanup_module(void)
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index a4dd1394271..16befbcea58 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -3950,13 +3950,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
pRsp->rsp0 = IN4500(ai, RESP0);
pRsp->rsp1 = IN4500(ai, RESP1);
pRsp->rsp2 = IN4500(ai, RESP2);
- if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
- airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
- airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
- airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
- airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
- airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
- }
+ if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
+ airo_print_err(ai->dev->name,
+ "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
+ pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
+ pRsp->rsp2);
// clear stuck command busy if necessary
if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c
index d425c3cefde..3bfa791c323 100644
--- a/drivers/net/wireless/atmel_pci.c
+++ b/drivers/net/wireless/atmel_pci.c
@@ -76,7 +76,7 @@ static void __devexit atmel_pci_remove(struct pci_dev *pdev)
static int __init atmel_init_module(void)
{
- return pci_module_init(&atmel_driver);
+ return pci_register_driver(&atmel_driver);
}
static void __exit atmel_cleanup_module(void)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 17a56828e23..c6ee1e974c8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -504,6 +504,12 @@ struct bcm43xx_phyinfo {
* This lock is only used by bcm43xx_phy_{un}lock()
*/
spinlock_t lock;
+
+ /* Firmware. */
+ const struct firmware *ucode;
+ const struct firmware *pcm;
+ const struct firmware *initvals0;
+ const struct firmware *initvals1;
};
@@ -593,12 +599,14 @@ struct bcm43xx_coreinfo {
u8 available:1,
enabled:1,
initialized:1;
- /** core_id ID number */
- u16 id;
/** core_rev revision number */
u8 rev;
/** Index number for _switch_core() */
u8 index;
+ /** core_id ID number */
+ u16 id;
+ /** Core-specific data. */
+ void *priv;
};
/* Additional information for each 80211 core. */
@@ -647,7 +655,23 @@ enum {
BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
};
#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
-#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat))
+#define bcm43xx_set_status(bcm, stat) do { \
+ atomic_set(&(bcm)->init_status, (stat)); \
+ smp_wmb(); \
+ } while (0)
+
+/* *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
+ * and the device registers. This mutex does _not_ protect
+ * against concurrency from the IRQ handler.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * Please note that, if you only take the irq_lock, you are not protected
+ * against concurrency from the periodic work handlers.
+ * Most times you want to take _both_ locks.
+ */
struct bcm43xx_private {
struct ieee80211_device *ieee;
@@ -659,7 +683,6 @@ struct bcm43xx_private {
void __iomem *mmio_addr;
- /* Locking, see "theory of locking" text below. */
spinlock_t irq_lock;
struct mutex mutex;
@@ -691,6 +714,7 @@ struct bcm43xx_private {
struct bcm43xx_sprominfo sprom;
#define BCM43xx_NR_LEDS 4
struct bcm43xx_led leds[BCM43xx_NR_LEDS];
+ spinlock_t leds_lock;
/* The currently active core. */
struct bcm43xx_coreinfo *current_core;
@@ -708,10 +732,6 @@ struct bcm43xx_private {
struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
/* Additional information, specific to the 80211 cores. */
struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
- /* Index of the current 80211 core. If current_core is not
- * an 80211 core, this is -1.
- */
- int current_80211_core_idx;
/* Number of available 80211 cores. */
int nr_80211_available;
@@ -724,6 +744,8 @@ struct bcm43xx_private {
u32 irq_savedstate;
/* Link Quality calculation context. */
struct bcm43xx_noise_calculation noisecalc;
+ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+ int mac_suspended;
/* Threshold values. */
//TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
@@ -746,12 +768,6 @@ struct bcm43xx_private {
struct bcm43xx_key key[54];
u8 default_key_idx;
- /* Firmware. */
- const struct firmware *ucode;
- const struct firmware *pcm;
- const struct firmware *initvals0;
- const struct firmware *initvals1;
-
/* Random Number Generator. */
struct hwrng rng;
char rng_name[20 + 1];
@@ -763,55 +779,6 @@ struct bcm43xx_private {
};
-/* *** THEORY OF LOCKING ***
- *
- * We have two different locks in the bcm43xx driver.
- * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
- * and the device registers.
- * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
- *
- * We have three types of helper function pairs to utilize these locks.
- * (Always use the helper functions.)
- * 1) bcm43xx_{un}lock_noirq():
- * Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
- * so it is almost always unsafe, if device IRQs are enabled.
- * So only use this, if device IRQs are masked.
- * Locking may sleep.
- * You can sleep within the critical section.
- * 2) bcm43xx_{un}lock_irqonly():
- * Takes bcm->irq_lock. Does _not_ protect against
- * bcm43xx_lock_noirq() critical sections.
- * Does only protect against the IRQ handler path and other
- * irqonly() critical sections.
- * Locking does not sleep.
- * You must not sleep within the critical section.
- * 3) bcm43xx_{un}lock_irqsafe():
- * This is the cummulative lock and takes both, mutex and irq_lock.
- * Protects against noirq() and irqonly() critical sections (and
- * the IRQ handler path).
- * Locking may sleep.
- * You must not sleep within the critical section.
- */
-
-/* Lock type 1 */
-#define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex)
-#define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex)
-/* Lock type 2 */
-#define bcm43xx_lock_irqonly(bcm, flags) \
- spin_lock_irqsave(&(bcm)->irq_lock, flags)
-#define bcm43xx_unlock_irqonly(bcm, flags) \
- spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
-/* Lock type 3 */
-#define bcm43xx_lock_irqsafe(bcm, flags) do { \
- bcm43xx_lock_noirq(bcm); \
- bcm43xx_lock_irqonly(bcm, flags); \
- } while (0)
-#define bcm43xx_unlock_irqsafe(bcm, flags) do { \
- bcm43xx_unlock_irqonly(bcm, flags); \
- bcm43xx_unlock_noirq(bcm); \
- } while (0)
-
-
static inline
struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
{
@@ -863,34 +830,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm)
* any of these functions.
*/
static inline
+struct bcm43xx_coreinfo_80211 *
+bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
+{
+ assert(bcm->current_core->id == BCM43xx_COREID_80211);
+ return bcm->current_core->priv;
+}
+static inline
struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
{
assert(bcm43xx_using_pio(bcm));
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
+ return &(bcm43xx_current_80211_priv(bcm)->pio);
}
static inline
struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
{
assert(!bcm43xx_using_pio(bcm));
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
+ return &(bcm43xx_current_80211_priv(bcm)->dma);
}
static inline
struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
{
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
+ return &(bcm43xx_current_80211_priv(bcm)->phy);
}
static inline
struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
{
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
+ return &(bcm43xx_current_80211_priv(bcm)->radio);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index ce2e40b29b4..923275ea078 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
@@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("\n");
out:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
unsigned long flags;
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
out:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
u64 tsf;
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
(unsigned int)(tsf & 0xFFFFFFFFULL));
out:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = -EFAULT;
goto out_up;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = buf_size;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
out_up:
up(&big_buffer_sem);
return res;
@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
int i, cnt, j = 0;
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- bcm43xx_lock_irqsafe(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (*ppos == pos) {
/* Done. Drop the copied data. */
e->xmitstatus_printing = 0;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
+ up(&big_buffer_sem);
+ return res;
+}
+
+static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct bcm43xx_private *bcm = file->private_data;
+ char *buf = really_big_buffer;
+ ssize_t buf_size;
+ ssize_t res;
+ unsigned long flags;
+
+ buf_size = min(count, sizeof (really_big_buffer) - 1);
+ down(&big_buffer_sem);
+ if (copy_from_user(buf, user_buf, buf_size)) {
+ res = -EFAULT;
+ goto out_up;
+ }
+ mutex_lock(&(bcm)->mutex);
+ spin_lock_irqsave(&(bcm)->irq_lock, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+ printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ if (count > 0 && buf[0] == '1') {
+ bcm43xx_controller_restart(bcm, "manually restarted");
+ res = count;
+ } else
+ res = -EINVAL;
+
+out_unlock:
+ spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
+ mutex_unlock(&(bcm)->mutex);
+out_up:
up(&big_buffer_sem);
return res;
}
@@ -339,6 +385,11 @@ static struct file_operations txstat_fops = {
.open = open_file_generic,
};
+static struct file_operations restart_fops = {
+ .write = restart_write_file,
+ .open = open_file_generic,
+};
+
void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
{
@@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
bcm, &txstat_fops);
if (!e->dentry_txstat)
printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
+ e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
+ bcm, &restart_fops);
+ if (!e->dentry_restart)
+ printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
}
void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
@@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
debugfs_remove(e->dentry_devinfo);
debugfs_remove(e->dentry_tsf);
debugfs_remove(e->dentry_txstat);
+ debugfs_remove(e->dentry_restart);
debugfs_remove(e->subdir);
kfree(e->xmitstatus_buffer);
kfree(e->xmitstatus_print_buffer);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
index 50ce267f794..a40d1af3554 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
struct dentry *dentry_spromdump;
struct dentry *dentry_tsf;
struct dentry *dentry_txstat;
+ struct dentry *dentry_restart;
struct bcm43xx_private *bcm;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index ec80692d638..c3f90c8563d 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d)
struct bcm43xx_private *bcm = led->bcm;
unsigned long flags;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->leds_lock, flags);
if (led->blink_interval) {
bcm43xx_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval);
}
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->leds_lock, flags);
}
static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
int i, turn_on;
unsigned long interval = 0;
u16 ledctl;
+ unsigned long flags;
+ spin_lock_irqsave(&bcm->leds_lock, flags);
ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(bcm->leds[i]);
@@ -266,6 +268,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
ledctl &= ~(1 << i);
}
bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&bcm->leds_lock, flags);
}
void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
@@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
u16 ledctl;
int i;
int bit_on;
+ unsigned long flags;
+ spin_lock_irqsave(&bcm->leds_lock, flags);
ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(bcm->leds[i]);
@@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
ledctl &= ~(1 << i);
}
bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&bcm->leds_lock, flags);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index df317c1e12a..b095f3cc673 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -509,23 +509,19 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
}
/* Make sure we don't receive more data from the device. */
-static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
+static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
{
unsigned long flags;
- u32 old;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
return -EBUSY;
}
- old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_unlock_irqonly(bcm, flags);
+ bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
bcm43xx_synchronize_irq(bcm);
- if (oldstate)
- *oldstate = old;
-
return 0;
}
@@ -537,7 +533,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
u16 manufact;
u16 version;
u8 revision;
- s8 i;
if (bcm->chip_id == 0x4317) {
if (bcm->chip_rev == 0x00)
@@ -580,20 +575,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
radio->version = version;
radio->revision = revision;
- /* Set default attenuation values. */
- radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
- radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
- radio->txctl1 = bcm43xx_default_txctl1(bcm);
- radio->txctl2 = 0xFFFF;
if (phy->type == BCM43xx_PHYTYPE_A)
radio->txpower_desired = bcm->sprom.maxpower_aphy;
else
radio->txpower_desired = bcm->sprom.maxpower_bgphy;
- /* Initialize the in-memory nrssi Lookup Table. */
- for (i = 0; i < 64; i++)
- radio->nrssi_lt[i] = i;
-
return 0;
err_unsupported_radio:
@@ -1250,10 +1236,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
goto out;
bcm->current_core = new_core;
- bcm->current_80211_core_idx = -1;
- if (new_core->id == BCM43xx_COREID_80211)
- bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
-
out:
return err;
}
@@ -1423,43 +1405,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
bcm43xx_core_disable(bcm, 0);
}
-/* Mark the current 80211 core inactive.
- * "active_80211_core" is the other 80211 core, which is used.
- */
-static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
- struct bcm43xx_coreinfo *active_80211_core)
+/* Mark the current 80211 core inactive. */
+static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
{
u32 sbtmstatelow;
- struct bcm43xx_coreinfo *old_core;
- int err = 0;
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_radio_turn_off(bcm);
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= ~0x200a0000;
- sbtmstatelow |= 0xa0000;
+ sbtmstatelow &= 0xDFF5FFFF;
+ sbtmstatelow |= 0x000A0000;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
udelay(1);
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= ~0xa0000;
- sbtmstatelow |= 0x80000;
+ sbtmstatelow &= 0xFFF5FFFF;
+ sbtmstatelow |= 0x00080000;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
udelay(1);
-
- if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
- old_core = bcm->current_core;
- err = bcm43xx_switch_core(bcm, active_80211_core);
- if (err)
- goto out;
- sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= ~0x20000000;
- sbtmstatelow |= 0x20000000;
- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
- err = bcm43xx_switch_core(bcm, old_core);
- }
-
-out:
- return err;
}
static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
@@ -1720,7 +1682,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
# define bcmirq_handled(irq) do { /* nothing */ } while (0)
#endif /* CONFIG_BCM43XX_DEBUG*/
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
reason = bcm->irq_reason;
dma_reason[0] = bcm->dma_reason[0];
dma_reason[1] = bcm->dma_reason[1];
@@ -1746,7 +1708,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
dma_reason[2], dma_reason[3]);
bcm43xx_controller_restart(bcm, "DMA error");
mmiowb();
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
return;
}
if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1834,7 +1796,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
bcm43xx_leds_update(bcm, activity);
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
mmiowb();
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
}
static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1885,14 +1847,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
spin_lock(&bcm->irq_lock);
- /* Only accept IRQs, if we are initialized properly.
- * This avoids an RX race while initializing.
- * We should probably not enable IRQs before we are initialized
- * completely, but some careful work is needed to fix this. I think it
- * is best to stay with this cheap workaround for now... .
- */
- if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
- goto out;
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+ assert(bcm->current_core->id == BCM43xx_COREID_80211);
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
@@ -1930,16 +1886,18 @@ out:
static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
if (bcm->firmware_norelease && !force)
return; /* Suspending or controller reset. */
- release_firmware(bcm->ucode);
- bcm->ucode = NULL;
- release_firmware(bcm->pcm);
- bcm->pcm = NULL;
- release_firmware(bcm->initvals0);
- bcm->initvals0 = NULL;
- release_firmware(bcm->initvals1);
- bcm->initvals1 = NULL;
+ release_firmware(phy->ucode);
+ phy->ucode = NULL;
+ release_firmware(phy->pcm);
+ phy->pcm = NULL;
+ release_firmware(phy->initvals0);
+ phy->initvals0 = NULL;
+ release_firmware(phy->initvals1);
+ phy->initvals1 = NULL;
}
static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
@@ -1950,11 +1908,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
int nr;
char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
- if (!bcm->ucode) {
+ if (!phy->ucode) {
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
(rev >= 5 ? 5 : rev),
modparam_fwpostfix);
- err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: Microcode \"%s\" not available or load failed.\n",
@@ -1963,12 +1921,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
}
}
- if (!bcm->pcm) {
+ if (!phy->pcm) {
snprintf(buf, ARRAY_SIZE(buf),
"bcm43xx_pcm%d%s.fw",
(rev < 5 ? 4 : 5),
modparam_fwpostfix);
- err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: PCM \"%s\" not available or load failed.\n",
@@ -1977,7 +1935,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
}
}
- if (!bcm->initvals0) {
+ if (!phy->initvals0) {
if (rev == 2 || rev == 4) {
switch (phy->type) {
case BCM43xx_PHYTYPE_A:
@@ -2008,20 +1966,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
nr, modparam_fwpostfix);
- err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: InitVals \"%s\" not available or load failed.\n",
buf);
goto error;
}
- if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
+ if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
printk(KERN_ERR PFX "InitVals fileformat error.\n");
goto error;
}
}
- if (!bcm->initvals1) {
+ if (!phy->initvals1) {
if (rev >= 5) {
u32 sbtmstatehigh;
@@ -2043,14 +2001,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
nr, modparam_fwpostfix);
- err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: InitVals \"%s\" not available or load failed.\n",
buf);
goto error;
}
- if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
+ if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
printk(KERN_ERR PFX "InitVals fileformat error.\n");
goto error;
}
@@ -2070,12 +2028,13 @@ err_noinitval:
static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
const u32 *data;
unsigned int i, len;
/* Upload Microcode. */
- data = (u32 *)(bcm->ucode->data);
- len = bcm->ucode->size / sizeof(u32);
+ data = (u32 *)(phy->ucode->data);
+ len = phy->ucode->size / sizeof(u32);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
for (i = 0; i < len; i++) {
bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
@@ -2084,8 +2043,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
}
/* Upload PCM data. */
- data = (u32 *)(bcm->pcm->data);
- len = bcm->pcm->size / sizeof(u32);
+ data = (u32 *)(phy->pcm->data);
+ len = phy->pcm->size / sizeof(u32);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
@@ -2131,15 +2090,16 @@ err_format:
static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err;
- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
- bcm->initvals0->size / sizeof(struct bcm43xx_initval));
+ err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
+ phy->initvals0->size / sizeof(struct bcm43xx_initval));
if (err)
goto out;
- if (bcm->initvals1) {
- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
- bcm->initvals1->size / sizeof(struct bcm43xx_initval));
+ if (phy->initvals1) {
+ err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
+ phy->initvals1->size / sizeof(struct bcm43xx_initval));
if (err)
goto out;
}
@@ -2156,9 +2116,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = {
static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
{
- int res;
- unsigned int i;
- u32 data;
+ int err;
bcm->irq = bcm->pci_dev->irq;
#ifdef CONFIG_BCM947XX
@@ -2175,32 +2133,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
}
}
#endif
- res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
+ err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
IRQF_SHARED, KBUILD_MODNAME, bcm);
- if (res) {
+ if (err)
printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
- return -ENODEV;
- }
- bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
- i = 0;
- while (1) {
- data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (data == BCM43xx_IRQ_READY)
- break;
- i++;
- if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
- printk(KERN_ERR PFX "Card IRQ register not responding. "
- "Giving up.\n");
- free_irq(bcm->irq, bcm);
- return -ENODEV;
- }
- udelay(10);
- }
- // dummy read
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- return 0;
+ return err;
}
/* Switch to the core used to write the GPIO register.
@@ -2298,13 +2236,17 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
/* http://bcm-specs.sipsolutions.net/EnableMac */
void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
{
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
- | BCM43xx_SBF_MAC_ENABLED);
- bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
- bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+ bcm->mac_suspended--;
+ assert(bcm->mac_suspended >= 0);
+ if (bcm->mac_suspended == 0) {
+ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+ | BCM43xx_SBF_MAC_ENABLED);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+ bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+ }
}
/* http://bcm-specs.sipsolutions.net/SuspendMAC */
@@ -2313,18 +2255,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
int i;
u32 tmp;
- bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
- & ~BCM43xx_SBF_MAC_ENABLED);
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
- for (i = 100000; i; i--) {
- tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (tmp & BCM43xx_IRQ_READY)
- return;
- udelay(10);
+ assert(bcm->mac_suspended >= 0);
+ if (bcm->mac_suspended == 0) {
+ bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+ & ~BCM43xx_SBF_MAC_ENABLED);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+ for (i = 10000; i; i--) {
+ tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+ if (tmp & BCM43xx_IRQ_READY)
+ goto out;
+ udelay(1);
+ }
+ printkl(KERN_ERR PFX "MAC suspend failed\n");
}
- printkl(KERN_ERR PFX "MAC suspend failed\n");
+out:
+ bcm->mac_suspended++;
}
void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
@@ -2394,7 +2341,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
if (!modparam_noleds)
bcm43xx_leds_exit(bcm);
bcm43xx_gpio_cleanup(bcm);
- free_irq(bcm->irq, bcm);
bcm43xx_release_firmware(bcm, 0);
}
@@ -2406,7 +2352,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err;
- int tmp;
+ int i, tmp;
u32 value32;
u16 value16;
@@ -2419,13 +2365,26 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
goto out;
bcm43xx_upload_microcode(bcm);
- err = bcm43xx_initialize_irq(bcm);
- if (err)
- goto err_release_fw;
+ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
+ i = 0;
+ while (1) {
+ value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+ if (value32 == BCM43xx_IRQ_READY)
+ break;
+ i++;
+ if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
+ printk(KERN_ERR PFX "IRQ_READY timeout\n");
+ err = -ENODEV;
+ goto err_release_fw;
+ }
+ udelay(10);
+ }
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
err = bcm43xx_gpio_init(bcm);
if (err)
- goto err_free_irq;
+ goto err_release_fw;
err = bcm43xx_upload_initvals(bcm);
if (err)
@@ -2509,8 +2468,6 @@ err_radio_off:
bcm43xx_radio_turn_off(bcm);
err_gpio_cleanup:
bcm43xx_gpio_cleanup(bcm);
-err_free_irq:
- free_irq(bcm->irq, bcm);
err_release_fw:
bcm43xx_release_firmware(bcm, 1);
goto out;
@@ -2550,11 +2507,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
{
/* Initialize a "phyinfo" structure. The structure is already
* zeroed out.
+ * This is called on insmod time to initialize members.
*/
- phy->antenna_diversity = 0xFFFF;
phy->savedpctlreg = 0xFFFF;
- phy->minlowsig[0] = 0xFFFF;
- phy->minlowsig[1] = 0xFFFF;
spin_lock_init(&phy->lock);
}
@@ -2562,14 +2517,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
{
/* Initialize a "radioinfo" structure. The structure is already
* zeroed out.
+ * This is called on insmod time to initialize members.
*/
radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
radio->channel = 0xFF;
radio->initial_channel = 0xFF;
- radio->lofcal = 0xFFFF;
- radio->initval = 0xFFFF;
- radio->nrssi[0] = -1000;
- radio->nrssi[1] = -1000;
}
static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
@@ -2587,7 +2539,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
* BCM43xx_MAX_80211_CORES);
memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
* BCM43xx_MAX_80211_CORES);
- bcm->current_80211_core_idx = -1;
bcm->nr_80211_available = 0;
bcm->current_core = NULL;
bcm->active_80211_core = NULL;
@@ -2757,6 +2708,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
goto out;
}
bcm->nr_80211_available++;
+ core->priv = ext_80211;
bcm43xx_init_struct_phyinfo(&ext_80211->phy);
bcm43xx_init_struct_radioinfo(&ext_80211->radio);
break;
@@ -2857,7 +2809,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
}
/* http://bcm-specs.sipsolutions.net/80211Init */
-static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
+static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
+ int active_wlcore)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
@@ -2939,19 +2892,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
if (bcm->current_core->rev >= 5)
bcm43xx_write16(bcm, 0x043C, 0x000C);
- if (bcm43xx_using_pio(bcm))
- err = bcm43xx_pio_init(bcm);
- else
- err = bcm43xx_dma_init(bcm);
- if (err)
- goto err_chip_cleanup;
+ if (active_wlcore) {
+ if (bcm43xx_using_pio(bcm))
+ err = bcm43xx_pio_init(bcm);
+ else
+ err = bcm43xx_dma_init(bcm);
+ if (err)
+ goto err_chip_cleanup;
+ }
bcm43xx_write16(bcm, 0x0612, 0x0050);
bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
- bcm43xx_mac_enable(bcm);
- bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+ if (active_wlcore) {
+ if (radio->initial_channel != 0xFF)
+ bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
+ }
+ /* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
+ * We enable it later.
+ */
bcm->current_core->initialized = 1;
out:
return err;
@@ -3066,11 +3026,6 @@ out:
return err;
}
-static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
-{
- ieee80211softmac_start(bcm->net_dev);
-}
-
static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -3182,39 +3137,40 @@ static void bcm43xx_periodic_work_handler(void *d)
/* Periodic work will take a long time, so we want it to
* be preemtible.
*/
- bcm43xx_lock_irqonly(bcm, flags);
netif_stop_queue(bcm->net_dev);
+ synchronize_net();
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ bcm43xx_mac_suspend(bcm);
if (bcm43xx_using_pio(bcm))
bcm43xx_pio_freeze_txqueues(bcm);
savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_unlock_irqonly(bcm, flags);
- bcm43xx_lock_noirq(bcm);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_lock(&bcm->mutex);
bcm43xx_synchronize_irq(bcm);
} else {
/* Periodic work should take short time, so we want low
* locking overhead.
*/
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
}
do_periodic_work(bcm);
if (badness > BADNESS_LIMIT) {
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
tasklet_enable(&bcm->isr_tasklet);
bcm43xx_interrupt_enable(bcm, savedirqs);
if (bcm43xx_using_pio(bcm))
bcm43xx_pio_thaw_txqueues(bcm);
+ bcm43xx_mac_enable(bcm);
}
netif_wake_queue(bcm->net_dev);
- mmiowb();
- bcm43xx_unlock_irqonly(bcm, flags);
- bcm43xx_unlock_noirq(bcm);
- } else {
- mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
}
+ mmiowb();
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
}
static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
@@ -3243,9 +3199,9 @@ static int bcm43xx_rng_read(struct hwrng *rng, u32 *data)
struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
unsigned long flags;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&(bcm)->irq_lock, flags);
*data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
return (sizeof(u16));
}
@@ -3271,139 +3227,322 @@ static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
return err;
}
-/* This is the opposite of bcm43xx_init_board() */
-static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
{
+ int ret = 0;
int i, err;
+ struct bcm43xx_coreinfo *core;
- bcm43xx_lock_noirq(bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+ for (i = 0; i < bcm->nr_80211_available; i++) {
+ core = &(bcm->core_80211[i]);
+ assert(core->available);
+ if (!core->initialized)
+ continue;
+ err = bcm43xx_switch_core(bcm, core);
+ if (err) {
+ dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
+ "switch_core failed (%d)\n", err);
+ ret = err;
+ continue;
+ }
+ bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+ bcm43xx_wireless_core_cleanup(bcm);
+ if (core == bcm->active_80211_core)
+ bcm->active_80211_core = NULL;
+ }
+ free_irq(bcm->irq, bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+
+ return ret;
+}
+
+/* This is the opposite of bcm43xx_init_board() */
+static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+{
bcm43xx_sysfs_unregister(bcm);
bcm43xx_periodic_tasks_delete(bcm);
- bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+ mutex_lock(&(bcm)->mutex);
+ bcm43xx_shutdown_all_wireless_cores(bcm);
+ bcm43xx_pctl_set_crystal(bcm, 0);
+ mutex_unlock(&(bcm)->mutex);
+}
+
+static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
+{
+ phy->antenna_diversity = 0xFFFF;
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->calibrated = 0;
+ phy->is_locked = 0;
+
+ if (phy->_lo_pairs) {
+ memset(phy->_lo_pairs, 0,
+ sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
+ }
+ memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
+}
+
+static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
+ struct bcm43xx_radioinfo *radio)
+{
+ int i;
+
+ /* Set default attenuation values. */
+ radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+ radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+ radio->txctl1 = bcm43xx_default_txctl1(bcm);
+ radio->txctl2 = 0xFFFF;
+ radio->txpwr_offset = 0;
+
+ /* NRSSI */
+ radio->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
+ radio->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
+ radio->nrssi_lt[i] = i;
+
+ radio->lofcal = 0xFFFF;
+ radio->initval = 0xFFFF;
+
+ radio->aci_enable = 0;
+ radio->aci_wlan_automatic = 0;
+ radio->aci_hw_rssi = 0;
+}
+
+static void prepare_priv_for_init(struct bcm43xx_private *bcm)
+{
+ int i;
+ struct bcm43xx_coreinfo *core;
+ struct bcm43xx_coreinfo_80211 *wlext;
- bcm43xx_rng_exit(bcm);
+ assert(!bcm->active_80211_core);
+
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+
+ /* Flags */
+ bcm->was_initialized = 0;
+ bcm->reg124_set_0x4 = 0;
+
+ /* Stats */
+ memset(&bcm->stats, 0, sizeof(bcm->stats));
+
+ /* Wireless core data */
for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
- if (!bcm->core_80211[i].available)
- continue;
- if (!bcm->core_80211[i].initialized)
+ core = &(bcm->core_80211[i]);
+ wlext = core->priv;
+
+ if (!core->available)
continue;
+ assert(wlext == &(bcm->core_80211_ext[i]));
- err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
- assert(err == 0);
- bcm43xx_wireless_core_cleanup(bcm);
+ prepare_phydata_for_init(&wlext->phy);
+ prepare_radiodata_for_init(bcm, &wlext->radio);
}
- bcm43xx_pctl_set_crystal(bcm, 0);
+ /* IRQ related flags */
+ bcm->irq_reason = 0;
+ memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
+ bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
- bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
- bcm43xx_unlock_noirq(bcm);
+ /* Noise calculation context */
+ memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
+
+ /* Periodic work context */
+ bcm->periodic_state = 0;
}
-static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+static int wireless_core_up(struct bcm43xx_private *bcm,
+ int active_wlcore)
+{
+ int err;
+
+ if (!bcm43xx_core_enabled(bcm))
+ bcm43xx_wireless_core_reset(bcm, 1);
+ if (!active_wlcore)
+ bcm43xx_wireless_core_mark_inactive(bcm);
+ err = bcm43xx_wireless_core_init(bcm, active_wlcore);
+ if (err)
+ goto out;
+ if (!active_wlcore)
+ bcm43xx_radio_turn_off(bcm);
+out:
+ return err;
+}
+
+/* Select and enable the "to be used" wireless core.
+ * Locking: bcm->mutex must be aquired before calling this.
+ * bcm->irq_lock must not be aquired.
+ */
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+ int phytype)
{
int i, err;
- int connect_phy;
+ struct bcm43xx_coreinfo *active_core = NULL;
+ struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
+ struct bcm43xx_coreinfo *core;
+ struct bcm43xx_coreinfo_80211 *wlext;
+ int adjust_active_sbtmstatelow = 0;
might_sleep();
- bcm43xx_lock_noirq(bcm);
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+ if (phytype < 0) {
+ /* If no phytype is requested, select the first core. */
+ assert(bcm->core_80211[0].available);
+ wlext = bcm->core_80211[0].priv;
+ phytype = wlext->phy.type;
+ }
+ /* Find the requested core. */
+ for (i = 0; i < bcm->nr_80211_available; i++) {
+ core = &(bcm->core_80211[i]);
+ wlext = core->priv;
+ if (wlext->phy.type == phytype) {
+ active_core = core;
+ active_wlext = wlext;
+ break;
+ }
+ }
+ if (!active_core)
+ return -ESRCH; /* No such PHYTYPE on this board. */
+
+ if (bcm->active_80211_core) {
+ /* We already selected a wl core in the past.
+ * So first clean up everything.
+ */
+ dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
+ ieee80211softmac_stop(bcm->net_dev);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+ err = bcm43xx_disable_interrupts_sync(bcm);
+ assert(!err);
+ tasklet_enable(&bcm->isr_tasklet);
+ err = bcm43xx_shutdown_all_wireless_cores(bcm);
+ if (err)
+ goto error;
+ /* Ok, everything down, continue to re-initialize. */
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+ }
+
+ /* Reset all data structures. */
+ prepare_priv_for_init(bcm);
- err = bcm43xx_pctl_set_crystal(bcm, 1);
- if (err)
- goto out;
- err = bcm43xx_pctl_init(bcm);
- if (err)
- goto err_crystal_off;
err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
if (err)
- goto err_crystal_off;
+ goto error;
- tasklet_enable(&bcm->isr_tasklet);
+ /* Mark all unused cores "inactive". */
for (i = 0; i < bcm->nr_80211_available; i++) {
- err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
- assert(err != -ENODEV);
- if (err)
- goto err_80211_unwind;
+ core = &(bcm->core_80211[i]);
+ wlext = core->priv;
- /* Enable the selected wireless core.
- * Connect PHY only on the first core.
- */
- if (!bcm43xx_core_enabled(bcm)) {
- if (bcm->nr_80211_available == 1) {
- connect_phy = bcm43xx_current_phy(bcm)->connected;
- } else {
- if (i == 0)
- connect_phy = 1;
- else
- connect_phy = 0;
- }
- bcm43xx_wireless_core_reset(bcm, connect_phy);
+ if (core == active_core)
+ continue;
+ err = bcm43xx_switch_core(bcm, core);
+ if (err) {
+ dprintk(KERN_ERR PFX "Could not switch to inactive "
+ "802.11 core (%d)\n", err);
+ goto error;
}
+ err = wireless_core_up(bcm, 0);
+ if (err) {
+ dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
+ "failed (%d)\n", err);
+ goto error;
+ }
+ adjust_active_sbtmstatelow = 1;
+ }
- if (i != 0)
- bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
-
- err = bcm43xx_wireless_core_init(bcm);
- if (err)
- goto err_80211_unwind;
+ /* Now initialize the active 802.11 core. */
+ err = bcm43xx_switch_core(bcm, active_core);
+ if (err) {
+ dprintk(KERN_ERR PFX "Could not switch to active "
+ "802.11 core (%d)\n", err);
+ goto error;
+ }
+ if (adjust_active_sbtmstatelow &&
+ active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
+ u32 sbtmstatelow;
- if (i != 0) {
- bcm43xx_mac_suspend(bcm);
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_radio_turn_off(bcm);
- }
+ sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+ sbtmstatelow |= 0x20000000;
+ bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
}
- bcm->active_80211_core = &bcm->core_80211[0];
- if (bcm->nr_80211_available >= 2) {
- bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
- bcm43xx_mac_enable(bcm);
+ err = wireless_core_up(bcm, 1);
+ if (err) {
+ dprintk(KERN_ERR PFX "core_up for active 802.11 core "
+ "failed (%d)\n", err);
+ goto error;
}
- err = bcm43xx_rng_init(bcm);
+ err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
if (err)
- goto err_80211_unwind;
+ goto error;
+ bcm->active_80211_core = active_core;
+
bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
- dprintk(KERN_INFO PFX "80211 cores initialized\n");
bcm43xx_security_init(bcm);
- bcm43xx_softmac_init(bcm);
+ ieee80211softmac_start(bcm->net_dev);
- bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+ /* Let's go! Be careful after enabling the IRQs.
+ * Don't switch cores, for example.
+ */
+ bcm43xx_mac_enable(bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+ err = bcm43xx_initialize_irq(bcm);
+ if (err)
+ goto error;
+ bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
- if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
- bcm43xx_mac_suspend(bcm);
- bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
- bcm43xx_mac_enable(bcm);
- }
+ dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
+ active_wlext->phy.type);
- /* Initialization of the board is done. Flag it as such. */
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+ return 0;
+
+error:
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+ bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+ return err;
+}
+
+static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+{
+ int err;
+
+ mutex_lock(&(bcm)->mutex);
+
+ tasklet_enable(&bcm->isr_tasklet);
+ err = bcm43xx_pctl_set_crystal(bcm, 1);
+ if (err)
+ goto err_tasklet;
+ err = bcm43xx_pctl_init(bcm);
+ if (err)
+ goto err_crystal_off;
+ err = bcm43xx_select_wireless_core(bcm, -1);
+ if (err)
+ goto err_crystal_off;
bcm43xx_periodic_tasks_setup(bcm);
- bcm43xx_sysfs_register(bcm);
- //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
+ err = bcm43xx_sysfs_register(bcm);
+ if (err)
+ goto err_wlshutdown;
/*FIXME: This should be handled by softmac instead. */
schedule_work(&bcm->softmac->associnfo.work);
- assert(err == 0);
out:
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&(bcm)->mutex);
return err;
-err_80211_unwind:
- tasklet_disable(&bcm->isr_tasklet);
- /* unwind all 80211 initialization */
- for (i = 0; i < bcm->nr_80211_available; i++) {
- if (!bcm->core_80211[i].initialized)
- continue;
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_wireless_core_cleanup(bcm);
- }
+err_wlshutdown:
+ bcm43xx_shutdown_all_wireless_cores(bcm);
err_crystal_off:
bcm43xx_pctl_set_crystal(bcm, 0);
+err_tasklet:
+ tasklet_disable(&bcm->isr_tasklet);
goto out;
}
@@ -3647,7 +3786,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
struct bcm43xx_radioinfo *radio;
unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
bcm43xx_mac_suspend(bcm);
bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -3656,7 +3796,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
radio = bcm43xx_current_radio(bcm);
radio->initial_channel = channel;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
}
/* set_security() callback in struct ieee80211_device */
@@ -3670,7 +3811,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
dprintk(KERN_INFO PFX "set security called");
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
if (sec->flags & (1<<keyidx)) {
@@ -3739,7 +3881,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
} else
bcm43xx_clear_keys(bcm);
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
}
/* hard_start_xmit() callback in struct ieee80211_device */
@@ -3751,10 +3894,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
int err = -ENODEV;
unsigned long flags;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
err = bcm43xx_tx(bcm, txb);
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
return err;
}
@@ -3769,9 +3912,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm43xx_controller_restart(bcm, "TX timeout");
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3781,7 +3924,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev)
unsigned long flags;
local_irq_save(flags);
- bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
+ bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
local_irq_restore(flags);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -3799,7 +3943,7 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
int err;
ieee80211softmac_stop(net_dev);
- err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+ err = bcm43xx_disable_interrupts_sync(bcm);
assert(!err);
bcm43xx_free_board(bcm);
@@ -3818,10 +3962,12 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+ bcm->mac_suspended = 1;
bcm->pci_dev = pci_dev;
bcm->net_dev = net_dev;
bcm->bad_frames_preempt = modparam_bad_frames_preempt;
spin_lock_init(&bcm->irq_lock);
+ spin_lock_init(&bcm->leds_lock);
mutex_init(&bcm->mutex);
tasklet_init(&bcm->isr_tasklet,
(void (*)(unsigned long))bcm43xx_interrupt_tasklet,
@@ -3940,7 +4086,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
bcm43xx_debugfs_remove_device(bcm);
unregister_netdev(net_dev);
bcm43xx_detach_board(bcm);
- assert(bcm->ucode == NULL);
free_ieee80211softmac(net_dev);
}
@@ -3950,47 +4095,25 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
static void bcm43xx_chip_reset(void *_bcm)
{
struct bcm43xx_private *bcm = _bcm;
- struct net_device *net_dev = bcm->net_dev;
- struct pci_dev *pci_dev = bcm->pci_dev;
+ struct bcm43xx_phyinfo *phy;
int err;
- int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
- netif_stop_queue(bcm->net_dev);
- tasklet_disable(&bcm->isr_tasklet);
+ mutex_lock(&(bcm)->mutex);
+ phy = bcm43xx_current_phy(bcm);
+ err = bcm43xx_select_wireless_core(bcm, phy->type);
+ mutex_unlock(&(bcm)->mutex);
- bcm->firmware_norelease = 1;
- if (was_initialized)
- bcm43xx_free_board(bcm);
- bcm->firmware_norelease = 0;
- bcm43xx_detach_board(bcm);
- err = bcm43xx_init_private(bcm, net_dev, pci_dev);
- if (err)
- goto failure;
- err = bcm43xx_attach_board(bcm);
- if (err)
- goto failure;
- if (was_initialized) {
- err = bcm43xx_init_board(bcm);
- if (err)
- goto failure;
- }
- netif_wake_queue(bcm->net_dev);
- printk(KERN_INFO PFX "Controller restarted\n");
-
- return;
-failure:
- printk(KERN_ERR PFX "Controller restart failed\n");
+ printk(KERN_ERR PFX "Controller restart%s\n",
+ (err == 0) ? "ed" : " failed");
}
/* Hard-reset the chip.
* This can be called from interrupt or process context.
- * Make sure to _not_ re-enable device interrupts after this has been called.
-*/
+ */
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
{
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
schedule_work(&bcm->restart_work);
@@ -4002,21 +4125,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *net_dev = pci_get_drvdata(pdev);
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- int try_to_shutdown = 0, err;
+ int err;
dprintk(KERN_INFO PFX "Suspending...\n");
- bcm43xx_lock_irqsafe(bcm, flags);
- bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
- if (bcm->was_initialized)
- try_to_shutdown = 1;
- bcm43xx_unlock_irqsafe(bcm, flags);
-
netif_device_detach(net_dev);
- if (try_to_shutdown) {
+ bcm->was_initialized = 0;
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+ bcm->was_initialized = 1;
ieee80211softmac_stop(net_dev);
- err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
+ err = bcm43xx_disable_interrupts_sync(bcm);
if (unlikely(err)) {
dprintk(KERN_ERR PFX "Suspend failed.\n");
return -EAGAIN;
@@ -4049,17 +4167,14 @@ static int bcm43xx_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
bcm43xx_chipset_attach(bcm);
- if (bcm->was_initialized) {
- bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+ if (bcm->was_initialized)
err = bcm43xx_init_board(bcm);
- }
if (err) {
printk(KERN_ERR PFX "Resume failed!\n");
return err;
}
-
netif_device_attach(net_dev);
-
+
dprintk(KERN_INFO PFX "Device resumed.\n");
return 0;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 116493671f8..505c86e2007 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -133,6 +133,9 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+ int phytype);
+
void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index f8200deecc8..eafd0f66268 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table[] = {
static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
+static inline
+void bcm43xx_voluntary_preempt(void)
+{
+ assert(!in_atomic() && !in_irq() &&
+ !in_interrupt() && !irqs_disabled());
+#ifndef CONFIG_PREEMPT
+ cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- unsigned long flags;
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
if (phy->calibrated)
return;
if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
- /* We do not want to be preempted while calibrating
- * the hardware.
- */
- local_irq_save(flags);
-
bcm43xx_wireless_core_reset(bcm, 0);
bcm43xx_phy_initg(bcm);
bcm43xx_wireless_core_reset(bcm, 1);
-
- local_irq_restore(flags);
}
phy->calibrated = 1;
}
@@ -1299,7 +1301,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
{
int i;
u16 ret = 0;
+ unsigned long flags;
+ local_irq_save(flags);
for (i = 0; i < 10; i++){
bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
udelay(1);
@@ -1309,6 +1313,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
udelay(40);
ret += bcm43xx_phy_read(bcm, 0x002C);
}
+ local_irq_restore(flags);
+ bcm43xx_voluntary_preempt();
return ret;
}
@@ -1435,6 +1441,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
}
ret = bcm43xx_phy_read(bcm, 0x002D);
local_irq_restore(flags);
+ bcm43xx_voluntary_preempt();
return ret;
}
@@ -1760,6 +1767,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
bcm43xx_radio_write16(bcm, 0x43, i);
bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
udelay(10);
+ bcm43xx_voluntary_preempt();
bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
@@ -1803,6 +1811,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
radio->txctl2
| (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
udelay(10);
+ bcm43xx_voluntary_preempt();
bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
@@ -1824,6 +1833,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
udelay(2);
bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
+ bcm43xx_voluntary_preempt();
} else
bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
bcm43xx_phy_lo_adjust(bcm, is_initializing);
@@ -2188,12 +2198,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err = -ENODEV;
- unsigned long flags;
-
- /* We do not want to be preempted while calibrating
- * the hardware.
- */
- local_irq_save(flags);
switch (phy->type) {
case BCM43xx_PHYTYPE_A:
@@ -2227,7 +2231,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
err = 0;
break;
}
- local_irq_restore(flags);
if (err)
printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 574085c4615..c60c1743ea0 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d)
int err;
u16 txctl;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (queue->tx_frozen)
goto out_unlock;
@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d)
continue;
}
out_unlock:
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
}
static void setup_txqueues(struct bcm43xx_pioqueue *queue)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index 6a23bdc7541..ece335178f6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
GFP_KERNEL);
if (!sprom)
return -ENOMEM;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
err = bcm43xx_sprom_read(bcm, sprom);
if (!err)
err = sprom2hex(sprom, buf, PAGE_SIZE);
mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
kfree(sprom);
return err;
@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
err = hex2sprom(sprom, buf, count);
if (err)
goto out_kfree;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ spin_lock(&bcm->leds_lock);
err = bcm43xx_sprom_write(bcm, sprom);
mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock(&bcm->leds_lock);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
out_kfree:
kfree(sprom);
@@ -176,7 +182,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock_noirq(bcm);
+ mutex_lock(&bcm->mutex);
switch (bcm43xx_current_radio(bcm)->interfmode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -193,7 +199,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
}
err = 0;
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
return err ? err : count;
@@ -229,7 +235,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
return -EINVAL;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
@@ -237,7 +244,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
"supported by device\n");
}
mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err ? err : count;
}
@@ -257,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock_noirq(bcm);
+ mutex_lock(&bcm->mutex);
if (bcm->short_preamble)
count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -265,7 +273,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
err = 0;
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
return err ? err : count;
}
@@ -285,12 +293,14 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
value = get_boolean(buf, count);
if (value < 0)
return value;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->short_preamble = !!value;
err = 0;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err ? err : count;
}
@@ -299,6 +309,70 @@ static DEVICE_ATTR(shortpreamble, 0644,
bcm43xx_attr_preamble_show,
bcm43xx_attr_preamble_store);
+static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+ int phytype;
+ int err = -EINVAL;
+
+ if (count < 1)
+ goto out;
+ switch (buf[0]) {
+ case 'a': case 'A':
+ phytype = BCM43xx_PHYTYPE_A;
+ break;
+ case 'b': case 'B':
+ phytype = BCM43xx_PHYTYPE_B;
+ break;
+ case 'g': case 'G':
+ phytype = BCM43xx_PHYTYPE_G;
+ break;
+ default:
+ goto out;
+ }
+
+ mutex_lock(&(bcm)->mutex);
+ err = bcm43xx_select_wireless_core(bcm, phytype);
+ mutex_unlock(&(bcm)->mutex);
+ if (err == -ESRCH)
+ err = -ENODEV;
+
+out:
+ return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+ ssize_t count = 0;
+
+ mutex_lock(&(bcm)->mutex);
+ switch (bcm43xx_current_phy(bcm)->type) {
+ case BCM43xx_PHYTYPE_A:
+ snprintf(buf, PAGE_SIZE, "A");
+ break;
+ case BCM43xx_PHYTYPE_B:
+ snprintf(buf, PAGE_SIZE, "B");
+ break;
+ case BCM43xx_PHYTYPE_G:
+ snprintf(buf, PAGE_SIZE, "G");
+ break;
+ default:
+ assert(0);
+ }
+ mutex_unlock(&(bcm)->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(phymode, 0644,
+ bcm43xx_attr_phymode_show,
+ bcm43xx_attr_phymode_store);
+
int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
@@ -315,9 +389,14 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
err = device_create_file(dev, &dev_attr_shortpreamble);
if (err)
goto err_remove_interfmode;
+ err = device_create_file(dev, &dev_attr_phymode);
+ if (err)
+ goto err_remove_shortpreamble;
out:
return err;
+err_remove_shortpreamble:
+ device_remove_file(dev, &dev_attr_shortpreamble);
err_remove_interfmode:
device_remove_file(dev, &dev_attr_interference);
err_remove_sprom:
@@ -329,6 +408,7 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
+ device_remove_file(dev, &dev_attr_phymode);
device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);
device_remove_file(dev, &dev_attr_sprom);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 5c36e29efff..1d3a3aaf96e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -47,6 +47,8 @@
#define BCM43xx_WX_VERSION 18
#define MAX_WX_STRING 80
+/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
+#define RX_RSSI_MAX 60
static int bcm43xx_wx_get_name(struct net_device *net_dev,
@@ -56,12 +58,11 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
int i;
- unsigned long flags;
struct bcm43xx_phyinfo *phy;
char suffix[7] = { 0 };
int have_a = 0, have_b = 0, have_g = 0;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
for (i = 0; i < bcm->nr_80211_available; i++) {
phy = &(bcm->core_80211_ext[i].phy);
switch (phy->type) {
@@ -77,7 +78,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
assert(0);
}
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
i = 0;
if (have_a) {
@@ -111,7 +112,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
int freq;
int err = -EINVAL;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+
if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
channel = data->freq.m;
freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -131,7 +134,8 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
err = 0;
}
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -143,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct bcm43xx_radioinfo *radio;
- unsigned long flags;
int err = -ENODEV;
u16 channel;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
radio = bcm43xx_current_radio(bcm);
channel = radio->channel;
if (channel == 0xFF) {
@@ -162,7 +165,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -180,13 +183,15 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
if (mode == IW_MODE_AUTO)
mode = BCM43xx_INITIAL_IWMODE;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
if (bcm->ieee->iw_mode != mode)
bcm43xx_set_iwmode(bcm, mode);
} else
bcm->ieee->iw_mode = mode;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -197,11 +202,10 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
data->mode = bcm->ieee->iw_mode;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -214,7 +218,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct iw_range *range = (struct iw_range *)extra;
const struct ieee80211_geo *geo;
- unsigned long flags;
int i, j;
struct bcm43xx_phyinfo *phy;
@@ -226,15 +229,14 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
range->throughput = 27 * 1000 * 1000;
range->max_qual.qual = 100;
- /* TODO: Real max RSSI */
- range->max_qual.level = 3;
- range->max_qual.noise = 100;
- range->max_qual.updated = 7;
+ range->max_qual.level = 152; /* set floor at -104 dBm (152 - 256) */
+ range->max_qual.noise = 152;
+ range->max_qual.updated = IW_QUAL_ALL_UPDATED;
- range->avg_qual.qual = 70;
- range->avg_qual.level = 2;
- range->avg_qual.noise = 40;
- range->avg_qual.updated = 7;
+ range->avg_qual.qual = 50;
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
@@ -254,7 +256,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
IW_ENC_CAPA_CIPHER_TKIP |
IW_ENC_CAPA_CIPHER_CCMP;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
phy = bcm43xx_current_phy(bcm);
range->num_bitrates = 0;
@@ -301,7 +303,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
}
range->num_frequency = j;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -314,11 +316,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
size_t len;
- bcm43xx_lock_noirq(bcm);
+ mutex_lock(&bcm->mutex);
len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
memcpy(bcm->nick, extra, len);
bcm->nick[len] = '\0';
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -331,12 +333,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
size_t len;
- bcm43xx_lock_noirq(bcm);
+ mutex_lock(&bcm->mutex);
len = strlen(bcm->nick) + 1;
memcpy(extra, bcm->nick, len);
data->data.length = (__u16)len;
data->data.flags = 1;
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -350,7 +352,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (data->rts.disabled) {
bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
err = 0;
@@ -361,7 +364,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -372,13 +376,12 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
data->rts.value = bcm->rts_threshold;
data->rts.fixed = 0;
data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -392,7 +395,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (data->frag.disabled) {
bcm->ieee->fts = MAX_FRAG_THRESHOLD;
err = 0;
@@ -403,7 +407,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -414,13 +419,12 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
data->frag.value = bcm->ieee->fts;
data->frag.fixed = 0;
data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -442,7 +446,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
return -EOPNOTSUPP;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
@@ -466,7 +471,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -478,10 +484,9 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct bcm43xx_radioinfo *radio;
- unsigned long flags;
int err = -ENODEV;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
@@ -493,7 +498,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -580,7 +585,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
return -EINVAL;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
@@ -595,7 +601,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
} else
bcm43xx_current_radio(bcm)->interfmode = mode;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -606,12 +613,11 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
int mode;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
mode = bcm43xx_current_radio(bcm)->interfmode;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
switch (mode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -641,9 +647,11 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
int on;
on = *((int *)extra);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->short_preamble = !!on;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -654,12 +662,11 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
int on;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
on = bcm->short_preamble;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
if (on)
strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -681,11 +688,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
on = *((int *)extra);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->ieee->host_encrypt = !!on;
bcm->ieee->host_decrypt = !!on;
bcm->ieee->host_build_iv = !on;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -696,12 +705,11 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
int on;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
on = bcm->ieee->host_encrypt;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
if (on)
strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -764,11 +772,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
if (!sprom)
goto out;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
err = -ENODEV;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_read(bcm, sprom);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
if (!err)
data->data.length = sprom2hex(sprom, extra);
kfree(sprom);
@@ -809,11 +819,15 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
if (err)
goto out_kfree;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ spin_lock(&bcm->leds_lock);
err = -ENODEV;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_write(bcm, sprom);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock(&bcm->leds_lock);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
out_kfree:
kfree(sprom);
out:
@@ -827,6 +841,10 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
struct iw_statistics *wstats;
+ struct ieee80211_network *network = NULL;
+ static int tmp_level = 0;
+ static int tmp_qual = 0;
+ unsigned long flags;
wstats = &bcm->stats.wstats;
if (!mac->associated) {
@@ -844,16 +862,28 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
wstats->qual.level = 0;
wstats->qual.noise = 0;
wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+ wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
return wstats;
}
/* fill in the real statistics when iface associated */
- wstats->qual.qual = 100; // TODO: get the real signal quality
- wstats->qual.level = 3 - bcm->stats.link_quality;
+ spin_lock_irqsave(&mac->ieee->lock, flags);
+ list_for_each_entry(network, &mac->ieee->network_list, list) {
+ if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
+ if (!tmp_level) { /* get initial values */
+ tmp_level = network->stats.signal;
+ tmp_qual = network->stats.rssi;
+ } else { /* smooth results */
+ tmp_level = (15 * tmp_level + network->stats.signal)/16;
+ tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
+ }
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&mac->ieee->lock, flags);
+ wstats->qual.level = tmp_level;
+ wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
wstats->qual.noise = bcm->stats.noise;
- wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED;
+ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index 6dbd855b364..c0efbfe605a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -492,16 +492,15 @@ int bcm43xx_rx(struct bcm43xx_private *bcm,
memset(&stats, 0, sizeof(stats));
stats.mac_time = le16_to_cpu(rxhdr->mactime);
- stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
+ stats.rssi = rxhdr->rssi;
+ stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
!!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
!!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
- stats.signal = rxhdr->signal_quality; //FIXME
//TODO stats.noise =
if (is_ofdm)
stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
else
stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
-//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
stats.received_channel = radio->channel;
//TODO stats.control =
stats.mask = IEEE80211_STATMASK_SIGNAL |
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index e955db435b3..5f8ccf48061 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -6531,7 +6531,7 @@ static int __init ipw2100_init(void)
printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
- ret = pci_module_init(&ipw2100_pci_driver);
+ ret = pci_register_driver(&ipw2100_pci_driver);
#ifdef CONFIG_IPW2100_DEBUG
ipw2100_debug_level = debug;
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index b3300ffe4ee..a72f3e1e991 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -2667,7 +2667,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv)
IPW_DEBUG_FW(">> :\n");
- //set the Stop and Abort bit
+ /* set the Stop and Abort bit */
control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
priv->sram_desc.last_cb_index = 0;
@@ -3002,8 +3002,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
if (rc < 0)
return rc;
-// spin_lock_irqsave(&priv->lock, flags);
-
for (addr = IPW_SHARED_LOWER_BOUND;
addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
ipw_write32(priv, addr, 0);
@@ -3097,8 +3095,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
firmware have problem getting alive resp. */
ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
-// spin_unlock_irqrestore(&priv->lock, flags);
-
return rc;
}
@@ -6387,13 +6383,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
(wrqu->data.length && extra == NULL))
return -EINVAL;
- //mutex_lock(&priv->mutex);
-
- //if (!ieee->wpa_enabled) {
- // err = -EOPNOTSUPP;
- // goto out;
- //}
-
if (wrqu->data.length) {
buf = kmalloc(wrqu->data.length, GFP_KERNEL);
if (buf == NULL) {
@@ -6413,7 +6402,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
out:
- //mutex_unlock(&priv->mutex);
return err;
}
@@ -6426,13 +6414,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
struct ieee80211_device *ieee = priv->ieee;
int err = 0;
- //mutex_lock(&priv->mutex);
-
- //if (!ieee->wpa_enabled) {
- // err = -EOPNOTSUPP;
- // goto out;
- //}
-
if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
wrqu->data.length = 0;
goto out;
@@ -6447,7 +6428,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
out:
- //mutex_unlock(&priv->mutex);
return err;
}
@@ -6558,7 +6538,6 @@ static int ipw_wx_set_auth(struct net_device *dev,
ieee->ieee802_1x = param->value;
break;
- //case IW_AUTH_ROAMING_CONTROL:
case IW_AUTH_PRIVACY_INVOKED:
ieee->privacy_invoked = param->value;
break;
@@ -6680,7 +6659,7 @@ static int ipw_wx_set_mlme(struct net_device *dev,
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
- // silently ignore
+ /* silently ignore */
break;
case IW_MLME_DISASSOC:
@@ -9766,7 +9745,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
return 0;
}
-#endif // CONFIG_IPW2200_MONITOR
+#endif /* CONFIG_IPW2200_MONITOR */
static int ipw_wx_reset(struct net_device *dev,
struct iw_request_info *info,
@@ -10009,7 +9988,7 @@ static void init_sys_config(struct ipw_sys_config *sys_config)
sys_config->dot11g_auto_detection = 0;
sys_config->enable_cts_to_self = 0;
sys_config->bt_coexist_collision_thr = 0;
- sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256
+ sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */
sys_config->silence_threshold = 0x1e;
}
@@ -11774,7 +11753,7 @@ static int __init ipw_init(void)
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
- ret = pci_module_init(&ipw_driver);
+ ret = pci_register_driver(&ipw_driver);
if (ret) {
IPW_ERROR("Unable to initialize PCI module\n");
return ret;
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index bf05b907747..eaf3d13b851 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -304,7 +304,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_nortel_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_nortel_driver);
+ return pci_register_driver(&orinoco_nortel_driver);
}
static void __exit orinoco_nortel_exit(void)
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 1759c543fbe..97a8b4ff32b 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -244,7 +244,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_pci_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_pci_driver);
+ return pci_register_driver(&orinoco_pci_driver);
}
static void __exit orinoco_pci_exit(void)
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 7f006f62417..31162ac25a9 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -351,7 +351,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_plx_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_plx_driver);
+ return pci_register_driver(&orinoco_plx_driver);
}
static void __exit orinoco_plx_exit(void)
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index 0831721e4d6..7c7b960c91d 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -228,7 +228,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_tmd_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_tmd_driver);
+ return pci_register_driver(&orinoco_tmd_driver);
}
static void __exit orinoco_tmd_exit(void)
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 989599ad33e..0c30fe7e8f7 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -35,10 +35,14 @@
#include <net/iw_handler.h> /* New driver API */
+#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */
+#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */
+/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
+#define KEY_SIZE_TKIP 32 /* TKIP keys */
-static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
u8 *wpa_ie, size_t wpa_ie_len);
-static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
__u32 *, char *);
@@ -468,6 +472,9 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
range->event_capa[1] = IW_EVENT_CAPA_K_1;
range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP;
+
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
@@ -567,6 +574,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
struct iw_event iwe; /* Temporary buffer */
short cap;
islpci_private *priv = netdev_priv(ndev);
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
/* The first entry must be the MAC address */
memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
@@ -627,27 +636,13 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
- if (priv->wpa) {
- u8 wpa_ie[MAX_WPA_IE_LEN];
- char *buf, *p;
- size_t wpa_ie_len;
- int i;
-
- wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
- if (wpa_ie_len > 0 &&
- (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
- p = buf;
- p += sprintf(p, "wpa_ie=");
- for (i = 0; i < wpa_ie_len; i++) {
- p += sprintf(p, "%02x", wpa_ie[i]);
- }
- memset(&iwe, 0, sizeof (iwe));
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
- &iwe, buf);
- kfree(buf);
- }
+ /* Add WPA/RSN Information Element, if any */
+ wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
+ if (wpa_ie_len > 0) {
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, wpa_ie);
}
return current_ev;
}
@@ -1051,12 +1046,24 @@ prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
current_index = r.u;
/* Verify that the key is not marked as invalid */
if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
- key.length = dwrq->length > sizeof (key.key) ?
- sizeof (key.key) : dwrq->length;
- memcpy(key.key, extra, key.length);
- if (key.length == 32)
- /* we want WPA-PSK */
+ if (dwrq->length > KEY_SIZE_TKIP) {
+ /* User-provided key data too big */
+ return -EINVAL;
+ }
+ if (dwrq->length > KEY_SIZE_WEP104) {
+ /* WPA-PSK TKIP */
key.type = DOT11_PRIV_TKIP;
+ key.length = KEY_SIZE_TKIP;
+ } else if (dwrq->length > KEY_SIZE_WEP40) {
+ /* WEP 104/128 */
+ key.length = KEY_SIZE_WEP104;
+ } else {
+ /* WEP 40/64 */
+ key.length = KEY_SIZE_WEP40;
+ }
+ memset(key.key, 0, sizeof (key.key));
+ memcpy(key.key, extra, dwrq->length);
+
if ((index < 0) || (index > 3))
/* no index provided use the current one */
index = current_index;
@@ -1210,6 +1217,489 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
}
}
+static int prism54_set_genie(struct net_device *ndev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ int alen, ret = 0;
+ struct obj_attachment *attach;
+
+ if (data->length > MAX_WPA_IE_LEN ||
+ (data->length && extra == NULL))
+ return -EINVAL;
+
+ memcpy(priv->wpa_ie, extra, data->length);
+ priv->wpa_ie_len = data->length;
+
+ alen = sizeof(*attach) + priv->wpa_ie_len;
+ attach = kzalloc(alen, GFP_KERNEL);
+ if (attach == NULL)
+ return -ENOMEM;
+
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+ /* Note: endianness is covered by mgt_set_varlen */
+ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_ASSOC_REQ << 4);
+ attach->id = -1;
+ attach->size = priv->wpa_ie_len;
+ memcpy(attach->data, extra, priv->wpa_ie_len);
+
+ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+ priv->wpa_ie_len);
+ if (ret == 0) {
+ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+ priv->wpa_ie_len);
+ if (ret == 0)
+ printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+ ndev->name);
+ }
+
+ kfree(attach);
+ return ret;
+}
+
+
+static int prism54_get_genie(struct net_device *ndev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ int len = priv->wpa_ie_len;
+
+ if (len <= 0) {
+ data->length = 0;
+ return 0;
+ }
+
+ if (data->length < len)
+ return -E2BIG;
+
+ data->length = len;
+ memcpy(extra, priv->wpa_ie, len);
+
+ return 0;
+}
+
+static int prism54_set_auth(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_param *param = &wrqu->param;
+ u32 mlmelevel = 0, authen = 0, dot1x = 0;
+ u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
+ u32 old_wpa;
+ int ret = 0;
+ union oid_res_t r;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* first get the flags */
+ down_write(&priv->mib_sem);
+ wpa = old_wpa = priv->wpa;
+ up_write(&priv->mib_sem);
+ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+ authen = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+ privinvoked = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+ exunencrypt = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+ dot1x = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
+ mlmelevel = r.u;
+
+ if (ret < 0)
+ goto out;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ /* Do the same thing as IW_AUTH_WPA_VERSION */
+ if (param->value) {
+ wpa = 1;
+ privinvoked = 1; /* For privacy invoked */
+ exunencrypt = 1; /* Filter out all unencrypted frames */
+ dot1x = 0x01; /* To enable eap filter */
+ mlmelevel = DOT11_MLME_EXTENDED;
+ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+ } else {
+ wpa = 0;
+ privinvoked = 0;
+ exunencrypt = 0; /* Do not filter un-encrypted data */
+ dot1x = 0;
+ mlmelevel = DOT11_MLME_AUTO;
+ }
+ break;
+
+ case IW_AUTH_WPA_VERSION:
+ if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
+ wpa = 0;
+ privinvoked = 0;
+ exunencrypt = 0; /* Do not filter un-encrypted data */
+ dot1x = 0;
+ mlmelevel = DOT11_MLME_AUTO;
+ } else {
+ if (param->value & IW_AUTH_WPA_VERSION_WPA)
+ wpa = 1;
+ else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
+ wpa = 2;
+ privinvoked = 1; /* For privacy invoked */
+ exunencrypt = 1; /* Filter out all unencrypted frames */
+ dot1x = 0x01; /* To enable eap filter */
+ mlmelevel = DOT11_MLME_EXTENDED;
+ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+ }
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ dot1x = param->value ? 1 : 0;
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ privinvoked = param->value ? 1 : 0;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ exunencrypt = param->value ? 1 : 0;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+ /* Only WEP uses _SK and _BOTH */
+ if (wpa > 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ authen = DOT11_AUTH_SK;
+ } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+ authen = DOT11_AUTH_OS;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ /* Set all the values */
+ down_write(&priv->mib_sem);
+ priv->wpa = wpa;
+ up_write(&priv->mib_sem);
+ mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+ mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
+ mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
+ mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+ mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
+
+out:
+ return ret;
+}
+
+static int prism54_get_auth(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_param *param = &wrqu->param;
+ u32 wpa = 0;
+ int ret = 0;
+ union oid_res_t r;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* first get the flags */
+ down_write(&priv->mib_sem);
+ wpa = priv->wpa;
+ up_write(&priv->mib_sem);
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * wpa_supplicant will control these internally
+ */
+ ret = -EOPNOTSUPP;
+ break;
+
+ case IW_AUTH_WPA_VERSION:
+ switch (wpa) {
+ case 1:
+ param->value = IW_AUTH_WPA_VERSION_WPA;
+ break;
+ case 2:
+ param->value = IW_AUTH_WPA_VERSION_WPA2;
+ break;
+ case 0:
+ default:
+ param->value = IW_AUTH_WPA_VERSION_DISABLED;
+ break;
+ }
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+ if (ret >= 0)
+ param->value = r.u > 0 ? 1 : 0;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+ if (ret >= 0) {
+ switch (r.u) {
+ case DOT11_AUTH_OS:
+ param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case DOT11_AUTH_BOTH:
+ case DOT11_AUTH_SK:
+ param->value = IW_AUTH_ALG_SHARED_KEY;
+ case DOT11_AUTH_NONE:
+ default:
+ param->value = 0;
+ break;
+ }
+ }
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ param->value = wpa > 0 ? 1 : 0;
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+ if (ret >= 0)
+ param->value = r.u > 0 ? 1 : 0;
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+ if (ret >= 0)
+ param->value = r.u > 0 ? 1 : 0;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int prism54_set_encodeext(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_point *encoding = &wrqu->encoding;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int idx, alg = ext->alg, set_key = 1;
+ union oid_res_t r;
+ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+ int ret = 0;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* Determine and validate the key index */
+ idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+ if (idx) {
+ if (idx < 0 || idx > 3)
+ return -EINVAL;
+ } else {
+ ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+ if (ret < 0)
+ goto out;
+ idx = r.u;
+ }
+
+ if (encoding->flags & IW_ENCODE_DISABLED)
+ alg = IW_ENCODE_ALG_NONE;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+ /* Only set transmit key index here, actual
+ * key is set below if needed.
+ */
+ ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
+ set_key = ext->key_len > 0 ? 1 : 0;
+ }
+
+ if (set_key) {
+ struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
+ switch (alg) {
+ case IW_ENCODE_ALG_NONE:
+ break;
+ case IW_ENCODE_ALG_WEP:
+ if (ext->key_len > KEY_SIZE_WEP104) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (ext->key_len > KEY_SIZE_WEP40)
+ key.length = KEY_SIZE_WEP104;
+ else
+ key.length = KEY_SIZE_WEP40;
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ if (ext->key_len > KEY_SIZE_TKIP) {
+ ret = -EINVAL;
+ goto out;
+ }
+ key.type = DOT11_PRIV_TKIP;
+ key.length = KEY_SIZE_TKIP;
+ default:
+ return -EINVAL;
+ }
+
+ if (key.length) {
+ memset(key.key, 0, sizeof(key.key));
+ memcpy(key.key, ext->key, ext->key_len);
+ ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
+ &key);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ /* Read the flags */
+ if (encoding->flags & IW_ENCODE_DISABLED) {
+ /* Encoding disabled,
+ * authen = DOT11_AUTH_OS;
+ * invoke = 0;
+ * exunencrypt = 0; */
+ }
+ if (encoding->flags & IW_ENCODE_OPEN) {
+ /* Encode but accept non-encoded packets. No auth */
+ invoke = 1;
+ }
+ if (encoding->flags & IW_ENCODE_RESTRICTED) {
+ /* Refuse non-encoded packets. Auth */
+ authen = DOT11_AUTH_BOTH;
+ invoke = 1;
+ exunencrypt = 1;
+ }
+
+ /* do the change if requested */
+ if (encoding->flags & IW_ENCODE_MODE) {
+ ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
+ &authen);
+ ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
+ &invoke);
+ ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+ &exunencrypt);
+ }
+
+out:
+ return ret;
+}
+
+
+static int prism54_get_encodeext(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_point *encoding = &wrqu->encoding;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int idx, max_key_len;
+ union oid_res_t r;
+ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
+ int ret = 0;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* first get the flags */
+ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+ authen = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+ invoke = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+ exunencrypt = r.u;
+ if (ret < 0)
+ goto out;
+
+ max_key_len = encoding->length - sizeof(*ext);
+ if (max_key_len < 0)
+ return -EINVAL;
+
+ idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+ if (idx) {
+ if (idx < 0 || idx > 3)
+ return -EINVAL;
+ } else {
+ ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+ if (ret < 0)
+ goto out;
+ idx = r.u;
+ }
+
+ encoding->flags = idx + 1;
+ memset(ext, 0, sizeof(*ext));
+
+ switch (authen) {
+ case DOT11_AUTH_BOTH:
+ case DOT11_AUTH_SK:
+ wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
+ case DOT11_AUTH_OS:
+ default:
+ wrqu->encoding.flags |= IW_ENCODE_OPEN;
+ break;
+ }
+
+ down_write(&priv->mib_sem);
+ wpa = priv->wpa;
+ up_write(&priv->mib_sem);
+
+ if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
+ /* No encryption */
+ ext->alg = IW_ENCODE_ALG_NONE;
+ ext->key_len = 0;
+ wrqu->encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ struct obj_key *key;
+
+ ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
+ if (ret < 0)
+ goto out;
+ key = r.ptr;
+ if (max_key_len < key->length) {
+ ret = -E2BIG;
+ goto out;
+ }
+ memcpy(ext->key, key->key, key->length);
+ ext->key_len = key->length;
+
+ switch (key->type) {
+ case DOT11_PRIV_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ break;
+ default:
+ case DOT11_PRIV_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ break;
+ }
+ wrqu->encoding.flags |= IW_ENCODE_ENABLED;
+ }
+
+out:
+ return ret;
+}
+
+
static int
prism54_reset(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
@@ -1591,8 +2081,8 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
static void
-prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
- u8 *wpa_ie, size_t wpa_ie_len)
+prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
+ u8 *wpa_ie, size_t wpa_ie_len)
{
struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL;
@@ -1658,7 +2148,7 @@ prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
}
static size_t
-prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
{
struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL;
@@ -1683,14 +2173,14 @@ prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
}
void
-prism54_wpa_ie_init(islpci_private *priv)
+prism54_wpa_bss_ie_init(islpci_private *priv)
{
INIT_LIST_HEAD(&priv->bss_wpa_list);
sema_init(&priv->wpa_sem, 1);
}
void
-prism54_wpa_ie_clean(islpci_private *priv)
+prism54_wpa_bss_ie_clean(islpci_private *priv)
{
struct list_head *ptr, *n;
@@ -1722,7 +2212,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
}
if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
memcmp(pos + 2, wpa_oid, 4) == 0) {
- prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
+ prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
return;
}
pos += 2 + pos[1];
@@ -1879,7 +2369,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
send_formatted_event(priv, "Associate request (ex)", mlme, 1);
if (priv->iw_mode != IW_MODE_MASTER
- && mlmeex->state != DOT11_STATE_AUTHING)
+ && mlmeex->state != DOT11_STATE_ASSOCING)
break;
confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
@@ -1893,7 +2383,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
confirm->state = 0; /* not used */
confirm->code = 0;
- wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+ wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
printk(KERN_DEBUG "No WPA IE found from "
@@ -1937,7 +2427,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
confirm->state = 0; /* not used */
confirm->code = 0;
- wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+ wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
printk(KERN_DEBUG "No WPA IE found from "
@@ -2553,6 +3043,15 @@ static const iw_handler prism54_handler[] = {
(iw_handler) prism54_get_encode, /* SIOCGIWENCODE */
(iw_handler) NULL, /* SIOCSIWPOWER */
(iw_handler) NULL, /* SIOCGIWPOWER */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */
+ (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */
+ (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
+ NULL, /* SIOCSIWPMKSA */
};
/* The low order bit identify a SET (0) or a GET (1) ioctl. */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
index 46d5cde80c8..65f33acd0a4 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.h
+++ b/drivers/net/wireless/prism54/isl_ioctl.h
@@ -27,7 +27,7 @@
#include <net/iw_handler.h> /* New driver API */
-#define SUPPORTED_WIRELESS_EXT 16
+#define SUPPORTED_WIRELESS_EXT 19
void prism54_mib_init(islpci_private *);
@@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl *);
void prism54_process_trap(void *);
-void prism54_wpa_ie_init(islpci_private *priv);
-void prism54_wpa_ie_clean(islpci_private *priv);
+void prism54_wpa_bss_ie_init(islpci_private *priv);
+void prism54_wpa_bss_ie_clean(islpci_private *priv);
int prism54_set_mac_address(struct net_device *, void *);
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 5ddf2959903..ab3c5a27efd 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -715,7 +715,7 @@ islpci_alloc_memory(islpci_private *priv)
}
prism54_acl_init(&priv->acl);
- prism54_wpa_ie_init(priv);
+ prism54_wpa_bss_ie_init(priv);
if (mgt_init(priv))
goto out_free;
@@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv)
/* Free the acces control list and the WPA list */
prism54_acl_clean(&priv->acl);
- prism54_wpa_ie_clean(priv);
+ prism54_wpa_bss_ie_clean(priv);
mgt_clean(priv);
return 0;
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 07053165e4c..5049f37455b 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -179,6 +179,8 @@ typedef struct {
struct list_head bss_wpa_list;
int num_bss_wpa;
struct semaphore wpa_sem;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
struct work_struct reset_task;
int reset_task_pending;
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 09fc17a0f02..f692dccf0d0 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -313,7 +313,7 @@ prism54_module_init(void)
__bug_on_wrong_struct_sizes ();
- return pci_module_init(&prism54_driver);
+ return pci_register_driver(&prism54_driver);
}
/* by the time prism54_module_exit() terminates, as a postcondition
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 61b83a5e737..8e112d139e2 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -52,8 +52,8 @@
#include <pcmcia/ds.h>
#include <pcmcia/mem_op.h>
-#include <net/ieee80211.h>
#include <linux/wireless.h>
+#include <net/iw_handler.h>
#include <asm/io.h>
#include <asm/system.h>
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 500314fc74d..6603ad5be63 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o
zd1211rw-objs := zd_chip.o zd_ieee80211.o \
zd_mac.o zd_netdev.o \
zd_rf_al2230.o zd_rf_rf2959.o \
+ zd_rf_al7230b.o \
zd_rf.o zd_usb.o zd_util.o
ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index da9d06bdb81..58419985e00 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -42,12 +42,11 @@ void zd_chip_init(struct zd_chip *chip,
void zd_chip_clear(struct zd_chip *chip)
{
- mutex_lock(&chip->mutex);
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
zd_usb_clear(&chip->usb);
zd_rf_clear(&chip->rf);
- mutex_unlock(&chip->mutex);
mutex_destroy(&chip->mutex);
- memset(chip, 0, sizeof(*chip));
+ ZD_MEMCLEAR(chip, sizeof(*chip));
}
static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
@@ -68,10 +67,11 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " ");
i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
- i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c", chip->pa_type,
+ i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
chip->patch_cck_gain ? 'g' : '-',
chip->patch_cr157 ? '7' : '-',
- chip->patch_6m_band_edge ? '6' : '-');
+ chip->patch_6m_band_edge ? '6' : '-',
+ chip->new_phy_layout ? 'N' : '-');
return i;
}
@@ -330,13 +330,14 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type)
chip->patch_cck_gain = (value >> 8) & 0x1;
chip->patch_cr157 = (value >> 13) & 0x1;
chip->patch_6m_band_edge = (value >> 21) & 0x1;
+ chip->new_phy_layout = (value >> 31) & 0x1;
dev_dbg_f(zd_chip_dev(chip),
"RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
- "patch 6M %d\n",
+ "patch 6M %d new PHY %d\n",
zd_rf_name(*rf_type), *rf_type,
chip->pa_type, chip->patch_cck_gain,
- chip->patch_cr157, chip->patch_6m_band_edge);
+ chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout);
return 0;
error:
*rf_type = 0;
@@ -344,6 +345,7 @@ error:
chip->patch_cck_gain = 0;
chip->patch_cr157 = 0;
chip->patch_6m_band_edge = 0;
+ chip->new_phy_layout = 0;
return r;
}
@@ -717,7 +719,7 @@ static int zd1211b_hw_reset_phy(struct zd_chip *chip)
{ CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 },
{ CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 },
{ CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 },
- { CR30, 0x49 }, /* jointly decoder, no ASIC */
+ { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */
{ CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
{ CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
{ CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
@@ -807,7 +809,6 @@ static int zd1211_hw_init_hmac(struct zd_chip *chip)
{ CR_ACK_TIMEOUT_EXT, 0x80 },
{ CR_ADDA_PWR_DWN, 0x00 },
{ CR_ACK_TIME_80211, 0x100 },
- { CR_IFS_VALUE, 0x547c032 },
{ CR_RX_PE_DELAY, 0x70 },
{ CR_PS_CTRL, 0x10000000 },
{ CR_RTS_CTS_RATE, 0x02030203 },
@@ -854,11 +855,10 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{ CR_ACK_TIMEOUT_EXT, 0x80 },
{ CR_ADDA_PWR_DWN, 0x00 },
{ CR_ACK_TIME_80211, 0x100 },
- { CR_IFS_VALUE, 0x547c032 },
{ CR_RX_PE_DELAY, 0x70 },
{ CR_PS_CTRL, 0x10000000 },
{ CR_RTS_CTS_RATE, 0x02030203 },
- { CR_RX_THRESHOLD, 0x000c0640 },
+ { CR_RX_THRESHOLD, 0x000c0eff, },
{ CR_AFTER_PNP, 0x1 },
{ CR_WEP_PROTECT, 0x114 },
};
@@ -970,10 +970,15 @@ static int hw_init(struct zd_chip *chip)
r = hw_init_hmac(chip);
if (r)
return r;
- r = set_beacon_interval(chip, 100);
+
+ /* Although the vendor driver defaults to a different value during
+ * init, it overwrites the IFS value with the following every time
+ * the channel changes. We should aim to be more intelligent... */
+ r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
if (r)
return r;
- return 0;
+
+ return set_beacon_interval(chip, 100);
}
#ifdef DEBUG
@@ -1613,3 +1618,34 @@ int zd_rfwritev_locked(struct zd_chip *chip,
return 0;
}
+
+/*
+ * We can optionally program the RF directly through CR regs, if supported by
+ * the hardware. This is much faster than the older method.
+ */
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
+{
+ struct zd_ioreq16 ioreqs[] = {
+ { CR244, (value >> 16) & 0xff },
+ { CR243, (value >> 8) & 0xff },
+ { CR242, value & 0xff },
+ };
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+ const u32 *values, unsigned int count)
+{
+ int r;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ r = zd_rfwrite_cr_locked(chip, values[i]);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 069d2b46733..4b125085989 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -473,7 +473,15 @@
#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
#define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694)
+
#define CR_IFS_VALUE CTL_REG(0x0698)
+#define IFS_VALUE_DIFS_SH 0
+#define IFS_VALUE_EIFS_SH 12
+#define IFS_VALUE_SIFS_SH 24
+#define IFS_VALUE_DEFAULT (( 50 << IFS_VALUE_DIFS_SH) | \
+ (1148 << IFS_VALUE_EIFS_SH) | \
+ ( 10 << IFS_VALUE_SIFS_SH))
+
#define CR_RX_TIME_OUT CTL_REG(0x069C)
#define CR_TOTAL_RX_FRM CTL_REG(0x06A0)
#define CR_CRC32_CNT CTL_REG(0x06A4)
@@ -630,6 +638,7 @@ enum {
LOAD_CODE_SIZE = 0xe, /* words */
LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+ EEPROM_REGS_SIZE = 0x7e, /* words */
E2P_BASE_OFFSET = EEPROM_START_OFFSET +
EEPROM_REGS_OFFSET,
};
@@ -655,7 +664,7 @@ struct zd_chip {
/* SetPointOFDM in the vendor driver */
u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
- is_zd1211b:1;
+ new_phy_layout:1, is_zd1211b:1;
};
static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
@@ -739,8 +748,12 @@ static inline int zd_rfwrite_locked(struct zd_chip *chip, u32 value, u8 bits)
return zd_usb_rfwrite(&chip->usb, value, bits);
}
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value);
+
int zd_rfwritev_locked(struct zd_chip *chip,
const u32* values, unsigned int count, u8 bits);
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count);
/* Locking functions for reading and writing registers.
* The different parameters are intentional.
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index 465906812fc..a13ec72eb30 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -45,4 +45,10 @@ do { \
# define ZD_ASSERT(x) do { } while (0)
#endif
+#ifdef DEBUG
+# define ZD_MEMCLEAR(pointer, size) memset((pointer), 0xff, (size))
+#else
+# define ZD_MEMCLEAR(pointer, size) do { } while (0)
+#endif
+
#endif /* _ZD_DEF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index d6f3e02a0b5..0eda534a648 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -127,11 +127,9 @@ out:
void zd_mac_clear(struct zd_mac *mac)
{
- /* Aquire the lock. */
- spin_lock(&mac->lock);
- spin_unlock(&mac->lock);
zd_chip_clear(&mac->chip);
- memset(mac, 0, sizeof(*mac));
+ ZD_ASSERT(!spin_is_locked(&mac->lock));
+ ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
}
static int reset_mode(struct zd_mac *mac)
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 71e382c589e..082bcf8ec8d 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -121,9 +121,9 @@ enum mac_flags {
};
struct zd_mac {
- struct net_device *netdev;
struct zd_chip chip;
spinlock_t lock;
+ struct net_device *netdev;
/* Unlocked reading possible */
struct iw_statistics iw_stats;
u8 qual_average;
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 9df232c2c86..440ef24b5fd 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -72,10 +72,18 @@ static int iw_get_name(struct net_device *netdev,
struct iw_request_info *info,
union iwreq_data *req, char *extra)
{
- /* FIXME: check whether 802.11a will also supported, add also
- * zd1211B, if we support it.
- */
- strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
+ /* FIXME: check whether 802.11a will also supported */
+ strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
+ return 0;
+}
+
+static int iw_get_nick(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ strcpy(extra, "zd1211");
+ req->data.length = strlen(extra) + 1;
+ req->data.flags = 1;
return 0;
}
@@ -181,6 +189,7 @@ static int iw_get_encodeext(struct net_device *netdev,
static const iw_handler zd_standard_iw_handlers[] = {
WX(SIOCGIWNAME) = iw_get_name,
+ WX(SIOCGIWNICKN) = iw_get_nick,
WX(SIOCSIWFREQ) = iw_set_freq,
WX(SIOCGIWFREQ) = iw_get_freq,
WX(SIOCSIWMODE) = iw_set_mode,
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index d3770d2c61b..f50cff3db91 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -56,7 +56,7 @@ void zd_rf_init(struct zd_rf *rf)
void zd_rf_clear(struct zd_rf *rf)
{
- memset(rf, 0, sizeof(*rf));
+ ZD_MEMCLEAR(rf, sizeof(*rf));
}
int zd_rf_init_hw(struct zd_rf *rf, u8 type)
@@ -76,6 +76,11 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
if (r)
return r;
break;
+ case AL7230B_RF:
+ r = zd_rf_init_al7230b(rf);
+ if (r)
+ return r;
+ break;
default:
dev_err(zd_chip_dev(chip),
"RF %s %#x is not supported\n", zd_rf_name(type), type);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index ea30f693fcc..676b3734f1e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -78,5 +78,6 @@ int zd_switch_radio_off(struct zd_rf *rf);
int zd_rf_init_rf2959(struct zd_rf *rf);
int zd_rf_init_al2230(struct zd_rf *rf);
+int zd_rf_init_al7230b(struct zd_rf *rf);
#endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 0948b25f660..25323a13a3d 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -21,7 +21,7 @@
#include "zd_usb.h"
#include "zd_chip.h"
-static const u32 al2230_table[][3] = {
+static const u32 zd1211_al2230_table[][3] = {
RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
@@ -38,6 +38,53 @@ static const u32 al2230_table[][3] = {
RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
};
+static const u32 zd1211b_al2230_table[][3] = {
+ RF_CHANNEL( 1) = { 0x09efc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 2) = { 0x09efc0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 3) = { 0x09e7c0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 4) = { 0x09e7c0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 5) = { 0x05efc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 6) = { 0x05efc0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 7) = { 0x05e7c0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 8) = { 0x05e7c0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 9) = { 0x0defc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL(10) = { 0x0defc0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL(11) = { 0x0de7c0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL(12) = { 0x0de7c0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL(13) = { 0x03efc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL(14) = { 0x03e7c0, 0x866660, 0xb00000, },
+};
+
+static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
+ { CR240, 0x57 }, { CR9, 0xe0 },
+};
+
+static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
+{
+ int r;
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
+ { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
+ { CR203, 0x06 },
+ { },
+
+ { CR240, 0x80 },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ /* related to antenna selection? */
+ if (chip->new_phy_layout) {
+ r = zd_iowrite16_locked(chip, 0xe1, CR9);
+ if (r)
+ return r;
+ }
+
+ return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
static int zd1211_al2230_init_hw(struct zd_rf *rf)
{
int r;
@@ -139,7 +186,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
{ CR47, 0x1e },
/* ZD1211B 05.06.10 */
- { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
+ { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 },
{ CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
{ CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
{ CR69, 0x28 },
@@ -172,79 +219,78 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
{ CR137, 0x50 }, /* 5614 */
{ CR138, 0xa8 },
{ CR144, 0xac }, /* 5621 */
- { CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
+ { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 },
};
static const u32 rv1[] = {
- /* channel 1 */
- 0x03f790,
- 0x033331,
- 0x00000d,
-
- 0x0b3331,
- 0x03b812,
- 0x00fff3,
- 0x0005a4,
- 0x0f4dc5, /* fix freq shift 0x044dc5 */
- 0x0805b6,
- 0x0146c7,
- 0x000688,
- 0x0403b9, /* External control TX power (CR31) */
- 0x00dbba,
- 0x00099b,
- 0x0bdffc,
- 0x00000d,
- 0x00580f,
+ 0x8cccd0,
+ 0x481dc0,
+ 0xcfff00,
+ 0x25a000,
+
+ /* To improve AL2230 yield, improve phase noise, 4713 */
+ 0x25a000,
+ 0xa3b2f0,
+
+ 0x6da010, /* Reg6 update for MP versio */
+ 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */
+ 0x116000,
+ 0x9dc020, /* External control TX power (CR31) */
+ 0x5ddb00, /* RegA update for MP version */
+ 0xd99000, /* RegB update for MP version */
+ 0x3ffbd0, /* RegC update for MP version */
+ 0xb00000, /* RegD update for MP version */
+
+ /* improve phase noise and remove phase calibration,4713 */
+ 0xf01a00,
};
static const struct zd_ioreq16 ioreqs2[] = {
- { CR47, 0x1e }, { CR_RFCFG, 0x03 },
+ { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
+ { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
};
static const u32 rv2[] = {
- 0x00880f,
- 0x00080f,
+ /* To improve AL2230 yield, 4713 */
+ 0xf01b00,
+ 0xf01e00,
+ 0xf01a00,
};
static const struct zd_ioreq16 ioreqs3[] = {
- { CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
- };
-
- static const u32 rv3[] = {
- 0x00d80f,
- 0x00780f,
- 0x00580f,
- };
-
- static const struct zd_ioreq16 ioreqs4[] = {
- { CR138, 0x28 }, { CR203, 0x06 },
+ /* related to 6M band edge patching, happens unconditionally */
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
};
+ r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+ ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+ if (r)
+ return r;
r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
if (r)
return r;
- r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+ r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
if (r)
return r;
- r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+ r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
if (r)
return r;
- r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+ r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
if (r)
return r;
- r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+ r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
if (r)
return r;
- r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
+ r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
if (r)
return r;
- return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
+ return zd1211b_al2230_finalize_rf(chip);
}
-static int al2230_set_channel(struct zd_rf *rf, u8 channel)
+static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel)
{
int r;
- const u32 *rv = al2230_table[channel-1];
+ const u32 *rv = zd1211_al2230_table[channel-1];
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
{ CR138, 0x28 },
@@ -257,6 +303,24 @@ static int al2230_set_channel(struct zd_rf *rf, u8 channel)
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
+static int zd1211b_al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ const u32 *rv = zd1211b_al2230_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+ ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_cr_locked(chip, rv, 3);
+ if (r)
+ return r;
+
+ return zd1211b_al2230_finalize_rf(chip);
+}
+
static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
@@ -294,13 +358,14 @@ int zd_rf_init_al2230(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
- rf->set_channel = al2230_set_channel;
rf->switch_radio_off = al2230_switch_radio_off;
if (chip->is_zd1211b) {
rf->init_hw = zd1211b_al2230_init_hw;
+ rf->set_channel = zd1211b_al2230_set_channel;
rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
} else {
rf->init_hw = zd1211_al2230_init_hw;
+ rf->set_channel = zd1211_al2230_set_channel;
rf->switch_radio_on = zd1211_al2230_switch_radio_on;
}
rf->patch_6m_band_edge = 1;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
new file mode 100644
index 00000000000..a289f95187e
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -0,0 +1,274 @@
+/* zd_rf_al7230b.c: Functions for the AL7230B RF controller
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 chan_rv[][2] = {
+ RF_CHANNEL( 1) = { 0x09ec00, 0x8cccc8 },
+ RF_CHANNEL( 2) = { 0x09ec00, 0x8cccd8 },
+ RF_CHANNEL( 3) = { 0x09ec00, 0x8cccc0 },
+ RF_CHANNEL( 4) = { 0x09ec00, 0x8cccd0 },
+ RF_CHANNEL( 5) = { 0x05ec00, 0x8cccc8 },
+ RF_CHANNEL( 6) = { 0x05ec00, 0x8cccd8 },
+ RF_CHANNEL( 7) = { 0x05ec00, 0x8cccc0 },
+ RF_CHANNEL( 8) = { 0x05ec00, 0x8cccd0 },
+ RF_CHANNEL( 9) = { 0x0dec00, 0x8cccc8 },
+ RF_CHANNEL(10) = { 0x0dec00, 0x8cccd8 },
+ RF_CHANNEL(11) = { 0x0dec00, 0x8cccc0 },
+ RF_CHANNEL(12) = { 0x0dec00, 0x8cccd0 },
+ RF_CHANNEL(13) = { 0x03ec00, 0x8cccc8 },
+ RF_CHANNEL(14) = { 0x03ec00, 0x866660 },
+};
+
+static const u32 std_rv[] = {
+ 0x4ff821,
+ 0xc5fbfc,
+ 0x21ebfe,
+ 0xafd401, /* freq shift 0xaad401 */
+ 0x6cf56a,
+ 0xe04073,
+ 0x193d76,
+ 0x9dd844,
+ 0x500007,
+ 0xd8c010,
+};
+
+static int al7230b_init_hw(struct zd_rf *rf)
+{
+ int i, r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ /* All of these writes are identical to AL2230 unless otherwise
+ * specified */
+ static const struct zd_ioreq16 ioreqs_1[] = {
+ /* This one is 7230-specific, and happens before the rest */
+ { CR240, 0x57 },
+ { },
+
+ { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
+ { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
+ { CR44, 0x33 },
+ /* This value is different for 7230 (was: 0x2a) */
+ { CR106, 0x22 },
+ { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 },
+ { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a },
+ /* This happened further down in AL2230,
+ * and the value changed (was: 0xe0) */
+ { CR122, 0xfc },
+ { CR10, 0x89 },
+ /* for newest (3rd cut) AL2300 */
+ { CR17, 0x28 },
+ { CR26, 0x93 }, { CR34, 0x30 },
+ /* for newest (3rd cut) AL2300 */
+ { CR35, 0x3e },
+ { CR41, 0x24 }, { CR44, 0x32 },
+ /* for newest (3rd cut) AL2300 */
+ { CR46, 0x96 },
+ { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
+ { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
+ { CR92, 0x0a }, { CR99, 0x28 },
+ /* This value is different for 7230 (was: 0x00) */
+ { CR100, 0x02 },
+ { CR101, 0x13 }, { CR102, 0x27 },
+ /* This value is different for 7230 (was: 0x24) */
+ { CR106, 0x22 },
+ /* This value is different for 7230 (was: 0x2a) */
+ { CR107, 0x3f },
+ { CR109, 0x09 },
+ /* This value is different for 7230 (was: 0x13) */
+ { CR110, 0x1f },
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ /* for newest (3rd cut) AL2300 */
+ { CR115, 0x24 },
+ /* This value is different for 7230 (was: 0x24) */
+ { CR116, 0x3f },
+ /* This value is different for 7230 (was: 0xf4) */
+ { CR117, 0xfa },
+ { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f },
+ { CR121, 0x77 }, { CR137, 0x88 },
+ /* This one is 7230-specific */
+ { CR138, 0xa8 },
+ /* This value is different for 7230 (was: 0xff) */
+ { CR252, 0x34 },
+ /* This value is different for 7230 (was: 0xff) */
+ { CR253, 0x34 },
+
+ /* PLL_OFF */
+ { CR251, 0x2f },
+ };
+
+ static const struct zd_ioreq16 ioreqs_2[] = {
+ /* PLL_ON */
+ { CR251, 0x3f },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0x09ec04);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+ if (r)
+ return r;
+
+ for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+ r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0x700000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16_locked(chip, 0x06, CR203);
+ if (r)
+ return r;
+ r = zd_iowrite16_locked(chip, 0x80, CR240);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int i, r;
+ const u32 *rv = chan_rv[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ struct zd_ioreq16 ioreqs_1[] = {
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+ };
+
+ struct zd_ioreq16 ioreqs_2[] = {
+ /* PLL_ON */
+ { CR251, 0x3f },
+ { CR203, 0x06 }, { CR240, 0x08 },
+ };
+
+ r = zd_iowrite16_locked(chip, 0x57, CR240);
+ if (r)
+ return r;
+
+ /* PLL_OFF */
+ r = zd_iowrite16_locked(chip, 0x2f, CR251);
+ if (r)
+ return r;
+
+ for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+ r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ if (r)
+ return r;
+
+ for (i = 0; i < 2; i++) {
+ r = zd_rfwrite_cr_locked(chip, rv[i]);
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+
+ return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+}
+
+static int al7230b_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x3f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al7230b_switch_radio_off(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x04 },
+ { CR251, 0x2f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al7230b(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ if (chip->is_zd1211b) {
+ dev_err(zd_chip_dev(chip), "AL7230B is currently not "
+ "supported for ZD1211B devices\n");
+ return -ENODEV;
+ }
+
+ rf->init_hw = al7230b_init_hw;
+ rf->set_channel = al7230b_set_channel;
+ rf->switch_radio_on = al7230b_switch_radio_on;
+ rf->switch_radio_off = al7230b_switch_radio_off;
+ rf->patch_6m_band_edge = 1;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 6320984126c..47489fe8ab5 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -16,6 +16,7 @@
*/
#include <asm/unaligned.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/firmware.h>
@@ -39,9 +40,17 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+ /* "Driverless" devices that need ejecting */
+ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{}
};
@@ -263,6 +272,39 @@ static char *get_fw_name(char *buffer, size_t size, u8 device_type,
return buffer;
}
+static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
+ const struct firmware *ub_fw)
+{
+ const struct firmware *ur_fw = NULL;
+ int offset;
+ int r = 0;
+ char fw_name[128];
+
+ r = request_fw_file(&ur_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
+ REBOOT);
+ if (r)
+ goto error;
+
+ offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+ r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
+ E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+
+ /* At this point, the vendor driver downloads the whole firmware
+ * image, hacks around with version IDs, and uploads it again,
+ * completely overwriting the boot code. We do not do this here as
+ * it is not required on any tested devices, and it is suspected to
+ * cause problems. */
+error:
+ release_firmware(ur_fw);
+ return r;
+}
+
static int upload_firmware(struct usb_device *udev, u8 device_type)
{
int r;
@@ -282,15 +324,17 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
- /* FIXME: do we have any reason to perform the kludge that the vendor
- * driver does when there is a version mismatch? (their driver uploads
- * different firmwares and stuff)
- */
if (fw_bcdDevice != bcdDevice) {
dev_info(&udev->dev,
- "firmware device id %#06x and actual device id "
- "%#06x differ, continuing anyway\n",
- fw_bcdDevice, bcdDevice);
+ "firmware version %#06x and device bootcode version "
+ "%#06x differ\n", fw_bcdDevice, bcdDevice);
+ if (bcdDevice <= 0x4313)
+ dev_warn(&udev->dev, "device has old bootcode, please "
+ "report success or failure\n");
+
+ r = handle_version_mismatch(udev, device_type, ub_fw);
+ if (r)
+ goto error;
} else {
dev_dbg_f(&udev->dev,
"firmware device id %#06x is equal to the "
@@ -620,7 +664,7 @@ resubmit:
usb_submit_urb(urb, GFP_ATOMIC);
}
-struct urb *alloc_urb(struct zd_usb *usb)
+static struct urb *alloc_urb(struct zd_usb *usb)
{
struct usb_device *udev = zd_usb_to_usbdev(usb);
struct urb *urb;
@@ -644,7 +688,7 @@ struct urb *alloc_urb(struct zd_usb *usb)
return urb;
}
-void free_urb(struct urb *urb)
+static void free_urb(struct urb *urb)
{
if (!urb)
return;
@@ -864,7 +908,7 @@ void zd_usb_clear(struct zd_usb *usb)
{
usb_set_intfdata(usb->intf, NULL);
usb_put_intf(usb->intf);
- memset(usb, 0, sizeof(*usb));
+ ZD_MEMCLEAR(usb, sizeof(*usb));
/* FIXME: usb_interrupt, usb_tx, usb_rx? */
}
@@ -910,6 +954,55 @@ static void print_id(struct usb_device *udev)
#define print_id(udev) do { } while (0)
#endif
+static int eject_installer(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *iface_desc = &intf->altsetting[0];
+ struct usb_endpoint_descriptor *endpoint;
+ unsigned char *cmd;
+ u8 bulk_out_ep;
+ int r;
+
+ /* Find bulk out endpoint */
+ endpoint = &iface_desc->endpoint[1].desc;
+ if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
+ (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK) {
+ bulk_out_ep = endpoint->bEndpointAddress;
+ } else {
+ dev_err(&udev->dev,
+ "zd1211rw: Could not find bulk out endpoint\n");
+ return -ENODEV;
+ }
+
+ cmd = kzalloc(31, GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENODEV;
+
+ /* USB bulk command block */
+ cmd[0] = 0x55; /* bulk command signature */
+ cmd[1] = 0x53; /* bulk command signature */
+ cmd[2] = 0x42; /* bulk command signature */
+ cmd[3] = 0x43; /* bulk command signature */
+ cmd[14] = 6; /* command length */
+
+ cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
+ cmd[19] = 0x2; /* eject disc */
+
+ dev_info(&udev->dev, "Ejecting virtual installer media...\n");
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
+ cmd, 31, NULL, 2000);
+ kfree(cmd);
+ if (r)
+ return r;
+
+ /* At this point, the device disconnects and reconnects with the real
+ * ID numbers. */
+
+ usb_set_intfdata(intf, NULL);
+ return 0;
+}
+
static int probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int r;
@@ -918,6 +1011,9 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
print_id(udev);
+ if (id->driver_info & DEVICE_INSTALLER)
+ return eject_installer(intf);
+
switch (udev->speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
@@ -983,6 +1079,11 @@ static void disconnect(struct usb_interface *intf)
struct zd_mac *mac = zd_netdev_mac(netdev);
struct zd_usb *usb = &mac->chip.usb;
+ /* Either something really bad happened, or we're just dealing with
+ * a DEVICE_INSTALLER. */
+ if (netdev == NULL)
+ return;
+
dev_dbg_f(zd_usb_dev(usb), "\n");
zd_netdev_disconnect(netdev);
@@ -998,7 +1099,6 @@ static void disconnect(struct usb_interface *intf)
*/
usb_reset_device(interface_to_usbdev(intf));
- /* If somebody still waits on this lock now, this is an error. */
zd_netdev_free(netdev);
dev_dbg(&intf->dev, "disconnected\n");
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index d6420283bd5..92746f76239 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -30,6 +30,7 @@
enum devicetype {
DEVICE_ZD1211 = 0,
DEVICE_ZD1211B = 1,
+ DEVICE_INSTALLER = 2,
};
enum endpoints {
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 8459a18254a..b6b24743370 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1434,7 +1434,7 @@ static int __init yellowfin_init (void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init (&yellowfin_driver);
+ return pci_register_driver(&yellowfin_driver);
}