Commit 5f945956 authored by Manfred Spraul's avatar Manfred Spraul Committed by Jeff Garzik

[PATCH] forcedeth update

Andrew de Quincey added wol support to forcedeth.
The patch also renames additional function, to help analyzing backtraces. 
parent 1f676e60
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* countries. * countries.
* *
* Copyright (C) 2003 Manfred Spraul * Copyright (C) 2003 Manfred Spraul
* Copyright (C) 2004 Andrew de Quincey (wol support)
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
* *
* Changelog: * Changelog:
* 0.01: 05 Oct 2003: First release that compiles without warnings. * 0.01: 05 Oct 2003: First release that compiles without warnings.
* 0.02: 05 Oct 2003: Fix bug for drain_tx: do not try to free NULL skbs. * 0.02: 05 Oct 2003: Fix bug for nv_drain_tx: do not try to free NULL skbs.
* Check all PCI BARs for the register window. * Check all PCI BARs for the register window.
* udelay added to mii_rw. * udelay added to mii_rw.
* 0.03: 06 Oct 2003: Initialize dev->irq. * 0.03: 06 Oct 2003: Initialize dev->irq.
...@@ -37,7 +38,7 @@ ...@@ -37,7 +38,7 @@
* 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated, * 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated,
* irq mask updated * irq mask updated
* 0.07: 14 Oct 2003: Further irq mask updates. * 0.07: 14 Oct 2003: Further irq mask updates.
* 0.08: 20 Oct 2003: rx_desc.Length initialization added, alloc_rx refill * 0.08: 20 Oct 2003: rx_desc.Length initialization added, nv_alloc_rx refill
* added into irq handler, NULL check for drain_ring. * added into irq handler, NULL check for drain_ring.
* 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the * 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the
* requested interrupt sources. * requested interrupt sources.
...@@ -47,7 +48,7 @@ ...@@ -47,7 +48,7 @@
* 0.12: 23 Oct 2003: Cleanups for release. * 0.12: 23 Oct 2003: Cleanups for release.
* 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10. * 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10.
* Set link speed correctly. start rx before starting * Set link speed correctly. start rx before starting
* tx (start_rx sets the link speed). * tx (nv_start_rx sets the link speed).
* 0.14: 25 Oct 2003: Nic dependant irq mask. * 0.14: 25 Oct 2003: Nic dependant irq mask.
* 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during * 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during
* open. * open.
...@@ -58,7 +59,7 @@ ...@@ -58,7 +59,7 @@
* 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats * 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats
* 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac * 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac
* addresses, really stop rx if already running * addresses, really stop rx if already running
* in start_rx, clean up a bit. * in nv_start_rx, clean up a bit.
* (C) Carl-Daniel Hailfinger * (C) Carl-Daniel Hailfinger
* 0.20: 07 Dec 2003: alloc fixes * 0.20: 07 Dec 2003: alloc fixes
* 0.21: 12 Jan 2004: additional alloc fix, nic polling fix. * 0.21: 12 Jan 2004: additional alloc fix, nic polling fix.
...@@ -66,6 +67,8 @@ ...@@ -66,6 +67,8 @@
* on close. * on close.
* (C) Carl-Daniel Hailfinger, Manfred Spraul * (C) Carl-Daniel Hailfinger, Manfred Spraul
* 0.23: 26 Jan 2004: various small cleanups * 0.23: 26 Jan 2004: various small cleanups
* 0.24: 27 Feb 2004: make driver even less anonymous in backtraces
* 0.25: 09 Mar 2004: wol support
* *
* Known bugs: * Known bugs:
* We suspect that on some hardware no TX done interrupts are generated. * We suspect that on some hardware no TX done interrupts are generated.
...@@ -77,7 +80,7 @@ ...@@ -77,7 +80,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic. * superfluous timer interrupts from the nic.
*/ */
#define FORCEDETH_VERSION "0.23" #define FORCEDETH_VERSION "0.25"
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -232,6 +235,7 @@ enum { ...@@ -232,6 +235,7 @@ enum {
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 #define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 #define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 #define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
#define NVREG_WAKEUPFLAGS_ENABLE 0x1111
NvRegPatternCRC = 0x204, NvRegPatternCRC = 0x204,
NvRegPatternMask = 0x208, NvRegPatternMask = 0x208,
...@@ -340,6 +344,7 @@ struct fe_priv { ...@@ -340,6 +344,7 @@ struct fe_priv {
u32 linkspeed; u32 linkspeed;
int duplex; int duplex;
int phyaddr; int phyaddr;
int wolenabled;
/* General data: RO fields */ /* General data: RO fields */
dma_addr_t ring_addr; dma_addr_t ring_addr;
...@@ -468,12 +473,12 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) ...@@ -468,12 +473,12 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
return retval; return retval;
} }
static void start_rx(struct net_device *dev) static void nv_start_rx(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev); u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: start_rx\n", dev->name); dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
/* Already running? Stop it. */ /* Already running? Stop it. */
if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) {
writel(0, base + NvRegReceiverControl); writel(0, base + NvRegReceiverControl);
...@@ -485,48 +490,48 @@ static void start_rx(struct net_device *dev) ...@@ -485,48 +490,48 @@ static void start_rx(struct net_device *dev)
pci_push(base); pci_push(base);
} }
static void stop_rx(struct net_device *dev) static void nv_stop_rx(struct net_device *dev)
{ {
u8 *base = get_hwbase(dev); u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: stop_rx\n", dev->name); dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name);
writel(0, base + NvRegReceiverControl); writel(0, base + NvRegReceiverControl);
reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0,
NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX,
KERN_INFO "stop_rx: ReceiverStatus remained busy"); KERN_INFO "nv_stop_rx: ReceiverStatus remained busy");
udelay(NV_RXSTOP_DELAY2); udelay(NV_RXSTOP_DELAY2);
writel(0, base + NvRegLinkSpeed); writel(0, base + NvRegLinkSpeed);
} }
static void start_tx(struct net_device *dev) static void nv_start_tx(struct net_device *dev)
{ {
u8 *base = get_hwbase(dev); u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: start_tx\n", dev->name); dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name);
writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl);
pci_push(base); pci_push(base);
} }
static void stop_tx(struct net_device *dev) static void nv_stop_tx(struct net_device *dev)
{ {
u8 *base = get_hwbase(dev); u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: stop_tx\n", dev->name); dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name);
writel(0, base + NvRegTransmitterControl); writel(0, base + NvRegTransmitterControl);
reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0,
NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX,
KERN_INFO "stop_tx: TransmitterStatus remained busy"); KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
udelay(NV_TXSTOP_DELAY2); udelay(NV_TXSTOP_DELAY2);
writel(0, base + NvRegUnknownTransmitterReg); writel(0, base + NvRegUnknownTransmitterReg);
} }
static void txrx_reset(struct net_device *dev) static void nv_txrx_reset(struct net_device *dev)
{ {
u8 *base = get_hwbase(dev); u8 *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: txrx_reset\n", dev->name); dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl); writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl);
pci_push(base); pci_push(base);
udelay(NV_TXRX_RESET_DELAY); udelay(NV_TXRX_RESET_DELAY);
...@@ -551,9 +556,10 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) ...@@ -551,9 +556,10 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
return &np->stats; return &np->stats;
} }
static int nv_ethtool_ioctl (struct net_device *dev, void *useraddr) static int nv_ethtool_ioctl(struct net_device *dev, void *useraddr)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev);
u32 ethcmd; u32 ethcmd;
if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd))) if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
...@@ -580,6 +586,39 @@ static int nv_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -580,6 +586,39 @@ static int nv_ethtool_ioctl (struct net_device *dev, void *useraddr)
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case ETHTOOL_GWOL:
{
struct ethtool_wolinfo wolinfo;
memset(&wolinfo, 0, sizeof(wolinfo));
wolinfo.supported = WAKE_MAGIC;
spin_lock_irq(&np->lock);
if (np->wolenabled)
wolinfo.wolopts = WAKE_MAGIC;
spin_unlock_irq(&np->lock);
if (copy_to_user(useraddr, &wolinfo, sizeof(wolinfo)))
return -EFAULT;
return 0;
}
case ETHTOOL_SWOL:
{
struct ethtool_wolinfo wolinfo;
if (copy_from_user(&wolinfo, useraddr, sizeof(wolinfo)))
return -EFAULT;
spin_lock_irq(&np->lock);
if (wolinfo.wolopts == 0) {
writel(0, base + NvRegWakeUpFlags);
np->wolenabled = 0;
}
if (wolinfo.wolopts & WAKE_MAGIC) {
writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
np->wolenabled = 1;
}
spin_unlock_irq(&np->lock);
return 0;
}
default: default:
break; break;
...@@ -603,11 +642,11 @@ static int nv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -603,11 +642,11 @@ static int nv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
} }
/* /*
* alloc_rx: fill rx ring entries. * nv_alloc_rx: fill rx ring entries.
* Return 1 if the allocations for the skbs failed and the * Return 1 if the allocations for the skbs failed and the
* rx engine is without Available descriptors * rx engine is without Available descriptors
*/ */
static int alloc_rx(struct net_device *dev) static int nv_alloc_rx(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
unsigned int refill_rx = np->refill_rx; unsigned int refill_rx = np->refill_rx;
...@@ -633,7 +672,7 @@ static int alloc_rx(struct net_device *dev) ...@@ -633,7 +672,7 @@ static int alloc_rx(struct net_device *dev)
np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE); np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE);
wmb(); wmb();
np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL); np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL);
dprintk(KERN_DEBUG "%s: alloc_rx: Packet %d marked as Available\n", dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
dev->name, refill_rx); dev->name, refill_rx);
refill_rx++; refill_rx++;
} }
...@@ -643,13 +682,13 @@ static int alloc_rx(struct net_device *dev) ...@@ -643,13 +682,13 @@ static int alloc_rx(struct net_device *dev)
return 0; return 0;
} }
static void do_rx_refill(unsigned long data) static void nv_do_rx_refill(unsigned long data)
{ {
struct net_device *dev = (struct net_device *) data; struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
disable_irq(dev->irq); disable_irq(dev->irq);
if (alloc_rx(dev)) { if (nv_alloc_rx(dev)) {
spin_lock(&np->lock); spin_lock(&np->lock);
if (!np->in_shutdown) if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL); mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
...@@ -658,7 +697,7 @@ static void do_rx_refill(unsigned long data) ...@@ -658,7 +697,7 @@ static void do_rx_refill(unsigned long data)
enable_irq(dev->irq); enable_irq(dev->irq);
} }
static int init_ring(struct net_device *dev) static int nv_init_ring(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
int i; int i;
...@@ -673,10 +712,10 @@ static int init_ring(struct net_device *dev) ...@@ -673,10 +712,10 @@ static int init_ring(struct net_device *dev)
for (i = 0; i < RX_RING; i++) { for (i = 0; i < RX_RING; i++) {
np->rx_ring[i].Flags = 0; np->rx_ring[i].Flags = 0;
} }
return alloc_rx(dev); return nv_alloc_rx(dev);
} }
static void drain_tx(struct net_device *dev) static void nv_drain_tx(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
int i; int i;
...@@ -693,7 +732,7 @@ static void drain_tx(struct net_device *dev) ...@@ -693,7 +732,7 @@ static void drain_tx(struct net_device *dev)
} }
} }
static void drain_rx(struct net_device *dev) static void nv_drain_rx(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
int i; int i;
...@@ -712,8 +751,8 @@ static void drain_rx(struct net_device *dev) ...@@ -712,8 +751,8 @@ static void drain_rx(struct net_device *dev)
static void drain_ring(struct net_device *dev) static void drain_ring(struct net_device *dev)
{ {
drain_tx(dev); nv_drain_tx(dev);
drain_rx(dev); nv_drain_rx(dev);
} }
/* /*
...@@ -759,11 +798,11 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -759,11 +798,11 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
} }
/* /*
* tx_done: check for completed packets, release the skbs. * nv_tx_done: check for completed packets, release the skbs.
* *
* Caller must own np->lock. * Caller must own np->lock.
*/ */
static void tx_done(struct net_device *dev) static void nv_tx_done(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
...@@ -773,7 +812,7 @@ static void tx_done(struct net_device *dev) ...@@ -773,7 +812,7 @@ static void tx_done(struct net_device *dev)
prd = &np->tx_ring[i]; prd = &np->tx_ring[i];
dprintk(KERN_DEBUG "%s: tx_done: looking at packet %d, Flags 0x%x.\n", dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
dev->name, np->nic_tx, prd->Flags); dev->name, np->nic_tx, prd->Flags);
if (prd->Flags & cpu_to_le16(NV_TX_VALID)) if (prd->Flags & cpu_to_le16(NV_TX_VALID))
break; break;
...@@ -814,26 +853,26 @@ static void nv_tx_timeout(struct net_device *dev) ...@@ -814,26 +853,26 @@ static void nv_tx_timeout(struct net_device *dev)
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
/* 1) stop tx engine */ /* 1) stop tx engine */
stop_tx(dev); nv_stop_tx(dev);
/* 2) check that the packets were not sent already: */ /* 2) check that the packets were not sent already: */
tx_done(dev); nv_tx_done(dev);
/* 3) if there are dead entries: clear everything */ /* 3) if there are dead entries: clear everything */
if (np->next_tx != np->nic_tx) { if (np->next_tx != np->nic_tx) {
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
drain_tx(dev); nv_drain_tx(dev);
np->next_tx = np->nic_tx = 0; np->next_tx = np->nic_tx = 0;
writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
/* 4) restart tx engine */ /* 4) restart tx engine */
start_tx(dev); nv_start_tx(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
} }
static void rx_process(struct net_device *dev) static void nv_rx_process(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
...@@ -847,7 +886,7 @@ static void rx_process(struct net_device *dev) ...@@ -847,7 +886,7 @@ static void rx_process(struct net_device *dev)
i = np->cur_rx % RX_RING; i = np->cur_rx % RX_RING;
prd = &np->rx_ring[i]; prd = &np->rx_ring[i];
dprintk(KERN_DEBUG "%s: rx_process: looking at packet %d, Flags 0x%x.\n", dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
dev->name, np->cur_rx, prd->Flags); dev->name, np->cur_rx, prd->Flags);
if (prd->Flags & cpu_to_le16(NV_RX_AVAIL)) if (prd->Flags & cpu_to_le16(NV_RX_AVAIL))
...@@ -915,7 +954,7 @@ static void rx_process(struct net_device *dev) ...@@ -915,7 +954,7 @@ static void rx_process(struct net_device *dev)
skb_put(skb, len); skb_put(skb, len);
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
dprintk(KERN_DEBUG "%s: rx_process: packet %d with %d bytes, proto %d accepted.\n", dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
dev->name, np->cur_rx, len, skb->protocol); dev->name, np->cur_rx, len, skb->protocol);
netif_rx(skb); netif_rx(skb);
dev->last_rx = jiffies; dev->last_rx = jiffies;
...@@ -990,24 +1029,24 @@ static void nv_set_multicast(struct net_device *dev) ...@@ -990,24 +1029,24 @@ static void nv_set_multicast(struct net_device *dev)
addr[0] |= NVREG_MCASTADDRA_FORCE; addr[0] |= NVREG_MCASTADDRA_FORCE;
pff |= NVREG_PFF_ALWAYS; pff |= NVREG_PFF_ALWAYS;
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
stop_rx(dev); nv_stop_rx(dev);
writel(addr[0], base + NvRegMulticastAddrA); writel(addr[0], base + NvRegMulticastAddrA);
writel(addr[1], base + NvRegMulticastAddrB); writel(addr[1], base + NvRegMulticastAddrB);
writel(mask[0], base + NvRegMulticastMaskA); writel(mask[0], base + NvRegMulticastMaskA);
writel(mask[1], base + NvRegMulticastMaskB); writel(mask[1], base + NvRegMulticastMaskB);
writel(pff, base + NvRegPacketFilterFlags); writel(pff, base + NvRegPacketFilterFlags);
start_rx(dev); nv_start_rx(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
} }
static int update_linkspeed(struct net_device *dev) static int nv_update_linkspeed(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
int adv, lpa, newls, newdup; int adv, lpa, newls, newdup;
adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ);
dprintk(KERN_DEBUG "%s: update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n",
dev->name, adv, lpa); dev->name, adv, lpa);
/* FIXME: handle parallel detection properly, handle gigabit ethernet */ /* FIXME: handle parallel detection properly, handle gigabit ethernet */
...@@ -1037,7 +1076,7 @@ static int update_linkspeed(struct net_device *dev) ...@@ -1037,7 +1076,7 @@ static int update_linkspeed(struct net_device *dev)
return 0; return 0;
} }
static void link_irq(struct net_device *dev) static void nv_link_irq(struct net_device *dev)
{ {
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev); u8 *base = get_hwbase(dev);
...@@ -1050,29 +1089,29 @@ static void link_irq(struct net_device *dev) ...@@ -1050,29 +1089,29 @@ static void link_irq(struct net_device *dev)
miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
if (miival & BMSR_ANEGCOMPLETE) { if (miival & BMSR_ANEGCOMPLETE) {
update_linkspeed(dev); nv_update_linkspeed(dev);
if (netif_carrier_ok(dev)) { if (netif_carrier_ok(dev)) {
stop_rx(dev); nv_stop_rx(dev);
} else { } else {
netif_carrier_on(dev); netif_carrier_on(dev);
printk(KERN_INFO "%s: link up.\n", dev->name); printk(KERN_INFO "%s: link up.\n", dev->name);
} }
writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
base + NvRegMisc1); base + NvRegMisc1);
start_rx(dev); nv_start_rx(dev);
} else { } else {
if (netif_carrier_ok(dev)) { if (netif_carrier_ok(dev)) {
netif_carrier_off(dev); netif_carrier_off(dev);
printk(KERN_INFO "%s: link down.\n", dev->name); printk(KERN_INFO "%s: link down.\n", dev->name);
stop_rx(dev); nv_stop_rx(dev);
} }
writel(np->linkspeed, base + NvRegLinkSpeed); writel(np->linkspeed, base + NvRegLinkSpeed);
pci_push(base); pci_push(base);
} }
} }
static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
{ {
struct net_device *dev = (struct net_device *) data; struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
...@@ -1080,7 +1119,7 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) ...@@ -1080,7 +1119,7 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs)
u32 events; u32 events;
int i; int i;
dprintk(KERN_DEBUG "%s: nic_irq\n", dev->name); dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name);
for (i=0; ; i++) { for (i=0; ; i++) {
events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
...@@ -1092,13 +1131,13 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) ...@@ -1092,13 +1131,13 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs)
if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
spin_lock(&np->lock); spin_lock(&np->lock);
tx_done(dev); nv_tx_done(dev);
spin_unlock(&np->lock); spin_unlock(&np->lock);
} }
if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
rx_process(dev); nv_rx_process(dev);
if (alloc_rx(dev)) { if (nv_alloc_rx(dev)) {
spin_lock(&np->lock); spin_lock(&np->lock);
if (!np->in_shutdown) if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL); mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
...@@ -1108,7 +1147,7 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) ...@@ -1108,7 +1147,7 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs)
if (events & NVREG_IRQ_LINK) { if (events & NVREG_IRQ_LINK) {
spin_lock(&np->lock); spin_lock(&np->lock);
link_irq(dev); nv_link_irq(dev);
spin_unlock(&np->lock); spin_unlock(&np->lock);
} }
if (events & (NVREG_IRQ_TX_ERR)) { if (events & (NVREG_IRQ_TX_ERR)) {
...@@ -1127,31 +1166,32 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) ...@@ -1127,31 +1166,32 @@ static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs)
if (!np->in_shutdown) if (!np->in_shutdown)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT); mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
printk(KERN_DEBUG "%s: too many iterations (%d) in nic_irq.\n", dev->name, i); printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
spin_unlock(&np->lock); spin_unlock(&np->lock);
break; break;
} }
} }
dprintk(KERN_DEBUG "%s: nic_irq completed\n", dev->name); dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
return IRQ_RETVAL(i); return IRQ_RETVAL(i);
} }
static void do_nic_poll(unsigned long data) static void nv_do_nic_poll(unsigned long data)
{ {
struct net_device *dev = (struct net_device *) data; struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = get_nvpriv(dev); struct fe_priv *np = get_nvpriv(dev);
u8 *base = get_hwbase(dev); u8 *base = get_hwbase(dev);
disable_irq(dev->irq); disable_irq(dev->irq);
/* FIXME: Do we need synchronize_irq(dev->irq) here? */
/* /*
* reenable interrupts on the nic, we have to do this before calling * reenable interrupts on the nic, we have to do this before calling
* nic_irq because that may decide to do otherwise * nv_nic_irq because that may decide to do otherwise
*/ */
writel(np->irqmask, base + NvRegIrqMask); writel(np->irqmask, base + NvRegIrqMask);
pci_push(base); pci_push(base);
nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
enable_irq(dev->irq); enable_irq(dev->irq);
} }
...@@ -1173,12 +1213,12 @@ static int nv_open(struct net_device *dev) ...@@ -1173,12 +1213,12 @@ static int nv_open(struct net_device *dev)
writel(0, base + NvRegAdapterControl); writel(0, base + NvRegAdapterControl);
writel(0, base + NvRegLinkSpeed); writel(0, base + NvRegLinkSpeed);
writel(0, base + NvRegUnknownTransmitterReg); writel(0, base + NvRegUnknownTransmitterReg);
txrx_reset(dev); nv_txrx_reset(dev);
writel(0, base + NvRegUnknownSetupReg6); writel(0, base + NvRegUnknownSetupReg6);
/* 2) initialize descriptor rings */ /* 2) initialize descriptor rings */
np->in_shutdown = 0; np->in_shutdown = 0;
oom = init_ring(dev); oom = nv_init_ring(dev);
/* 3) set mac address */ /* 3) set mac address */
{ {
...@@ -1224,7 +1264,7 @@ static int nv_open(struct net_device *dev) ...@@ -1224,7 +1264,7 @@ static int nv_open(struct net_device *dev)
np->phyaddr = i; np->phyaddr = i;
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
update_linkspeed(dev); nv_update_linkspeed(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
break; break;
...@@ -1279,7 +1319,7 @@ static int nv_open(struct net_device *dev) ...@@ -1279,7 +1319,7 @@ static int nv_open(struct net_device *dev)
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base); pci_push(base);
ret = request_irq(dev->irq, &nic_irq, SA_SHIRQ, dev->name, dev); ret = request_irq(dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev);
if (ret) if (ret)
goto out_drain; goto out_drain;
...@@ -1291,8 +1331,8 @@ static int nv_open(struct net_device *dev) ...@@ -1291,8 +1331,8 @@ static int nv_open(struct net_device *dev)
writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskA);
writel(0, base + NvRegMulticastMaskB); writel(0, base + NvRegMulticastMaskB);
writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
start_rx(dev); nv_start_rx(dev);
start_tx(dev); nv_start_tx(dev);
netif_start_queue(dev); netif_start_queue(dev);
if (oom) if (oom)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL); mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
...@@ -1326,8 +1366,8 @@ static int nv_close(struct net_device *dev) ...@@ -1326,8 +1366,8 @@ static int nv_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
stop_tx(dev); nv_stop_tx(dev);
stop_rx(dev); nv_stop_rx(dev);
base = get_hwbase(dev); base = get_hwbase(dev);
/* disable interrupts on the nic or we will lock up */ /* disable interrupts on the nic or we will lock up */
...@@ -1341,6 +1381,9 @@ static int nv_close(struct net_device *dev) ...@@ -1341,6 +1381,9 @@ static int nv_close(struct net_device *dev)
drain_ring(dev); drain_ring(dev);
if (np->wolenabled)
nv_start_rx(dev);
/* FIXME: power down nic */ /* FIXME: power down nic */
return 0; return 0;
...@@ -1367,10 +1410,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i ...@@ -1367,10 +1410,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
init_timer(&np->oom_kick); init_timer(&np->oom_kick);
np->oom_kick.data = (unsigned long) dev; np->oom_kick.data = (unsigned long) dev;
np->oom_kick.function = &do_rx_refill; /* timer handler */ np->oom_kick.function = &nv_do_rx_refill; /* timer handler */
init_timer(&np->nic_poll); init_timer(&np->nic_poll);
np->nic_poll.data = (unsigned long) dev; np->nic_poll.data = (unsigned long) dev;
np->nic_poll.function = &do_nic_poll; /* timer handler */ np->nic_poll.function = &nv_do_nic_poll; /* timer handler */
err = pci_enable_device(pci_dev); err = pci_enable_device(pci_dev);
if (err) { if (err) {
...@@ -1459,6 +1502,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i ...@@ -1459,6 +1502,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/* disable WOL */
writel(0, base + NvRegWakeUpFlags);
np->wolenabled = 0;
np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID); np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID);
if (id->driver_data & DEV_NEED_LASTPACKET1) if (id->driver_data & DEV_NEED_LASTPACKET1)
np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1); np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment