Resent-Date: Mon, 14 Dec 1998 12:42:42 +0100 (MET)
Date: Mon, 14 Dec 1998 00:27:58 +0000
From: Richard Hirst <richard@sleepie.demon.co.uk>
To: linux-m68k@lists.linux-m68k.org
Cc: Jes Sorensen <Jes.Sorensen@cern.ch>
Subject: 2.1.130 patches for VME
Resent-From: linux-m68k@phil.uni-sb.de

Hi,
  These diffs are mainly VME related:

linux68k-2.1.130/arch/m68k/bvme6000/bvmeints.c
linux68k-2.1.130/arch/m68k/bvme6000/config.c
linux68k-2.1.130/arch/m68k/mvme16x/16xints.c
linux68k-2.1.130/include/asm-m68k/bvme6000hw.h

  Just minor edits.

linux68k-2.1.130/arch/m68k/config.in

  Allow 82596.c ethernet driver for VME to be built as a module, and no
  longer forces CONFIG_060_WRITETHROUGH for 68060 VME systems.

linux68k-2.1.130/arch/m68k/kernel/m68k_ksyms.c

  Exports kernel_set_cachemode() for use by 82596.c

linux68k-2.1.130/drivers/net/82596.c

  Updated to work with 68060 in copyback mode, and to allow building as
  a module.

linux68k-2.1.130/drivers/scsi/53c7xx.c

  Fixed to disable snooping on ALL systems (assuming snooping is controlled
  by the SC0/SC1 bits of the CTEST7 register).  Driver makes appropriate use
  use of cache_push/cache_clear/non-cached pages such that it works on
  68060 in copyback mode provided snooping is disabled.

linux68k-2.1.130/fs/Config.in

  Force CONFIG_MSDOS_PARTITION for VME systems.

Richard.



diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/arch/m68k/bvme6000/bvmeints.c linuxvme-2.1.130/arch/m68k/bvme6000/bvmeints.c
--- linux68k-2.1.130/arch/m68k/bvme6000/bvmeints.c	Mon Jun  8 17:07:44 1998
+++ linuxvme-2.1.130/arch/m68k/bvme6000/bvmeints.c	Sun Dec 13 20:00:15 1998
@@ -119,9 +119,12 @@
 void bvme6000_process_int (unsigned long vec, struct pt_regs *fp)
 {
 	if (vec > 255)
-		panic ("bvme6000_process_int: Illegal vector %ld", vec);
-	irq_tab[vec].count++;
-	irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+		printk ("bvme6000_process_int: Illegal vector %ld", vec);
+	else
+	{
+		irq_tab[vec].count++;
+		irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+	}
 }
 
 int bvme6000_get_irq_list (char *buf)
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/arch/m68k/bvme6000/config.c linuxvme-2.1.130/arch/m68k/bvme6000/config.c
--- linux68k-2.1.130/arch/m68k/bvme6000/config.c	Mon Jun  8 17:07:45 1998
+++ linuxvme-2.1.130/arch/m68k/bvme6000/config.c	Sun Dec 13 20:00:15 1998
@@ -91,8 +91,7 @@
 
 static void bvme6000_get_model(char *model)
 {
-    /* XXX Need to detect if BVME4000 or BVME6000 */
-    sprintf(model, "BVME6000");
+    sprintf(model, "BVME%d000", m68k_cputype == CPU_68060 ? 6 : 4);
 }
 
 
@@ -152,13 +151,17 @@
     pit->pbddr	= 0xf3;	/* Mostly outputs */
     pit->pcdr	= 0x01;	/* PA transceiver disabled */
     pit->pcddr	= 0x03;	/* WDOG disable */
+
+    /* Disable snooping for Ethernet and VME accesses */
+
+    bvme_acr_addrctl = 0;
 }
 
 
 void bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
 {
         unsigned long *new = (unsigned long *)vectors;
-        unsigned long *old = (unsigned long *)0xf8000000;;
+        unsigned long *old = (unsigned long *)0xf8000000;
 
         /* Wait for button release */
 	while (*config_reg_ptr & BVME_ABORT_STATUS)
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/arch/m68k/config.in linuxvme-2.1.130/arch/m68k/config.in
--- linux68k-2.1.130/arch/m68k/config.in	Mon Dec 14 00:02:20 1998
+++ linuxvme-2.1.130/arch/m68k/config.in	Sun Dec 13 22:03:20 1998
@@ -61,14 +61,11 @@
     bool 'Use 68060 specific optimizations' CONFIG_OPTIMIZE_060
   fi
 fi
-if [ "$CONFIG_VME" = "y" -a "$CONFIG_M68060" = "y" ]; then
-  define_bool CONFIG_060_WRITETHROUGH y
-fi
 bool 'Advanced configuration options' CONFIG_ADVANCED
 if [ "$CONFIG_ADVANCED" = "y" ]; then
   bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
   bool 'Use one physical chunk of memory only' CONFIG_SINGLE_MEMORY_CHUNK
-  if [ "$CONFIG_M68060" = "y" -a "$CONFIG_VME" = "n" ]; then
+  if [ "$CONFIG_M68060" = "y" ]; then
     bool 'Use write-through caching for 68060 supervisor accesses' CONFIG_060_WRITETHROUGH
   fi
 fi
@@ -160,10 +157,10 @@
   bool 'Macintosh onboard SONIC ethernet' CONFIG_MACSONIC
 fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
-  bool 'MVME16x Ethernet support' CONFIG_MVME16x_NET
+  tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
 fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
-  bool 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
+  tristate 'BVME6000 Ethernet support' CONFIG_BVME6000_NET
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari Lance support' CONFIG_ATARILANCE
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/arch/m68k/kernel/m68k_ksyms.c linuxvme-2.1.130/arch/m68k/kernel/m68k_ksyms.c
--- linux68k-2.1.130/arch/m68k/kernel/m68k_ksyms.c	Mon Dec 14 00:02:22 1998
+++ linuxvme-2.1.130/arch/m68k/kernel/m68k_ksyms.c	Sun Dec 13 22:03:22 1998
@@ -50,6 +50,7 @@
 EXPORT_SYMBOL(local_bh_count);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(kernel_set_cachemode);
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/arch/m68k/mvme16x/16xints.c linuxvme-2.1.130/arch/m68k/mvme16x/16xints.c
--- linux68k-2.1.130/arch/m68k/mvme16x/16xints.c	Mon Jun  8 17:07:52 1998
+++ linuxvme-2.1.130/arch/m68k/mvme16x/16xints.c	Sun Dec 13 20:00:15 1998
@@ -106,9 +106,12 @@
 void mvme16x_process_int (unsigned long vec, struct pt_regs *fp)
 {
 	if (vec < 64 || vec > 255)
-		panic ("mvme16x_process_int: Illegal vector %ld", vec);
-	irq_tab[vec-64].count++;
-	irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
+		printk ("mvme16x_process_int: Illegal vector %ld", vec);
+	else
+	{
+		irq_tab[vec-64].count++;
+		irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp);
+	}
 }
 
 int mvme16x_get_irq_list (char *buf)
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/drivers/net/82596.c linuxvme-2.1.130/drivers/net/82596.c
--- linux68k-2.1.130/drivers/net/82596.c	Sun Oct 11 22:03:07 1998
+++ linuxvme-2.1.130/drivers/net/82596.c	Sun Dec 13 20:00:15 1998
@@ -11,8 +11,18 @@
    by Richard Hirst <richard@sleepie.demon.co.uk>
    Renamed to be 82596.c
 
+   980825:  Changed to receive directly in to sk_buffs which are
+   allocated at open() time.  Eliminates copy on incoming frames
+   (small ones are still copied).  Shared data now held in a
+   non-cached page, so we can run on 68060 in copyback mode.
+
+   TBD:
+   * look at deferring rx frames rather than discarding (as per tulip)
+   * handle tx ring full as per tulip
+   * performace test to tune rx_copybreak
+
    *** Untested on Apricot hardware, and may require some hacking
-   *** to make it work.  The old 82596.c reported hasn't worked
+   *** to make it work.  The old apricot.c reportedly hasn't worked
    *** since 1.3.xx anyway.  I have been unable to find any users
    *** of Apricot hardware to test this on.
 
@@ -57,12 +67,19 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/pgtable.h>	/*?? */
+#include <asm/pgtable.h>
 
-#ifdef CONFIG_MVME16x_NET
+#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_MVME16x_NET_MODULE)
+#define ENABLE_MVME16x_NET
+#endif
+#if defined(CONFIG_BVME6000_NET) || defined(CONFIG_BVME6000_NET_MODULE)
+#define ENABLE_BVME6000_NET
+#endif
+
+#ifdef ENABLE_MVME16x_NET
 #include <asm/mvme16xhw.h>
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 #include <asm/bvme6000hw.h>
 #endif
 
@@ -103,24 +120,22 @@
 #define PORT_ALTSCP		0x02	/* alternate SCB address */
 #define PORT_ALTDUMP		0x03	/* Alternate DUMP address */
 
-#ifndef HAVE_PORTRESERVE
-#define check_region(addr, size)	0
-#define request_region(addr, size,name)	do ; while(0)
-#endif
-
-#ifndef HAVE_ALLOC_SKB
-#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(buff, size) kfree_s(buff,size)
-#endif
-
-#define APRICOT_DEBUG 2
+#define I82596_DEBUG 2
 
