Subject: [PATCH] SGI Seeq cleanup

From: Ladislav Michl <[email-masked]>
Date: Wed, 7 May 2003 22:28:51 +0200

read eaddr using NVRAM access fuctions and make various cleanups so driver
can be build as module

diff -Naur linux_2_4/drivers/net/Config.in linux_2_4-fucked/drivers/net/Config.in
--- linux_2_4/drivers/net/Config.in	Wed Apr 16 09:11:57 2003
+++ linux_2_4-fucked/drivers/net/Config.in	Wed May  7 19:55:30 2003
@@ -217,7 +217,7 @@
       dep_tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620 $CONFIG_ISA
    fi
    if [ "$CONFIG_SGI_IP22" = "y" ]; then
-      bool '  SGI Seeq ethernet controller support' CONFIG_SGISEEQ
+      tristate '  SGI Seeq ethernet controller support' CONFIG_SGISEEQ
    fi
    if [ "$CONFIG_DECSTATION" = "y" ]; then
       tristate '  DEC LANCE ethernet controller support' CONFIG_DECLANCE
diff -Naur linux_2_4/drivers/net/Space.c linux_2_4-fucked/drivers/net/Space.c
--- linux_2_4/drivers/net/Space.c	Thu Aug  1 21:51:01 2002
+++ linux_2_4-fucked/drivers/net/Space.c	Wed May  7 19:55:30 2003
@@ -83,7 +83,6 @@
 extern int SK_init(struct net_device *);
 extern int seeq8005_probe(struct net_device *);
 extern int smc_init( struct net_device * );
-extern int sgiseeq_probe(struct net_device *);
 extern int atarilance_probe(struct net_device *);
 extern int sun3lance_probe(struct net_device *);
 extern int sun3_82586_probe(struct net_device *);
@@ -366,14 +365,6 @@
 	{NULL, 0},
 };
 
-
-static struct devprobe sgi_probes[] __initdata = {
-#ifdef CONFIG_SGISEEQ
-	{sgiseeq_probe, 0},
-#endif
-	{NULL, 0},
-};
-
 static struct devprobe mips_probes[] __initdata = {
 #ifdef CONFIG_MIPS_JAZZ_SONIC
 	{sonic_probe, 0},
@@ -407,8 +398,6 @@
 	if (probe_list(dev, m68k_probes) == 0)
 		return 0;
 	if (probe_list(dev, mips_probes) == 0)
-		return 0;
-	if (probe_list(dev, sgi_probes) == 0)
 		return 0;
 	if (probe_list(dev, eisa_probes) == 0)
 		return 0;
diff -Naur linux_2_4/drivers/net/sgiseeq.c linux_2_4-fucked/drivers/net/sgiseeq.c
--- linux_2_4/drivers/net/sgiseeq.c	Wed Mar 19 18:33:03 2003
+++ linux_2_4-fucked/drivers/net/sgiseeq.c	Wed May  7 19:55:30 2003
@@ -5,6 +5,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
@@ -96,8 +97,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 +109,22 @@
 	unsigned char mode;
 
 	struct net_device_stats stats;
+
+	struct net_device *next_module;
 };
 
-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);
 	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 +134,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;
 
@@ -177,7 +183,6 @@
 				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);
 	}
@@ -192,7 +197,6 @@
 				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);
 	}
@@ -209,7 +213,7 @@
 	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)
@@ -248,9 +252,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);
@@ -291,8 +295,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 +309,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;
@@ -338,7 +342,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++;
 			}
@@ -356,7 +360,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 +369,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 +387,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;
@@ -426,8 +430,8 @@
 {
 	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;
 
 	/* Ack the IRQ and set software state. */
 	hregs->rx_reset = HPC3_ERXRST_CLRIRQ;
@@ -435,7 +439,7 @@
 	/* 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);
 
@@ -447,47 +451,34 @@
 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,7 +500,7 @@
 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;
@@ -565,7 +556,7 @@
 
 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,41 +599,58 @@
 	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;
-
-	dev->priv = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL);
-	if (dev->priv == NULL)
+	int i;
+	
+	sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL);
+	if (!sp) {
+		printk (KERN_ERR
+			"Seeq8003: Could not allocate private data.\n");
 		return -ENOMEM;
+	}
 
-	if (!version_printed++)
-		printk(version);
-
-	printk("%s: SGI Seeq8003 ", dev->name);
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c",
-		       dev->dev_addr[i] = onboard_eth_addr[i],
-		       i == 5 ? ' ': ':');
+	dev = init_etherdev(NULL, 0);
+	if (!dev) {
+		printk (KERN_ERR
+			"Seeq8003: Could not allocate memory for device.\n");
+		free_page((unsigned long) sp);
+		return -ENOMEM;
+	}
+	/* let unregister_netdev free memory for us */
+	dev->features |= NETIF_F_DYNALLOC;
 
+	if (request_irq(irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) {
+		printk(KERN_ERR "Seeq8003: Can't get irq %d\n", dev->irq);
+		free_page((unsigned long) sp);
+		unregister_netdev(dev);
+		return -EAGAIN;
+	}
+
+	printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name);
+
+#define EADDR_NVOFS     250
+	for (i = 0; i < 3; i++) {
+		unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
+
+		printk("%2.2x:%2.2x%c",
+			dev->dev_addr[2 * i]     = tmp >> 8,
+			dev->dev_addr[2 * i + 1] = tmp & 0xff,
+			i == 2 ? ' ' : ':');
+	}
 	printk("\n");
 
-	sp = (struct sgiseeq_private *) dev->priv;
+	dev->priv = sp;
 #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 *)
@@ -659,14 +667,13 @@
 	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->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;
@@ -679,58 +686,36 @@
 	dev->dma                  = 0;
 	ether_setup(dev);
 
+	sp->next_module = root_sgiseeq_dev;
+	root_sgiseeq_dev = dev;
+
 	return 0;
 }
 
