Written/copyright 1999-2001 by Donald Becker.
Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com)
Portions copyright 2001,2002 Manfred Spraul (manfred@colorfullife.com)
+ Portions copyright 2004 Harald Welte <laforge@gnumonks.org>
This software may be used and distributed according to the terms of
the GNU General Public License (GPL), incorporated herein by reference.
Support information and updates available at
http://www.scyld.com/network/netsemi.html
+ [link no longer provides useful info -jgarzik]
- Linux kernel modifications:
-
- Version 1.0.1:
- - Spinlock fixes
- - Bug fixes and better intr performance (Tjeerd)
- Version 1.0.2:
- - Now reads correct MAC address from eeprom
- Version 1.0.3:
- - Eliminate redundant priv->tx_full flag
- - Call netif_start_queue from dev->tx_timeout
- - wmb() in start_tx() to flush data
- - Update Tx locking
- - Clean up PCI enable (davej)
- Version 1.0.4:
- - Merge Donald Becker's natsemi.c version 1.07
- Version 1.0.5:
- - { fill me in }
- Version 1.0.6:
- * ethtool support (jgarzik)
- * Proper initialization of the card (which sometimes
- fails to occur and leaves the card in a non-functional
- state). (uzi)
-
- * Some documented register settings to optimize some
- of the 100Mbit autodetection circuitry in rev C cards. (uzi)
-
- * Polling of the PHY intr for stuff like link state
- change and auto- negotiation to finally work properly. (uzi)
-
- * One-liner removal of a duplicate declaration of
- netdev_error(). (uzi)
-
- Version 1.0.7: (Manfred Spraul)
- * pci dma
- * SMP locking update
- * full reset added into tx_timeout
- * correct multicast hash generation (both big and little endian)
- [copied from a natsemi driver version
- from Myrio Corporation, Greg Smith]
- * suspend/resume
-
- version 1.0.8 (Tim Hockin <thockin@sun.com>)
- * ETHTOOL_* support
- * Wake on lan support (Erik Gilling)
- * MXDMA fixes for serverworks
- * EEPROM reload
-
- version 1.0.9 (Manfred Spraul)
- * Main change: fix lack of synchronize
- netif_close/netif_suspend against a last interrupt
- or packet.
- * do not enable superflous interrupts (e.g. the
- drivers relies on TxDone - TxIntr not needed)
- * wait that the hardware has really stopped in close
- and suspend.
- * workaround for the (at least) gcc-2.95.1 compiler
- problem. Also simplifies the code a bit.
- * disable_irq() in tx_timeout - needed to protect
- against rx interrupts.
- * stop the nic before switching into silent rx mode
- for wol (required according to docu).
-
- version 1.0.10:
- * use long for ee_addr (various)
- * print pointers properly (DaveM)
- * include asm/irq.h (?)
-
- version 1.0.11:
- * check and reset if PHY errors appear (Adrian Sun)
- * WoL cleanup (Tim Hockin)
- * Magic number cleanup (Tim Hockin)
- * Don't reload EEPROM on every reset (Tim Hockin)
- * Save and restore EEPROM state across reset (Tim Hockin)
- * MDIO Cleanup (Tim Hockin)
- * Reformat register offsets/bits (jgarzik)
-
- version 1.0.12:
- * ETHTOOL_* further support (Tim Hockin)
-
- version 1.0.13:
- * ETHTOOL_[G]EEPROM support (Tim Hockin)
-
- version 1.0.13:
- * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
-
- version 1.0.14:
- * Cleanup some messages and autoneg in ethtool (Tim Hockin)
-
- version 1.0.15:
- * Get rid of cable_magic flag
- * use new (National provided) solution for cable magic issue
-
- version 1.0.16:
- * call netdev_rx() for RxErrors (Manfred Spraul)
- * formatting and cleanups
- * change options and full_duplex arrays to be zero
- initialized
- * enable only the WoL and PHY interrupts in wol mode
-
- version 1.0.17:
- * only do cable_magic on 83815 and early 83816 (Tim Hockin)
- * create a function for rx refill (Manfred Spraul)
- * combine drain_ring and init_ring (Manfred Spraul)
- * oom handling (Manfred Spraul)
- * hands_off instead of playing with netif_device_{de,a}ttach
- (Manfred Spraul)
- * be sure to write the MAC back to the chip (Manfred Spraul)
- * lengthen EEPROM timeout, and always warn about timeouts
- (Manfred Spraul)
- * comments update (Manfred)
- * do the right thing on a phy-reset (Manfred and Tim)
-
TODO:
* big endian support with CFG:BEM instead of cpu_to_le32
- * support for an external PHY
- * NAPI
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mii.h>
#include <linux/crc32.h>
#include <linux/bitops.h>
+#include <linux/prefetch.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#define DRV_NAME "natsemi"
-#define DRV_VERSION "1.07+LK1.0.17"
-#define DRV_RELDATE "Sep 27, 2002"
+#define DRV_VERSION "2.1"
+#define DRV_RELDATE "Sept 11, 2006"
#define RX_OFFSET 2
NETIF_MSG_TX_ERR)
static int debug = -1;
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
static int mtu;
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
This chip uses a 512 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 100;
+static const int multicast_filter_limit = 100;
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1518 effectively disables this feature. */
NATSEMI_PG1_NREGS)
#define NATSEMI_REGS_VER 1 /* v1 added RFDR registers */
#define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32))
-#define NATSEMI_EEPROM_SIZE 24 /* 12 16-bit values */
/* Buffer sizes:
* The nic writes 32-bit values, even if the upper bytes of
#define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */
/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static const char version[] __devinitdata =
KERN_INFO DRV_NAME " dp8381x driver, version "
DRV_VERSION ", " DRV_RELDATE "\n"
KERN_INFO " originally by Donald Becker <becker@scyld.com>\n"
MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver");
MODULE_LICENSE("GPL");
-module_param(max_interrupt_work, int, 0);
module_param(mtu, int, 0);
module_param(debug, int, 0);
module_param(rx_copybreak, int, 0);
module_param_array(options, int, NULL, 0);
module_param_array(full_duplex, int, NULL, 0);
-MODULE_PARM_DESC(max_interrupt_work,
- "DP8381x maximum events handled per interrupt");
MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
MODULE_PARM_DESC(debug, "DP8381x default debug level");
-MODULE_PARM_DESC(rx_copybreak,
+MODULE_PARM_DESC(rx_copybreak,
"DP8381x copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options,
+MODULE_PARM_DESC(options,
"DP8381x: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
The rx process only runs in the interrupt handler. Access from outside
the interrupt handler is only permitted after disable_irq().
-The rx process usually runs under the dev->xmit_lock. If np->intr_tx_reap
+The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
is set, then access is permitted under spin_lock_irq(&np->lock).
Thus configuration functions that want to access everything must call
disable_irq(dev->irq);
- spin_lock_bh(dev->xmit_lock);
+ netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
IV. Notes
-enum pcistuff {
- PCI_USES_IO = 0x01,
- PCI_USES_MEM = 0x02,
- PCI_USES_MASTER = 0x04,
- PCI_ADDR0 = 0x08,
- PCI_ADDR1 = 0x10,
-};
-
-/* MMIO operations required */
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-
-
/*
* Support for fibre connections on Am79C874:
* This phy needs a special setup when connected to a fibre cable.
*/
#define PHYID_AM79C874 0x0022561b
-#define MII_MCTRL 0x15 /* mode control register */
-#define MII_FX_SEL 0x0001 /* 100BASE-FX (fiber) */
-#define MII_EN_SCRM 0x0004 /* enable scrambler (tp) */
+enum {
+ MII_MCTRL = 0x15, /* mode control register */
+ MII_FX_SEL = 0x0001, /* 100BASE-FX (fiber) */
+ MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */
+};
+
-
/* array of board data directly indexed by pci_tbl[x].driver_data */
-static struct {
+static const struct {
const char *name;
unsigned long flags;
+ unsigned int eeprom_size;
} natsemi_pci_info[] __devinitdata = {
- { "NatSemi DP8381[56]", PCI_IOTYPE },
+ { "NatSemi DP8381[56]", 0, 24 },
};
-static struct pci_device_id natsemi_pci_tbl[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, },
+static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl);
TxCarrierIgn = 0x80000000
};
-/*
+/*
* Tx Configuration:
* - 256 byte DMA burst length
* - fill threshold 512 bytes (i.e. restart DMA when 512 bytes are free)
/* Based on MTU+slack. */
unsigned int rx_buf_sz;
int oom;
+ /* Interrupt status */
+ u32 intr_status;
/* Do not touch the nic registers */
int hands_off;
/* external phy that is used: only valid if dev->if_port != PORT_TP */
unsigned int iosize;
spinlock_t lock;
u32 msg_enable;
+ /* EEPROM data */
+ int eeprom_size;
};
static void move_int_phy(struct net_device *dev, int addr);
static void reinit_ring(struct net_device *dev);
static void init_registers(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
static void netdev_error(struct net_device *dev, int intr_status);
-static void netdev_rx(struct net_device *dev);
+static int natsemi_poll(struct net_device *dev, int *budget);
+static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
static void netdev_tx_done(struct net_device *dev);
static int natsemi_change_mtu(struct net_device *dev, int new_mtu);
#ifdef CONFIG_NET_POLL_CONTROLLER
static int netdev_close(struct net_device *dev);
static int netdev_get_regs(struct net_device *dev, u8 *buf);
static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
static inline void __iomem *ns_ioaddr(struct net_device *dev)
{
return (void __iomem *) dev->base_addr;
}
+static inline void natsemi_irq_enable(struct net_device *dev)
+{
+ writel(1, ns_ioaddr(dev) + IntrEnable);
+ readl(ns_ioaddr(dev) + IntrEnable);
+}
+
+static inline void natsemi_irq_disable(struct net_device *dev)
+{
+ writel(0, ns_ioaddr(dev) + IntrEnable);
+ readl(ns_ioaddr(dev) + IntrEnable);
+}
+
static void move_int_phy(struct net_device *dev, int addr)
{
struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = ns_ioaddr(dev);
int target = 31;
- /*
+ /*
* The internal phy is visible on the external mii bus. Therefore we must
* move it away before we can send commands to an external phy.
* There are two addresses we must avoid:
udelay(1);
}
+static void __devinit natsemi_init_media (struct net_device *dev)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ u32 tmp;
+
+ netif_carrier_off(dev);
+
+ /* get the initial settings from hardware */
+ tmp = mdio_read(dev, MII_BMCR);
+ np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10;
+ np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF;
+ np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
+ np->advertising= mdio_read(dev, MII_ADVERTISE);
+
+ if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
+ && netif_msg_probe(np)) {
+ printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
+ "10%s %s duplex.\n",
+ pci_name(np->pci_dev),
+ (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
+ "enabled, advertise" : "disabled, force",
+ (np->advertising &
+ (ADVERTISE_100FULL|ADVERTISE_100HALF))?
+ "0" : "",
+ (np->advertising &
+ (ADVERTISE_100FULL|ADVERTISE_10FULL))?
+ "full" : "half");
+ }
+ if (netif_msg_probe(np))
+ printk(KERN_INFO
+ "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
+ pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
+ np->advertising);
+
+}
+
static int __devinit natsemi_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
iosize = pci_resource_len(pdev, pcibar);
irq = pdev->irq;
- if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER)
- pci_set_master(pdev);
+ pci_set_master(pdev);
dev = alloc_etherdev(sizeof (struct netdev_private));
if (!dev)
spin_lock_init(&np->lock);
np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
np->hands_off = 0;
+ np->intr_status = 0;
+ np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size;
/* Initial port:
* - If the nic was configured to use an external phy and if find_mii
dev->do_ioctl = &netdev_ioctl;
dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ dev->poll = natsemi_poll;
+ dev->weight = 64;
+
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = &natsemi_poll_controller;
#endif
if (mtu)
dev->mtu = mtu;
- netif_carrier_off(dev);
-
- /* get the initial settings from hardware */
- tmp = mdio_read(dev, MII_BMCR);
- np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10;
- np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF;
- np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
- np->advertising= mdio_read(dev, MII_ADVERTISE);
-
- if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
- && netif_msg_probe(np)) {
- printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
- "10%s %s duplex.\n",
- pci_name(np->pci_dev),
- (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
- "enabled, advertise" : "disabled, force",
- (np->advertising &
- (ADVERTISE_100FULL|ADVERTISE_100HALF))?
- "0" : "",
- (np->advertising &
- (ADVERTISE_100FULL|ADVERTISE_10FULL))?
- "full" : "half");
- }
- if (netif_msg_probe(np))
- printk(KERN_INFO
- "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
- pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
- np->advertising);
+ natsemi_init_media(dev);
/* save the silicon revision for later querying */
np->srr = readl(ioaddr + SiliconRev);
tmp |= BMCR_SPEED100;
if (np->duplex == DUPLEX_FULL)
tmp |= BMCR_FULLDPLX;
- /*
+ /*
* Note: there is no good way to inform the link partner
* that our capabilities changed. The user has to unplug
* and replug the network cable after some changes, e.g.
writel(cfg, ioaddr + ChipConfig);
readl(ioaddr + ChipConfig);
udelay(1);
-
+
/* 2) reset the internal phy: */
bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2));
writel(bmcr | BMCR_RESET, ioaddr+BasicControl+(MII_BMCR<<2));
/* Switch to external phy */
did_switch = switch_port_external(dev);
-
+
/* Scan the possible phy addresses:
*
* PHY address 0 means that the phy is in isolate mode. Not yet
writel(rfcr, ioaddr + RxFilterAddr);
}
+static void reset_rx(struct net_device *dev)
+{
+ int i;
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = ns_ioaddr(dev);
+
+ np->intr_status &= ~RxResetDone;
+
+ writel(RxReset, ioaddr + ChipCmd);
+
+ for (i=0;i<NATSEMI_HW_TIMEOUT;i++) {
+ np->intr_status |= readl(ioaddr + IntrStatus);
+ if (np->intr_status & RxResetDone)
+ break;
+ udelay(15);
+ }
+ if (i==NATSEMI_HW_TIMEOUT) {
+ printk(KERN_WARNING "%s: RX reset did not complete in %d usec.\n",
+ dev->name, i*15);
+ } else if (netif_msg_hw(np)) {
+ printk(KERN_WARNING "%s: RX reset took %d usec.\n",
+ dev->name, i*15);
+ }
+}
+
static void natsemi_reload_eeprom(struct net_device *dev)
{
struct netdev_private *np = netdev_priv(dev);
/* Reset the chip, just in case. */
natsemi_reset(dev);
- i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+ i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev);
if (i) return i;
if (netif_msg_ifup(np))
void __iomem * ioaddr = ns_ioaddr(dev);
int duplex;
u16 bmsr;
-
+
/* The link status field is latched: it remains low after a temporary
* link failure until it's read. We need the current link status,
* thus read twice.
}
}
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+/* The interrupt handler doesn't actually handle interrupts itself, it
+ * schedules a NAPI poll if there is anything to do. */
+static irqreturn_t intr_handler(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct netdev_private *np = netdev_priv(dev);
void __iomem * ioaddr = ns_ioaddr(dev);
- int boguscnt = max_interrupt_work;
- unsigned int handled = 0;
if (np->hands_off)
return IRQ_NONE;
- do {
- /* Reading automatically acknowledges all int sources. */
- u32 intr_status = readl(ioaddr + IntrStatus);
- if (netif_msg_intr(np))
- printk(KERN_DEBUG
- "%s: Interrupt, status %#08x, mask %#08x.\n",
- dev->name, intr_status,
- readl(ioaddr + IntrMask));
+ /* Reading automatically acknowledges. */
+ np->intr_status = readl(ioaddr + IntrStatus);
- if (intr_status == 0)
- break;
- handled = 1;
+ if (netif_msg_intr(np))
+ printk(KERN_DEBUG
+ "%s: Interrupt, status %#08x, mask %#08x.\n",
+ dev->name, np->intr_status,
+ readl(ioaddr + IntrMask));
- if (intr_status &
- (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
- IntrRxErr | IntrRxOverrun)) {
- netdev_rx(dev);
- }
+ if (!np->intr_status)
+ return IRQ_NONE;
- if (intr_status &
- (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
+ prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
+
+ if (netif_rx_schedule_prep(dev)) {
+ /* Disable interrupts and register for poll */
+ natsemi_irq_disable(dev);
+ __netif_rx_schedule(dev);
+ }
+ return IRQ_HANDLED;
+}
+
+/* This is the NAPI poll routine. As well as the standard RX handling
+ * it also handles all other interrupts that the chip might raise.
+ */
+static int natsemi_poll(struct net_device *dev, int *budget)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem * ioaddr = ns_ioaddr(dev);
+
+ int work_to_do = min(*budget, dev->quota);
+ int work_done = 0;
+
+ do {
+ if (np->intr_status &
+ (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
spin_lock(&np->lock);
netdev_tx_done(dev);
spin_unlock(&np->lock);
}
/* Abnormal error summary/uncommon events handlers. */
- if (intr_status & IntrAbnormalSummary)
- netdev_error(dev, intr_status);
-
- if (--boguscnt < 0) {
- if (netif_msg_intr(np))
- printk(KERN_WARNING
- "%s: Too much work at interrupt, "
- "status=%#08x.\n",
- dev->name, intr_status);
- break;
+ if (np->intr_status & IntrAbnormalSummary)
+ netdev_error(dev, np->intr_status);
+
+ if (np->intr_status &
+ (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
+ IntrRxErr | IntrRxOverrun)) {
+ netdev_rx(dev, &work_done, work_to_do);
}
- } while (1);
- if (netif_msg_intr(np))
- printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name);
+ *budget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done >= work_to_do)
+ return 1;
+
+ np->intr_status = readl(ioaddr + IntrStatus);
+ } while (np->intr_status);
+
+ netif_rx_complete(dev);
+
+ /* Reenable interrupts providing nothing is trying to shut
+ * the chip down. */
+ spin_lock(&np->lock);
+ if (!np->hands_off && netif_running(dev))
+ natsemi_irq_enable(dev);
+ spin_unlock(&np->lock);
- return IRQ_RETVAL(handled);
+ return 0;
}
/* This routine is logically part of the interrupt handler, but separated
for clarity and better register allocation. */
-static void netdev_rx(struct net_device *dev)
+static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
{
struct netdev_private *np = netdev_priv(dev);
int entry = np->cur_rx % RX_RING_SIZE;
entry, desc_status);
if (--boguscnt < 0)
break;
+
+ if (*work_done >= work_to_do)
+ break;
+
+ (*work_done)++;
+
pkt_len = (desc_status & DescSizeMask) - 4;
if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
if (desc_status & DescMore) {
"status %#08x.\n", dev->name,
np->cur_rx, desc_status);
np->stats.rx_length_errors++;
+
+ /* The RX state machine has probably
+ * locked up beneath us. Follow the
+ * reset procedure documented in
+ * AN-1287. */
+
+ spin_lock_irq(&np->lock);
+ reset_rx(dev);
+ reinit_rx(dev);
+ writel(np->ring_dma, ioaddr + RxRingPtr);
+ check_link(dev);
+ spin_unlock_irq(&np->lock);
+
+ /* We'll enable RX on exit from this
+ * function. */
+ break;
+
} else {
/* There was an error. */
np->stats.rx_errors++;
np->rx_skbuff[entry] = NULL;
}
skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
+ netif_receive_skb(skb);
dev->last_rx = jiffies;
np->stats.rx_packets++;
np->stats.rx_bytes += pkt_len;
static void natsemi_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- intr_handler(dev->irq, dev, NULL);
+ intr_handler(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
u32 rx_mode;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
} else if ((dev->mc_count > multicast_filter_limit)
static int get_eeprom_len(struct net_device *dev)
{
- return NATSEMI_EEPROM_SIZE;
+ struct netdev_private *np = netdev_priv(dev);
+ return np->eeprom_size;
}
static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
{
struct netdev_private *np = netdev_priv(dev);
- u8 eebuf[NATSEMI_EEPROM_SIZE];
+ u8 *eebuf;
int res;
+ eebuf = kmalloc(np->eeprom_size, GFP_KERNEL);
+ if (!eebuf)
+ return -ENOMEM;
+
eeprom->magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16);
spin_lock_irq(&np->lock);
res = netdev_get_eeprom(dev, eebuf);
spin_unlock_irq(&np->lock);
if (!res)
memcpy(data, eebuf+eeprom->offset, eeprom->len);
+ kfree(eebuf);
return res;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = get_drvinfo,
.get_regs_len = get_regs_len,
.get_eeprom_len = get_eeprom_len,
* phy, even if the internal phy is used. This is necessary
* to work around a deficiency of the ethtool interface:
* It's only possible to query the settings of the active
- * port. Therefore
+ * port. Therefore
* # ethtool -s ethX port mii
* actually sends an ioctl to switch to port mii with the
* settings that are used for the current active port.
int i;
u16 *ebuf = (u16 *)buf;
void __iomem * ioaddr = ns_ioaddr(dev);
+ struct netdev_private *np = netdev_priv(dev);
/* eeprom_read reads 16 bits, and indexes by 16 bits */
- for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) {
+ for (i = 0; i < np->eeprom_size/2; i++) {
ebuf[i] = eeprom_read(ioaddr, i);
/* The EEPROM itself stores data bit-swapped, but eeprom_read
* reads it back "sanely". So we swap it back here in order to
del_timer_sync(&np->timer);
disable_irq(dev->irq);
spin_lock_irq(&np->lock);
- /* Disable interrupts, and flush posted writes */
- writel(0, ioaddr + IntrEnable);
- readl(ioaddr + IntrEnable);
+ natsemi_irq_disable(dev);
np->hands_off = 1;
spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
* * netdev_timer: timer stopped by natsemi_suspend.
* * intr_handler: doesn't acquire the spinlock. suspend calls
* disable_irq() to enforce synchronization.
+ * * natsemi_poll: checks before reenabling interrupts. suspend
+ * sets hands_off, disables interrupts and then waits with
+ * netif_poll_disable().
*
* Interrupts must be disabled, otherwise hands_off can cause irq storms.
*/
spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
+ netif_poll_disable(dev);
+
/* Update the error counts. */
__get_stats(dev);
mod_timer(&np->timer, jiffies + 1*HZ);
}
netif_device_attach(dev);
+ netif_poll_enable(dev);
out:
rtnl_unlock();
return 0;
printk(version);
#endif
- return pci_module_init (&natsemi_driver);
+ return pci_register_driver(&natsemi_driver);
}
static void __exit natsemi_exit_mod (void)