-#ifdef APRICOT_DEBUG
-int i596_debug = APRICOT_DEBUG;
+#ifdef I82596_DEBUG
+int i596_debug = I82596_DEBUG;
 #else
 int i596_debug = 1;
 #endif
 
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ	1536
+#define MAX_MC_CNT	64
+
 #define I596_TOTAL_SIZE 17
 
 #define I596_NULL -1
@@ -184,12 +199,22 @@
 	unsigned short stat;
 	unsigned short cmd;
 	struct i596_rfd *next;
-	long rbd;
+	struct i596_rbd *rbd;
 	unsigned short count;
 	unsigned short size;
-	char data[1532];
 };
 
+struct i596_rbd {
+    unsigned short count;
+    unsigned short zero1;
+    struct i596_rbd *next;
+    char *data;
+    unsigned short size;
+    unsigned short zero2;
+    struct sk_buff *skb;
+};
+
+#define TX_RING_SIZE 16
 #define RX_RING_SIZE 16
 
 struct i596_scb {
@@ -227,6 +252,9 @@
 	struct i596_cmd set_conf;
 	char i596_config[16];
 	struct i596_cmd tdr;
+	struct i596_cmd mc_cmd;		/* Keep these three together!!! */
+	short mc_cnt;			/* Keep these three together!!! */
+	char mc_addrs[MAX_MC_CNT*6];	/* Keep these three together!!! */
 	unsigned long stat;
 	int last_restart __attribute__((aligned(4)));
 	struct i596_rfd *rx_tail;
@@ -235,6 +263,11 @@
 	int cmd_backlog;
 	unsigned long last_cmd;
 	struct net_device_stats stats;
+	struct i596_rfd rfds[RX_RING_SIZE];
+	struct i596_rbd rbds[RX_RING_SIZE];
+	struct tx_cmd tx_cmds[TX_RING_SIZE];
+	struct i596_tbd tbds[TX_RING_SIZE];
+	int next_tx_cmd;
 };
 
 char init_setup[] =
@@ -267,18 +300,19 @@
 static void print_eth(char *);
 static void set_multicast_list(struct device *dev);
 
+static int rx_ring_size = RX_RING_SIZE;
 static int ticks_limit = 25;
 static int max_cmd_backlog = 16;
 
 
 static inline void CA(struct device *dev)
 {
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		((struct i596_reg *) dev->base_addr)->ca = 1;
 	}
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		volatile u32 i = *(volatile u32 *) (dev->base_addr);
 	}
@@ -293,14 +327,14 @@
 
 static inline void MPU_PORT(struct device *dev, int c, volatile void *x)
 {
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		struct i596_reg *p = (struct i596_reg *) (dev->base_addr);
 		p->porthi = ((c) | (u32) (x)) & 0xffff;
 		p->portlo = ((c) | (u32) (x)) >> 16;
 	}
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		u32 v = (u32) (c) | (u32) (x);
 		v = ((u32) (v) << 16) | ((u32) (v) >> 16);
@@ -312,7 +346,7 @@
 }
 
 
-#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)
+#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
 static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct device *dev = dev_id;
@@ -338,77 +372,86 @@
 }
 #endif
 