-static inline unsigned char str2hexnum(unsigned char c)
+static int __init sgiseeq_probe(void)
 {
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	return 0; /* foo */
+	printk(version);
+
+	/* On board adapter on 1st HPC is always present */
+	return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
 }
 
-static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+static void __exit sgiseeq_exit(void)
 {
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		unsigned char num;
+	struct sgiseeq_private *sp;
+	struct net_device *next, *dev = root_sgiseeq_dev;
 
-		if(*str == ':')
-			str++;
-		num = str2hexnum(*str++) << 4;
-		num |= (str2hexnum(*str++));
-		ea[i] = num;
+	while (dev) {
+		sp = (struct sgiseeq_private *) dev->priv;
+		next = sp->next_module;
+		free_irq(dev->irq, dev);
+		free_page((unsigned long) sp);
+		unregister_netdev(dev);
+		dev = next;
 	}
 }
 
-int sgiseeq_probe(struct net_device *dev)
-{
-	static int initialized;
-	char *ep;
-
-	if (initialized)	/* Already initialized? */
-		return 1;
-	initialized++;
-
-	/* 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");
-	if (ep == NULL) {
-		/*
-		 * This one is likely to be caused by a broken NVRAM
-		 */
-		printk(KERN_CRIT "Seeq8003: Can't get MAC address!\n");
-		return -ENODEV;
-	}
-	str2eaddr(onboard_eth_addr, ep);
-	return sgiseeq_init(dev,
-			    (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)),
-			    &hpc3c0->ethregs, SGI_ENET_IRQ);
-}
+module_init(sgiseeq_probe);
+module_exit(sgiseeq_exit);
 
 MODULE_LICENSE("GPL");

---

From: Juan Quintela <[email-masked]>
Date: Thu, 08 May 2003 00:14:56 +0200

>>>>> "ladis" == Ladislav Michl <[email-masked]> writes:

ladis> read eaddr using NVRAM access fuctions and make various cleanups so driver
ladis> can be build as module

You are my hero!

[ Removal of Space.c entry ] 

Hero++

ladis> @@ -96,8 +97,8 @@
ladis> struct sgiseeq_private {
ladis> volatile struct sgiseeq_init_block srings;
ladis> char *name;
ladis> -	volatile struct hpc3_ethregs *hregs;
ladis> -	volatile struct sgiseeq_regs *sregs;
ladis> +	struct hpc3_ethregs *hregs;
ladis> +	struct sgiseeq_regs *sregs;

I read through all the patch, and I didn't understand why volatile is
not needed anymore :(

Althought not that I did understand why it was needed in the first
place :)

ladis> @@ -435,7 +439,7 @@
ladis> /* Always check for received packets. */
ladis> sgiseeq_rx(dev, sp, hregs, sregs);
 
ladis> -	/* Only check for tx acks iff we have something queued. */
ladis> +	/* Only check for tx acks if we have something queued. */
ladis> if (sp->tx_old != sp->tx_new)
ladis> sgiseeq_tx(dev, sp, hregs, sregs);

iff == Math speak for if and only if.  Not sure if iff is needed in
that context at all.

Later, Juan. 

-- 
In theory, practice and theory are the same, but in practice they 
are different -- Larry McVoy

---

From: Ladislav Michl <[email-masked]>
Date: Thu, 8 May 2003 09:43:09 +0200

> [ Removal of Space.c entry ] 

Question comes in mind: It's possible to have ISA eth card installed in
Indigo2. How to ensure that onboard Seeq will be always eth0 without
using Space.c? (and don't advice me to build driver for ISA card as
module :))

> Althought not that I did understand why it was needed in the first

I think struct members have to be volatile, not struct itself.

> iff == Math speak for if and only if.  Not sure if iff is needed in

Ah, didn't know it. But i'd say simple if is enough in this case :)

	ladis

---

From: Ralf Baechle <[email-masked]>
Date: Thu, 8 May 2003 14:20:11 +0200

> > [ Removal of Space.c entry ] 

Absolutely, Space.c, RIP - Rot In Pieces.

> using Space.c? (and don't advice me to build driver for ISA card as

You just need to make sure sgiseeq.o is linked in before any of the ISA
drivers.

ISA link ordering is sort of emprical rocket science but fortunately
the IP22 Seeq isn't ISA.

  Ralf