patch-2.4.25 linux-2.4.25/drivers/net/sgiseeq.c
Next file: linux-2.4.25/drivers/net/sk98lin/Makefile
Previous file: linux-2.4.25/drivers/net/sb1250-mac.c
Back to the patch index
Back to the overall index
- Lines: 656
- Date:
2004-02-18 05:36:31.000000000 -0800
- Orig file:
linux-2.4.24/drivers/net/sgiseeq.c
- Orig date:
2003-06-13 07:51:35.000000000 -0700
diff -urN linux-2.4.24/drivers/net/sgiseeq.c linux-2.4.25/drivers/net/sgiseeq.c
@@ -5,51 +5,45 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/types.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
+#include <linux/socket.h>
#include <linux/in.h>
+#include <linux/route.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <asm/byteorder.h>
#include <asm/io.h>
-#include <asm/segment.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <linux/errno.h>
-#include <asm/byteorder.h>
-
-#include <linux/socket.h>
-#include <linux/route.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/sgi/sgihpc.h>
-#include <asm/sgi/sgint23.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ip22.h>
#include <asm/sgialib.h>
#include "sgiseeq.h"
-static char *version =
- "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n";
+static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n";
static char *sgiseeqstr = "SGI Seeq8003";
-/* If you want speed, you do something silly, it always has worked
- * for me. So, with that in mind, I've decided to make this driver
- * look completely like a stupid Lance from a driver architecture
- * perspective. Only difference is that here our "ring buffer" looks
- * and acts like a real Lance one does but is layed out like how the
- * HPC DMA and the Seeq want it to. You'd be surprised how a stupid
- * idea like this can pay off in performance, not to mention making
- * this driver 2,000 times easier to write. ;-)
+/*
+ * If you want speed, you do something silly, it always has worked for me. So,
+ * with that in mind, I've decided to make this driver look completely like a
+ * stupid Lance from a driver architecture perspective. Only difference is that
+ * here our "ring buffer" looks and acts like a real Lance one does but is
+ * layed out like how the HPC DMA and the Seeq want it to. You'd be surprised
+ * how a stupid idea like this can pay off in performance, not to mention
+ * making this driver 2,000 times easier to write. ;-)
*/
/* Tune these if we tend to run out often etc. */
@@ -79,9 +73,10 @@
signed int buf_vaddr;
};
-/* Warning: This structure is layed out in a certain way because
- * HPC dma descriptors must be 8-byte aligned. So don't
- * touch this without some care.
+/*
+ * Warning: This structure is layed out in a certain way because HPC dma
+ * descriptors must be 8-byte aligned. So don't touch this without
+ * some care.
*/
struct sgiseeq_init_block { /* Note the name ;-) */
/* Ptrs to the descriptors in KSEG1 uncached space. */
@@ -96,8 +91,8 @@
struct sgiseeq_private {
volatile struct sgiseeq_init_block srings;
char *name;
- volatile struct hpc3_ethregs *hregs;
- volatile struct sgiseeq_regs *sregs;
+ struct hpc3_ethregs *hregs;
+ struct sgiseeq_regs *sregs;
/* Ring entry counters. */
unsigned int rx_new, tx_new;
@@ -108,17 +103,23 @@
unsigned char mode;
struct net_device_stats stats;
+
+ struct net_device *next_module;
+ spinlock_t tx_lock;
};
-static inline void hpc3_eth_reset(volatile struct hpc3_ethregs *hregs)
+/* A list of all installed seeq devices, for removing the driver module. */
+static struct net_device *root_sgiseeq_dev;
+
+static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
{
- hregs->rx_reset = (HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ);
+ hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ;
udelay(20);
hregs->rx_reset = 0;
}
-static inline void reset_hpc3_and_seeq(volatile struct hpc3_ethregs *hregs,
- volatile struct sgiseeq_regs *sregs)
+static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs,
+ struct sgiseeq_regs *sregs)
{
hregs->rx_ctrl = hregs->tx_ctrl = 0;
hpc3_eth_reset(hregs);
@@ -128,15 +129,15 @@
SEEQ_RCMD_IDRIB | SEEQ_RCMD_ICRC)
static inline void seeq_go(struct sgiseeq_private *sp,
- volatile struct hpc3_ethregs *hregs,
- volatile struct sgiseeq_regs *sregs)
+ struct hpc3_ethregs *hregs,
+ struct sgiseeq_regs *sregs)
{
sregs->rstat = sp->mode | RSTAT_GO_BITS;
hregs->rx_ctrl = HPC3_ERXCTRL_ACTIVE;
}
static inline void seeq_load_eaddr(struct net_device *dev,
- volatile struct sgiseeq_regs *sregs)
+ struct sgiseeq_regs *sregs)
{
int i;
@@ -169,7 +170,7 @@
/* Setup tx ring. */
for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
- if(!ib->tx_desc[i].tdma.pbuf) {
+ if (!ib->tx_desc[i].tdma.pbuf) {
unsigned long buffer;
buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
@@ -177,9 +178,8 @@
return -ENOMEM;
ib->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
ib->tx_desc[i].tdma.pbuf = PHYSADDR(buffer);
-// flush_cache_all();
}
- ib->tx_desc[i].tdma.cntinfo = (TCNTINFO_INIT);
+ ib->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT;
}
/* And now the rx ring. */
@@ -192,11 +192,10 @@
return -ENOMEM;
ib->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
ib->rx_desc[i].rdma.pbuf = PHYSADDR(buffer);
-// flush_cache_all();
}
- ib->rx_desc[i].rdma.cntinfo = (RCNTINFO_INIT);
+ ib->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT;
}
- ib->rx_desc[i - 1].rdma.cntinfo |= (HPCDMA_EOR);
+ ib->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR;
return 0;
}
@@ -209,10 +208,10 @@
static int once;
struct sgiseeq_rx_desc *r = gpriv->srings.rx_desc;
struct sgiseeq_tx_desc *t = gpriv->srings.tx_desc;
- volatile struct hpc3_ethregs *hregs = gpriv->hregs;
+ struct hpc3_ethregs *hregs = gpriv->hregs;
int i;
- if(once)
+ if (once)
return;
once++;
printk("RING DUMP:\n");
@@ -248,9 +247,9 @@
#define RDMACFG_INIT (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ)
static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
- volatile struct sgiseeq_regs *sregs)
+ struct sgiseeq_regs *sregs)
{
- volatile struct hpc3_ethregs *hregs = sp->hregs;
+ struct hpc3_ethregs *hregs = sp->hregs;
int err;
reset_hpc3_and_seeq(hregs, sregs);
@@ -260,11 +259,11 @@
/* Setup to field the proper interrupt types. */
if (sp->is_edlc) {
- sregs->tstat = (TSTAT_INIT_EDLC);
+ sregs->tstat = TSTAT_INIT_EDLC;
sregs->rw.wregs.control = sp->control;
sregs->rw.wregs.frame_gap = 0;
} else {
- sregs->tstat = (TSTAT_INIT_SEEQ);
+ sregs->tstat = TSTAT_INIT_SEEQ;
}
hregs->rx_dconfig |= RDMACFG_INIT;
@@ -291,8 +290,8 @@
}
static inline void rx_maybe_restart(struct sgiseeq_private *sp,
- volatile struct hpc3_ethregs *hregs,
- volatile struct sgiseeq_regs *sregs)
+ struct hpc3_ethregs *hregs,
+ struct sgiseeq_regs *sregs)
{
if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) {
hregs->rx_ndptr = PHYSADDR(&sp->srings.rx_desc[sp->rx_new]);
@@ -305,8 +304,8 @@
(rd) = &(sp)->srings.rx_desc[(sp)->rx_new])
static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp,
- volatile struct hpc3_ethregs *hregs,
- volatile struct sgiseeq_regs *sregs)
+ struct hpc3_ethregs *hregs,
+ struct sgiseeq_regs *sregs)
{
struct sgiseeq_rx_desc *rd;
struct sk_buff *skb = 0;
@@ -317,7 +316,7 @@
/* Service every received packet. */
for_each_rx(rd, sp) {
- len = (PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3);
+ len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3;
pkt_pointer = (unsigned char *)(long)rd->buf_vaddr;
pkt_status = pkt_pointer[len + 2];
@@ -338,7 +337,7 @@
sp->stats.rx_packets++;
sp->stats.rx_bytes += len;
} else {
- printk ("%s: Memory squeeze, deferring packet.\n",
+ printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
dev->name);
sp->stats.rx_dropped++;
}
@@ -347,7 +346,7 @@
}
/* Return the entry to the ring pool. */
- rd->rdma.cntinfo = (RCNTINFO_INIT);
+ rd->rdma.cntinfo = RCNTINFO_INIT;
sp->rx_new = NEXT_RX(sp->rx_new);
}
sp->srings.rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR);
@@ -356,7 +355,7 @@
}
static inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp,
- volatile struct sgiseeq_regs *sregs)
+ struct sgiseeq_regs *sregs)
{
if (sp->is_edlc) {
sregs->rw.wregs.control = sp->control & ~(SEEQ_CTRL_XCNT);
@@ -365,7 +364,7 @@
}
static inline void kick_tx(struct sgiseeq_tx_desc *td,
- volatile struct hpc3_ethregs *hregs)
+ struct hpc3_ethregs *hregs)
{
/* If the HPC aint doin nothin, and there are more packets
* with ETXD cleared and XIU set we must make very certain
@@ -383,8 +382,8 @@
}
static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp,
- volatile struct hpc3_ethregs *hregs,
- volatile struct sgiseeq_regs *sregs)
+ struct hpc3_ethregs *hregs,
+ struct sgiseeq_regs *sregs)
{
struct sgiseeq_tx_desc *td;
unsigned long status = hregs->tx_ctrl;
@@ -409,7 +408,7 @@
if (!(td->tdma.cntinfo & (HPCDMA_XIU)))
break;
if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) {
- if(!(status & HPC3_ETXCTRL_ACTIVE)) {
+ if (!(status & HPC3_ETXCTRL_ACTIVE)) {
hregs->tx_ndptr = PHYSADDR(td);
hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
}
@@ -426,8 +425,10 @@
{
struct net_device *dev = (struct net_device *) dev_id;
struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
- volatile struct hpc3_ethregs *hregs = sp->hregs;
- volatile struct sgiseeq_regs *sregs = sp->sregs;
+ struct hpc3_ethregs *hregs = sp->hregs;
+ struct sgiseeq_regs *sregs = sp->sregs;
+
+ spin_lock(&sp->tx_lock);
/* Ack the IRQ and set software state. */
hregs->rx_reset = HPC3_ERXRST_CLRIRQ;
@@ -435,59 +436,47 @@
/* Always check for received packets. */
sgiseeq_rx(dev, sp, hregs, sregs);
- /* Only check for tx acks iff we have something queued. */
+ /* Only check for tx acks if we have something queued. */
if (sp->tx_old != sp->tx_new)
sgiseeq_tx(dev, sp, hregs, sregs);
if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) {
netif_wake_queue(dev);
}
+ spin_unlock(&sp->tx_lock);
}
static int sgiseeq_open(struct net_device *dev)
{
struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv;
- volatile struct sgiseeq_regs *sregs = sp->sregs;
- unsigned long flags;
- int err;
-
- __save_and_cli(flags);
+ struct sgiseeq_regs *sregs = sp->sregs;
- err = -EAGAIN;
- if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
- printk("Seeq8003: Can't get irq %d\n", dev->irq);
- goto out;
- }
- err = init_seeq(dev, sp, sregs);
+ int err = init_seeq(dev, sp, sregs);
if (err)
- goto out;
+ return err;
netif_start_queue(dev);
-out:
- __restore_flags(flags);
- return err;
+ return 0;
}
static int sgiseeq_close(struct net_device *dev)
{
struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
- volatile struct sgiseeq_regs *sregs = sp->sregs;
+ struct sgiseeq_regs *sregs = sp->sregs;
netif_stop_queue(dev);
/* Shutdown the Seeq. */
reset_hpc3_and_seeq(sp->hregs, sregs);
- free_irq(dev->irq, dev);
-
return 0;
}
static inline int sgiseeq_reset(struct net_device *dev)
{
struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
- volatile struct sgiseeq_regs *sregs = sp->sregs;
+ struct sgiseeq_regs *sregs = sp->sregs;
int err;
err = init_seeq(dev, sp, sregs);
@@ -509,12 +498,12 @@
static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
- volatile struct hpc3_ethregs *hregs = sp->hregs;
+ struct hpc3_ethregs *hregs = sp->hregs;
unsigned long flags;
struct sgiseeq_tx_desc *td;
int skblen, len, entry;
- save_and_cli(flags);
+ spin_lock_irqsave(&sp->tx_lock, flags);
/* Setup... */
skblen = skb->len;
@@ -530,22 +519,22 @@
* 2) Do no allow the HPC to look at a new descriptor until
* we have completely set up it's state. This means, do
* not clear HPCDMA_EOX in the current last descritptor
- * until the one we are adding looks consistant and could
+ * until the one we are adding looks consistent and could
* be processes right now.
* 3) The tx interrupt code must notice when we've added a new
* entry and the HPC got to the end of the chain before we
* added this new entry and restarted it.
*/
memcpy((char *)(long)td->buf_vaddr, skb->data, skblen);
- if(len != skblen)
+ if (len != skblen)
memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen);
td->tdma.cntinfo = (len & HPCDMA_BCNT) |
- (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX);
+ HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX;
if (sp->tx_old != sp->tx_new) {
struct sgiseeq_tx_desc *backend;
backend = &sp->srings.tx_desc[PREV_TX(sp->tx_new)];
- backend->tdma.cntinfo &= ~(HPCDMA_EOX);
+ backend->tdma.cntinfo &= ~HPCDMA_EOX;
}
sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */
@@ -558,14 +547,14 @@
if (!TX_BUFFS_AVAIL(sp))
netif_stop_queue(dev);
- restore_flags(flags);
+ spin_unlock_irqrestore(&sp->tx_lock, flags);
return 0;
}
static void timeout(struct net_device *dev)
{
- printk("%s: transmit timed out, resetting\n", dev->name);
+ printk(KERN_NOTICE "%s: transmit timed out, resetting\n", dev->name);
sgiseeq_reset(dev);
dev->trans_start = jiffies;
@@ -608,49 +597,56 @@
buf[i].rdma.pnext = PHYSADDR(&buf[0]);
}
-static char onboard_eth_addr[6];
-
#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))
-int sgiseeq_init(struct net_device *dev, struct sgiseeq_regs *sregs,
- struct hpc3_ethregs *hregs, int irq)
+int sgiseeq_init(struct hpc3_regs* regs, int irq)
{
- static unsigned version_printed;
- int i;
+ struct net_device *dev;
struct sgiseeq_private *sp;
+ int err, i;
- dev->priv = (struct sgiseeq_private *) get_free_page(GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
-
- if (!version_printed++)
- printk(version);
-
- printk("%s: SGI Seeq8003 ", dev->name);
+ dev = alloc_etherdev(0);
+ if (!dev) {
+ printk(KERN_ERR "Sgiseeq: Etherdev alloc failed, aborting.\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+ /* Make private data page aligned */
+ sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL);
+ if (!sp) {
+ printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
+ err = -ENOMEM;
+ goto err_out_free_dev;
+ }
+
+ if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
+ printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq);
+ err = -EAGAIN;
+ goto err_out_free_page;
+ }
+
+#define EADDR_NVOFS 250
+ for (i = 0; i < 3; i++) {
+ unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c",
- dev->dev_addr[i] = onboard_eth_addr[i],
- i == 5 ? ' ': ':');
-
- printk("\n");
+ dev->dev_addr[2 * i] = tmp >> 8;
+ dev->dev_addr[2 * i + 1] = tmp & 0xff;
+ }
- sp = (struct sgiseeq_private *) dev->priv;
#ifdef DEBUG
gpriv = sp;
gdev = dev;
#endif
- memset((char *)dev->priv, 0, sizeof(struct sgiseeq_private));
- sp->sregs = sregs;
- sp->hregs = hregs;
+ sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
+ sp->hregs = &hpc3c0->ethregs;
sp->name = sgiseeqstr;
sp->srings.rx_desc = (struct sgiseeq_rx_desc *)
- (KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0])));
+ KSEG1ADDR(ALIGNED(&sp->srings.rxvector[0]));
dma_cache_wback_inv((unsigned long)&sp->srings.rxvector,
sizeof(sp->srings.rxvector));
sp->srings.tx_desc = (struct sgiseeq_tx_desc *)
- (KSEG1ADDR(ALIGNED(&sp->srings.txvector[0])));
+ KSEG1ADDR(ALIGNED(&sp->srings.txvector[0]));
dma_cache_wback_inv((unsigned long)&sp->srings.txvector,
sizeof(sp->srings.txvector));
@@ -659,71 +655,78 @@
setup_tx_ring(sp->srings.tx_desc, SEEQ_TX_BUFFERS);
/* Reset the chip. */
- hpc3_eth_reset((volatile struct hpc3_ethregs *) hregs);
+ hpc3_eth_reset(sp->hregs);
- sp->is_edlc = !(sregs->rw.rregs.collision_tx[0] & 0xff);
- if (sp->is_edlc) {
- sp->control = (SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT |
- SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT |
- SEEQ_CTRL_ENCARR);
+ sp->is_edlc = !(sp->sregs->rw.rregs.collision_tx[0] & 0xff);
+ if (sp->is_edlc)
+ sp->control = SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT |
+ SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT |
+ SEEQ_CTRL_ENCARR;
+
+ dev->open = sgiseeq_open;
+ dev->stop = sgiseeq_close;
+ dev->hard_start_xmit = sgiseeq_start_xmit;
+ dev->tx_timeout = timeout;
+ dev->watchdog_timeo = (200 * HZ) / 1000;
+ dev->get_stats = sgiseeq_get_stats;
+ dev->set_multicast_list = sgiseeq_set_multicast;
+ dev->irq = irq;
+ dev->dma = 0;
+ dev->priv = sp;
+
+ if (register_netdev(dev)) {
+ printk(KERN_ERR "Sgiseeq: Cannot register net device, "
+ "aborting.\n");
+ err = -ENODEV;
+ goto err_out_free_irq;
}
- dev->open = sgiseeq_open;
- dev->stop = sgiseeq_close;
- dev->hard_start_xmit = sgiseeq_start_xmit;
- dev->tx_timeout = timeout;
- dev->watchdog_timeo = (200 * HZ) / 1000;
- dev->get_stats = sgiseeq_get_stats;
- dev->set_multicast_list = sgiseeq_set_multicast;
- dev->irq = irq;
- dev->dma = 0;
- ether_setup(dev);
+ printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name);
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+ sp->next_module = root_sgiseeq_dev;
+ root_sgiseeq_dev = dev;
return 0;
-}
-static inline unsigned char str2hexnum(unsigned char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- return 0; /* foo */
+err_out_free_irq:
+ free_irq(irq, dev);
+err_out_free_page:
+ free_page((unsigned long) sp);
+err_out_free_dev:
+ kfree(dev);
+
+err_out:
+ return err;
}
-static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+static int __init sgiseeq_probe(void)
{
- int i;
-
- for (i = 0; i < 6; i++) {
- unsigned char num;
+ printk(version);
- if(*str == ':')
- str++;
- num = str2hexnum(*str++) << 4;
- num |= (str2hexnum(*str++));
- ea[i] = num;
- }
+ /* On board adapter on 1st HPC is always present */
+ return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
}
-int sgiseeq_probe(struct net_device *dev)
+static void __exit sgiseeq_exit(void)
{
- static int initialized;
- char *ep;
-
- if (initialized) /* Already initialized? */
- return 1;
- initialized++;
+ struct net_device *next, *dev;
+ struct sgiseeq_private *sp;
+ int irq;
- /* First get the ethernet address of the onboard interface from ARCS.
- * This is fragile; PROM doesn't like running from cache.
- * On MIPS64 it crashes for some other, yet unknown reason ...
- */
- ep = ArcGetEnvironmentVariable("eaddr");
- str2eaddr(onboard_eth_addr, ep);
- return sgiseeq_init(dev,
- (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)),
- &hpc3c0->ethregs, SGI_ENET_IRQ);
+ for (dev = root_sgiseeq_dev; dev; dev = next) {
+ sp = (struct sgiseeq_private *) dev->priv;
+ next = sp->next_module;
+ irq = dev->irq;
+ unregister_netdev(dev);
+ free_irq(irq, dev);
+ free_page((unsigned long) dev->priv);
+ kfree(dev);
+ }
}
+module_init(sgiseeq_probe);
+module_exit(sgiseeq_exit);
+
MODULE_LICENSE("GPL");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)