-static inline int init_rx_bufs(struct device *dev, int num)
+static inline void init_rx_bufs(struct device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = (struct i596_private *)dev->priv;
 	int i;
 	struct i596_rfd *rfd;
-
-	lp->scb.rfd = (struct i596_rfd *) I596_NULL;
+	struct i596_rbd *rbd;
 
 	if (i596_debug > 1)
-		printk("%s: init_rx_bufs %d.\n", dev->name, num);
-
-	for (i = 0; i < num; i++) {
-		if (!(rfd = (struct i596_rfd *) kmalloc(sizeof(struct i596_rfd), GFP_KERNEL)))
-			 break;
+		printk ("%s: init_rx_bufs %d.\n", dev->name, rx_ring_size);
 
-		rfd->stat = 0x0000;
-		rfd->rbd = I596_NULL;
-		rfd->count = 0;
-		rfd->size = 1532;
-		if (i == 0) {
-			rfd->cmd = CMD_EOL;
-			lp->rx_tail = rfd;
-		} else
-			rfd->cmd = 0x0000;
+	/* First build the Receive Buffer Descriptor List */
 
-		rfd->next = lp->scb.rfd;
-		lp->scb.rfd = WSWAPrfd(rfd);
-	}
+	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
 
-	if (i != 0)
-		lp->rx_tail->next = lp->scb.rfd;
-
-	return (i);
+		if (skb == NULL)
+			panic("82596: alloc_skb() failed");
+		skb->dev = dev;
+		rbd->next = WSWAPrbd(rbd+1);
+		rbd->skb = skb;
+		rbd->data = WSWAPchar(virt_to_bus(skb->tail));
+		rbd->size = PKT_BUF_SZ;
+		cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ);
+	}
+	lp->rbds[rx_ring_size-1].next = WSWAPrbd(lp->rbds);
+
+	/* Now build the Receive Frame Descriptor List */
+
+	for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
+		rfd->rbd = (struct i596_rbd *)I596_NULL;
+		rfd->next = WSWAPrfd(rfd+1);
+		rfd->cmd = CMD_FLEX;
+	}
+	lp->scb.rfd = WSWAPrfd(lp->rfds);
+	lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
+	rfd = lp->rfds + rx_ring_size - 1;
+	lp->rx_tail = rfd;
+	rfd->next = WSWAPrfd(lp->rfds);
+	rfd->cmd = CMD_EOL|CMD_FLEX;
 }
 
 static inline void remove_rx_bufs(struct device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
-	struct i596_rfd *rfd = WSWAPrfd(lp->scb.rfd);
-
-	lp->rx_tail->next = (struct i596_rfd *) I596_NULL;
+	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_rbd *rbd;
+	int i;
 
-	do {
-		lp->scb.rfd = rfd->next;
-		kfree(rfd);
-		rfd = WSWAPrfd(lp->scb.rfd);
+	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
+		if (rbd->skb == NULL)
+			break;
+		dev_kfree_skb(rbd->skb);
 	}
-	while (rfd != lp->rx_tail);
 }
 
 static inline void init_i596_mem(struct device *dev)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-#if !defined(CONFIG_MVME16x_NET) && !defined(CONFIG_BVME6000_NET)
+#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
 	short ioaddr = dev->base_addr;
 #endif
 	int boguscnt = 100000;
 	unsigned long flags;
+	int i;
 
-#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)
-#ifdef CONFIG_MVME16x_NET
+#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
 
 		/* Disable all ints for now */
 		pcc2[0x28] = 1;
 		pcc2[0x2a] = 0x40;
-		pcc2[0x2b] = 0x40;	/* Set snooping bits now! */
+		/* Following disables snooping.  Snooping is not required
+		 * as we make appropriate use of non-cached pages for
+		 * shared data, and cache_push/cache_clear.
+		 */
+		pcc2[0x2b] = 0x00;
 	}
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
 
@@ -436,11 +479,11 @@
 
 	lp->last_cmd = jiffies;
 
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x)
 		lp->scp.sysbus = 0x00000054;
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000)
 		lp->scp.sysbus = 0x0000004c;
 #endif
@@ -459,7 +502,7 @@
 	if (i596_debug > 1)
 		printk("%s: starting i82596.\n", dev->name);
 
-#if !defined(CONFIG_MVME16x_NET) && !defined(CONFIG_BVME6000_NET)
+#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
 	(void) inb(ioaddr + 0x10);
 	outb(4, ioaddr + 0xf);
 #endif
@@ -471,9 +514,22 @@
 			     dev->name, lp->scb.status, lp->scb.command);
 			break;
 		}
+
+	/* Ensure rx frame/buffer descriptors are tidy */
+	/* Bit naff doing this here as well as in init_rx_bufs() */
+
+	for (i = 0; i < rx_ring_size; i++) {
+		lp->rfds[i].rbd = (struct i596_rbd *)I596_NULL;
+		lp->rfds[i].cmd = CMD_FLEX;
+	}
+	lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
+	lp->scb.rfd = WSWAPrfd(lp->rfds);
+	lp->rfds[0].rbd = WSWAPrbd(lp->rbds);
+	lp->rx_tail = lp->rfds + rx_ring_size - 1;
+
 	lp->scb.command = 0;
 
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
 
@@ -483,7 +539,7 @@
 		pcc2[0x2b] = 0x55;
 	}
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
 
