aboutsummaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-06-22 22:15:09 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-22 22:15:09 -0700
commit065a3e17baa36d1d48eb7376138820035b44775e (patch)
tree556abb5dbeaad98fc5a66bd56f6a647dfbd22182 /drivers/net
parent45c091bb2d453ce4a8b06cf19872ec7a77fc4799 (diff)
parentbfcbb00855db21dacd3c154ea13ec3fdd98e747b (diff)
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (33 commits) [PATCH] myri10ge - drop workaround pci_save_state() disabling MSI [PATCH] myri10ge - drop workaround for the missing AER ext cap on nVidia CK804 via-velocity: the link is not correctly detected when the device starts [PATCH] add b44 to maintainers [PATCH] WAN: ioremap() failure checks in drivers [PATCH] WAN: register_hdlc_device() doesn't need dev_alloc_name() [PATCH] skb_padto()-area fixes in 8390, wavelan [PATCH] make drivers/net/forcedeth.c:nv_update_pause() static [PATCH] network driver for Hilscher netx [PATCH] Dereference in tokenring/olympic.c [PATCH] Array overrun in drivers/net/wireless/wavelan.c [PATCH] Remove useless check in drivers/net/pcmcia/xirc2ps_cs.c [PATCH] 8139cp: add ethtool eeprom support [PATCH] 8139cp: fix eeprom read command length [PATCH] b44: update b44 Kconfig entry [PATCH] b44: update version to 1.01 [PATCH] b44: add wol for old nic [PATCH] b44: add parameter [PATCH] b44: add wol [PATCH] b44: fix manual speed/duplex/autoneg settings ...
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/8139cp.c179
-rw-r--r--drivers/net/8390.c10
-rw-r--r--drivers/net/Kconfig15
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/arm/at91_ether.c156
-rw-r--r--drivers/net/arm/at91_ether.h1
-rw-r--r--drivers/net/b44.c277
-rw-r--r--drivers/net/b44.h7
-rw-r--r--drivers/net/forcedeth.c2
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c8
-rw-r--r--drivers/net/netx-eth.c516
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c2
-rw-r--r--drivers/net/s2io.c48
-rw-r--r--drivers/net/sundance.c8
-rw-r--r--drivers/net/tokenring/olympic.c4
-rw-r--r--drivers/net/via-velocity.c6
-rw-r--r--drivers/net/wan/c101.c6
-rw-r--r--drivers/net/wan/hdlc_generic.c24
-rw-r--r--drivers/net/wan/n2.c5
-rw-r--r--drivers/net/wan/pci200syn.c1
-rw-r--r--drivers/net/wan/wanxl.c12
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h100
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c33
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c221
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c9
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c44
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.h13
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c38
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c107
-rw-r--r--drivers/net/wireless/ipw2200.c41
-rw-r--r--drivers/net/wireless/ipw2200.h1
-rw-r--r--drivers/net/wireless/wavelan.c18
34 files changed, 1570 insertions, 349 deletions
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 46d8c01437e..a26077a175a 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -401,6 +401,11 @@ static void cp_clean_rings (struct cp_private *cp);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void cp_poll_controller(struct net_device *dev);
#endif
+static int cp_get_eeprom_len(struct net_device *dev);
+static int cp_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data);
+static int cp_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data);
static struct pci_device_id cp_pci_tbl[] = {
{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
@@ -1577,6 +1582,9 @@ static struct ethtool_ops cp_ethtool_ops = {
.get_strings = cp_get_strings,
.get_ethtool_stats = cp_get_ethtool_stats,
.get_perm_addr = ethtool_op_get_perm_addr,
+ .get_eeprom_len = cp_get_eeprom_len,
+ .get_eeprom = cp_get_eeprom,
+ .set_eeprom = cp_set_eeprom,
};
static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1612,24 +1620,32 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
#define eeprom_delay() readl(ee_addr)
/* The EEPROM commands include the alway-set leading bit. */
+#define EE_EXTEND_CMD (4)
#define EE_WRITE_CMD (5)
#define EE_READ_CMD (6)
#define EE_ERASE_CMD (7)
-static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
-{
- int i;
- unsigned retval = 0;
- void __iomem *ee_addr = ioaddr + Cfg9346;
- int read_cmd = location | (EE_READ_CMD << addr_len);
+#define EE_EWDS_ADDR (0)
+#define EE_WRAL_ADDR (1)
+#define EE_ERAL_ADDR (2)
+#define EE_EWEN_ADDR (3)
+
+#define CP_EEPROM_MAGIC PCI_DEVICE_ID_REALTEK_8139
+static void eeprom_cmd_start(void __iomem *ee_addr)
+{
writeb (EE_ENB & ~EE_CS, ee_addr);
writeb (EE_ENB, ee_addr);
eeprom_delay ();
+}
- /* Shift the read command bits out. */
- for (i = 4 + addr_len; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+static void eeprom_cmd(void __iomem *ee_addr, int cmd, int cmd_len)
+{
+ int i;
+
+ /* Shift the command bits out. */
+ for (i = cmd_len - 1; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
writeb (EE_ENB | dataval, ee_addr);
eeprom_delay ();
writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
@@ -1637,6 +1653,33 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
}
writeb (EE_ENB, ee_addr);
eeprom_delay ();
+}
+
+static void eeprom_cmd_end(void __iomem *ee_addr)
+{
+ writeb (~EE_CS, ee_addr);
+ eeprom_delay ();
+}
+
+static void eeprom_extend_cmd(void __iomem *ee_addr, int extend_cmd,
+ int addr_len)
+{
+ int cmd = (EE_EXTEND_CMD << addr_len) | (extend_cmd << (addr_len - 2));
+
+ eeprom_cmd_start(ee_addr);
+ eeprom_cmd(ee_addr, cmd, 3 + addr_len);
+ eeprom_cmd_end(ee_addr);
+}
+
+static u16 read_eeprom (void __iomem *ioaddr, int location, int addr_len)
+{
+ int i;
+ u16 retval = 0;
+ void __iomem *ee_addr = ioaddr + Cfg9346;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ eeprom_cmd_start(ee_addr);
+ eeprom_cmd(ee_addr, read_cmd, 3 + addr_len);
for (i = 16; i > 0; i--) {
writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
@@ -1648,13 +1691,125 @@ static int read_eeprom (void __iomem *ioaddr, int location, int addr_len)
eeprom_delay ();
}
- /* Terminate the EEPROM access. */
- writeb (~EE_CS, ee_addr);
- eeprom_delay ();
+ eeprom_cmd_end(ee_addr);
return retval;
}
+static void write_eeprom(void __iomem *ioaddr, int location, u16 val,
+ int addr_len)
+{
+ int i;
+ void __iomem *ee_addr = ioaddr + Cfg9346;
+ int write_cmd = location | (EE_WRITE_CMD << addr_len);
+
+ eeprom_extend_cmd(ee_addr, EE_EWEN_ADDR, addr_len);
+
+ eeprom_cmd_start(ee_addr);
+ eeprom_cmd(ee_addr, write_cmd, 3 + addr_len);
+ eeprom_cmd(ee_addr, val, 16);
+ eeprom_cmd_end(ee_addr);
+
+ eeprom_cmd_start(ee_addr);
+ for (i = 0; i < 20000; i++)
+ if (readb(ee_addr) & EE_DATA_READ)
+ break;
+ eeprom_cmd_end(ee_addr);
+
+ eeprom_extend_cmd(ee_addr, EE_EWDS_ADDR, addr_len);
+}
+
+static int cp_get_eeprom_len(struct net_device *dev)
+{
+ struct cp_private *cp = netdev_priv(dev);
+ int size;
+
+ spin_lock_irq(&cp->lock);
+ size = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 256 : 128;
+ spin_unlock_irq(&cp->lock);
+
+ return size;
+}
+
+static int cp_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct cp_private *cp = netdev_priv(dev);
+ unsigned int addr_len;
+ u16 val;
+ u32 offset = eeprom->offset >> 1;
+ u32 len = eeprom->len;
+ u32 i = 0;
+
+ eeprom->magic = CP_EEPROM_MAGIC;
+
+ spin_lock_irq(&cp->lock);
+
+ addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
+
+ if (eeprom->offset & 1) {
+ val = read_eeprom(cp->regs, offset, addr_len);
+ data[i++] = (u8)(val >> 8);
+ offset++;
+ }
+
+ while (i < len - 1) {
+ val = read_eeprom(cp->regs, offset, addr_len);
+ data[i++] = (u8)val;
+ data[i++] = (u8)(val >> 8);
+ offset++;
+ }
+
+ if (i < len) {
+ val = read_eeprom(cp->regs, offset, addr_len);
+ data[i] = (u8)val;
+ }
+
+ spin_unlock_irq(&cp->lock);
+ return 0;
+}
+
+static int cp_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct cp_private *cp = netdev_priv(dev);
+ unsigned int addr_len;
+ u16 val;
+ u32 offset = eeprom->offset >> 1;
+ u32 len = eeprom->len;
+ u32 i = 0;
+
+ if (eeprom->magic != CP_EEPROM_MAGIC)
+ return -EINVAL;
+
+ spin_lock_irq(&cp->lock);
+
+ addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;
+
+ if (eeprom->offset & 1) {
+ val = read_eeprom(cp->regs, offset, addr_len) & 0xff;
+ val |= (u16)data[i++] << 8;
+ write_eeprom(cp->regs, offset, val, addr_len);
+ offset++;
+ }
+
+ while (i < len - 1) {
+ val = (u16)data[i++];
+ val |= (u16)data[i++] << 8;
+ write_eeprom(cp->regs, offset, val, addr_len);
+ offset++;
+ }
+
+ if (i < len) {
+ val = read_eeprom(cp->regs, offset, addr_len) & 0xff00;
+ val |= (u16)data[i];
+ write_eeprom(cp->regs, offset, val, addr_len);
+ }
+
+ spin_unlock_irq(&cp->lock);
+ return 0;
+}
+
/* Put the board into D3cold state and wait for WakeUp signal */
static void cp_set_d3_state (struct cp_private *cp)
{
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index f8702742008..86be96af9c8 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -275,12 +275,14 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
int send_length = skb->len, output_page;
unsigned long flags;
+ char buf[ETH_ZLEN];
+ char *data = skb->data;
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
+ memset(buf, 0, ETH_ZLEN); /* more efficient than doing just the needed bits */
+ memcpy(buf, data, skb->len);
send_length = ETH_ZLEN;
+ data = buf;
}
/* Mask interrupts from the ethercard.
@@ -347,7 +349,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* trigger the send later, upon receiving a Tx done interrupt.
*/
- ei_block_output(dev, send_length, skb->data, output_page);
+ ei_block_output(dev, send_length, data, output_page);
if (! ei_local->txing)
{
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c3c1a8d5f7a..39189903e35 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -854,6 +854,17 @@ config SMC9194
<file:Documentation/networking/net-modules.txt>. The module
will be called smc9194.
+config NET_NETX
+ tristate "NetX Ethernet support"
+ select MII
+ depends on NET_ETHERNET && ARCH_NETX
+ help
+ This is support for the Hilscher netX builtin Ethernet ports
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/networking/net-modules.txt>. The module
+ will be called netx-eth.
+
config DM9000
tristate "DM9000 support"
depends on (ARM || MIPS) && NET_ETHERNET
@@ -1376,8 +1387,8 @@ config APRICOT
called apricot.
config B44
- tristate "Broadcom 4400 ethernet support (EXPERIMENTAL)"
- depends on NET_PCI && PCI && EXPERIMENTAL
+ tristate "Broadcom 4400 ethernet support"
+ depends on NET_PCI && PCI
select MII
help
If you have a network (Ethernet) controller of this type, say Y and
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1eced328750..c91e95126f7 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -187,6 +187,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_NET_NETX) += netx-eth.o
obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_R8169) += r8169.o
obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 5503dc8a66e..613005a0285 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -43,7 +43,9 @@
#define DRV_VERSION "1.0"
static struct net_device *at91_dev;
-static struct clk *ether_clk;
+
+static struct timer_list check_timer;
+#define LINK_POLL_INTERVAL (HZ)
/* ..................................................................... */
@@ -143,7 +145,7 @@ static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int
* MAC accordingly.
* If no link or auto-negotiation is busy, then no changes are made.
*/
-static void update_linkspeed(struct net_device *dev)
+static void update_linkspeed(struct net_device *dev, int silent)
{
struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned int bmsr, bmcr, lpa, mac_cfg;
@@ -151,7 +153,8 @@ static void update_linkspeed(struct net_device *dev)
if (!mii_link_ok(&lp->mii)) { /* no link */
netif_carrier_off(dev);
- printk(KERN_INFO "%s: Link down.\n", dev->name);
+ if (!silent)
+ printk(KERN_INFO "%s: Link down.\n", dev->name);
return;
}
@@ -186,7 +189,8 @@ static void update_linkspeed(struct net_device *dev)
}
at91_emac_write(AT91_EMAC_CFG, mac_cfg);
- printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+ if (!silent)
+ printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
netif_carrier_on(dev);
}
@@ -226,7 +230,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs
goto done;
}
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
done:
disable_mdi();
@@ -243,14 +247,17 @@ static void enable_phyirq(struct net_device *dev)
unsigned int dsintr, irq_number;
int status;
- if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */
- return;
- if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */
- return;
- if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */
+ irq_number = lp->board_data.phy_irq_pin;
+ if (!irq_number) {
+ /*
+ * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L),
+ * or board does not have it connected.
+ */
+ check_timer.expires = jiffies + LINK_POLL_INTERVAL;
+ add_timer(&check_timer);
return;
+ }
- irq_number = lp->board_data.phy_irq_pin;
status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
if (status) {
printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
@@ -292,12 +299,11 @@ static void disable_phyirq(struct net_device *dev)
unsigned int dsintr;
unsigned int irq_number;
- if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */
- return;
- if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */
- return;
- if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */
+ irq_number = lp->board_data.phy_irq_pin;
+ if (!irq_number) {
+ del_timer_sync(&check_timer);
return;
+ }
spin_lock_irq(&lp->lock);
enable_mdi();
@@ -326,7 +332,6 @@ static void disable_phyirq(struct net_device *dev)
disable_mdi();
spin_unlock_irq(&lp->lock);
- irq_number = lp->board_data.phy_irq_pin;
free_irq(irq_number, dev); /* Free interrupt handler */
}
@@ -355,6 +360,18 @@ static void reset_phy(struct net_device *dev)
}
#endif
+static void at91ether_check_link(unsigned long dev_id)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+
+ enable_mdi();
+ update_linkspeed(dev, 1);
+ disable_mdi();
+
+ check_timer.expires = jiffies + LINK_POLL_INTERVAL;
+ add_timer(&check_timer);
+}
+
/* ......................... ADDRESS MANAGEMENT ........................ */
/*
@@ -501,7 +518,7 @@ static int hash_get_index(__u8 *addr)
hash_index |= (bitval << j);
}
- return hash_index;
+ return hash_index;
}
/*
@@ -557,10 +574,8 @@ static void at91ether_set_rx_mode(struct net_device *dev)
at91_emac_write(AT91_EMAC_CFG, cfg);
}
-
/* ......................... ETHTOOL SUPPORT ........................... */
-
static int mdio_read(struct net_device *dev, int phy_id, int location)
{
unsigned int value;
@@ -642,6 +657,22 @@ static struct ethtool_ops at91ether_ethtool_ops = {
.get_link = ethtool_op_get_link,
};
+static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct at91_private *lp = (struct at91_private *) dev->priv;
+ int res;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ spin_lock_irq(&lp->lock);
+ enable_mdi();
+ res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+ disable_mdi();
+ spin_unlock_irq(&lp->lock);
+
+ return res;
+}
/* ................................ MAC ................................ */
@@ -685,10 +716,10 @@ static int at91ether_open(struct net_device *dev)
struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned long ctl;
- if (!is_valid_ether_addr(dev->dev_addr))
- return -EADDRNOTAVAIL;
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
- clk_enable(ether_clk); /* Re-enable Peripheral clock */
+ clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */
/* Clear internal statistics */
ctl = at91_emac_read(AT91_EMAC_CTL);
@@ -708,7 +739,7 @@ static int at91ether_open(struct net_device *dev)
/* Determine current link speed */
spin_lock_irq(&lp->lock);
enable_mdi();
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
disable_mdi();
spin_unlock_irq(&lp->lock);
@@ -722,6 +753,7 @@ static int at91ether_open(struct net_device *dev)
*/
static int at91ether_close(struct net_device *dev)
{
+ struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned long ctl;
/* Disable Receiver and Transmitter */
@@ -738,7 +770,7 @@ static int at91ether_close(struct net_device *dev)
netif_stop_queue(dev);
- clk_disable(ether_clk); /* Disable Peripheral clock */
+ clk_disable(lp->ether_clk); /* Disable Peripheral clock */
return 0;
}
@@ -870,7 +902,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *re
if (intstatus & AT91_EMAC_RCOM) /* Receive complete */
at91ether_rx(dev);
- if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */
+ if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */
/* The TCOM bit is set even if the transmission failed. */
if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY))
lp->stats.tx_errors += 1;
@@ -899,7 +931,8 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *re
/*
* Initialize the ethernet interface
*/
-static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, struct platform_device *pdev)
+static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
+ struct platform_device *pdev, struct clk *ether_clk)
{
struct at91_eth_data *board_data = pdev->dev.platform_data;
struct net_device *dev;
@@ -933,6 +966,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
return -ENOMEM;
}
lp->board_data = *board_data;
+ lp->ether_clk = ether_clk;
platform_set_drvdata(pdev, dev);
spin_lock_init(&lp->lock);
@@ -945,6 +979,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
dev->set_multicast_list = at91ether_set_rx_mode;
dev->set_mac_address = set_mac_address;
dev->ethtool_ops = &at91ether_ethtool_ops;
+ dev->do_ioctl = at91ether_ioctl;
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -975,6 +1010,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
lp->mii.dev = dev; /* Support for ethtool */
lp->mii.mdio_read = mdio_read;
lp->mii.mdio_write = mdio_write;
+ lp->mii.phy_id = phy_address;
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
lp->phy_type = phy_type; /* Type of PHY connected */
lp->phy_address = phy_address; /* MDI address of PHY */
@@ -992,11 +1030,18 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
/* Determine current link speed */
spin_lock_irq(&lp->lock);
enable_mdi();
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
disable_mdi();
spin_unlock_irq(&lp->lock);
netif_carrier_off(dev); /* will be enabled in open() */
+ /* If board has no PHY IRQ, use a timer to poll the PHY */
+ if (!lp->board_data.phy_irq_pin) {
+ init_timer(&check_timer);
+ check_timer.data = (unsigned long)dev;
+ check_timer.function = at91ether_check_link;
+ }
+
/* Display ethernet banner */
printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
dev->name, (uint) dev->base_addr, dev->irq,
@@ -1005,7 +1050,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
- printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
+ printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
else if (phy_type == MII_LXT971A_ID)
printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
else if (phy_type == MII_RTL8201_ID)
@@ -1031,9 +1076,10 @@ static int __init at91ether_probe(struct platform_device *pdev)
int detected = -1;
unsigned long phy_id;
unsigned short phy_address = 0;
+ struct clk *ether_clk;
ether_clk = clk_get(&pdev->dev, "ether_clk");
- if (!ether_clk) {
+ if (IS_ERR(ether_clk)) {
printk(KERN_ERR "at91_ether: no clock defined\n");
return -ENODEV;
}
@@ -1056,7 +1102,7 @@ static int __init at91ether_probe(struct platform_device *pdev)
case MII_DP83847_ID: /* National Semiconductor DP83847: */
case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
- detected = at91ether_setup(phy_id, phy_address, pdev);
+ detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
break;
}
@@ -1075,17 +1121,61 @@ static int __devexit at91ether_remove(struct platform_device *pdev)
unregister_netdev(at91_dev);
free_irq(at91_dev->irq, at91_dev);
dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
- clk_put(ether_clk);
+ clk_put(lp->ether_clk);
free_netdev(at91_dev);
at91_dev = NULL;
return 0;
}
+#ifdef CONFIG_PM
+
+static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+ int phy_irq = lp->board_data.phy_irq_pin;
+
+ if (netif_running(net_dev)) {
+ if (phy_irq)
+ disable_irq(phy_irq);
+
+ netif_stop_queue(net_dev);
+ netif_device_detach(net_dev);
+
+ clk_disable(lp->ether_clk);
+ }
+ return 0;
+}
+
+static int at91ether_resume(struct platform_device *pdev)
+{
+ struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+ int phy_irq = lp->board_data.phy_irq_pin;
+
+ if (netif_running(net_dev)) {
+ clk_enable(lp->ether_clk);
+
+ netif_device_attach(net_dev);
+ netif_start_queue(net_dev);
+
+ if (phy_irq)
+ enable_irq(phy_irq);
+ }
+ return 0;
+}
+
+#else
+#define at91ether_suspend NULL
+#define at91ether_resume NULL
+#endif
+
static struct platform_driver at91ether_driver = {
.probe = at91ether_probe,
.remove = __devexit_p(at91ether_remove),
- /* FIXME: support suspend and resume */
+ .suspend = at91ether_suspend,
+ .resume = at91ether_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h
index 9885735c9c8..d1e72e02be3 100644
--- a/drivers/net/arm/at91_ether.h
+++ b/drivers/net/arm/at91_ether.h
@@ -80,6 +80,7 @@ struct at91_private
struct net_device_stats stats;
struct mii_if_info mii; /* ethtool support */
struct at91_eth_data board_data; /* board-specific configuration */
+ struct clk *ether_clk; /* clock */
/* PHY */
unsigned long phy_type; /* type of PHY (PHY_ID) */
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index d8233e0b789..a7e4ba5a580 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -29,8 +29,8 @@
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.00"
-#define DRV_MODULE_RELDATE "Apr 7, 2006"
+#define DRV_MODULE_VERSION "1.01"
+#define DRV_MODULE_RELDATE "Jun 16, 2006"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -75,6 +75,15 @@
/* minimum number of free TX descriptors required to wake up TX process */
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
+/* b44 internal pattern match filter info */
+#define B44_PATTERN_BASE 0x400
+#define B44_PATTERN_SIZE 0x80
+#define B44_PMASK_BASE 0x600
+#define B44_PMASK_SIZE 0x10
+#define B44_MAX_PATTERNS 16
+#define B44_ETHIPV6UDP_HLEN 62
+#define B44_ETHIPV4UDP_HLEN 42
+
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -101,7 +110,7 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
static void b44_halt(struct b44 *);
static void b44_init_rings(struct b44 *);
-static void b44_init_hw(struct b44 *);
+static void b44_init_hw(struct b44 *, int);
static int dma_desc_align_mask;
static int dma_desc_sync_size;
@@ -873,7 +882,7 @@ static int b44_poll(struct net_device *netdev, int *budget)
spin_lock_irq(&bp->lock);
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
netif_wake_queue(bp->dev);
spin_unlock_irq(&bp->lock);
done = 1;
@@ -942,7 +951,7 @@ static void b44_tx_timeout(struct net_device *dev)
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
spin_unlock_irq(&bp->lock);
@@ -1059,7 +1068,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu)
b44_halt(bp);
dev->mtu = new_mtu;
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
spin_unlock_irq(&bp->lock);
b44_enable_ints(bp);
@@ -1356,13 +1365,15 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
* packet processing. Invoked with bp->lock held.
*/
static void __b44_set_rx_mode(struct net_device *);
-static void b44_init_hw(struct b44 *bp)
+static void b44_init_hw(struct b44 *bp, int full_reset)
{
u32 val;
b44_chip_reset(bp);
- b44_phy_reset(bp);
- b44_setup_phy(bp);
+ if (full_reset) {
+ b44_phy_reset(bp);
+ b44_setup_phy(bp);
+ }
/* Enable CRC32, set proper LED modes and power on PHY */
bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
@@ -1376,16 +1387,21 @@ static void b44_init_hw(struct b44 *bp)
bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN);
bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
- bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
- bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
- bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
- (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
- bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
+ if (full_reset) {
+ bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
+ bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
+ bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+ (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+ bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
- bw32(bp, B44_DMARX_PTR, bp->rx_pending);
- bp->rx_prod = bp->rx_pending;
+ bw32(bp, B44_DMARX_PTR, bp->rx_pending);
+ bp->rx_prod = bp->rx_pending;
- bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+ bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+ } else {
+ bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+ (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+ }
val = br32(bp, B44_ENET_CTRL);
bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
@@ -1401,7 +1417,7 @@ static int b44_open(struct net_device *dev)
goto out;
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
b44_check_phy(bp);
@@ -1450,6 +1466,140 @@ static void b44_poll_controller(struct net_device *dev)
}
#endif
+static void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset)
+{
+ u32 i;
+ u32 *pattern = (u32 *) pp;
+
+ for (i = 0; i < bytes; i += sizeof(u32)) {
+ bw32(bp, B44_FILT_ADDR, table_offset + i);
+ bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]);
+ }
+}
+
+static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
+{
+ int magicsync = 6;
+ int k, j, len = offset;
+ int ethaddr_bytes = ETH_ALEN;
+
+ memset(ppattern + offset, 0xff, magicsync);
+ for (j = 0; j < magicsync; j++)
+ set_bit(len++, (unsigned long *) pmask);
+
+ for (j = 0; j < B44_MAX_PATTERNS; j++) {
+ if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
+ ethaddr_bytes = ETH_ALEN;
+ else
+ ethaddr_bytes = B44_PATTERN_SIZE - len;
+ if (ethaddr_bytes <=0)
+ break;
+ for (k = 0; k< ethaddr_bytes; k++) {
+ ppattern[offset + magicsync +
+ (j * ETH_ALEN) + k] = macaddr[k];
+ len++;
+ set_bit(len, (unsigned long *) pmask);
+ }
+ }
+ return len - 1;
+}
+
+/* Setup magic packet patterns in the b44 WOL
+ * pattern matching filter.
+ */
+static void b44_setup_pseudo_magicp(struct b44 *bp)
+{
+
+ u32 val;
+ int plen0, plen1, plen2;
+ u8 *pwol_pattern;
+ u8 pwol_mask[B44_PMASK_SIZE];
+
+ pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
+ if (!pwol_pattern) {
+ printk(KERN_ERR PFX "Memory not available for WOL\n");
+ return;
+ }
+
+ /* Ipv4 magic packet pattern - pattern 0.*/
+ memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+ memset(pwol_mask, 0, B44_PMASK_SIZE);
+ plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+ B44_ETHIPV4UDP_HLEN);
+
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
+
+ /* Raw ethernet II magic packet pattern - pattern 1 */
+ memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+ memset(pwol_mask, 0, B44_PMASK_SIZE);
+ plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+ ETH_HLEN);
+
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ B44_PATTERN_BASE + B44_PATTERN_SIZE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ B44_PMASK_BASE + B44_PMASK_SIZE);
+
+ /* Ipv6 magic packet pattern - pattern 2 */
+ memset(pwol_pattern, 0, B44_PATTERN_SIZE);
+ memset(pwol_mask, 0, B44_PMASK_SIZE);
+ plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
+ B44_ETHIPV6UDP_HLEN);
+
+ bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
+ B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
+ bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
+ B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
+
+ kfree(pwol_pattern);
+
+ /* set these pattern's lengths: one less than each real length */
+ val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE;
+ bw32(bp, B44_WKUP_LEN, val);
+
+ /* enable wakeup pattern matching */
+ val = br32(bp, B44_DEVCTRL);
+ bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE);
+
+}
+
+static void b44_setup_wol(struct b44 *bp)
+{
+ u32 val;
+ u16 pmval;
+
+ bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
+
+ if (bp->flags & B44_FLAG_B0_ANDLATER) {
+
+ bw32(bp, B44_WKUP_LEN, WKUP_LEN_DISABLE);
+
+ val = bp->dev->dev_addr[2] << 24 |
+ bp->dev->dev_addr[3] << 16 |
+ bp->dev->dev_addr[4] << 8 |
+ bp->dev->dev_addr[5];
+ bw32(bp, B44_ADDR_LO, val);
+
+ val = bp->dev->dev_addr[0] << 8 |
+ bp->dev->dev_addr[1];
+ bw32(bp, B44_ADDR_HI, val);
+
+ val = br32(bp, B44_DEVCTRL);
+ bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
+
+ } else {
+ b44_setup_pseudo_magicp(bp);
+ }
+
+ val = br32(bp, B44_SBTMSLOW);
+ bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
+
+ pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval);
+ pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE);
+
+}
+
static int b44_close(struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev);
@@ -1475,6 +1625,11 @@ static int b44_close(struct net_device *dev)
netif_poll_enable(dev);
+ if (bp->flags & B44_FLAG_WOL_ENABLE) {
+ b44_init_hw(bp, 0);
+ b44_setup_wol(bp);
+ }
+
b44_free_consistent(bp);
return 0;
@@ -1620,8 +1775,6 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- if (!netif_running(dev))
- return -EAGAIN;
cmd->supported = (SUPPORTED_Autoneg);
cmd->supported |= (SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
@@ -1649,6 +1802,12 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
XCVR_INTERNAL : XCVR_EXTERNAL;
cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
AUTONEG_DISABLE : AUTONEG_ENABLE;
+ if (cmd->autoneg == AUTONEG_ENABLE)
+ cmd->advertising |= ADVERTISED_Autoneg;
+ if (!netif_running(dev)){
+ cmd->speed = 0;
+ cmd->duplex = 0xff;
+ }
cmd->maxtxpkt = 0;
cmd->maxrxpkt = 0;
return 0;
@@ -1658,9 +1817,6 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- if (!netif_running(dev))
- return -EAGAIN;
-
/* We do not support gigabit. */
if (cmd->autoneg == AUTONEG_ENABLE) {
if (cmd->advertising &
@@ -1677,28 +1833,39 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
spin_lock_irq(&bp->lock);
if (cmd->autoneg == AUTONEG_ENABLE) {
- bp->flags &= ~B44_FLAG_FORCE_LINK;
- bp->flags &= ~(B44_FLAG_ADV_10HALF |
+ bp->flags &= ~(B44_FLAG_FORCE_LINK |
+ B44_FLAG_100_BASE_T |
+ B44_FLAG_FULL_DUPLEX |
+ B44_FLAG_ADV_10HALF |
B44_FLAG_ADV_10FULL |
B44_FLAG_ADV_100HALF |
B44_FLAG_ADV_100FULL);
- if (cmd->advertising & ADVERTISE_10HALF)
- bp->flags |= B44_FLAG_ADV_10HALF;
- if (cmd->advertising & ADVERTISE_10FULL)
- bp->flags |= B44_FLAG_ADV_10FULL;
- if (cmd->advertising & ADVERTISE_100HALF)
- bp->flags |= B44_FLAG_ADV_100HALF;
- if (cmd->advertising & ADVERTISE_100FULL)
- bp->flags |= B44_FLAG_ADV_100FULL;
+ if (cmd->advertising == 0) {
+ bp->flags |= (B44_FLAG_ADV_10HALF |
+ B44_FLAG_ADV_10FULL |
+ B44_FLAG_ADV_100HALF |
+ B44_FLAG_ADV_100FULL);
+ } else {
+ if (cmd->advertising & ADVERTISED_10baseT_Half)
+ bp->flags |= B44_FLAG_ADV_10HALF;
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ bp->flags |= B44_FLAG_ADV_10FULL;
+ if (cmd->advertising & ADVERTISED_100baseT_Half)
+ bp->flags |= B44_FLAG_ADV_100HALF;
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ bp->flags |= B44_FLAG_ADV_100FULL;
+ }
} else {
bp->flags |= B44_FLAG_FORCE_LINK;
+ bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX);
if (cmd->speed == SPEED_100)
bp->flags |= B44_FLAG_100_BASE_T;
if (cmd->duplex == DUPLEX_FULL)
bp->flags |= B44_FLAG_FULL_DUPLEX;
}
- b44_setup_phy(bp);
+ if (netif_running(dev))
+ b44_setup_phy(bp);
spin_unlock_irq(&bp->lock);
@@ -1734,7 +1901,7 @@ static int b44_set_ringparam(struct net_device *dev,
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
netif_wake_queue(bp->dev);
spin_unlock_irq(&bp->lock);
@@ -1777,7 +1944,7 @@ static int b44_set_pauseparam(struct net_device *dev,
if (bp->flags & B44_FLAG_PAUSE_AUTO) {
b44_halt(bp);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
} else {
__b44_set_flow_ctrl(bp, bp->flags);
}
@@ -1819,12 +1986,40 @@ static void b44_get_ethtool_stats(struct net_device *dev,
spin_unlock_irq(&bp->lock);
}
+static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct b44 *bp = netdev_priv(dev);
+
+ wol->supported = WAKE_MAGIC;
+ if (bp->flags & B44_FLAG_WOL_ENABLE)
+ wol->wolopts = WAKE_MAGIC;
+ else
+ wol->wolopts = 0;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct b44 *bp = netdev_priv(dev);
+
+ spin_lock_irq(&bp->lock);
+ if (wol->wolopts & WAKE_MAGIC)
+ bp->flags |= B44_FLAG_WOL_ENABLE;
+ else
+ bp->flags &= ~B44_FLAG_WOL_ENABLE;
+ spin_unlock_irq(&bp->lock);
+
+ return 0;
+}
+
static struct ethtool_ops b44_ethtool_ops = {
.get_drvinfo = b44_get_drvinfo,
.get_settings = b44_get_settings,
.set_settings = b44_set_settings,
.nway_reset = b44_nway_reset,
.get_link = ethtool_op_get_link,
+ .get_wol = b44_get_wol,
+ .set_wol = b44_set_wol,
.get_ringparam = b44_get_ringparam,
.set_ringparam = b44_set_ringparam,
.get_pauseparam = b44_get_pauseparam,
@@ -1903,6 +2098,10 @@ static int __devinit b44_get_invariants(struct b44 *bp)
/* XXX - really required?
bp->flags |= B44_FLAG_BUGGY_TXPTR;
*/
+
+ if (ssb_get_core_rev(bp) >= 7)
+ bp->flags |= B44_FLAG_B0_ANDLATER;
+
out:
return err;
}
@@ -2103,6 +2302,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
spin_unlock_irq(&bp->lock);
free_irq(dev->irq, dev);
+ if (bp->flags & B44_FLAG_WOL_ENABLE) {
+ b44_init_hw(bp, 0);
+ b44_setup_wol(bp);
+ }
pci_disable_device(pdev);
return 0;
}
@@ -2125,7 +2328,7 @@ static int b44_resume(struct pci_dev *pdev)
spin_lock_irq(&bp->lock);
b44_init_rings(bp);
- b44_init_hw(bp);
+ b44_init_hw(bp, 1);
netif_device_attach(bp->dev);
spin_unlock_irq(&bp->lock);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index b178662978f..4944507fad2 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -24,6 +24,9 @@
#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */
#define WKUP_LEN_P3_SHIFT 24
#define WKUP_LEN_D3 0x80000000
+#define WKUP_LEN_DISABLE 0x80808080
+#define WKUP_LEN_ENABLE_TWO 0x80800000
+#define WKUP_LEN_ENABLE_THREE 0x80000000
#define B44_ISTAT 0x0020UL /* Interrupt Status */
#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */
#define ISTAT_PME 0x00000040 /* Power Management Event */
@@ -264,6 +267,8 @@
#define SBIDHIGH_VC_SHIFT 16
/* SSB PCI config space registers. */
+#define SSB_PMCSR 0x44
+#define SSB_PE 0x100
#define SSB_BAR0_WIN 0x80
#define SSB_BAR1_WIN 0x84
#define SSB_SPROM_CONTROL 0x88
@@ -420,6 +425,7 @@ struct b44 {
u32 dma_offset;
u32 flags;
+#define B44_FLAG_B0_ANDLATER 0x00000001
#define B44_FLAG_BUGGY_TXPTR 0x00000002
#define B44_FLAG_REORDER_BUG 0x00000004
#define B44_FLAG_PAUSE_AUTO 0x00008000
@@ -435,6 +441,7 @@ struct b44 {
#define B44_FLAG_INTERNAL_PHY 0x10000000
#define B44_FLAG_RX_RING_HACK 0x20000000
#define B44_FLAG_TX_RING_HACK 0x40000000
+#define B44_FLAG_WOL_ENABLE 0x80000000
u32 rx_offset;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 62b38a4494b..191383d461d 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -2076,7 +2076,7 @@ static void nv_set_multicast(struct net_device *dev)
spin_unlock_irq(&np->lock);
}
-void nv_update_pause(struct net_device *dev, u32 pause_flags)
+static void nv_update_pause(struct net_device *dev, u32 pause_flags)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index ae71ed57c12..e76e6e7be0b 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -145,7 +145,7 @@ static inline struct sk_buff * ioc3_alloc_skb(unsigned long length,
static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
{
#ifdef CONFIG_SGI_IP27
- vdev <<= 58; /* Shift to PCI64_ATTR_VIRTUAL */
+ vdev <<= 57; /* Shift to PCI64_ATTR_VIRTUAL */
return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF |
((unsigned long)ptr & TO_PHYS_MASK);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 1a2b9785e99..5a74f63618b 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -2251,12 +2251,6 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
}
cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR);
- /* nvidia ext cap is not always linked in ext cap chain */
- if (!cap
- && bridge->vendor == PCI_VENDOR_ID_NVIDIA
- && bridge->device == PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE)
- cap = 0x160;
-
if (!cap)
return;
@@ -2732,8 +2726,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Save configuration space to be restored if the
* nic resets due to a parity error */
myri10ge_save_state(mgp);
- /* Restore state immediately since pci_save_msi_state disables MSI */
- myri10ge_restore_state(mgp);
/* Setup the watchdog timer */
setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer,
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
new file mode 100644
index 00000000000..b92430c4e3a
--- /dev/null
+++ b/drivers/net/netx-eth.c
@@ -0,0 +1,516 @@
+/*
+ * drivers/net/netx-eth.c
+ *
+ * Copyright (c) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/netx-regs.h>
+#include <asm/arch/pfifo.h>
+#include <asm/arch/xc.h>
+#include <asm/arch/eth.h>
+
+/* XC Fifo Offsets */
+#define EMPTY_PTR_FIFO(xcno) (0 + ((xcno) << 3)) /* Index of the empty pointer FIFO */
+#define IND_FIFO_PORT_HI(xcno) (1 + ((xcno) << 3)) /* Index of the FIFO where received */
+ /* Data packages are indicated by XC */
+#define IND_FIFO_PORT_LO(xcno) (2 + ((xcno) << 3)) /* Index of the FIFO where received */
+ /* Data packages are indicated by XC */
+#define REQ_FIFO_PORT_HI(xcno) (3 + ((xcno) << 3)) /* Index of the FIFO where Data packages */
+ /* have to be indicated by ARM which */
+ /* shall be sent */
+#define REQ_FIFO_PORT_LO(xcno) (4 + ((xcno) << 3)) /* Index of the FIFO where Data packages */
+ /* have to be indicated by ARM which shall */
+ /* be sent */
+#define CON_FIFO_PORT_HI(xcno) (5 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages */
+ /* are confirmed */
+#define CON_FIFO_PORT_LO(xcno) (6 + ((xcno) << 3)) /* Index of the FIFO where sent Data */
+ /* packages are confirmed */
+#define PFIFO_MASK(xcno) (0x7f << (xcno*8))
+
+#define FIFO_PTR_FRAMELEN_SHIFT 0
+#define FIFO_PTR_FRAMELEN_MASK (0x7ff << 0)
+#define FIFO_PTR_FRAMELEN(len) (((len) << 0) & FIFO_PTR_FRAMELEN_MASK)
+#define FIFO_PTR_TIMETRIG (1<<11)
+#define FIFO_PTR_MULTI_REQ
+#define FIFO_PTR_ORIGIN (1<<14)
+#define FIFO_PTR_VLAN (1<<15)
+#define FIFO_PTR_FRAMENO_SHIFT 16
+#define FIFO_PTR_FRAMENO_MASK (0x3f << 16)
+#define FIFO_PTR_FRAMENO(no) (((no) << 16) & FIFO_PTR_FRAMENO_MASK)
+#define FIFO_PTR_SEGMENT_SHIFT 22
+#define FIFO_PTR_SEGMENT_MASK (0xf << 22)
+#define FIFO_PTR_SEGMENT(seg) (((seg) & 0xf) << 22)
+#define FIFO_PTR_ERROR_SHIFT 28
+#define FIFO_PTR_ERROR_MASK (0xf << 28)
+
+#define ISR_LINK_STATUS_CHANGE (1<<4)
+#define ISR_IND_LO (1<<3)
+#define ISR_CON_LO (1<<2)
+#define ISR_IND_HI (1<<1)
+#define ISR_CON_HI (1<<0)
+
+#define ETH_MAC_LOCAL_CONFIG 0x1560
+#define ETH_MAC_4321 0x1564
+#define ETH_MAC_65 0x1568
+
+#define MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT 16
+#define MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK (0xf<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT)
+#define MAC_TRAFFIC_CLASS_ARRANGEMENT(x) (((x)<<MAC_TRAFFIC_CLASS_ARRANGEMENT_SHIFT) & MAC_TRAFFIC_CLASS_ARRANGEMENT_MASK)
+#define LOCAL_CONFIG_LINK_STATUS_IRQ_EN (1<<24)
+#define LOCAL_CONFIG_CON_LO_IRQ_EN (1<<23)
+#define LOCAL_CONFIG_CON_HI_IRQ_EN (1<<22)
+#define LOCAL_CONFIG_IND_LO_IRQ_EN (1<<21)
+#define LOCAL_CONFIG_IND_HI_IRQ_EN (1<<20)
+
+#define CARDNAME "netx-eth"
+
+/* LSB must be zero */
+#define INTERNAL_PHY_ADR 0x1c
+
+struct netx_eth_priv {
+ void __iomem *sram_base, *xpec_base, *xmac_base;
+ int id;
+ struct net_device_stats stats;
+ struct mii_if_info mii;
+ u32 msg_enable;
+ struct xc *xc;
+ spinlock_t lock;
+};
+
+static void netx_eth_set_multicast_list(struct net_device *ndev)
+{
+ /* implement me */
+}
+
+static int
+netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ unsigned char *buf = skb->data;
+ unsigned int len = skb->len;
+
+ spin_lock_irq(&priv->lock);
+ memcpy_toio(priv->sram_base + 1560, (void *)buf, len);
+ if (len < 60) {
+ memset_io(priv->sram_base + 1560 + len, 0, 60 - len);
+ len = 60;
+ }
+
+ pfifo_push(REQ_FIFO_PORT_LO(priv->id),
+ FIFO_PTR_SEGMENT(priv->id) |
+ FIFO_PTR_FRAMENO(1) |
+ FIFO_PTR_FRAMELEN(len));
+
+ ndev->trans_start = jiffies;
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+
+ netif_stop_queue(ndev);
+ spin_unlock_irq(&priv->lock);
+ dev_kfree_skb(skb);
+
+ return 0;
+}
+
+static void netx_eth_receive(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ unsigned int val, frameno, seg, len;
+ unsigned char *data;
+ struct sk_buff *skb;
+
+ val = pfifo_pop(IND_FIFO_PORT_LO(priv->id));
+
+ frameno = (val & FIFO_PTR_FRAMENO_MASK) >> FIFO_PTR_FRAMENO_SHIFT;
+ seg = (val & FIFO_PTR_SEGMENT_MASK) >> FIFO_PTR_SEGMENT_SHIFT;
+ len = (val & FIFO_PTR_FRAMELEN_MASK) >> FIFO_PTR_FRAMELEN_SHIFT;
+
+ skb = dev_alloc_skb(len);
+ if (unlikely(skb == NULL)) {
+ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
+ ndev->name);
+ priv->stats.rx_dropped++;
+ return;
+ }
+
+ data = skb_put(skb, len);
+
+ memcpy_fromio(data, priv->sram_base + frameno * 1560, len);
+
+ pfifo_push(EMPTY_PTR_FIFO(priv->id),
+ FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno));
+
+ ndev->last_rx = jiffies;
+ skb->dev = ndev;
+ skb->protocol = eth_type_trans(skb, ndev);
+ netif_rx(skb);
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += len;
+}
+
+static irqreturn_t
+netx_eth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *ndev = dev_id;
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ int status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ status = readl(NETX_PFIFO_XPEC_ISR(priv->id));
+ while (status) {
+ int fill_level;
+ writel(status, NETX_PFIFO_XPEC_ISR(priv->id));
+
+ if ((status & ISR_CON_HI) || (status & ISR_IND_HI))
+ printk("%s: unexpected status: 0x%08x\n",
+ __FUNCTION__, status);
+
+ fill_level =
+ readl(NETX_PFIFO_FILL_LEVEL(IND_FIFO_PORT_LO(priv->id)));
+ while (fill_level--)
+ netx_eth_receive(ndev);
+
+ if (status & ISR_CON_LO)
+ netif_wake_queue(ndev);
+
+ if (status & ISR_LINK_STATUS_CHANGE)
+ mii_check_media(&priv->mii, netif_msg_link(priv), 1);
+
+ status = readl(NETX_PFIFO_XPEC_ISR(priv->id));
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ return &priv->stats;
+}
+
+static int netx_eth_open(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+
+ if (request_irq
+ (ndev->irq, &netx_eth_interrupt, SA_SHIRQ, ndev->name, ndev))
+ return -EAGAIN;
+
+ writel(ndev->dev_addr[0] |
+ ndev->dev_addr[1]<<8 |
+ ndev->dev_addr[2]<<16 |
+ ndev->dev_addr[3]<<24,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_4321);
+ writel(ndev->dev_addr[4] |
+ ndev->dev_addr[5]<<8,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_65);
+
+ writel(LOCAL_CONFIG_LINK_STATUS_IRQ_EN |
+ LOCAL_CONFIG_CON_LO_IRQ_EN |
+ LOCAL_CONFIG_CON_HI_IRQ_EN |
+ LOCAL_CONFIG_IND_LO_IRQ_EN |
+ LOCAL_CONFIG_IND_HI_IRQ_EN,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS +
+ ETH_MAC_LOCAL_CONFIG);
+
+ mii_check_media(&priv->mii, netif_msg_link(priv), 1);
+ netif_start_queue(ndev);
+
+ return 0;
+}
+
+static int netx_eth_close(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+
+ writel(0,
+ priv->xpec_base + NETX_XPEC_RAM_START_OFS + ETH_MAC_LOCAL_CONFIG);
+
+ free_irq(ndev->irq, ndev);
+
+ return 0;
+}
+
+static void netx_eth_timeout(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ int i;
+
+ printk(KERN_ERR "%s: transmit timed out, resetting\n", ndev->name);
+
+ spin_lock_irq(&priv->lock);
+
+ xc_reset(priv->xc);
+ xc_start(priv->xc);
+
+ for (i=2; i<=18; i++)
+ pfifo_push(EMPTY_PTR_FIFO(priv->id),
+ FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id));
+
+ spin_unlock_irq(&priv->lock);
+
+ netif_wake_queue(ndev);
+}
+
+static int
+netx_eth_phy_read(struct net_device *ndev, int phy_id, int reg)
+{
+ unsigned int val;
+
+ val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) |
+ MIIMU_REGADDR(reg) | MIIMU_PHY_NRES;
+
+ writel(val, NETX_MIIMU);
+ while (readl(NETX_MIIMU) & MIIMU_SNRDY);
+
+ return readl(NETX_MIIMU) >> 16;
+
+}
+
+static void
+netx_eth_phy_write(struct net_device *ndev, int phy_id, int reg, int value)
+{
+ unsigned int val;
+
+ val = MIIMU_SNRDY | MIIMU_PREAMBLE | MIIMU_PHYADDR(phy_id) |
+ MIIMU_REGADDR(reg) | MIIMU_PHY_NRES | MIIMU_OPMODE_WRITE |
+ MIIMU_DATA(value);
+
+ writel(val, NETX_MIIMU);
+ while (readl(NETX_MIIMU) & MIIMU_SNRDY);
+}
+
+static int netx_eth_enable(struct net_device *ndev)
+{
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+ unsigned int mac4321, mac65;
+ int running, i;
+
+ ether_setup(ndev);
+
+ ndev->open = netx_eth_open;
+ ndev->stop = netx_eth_close;
+ ndev->hard_start_xmit = netx_eth_hard_start_xmit;
+ ndev->tx_timeout = netx_eth_timeout;
+ ndev->watchdog_timeo = msecs_to_jiffies(5000);
+ ndev->get_stats = netx_eth_query_statistics;
+ ndev->set_multicast_list = netx_eth_set_multicast_list;
+
+ priv->msg_enable = NETIF_MSG_LINK;
+ priv->mii.phy_id_mask = 0x1f;
+ priv->mii.reg_num_mask = 0x1f;
+ priv->mii.force_media = 0;
+ priv->mii.full_duplex = 0;
+ priv->mii.dev = ndev;
+ priv->mii.mdio_read = netx_eth_phy_read;
+ priv->mii.mdio_write = netx_eth_phy_write;
+ priv->mii.phy_id = INTERNAL_PHY_ADR + priv->id;
+
+ running = xc_running(priv->xc);
+ xc_stop(priv->xc);
+
+ /* if the xc engine is already running, assume the bootloader has
+ * loaded the firmware for us
+ */
+ if (running) {
+ /* get Node Address from hardware */
+ mac4321 = readl(priv->xpec_base +
+ NETX_XPEC_RAM_START_OFS + ETH_MAC_4321);
+ mac65 = readl(priv->xpec_base +
+ NETX_XPEC_RAM_START_OFS + ETH_MAC_65);
+
+ ndev->dev_addr[0] = mac4321 & 0xff;
+ ndev->dev_addr[1] = (mac4321 >> 8) & 0xff;
+ ndev->dev_addr[2] = (mac4321 >> 16) & 0xff;
+ ndev->dev_addr[3] = (mac4321 >> 24) & 0xff;
+ ndev->dev_addr[4] = mac65 & 0xff;
+ ndev->dev_addr[5] = (mac65 >> 8) & 0xff;
+ } else {
+ if (xc_request_firmware(priv->xc)) {
+ printk(CARDNAME ": requesting firmware failed\n");
+ return -ENODEV;
+ }
+ }
+
+ xc_reset(priv->xc);
+ xc_start(priv->xc);
+
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ printk("%s: Invalid ethernet MAC address. Please "
+ "set using ifconfig\n", ndev->name);
+
+ for (i=2; i<=18; i++)
+ pfifo_push(EMPTY_PTR_FIFO(priv->id),
+ FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(priv->id));
+
+ return register_netdev(ndev);
+
+}
+
+static int netx_eth_drv_probe(struct platform_device *pdev)
+{
+ struct netx_eth_priv *priv;
+ struct net_device *ndev;
+ struct netxeth_platform_data *pdata;
+ int ret;
+
+ ndev = alloc_etherdev(sizeof (struct netx_eth_priv));
+ if (!ndev) {
+ printk("%s: could not allocate device.\n", CARDNAME);
+ ret = -ENOMEM;
+ goto exit;
+ }
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ platform_set_drvdata(pdev, ndev);
+
+ priv = netdev_priv(ndev);
+
+ pdata = (struct netxeth_platform_data *)pdev->dev.platform_data;
+ priv->xc = request_xc(pdata->xcno, &pdev->dev);
+ if (!priv->xc) {
+ dev_err(&pdev->dev, "unable to request xc engine\n");
+ ret = -ENODEV;
+ goto exit_free_netdev;
+ }
+
+ ndev->irq = priv->xc->irq;
+ priv->id = pdev->id;
+ priv->xpec_base = priv->xc->xpec_base;
+ priv->xmac_base = priv->xc->xmac_base;
+ priv->sram_base = priv->xc->sram_base;
+
+ ret = pfifo_request(PFIFO_MASK(priv->id));
+ if (ret) {
+ printk("unable to request PFIFO\n");
+ goto exit_free_xc;
+ }
+
+ ret = netx_eth_enable(ndev);
+ if (ret)
+ goto exit_free_pfifo;
+
+ return 0;
+exit_free_pfifo:
+ pfifo_free(PFIFO_MASK(priv->id));
+exit_free_xc:
+ free_xc(priv->xc);
+exit_free_netdev:
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+exit:
+ return ret;
+}
+
+static int netx_eth_drv_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = dev_get_drvdata(&pdev->dev);
+ struct netx_eth_priv *priv = netdev_priv(ndev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ unregister_netdev(ndev);
+ xc_stop(priv->xc);
+ free_xc(priv->xc);
+ free_netdev(ndev);
+ pfifo_free(PFIFO_MASK(priv->id));
+
+ return 0;
+}
+
+static int netx_eth_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ dev_err(&pdev->dev, "suspend not implemented\n");
+ return 0;
+}
+
+static int netx_eth_drv_resume(struct platform_device *pdev)
+{
+ dev_err(&pdev->dev, "resume not implemented\n");
+ return 0;
+}
+
+static struct platform_driver netx_eth_driver = {
+ .probe = netx_eth_drv_probe,
+ .remove = netx_eth_drv_remove,
+ .suspend = netx_eth_drv_suspend,
+ .resume = netx_eth_drv_resume,
+ .driver = {
+ .name = CARDNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init netx_eth_init(void)
+{
+ unsigned int phy_control, val;
+
+ printk("NetX Ethernet driver\n");
+
+ phy_control = PHY_CONTROL_PHY_ADDRESS(INTERNAL_PHY_ADR>>1) |
+ PHY_CONTROL_PHY1_MODE(PHY_MODE_ALL) |
+ PHY_CONTROL_PHY1_AUTOMDIX |
+ PHY_CONTROL_PHY1_EN |
+ PHY_CONTROL_PHY0_MODE(PHY_MODE_ALL) |
+ PHY_CONTROL_PHY0_AUTOMDIX |
+ PHY_CONTROL_PHY0_EN |
+ PHY_CONTROL_CLK_XLATIN;
+
+ val = readl(NETX_SYSTEM_IOC_ACCESS_KEY);
+ writel(val, NETX_SYSTEM_IOC_ACCESS_KEY);
+
+ writel(phy_control | PHY_CONTROL_RESET, NETX_SYSTEM_PHY_CONTROL);
+ udelay(100);
+
+ val = readl(NETX_SYSTEM_IOC_ACCESS_KEY);
+ writel(val, NETX_SYSTEM_IOC_ACCESS_KEY);
+
+ writel(phy_control, NETX_SYSTEM_PHY_CONTROL);
+
+ return platform_driver_register(&netx_eth_driver);
+}
+
+static void __exit netx_eth_cleanup(void)
+{
+ platform_driver_unregister(&netx_eth_driver);
+}
+
+module_init(netx_eth_init);
+module_exit(netx_eth_cleanup);
+
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 71f45056a70..e80d1e3aec6 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1359,7 +1359,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
kio_addr_t ioaddr = dev->base_addr;
int okay;
unsigned freespace;
- unsigned pktlen = skb? skb->len : 0;
+ unsigned pktlen = skb->len;
DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
skb, dev, pktlen);
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index cac9fdd2e1d..11daed495b9 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2627,6 +2627,50 @@ no_rx:
#endif
/**
+ * s2io_netpoll - Rx interrupt service handler for netpoll support
+ * @dev : pointer to the device structure.
+ * Description:
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void s2io_netpoll(struct net_device *dev)
+{
+ nic_t *nic = dev->priv;
+ mac_info_t *mac_control;
+ struct config_param *config;
+ XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ u64 val64;
+ int i;
+
+ disable_irq(dev->irq);
+
+ atomic_inc(&nic->isr_cnt);
+ mac_control = &nic->mac_control;
+ config = &nic->config;
+
+ val64 = readq(&bar0->rx_traffic_int);
+ writeq(val64, &bar0->rx_traffic_int);
+
+ for (i = 0; i < config->rx_ring_num; i++)
+ rx_intr_handler(&mac_control->rings[i]);
+
+ for (i = 0; i < config->rx_ring_num; i++) {
+ if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+ break;
+ }
+ }
+ atomic_dec(&nic->isr_cnt);
+ enable_irq(dev->irq);
+ return;
+}
+#endif
+
+/**
* rx_intr_handler - Rx interrupt handler
* @nic: device private variable.
* Description:
@@ -6967,6 +7011,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->weight = 32;
#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = s2io_netpoll;
+#endif
+
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
if (sp->high_dma_flag == TRUE)
dev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 61eec46cb11..f13b2a195c7 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -94,11 +94,13 @@
Version LK1.10 (Philippe De Muyter phdm@macqel.be):
- Make 'unblock interface after Tx underrun' work
+ Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com):
+ - Add support for IC Plus Corporation IP100A chipset
*/
#define DRV_NAME "sundance"
-#define DRV_VERSION "1.01+LK1.10"
-#define DRV_RELDATE "28-Oct-2005"
+#define DRV_VERSION "1.01+LK1.11"
+#define DRV_RELDATE "14-Jun-2006"
/* The user-configurable values.
@@ -287,6 +289,7 @@ static struct pci_device_id sundance_pci_tbl[] = {
{0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
{0,}
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -305,6 +308,7 @@ static const struct pci_id_info pci_id_tbl[] = {
{"D-Link DFE-530TXS FAST Ethernet Adapter"},
{"D-Link DL10050-based FAST Ethernet Adapter"},
{"Sundance Technology Alta"},
+ {"IC Plus Corporation IP100A FAST Ethernet Adapter"},
{NULL,}, /* 0 terminated list. */
};
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 23032a7bc0a..c3cb8d26cfe 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -217,7 +217,7 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
dev = alloc_trdev(sizeof(struct olympic_private)) ;
if (!dev) {
i = -ENOMEM;
- goto op_free_dev;
+ goto op_release_dev;
}
olympic_priv = dev->priv ;
@@ -282,8 +282,8 @@ op_free_iomap:
if (olympic_priv->olympic_lap)
iounmap(olympic_priv->olympic_lap);
-op_free_dev:
free_netdev(dev);
+op_release_dev:
pci_release_regions(pdev);
op_disable_dev:
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 2eb6b5f9ba0..09e05fe40c3 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -248,6 +248,7 @@ static void velocity_free_rd_ring(struct velocity_info *vptr);
static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
static int velocity_soft_reset(struct velocity_info *vptr);
static void mii_init(struct velocity_info *vptr, u32 mii_status);
+static u32 velocity_get_link(struct net_device *dev);
static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
static void velocity_print_link_status(struct velocity_info *vptr);
static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
@@ -798,6 +799,9 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
if (ret < 0)
goto err_iounmap;
+ if (velocity_get_link(dev))
+ netif_carrier_off(dev);
+
velocity_print_info(vptr);
pci_set_drvdata(pdev, dev);
@@ -1653,8 +1657,10 @@ static void velocity_error(struct velocity_info *vptr, int status)
if (linked) {
vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+ netif_carrier_on(vptr->dev);
} else {
vptr->mii_status |= VELOCITY_LINK_FAIL;
+ netif_carrier_off(vptr->dev);
}
velocity_print_link_status(vptr);
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 43d854ace23..b60ef02db7b 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -326,21 +326,21 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
if (request_irq(irq, sca_intr, 0, devname, card)) {
printk(KERN_ERR "c101: could not allocate IRQ\n");
c101_destroy_card(card);
- return(-EBUSY);
+ return -EBUSY;
}
card->irq = irq;
if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) {
printk(KERN_ERR "c101: could not request RAM window\n");
c101_destroy_card(card);
- return(-EBUSY);
+ return -EBUSY;
}
card->phy_winbase = winbase;
card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE);
if (!card->win0base) {
printk(KERN_ERR "c101: could not map I/O address\n");
c101_destroy_card(card);
- return -EBUSY;
+ return -EFAULT;
}
card->tx_ring_buffers = TX_RING_BUFFERS;
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c
index 46cef8f9213..57f9538b8fb 100644
--- a/drivers/net/wan/hdlc_generic.c
+++ b/drivers/net/wan/hdlc_generic.c
@@ -259,7 +259,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
}
-static void hdlc_setup(struct net_device *dev)
+void hdlc_setup(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -288,26 +288,6 @@ struct net_device *alloc_hdlcdev(void *priv)
return dev;
}
-int register_hdlc_device(struct net_device *dev)
-{
- int result = dev_alloc_name(dev, "hdlc%d");
- if (result < 0)
- return result;
-
- result = register_netdev(dev);
- if (result != 0)
- return -EIO;
-
-#if 0
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev); /* no carrier until DCD goes up */
-#endif
-
- return 0;
-}
-
-
-
void unregister_hdlc_device(struct net_device *dev)
{
rtnl_lock();
@@ -326,8 +306,8 @@ EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
EXPORT_SYMBOL(hdlc_set_carrier);
EXPORT_SYMBOL(hdlc_ioctl);
+EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
-EXPORT_SYMBOL(register_hdlc_device);
EXPORT_SYMBOL(unregister_hdlc_device);
static struct packet_type hdlc_packet_type = {
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index cd32751b64e..b7d88db89a5 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -387,6 +387,11 @@ static int __init n2_run(unsigned long io, unsigned long irq,
}
card->phy_winbase = winbase;
card->winbase = ioremap(winbase, USE_WINDOWSIZE);
+ if (!card->winbase) {
+ printk(KERN_ERR "n2: ioremap() failed\n");
+ n2_destroy_card(card);
+ return -EFAULT;
+ }
outb(0, io + N2_PCR);
outb(winbase >> 12, io + N2_BAR);
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index f485a97844c..670e8bd2245 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -354,6 +354,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
card->rambase == NULL) {
printk(KERN_ERR "pci200syn: ioremap() failed\n");
pci200_pci_remove_one(pdev);
+ return -EFAULT;
}
/* Reset PLX */
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index 29a756dd979..437e0e938e3 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -634,7 +634,13 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
/* set up PLX mapping */
plx_phy = pci_resource_start(pdev, 0);
+
card->plx = ioremap_nocache(plx_phy, 0x70);
+ if (!card->plx) {
+ printk(KERN_ERR "wanxl: ioremap() failed\n");
+ wanxl_pci_remove_one(pdev);
+ return -EFAULT;
+ }
#if RESET_WHILE_LOADING
wanxl_reset(card);
@@ -700,6 +706,12 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
}
mem = ioremap_nocache(mem_phy, PDM_OFFSET + sizeof(firmware));
+ if (!mem) {
+ printk(KERN_ERR "wanxl: ioremap() failed\n");
+ wanxl_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
for (i = 0; i < sizeof(firmware); i += 4)
writel(htonl(*(u32*)(firmware + i)), mem + PDM_OFFSET + i);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index e66fdb1f3cf..d8f917c21ea 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -636,6 +636,17 @@ struct bcm43xx_key {
u8 algorithm;
};
+/* Driver initialization status. */
+enum {
+ BCM43xx_STAT_UNINIT, /* Uninitialized. */
+ BCM43xx_STAT_INITIALIZING, /* init_board() in progress. */
+ BCM43xx_STAT_INITIALIZED, /* Fully operational. */
+ BCM43xx_STAT_SHUTTINGDOWN, /* free_board() in progress. */
+ 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))
+
struct bcm43xx_private {
struct ieee80211_device *ieee;
struct ieee80211softmac_device *softmac;
@@ -646,18 +657,17 @@ struct bcm43xx_private {
void __iomem *mmio_addr;
- /* Do not use the lock directly. Use the bcm43xx_lock* helper
- * functions, to be MMIO-safe. */
- spinlock_t _lock;
+ /* Locking, see "theory of locking" text below. */
+ spinlock_t irq_lock;
+ struct mutex mutex;
- /* Driver status flags. */
- u32 initialized:1, /* init_board() succeed */
- was_initialized:1, /* for PCI suspend/resume. */
- shutting_down:1, /* free_board() in progress */
+ /* Driver initialization status BCM43xx_STAT_*** */
+ atomic_t init_status;
+
+ u16 was_initialized:1, /* for PCI suspend/resume. */
__using_pio:1, /* Internal, use bcm43xx_using_pio(). */
bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
- powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */
short_preamble:1, /* TRUE, if short preamble is enabled. */
firmware_norelease:1; /* Do not release the firmware. Used on suspend. */
@@ -721,7 +731,7 @@ struct bcm43xx_private {
struct tasklet_struct isr_tasklet;
/* Periodic tasks */
- struct timer_list periodic_tasks;
+ struct work_struct periodic_work;
unsigned int periodic_state;
struct work_struct restart_work;
@@ -746,21 +756,55 @@ struct bcm43xx_private {
#endif
};
-/* bcm43xx_(un)lock() protect struct bcm43xx_private.
- * Note that _NO_ MMIO writes are allowed. If you want to
- * write to the device through MMIO in the critical section, use
- * the *_mmio lock functions.
- * MMIO read-access is allowed, though.
- */
-#define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags)
-#define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags)
-/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
- * MMIO write-access to the device is allowed.
- * All MMIO writes are flushed on unlock, so it is guaranteed to not
- * interfere with other threads writing MMIO registers.
+
+/* *** 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.
*/
-#define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags)
-#define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)
+
+/* 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)
@@ -843,16 +887,6 @@ struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
}
-/* Are we running in init_board() context? */
-static inline
-int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
-{
- if (bcm->initialized)
- return 0;
- if (bcm->shutting_down)
- return 0;
- return 1;
-}
static inline
struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index 7497fb16076..ce2e40b29b4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -77,8 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
down(&big_buffer_sem);
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
}
@@ -121,7 +121,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("\n");
out:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -159,8 +159,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
unsigned long flags;
down(&big_buffer_sem);
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
}
@@ -169,7 +169,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
out:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -188,8 +188,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
u64 tsf;
down(&big_buffer_sem);
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
}
@@ -199,7 +199,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
(unsigned int)(tsf & 0xFFFFFFFFULL));
out:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -221,8 +221,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = -EFAULT;
goto out_up;
}
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
goto out_unlock;
@@ -233,10 +233,11 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
goto out_unlock;
}
bcm43xx_tsf_write(bcm, tsf);
+ mmiowb();
res = buf_size;
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
out_up:
up(&big_buffer_sem);
return res;
@@ -257,7 +258,7 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
int i, cnt, j = 0;
down(&big_buffer_sem);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -293,14 +294,14 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if (*ppos == pos) {
/* Done. Drop the copied data. */
e->xmitstatus_printing = 0;
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
up(&big_buffer_sem);
return res;
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 4b2c02c0b31..ec80692d638 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_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
if (led->blink_interval) {
bcm43xx_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval);
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
}
static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 736dde96c4a..085d7857fe3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -498,20 +498,31 @@ static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mas
return old_mask;
}
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
+{
+ synchronize_irq(bcm->irq);
+ tasklet_disable(&bcm->isr_tasklet);
+}
+
/* Make sure we don't receive more data from the device. */
static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
{
- u32 old;
unsigned long flags;
+ u32 old;
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
+ if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
+ bcm43xx_unlock_irqonly(bcm, flags);
return -EBUSY;
}
old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- tasklet_disable(&bcm->isr_tasklet);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
+ bcm43xx_synchronize_irq(bcm);
+
if (oldstate)
*oldstate = old;
@@ -1389,7 +1400,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
#endif
}
- if (bcm->shutting_down) {
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
@@ -1709,7 +1720,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
# define bcmirq_handled(irq) do { /* nothing */ } while (0)
#endif /* CONFIG_BCM43XX_DEBUG*/
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
reason = bcm->irq_reason;
dma_reason[0] = bcm->dma_reason[0];
dma_reason[1] = bcm->dma_reason[1];
@@ -1734,7 +1745,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3]);
bcm43xx_controller_restart(bcm, "DMA error");
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqonly(bcm, flags);
return;
}
if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1821,7 +1833,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
if (!modparam_noleds)
bcm43xx_leds_update(bcm, activity);
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqonly(bcm, flags);
}
static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1870,7 +1883,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
if (!bcm)
return IRQ_NONE;
- spin_lock(&bcm->_lock);
+ spin_lock(&bcm->irq_lock);
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
@@ -1899,7 +1912,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
* completely, but some careful work is needed to fix this. I think it
* is best to stay with this cheap workaround for now... .
*/
- if (likely(bcm->initialized)) {
+ if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
/* disable all IRQs. They are enabled again in the bottom half. */
bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
/* save the reason code and call our bottom half. */
@@ -1909,7 +1922,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
out:
mmiowb();
- spin_unlock(&bcm->_lock);
+ spin_unlock(&bcm->irq_lock);
return ret;
}
@@ -2133,6 +2146,13 @@ out:
return err;
}
+#ifdef CONFIG_BCM947XX
+static struct pci_device_id bcm43xx_47xx_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+ { 0 }
+};
+#endif
+
static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
{
int res;
@@ -2142,11 +2162,15 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
bcm->irq = bcm->pci_dev->irq;
#ifdef CONFIG_BCM947XX
if (bcm->pci_dev->bus->number == 0) {
- struct pci_dev *d = NULL;
- /* FIXME: we will probably need more device IDs here... */
- d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
- if (d != NULL) {
- bcm->irq = d->irq;
+ struct pci_dev *d;
+ struct pci_device_id *id;
+ for (id = bcm43xx_47xx_ids; id->vendor; id++) {
+ d = pci_get_device(id->vendor, id->device, NULL);
+ if (d != NULL) {
+ bcm->irq = d->irq;
+ pci_dev_put(d);
+ break;
+ }
}
}
#endif
@@ -3106,15 +3130,10 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
//TODO for APHY (temperature?)
}
-static void bcm43xx_periodic_task_handler(unsigned long d)
+static void do_periodic_work(struct bcm43xx_private *bcm)
{
- struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
- unsigned long flags;
unsigned int state;
- bcm43xx_lock_mmio(bcm, flags);
-
- assert(bcm->initialized);
state = bcm->periodic_state;
if (state % 8 == 0)
bcm43xx_periodic_every120sec(bcm);
@@ -3122,29 +3141,93 @@ static void bcm43xx_periodic_task_handler(unsigned long d)
bcm43xx_periodic_every60sec(bcm);
if (state % 2 == 0)
bcm43xx_periodic_every30sec(bcm);
- bcm43xx_periodic_every15sec(bcm);
+ if (state % 1 == 0)
+ bcm43xx_periodic_every15sec(bcm);
bcm->periodic_state = state + 1;
- mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
+ schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+}
+
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+ int badness = 0;
+
+ if (state % 8 == 0) /* every 120 sec */
+ badness += 10;
+ if (state % 4 == 0) /* every 60 sec */
+ badness += 5;
+ if (state % 2 == 0) /* every 30 sec */
+ badness += 1;
+ if (state % 1 == 0) /* every 15 sec */
+ badness += 1;
- bcm43xx_unlock_mmio(bcm, flags);
+#define BADNESS_LIMIT 4
+ return badness;
+}
+
+static void bcm43xx_periodic_work_handler(void *d)
+{
+ struct bcm43xx_private *bcm = d;
+ unsigned long flags;
+ u32 savedirqs = 0;
+ int badness;
+
+ badness = estimate_periodic_work_badness(bcm->periodic_state);
+ if (badness > BADNESS_LIMIT) {
+ /* 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);
+ 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);
+ bcm43xx_synchronize_irq(bcm);
+ } else {
+ /* Periodic work should take short time, so we want low
+ * locking overhead.
+ */
+ bcm43xx_lock_irqsafe(bcm, flags);
+ }
+
+ do_periodic_work(bcm);
+
+ if (badness > BADNESS_LIMIT) {
+ bcm43xx_lock_irqonly(bcm, 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);
+ }
+ netif_wake_queue(bcm->net_dev);
+ mmiowb();
+ bcm43xx_unlock_irqonly(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
+ } else {
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
+ }
}
static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
{
- del_timer_sync(&bcm->periodic_tasks);
+ cancel_rearming_delayed_work(&bcm->periodic_work);
}
static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
{
- struct timer_list *timer = &(bcm->periodic_tasks);
+ struct work_struct *work = &(bcm->periodic_work);
- assert(bcm->initialized);
- setup_timer(timer,
- bcm43xx_periodic_task_handler,
- (unsigned long)bcm);
- timer->expires = jiffies;
- add_timer(timer);
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+ INIT_WORK(work, bcm43xx_periodic_work_handler, bcm);
+ schedule_work(work);
}
static void bcm43xx_security_init(struct bcm43xx_private *bcm)
@@ -3158,16 +3241,12 @@ static void bcm43xx_security_init(struct bcm43xx_private *bcm)
static void bcm43xx_free_board(struct bcm43xx_private *bcm)
{
int i, err;
- unsigned long flags;
+ bcm43xx_lock_noirq(bcm);
bcm43xx_sysfs_unregister(bcm);
-
bcm43xx_periodic_tasks_delete(bcm);
- bcm43xx_lock(bcm, flags);
- bcm->initialized = 0;
- bcm->shutting_down = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
if (!bcm->core_80211[i].available)
@@ -3182,23 +3261,19 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm)
bcm43xx_pctl_set_crystal(bcm, 0);
- bcm43xx_lock(bcm, flags);
- bcm->shutting_down = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+ bcm43xx_unlock_noirq(bcm);
}
static int bcm43xx_init_board(struct bcm43xx_private *bcm)
{
int i, err;
int connect_phy;
- unsigned long flags;
might_sleep();
- bcm43xx_lock(bcm, flags);
- bcm->initialized = 0;
- bcm->shutting_down = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_lock_noirq(bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
err = bcm43xx_pctl_set_crystal(bcm, 1);
if (err)
@@ -3265,9 +3340,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
}
/* Initialization of the board is done. Flag it as such. */
- bcm43xx_lock(bcm, flags);
- bcm->initialized = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
bcm43xx_periodic_tasks_setup(bcm);
bcm43xx_sysfs_register(bcm);
@@ -3278,6 +3351,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
assert(err == 0);
out:
+ bcm43xx_unlock_noirq(bcm);
+
return err;
err_80211_unwind:
@@ -3534,8 +3609,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
struct bcm43xx_radioinfo *radio;
unsigned long flags;
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
bcm43xx_mac_suspend(bcm);
bcm43xx_radio_selectchannel(bcm, channel, 0);
bcm43xx_mac_enable(bcm);
@@ -3543,7 +3618,7 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
radio = bcm43xx_current_radio(bcm);
radio->initial_channel = channel;
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
}
/* set_security() callback in struct ieee80211_device */
@@ -3557,7 +3632,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
dprintk(KERN_INFO PFX "set security called");
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
if (sec->flags & (1<<keyidx)) {
@@ -3587,7 +3662,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
dprintk(", .encrypt = %d", sec->encrypt);
}
dprintk("\n");
- if (bcm->initialized && !bcm->ieee->host_encrypt) {
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
+ !bcm->ieee->host_encrypt) {
if (secinfo->enabled) {
/* upload WEP keys to hardware */
char null_address[6] = { 0 };
@@ -3621,7 +3697,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
} else
bcm43xx_clear_keys(bcm);
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
}
/* hard_start_xmit() callback in struct ieee80211_device */
@@ -3633,10 +3709,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
int err = -ENODEV;
unsigned long flags;
- bcm43xx_lock_mmio(bcm, flags);
- if (likely(bcm->initialized))
+ bcm43xx_lock_irqonly(bcm, flags);
+ if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
err = bcm43xx_tx(bcm, txb);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
return err;
}
@@ -3651,9 +3727,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_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
bcm43xx_controller_restart(bcm, "TX timeout");
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3678,9 +3754,11 @@ static int bcm43xx_net_open(struct net_device *net_dev)
static int bcm43xx_net_stop(struct net_device *net_dev)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+ int err;
ieee80211softmac_stop(net_dev);
- bcm43xx_disable_interrupts_sync(bcm, NULL);
+ err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+ assert(!err);
bcm43xx_free_board(bcm);
return 0;
@@ -3692,6 +3770,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
{
int err;
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
bcm->ieee = netdev_priv(net_dev);
bcm->softmac = ieee80211_priv(net_dev);
bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
@@ -3700,7 +3779,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
bcm->pci_dev = pci_dev;
bcm->net_dev = net_dev;
bcm->bad_frames_preempt = modparam_bad_frames_preempt;
- spin_lock_init(&bcm->_lock);
+ spin_lock_init(&bcm->irq_lock);
+ mutex_init(&bcm->mutex);
tasklet_init(&bcm->isr_tasklet,
(void (*)(unsigned long))bcm43xx_interrupt_tasklet,
(unsigned long)bcm);
@@ -3831,7 +3911,7 @@ static void bcm43xx_chip_reset(void *_bcm)
struct net_device *net_dev = bcm->net_dev;
struct pci_dev *pci_dev = bcm->pci_dev;
int err;
- int was_initialized = bcm->initialized;
+ int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
netif_stop_queue(bcm->net_dev);
tasklet_disable(&bcm->isr_tasklet);
@@ -3866,6 +3946,7 @@ failure:
*/
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
{
+ 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);
@@ -3884,11 +3965,11 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
dprintk(KERN_INFO PFX "Suspending...\n");
- bcm43xx_lock(bcm, flags);
- bcm->was_initialized = bcm->initialized;
- if (bcm->initialized)
+ bcm43xx_lock_irqsafe(bcm, flags);
+ bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+ if (bcm->was_initialized)
try_to_shutdown = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
netif_device_detach(net_dev);
if (try_to_shutdown) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index b0abac51553..f8200deecc8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1410,7 +1410,10 @@ static inline
u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ u16 ret;
+ unsigned long flags;
+ local_irq_save(flags);
if (phy->connected) {
bcm43xx_phy_write(bcm, 0x15, 0xE300);
control <<= 8;
@@ -1430,8 +1433,10 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
udelay(8);
}
+ ret = bcm43xx_phy_read(bcm, 0x002D);
+ local_irq_restore(flags);
- return bcm43xx_phy_read(bcm, 0x002D);
+ return ret;
}
static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
@@ -1648,7 +1653,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
{
static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
- const int is_initializing = bcm43xx_is_initializing(bcm);
+ const int is_initializing = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZING);
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
u16 h, i, oldi = 0, j;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 0aa1bd269a2..574085c4615 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,8 +262,10 @@ static void tx_tasklet(unsigned long d)
int err;
u16 txctl;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqonly(bcm, flags);
+ if (queue->tx_frozen)
+ goto out_unlock;
txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
goto out_unlock;
@@ -298,7 +300,7 @@ static void tx_tasklet(unsigned long d)
continue;
}
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqonly(bcm, flags);
}
static void setup_txqueues(struct bcm43xx_pioqueue *queue)
@@ -374,7 +376,6 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue)
struct bcm43xx_pio_txpacket *packet, *tmp_packet;
netif_tx_disable(queue->bcm->net_dev);
- assert(queue->bcm->shutting_down);
tasklet_disable(&queue->txtask);
list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
@@ -634,5 +635,40 @@ void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
& ~BCM43xx_PIO_TXCTL_SUSPEND);
bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1);
- tasklet_schedule(&queue->txtask);
+ if (!list_empty(&queue->txqueue))
+ tasklet_schedule(&queue->txtask);
+}
+
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+ struct bcm43xx_pio *pio;
+
+ assert(bcm43xx_using_pio(bcm));
+ pio = bcm43xx_current_pio(bcm);
+ pio->queue0->tx_frozen = 1;
+ pio->queue1->tx_frozen = 1;
+ pio->queue2->tx_frozen = 1;
+ pio->queue3->tx_frozen = 1;
}
+
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+ struct bcm43xx_pio *pio;
+
+ assert(bcm43xx_using_pio(bcm));
+ pio = bcm43xx_current_pio(bcm);
+ pio->queue0->tx_frozen = 0;
+ pio->queue1->tx_frozen = 0;
+ pio->queue2->tx_frozen = 0;
+ pio->queue3->tx_frozen = 0;
+ if (!list_empty(&pio->queue0->txqueue))
+ tasklet_schedule(&pio->queue0->txtask);
+ if (!list_empty(&pio->queue1->txqueue))
+ tasklet_schedule(&pio->queue1->txtask);
+ if (!list_empty(&pio->queue2->txqueue))
+ tasklet_schedule(&pio->queue2->txtask);
+ if (!list_empty(&pio->queue3->txqueue))
+ tasklet_schedule(&pio->queue3->txtask);
+}
+
+
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
index dfc78209e3a..bc78a3c2caf 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -54,6 +54,7 @@ struct bcm43xx_pioqueue {
u16 mmio_base;
u8 tx_suspended:1,
+ tx_frozen:1,
need_workarounds:1; /* Workarounds needed for core.rev < 3 */
/* Adjusted size of the device internal TX buffer. */
@@ -108,8 +109,12 @@ void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm,
struct bcm43xx_xmitstatus *status);
void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
+/* Suspend a TX queue on hardware level. */
void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm);
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm);
#else /* CONFIG_BCM43XX_PIO */
@@ -145,6 +150,14 @@ static inline
void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
{
}
+static inline
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+}
+static inline
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+}
#endif /* CONFIG_BCM43XX_PIO */
#endif /* BCM43xx_PIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index b438f48e891..6a23bdc7541 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,12 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
GFP_KERNEL);
if (!sprom)
return -ENOMEM;
- bcm43xx_lock_mmio(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = bcm43xx_sprom_read(bcm, sprom);
if (!err)
err = sprom2hex(sprom, buf, PAGE_SIZE);
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
kfree(sprom);
return err;
@@ -150,10 +150,10 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
err = hex2sprom(sprom, buf, count);
if (err)
goto out_kfree;
- bcm43xx_lock_mmio(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = bcm43xx_sprom_write(bcm, sprom);
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
out_kfree:
kfree(sprom);
@@ -170,15 +170,13 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- unsigned long flags;
int err;
ssize_t count = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_noirq(bcm);
switch (bcm43xx_current_radio(bcm)->interfmode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -195,7 +193,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
}
err = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return err ? err : count;
@@ -231,16 +229,15 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
return -EINVAL;
}
- bcm43xx_lock_mmio(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
printk(KERN_ERR PFX "Interference Mitigation not "
"supported by device\n");
}
-
- bcm43xx_unlock_mmio(bcm, flags);
+ mmiowb();
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err ? err : count;
}
@@ -254,15 +251,13 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- unsigned long flags;
int err;
ssize_t count;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_noirq(bcm);
if (bcm->short_preamble)
count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -270,7 +265,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(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return err ? err : count;
}
@@ -290,13 +285,12 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
value = get_boolean(buf, count);
if (value < 0)
return value;
- bcm43xx_lock(bcm, flags);
- assert(bcm->initialized);
+ bcm43xx_lock_irqsafe(bcm, flags);
bcm->short_preamble = !!value;
err = 0;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err ? err : count;
}
@@ -310,7 +304,7 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
struct device *dev = &bcm->pci_dev->dev;
int err;
- assert(bcm->initialized);
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
err = device_create_file(dev, &dev_attr_sprom);
if (err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index b45063974ae..c35cb3a0777 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -55,13 +55,13 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
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(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
for (i = 0; i < bcm->nr_80211_available; i++) {
phy = &(bcm->core_80211_ext[i].phy);
switch (phy->type) {
@@ -77,7 +77,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
assert(0);
}
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
i = 0;
if (have_a) {
@@ -111,7 +111,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
int freq;
int err = -EINVAL;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
channel = data->freq.m;
freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -121,7 +121,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
}
if (!bcm43xx_is_valid_channel(bcm, channel))
goto out_unlock;
- if (bcm->initialized) {
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
//ieee80211softmac_disassoc(softmac, $REASON);
bcm43xx_mac_suspend(bcm);
err = bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -131,7 +131,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
err = 0;
}
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -147,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
int err = -ENODEV;
u16 channel;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
radio = bcm43xx_current_radio(bcm);
channel = radio->channel;
if (channel == 0xFF) {
- assert(!bcm->initialized);
channel = radio->initial_channel;
if (channel == 0xFF)
goto out_unlock;
@@ -163,7 +162,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -181,13 +180,13 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
if (mode == IW_MODE_AUTO)
mode = BCM43xx_INITIAL_IWMODE;
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, 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_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -200,9 +199,9 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
data->mode = bcm->ieee->iw_mode;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -255,7 +254,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
IW_ENC_CAPA_CIPHER_TKIP |
IW_ENC_CAPA_CIPHER_CCMP;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
phy = bcm43xx_current_phy(bcm);
range->num_bitrates = 0;
@@ -302,7 +301,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
}
range->num_frequency = j;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -313,14 +312,13 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
size_t len;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_noirq(bcm);
len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
memcpy(bcm->nick, extra, len);
bcm->nick[len] = '\0';
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return 0;
}
@@ -331,15 +329,14 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
size_t len;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_noirq(bcm);
len = strlen(bcm->nick) + 1;
memcpy(extra, bcm->nick, len);
data->data.length = (__u16)len;
data->data.flags = 1;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_noirq(bcm);
return 0;
}
@@ -353,7 +350,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if (data->rts.disabled) {
bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
err = 0;
@@ -364,7 +361,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -377,11 +374,11 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
data->rts.value = bcm->rts_threshold;
data->rts.fixed = 0;
data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -395,7 +392,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
if (data->frag.disabled) {
bcm->ieee->fts = MAX_FRAG_THRESHOLD;
err = 0;
@@ -406,7 +403,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -419,11 +416,11 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
data->frag.value = bcm->ieee->fts;
data->frag.fixed = 0;
data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -445,8 +442,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
return -EOPNOTSUPP;
}
- bcm43xx_lock_mmio(bcm, flags);
- if (!bcm->initialized)
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
phy = bcm43xx_current_phy(bcm);
@@ -469,7 +466,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -484,8 +481,8 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
unsigned long flags;
int err = -ENODEV;
- bcm43xx_lock(bcm, flags);
- if (!bcm->initialized)
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
/* desired dBm value is in Q5.2 */
@@ -496,7 +493,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -583,8 +580,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
return -EINVAL;
}
- bcm43xx_lock_mmio(bcm, flags);
- if (bcm->initialized) {
+ bcm43xx_lock_irqsafe(bcm, flags);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
printk(KERN_ERR PFX "Interference Mitigation not "
@@ -598,7 +595,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
} else
bcm43xx_current_radio(bcm)->interfmode = mode;
}
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return err;
}
@@ -612,9 +609,9 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
unsigned long flags;
int mode;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
mode = bcm43xx_current_radio(bcm)->interfmode;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
switch (mode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -644,9 +641,9 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
int on;
on = *((int *)extra);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
bcm->short_preamble = !!on;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -660,9 +657,9 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
unsigned long flags;
int on;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
on = bcm->short_preamble;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
if (on)
strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -684,11 +681,11 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
on = *((int *)extra);
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
bcm->ieee->host_encrypt = !!on;
bcm->ieee->host_decrypt = !!on;
bcm->ieee->host_build_iv = !on;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
return 0;
}
@@ -702,9 +699,9 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
unsigned long flags;
int on;
- bcm43xx_lock(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
on = bcm->ieee->host_encrypt;
- bcm43xx_unlock(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
if (on)
strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -767,11 +764,11 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
if (!sprom)
goto out;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = -ENODEV;
- if (bcm->initialized)
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_read(bcm, sprom);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
if (!err)
data->data.length = sprom2hex(sprom, extra);
kfree(sprom);
@@ -812,11 +809,11 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
if (err)
goto out_kfree;
- bcm43xx_lock_mmio(bcm, flags);
+ bcm43xx_lock_irqsafe(bcm, flags);
err = -ENODEV;
- if (bcm->initialized)
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_write(bcm, sprom);
- bcm43xx_unlock_mmio(bcm, flags);
+ bcm43xx_unlock_irqsafe(bcm, flags);
out_kfree:
kfree(sprom);
out:
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 39f82f21974..081a8999666 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
}
-static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_enable_interrupts(struct ipw_priv *priv)
{
if (priv->status & STATUS_INT_ENABLED)
return;
@@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv)
ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
}
-static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_disable_interrupts(struct ipw_priv *priv)
{
if (!(priv->status & STATUS_INT_ENABLED))
return;
@@ -549,6 +549,24 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv)
ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
}
+static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->irq_lock, flags);
+ __ipw_enable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->irq_lock, flags);
+ __ipw_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
#ifdef CONFIG_IPW2200_DEBUG
static char *ipw_error_desc(u32 val)
{
@@ -1856,7 +1874,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
unsigned long flags;
int rc = 0;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&priv->irq_lock, flags);
inta = ipw_read32(priv, IPW_INTA_RW);
inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
@@ -1865,6 +1883,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
/* Add any cached INTA values that need to be handled */
inta |= priv->isr_inta;
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
/* handle all the justifications for the interrupt */
if (inta & IPW_INTA_BIT_RX_TRANSFER) {
ipw_rx(priv);
@@ -1993,10 +2015,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
}
+ spin_unlock_irqrestore(&priv->lock, flags);
+
/* enable all interrupts */
ipw_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
}
#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
@@ -10460,7 +10482,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
if (!priv)
return IRQ_NONE;
- spin_lock(&priv->lock);
+ spin_lock(&priv->irq_lock);
if (!(priv->status & STATUS_INT_ENABLED)) {
/* Shared IRQ */
@@ -10482,7 +10504,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
}
/* tell the device to stop sending interrupts */
- ipw_disable_interrupts(priv);
+ __ipw_disable_interrupts(priv);
/* ack current interrupts */
inta &= (IPW_INTA_MASK_ALL & inta_mask);
@@ -10493,11 +10515,11 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
tasklet_schedule(&priv->irq_tasklet);
- spin_unlock(&priv->lock);
+ spin_unlock(&priv->irq_lock);
return IRQ_HANDLED;
none:
- spin_unlock(&priv->lock);
+ spin_unlock(&priv->irq_lock);
return IRQ_NONE;
}
@@ -11477,6 +11499,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_IPW2200_DEBUG
ipw_debug_level = debug;
#endif
+ spin_lock_init(&priv->irq_lock);
spin_lock_init(&priv->lock);
for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 6044c0be2c8..ea12ad66b8e 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1173,6 +1173,7 @@ struct ipw_priv {
struct ieee80211_device *ieee;
spinlock_t lock;
+ spinlock_t irq_lock;
struct mutex mutex;
/* basic pci-network driver stuff */
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index dade4b90357..5b69befdab7 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -1695,8 +1695,8 @@ static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */
/* Look in the table if the frequency is allowed */
if (table[9 - (freq / 16)] & (1 << (freq % 16))) {
/* Compute approximate channel number */
- while ((((channel_bands[c] >> 1) - 24) < freq) &&
- (c < NELS(channel_bands)))
+ while ((c < NELS(channel_bands)) &&
+ (((channel_bands[c] >> 1) - 24) < freq))
c++;
list[i].i = c; /* Set the list index */
@@ -2903,6 +2903,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
{
net_local *lp = (net_local *) dev->priv;
unsigned long flags;
+ char data[ETH_ZLEN];
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
@@ -2937,15 +2938,16 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
if (skb->len < ETH_ZLEN) {
- skb = skb_padto(skb, ETH_ZLEN);
- if (skb == NULL)
- return 0;
+ memset(data, 0, ETH_ZLEN);
+ memcpy(data, skb->data, skb->len);
+ /* Write packet on the card */
+ if(wv_packet_write(dev, data, ETH_ZLEN))
+ return 1; /* We failed */
}
-
- /* Write packet on the card */
- if(wv_packet_write(dev, skb->data, skb->len))
+ else if(wv_packet_write(dev, skb->data, skb->len))
return 1; /* We failed */
+
dev_kfree_skb(skb);
#ifdef DEBUG_TX_TRACE