@@ -530,38 +586,84 @@
 
 static inline int i596_rx(struct device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = (struct i596_private *)dev->priv;
 	struct i596_rfd *rfd;
+	struct i596_rbd *rbd;
 	int frames = 0;
 
 	if (i596_debug > 3)
-		printk("i596_rx()\n");
+		printk ("i596_rx()\n");
 
-	rfd = WSWAPrfd(lp->scb.rfd);	/* Reference next frame descriptor to check */
+	rfd = WSWAPrfd(lp->scb.rfd);		/* Ref next frame to check */
 
-	while ((rfd->stat) & STAT_C) {	/* Loop while we have complete frames */
-		if (i596_debug > 2)
-			print_eth(rfd->data);
+	while ((rfd->stat) & STAT_C) {		/* Loop while complete frames */
+		rbd = WSWAPrbd(rfd->rbd);       /* Ref associated buffer desc */
+
+		if (i596_debug >2)
+			print_eth(WSWAPchar(rbd->data));
 
 		if ((rfd->stat) & STAT_OK) {
 			/* a good frame */
-			int pkt_len = rfd->count & 0x3fff;
-			struct sk_buff *skb = dev_alloc_skb(pkt_len);
+			int pkt_len = rbd->count & 0x3fff;
+			struct sk_buff *skb = rbd->skb;
+			int rx_in_place = 0;
 
 			frames++;
 
+			/* Check if the packet is long enough to just accept
+			 * without copying to a properly sized skbuff.
+			 */
+
+			if (pkt_len > rx_copybreak) {
+				struct sk_buff *newskb;
+				char *temp;
+
+				/* Get fresh skbuff to replace filled one. */
+				newskb = dev_alloc_skb(PKT_BUF_SZ);
+				if (newskb == NULL) {
+					skb = NULL;	/* drop pkt */
+					goto memory_squeeze;
+				}
+				/* Pass up the skb already on the Rx ring. */
+				temp = skb_put(skb, pkt_len);
+				if (bus_to_virt((int)WSWAPchar(rbd->data)) != temp)
+					printk(KERN_ERR "%s: Internal consistency error "
+						"-- the skbuff addresses do not match"
+						" in i596_rx: %p vs. %p / %p.\n", dev->name,
+						bus_to_virt((int)WSWAPchar(rbd->data)),
+						skb->head, temp);
+				rx_in_place = 1;
+				rbd->skb = newskb;
+				newskb->dev = dev;
+				rbd->data = WSWAPchar(virt_to_bus(newskb->tail));
+				cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ);
+			}
+			else
+				skb = dev_alloc_skb(pkt_len + 2);
+memory_squeeze:
 			if (skb == NULL) {
-				printk("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
+				/* XXX tulip.c can defer packets here!! */
+				printk ("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
 				lp->stats.rx_dropped++;
-			} else {
+			}
+			else {
 				skb->dev = dev;
-				memcpy(skb_put(skb, pkt_len), rfd->data, pkt_len);
-				skb->protocol = eth_type_trans(skb, dev);
+				if (!rx_in_place) {
+					/* 16 byte align the data fields */
+					skb_reserve(skb, 2);
+					memcpy(skb_put(skb,pkt_len),
+						WSWAPchar(rbd->data), pkt_len);
+				}
+				skb->protocol=eth_type_trans(skb,dev);
+				skb->len = pkt_len;
+				cache_clear(virt_to_phys(rbd->skb->tail),
+						pkt_len);
 				netif_rx(skb);
 				lp->stats.rx_packets++;
-				lp->stats.rx_bytes += pkt_len;
+				lp->stats.rx_bytes+=pkt_len;
 			}
-		} else {
+		}
+		else {
 			lp->stats.rx_errors++;
 			if ((rfd->stat) & 0x0001)
 				lp->stats.collisions++;
@@ -581,21 +683,40 @@
 
 		/* Clear the buffer descriptor count and EOF + F flags */
 
+		if (rbd != (struct i596_rbd *)I596_NULL)
+			rbd->count=0;
+		else
+			printk("%s: Null rbd - oops!\n", dev->name);
+
+		/* Tidy the frame descriptor, marking it as end of list */
+
+		rfd->rbd = (struct i596_rbd *)I596_NULL;
 		rfd->stat = 0;
+		rfd->cmd = CMD_EOL|CMD_FLEX;
 		rfd->count = 0;
-		rfd->cmd = CMD_EOL;
-		lp->rx_tail->cmd = 0;
+
+		/* Remove end-of-list from old end descriptor */
+
+		lp->rx_tail->cmd = CMD_FLEX;
+
+		/* Update last frame descriptor to reference the one just
+		 * processed */
+
 		lp->rx_tail = rfd;
+
+		/* Update record of next frame descriptor to process */
+
 		lp->scb.rfd = rfd->next;
-		rfd = WSWAPrfd(lp->scb.rfd);	/* Next frame descriptor to check */
+		rfd = WSWAPrfd(lp->scb.rfd);	/* Next frame desc. to check */
 	}
 
 	if (i596_debug > 3)
-		printk("frames %d\n", frames);
+		printk ("frames %d\n", frames);
 
 	return 0;
 }
 
+
 static inline void i596_cleanup_cmd(struct i596_private *lp)
 {
 	struct i596_cmd *ptr;
@@ -622,13 +743,12 @@
 				lp->stats.tx_aborted_errors++;
 
 				ptr->next = (struct i596_cmd *) I596_NULL;
-				kfree(tx_cmd);
+				tx_cmd->cmd.command = 0;  /* Mark as free */
 				break;
 			}
 		case CmdMulticastList:
 			{
 				ptr->next = (struct i596_cmd *) I596_NULL;
-				kfree(ptr);
 				break;
 			}
 		default:
@@ -748,26 +868,19 @@
 
 static int i596_open(struct device *dev)
 {
-	int i;
-
 	if (i596_debug > 1)
 		printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
 
 	if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", dev))
 		return -EAGAIN;
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		if (request_irq(0x56, &i596_error, 0, "apricot_error", dev))
 			return -EAGAIN;
 	}
 #endif
-	if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
-		printk("%s: only able to allocate %d receive buffers\n", dev->name, i);
+	init_rx_bufs(dev);
 
-	if (i < 4) {
-		free_irq(dev->irq, dev);
-		return -EAGAIN;
-	}
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
@@ -784,6 +897,7 @@
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 	int ioaddr = dev->base_addr;
 	struct tx_cmd *tx_cmd;
+	struct i596_tbd *tbd;
 
 	if (i596_debug > 2)
 		printk("%s: 82596 start xmit\n", dev->name);
@@ -815,7 +929,8 @@
 		dev->trans_start = jiffies;
 	}
 	if (i596_debug > 3)
-		printk("%s: i596_start_xmit() called\n", dev->name);
+		printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
+				skb->len, (unsigned int)skb->data);
 
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
@@ -825,14 +940,18 @@
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		dev->trans_start = jiffies;
 
-		tx_cmd = (struct tx_cmd *) kmalloc((sizeof(struct tx_cmd) + sizeof(struct i596_tbd)), GFP_ATOMIC);
-		if (tx_cmd == NULL) {
-			printk("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
+		tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
+		tbd = lp->tbds + lp->next_tx_cmd;
+
+		if (tx_cmd->cmd.command) {
+			printk ("%s: xmit ring full, dropping packet.\n",
+					dev->name);
 			lp->stats.tx_dropped++;
 
 			dev_kfree_skb(skb);
 		} else {
-			struct i596_tbd *tbd = (struct i596_tbd *) (tx_cmd + 1);
+			if (++lp->next_tx_cmd == TX_RING_SIZE)
+				lp->next_tx_cmd = 0;
 			tx_cmd->tbd = WSWAPtbd(tbd);
 			tbd->next = (struct i596_tbd *) I596_NULL;
 
@@ -846,6 +965,7 @@
 
 			tbd->data = WSWAPchar(skb->data);
 
+			cache_push(virt_to_phys(skb->data), length);
 			if (i596_debug > 3)
 				print_eth(skb->data);
 			i596_add_cmd(dev, (struct i596_cmd *) tx_cmd);
@@ -884,14 +1004,15 @@
 	struct i596_private *lp;
 	char eth_addr[6];
 
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		static int probed = 0;
-
+#ifdef XXX_FIXME
 		if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {
 			printk("Ethernet probe disabled - chip not present\n");
 			return ENODEV;
 		}
+#endif
 		if (probed)
 			return ENODEV;
 		probed++;
@@ -900,7 +1021,7 @@
 		dev->irq = (unsigned) MVME16x_IRQ_I596;
 	}
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;
 		unsigned char msr = rtc[3];
@@ -965,15 +1086,20 @@
 	dev->get_stats = &i596_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 
-	dev->mem_start = (int) kmalloc(sizeof(struct i596_private) + 0x0f, GFP_KERNEL);
-	/* align for scp */
-	dev->priv = (void *) ((dev->mem_start + 0xf) & 0xfffffff0);
+	dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);
+	dev->priv = (void *)(dev->mem_start);
 
 	lp = (struct i596_private *) dev->priv;
 	if (i596_debug)
-		printk("%s: lp at 0x%08lx, lp->scb at 0x%08lx\n"
-		,dev->name, (unsigned long) lp, (unsigned long) &lp->scb);
+		printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
+			dev->name, (unsigned long)lp,
+			sizeof(struct i596_private), (unsigned long)&lp->scb);
 	memset((void *) lp, 0, sizeof(struct i596_private));
+
+	cache_push(virt_to_phys((void *)(dev->mem_start)), 4096);
+	cache_clear(virt_to_phys((void *)(dev->mem_start)), 4096);
+	kernel_set_cachemode(dev->mem_start, 4096, KERNELMAP_NOCACHE_SER);
+
 	lp->scb.command = 0;
 	lp->scb.cmd = (struct i596_cmd *) I596_NULL;
 	lp->scb.rfd = (struct i596_rfd *) I596_NULL;
@@ -989,7 +1115,7 @@
 	int boguscnt = 2000;
 	unsigned short status, ack_cmd = 0;
 
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
 			i596_error(BVME_IRQ_I596, NULL, NULL);
@@ -1068,13 +1194,12 @@
 					dev_kfree_skb(skb);
 
 					ptr->next = (struct i596_cmd *) I596_NULL;
-					kfree(tx_cmd);
+					tx_cmd->cmd.command = 0; /* Mark free */
 					break;
 				}
 			case CmdMulticastList:
 				{
 					ptr->next = (struct i596_cmd *) I596_NULL;
-					kfree(ptr);
 					break;
 				}
 			case CmdTDR:
@@ -1146,7 +1271,7 @@
 		}
 	lp->scb.command = ack_cmd;
 
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		/* Ack the interrupt */
 
@@ -1155,7 +1280,7 @@
 		pcc2[0x2a] |= 0x08;
 	}
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
 
@@ -1213,7 +1338,7 @@
 
 	i596_cleanup_cmd(lp);
 
-#ifdef CONFIG_MVME16x_NET
+#ifdef ENABLE_MVME16x_NET
 	if (MACH_IS_MVME16x) {
 		volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
 
@@ -1223,7 +1348,7 @@
 		pcc2[0x2b] = 0x40;	/* Set snooping bits now! */
 	}
 #endif
-#ifdef CONFIG_BVME6000_NET
+#ifdef ENABLE_BVME6000_NET
 	if (MACH_IS_BVME6000) {
 		volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;
 
@@ -1254,7 +1379,7 @@
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 	struct i596_cmd *cmd;
-	int config = 0;
+	int config = 0, cnt;
 
 	if (i596_debug > 1)
 		printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF");
@@ -1284,18 +1409,24 @@
 			i596_add_cmd(dev, &lp->set_conf);
 		}
 	}
+
+	cnt = dev->mc_count;
+	if (cnt > MAX_MC_CNT)
+	{
+		cnt = MAX_MC_CNT;
+		printk("%s: Only %d multicast addresses supported",
+			dev->name, cnt);
+	}
+	
 	if (dev->mc_count > 0) {
 		struct dev_mc_list *dmi;
 		unsigned char *cp;
-		cmd = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd) + 2 + dev->mc_count * 6, GFP_ATOMIC);
-		if (cmd == NULL) {
-			printk("%s: set_multicast Memory squeeze.\n", dev->name);
-			return;
-		}
+
+		cmd = &lp->mc_cmd;
 		cmd->command = CmdMulticastList;
 		*((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
 		cp = ((unsigned char *) (cmd + 1)) + 2;
-		for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+		for(dmi=dev->mc_list;cnt && dmi!=NULL;dmi=dmi->next,cnt--) {
 			memcpy(cp, dmi->dmi_addr, 6);
 			if (i596_debug > 1)
 				printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, *(cp + 0), *(cp + 1), *(cp + 2), *(cp + 3), *(cp + 4), *(cp + 5));
@@ -1317,34 +1448,51 @@
 #ifdef MODULE
 static char devicename[9] =
 {0,};
-static struct device dev_apricot =
+static struct device dev_82596 =
 {
-	devicename,		/* device name inserted by /linux/drivers/net/net_init.c */
+	devicename,	/* device name inserted by drivers/net/net_init.c */
 	0, 0, 0, 0,
-	0x300, 10,
+	0, 0,		/* base, irq */
 	0, 0, 0, NULL, i82596_probe};
 
+#ifdef CONFIG_APRICOT_INTEL
 static int io = 0x300;
 static int irq = 10;
 MODULE_PARM(irq, "i");
+#endif
+
+MODULE_PARM(debug, "i");
+static int debug = -1;
 
 int init_module(void)
 {
-	dev_apricot.base_addr = io;
-	dev_apricot.irq = irq;
-	if (register_netdev(&dev_apricot) != 0)
+#ifdef CONFIG_APRICOT_INTEL
+	dev_82596.base_addr = io;
+	dev_82596.irq = irq;
+#endif
+	if (debug >= 0)
+		i596_debug = debug;
+	if (register_netdev(&dev_82596) != 0)
 		return -EIO;
 	return 0;
 }
 
 void cleanup_module(void)
 {
-	unregister_netdev(&dev_apricot);
-	kfree((void *) dev_apricot.mem_start);
-	dev_apricot.priv = NULL;
+	unregister_netdev(&dev_82596);
 
+	/* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING,
+	 * XXX which may be invalid (CONFIG_060_WRITETHROUGH)
+	 */
+
+	kernel_set_cachemode((u32)(dev_82596.mem_start), 4096,
+			KERNELMAP_FULL_CACHING);
+	free_page ((u32)(dev_82596.mem_start));
+	dev_82596.priv = NULL;
+#ifdef CONFIG_APRICOT_INTEL
 	/* If we don't do this, we can't re-insmod it later. */
-	release_region(dev_apricot.base_addr, I596_TOTAL_SIZE);
+	release_region(dev_82596.base_addr, I596_TOTAL_SIZE);
+#endif
 }
 
 #endif				/* MODULE */
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/drivers/scsi/53c7xx.c linuxvme-2.1.130/drivers/scsi/53c7xx.c
--- linux68k-2.1.130/drivers/scsi/53c7xx.c	Sun Dec 13 19:15:51 1998
+++ linuxvme-2.1.130/drivers/scsi/53c7xx.c	Sun Dec 13 20:00:15 1998
@@ -2965,14 +2965,14 @@
     	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
     else
     	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
-#if 0
-    /* Following disables snooping - run with caches disabled at first */
+    /* Following disables snooping - snooping is not required, as non-
+     * cached pages are used for shared data, and appropriate use is
+     * made of cache_push/cache_clear.  Indeed, for 68060
+     * enabling snooping causes disk corruption of ext2fs free block
+     * bitmaps and the like.  If you have a 68060 with snooping hardwared
+     * on, then you need to enable CONFIG_060_WRITETHROUGH.
+     */
     NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
-#else
-    /* Setup CTEST7 for SC1=0, SC0=1 - sink/source data without invalidating
-     * cache lines. */
-    NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD|CTEST7_10_SC0);
-#endif
     /* Actually burst of eight, according to my 53c710 databook */
     NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
     NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/fs/Config.in linuxvme-2.1.130/fs/Config.in
--- linux68k-2.1.130/fs/Config.in	Sun Dec 13 19:15:57 1998
+++ linuxvme-2.1.130/fs/Config.in	Sun Dec 13 20:00:16 1998
@@ -82,6 +82,9 @@
   if [ "$CONFIG_ATARI" = "y" ]; then
     define_bool CONFIG_ATARI_PARTITION y
   fi
+  if [ "$CONFIG_VME" = "y" ]; then
+    define_bool CONFIG_MSDOS_PARTITION y
+  fi
   if [ "$CONFIG_MAC" = "y" ]; then
     define_bool CONFIG_MAC_PARTITION y
   fi
diff -ur -X dodiffs-exclude --new-file linux68k-2.1.130/include/asm-m68k/bvme6000hw.h linuxvme-2.1.130/include/asm-m68k/bvme6000hw.h
--- linux68k-2.1.130/include/asm-m68k/bvme6000hw.h	Mon Jun  8 17:04:45 1998
+++ linuxvme-2.1.130/include/asm-m68k/bvme6000hw.h	Sun Dec 13 20:48:03 1998
@@ -98,7 +98,7 @@
 
 #define BVME_CONFIG_REG	0xff500003
 
-#define config_reg_ptr	(unsigned char *)BVME_CONFIG_REG
+#define config_reg_ptr	(volatile unsigned char *)BVME_CONFIG_REG
 
 #define BVME_CONFIG_SW1	0x08
 #define BVME_CONFIG_SW2	0x04
@@ -125,5 +125,25 @@
 #define BVME_IRQ_SCCA_STAT		0x4a
 #define BVME_IRQ_SCCA_RX		0x4c
 #define BVME_IRQ_SCCA_SPCOND		0x4e
+
+/* Address control registers */
+
+#define BVME_ACR_A32VBA		0xff400003
+#define BVME_ACR_A32MSK		0xff410003
+#define BVME_ACR_A24VBA		0xff420003
+#define BVME_ACR_A24MSK		0xff430003
+#define BVME_ACR_A16VBA		0xff440003
+#define BVME_ACR_A32LBA		0xff450003
+#define BVME_ACR_A24LBA		0xff460003
+#define BVME_ACR_ADDRCTL	0xff470003
+
+#define bvme_acr_a32vba		*(volatile unsigned char *)BVME_ACR_A32VBA
+#define bvme_acr_a32msk		*(volatile unsigned char *)BVME_ACR_A32MSK
+#define bvme_acr_a24vba		*(volatile unsigned char *)BVME_ACR_A24VBA
+#define bvme_acr_a24msk		*(volatile unsigned char *)BVME_ACR_A24MSK
+#define bvme_acr_a16vba		*(volatile unsigned char *)BVME_ACR_A16VBA
+#define bvme_acr_a32lba		*(volatile unsigned char *)BVME_ACR_A32LBA
+#define bvme_acr_a24lba		*(volatile unsigned char *)BVME_ACR_A24LBA
+#define bvme_acr_addrctl	*(volatile unsigned char *)BVME_ACR_ADDRCTL
 
 #endif

