diff -u --recursive --new-file v2.1.33/linux/CREDITS linux/CREDITS
--- v2.1.33/linux/CREDITS	Sun Apr 13 10:18:19 1997
+++ linux/CREDITS	Sun Apr 13 20:28:27 1997
@@ -257,14 +257,12 @@
 
 N: Alan Cox
 E: alan@lxorguk.ukuu.org.uk (linux related - except big patches)
-E: iialan@www.linux.org.uk (linux.org.uk/big patches)
+E: iialan@www.uk.linux.org (linux.org.uk/big patches)
 E: alan@cymru.net (commercial CymruNET stuff)
-E: gw4pts@gw4pts.ampr.org (amateur radio stuff)
-E: GW4PTS@GB7SWN (packet radio)
-E: Please don't use iialan@iifeak.swan.ac.uk for Linux stuff
-S: c/o 3Com/I^2IT Limited
+E: Alan.Cox@linux.org (if others fail)
+S: CymruNet Limited
 S: The Innovation Centre
-S: University Of Wales
+S: Singleton Park
 S: Swansea, SA2 8PP
 S: Wales, UK
 D: NET2Debugged/NET3 author
diff -u --recursive --new-file v2.1.33/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.33/linux/Documentation/Configure.help	Sun Apr 13 10:18:19 1997
+++ linux/Documentation/Configure.help	Mon Apr 14 09:25:59 1997
@@ -539,6 +539,12 @@
   any security protocols currently and that this option only really supports
   security on IPv4 links at the moment.
 
+Socket Security API Support (EXPERIMENTAL)
+CONFIG_NET_SECURITY
+  Enable use of the socket security API. Note that Linux does not include
+  any security protocols currently and that this option only really supports
+  security on IPv4 links at the moment.
+
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
   This is support for floppy drives on Sun Sparc workstations. Say Y
@@ -1530,9 +1536,10 @@
 Enable vendor-specific extensions (for SCSI CDROM)
 CONFIG_BLK_DEV_SR_VENDOR
   This enables the usage of vendor specific SCSI commands. This is
-  required for some stuff which is newer than the SCSI-II standard,
-  most important is the MultiSession CD support. You'll probably want
-  to say Y here, unless you have a _real old_ CD-ROM drive.
+  required for some stuff which is newer than the SCSI-II standard:
+  MultiSession CD support and some ioctls for reading Mode 2 Form 2
+  sectors. You'll probably want to say Y here, unless you have a
+  _real old_ CD-ROM drive.
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
diff -u --recursive --new-file v2.1.33/linux/Makefile linux/Makefile
--- v2.1.33/linux/Makefile	Sun Apr 13 10:18:20 1997
+++ linux/Makefile	Mon Apr 14 11:55:24 1997
@@ -1,8 +1,8 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 33
+SUBLEVEL = 34
 
-ARCH = i386
+ARCH := $(shell uname -m | sed s/i.86/i386/)
 
 #
 # For SMP kernels, set this. We don't want to have this in the config file
@@ -14,7 +14,7 @@
 SMP = 1
 #
 # SMP profiling options
-SMP_PROF = 1
+# SMP_PROF = 1
 
 .EXPORT_ALL_VARIABLES:
 
diff -u --recursive --new-file v2.1.33/linux/Rules.make linux/Rules.make
--- v2.1.33/linux/Rules.make	Sun Apr 13 10:18:20 1997
+++ linux/Rules.make	Sun Apr 13 20:47:29 1997
@@ -197,7 +197,7 @@
 endif # CONFIG_MODVERSIONS
 
 ifneq "$(strip $(SYMTAB_OBJS))" ""
-$(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h
+$(SYMTAB_OBJS): $(TOPDIR)/include/linux/modversions.h $(SYMTAB_OBJS:.o=.c)
 	$(CC) $(CFLAGS) -DEXPORT_SYMTAB -c $(@:.o=.c)
 endif
 
diff -u --recursive --new-file v2.1.33/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.1.33/linux/arch/alpha/kernel/alpha_ksyms.c	Thu Mar 27 14:39:59 1997
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Mon Apr 14 09:31:08 1997
@@ -19,7 +19,7 @@
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <asm/checksum.h>
-
+#include <asm/softirq.h>
 
 extern void bcopy (const char *src, char *dst, int len);
 extern struct hwrpb_struct *hwrpb;
@@ -37,6 +37,7 @@
 extern void __divqu (void);
 extern void __remqu (void);
 
+EXPORT_SYMBOL(__alpha_bh_counter);
 
 /* platform dependent support */
 EXPORT_SYMBOL(_inb);
diff -u --recursive --new-file v2.1.33/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.1.33/linux/arch/alpha/kernel/irq.c	Tue Oct 15 23:05:09 1996
+++ linux/arch/alpha/kernel/irq.c	Mon Apr 14 11:39:14 1997
@@ -53,7 +53,6 @@
  */
 static unsigned long irq_mask = ~0UL;
 
-
 /*
  * Update the hardware with the irq mask passed in MASK.  The function
  * exploits the fact that it is known that only bit IRQ has changed.
@@ -274,6 +273,16 @@
 	printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
 }
 
+unsigned int local_irq_count[NR_CPUS];
+atomic_t __alpha_bh_counter;
+
+#ifdef __SMP__
+#error Me no hablo Alpha SMP
+#else
+#define irq_enter(cpu, irq)	(++local_irq_count[cpu])
+#define irq_exit(cpu, irq)	(--local_irq_count[cpu])
+#endif
+
 static void unexpected_irq(int irq, struct pt_regs * regs)
 {
 	struct irqaction *action;
@@ -302,16 +311,19 @@
 static inline void handle_irq(int irq, struct pt_regs * regs)
 {
 	struct irqaction * action = irq_action[irq];
+	int cpu = smp_processor_id();
 
+	irq_enter(cpu, irq);
 	kstat.interrupts[irq]++;
 	if (!action) {
 		unexpected_irq(irq, regs);
-		return;
+	} else {
+		do {
+			action->handler(irq, action->dev_id, regs);
+			action = action->next;
+		} while (action);
 	}
-	do {
-		action->handler(irq, action->dev_id, regs);
-		action = action->next;
-	} while (action);
+	irq_exit(cpu, irq);
 }
 
 static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
@@ -323,6 +335,7 @@
 		return;
 	}
 
+	irq_enter(cpu, irq);
 	kstat.interrupts[irq]++;
 	action = irq_action[irq];
 	/*
@@ -336,15 +349,16 @@
 	 */
 	mask_irq(ack);
 	ack_irq(ack);
-	if (!action)
-		return;
-	if (action->flags & SA_SAMPLE_RANDOM)
-		add_interrupt_randomness(irq);
-	do {
-		action->handler(irq, action->dev_id, regs);
-		action = action->next;
-	} while (action);
-	unmask_irq(ack);
+	if (action) {
+		if (action->flags & SA_SAMPLE_RANDOM)
+			add_interrupt_randomness(irq);
+		do {
+			action->handler(irq, action->dev_id, regs);
+			action = action->next;
+		} while (action);
+		unmask_irq(ack);
+	}
+	irq_exit(cpu, irq);
 }
 
 #ifdef CONFIG_PCI
diff -u --recursive --new-file v2.1.33/linux/arch/alpha/lib/csum_partial_copy.c linux/arch/alpha/lib/csum_partial_copy.c
--- v2.1.33/linux/arch/alpha/lib/csum_partial_copy.c	Tue Mar  4 10:25:23 1997
+++ linux/arch/alpha/lib/csum_partial_copy.c	Fri Apr 11 10:37:40 1997
@@ -13,7 +13,7 @@
 
 
 #define ldq_u(x,y) \
-__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(unsigned long *)(y)))
+__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(const unsigned long *)(y)))
 
 #define stq_u(x,y) \
 __asm__ __volatile__("stq_u %1,%0":"=m" (*(unsigned long *)(y)):"r" (x))
@@ -72,7 +72,7 @@
  * Ok. This isn't fun, but this is the EASY case.
  */
 static inline unsigned long
-csum_partial_cfu_aligned(unsigned long *src, unsigned long *dst,
+csum_partial_cfu_aligned(const unsigned long *src, unsigned long *dst,
 			 long len, unsigned long checksum,
 			 int *errp)
 {
@@ -165,7 +165,7 @@
  * This is slightly less fun than the above..
  */
 static inline unsigned long
-csum_partial_cfu_src_aligned(unsigned long *src, unsigned long *dst,
+csum_partial_cfu_src_aligned(const unsigned long *src, unsigned long *dst,
 			     unsigned long doff,
 			     long len, unsigned long checksum,
 			     unsigned long partial_dest,
@@ -227,7 +227,7 @@
  * look at this too closely, you'll go blind.
  */
 static inline unsigned long
-csum_partial_cfu_unaligned(unsigned long * src, unsigned long * dst,
+csum_partial_cfu_unaligned(const unsigned long * src, unsigned long * dst,
 			   unsigned long soff, unsigned long doff,
 			   long len, unsigned long checksum,
 			   unsigned long partial_dest,
@@ -305,7 +305,7 @@
 }
 
 static unsigned int
-do_csum_partial_copy_from_user(char *src, char *dst, int len,
+do_csum_partial_copy_from_user(const char *src, char *dst, int len,
 			       unsigned int sum, int *errp)
 {
 	unsigned long checksum = (unsigned) sum;
@@ -316,12 +316,12 @@
 		if (!doff) {
 			if (!soff)
 				checksum = csum_partial_cfu_aligned(
-					(unsigned long *) src,
+					(const unsigned long *) src,
 					(unsigned long *) dst,
 					len-8, checksum, errp);
 			else
 				checksum = csum_partial_cfu_dest_aligned(
-					(unsigned long *) src,
+					(const unsigned long *) src,
 					(unsigned long *) dst,
 					soff, len-8, checksum, errp);
 		} else {
@@ -329,13 +329,13 @@
 			ldq_u(partial_dest, dst);
 			if (!soff)
 				checksum = csum_partial_cfu_src_aligned(
-					(unsigned long *) src,
+					(const unsigned long *) src,
 					(unsigned long *) dst,
 					doff, len-8, checksum,
 					partial_dest, errp);
 			else
 				checksum = csum_partial_cfu_unaligned(
-					(unsigned long *) src,
+					(const unsigned long *) src,
 					(unsigned long *) dst,
 					soff, doff, len-8, checksum,
 					partial_dest, errp);
@@ -352,7 +352,7 @@
 }
 
 unsigned int
-csum_partial_copy_from_user(char *src, char *dst, int len,
+csum_partial_copy_from_user(const char *src, char *dst, int len,
 			    unsigned int sum, int *errp)
 {
 	if (!access_ok(src, len, VERIFY_READ)) {
diff -u --recursive --new-file v2.1.33/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.1.33/linux/arch/alpha/mm/init.c	Sun Jan 26 02:07:04 1997
+++ linux/arch/alpha/mm/init.c	Mon Apr 14 09:31:08 1997
@@ -64,10 +64,10 @@
 		total++;
 		if (PageReserved(mem_map+i))
 			reserved++;
-		else if (!mem_map[i].count)
+		else if (!atomic_read(&mem_map[i].count))
 			free++;
 		else
-			shared += mem_map[i].count-1;
+			shared += atomic_read(&mem_map[i].count) - 1;
 	}
 	printk("%d pages of RAM\n",total);
 	printk("%d free pages\n",free);
@@ -163,7 +163,7 @@
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
 		if (PageReserved(mem_map+MAP_NR(tmp)))
 			continue;
-		mem_map[MAP_NR(tmp)].count = 1;
+		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
 		free_page(tmp);
 	}
 	tmp = nr_free_pages << PAGE_SHIFT;
@@ -189,9 +189,9 @@
 		if (PageReserved(mem_map+i))
 			continue;
 		val->totalram++;
-		if (!mem_map[i].count)
+		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += mem_map[i].count-1;
+		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.1.33/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.33/linux/arch/i386/defconfig	Sun Apr 13 10:18:20 1997
+++ linux/arch/i386/defconfig	Fri Apr 11 22:13:19 1997
@@ -30,6 +30,12 @@
 # CONFIG_M586 is not set
 CONFIG_M686=y
 # CONFIG_VIDEO_SELECT is not set
+# CONFIG_PNP_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
 
 #
 # Floppy, IDE, and other block devices
@@ -131,7 +137,6 @@
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_PPA is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
@@ -163,7 +168,6 @@
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_SLIP is not set
@@ -214,7 +218,6 @@
 CONFIG_SERIAL=y
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_PRINTER is not set
 CONFIG_MOUSE=y
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
diff -u --recursive --new-file v2.1.33/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.33/linux/arch/i386/kernel/irq.c	Sun Apr 13 10:18:20 1997
+++ linux/arch/i386/kernel/irq.c	Mon Apr 14 11:39:49 1997
@@ -36,7 +36,7 @@
 #include <asm/pgtable.h>
 
 #ifdef __SMP_PROF__
-extern volatile unsigned long smp_apic_timer_ticks[1+NR_CPUS];
+extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
 #endif
 
 #define CR0_NE 32
@@ -45,6 +45,11 @@
 static unsigned char cache_A1 = 0xff;
 
 unsigned int local_irq_count[NR_CPUS];
+#ifdef __SMP__
+atomic_t __intel_bh_counter;
+#else
+int __intel_bh_counter;
+#endif
 
 #ifdef __SMP_PROF__
 static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
@@ -252,6 +257,9 @@
 
 #ifdef __SMP_PROF__
 
+extern unsigned int prof_multiplier[NR_CPUS];
+extern unsigned int prof_counter[NR_CPUS];
+
 int get_smp_prof_list(char *buf) {
 	int i,j, len = 0;
 	struct irqaction * action;
@@ -259,7 +267,7 @@
 	unsigned long sum_spins_syscall = 0;
 	unsigned long sum_spins_sys_idle = 0;
 	unsigned long sum_smp_idle_count = 0;
-	unsigned long sum_apic_timer_ticks = 0;
+	unsigned long sum_local_timer_ticks = 0;
 
 	for (i=0;i<smp_num_cpus;i++) {
 		int cpunum = cpu_logical_map[i];
@@ -267,7 +275,7 @@
 		sum_spins_syscall+=smp_spins_syscall[cpunum];
 		sum_spins_sys_idle+=smp_spins_sys_idle[cpunum];
 		sum_smp_idle_count+=smp_idle_count[cpunum];
-		sum_apic_timer_ticks+=smp_apic_timer_ticks[cpunum];
+		sum_local_timer_ticks+=smp_local_timer_ticks[cpunum];
 	}
 
 	len += sprintf(buf+len,"CPUS: %10i \n", smp_num_cpus);
@@ -324,12 +332,23 @@
 
 	len +=sprintf(buf+len,"   idle ticks\n");
 
-	len+=sprintf(buf+len,"TICK %10lu",sum_apic_timer_ticks);
+	len+=sprintf(buf+len,"TICK %10lu",sum_local_timer_ticks);
 	for (i=0;i<smp_num_cpus;i++)
-		len+=sprintf(buf+len," %10lu",smp_apic_timer_ticks[cpu_logical_map[i]]);
+		len+=sprintf(buf+len," %10lu",smp_local_timer_ticks[cpu_logical_map[i]]);
 
 	len +=sprintf(buf+len,"   local APIC timer ticks\n");
 
+	len+=sprintf(buf+len,"MULT:          ");
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10u",prof_multiplier[cpu_logical_map[i]]);
+	len +=sprintf(buf+len,"   profiling multiplier\n");
+
+	len+=sprintf(buf+len,"COUNT:         ");
+	for (i=0;i<smp_num_cpus;i++)
+		len+=sprintf(buf+len," %10u",prof_counter[cpu_logical_map[i]]);
+
+	len +=sprintf(buf+len,"   profiling counter\n");
+
 	len+=sprintf(buf+len, "IPI: %10lu   received\n",
 		ipi_count);
 
@@ -345,7 +364,7 @@
 #ifdef __SMP__
 unsigned char global_irq_holder = NO_PROC_ID;
 unsigned volatile int global_irq_lock;
-unsigned volatile int global_irq_count;
+atomic_t global_irq_count;
 
 #define irq_active(cpu) \
 	(global_irq_count != local_irq_count[cpu])
@@ -373,7 +392,7 @@
 
 #undef STUCK
 #define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, global_irq_count); stuck = INIT_STUCK; }
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
 
 static inline void wait_on_irq(int cpu, unsigned long where)
 {
@@ -381,7 +400,7 @@
 	int local_count = local_irq_count[cpu];
 
 	/* Are we the only one in an interrupt context? */
-	while (local_count != global_irq_count) {
+	while (local_count != atomic_read(&global_irq_count)) {
 		/*
 		 * No such luck. Now we need to release the lock,
 		 * _and_ release our interrupt context, because
@@ -398,7 +417,7 @@
 		for (;;) {
 			STUCK;
 			check_smp_invalidate(cpu);
-			if (global_irq_count)
+			if (atomic_read(&global_irq_count))
 				continue;
 			if (global_irq_lock)
 				continue;
@@ -424,7 +443,7 @@
 	int local_count = local_irq_count[cpu];
 
 	/* Do we need to wait? */
-	if (local_count != global_irq_count) {
+	if (local_count != atomic_read(&global_irq_count)) {
 		/* The stupid way to do this */
 		cli();
 		sti();
@@ -512,7 +531,7 @@
 #define STUCK \
 if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
 
-static inline void irq_enter(int cpu, int irq)
+inline void irq_enter(int cpu, int irq)
 {
 	int stuck = INIT_STUCK;
 
@@ -525,21 +544,19 @@
 		STUCK;
 		/* nothing */;
 	}
-	atomic_inc(&intr_count);
 }
 
-static inline void irq_exit(int cpu, int irq)
+inline void irq_exit(int cpu, int irq)
 {
 	__cli();
-	atomic_dec(&intr_count);
 	hardirq_exit(cpu);
 	release_irqlock(cpu);
 }
 
 #else
 
-#define irq_enter(cpu, irq)	(++intr_count)
-#define irq_exit(cpu, irq)	(--intr_count)
+#define irq_enter(cpu, irq)	(++local_irq_count[cpu])
+#define irq_exit(cpu, irq)	(--local_irq_count[cpu])
 
 #endif
 
diff -u --recursive --new-file v2.1.33/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.33/linux/arch/i386/kernel/smp.c	Sun Apr 13 10:18:20 1997
+++ linux/arch/i386/kernel/smp.c	Mon Apr 14 11:52:23 1997
@@ -141,7 +141,7 @@
 volatile unsigned long smp_idle_count[1+NR_CPUS]={0,};	/* Count idle ticks					*/
 
 /* Count local APIC timer ticks */
-volatile unsigned long smp_apic_timer_ticks[1+NR_CPUS]={0,};
+volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]={0,};
 
 #endif
 #if defined (__SMP_PROF__)
@@ -178,6 +178,16 @@
 		max_cpus = 0;
 }
 
+static inline void ack_APIC_irq (void)
+{
+	/* Clear the IPI */
+
+	/* Dummy read */
+	apic_read(APIC_SPIV);
+
+	/* Docs say use 0 for future compatibility */
+	apic_write(APIC_EOI, 0);
+}
 
 /* 
  *	Checksum an MP configuration block.
@@ -628,12 +638,10 @@
  	l|=(1<<8);		/* Enable */
  	apic_write(APIC_SPIV,l);
 
-#ifdef __SMP_PROF__
 	/*
 	 * Set up our APIC timer. 
 	 */
 	setup_APIC_clock ();
-#endif
 
  	sti();
 	/*
@@ -782,12 +790,10 @@
 
 	udelay(10);
 
-#ifdef __SMP_PROF__
 	/*
 	 * Set up our local APIC timer:
 	 */			
 	setup_APIC_clock ();
-#endif
 
 	/*
 	 *	Now scan the cpu present map and fire up the other CPUs.
@@ -1162,8 +1168,10 @@
 	 *	Just pray... there is nothing more we can do
 	 */
 	 
-	if(ct==1000)
+	if(ct==1000) {
 		printk("CPU #%d: previous IPI still not cleared after 10mS", p);
+		ack_APIC_irq ();
+	}
 		
 	/*
 	 *	Program the APIC to deliver the IPI
@@ -1298,10 +1306,7 @@
 asmlinkage void smp_reschedule_interrupt(void)
 {
 	need_resched=1;
-
-	/* Clear the IPI */
-	apic_read(APIC_SPIV);		/* Dummy read */
-	apic_write(APIC_EOI, 0);	/* Docs say use 0 for future compatibility */
+	ack_APIC_irq();
 }
 
 /*
@@ -1312,9 +1317,7 @@
 	if (clear_bit(smp_processor_id(), &smp_invalidate_needed))
 		local_flush_tlb();
 
-	/* Clear the IPI */
-	apic_read(APIC_SPIV);		/* Dummy read */
-	apic_write(APIC_EOI, 0);	/* Docs say use 0 for future compatibility */
+	ack_APIC_irq ();
 }	
 
 /*
@@ -1327,45 +1330,143 @@
 	for  (;;) ;
 }
 
-#ifdef __SMP_PROF__
+/*
+ * Platform specific profiling function.
+ * it builds a 'prof_shift' resolution EIP distribution histogram
+ *
+ * it's SMP safe.
+ */
+
+inline void x86_do_profile (unsigned long eip)
+{
+	if (prof_buffer && current->pid) {
+		extern int _stext;
+		eip -= (unsigned long) &_stext;
+		eip >>= prof_shift;
+		if (eip < prof_len)
+			atomic_inc(&prof_buffer[eip]);
+		else
+		/*
+		 * Dont ignore out-of-bounds EIP values silently,
+		 * put them into the last histogram slot, so if
+		 * present, they will show up as a sharp peak.
+		 */
+			atomic_inc(&prof_buffer[prof_len-1]);
+	}
+}
 
-extern void (*do_profile)(struct pt_regs *);
-static void (*default_do_profile)(struct pt_regs *) = NULL;
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
 
+extern void update_one_process(	struct task_struct *p,
+				unsigned long ticks, unsigned long user,
+				unsigned long system);
 /*
- *	APIC timer interrupt
+ * Local timer interrupt handler. It does both profiling and
+ * process statistics/rescheduling.
+ *
+ * We do profiling in every local tick, statistics/rescheduling
+ * happen only every 'profiling multiplier' ticks. The default
+ * multiplier is 1 and it can be changed by writing a 4 bytes multiplier
+ * value into /proc/profile.
  */
-void smp_apic_timer_interrupt(struct pt_regs * regs)
+static inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
 	int cpu = smp_processor_id();
-
-	if (!user_mode(regs)) {
-		unsigned long flags;
+	/*
+	 * Both the profiling function and the statistics
+	 * counters are SMP safe. We leave the APIC irq
+	 * unacked while updating the profiling info, thus
+	 * we cannot be interrupted by the same APIC interrupt.
+	 */
+	if (!user_mode(regs))
+		x86_do_profile (regs->eip);
+
+	if (!--prof_counter[cpu]) {
+		int user=0,system=0;
+		struct task_struct * p = current;
 
 		/*
-		 * local timer interrupt is not NMI yet, so
-		 * it's simple, we just aquire the global cli
-		 * lock to mess around with profiling info.
+		 * We mess around with thread statistics, but
+		 * since we are the CPU running it, we dont
+		 * have to lock it. We assume that switch_to()
+		 * protects 'current' against local irqs via __cli.
+		 *
+		 * kernel statistics counters are updated via atomic
+		 * operations.
 		 *
-		 * later, in the NMI version, we have to build
-		 * our own 'current' pointer (as we could have
-		 * interrupted code that just changes "current")
-		 * and have to lock profiling info between NMI
-		 * interrupts properly.
+		 * update_one_process() might send signals, thus
+		 * we have to get the irq lock for that one.
 		 */
-		save_flags(flags);
-		cli();
-		default_do_profile(regs);
-		restore_flags(flags);
+
+		if (user_mode(regs))
+			user=1;
+		else
+			system=1;
+
+		if (p->pid) {
+			unsigned long flags;
+	
+			save_flags(flags);
+			cli();
+			update_one_process(current, 1, user, system);
+			restore_flags(flags);
+
+			p->counter -= 1;
+			if (p->counter < 0) {
+				p->counter = 0;
+				need_resched = 1;
+			}
+			if (p->priority < DEF_PRIORITY)
+				atomic_add (user, &kstat.cpu_nice);
+			else
+				atomic_add (user, &kstat.cpu_user);
+
+			atomic_add (system, &kstat.cpu_system);
+		
+		} else {
+#ifdef __SMP_PROF__
+			if (test_bit(cpu,&smp_idle_map))
+				smp_idle_count[cpu]++;
+#endif
+			/*
+			 * This is a hack until we have need_resched[]
+			 */
+			if (read_smp_counter(&smp_process_available))
+				need_resched=1;
+		}
+
+		prof_counter[cpu]=prof_multiplier[cpu];
 	}
 
+#ifdef __SMP_PROF__
+	smp_local_timer_ticks[cpu]++;
+#endif
 	/*
-	 * this is safe outside the lock.
-	 */ 
-	smp_apic_timer_ticks[cpu]++;
+	 * We take the 'long' return path, and there every subsystem
+	 * grabs the apropriate locks (kernel lock/ irq lock).
+	 *
+	 * FIXME: we want to decouple profiling from the 'long path'.
+	 *
+	 * Currently this isnt too much of an issue (performancewise),
+	 * we can take more than 100K local irqs per second on a 100 MHz P5.
+	 * [ although we notice need_resched too early, thus the way we
+	 *   schedule (deliver signals and handle bhs) changes. ]
+	 *
+	 * Possibly we could solve these problems with 'smart irqs'.
+	 */
+}
+
+/*
+ * Local APIC timer interrupt. This is the most natural way for doing
+ * local interrupts, but local timer interrupts can be emulated by
+ * broadcast interrupts too. [in case the hw doesnt support APIC timers]
+ */
+void smp_apic_timer_interrupt(struct pt_regs * regs)
+{
+	smp_local_timer_interrupt(regs);
 
-	apic_read (APIC_SPIV);
-	apic_write (APIC_EOI, 0);
+	ack_APIC_irq ();
 }
 
 /*
@@ -1373,9 +1474,8 @@
  * per second. We assume that the caller has already set up the local
  * APIC at apic_addr.
  *
- * Later we might want to split HZ into two parts: introduce
- * PROFILING_HZ and scheduling HZ. The APIC timer is not exactly
- * sync with the external timer chip, it closely follows bus clocks.
+ * The APIC timer is not exactly sync with the external timer chip, it
+ * closely follows bus clocks.
  */
 
 #define RTDSC(x)	__asm__ __volatile__ (  ".byte 0x0f,0x31" \
@@ -1407,15 +1507,13 @@
  *
  * We are strictly in irqs off mode here, as we do not want to
  * get an APIC interrupt go off accidentally.
+ *
+ * We do reads before writes even if unnecessary, to get around the
+ * APIC double write bug.
  */
 
 #define APIC_DIVISOR 16
 
-/*
- * We do reads before writes even if unnecessary, to get around the
- * APIC double write 'bug'.
- */
-
 void setup_APIC_timer (unsigned int clocks)
 {
 	unsigned long lvtt1_value; 
@@ -1462,14 +1560,14 @@
 	 * chipset timer can cause.
 	 */
 
-	} while (delta<1000);
+	} while (delta<300);
 }
 
 /*
  * In this function we calibrate APIC bus clocks to the external
- * timer here. Unfortunately we cannot use jiffies and
- * the timer irq to calibrate, since some later bootup
- * code depends on getting the first irq? Ugh.
+ * timer. Unfortunately we cannot use jiffies and the timer irq
+ * to calibrate, since some later bootup code depends on getting
+ * the first irq? Ugh.
  *
  * We want to do the calibration only once since we
  * want to have local timer irqs syncron. CPUs connected
@@ -1481,8 +1579,7 @@
 int calibrate_APIC_clock (void)
 {
 	unsigned long long t1,t2;
-	unsigned long tt1,tt2;
-	unsigned int prev_count, curr_count;
+	long tt1,tt2;
 	long calibration_result;
 
 	printk("calibrating APIC timer ... ");
@@ -1518,15 +1615,13 @@
 
 	/*
 	 * The APIC bus clock counter is 32 bits only, it
-	 * might have overflown:
+	 * might have overflown, but note that we use signed
+	 * longs, thus no extra care needed.
+	 *
+	 * underflown to be exact, as the timer counts down ;)
 	 */
-	if (tt2<tt1) {
-		unsigned long tmp = tt2;
-		tt2=tt1;
-		tt1=tmp;
-	}
 
-	calibration_result = (tt2-tt1)*APIC_DIVISOR;
+	calibration_result = (tt1-tt2)*APIC_DIVISOR;
 
 	printk("\n..... %ld CPU clocks in 1 timer chip tick.\n",
 			 (unsigned long)(t2-t1));
@@ -1546,32 +1641,27 @@
 	return calibration_result;
 }
 
+static unsigned int calibration_result;
+
 void setup_APIC_clock (void)
 {
+	int cpu = smp_processor_id();
 	unsigned long flags; 
 
 	static volatile int calibration_lock;
-	static unsigned int calibration_result;
 
-	return;
 	save_flags(flags);
 	cli();
 
 	printk("setup_APIC_clock() called.\n");
 
 	/*
-	 * We use a private profiling function. (This is preparation
-	 * for NMI local timer interrupts.)
-	 *
 	 * [ setup_APIC_clock() is called from all CPUs, but we want
 	 *   to do this part of the setup only once ... and it fits
 	 *   here best ]
 	 */
 	if (!set_bit(0,&calibration_lock)) {
 
-		default_do_profile = do_profile;
-		do_profile = NULL;
-
 		calibration_result=calibrate_APIC_clock();
 		/*
 	 	 * Signal completion to the other CPU[s]:
@@ -1587,13 +1677,58 @@
 		printk("done, continuing.\n");
 	}
 
+/*
+ * Now set up the timer for real. Profiling multiplier is 1.
+ */
 	setup_APIC_timer (calibration_result);
 
+	prof_counter[cpu] = prof_multiplier[cpu] = 1;
+
+	/*
+	 * FIXME: i sporadically see booting problems (keyboard irq is
+	 * lost, looks like the  timer irq isnt working or some irq
+	 * lock is messed up). Once we reboot the bug doesnt showu
+	 * up anymore.
+	 *
+	 * i'm quite certain it's a timing problem/race condition in
+	 * the bootup logic, not a hw bug. It might have been gone
+	 * meanwhile, tell me if you see it.
+	 */
+
+	ack_APIC_irq ();
+
+	restore_flags(flags);
+}
+
+/*
+ * the frequency of the profiling timer can be changed
+ * by writing 4 bytes into /proc/profile.
+ *
+ * usually you want to run this on all CPUs ;)
+ */
+int setup_profiling_timer (unsigned int multiplier)
+{
+	int cpu = smp_processor_id();
+	unsigned long flags;
+
+	/*
+	 * Sanity check. [at least 500 APIC cycles should be
+	 * between APIC interrupts as a rule of thumb, rather be
+	 * careful as irq flooding renders the system unusable]
+	 */
+	if ( (!multiplier) || (calibration_result/multiplier < 500))
+		return -EINVAL;
+
+	save_flags(flags);
+	cli();
+	setup_APIC_timer (calibration_result/multiplier);
+	prof_multiplier[cpu]=multiplier;
 	restore_flags(flags);
+
+	return 0;
 }
 
 #undef APIC_DIVISOR
 #undef RTDSC
 
-#endif
 
diff -u --recursive --new-file v2.1.33/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.1.33/linux/arch/i386/kernel/time.c	Mon Apr  7 11:35:29 1997
+++ linux/arch/i386/kernel/time.c	Mon Apr 14 11:52:23 1997
@@ -364,6 +364,29 @@
 /* last time the cmos clock got updated */
 static long last_rtc_update = 0;
 
+
+/*
+ * Move this to a header file - right now it shows
+ * up both here and in smp.c
+ */
+inline void x86_do_profile (unsigned long eip)
+{
+	if (prof_buffer && current->pid) {
+		extern int _stext;
+		eip -= (unsigned long) &_stext;
+		eip >>= prof_shift;
+		if (eip < prof_len)
+			atomic_inc(&prof_buffer[eip]);
+		else
+		/*
+		 * Dont ignore out-of-bounds EIP values silently,
+		 * put them into the last histogram slot, so if
+		 * present, they will show up as a sharp peak.
+		 */
+			atomic_inc(&prof_buffer[prof_len-1]);
+	}
+}
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
@@ -371,6 +394,14 @@
 static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
+/*
+ * In the SMP case we use the local APIC timer interrupt to do the
+ * profiling.
+ */
+#ifndef __SMP__
+	if (!user_mode(regs))
+		x86_do_profile(regs->eip);
+#endif
 
 	/*
 	 * If we have an externally synchronized Linux clock, then update
@@ -495,6 +526,7 @@
 }
 
 static struct irqaction irq0  = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+
 
 void time_init(void)
 {
diff -u --recursive --new-file v2.1.33/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.33/linux/arch/i386/mm/init.c	Sun Apr 13 10:18:20 1997
+++ linux/arch/i386/mm/init.c	Mon Apr 14 09:31:08 1997
@@ -79,10 +79,10 @@
 		total++;
 		if (PageReserved(mem_map+i))
 			reserved++;
-		else if (!mem_map[i].count)
+		else if (!atomic_read(&mem_map[i].count))
 			free++;
 		else
-			shared += mem_map[i].count-1;
+			shared += atomic_read(&mem_map[i].count) - 1;
 	}
 	printk("%d pages of RAM\n",total);
 	printk("%d free pages\n",free);
@@ -259,7 +259,7 @@
 				datapages++;
 			continue;
 		}
-		mem_map[MAP_NR(tmp)].count = 1;
+		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (!initrd_start || (tmp < initrd_start || tmp >=
 		    initrd_end))
@@ -316,9 +316,9 @@
 		if (PageReserved(mem_map+i))
 			continue;
 		val->totalram++;
-		if (!mem_map[i].count)
+		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += mem_map[i].count-1;
+		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.1.33/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.33/linux/arch/m68k/mm/init.c	Sun Jan 26 02:07:05 1997
+++ linux/arch/m68k/mm/init.c	Mon Apr 14 09:31:08 1997
@@ -71,12 +71,12 @@
 	total++;
 	if (PageReserved(mem_map+i))
 	    reserved++;
-	else if (!mem_map[i].count)
+	else if (!atomic_read(&mem_map[i].count))
 	    free++;
-	else if (mem_map[i].count == 1)
+	else if (atomic_read(&mem_map[i].count) == 1)
 	    nonshared++;
 	else
-	    shared += mem_map[i].count-1;
+	    shared += atomic_read(&mem_map[i].count) - 1;
     }
     printk("%d pages of RAM\n",total);
     printk("%d free pages\n",free);
@@ -463,7 +463,7 @@
 				datapages++;
 			continue;
 		}
-		mem_map[MAP_NR(tmp)].count = 1;
+		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (!initrd_start ||
 		    (tmp < (initrd_start & PAGE_MASK) || tmp >= initrd_end))
@@ -495,9 +495,9 @@
 	if (PageReserved(mem_map+i))
 	    continue;
 	val->totalram++;
-	if (!mem_map[i].count)
+	if (!atomic_read(&mem_map[i].count))
 	    continue;
-	val->sharedram += mem_map[i].count-1;
+	val->sharedram += atomic_read(&mem_map[i].count) - 1;
     }
     val->totalram <<= PAGE_SHIFT;
     val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.1.33/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
--- v2.1.33/linux/arch/mips/kernel/irq.c	Thu Feb 29 21:50:38 1996
+++ linux/arch/mips/kernel/irq.c	Mon Apr 14 09:31:08 1997
@@ -397,5 +397,5 @@
 		bh_base[i].data = NULL;
 	}
 	bh_active = 0;
-	intr_count = 0;
+	atomic_set(&intr_count, 0);
 }
diff -u --recursive --new-file v2.1.33/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c
--- v2.1.33/linux/arch/mips/mm/init.c	Sun Jan 26 02:07:05 1997
+++ linux/arch/mips/mm/init.c	Mon Apr 14 09:31:08 1997
@@ -208,10 +208,10 @@
 		total++;
 		if (mem_map[i].reserved)
 			reserved++;
-		else if (!mem_map[i].count)
+		else if (!atomic_read(&mem_map[i].count))
 			free++;
 		else
-			shared += mem_map[i].count-1;
+			shared += atomic_read(&mem_map[i].count) - 1;
 	}
 	printk("%d pages of RAM\n", total);
 	printk("%d free pages\n", free);
@@ -268,7 +268,7 @@
 				datapages++;
 			continue;
 		}
-		mem_map[MAP_NR(tmp)].count = 1;
+		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
 		free_page(tmp);
 	}
 	tmp = nr_free_pages << PAGE_SHIFT;
@@ -299,9 +299,9 @@
 		if (mem_map[i].reserved)
 			continue;
 		val->totalram++;
-		if (!mem_map[i].count)
+		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += mem_map[i].count-1;
+		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.1.33/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.1.33/linux/arch/ppc/kernel/irq.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/kernel/irq.c	Mon Apr 14 09:31:08 1997
@@ -161,7 +161,7 @@
 process_IRQ(int irq, int _irq, struct pt_regs *regs)
 {
   struct irq_action *action;
-  intr_count++;
+  atomic_inc(&intr_count);
   if (irq < 16)
   {
     /* Mask interrupt */
@@ -242,7 +242,7 @@
   {
     BeBox_enable_irq(irq);
   }
-  intr_count--;
+  atomic_dec(&intr_count);
 }
 
 asmlinkage inline void handle_IRQ(struct pt_regs *regs)
diff -u --recursive --new-file v2.1.33/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.33/linux/arch/ppc/mm/init.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/ppc/mm/init.c	Mon Apr 14 09:31:08 1997
@@ -72,10 +72,10 @@
     total++;
     if (PageReserved(mem_map+i))
       reserved++;
-    else if (!mem_map[i].count)
+    else if (!atomic_read(&mem_map[i].count))
       free++;
     else
-      shared += mem_map[i].count-1;
+      shared += atomic_read(&mem_map[i].count) - 1;
   }
   printk("%lu pages of RAM\n",total);
   printk("%lu free pages\n",free);
@@ -161,7 +161,7 @@
 	  continue;
 	}
       clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
-      mem_map[MAP_NR(tmp)].count = 1;
+      atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
       free_page(tmp);
     }
   tmp = nr_free_pages << PAGE_SHIFT;
@@ -192,9 +192,9 @@
 		if (PageReserved(mem_map+i))
 			continue;
 		val->totalram++;
-		if (!mem_map[i].count)
+		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += mem_map[i].count-1;
+		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.1.33/linux/arch/sparc/Makefile	Mon Apr  7 11:35:29 1997
+++ linux/arch/sparc/Makefile	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.26 1997/03/04 16:26:50 jj Exp $
+# $Id: Makefile,v 1.27 1997/04/07 06:54:08 davem Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -33,7 +33,8 @@
 
 ifdef CONFIG_AP1000
 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp
-CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o $(TOPDIR)/mpp/mpplib.o $(CORE_FILES) 
+CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \
+	      $(TOPDIR)/mpp/mpplib.o $(CORE_FILES) 
 DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a
 CFLAGS := $(CFLAGS) -D__MPP__=1
 endif
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.1.33/linux/arch/sparc/config.in	Mon Apr  7 11:35:29 1997
+++ linux/arch/sparc/config.in	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.33 1997/02/05 14:25:01 tdyas Exp $
+# $Id: config.in,v 1.35 1997/04/07 06:54:09 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.33/linux/arch/sparc/defconfig	Mon Apr  7 11:35:29 1997
+++ linux/arch/sparc/defconfig	Mon Apr 14 09:31:08 1997
@@ -49,6 +49,7 @@
 CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
 # CONFIG_SUN_BPP is not set
+# CONFIG_SUN_VIDEOPIX is not set
 
 #
 # Linux/SPARC audio subsystem (EXPERIMENTAL)
@@ -187,6 +188,9 @@
 CONFIG_ROOT_NFS=y
 CONFIG_RNFS_BOOTP=y
 CONFIG_RNFS_RARP=y
+CONFIG_NFSD=m
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
@@ -195,6 +199,7 @@
 CONFIG_SYSV_FS=m
 CONFIG_AFFS_FS=m
 CONFIG_ROMFS_FS=m
+CONFIG_AUTOFS_FS=m
 CONFIG_AMIGA_PARTITION=y
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v2.1.33/linux/arch/sparc/kernel/Makefile	Mon Mar 17 14:54:20 1997
+++ linux/arch/sparc/kernel/Makefile	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.38 1997/03/04 16:26:29 jj Exp $
+# $Id: Makefile,v 1.39 1997/04/01 02:21:44 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -15,6 +15,7 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
 
+CHECKASM_CC	=	$(CC) -D__SMP__
 
 else
 
@@ -24,7 +25,7 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
 
-
+CHECKASM_CC	=	$(CC)
 endif
 
 all: kernel.o head.o
@@ -62,14 +63,14 @@
 
 check_asm: dummy
 	@echo "#include <linux/sched.h>" > tmp.c
-	$(CC) -E tmp.c -o tmp.i
+	$(CHECKASM_CC) -E tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include <linux/sched.h>" >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c
 	$(SH) ./check_asm.sh task tmp.i check_asm.c
 	$(SH) ./check_asm.sh mm tmp.i check_asm.c
 	$(SH) ./check_asm.sh thread tmp.i check_asm.c
 	@echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c
 	@rm -f tmp.[ci]
-	$(CC) -o check_asm check_asm.c
+	$(CHECKASM_CC) -o check_asm check_asm.c
 	./check_asm > asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi
 	@rm -f check_asm check_asm.c
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v2.1.33/linux/arch/sparc/kernel/entry.S	Mon Mar 17 14:54:20 1997
+++ linux/arch/sparc/kernel/entry.S	Mon Apr 14 09:31:08 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.133 1997/03/04 16:26:22 jj Exp $
+/* $Id: entry.S,v 1.137 1997/04/14 05:38:17 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -288,28 +288,11 @@
 	SAVE_ALL
 
 #ifdef __SMP__
-	cmp	%l7, 13
-	bne	1f
-	 nop
-
-	/* This is where we catch the level 13 reschedule soft-IRQ. */
-	GET_PROCESSOR_MID(o3, o2)
-	set	C_LABEL(sun4m_interrupts), %l5
-	ld	[%l5], %o5
-	sethi	%hi(0x20000000), %o4
-	sll	%o3, 12, %o3
-	add	%o5, %o3, %o5
-	ld	[%o5], %o1		! read processor irq pending reg
-	andcc	%o1, %o4, %g0
-	be	1f
+	cmp	%l7, 12
+	bgu	maybe_smp_msg
 	 nop
-
-	b,a	linux_trap_ipi13_sun4m
-
-1:	
-
 #endif
-
+real_irq_continue:
 	or	%l0, PSR_PIL, %g2
 	wr	%g2, 0x0, %psr
 	WRITE_PAUSE
@@ -318,10 +301,102 @@
 	mov	%l7, %o0		! irq level
 	call	C_LABEL(handler_irq)
 	 add	%sp, REGWIN_SZ, %o1	! pt_regs ptr
+
+#if 1 /* ndef __SMP__ */ /* You don't want to know... -DaveM */
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
+#endif
+
+	RESTORE_ALL
+
+#ifdef __SMP__
+	/* Here is where we check for possible SMP IPI passed to us
+	 * on some level other than 15 which is the NMI and only used
+	 * for cross calls.  That has a seperate entry point below.
+	 */
+maybe_smp_msg:
+	GET_PROCESSOR_MID(o3, o2)
+	set	C_LABEL(sun4m_interrupts), %l5
+	ld	[%l5], %o5
+	sethi	%hi(0x60000000), %o4
+	sll	%o3, 12, %o3
+	ld	[%o5 + %o3], %o1
+	andcc	%o1, %o4, %g0
+	be	real_irq_continue
+	 cmp	%l7, 13
+	add	%o5, %o3, %o5
+	bne,a	1f
+	 sethi	%hi(0x40000000), %o2
+	sethi	%hi(0x20000000), %o2
+1:
+	st	%o2, [%o5 + 0x4]
+	WRITE_PAUSE
+	ld	[%o5], %g0
+	WRITE_PAUSE
+	or	%l0, PSR_PIL, %l4
+	wr	%l4, 0x0, %psr
+	WRITE_PAUSE
+	wr	%l4, PSR_ET, %psr
+	WRITE_PAUSE
+	cmp	%l7, 13
+	bne	2f
+	 nop
+	call	C_LABEL(smp_reschedule_irq)
+	 add	%o7, 8, %o7
+2:
+	call	C_LABEL(smp_stop_cpu_irq)
+	 nop
+	RESTORE_ALL
 
+	.align	4
+	.globl	linux_trap_ipi15_sun4m
+linux_trap_ipi15_sun4m:
+	SAVE_ALL
+	sethi	%hi(0x80000000), %o2
+	GET_PROCESSOR_MID(o0, o1)
+	set	C_LABEL(sun4m_interrupts), %l5
+	ld	[%l5], %o5
+	sll	%o0, 12, %o0
+	add	%o5, %o0, %o5
+	ld	[%o5], %o3
+	andcc	%o3, %o2, %g0
+	be	1f			! Must be an NMI async memory error
+	 st	%o2, [%o5 + 4]
+	WRITE_PAUSE
+	ld	[%o5], %g0
+	WRITE_PAUSE
+	or	%l0, PSR_PIL, %l4
+	wr	%l4, 0x0, %psr
+	WRITE_PAUSE
+	wr	%l4, PSR_ET, %psr
+	WRITE_PAUSE
+	call	C_LABEL(smp_cross_call_irq)
+	 nop
+	b	ret_trap_lockless_ipi
+	 clr	%l6
+1:
+	/* NMI async memory error handling. */
+	sethi	%hi(0x80000000), %l4
+	sethi	%hi(0x4000), %o3
+	sub	%o5, %o0, %o5
+	add	%o5, %o3, %l5
+	st	%l4, [%l5 + 0xc]
+	WRITE_PAUSE
+	ld	[%l5], %g0
+	WRITE_PAUSE
+	or	%l0, PSR_PIL, %l4
+	wr	%l4, 0x0, %psr
+	WRITE_PAUSE
+	wr	%l4, PSR_ET, %psr
+	WRITE_PAUSE
+	call	C_LABEL(sun4m_nmi)
+	 nop
+	st	%l4, [%l5 + 0x8]
+	WRITE_PAUSE
+	ld	[%l5], %g0
+	WRITE_PAUSE
 	RESTORE_ALL
+#endif /* __SMP__ */
 
 	/* This routine handles illegal instructions and privileged
 	 * instruction attempts from user code.
@@ -671,107 +746,6 @@
 
 	RESTORE_ALL
 
-#ifdef __SMP__
-	.align	4
-	.globl	linux_trap_ipi13_sun4m
-linux_trap_ipi13_sun4m:
-	sethi	%hi(0x20000000), %o2
-	GET_PROCESSOR_MID(o0, o1)
-	set	C_LABEL(sun4m_interrupts), %l5
-	ld	[%l5], %o5
-	sll	%o0, 12, %o0
-	add	%o5, %o0, %o5
-	st	%o2, [%o5 + 4]
-	WRITE_PAUSE
-
-	ld	[%o5], %g0
-	WRITE_PAUSE
-
-	/* IRQ's off else we deadlock. */
-	or	%l0, PSR_PIL, %l4
-	wr	%l4, 0x0, %psr
-	WRITE_PAUSE
-
-	wr	%l4, PSR_ET, %psr
-	WRITE_PAUSE
-
-	call	C_LABEL(smp_reschedule_irq)
-	 nop
-
-	RESTORE_ALL
-
-	.align	4
-	.globl	linux_trap_ipi15_sun4m
-linux_trap_ipi15_sun4m:
-	SAVE_ALL
-
-	/* First check for hard NMI memory error. */
-	sethi	%hi(0xf0000000), %o2
-	set	C_LABEL(sun4m_interrupts), %l5
-	set	0x4000, %o3
-	ld	[%l5], %l5
-	add	%l5, %o3, %l5
-	ld	[%l5], %l6
-	andcc	%o2, %l6, %o2
-	be	1f
-	 nop
-
-	/* Asynchronous fault, why you little ?!#&%@... */
-	sethi	%hi(0x80000000), %o2
-	st	%o2, [%l5 + 0xc]
-	WRITE_PAUSE
-	ld	[%l5], %g0
-	WRITE_PAUSE
-
-	/* All interrupts are off... now safe to enable traps
-	 * and call C-code.
-	 */	
-	or	%l0, PSR_PIL, %l4	! I am very paranoid...
-	wr	%l4, 0x0, %psr
-	WRITE_PAUSE
-	wr	%l4, PSR_ET, %psr
-	WRITE_PAUSE
-	call	C_LABEL(sun4m_nmi)
-	 nop
-
-	sethi	%hi(0x80000000), %o2
-	st	%o2, [%l5 + 0x8]
-	WRITE_PAUSE
-	ld	[%l5], %g0
-	WRITE_PAUSE
-
-	RESTORE_ALL
-
-1:
-	sethi	%hi(0x80000000), %o2
-	GET_PROCESSOR_MID(o0, o1)
-	set	C_LABEL(sun4m_interrupts), %l5
-	ld	[%l5], %o5
-	sll	%o0, 12, %o0
-	add	%o5, %o0, %o5
-	st	%o2, [%o5 + 4]
-	WRITE_PAUSE
-
-	ld	[%o5], %g0
-	WRITE_PAUSE
-
-	/* IRQ's off else we deadlock. */
-	or	%l0, PSR_PIL, %l4
-	wr	%l4, 0x0, %psr
-	WRITE_PAUSE
-
-	wr	%l4, PSR_ET, %psr
-	WRITE_PAUSE
-
-	call	C_LABEL(smp_message_irq)
-	 nop
-
-	b	ret_trap_lockless_ipi
-	 clr	%l6
-
-#endif
-
-
 	.align	4
 	.globl	C_LABEL(invalid_segment_patch1_ff)
 	.globl	C_LABEL(invalid_segment_patch2_ff)
@@ -839,7 +813,22 @@
 	be	sun4c_fault_fromuser
 	 and	%l5, %l4, %l5
 
-	lduba	[%l5] ASI_SEGMAP, %l4
+	/* Test for NULL pte_t * in vmalloc area. */
+	sethi   %hi(SUN4C_VMALLOC_START), %l4
+	cmp     %l5, %l4
+	blu,a   C_LABEL(invalid_segment_patch1)
+	 lduba  [%l5] ASI_SEGMAP, %l4
+
+	srl     %l5, SUN4C_PGDIR_SHIFT, %l6
+	sethi   %hi(C_LABEL(swapper_pg_dir)), %l4
+	or      %l4, %lo(C_LABEL(swapper_pg_dir)), %l4
+	sll     %l6, 2, %l6
+	ld      [%l4 + %l6], %l4
+	andcc   %l4, PAGE_MASK, %g0
+
+	be      sun4c_fault_fromuser
+	 lduba  [%l5] ASI_SEGMAP, %l4
+
 C_LABEL(invalid_segment_patch1):
 	cmp	%l4, 0x7f
 	bne	1f
@@ -1268,11 +1257,9 @@
 #ifdef __SMP__
 	.globl	C_LABEL(ret_from_smpfork)
 C_LABEL(ret_from_smpfork):
-	mov	NO_PROC_ID, %o5
-	sethi	%hi(C_LABEL(klock_info)), %o4
-	or	%o4, %lo(C_LABEL(klock_info)), %o4
-	stb	%o5, [%o4 + 1]
-	stb	%g0, [%o4 + 0]
+	/* Nowadays all we need to do is drop the scheduler lock. */
+	sethi	%hi(C_LABEL(scheduler_lock)), %o4
+	stb	%g0, [%o4 + %lo(C_LABEL(scheduler_lock))]
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 	b	C_LABEL(ret_sys_call)
@@ -1605,6 +1592,7 @@
 #else
 	GET_PROCESSOR_OFFSET(o4)
 	set	C_LABEL(cpu_data), %o3
+	sll	%o4, 1, %o4
 	call	.umul
 	 ld	[%o3 + %o4], %o1
 #endif
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v2.1.33/linux/arch/sparc/kernel/ioport.c	Sat Nov  9 00:11:39 1996
+++ linux/arch/sparc/kernel/ioport.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.22 1996/10/11 00:59:46 davem Exp $
+/* $Id: ioport.c,v 1.24 1997/04/10 03:02:32 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -45,8 +45,8 @@
  *  The virtual address where the mapping actually took place.
  */
 
-void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
-		      int bus_type, int rdonly)
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+		      u32 bus_type, int rdonly)
 {
 	unsigned long vaddr, base_address;
 	unsigned long addr = (unsigned long) address;
@@ -110,7 +110,7 @@
  * now have to know the peculiarities of where to read the Lance data
  * from. (for example)
  */
-void *sparc_dvma_malloc (int len, char *name)
+void *_sparc_dvma_malloc (int len, char *name)
 {
 	unsigned long vaddr, base_address;
 
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.1.33/linux/arch/sparc/kernel/irq.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/kernel/irq.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.59 1997/01/06 06:52:21 davem Exp $
+/*  $Id: irq.c,v 1.66 1997/04/14 05:38:21 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -37,6 +37,9 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
 
 /*
  * Dave Redman (djhr@tadpole.co.uk)
@@ -66,6 +69,8 @@
 
 void (*enable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
 void (*disable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
+void (*enable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
+void (*disable_pil_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic;
 void (*clear_clock_irq)( void ) = irq_panic;
 void (*clear_profile_irq)( void ) = irq_panic;
 void (*load_profile_irq)( unsigned int ) =  (void (*)(unsigned int)) irq_panic;
@@ -178,6 +183,201 @@
         restore_flags(flags);
 }
 
+/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
+unsigned int local_irq_count[NR_CPUS];
+atomic_t __sparc_bh_counter;
+
+#ifdef __SMP__
+/* SMP interrupt locking on Sparc. */
+
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT;
+
+#define irq_active(cpu) \
+	(atomic_read(&global_irq_count) != local_irq_count[cpu])
+
+static unsigned long previous_irqholder;
+
+#define INIT_STUCK 10000000
+
+#define STUCK \
+if (!--stuck) { \
+	printk("wait_on_irq CPU#%d stuck at %08lx, waiting for [%08lx:%x] " \
+	       "(local=[%d(%x:%x:%x:%x)], global=[%d:%x]) ", \
+	       cpu, where, previous_irqholder, global_irq_holder, \
+	       local_count, local_irq_count[0], local_irq_count[1], \
+	       local_irq_count[2], local_irq_count[3], \
+	       atomic_read(&global_irq_count), global_irq_lock); \
+	printk("g[%d:%x]\n", atomic_read(&global_irq_count), global_irq_lock); \
+	stuck = INIT_STUCK; \
+}
+
+static inline void wait_on_irq(int cpu, unsigned long where)
+{
+	int stuck = INIT_STUCK;
+	int local_count = local_irq_count[cpu];
+
+	while(local_count != atomic_read(&global_irq_count)) {
+		atomic_sub(local_count, &global_irq_count);
+		spin_unlock(&global_irq_lock);
+		while(1) {
+			STUCK;
+			if(atomic_read(&global_irq_count))
+				continue;
+			if(global_irq_lock)
+				continue;
+			if(spin_trylock(&global_irq_lock))
+				break;
+		}
+		atomic_add(local_count, &global_irq_count);
+	}
+}
+
+/* There has to be a better way. */
+void synchronize_irq(void)
+{
+	int cpu = smp_processor_id();
+	int local_count = local_irq_count[cpu];
+
+	if(local_count != atomic_read(&global_irq_count)) {
+		unsigned long flags;
+
+		/* See comment below at __global_save_flags to understand
+		 * why we must do it this way on Sparc.
+		 */
+		save_and_cli(flags);
+		restore_flags(flags);
+	}
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
+{
+	int stuck = INIT_STUCK;
+
+	if(!spin_trylock(&global_irq_lock)) {
+		if((unsigned char) cpu == global_irq_holder)
+			return;
+		do {
+			do {
+				STUCK;
+				barrier();
+			} while(global_irq_lock);
+		} while(!spin_trylock(&global_irq_lock));
+	}
+	wait_on_irq(cpu, where);
+	global_irq_holder = cpu;
+	previous_irqholder = where;
+}
+
+void __global_cli(void)
+{
+	int cpu = smp_processor_id();
+	unsigned long where;
+
+	__asm__ __volatile__("mov %%i7, %0\n\t" : "=r" (where));
+	__cli();
+	get_irqlock(cpu, where);
+}
+
+void __global_sti(void)
+{
+	release_irqlock(smp_processor_id());
+	__sti();
+}
+
+/* Yes, I know this is broken, but for the time being...
+ *
+ * On Sparc we must differentiate between real local processor
+ * interrupts being disabled and global interrupt locking, this
+ * is so that interrupt handlers which call this stuff don't get
+ * interrupts turned back on when restore_flags() runs because
+ * our current drivers will be very surprised about this, yes I
+ * know they need to be fixed... -DaveM
+ */
+unsigned long __global_save_flags(void)
+{
+	unsigned long flags, retval = 0;
+
+	__save_flags(flags);
+	if(global_irq_holder == (unsigned char) smp_processor_id())
+		retval |= 1;
+	if(flags & PSR_PIL)
+		retval |= 2;
+	return retval;
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+	if(flags & 1) {
+		__global_cli();
+	} else {
+		release_irqlock(smp_processor_id());
+
+		if(flags & 2)
+			__cli();
+		else
+			__sti();
+	}
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) { \
+	printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n", \
+	       irq, cpu, global_irq_holder); \
+	stuck = INIT_STUCK; \
+}
+
+static void irq_enter(int cpu, int irq)
+{
+	extern void smp_irq_rotate(int cpu);
+	int stuck = INIT_STUCK;
+
+	smp_irq_rotate(cpu);
+	hardirq_enter(cpu);
+	while(global_irq_lock) {
+		if((unsigned char) cpu == global_irq_holder) {
+			printk("YEEEE Local interrupts enabled, global disabled\n");
+			break;
+		}
+		STUCK;
+		barrier();
+	}
+}
+
+static void irq_exit(int cpu, int irq)
+{
+	__cli();
+	hardirq_exit(cpu);
+	release_irqlock(cpu);
+}
+
+#else /* !__SMP__ */
+
+#define irq_enter(cpu, irq)	(local_irq_count[cpu]++)
+#define irq_exit(cpu, irq)	(local_irq_count[cpu]--)
+
+#endif /* __SMP__ */
+
 void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
 {
         int i;
@@ -204,11 +404,11 @@
 void handler_irq(int irq, struct pt_regs * regs)
 {
 	struct irqaction * action;
-	unsigned int cpu_irq;
+	unsigned int cpu_irq = irq & NR_IRQS;
+	int cpu = smp_processor_id();
 	
-	lock_kernel();
-	intr_count++;
-	cpu_irq = irq & NR_IRQS;
+	disable_pil_irq(cpu_irq);
+	irq_enter(cpu, irq);
 	action = *(cpu_irq + irq_action);
 	kstat.interrupts[cpu_irq]++;
 	do {
@@ -217,8 +417,8 @@
 		action->handler(irq, action->dev_id, regs);
 		action = action->next;
 	} while (action);
-	intr_count--;
-	unlock_kernel();
+	irq_exit(cpu, irq);
+	enable_pil_irq(cpu_irq);
 }
 
 #ifdef CONFIG_BLK_DEV_FD
@@ -226,11 +426,13 @@
 
 void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
-	lock_kernel();
-	intr_count++;
+	int cpu = smp_processor_id();
+
+	disable_pil_irq(irq);
+	irq_enter(cpu, irq);
 	floppy_interrupt(irq, dev_id, regs);
-	intr_count--;
-	unlock_kernel();
+	irq_exit(cpu, irq);
+	disable_pil_irq(irq);
 }
 #endif
 
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/muldiv.c linux/arch/sparc/kernel/muldiv.c
--- v2.1.33/linux/arch/sparc/kernel/muldiv.c	Fri Dec 13 01:37:30 1996
+++ linux/arch/sparc/kernel/muldiv.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/* $Id: muldiv.c,v 1.3 1996/11/26 10:00:28 jj Exp $
+/* $Id: muldiv.c,v 1.4 1997/04/11 00:42:08 davem Exp $
  * muldiv.c: Hardware multiply/division illegal instruction trap
  *		for sun4c/sun4 (which do not have those instructions)
  *
@@ -120,7 +120,10 @@
 			"call	.umul\n\t"
 			" mov	%1, %%o1\n\t"
 			"mov	%%o0, %0\n\t"
-			"mov	%%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) : : "o0", "o1", "o2", "o3", "o4", "o5", "o7");
+			"mov	%%o1, %1\n\t"
+			: "=r" (rs1), "=r" (rs2)
+		        :
+			: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc");
 #ifdef DEBUG_MULDIV
 		printk ("0x%x%08x\n", rs2, rs1);
 #endif
@@ -138,7 +141,10 @@
 			"call	.mul\n\t"
 			" mov	%1, %%o1\n\t"
 			"mov	%%o0, %0\n\t"
-			"mov	%%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) : : "o0", "o1", "o2", "o3", "o4", "o5", "o7");
+			"mov	%%o1, %1\n\t"
+			: "=r" (rs1), "=r" (rs2)
+			:
+			: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc");
 #ifdef DEBUG_MULDIV
 		printk ("0x%x%08x\n", rs2, rs1);
 #endif
@@ -165,7 +171,11 @@
 			"call	__udivdi3\n\t"
 			" mov	%1, %%o3\n\t"
 			"mov	%%o1, %0\n\t"
-			"mov	%%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) : "r" (regs->y) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3");
+			"mov	%%o0, %1\n\t"
+			: "=r" (rs1), "=r" (rs2)
+			: "r" (regs->y)
+			: "o0", "o1", "o2", "o3", "o4", "o5", "o7",
+			  "g1", "g2", "g3", "cc");
 #ifdef DEBUG_MULDIV
 		printk ("0x%x\n", rs1);
 #endif
@@ -190,7 +200,11 @@
 			"call	__divdi3\n\t"
 			" mov	%1, %%o3\n\t"
 			"mov	%%o1, %0\n\t"
-			"mov	%%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) : "r" (regs->y) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3");
+			"mov	%%o0, %1\n\t"
+			: "=r" (rs1), "=r" (rs2)
+			: "r" (regs->y)
+			: "o0", "o1", "o2", "o3", "o4", "o5", "o7",
+			  "g1", "g2", "g3", "cc");
 #ifdef DEBUG_MULDIV
 		printk ("0x%x\n", rs1);
 #endif
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.1.33/linux/arch/sparc/kernel/process.c	Mon Mar 17 14:54:20 1997
+++ linux/arch/sparc/kernel/process.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.90 1997/01/31 23:26:16 tdyas Exp $
+/*  $Id: process.c,v 1.93 1997/04/11 08:55:40 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -57,6 +57,7 @@
 		goto out;
 
 	/* endless idle loop with no priority at all */
+	current->priority = -100;
 	current->counter = -100;
 	for (;;) {
 		if (sparc_cpu_model == sun4c) {
@@ -99,51 +100,33 @@
 
 #else
 
-/*
- * the idle loop on a SparcMultiPenguin...
- */
-asmlinkage int sys_idle(void)
-{
-	int ret = -EPERM;
-
-	lock_kernel();
-	if (current->pid != 0)
-		goto out;
-
-	/* endless idle loop with no priority at all */
-	current->counter = -100;
-	schedule();
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
 /* This is being executed in task 0 'user space'. */
 int cpu_idle(void *unused)
 {
-	volatile int *spap = &smp_process_available;
-	volatile int cval;
-
+	current->priority = -100;
 	while(1) {
-		if(0==*spap)
-			continue;
-		cli();
-		/* Acquire exclusive access. */
-		while((cval = smp_swap(spap, -1)) == -1)
-			while(*spap == -1)
-				;
-                if (0==cval) {
-			/* ho hum, release it. */
-			*spap = 0;
-			sti();
-                        continue;
-                }
-		/* Something interesting happened, whee... */
-		*spap = (cval - 1);
-		sti();
-		idle();
+		/*
+		 * tq_scheduler currently assumes we're running in a process
+		 * context (ie that we hold the kernel lock..)
+		 */
+		if (tq_scheduler) {
+			lock_kernel();
+			run_task_queue(&tq_scheduler);
+			unlock_kernel();
+		}
+		/* endless idle loop with no priority at all */
+		current->counter = -100;
+		schedule();
 	}
+}
+
+asmlinkage int sys_idle(void)
+{
+	if(current->pid != 0)
+		return -EPERM;
+
+	cpu_idle(NULL);
+	return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.1.33/linux/arch/sparc/kernel/ptrace.c	Mon Mar 17 14:54:21 1997
+++ linux/arch/sparc/kernel/ptrace.c	Fri Apr 11 10:47:35 1997
@@ -592,6 +592,9 @@
 		unsigned long tmp;
 		int res;
 
+		/* XXX Find out what is really going on. */
+		flush_cache_all();
+
 		/* Non-word alignment _not_ allowed on Sparc. */
 		if(addr & (sizeof(unsigned long) - 1)) {
 			pt_error_return(regs, EINVAL);
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v2.1.33/linux/arch/sparc/kernel/rtrap.S	Mon Mar 17 14:54:21 1997
+++ linux/arch/sparc/kernel/rtrap.S	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.45 1997/03/04 16:26:27 jj Exp $
+/* $Id: rtrap.S,v 1.46 1997/04/01 02:21:48 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -48,13 +48,8 @@
 	.globl	rtrap_patch3, rtrap_patch4, rtrap_patch5
 	.globl	C_LABEL(ret_trap_lockless_ipi)
 ret_trap_entry:
-	sethi	%hi(C_LABEL(intr_count)), %g4
-	ld	[%g4 + %lo(C_LABEL(intr_count))], %g5
-	orcc	%g5, 0x0, %g0
 	sethi	%hi(C_LABEL(bh_active)), %l3
-	bne	C_LABEL(ret_trap_lockless_ipi)
-	 sethi	%hi(C_LABEL(bh_mask)), %l4
-9:
+	sethi	%hi(C_LABEL(bh_mask)), %l4
 	ld	[%l4 + %lo(C_LABEL(bh_mask))], %g5
 	ld	[%l3 + %lo(C_LABEL(bh_active))], %g4
 	andcc	%g4, %g5, %g0
@@ -62,7 +57,6 @@
 	 nop
 	call	C_LABEL(do_bottom_half)
 	 nop
-	b,a	9b
 
 C_LABEL(ret_trap_lockless_ipi):
 	andcc	%t_psr, PSR_PS, %g0
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.1.33/linux/arch/sparc/kernel/setup.c	Thu Mar 27 14:39:59 1997
+++ linux/arch/sparc/kernel/setup.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.82 1997/03/08 08:27:04 ecd Exp $
+/*  $Id: setup.c,v 1.83 1997/04/01 02:21:49 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -24,6 +24,7 @@
 #include <linux/string.h>
 #include <linux/blk.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -38,6 +39,9 @@
 #include <asm/kdebug.h>
 #include <asm/mbus.h>
 #include <asm/idprom.h>
+#include <asm/spinlock.h>
+#include <asm/softirq.h>
+#include <asm/hardirq.h>
 
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
@@ -75,8 +79,13 @@
 void prom_sync_me(void)
 {
 	unsigned long prom_tbr, flags;
+	int cpu = smp_processor_id();
 
-	save_and_cli(flags);
+#ifdef __SMP__
+	global_irq_holder = NO_PROC_ID;
+	global_irq_lock = global_bh_lock = 0;
+#endif
+	__save_and_cli(flags);
 	__asm__ __volatile__("rd %%tbr, %0\n\t" : "=r" (prom_tbr));
 	__asm__ __volatile__("wr %0, 0x0, %%tbr\n\t"
 			     "nop\n\t"
@@ -89,9 +98,9 @@
 	prom_printf("PROM SYNC COMMAND...\n");
 	show_free_areas();
 	if(current->pid != 0) {
-		sti();
+		__sti();
 		sys_sync();
-		cli();
+		__cli();
 	}
 	prom_printf("Returning to prom\n");
 
@@ -99,7 +108,7 @@
 			     "nop\n\t"
 			     "nop\n\t"
 			     "nop\n\t" : : "r" (prom_tbr));
-	restore_flags(flags);
+	__restore_flags(flags);
 
 	return;
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.1.33/linux/arch/sparc/kernel/smp.c	Sun Jan 26 02:07:07 1997
+++ linux/arch/sparc/kernel/smp.c	Mon Apr 14 09:31:09 1997
@@ -5,6 +5,7 @@
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
+#include <asm/atomic.h>
 
 #include <linux/kernel.h>
 #include <linux/tasks.h>
@@ -18,38 +19,31 @@
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
 #include <asm/atops.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
+#define IRQ_RESCHEDULE		13
+#define IRQ_STOP_CPU		14
+#define IRQ_CROSS_CALL		15
 
 extern ctxd_t *srmmu_ctx_table_phys;
 extern int linux_num_cpus;
 
-struct tlog {
-	unsigned long pc;
-	unsigned long psr;
-};
-
-struct tlog trap_log[4][256];
-unsigned long trap_log_ent[4] = { 0, 0, 0, 0, };
-
 extern void calibrate_delay(void);
 
-volatile unsigned long stuck_pc = 0;
 volatile int smp_processors_ready = 0;
 
-int smp_found_config = 0;
 unsigned long cpu_present_map = 0;
 int smp_num_cpus = 1;
 int smp_threads_ready=0;
 unsigned char mid_xlate[NR_CPUS] = { 0, 0, 0, 0, };
 volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-volatile unsigned long smp_invalidate_needed[NR_CPUS] = { 0, };
 volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
+unsigned long smp_proc_in_lock[NR_CPUS] = { 0, };
 struct cpuinfo_sparc cpu_data[NR_CPUS];
-unsigned char boot_cpu_id = 0;
+static unsigned char boot_cpu_id = 0;
 static int smp_activated = 0;
-static volatile unsigned char smp_cpu_in_msg[NR_CPUS];
-static volatile unsigned long smp_msg_data;
-static volatile int smp_src_cpu;
-static volatile int smp_msg_id;
 volatile int cpu_number_map[NR_CPUS];
 volatile int cpu_logical_map[NR_CPUS];
 
@@ -60,7 +54,7 @@
  * compared to the Alpha and the intel no?  Most Sparcs have 'swap'
  * instruction which is much better...
  */
-struct klock_info klock_info = { KLOCK_CLEAR, 0, 0 };
+struct klock_info klock_info = { KLOCK_CLEAR, 0 };
 
 volatile unsigned long ipi_count;
 #ifdef __SMP_PROF__
@@ -74,7 +68,6 @@
 volatile unsigned long smp_idle_map=0;
 #endif
 
-volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,};
 volatile int smp_process_available=0;
 
 /*#define SMP_DEBUG*/
@@ -180,7 +173,7 @@
 	local_flush_cache_all();
 	local_flush_tlb_all();
 
-	sti();
+	__sti();
 }
 
 void cpu_panic(void)
@@ -200,14 +193,15 @@
 {
 	int cpucount = 0;
 	int i = 0;
+	int first, prev;
 
 	printk("Entering SMP Mode...\n");
 
 	penguin_ctable.which_io = 0;
-	penguin_ctable.phys_addr = (char *) srmmu_ctx_table_phys;
+	penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
 	penguin_ctable.reg_size = 0;
 
-	sti();
+	__sti();
 	cpu_present_map = 0;
 	for(i=0; i < linux_num_cpus; i++)
 		cpu_present_map |= (1<<i);
@@ -218,7 +212,7 @@
 	mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
 	cpu_number_map[boot_cpu_id] = 0;
 	cpu_logical_map[0] = boot_cpu_id;
-	klock_info.akp = klock_info.irq_udt = boot_cpu_id;
+	klock_info.akp = boot_cpu_id;
 	smp_store_cpu_info(boot_cpu_id);
 	set_irq_udt(mid_xlate[boot_cpu_id]);
 	local_flush_cache_all();
@@ -280,139 +274,75 @@
 		smp_activated = 1;
 		smp_num_cpus = cpucount + 1;
 	}
+
+	/* Setup CPU list for IRQ distribution scheme. */
+	first = prev = -1;
+	for(i = 0; i < NR_CPUS; i++) {
+		if(cpu_present_map & (1 << i)) {
+			if(first == -1)
+				first = i;
+			if(prev != -1)
+				cpu_data[i].next = i;
+			cpu_data[i].mid = mid_xlate[i];
+			prev = i;
+		}
+	}
+	cpu_data[prev].next = first;
+
+	/* Ok, they are spinning and ready to go. */
 	smp_processors_ready = 1;
 }
 
-static inline void send_ipi(unsigned long target_map, int irq)
+/* At each hardware IRQ, we get this called to forward IRQ reception
+ * to the next processor.  The caller must disable the IRQ level being
+ * serviced globally so that there are no double interrupts received.
+ */
+void smp_irq_rotate(int cpu)
 {
-	int i;
-
-	for(i = 0; i < 4; i++) {
-		if((1<<i) & target_map)
-			set_cpu_int(mid_xlate[i], irq);
-	}
+	if(smp_processors_ready)
+		set_irq_udt(cpu_data[cpu_data[cpu].next].mid);
 }
 
-/*
- * A non wait message cannot pass data or cpu source info. This current
- * setup is only safe because the kernel lock owner is the only person
- * who can send a message.
- *
- * Wrapping this whole block in a spinlock is not the safe answer either.
- * A processor may get stuck with irq's off waiting to send a message and
- * thus not replying to the person spinning for a reply....
- *
- * On the Sparc we use NMI's for all messages except reschedule.
+/* Cross calls, in order to work efficiently and atomically do all
+ * the message passing work themselves, only stopcpu and reschedule
+ * messages come through here.
  */
-
-static volatile int message_cpu = NO_PROC_ID;
-
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
-	unsigned long target_map;
-	int p = smp_processor_id();
-	int irq = 15;
-	int i;
-
-	/* Before processors have been placed into their initial
-	 * patterns do not send messages.
-	 */
-	if(!smp_processors_ready)
-		return;
+	static unsigned long smp_cpu_in_msg[NR_CPUS];
+	unsigned long mask;
+	int me = smp_processor_id();
+	int irq, i;
 
-	/* Skip the reschedule if we are waiting to clear a
-	 * message at this time. The reschedule cannot wait
-	 * but is not critical.
-	 */
 	if(msg == MSG_RESCHEDULE) {
-		if(!smp_commenced)
-			return;
-		irq = 13;
-		if(smp_cpu_in_msg[p])
-			return;
-	}
-
-	/* Sanity check we don't re-enter this across CPU's. Only the kernel
-	 * lock holder may send messages. For a STOP_CPU we are bringing the
-	 * entire box to the fastest halt we can.. A reschedule carries
-	 * no data and can occur during a flush.. guess what panic
-	 * I got to notice this bug...
-	 */
-	if(message_cpu != NO_PROC_ID && msg != MSG_STOP_CPU && msg != MSG_RESCHEDULE) {
-		printk("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
-		       smp_processor_id(),msg,message_cpu, smp_msg_id);
-
-		/* I don't know how to gracefully die so that debugging
-		 * this doesn't completely eat up my filesystems...
-		 * let's try this...
-		 */
-		smp_cpu_in_msg[p] = 0; /* In case we come back here... */
-		intr_count = 0;        /* and so panic don't barf... */
-		smp_swap(&message_cpu, NO_PROC_ID); /* push the store buffer */
-		sti();
-		printk("spinning, please L1-A, type ctrace and send output to davem\n");
-		while(1)
-			barrier();
-	}
-	smp_swap(&message_cpu, smp_processor_id()); /* store buffers... */
+		irq = IRQ_RESCHEDULE;
 
-	/* We are busy. */
-	smp_cpu_in_msg[p]++;
-
-	/* Reschedule is currently special. */
-	if(msg != MSG_RESCHEDULE) {
-		smp_src_cpu = p;
-		smp_msg_id = msg;
-		smp_msg_data = data;
+		if(smp_cpu_in_msg[me])
+			return;
+	} else if(msg == MSG_STOP_CPU) {
+		irq = IRQ_STOP_CPU;
+	} else {
+		goto barf;
 	}
 
-#if 0
-	printk("SMP message pass from cpu %d to cpu %d msg %d\n", p, target, msg);
-#endif
-
-	/* Set the target requirement. */
-	for(i = 0; i < smp_num_cpus; i++)
-		swap((unsigned long *) &cpu_callin_map[i], 0);
-	if(target == MSG_ALL_BUT_SELF) {
-		target_map = (cpu_present_map & ~(1<<p));
-		swap((unsigned long *) &cpu_callin_map[p], 1);
-	} else if(target == MSG_ALL) {
-		target_map = cpu_present_map;
+	smp_cpu_in_msg[me]++;
+	if(target == MSG_ALL_BUT_SELF || target == MSG_ALL) {
+		mask = cpu_present_map;
+		if(target == MSG_ALL_BUT_SELF)
+			mask &= ~(1 << me);
+		for(i = 0; i < 4; i++) {
+			if(mask & (1 << i))
+				set_cpu_int(mid_xlate[i], irq);
+		}
 	} else {
-		for(i = 0; i < smp_num_cpus; i++)
-			if(i != target)
-				swap((unsigned long *) &cpu_callin_map[i], 1);
-		target_map = (1<<target);
+		set_cpu_int(mid_xlate[target], irq);
 	}
+	smp_cpu_in_msg[me]--;
 
-	/* Fire it off. */
-	send_ipi(target_map, irq);
-
-	switch(wait) {
-	case 1:
-		for(i = 0; i < smp_num_cpus; i++)
-			while(!cpu_callin_map[i])
-				barrier();
-		break;
-	case 2:
-		for(i = 0; i < smp_num_cpus; i++)
-			while(smp_invalidate_needed[i])
-				barrier();
-		break;
-	case 3:
-		/* For cross calls we hold message_cpu and smp_cpu_in_msg[]
-		 * until all processors disperse.  Else we have _big_ problems.
-		 */
-		return;
-	case 4:
-		/* For captures we hold smp_cpu_in_msg[] until all processors
-		 * released.  Else we have _big_ problems.
-		 */
-		message_cpu = NO_PROC_ID;
-		return;
-	}
-	smp_cpu_in_msg[p]--;
-	message_cpu = NO_PROC_ID;
+	return;
+barf:
+	printk("Yeeee, trying to send SMP msg(%d) on cpu %d\n", msg, me);
+	panic("Bogon SMP message pass.");
 }
 
 struct smp_funcall {
@@ -432,29 +362,20 @@
 
 #define CCALL_TIMEOUT   5000000 /* enough for initial testing */
 
-/* #define DEBUG_CCALL */
+static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
 
-/* Some nice day when we really thread the kernel I'd like to synchronize
- * this with either a broadcast conditional variable, a resource adaptive
- * generic mutex, or a convoy semaphore scheme of some sort.  No reason
- * we can't let multiple processors in here if the appropriate locking
- * is done.  Note that such a scheme assumes we will have a
- * prioritized ipi scheme using different software level irq's.
- */
+/* Cross calls must be serialized, at least currently. */
 void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
 		    unsigned long arg3, unsigned long arg4, unsigned long arg5)
 {
 	unsigned long me = smp_processor_id();
-	unsigned long flags;
+	unsigned long flags, mask;
 	int i, timeout;
 
-#ifdef DEBUG_CCALL
-	printk("xc%d<", me);
-#endif
 	if(smp_processors_ready) {
-		save_and_cli(flags);
-		if(me != klock_info.akp)
-			goto cross_call_not_master;
+		__save_flags(flags);
+		__cli();
+		spin_lock(&cross_call_lock);
 
 		/* Init function glue. */
 		ccall_info.func = func;
@@ -473,7 +394,11 @@
 		ccall_info.processors_out[me] = 1;
 
 		/* Fire it off. */
-		smp_message_pass(MSG_ALL_BUT_SELF, MSG_CROSS_CALL, 0, 3);
+		mask = (cpu_present_map & ~(1 << me));
+		for(i = 0; i < 4; i++) {
+			if(mask & (1 << i))
+				set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL);
+		}
 
 		/* For debugging purposes right now we can timeout
 		 * on both callin and callexit.
@@ -485,9 +410,6 @@
 			if(!ccall_info.processors_in[i])
 				goto procs_time_out;
 		}
-#ifdef DEBUG_CCALL
-		printk("I");
-#endif
 
 		/* Run local copy. */
 		func(arg1, arg2, arg3, arg4, arg5);
@@ -500,33 +422,19 @@
 			if(!ccall_info.processors_out[i])
 				goto procs_time_out;
 		}
-#ifdef DEBUG_CCALL
-		printk("O>");
-#endif
-		/* See wait case 3 in smp_message_pass()... */
-		smp_cpu_in_msg[me]--;
-		message_cpu = NO_PROC_ID;
-		restore_flags(flags);
+		spin_unlock(&cross_call_lock);
+		__restore_flags(flags);
 		return; /* made it... */
 
 procs_time_out:
 		printk("smp: Wheee, penguin drops off the bus\n");
-		smp_cpu_in_msg[me]--;
-		message_cpu = NO_PROC_ID;
-		restore_flags(flags);
+		spin_unlock(&cross_call_lock);
+		__restore_flags(flags);
 		return; /* why me... why me... */
 	}
 
 	/* Just need to run local copy. */
 	func(arg1, arg2, arg3, arg4, arg5);
-	return;
-
-cross_call_not_master:
-	printk("Cross call initiated by non master cpu from [%p]\n",
-	       __builtin_return_address(0));
-	printk("akp=%x me=%08lx\n", klock_info.akp, me);
-	restore_flags(flags);
-	panic("penguin cross call");
 }
 
 void smp_flush_cache_all(void)
@@ -578,171 +486,24 @@
 /* Reschedule call back. */
 void smp_reschedule_irq(void)
 {
-	lock_kernel();
-	intr_count++;
-	if(smp_processor_id() != klock_info.akp) {
-		panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
-		      smp_processor_id(), klock_info.akp);
-	}
 	need_resched=1;
-	intr_count--;
-	unlock_kernel();
 }
 
-#undef DEBUG_CAPTURE
-
-static struct capture_struct {
-	int capture_level;
-	volatile unsigned long processors_in[NR_CPUS];
-	volatile unsigned long processors_out[NR_CPUS];
-} cap_info = { 0, };
-
-void smp_capture(void)
+/* Running cross calls. */
+void smp_cross_call_irq(void)
 {
-	unsigned long flags;
-	int me = smp_processor_id();
-	int cpu;
-
-	if(!smp_processors_ready)
-		return;
-
-	if (me != klock_info.akp)
-		panic("SMP Capture on CPU #%d, but #%d is active.\n",
-		      me, klock_info.akp);
-
-#ifdef DEBUG_CAPTURE
-	printk("C%d(%d)<", smp_processor_id(), cap_info.capture_level);
-#endif
-	save_and_cli(flags);
-
-	if (! cap_info.capture_level++) {
-		int timeout;
-
-		/* Initialize Capture Info. */
-		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
-			cap_info.processors_in[cpu] = 0;
-			cap_info.processors_out[cpu] = 0;
-		}
-		cap_info.processors_in[me] = 1;
-		cap_info.processors_out[me] = 1;
-
-		smp_message_pass(MSG_ALL_BUT_SELF, MSG_CAPTURE, 0, 4);
-
-		timeout = CCALL_TIMEOUT;
-		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
-			while (!cap_info.processors_in[cpu] && timeout-- > 0)
-				barrier();
-			if (!cap_info.processors_in[cpu])
-				goto procs_time_out;
-#ifdef DEBUG_CAPTURE
-			printk("%d", cpu);
-#endif
-		}
-	}
-#ifdef DEBUG_CAPTURE
-	printk(">");
-#endif
-	restore_flags(flags);
-	return;
-
-procs_time_out:
-	printk("smp_capture (%d): Wheee, penguin drops off the bus\n",
-		smp_processor_id());
-	printk("smp_capture: map: %ld %ld %ld %ld\n",
-		cap_info.processors_in[0], cap_info.processors_in[1],
-		cap_info.processors_in[2], cap_info.processors_in[3]);
-	smp_cpu_in_msg[me]--;
-	message_cpu = NO_PROC_ID;
-	restore_flags(flags);
-}
-
-void smp_release(void)
-{
-	unsigned long flags;
-	int me = smp_processor_id();
-	int cpu;
-
-	if(!smp_processors_ready)
-		return;
-#ifdef DEBUG_CAPTURE
-	printk("R%d(%d)<", smp_processor_id(), cap_info.capture_level);
-#endif
-
-	if (me != klock_info.akp)
-		panic("SMP Release on CPU #%d, but #%d is active.\n",
-		      me, klock_info.akp);
-
-	save_and_cli(flags);
-
-	if (! --cap_info.capture_level) {
-		int timeout;
-
-		for (cpu = 0; cpu < smp_num_cpus; cpu++)
-			cap_info.processors_in[cpu] = 0;
-
-		timeout = CCALL_TIMEOUT;
-		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
-			while (!cap_info.processors_out[cpu] && timeout-- > 0)
-				barrier();
-			if (!cap_info.processors_out[cpu])
-				goto procs_time_out;
-#ifdef DEBUG_CAPTURE
-			printk("%d", cpu);
-#endif
-		}
-
-		/* See wait case 4 in smp_message_pass()... */
-		smp_cpu_in_msg[me]--;
-	}
-#ifdef DEBUG_CAPTURE
-	printk(">");
-#endif
-	restore_flags(flags);
-	return;
+	int i = smp_processor_id();
 
-procs_time_out:
-	printk("smp_release (%d): Wheee, penguin drops off the bus\n",
-		smp_processor_id());
-	printk("smp_release: map: %ld %ld %ld %ld\n",
-		cap_info.processors_out[0], cap_info.processors_out[1],
-		cap_info.processors_out[2], cap_info.processors_out[3]);
-	smp_cpu_in_msg[me]--;
-	restore_flags(flags);
+	ccall_info.processors_in[i] = 1;
+	ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
+			ccall_info.arg4, ccall_info.arg5);
+	ccall_info.processors_out[i] = 1;
 }
 
-/* Message call back. */
-void smp_message_irq(void)
+/* Stopping processors. */
+void smp_stop_cpu_irq(void)
 {
-	int i=smp_processor_id();
-
-	switch(smp_msg_id) {
-	case MSG_CROSS_CALL:
-		/* Do it to it. */
-		ccall_info.processors_in[i] = 1;
-		ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
-				ccall_info.arg4, ccall_info.arg5);
-		ccall_info.processors_out[i] = 1;
-		break;
-
-	case MSG_CAPTURE:
-		flush_user_windows();
-		cap_info.processors_in[i] = 1;
-		while (cap_info.processors_in[i])
-			barrier();
-		cap_info.processors_out[i] = 1;
-		break;
-
-		/*
-		 *	Halt other CPU's for a panic or reboot
-		 */
-	case MSG_STOP_CPU:
-		sti();
-		while(1)
-			barrier();
-
-	default:
-		printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n",
-		       smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data);
-		break;
-	}
+	__sti();
+	while(1)
+		barrier();
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.1.33/linux/arch/sparc/kernel/sparc_ksyms.c	Thu Mar 27 14:39:59 1997
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.49 1997/03/15 07:47:45 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.54 1997/04/14 05:38:25 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/interrupt.h>
 #include <linux/in6.h>
 
 #include <asm/oplib.h>
@@ -26,6 +27,9 @@
 #include <asm/smp.h>
 #include <asm/mostek.h>
 #include <asm/ptrace.h>
+#include <asm/spinlock.h>
+#include <asm/softirq.h>
+#include <asm/hardirq.h>
 #include <asm/user.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
@@ -82,6 +86,8 @@
 #endif
 EXPORT_SYMBOL_PRIVATE(_lock_kernel);
 EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
+EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
+EXPORT_SYMBOL(__sparc_bh_counter);
 EXPORT_SYMBOL(page_offset);
 EXPORT_SYMBOL(stack_top);
 
@@ -97,6 +103,20 @@
 EXPORT_SYMBOL_PRIVATE(_set_le_bit);
 EXPORT_SYMBOL_PRIVATE(_clear_le_bit);
 
+/* IRQ implementation. */
+EXPORT_SYMBOL(local_irq_count);
+#ifdef __SMP__
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(synchronize_irq);
+#endif
+
 EXPORT_SYMBOL(udelay);
 EXPORT_SYMBOL(mstk48t02_regs);
 #if CONFIG_SUN_AUXIO
@@ -113,7 +133,7 @@
 EXPORT_SYMBOL(mmu_get_scsi_one);
 EXPORT_SYMBOL(mmu_release_scsi_sgl);
 EXPORT_SYMBOL(mmu_release_scsi_one);
-EXPORT_SYMBOL(sparc_dvma_malloc);
+EXPORT_SYMBOL(_sparc_dvma_malloc);
 EXPORT_SYMBOL(sun4c_unmapioaddr);
 EXPORT_SYMBOL(srmmu_unmapioaddr);
 #if CONFIG_SBUS
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/sun4c_irq.c linux/arch/sparc/kernel/sun4c_irq.c
--- v2.1.33/linux/arch/sparc/kernel/sun4c_irq.c	Fri Dec 13 01:37:31 1996
+++ linux/arch/sparc/kernel/sun4c_irq.c	Mon Apr 14 09:31:09 1997
@@ -128,7 +128,7 @@
 	/* Map the Timer chip, this is implemented in hardware inside
 	 * the cache chip on the sun4c.
 	 */
-	sun4c_timers = sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, 0,
+	sun4c_timers = sparc_alloc_io (SUN4C_TIMER_PHYSADDR, 0,
 				       sizeof(struct sun4c_timer_info),
 				       "timer", 0x0, 0x0);
     
@@ -174,6 +174,8 @@
 						   int_regs[0].which_io, 0x0);
 	enable_irq = sun4c_enable_irq;
 	disable_irq = sun4c_disable_irq;
+	enable_pil_irq = sun4c_enable_irq;
+	disable_pil_irq = sun4c_disable_irq;
 	clear_clock_irq = sun4c_clear_clock_irq;
 	clear_profile_irq = sun4c_clear_profile_irq;
 	load_profile_irq = sun4c_load_profile_irq;
@@ -184,5 +186,5 @@
 	set_irq_udt = (void (*) (int))sun4c_nop;
 #endif
 	*interrupt_enable = (SUN4C_INT_ENABLE);
-	sti();
+	/* Cannot enable interrupts until OBP ticker is disabled. */
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c
--- v2.1.33/linux/arch/sparc/kernel/sun4m_irq.c	Sun Jan 26 02:07:08 1997
+++ linux/arch/sparc/kernel/sun4m_irq.c	Mon Apr 14 09:31:09 1997
@@ -130,6 +130,38 @@
 	}
 }
 
+static unsigned long cpu_pil_to_imask[16] = {
+/*0*/	0x00000000,
+/*1*/	0x00000000,
+/*2*/	SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0),
+/*3*/	SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1),
+/*4*/	SUN4M_INT_SCSI,
+/*5*/	SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2),
+/*6*/	SUN4M_INT_ETHERNET,
+/*7*/	SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3),
+/*8*/	SUN4M_INT_VIDEO,
+/*9*/	SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
+/*10*/	SUN4M_INT_REALTIME,
+/*11*/	SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
+/*12*/	SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
+/*13*/	SUN4M_INT_AUDIO,
+/*14*/	0x00000000,
+/*15*/	0x00000000
+};
+
+/* We assume the caller is local cli()'d when these are called, or else
+ * very bizarre behavior will result.
+ */
+static void sun4m_disable_pil_irq(unsigned int pil)
+{
+	sun4m_interrupts->set = cpu_pil_to_imask[pil];
+}
+
+static void sun4m_enable_pil_irq(unsigned int pil)
+{
+	sun4m_interrupts->clear = cpu_pil_to_imask[pil];
+}
+
 void sun4m_send_ipi(int cpu, int level)
 {
 	unsigned long mask;
@@ -272,7 +304,7 @@
 	struct linux_prom_registers int_regs[PROMREG_MAX];
 	int num_regs;
     
-	cli();
+	__cli();
 	if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
 	   (ie_node = prom_getchild (ie_node)) == 0 ||
 	   (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
@@ -327,6 +359,8 @@
 	}
 	enable_irq = sun4m_enable_irq;
 	disable_irq = sun4m_disable_irq;
+	enable_pil_irq = sun4m_enable_pil_irq;
+	disable_pil_irq = sun4m_disable_pil_irq;
 	clear_clock_irq = sun4m_clear_clock_irq;
 	clear_profile_irq = sun4m_clear_profile_irq;
 	load_profile_irq = sun4m_load_profile_irq;
@@ -336,5 +370,5 @@
 	clear_cpu_int = (void (*) (int, int))sun4m_clear_ipi;
 	set_irq_udt = (void (*) (int))sun4m_set_udt;
 #endif
-	sti();
+	/* Cannot enable interrupts until OBP ticker is disabled. */
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v2.1.33/linux/arch/sparc/kernel/time.c	Sun Jan 26 02:07:08 1997
+++ linux/arch/sparc/kernel/time.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.23 1997/01/26 04:28:34 davem Exp $
+/* $Id: time.c,v 1.27 1997/04/14 05:38:31 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -54,6 +54,11 @@
 	    last_rtc_update = xtime.tv_sec;
 	  else
 	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+#ifdef __SMP__
+	/* I really think it should not be done this way... -DaveM */
+	smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
+#endif
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -198,7 +203,7 @@
 			prom_apply_obio_ranges(clk_reg, 1);
 		/* Map the clock register io area read-only */
 		mstk48t02_regs = (struct mostek48t02 *) 
-			sparc_alloc_io((void *) clk_reg[0].phys_addr,
+			sparc_alloc_io(clk_reg[0].phys_addr,
 				       (void *) 0, sizeof(*mstk48t02_regs),
 				       "clock", clk_reg[0].which_io, 0x0);
 		mstk48t08_regs = 0;  /* To catch weirdness */
@@ -215,7 +220,7 @@
 			prom_apply_obio_ranges(clk_reg, 1);
 		/* Map the clock register io area read-only */
 		mstk48t08_regs = (struct mostek48t08 *)
-			sparc_alloc_io((void *) clk_reg[0].phys_addr,
+			sparc_alloc_io(clk_reg[0].phys_addr,
 				       (void *) 0, sizeof(*mstk48t08_regs),
 				       "clock", clk_reg[0].which_io, 0x0);
 
@@ -265,7 +270,9 @@
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
 	xtime.tv_usec = 0;
 	mregs->creg &= ~MSTK_CREG_READ;
-	return;
+
+	/* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
+	__sti();
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
@@ -283,21 +290,49 @@
 
 void do_gettimeofday(struct timeval *tv)
 {
+#if CONFIG_AP1000
 	unsigned long flags;
 
 	save_and_cli(flags);
-#if CONFIG_AP1000
 	ap_gettimeofday(&xtime);
-#endif
 	*tv = xtime;
-#if !CONFIG_AP1000
-	tv->tv_usec += do_gettimeoffset();
-	if(tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
-	}
-#endif
 	restore_flags(flags);
+#else /* !(CONFIG_AP1000) */
+	/* Load doubles must be used on xtime so that what we get
+	 * is guarenteed to be atomic, this is why we can run this
+	 * with interrupts on full blast.  Don't touch this... -DaveM
+	 */
+	__asm__ __volatile__("
+	sethi	%hi(master_l10_counter), %o1
+	ld	[%o1 + %lo(master_l10_counter)], %g3
+	sethi	%hi(xtime), %g2
+1:	ldd	[%g2 + %lo(xtime)], %o4
+	ld	[%g3], %o1
+	ldd	[%g2 + %lo(xtime)], %o2
+	xor	%o4, %o2, %o2
+	xor	%o5, %o3, %o3
+	orcc	%o2, %o3, %g0
+	bne	1b
+	 subcc	%o1, 0x0, %g0
+	bpos	1f
+	 srl	%o1, 0xa, %o1
+	sethi	%hi(0x2710), %o3
+	or	%o3, %lo(0x2710), %o3
+	sethi	%hi(0x1fffff), %o2
+	or	%o2, %lo(0x1fffff), %o2
+	add	%o5, %o3, %o5
+	and	%o1, %o2, %o1
+1:	add	%o5, %o1, %o5
+	sethi	%hi(1000000), %o2
+	or	%o2, %lo(1000000), %o2
+	cmp	%o5, %o2
+	bl,a	1f
+	 st	%o4, [%o0 + 0x0]
+	add	%o4, 0x1, %o4
+	sub	%o5, %o2, %o5
+	st	%o4, [%o0 + 0x0]
+1:	st	%o5, [%o0 + 0x4]");
+#endif
 }
 
 void do_settimeofday(struct timeval *tv)
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/trampoline.S linux/arch/sparc/kernel/trampoline.S
--- v2.1.33/linux/arch/sparc/kernel/trampoline.S	Sat Nov  9 00:11:52 1996
+++ linux/arch/sparc/kernel/trampoline.S	Mon Apr 14 09:31:09 1997
@@ -1,5 +1,5 @@
-/* $Id: trampoline.S,v 1.5 1996/09/22 06:43:10 davem Exp $
- * mp.S:  Multiprocessor low-level routines on the Sparc.
+/* $Id: trampoline.S,v 1.6 1997/04/14 05:38:33 davem Exp $
+ * trampoline.S: SMP cpu boot-up trampoline code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/unaligned.c linux/arch/sparc/kernel/unaligned.c
--- v2.1.33/linux/arch/sparc/kernel/unaligned.c	Thu Mar 27 14:39:59 1997
+++ linux/arch/sparc/kernel/unaligned.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.16 1997/03/18 17:53:44 jj Exp $
+/* $Id: unaligned.c,v 1.17 1997/04/11 00:42:08 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -204,7 +204,7 @@
 	".word	16b, " #errh "\n\n\t"						\
 	".previous\n\t"								\
 	: : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed)		\
-	: "l1", "l2", "g7", "g1");						\
+	: "l1", "l2", "g7", "g1", "cc");					\
 })
 	
 #define store_common(dst_addr, size, src_val, errh) ({				\
@@ -258,7 +258,7 @@
 	".word	17b, " #errh "\n\n\t"						\
 	".previous\n\t"								\
 	: : "r" (dst_addr), "r" (size), "r" (src_val)				\
-	: "l1", "l2", "g7", "g1");						\
+	: "l1", "l2", "g7", "g1", "cc");					\
 })
 
 #define do_integer_store(reg_num, size, dst_addr, regs, errh) ({		\
@@ -343,8 +343,10 @@
 		"mov	%0, %%o0\n\t"
 		"call	kernel_mna_trap_fault\n\t"
 		" mov	%1, %%o1\n\t"
-		: : "r" (regs), "r" (insn)
-		: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+		:
+		: "r" (regs), "r" (insn)
+		: "o0", "o1", "o2", "o3", "o4", "o5", "o7",
+		  "g1", "g2", "g3", "g4", "g5", "g7", "cc");
 	} else {
 		unsigned long addr = compute_effective_address(regs, insn);
 
@@ -476,8 +478,10 @@
 			"mov	%0, %%o0\n\t"
 			"call	user_mna_trap_fault\n\t"
 			" mov	%1, %%o1\n\t"
-			: : "r" (regs), "r" (insn)
-			: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+			:
+			: "r" (regs), "r" (insn)
+			: "o0", "o1", "o2", "o3", "o4", "o5", "o7",
+			  "g1", "g2", "g3", "g4", "g5", "g7", "cc");
 			goto out;
 		}
 		advance(regs);
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/kernel/windows.c linux/arch/sparc/kernel/windows.c
--- v2.1.33/linux/arch/sparc/kernel/windows.c	Sun Jan 26 02:07:09 1997
+++ linux/arch/sparc/kernel/windows.c	Fri Apr 11 10:47:35 1997
@@ -33,7 +33,7 @@
 	: "=&r" (ctr)
 	: "0" (ctr),
 	  "i" ((const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask)))
-	: "g4");
+	: "g4", "cc");
 }
 
 static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp)
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/lib/atomic.S linux/arch/sparc/lib/atomic.S
--- v2.1.33/linux/arch/sparc/lib/atomic.S	Sun Jan 26 02:07:09 1997
+++ linux/arch/sparc/lib/atomic.S	Mon Apr 14 09:31:09 1997
@@ -10,10 +10,6 @@
 	.text
 	.align	4
 
-	/* XXX At boot time patch this with swap [x], y; retl; if
-	 * XXX processor is found to have that instruction.
-	 */
-
 	.globl	___xchg32
 ___xchg32:
 	rd	%psr, %g3
@@ -34,51 +30,47 @@
 	jmpl	%o7, %g0		/* Note, not + 0x8, see call in system.h */
 	 mov	%g4, %o7
 
-	.globl	___xchg32_hw
-___xchg32_hw:
-	swap	[%g1], %g2
-	jmpl	%o7, %g0		/* Note, not + 0x8, see call in system.h */
-	 mov	%g4, %o7
-
-	/* Atomic add/sub routines.  Returns the final value whether you
-	 * want it or not for even _better_ cache hit rates.
+	/* Read asm-sparc/atomic.h carefully to understand how this works for SMP.
+	 * Really, some things here for SMP are overly clever, go read the header.
 	 */
 	.globl	___atomic_add
 ___atomic_add:
-	rd	%psr, %g3
-	andcc	%g3, PSR_PIL, %g0
-	bne	1f
-	 nop
-	wr	%g3, PSR_PIL, %psr
-	nop; nop; nop;
-1:
-	ld	[%g1], %g7
-	andcc	%g3, PSR_PIL, %g0
-	add	%g7, %g2, %g2
-	bne	1f
-	 st	%g2, [%g1]
-	wr	%g3, 0x0, %psr
-	nop; nop; nop;
-1:
-	jmpl	%o7, %g0		/* NOTE: not + 8, see callers in atomic.h */
-	 mov	%g4, %o7
+	rd	%psr, %g3		! Keep the code small, old way was stupid
+	or	%g3, PSR_PIL, %g7	! Disable interrupts
+	wr	%g7, 0x0, %psr		! Set %psr
+	nop; nop; nop;			! Let the bits set
+#ifdef __SMP__
+1:	ldstub	[%g1 + 3], %g7		! Spin on the byte lock for SMP.
+	orcc	%g7, 0x0, %g0		! Did we get it?
+	bne	1b			! Nope...
+#endif
+	 ld	[%g1], %g7		! Load locked atomic_t
+	sra	%g7, 8, %g7		! Get signed 24-bit integer
+	add	%g7, %g2, %g2		! Add in argument
+	sll	%g2, 8, %g7		! Transpose back to atomic_t
+	st	%g7, [%g1]		! Clever: This releases the lock as well.
+	wr	%g3, 0x0, %psr		! Restore original PSR_PIL
+	nop; nop; nop;			! Let the bits set
+	jmpl	%o7, %g0		! NOTE: not + 8, see callers in atomic.h
+	 mov	%g4, %o7		! Restore %o7
 
 	.globl	___atomic_sub
 ___atomic_sub:
-	rd	%psr, %g3
-	andcc	%g3, PSR_PIL, %g0
-	bne	1f
-	 nop
-	wr	%g3, PSR_PIL, %psr
-	nop; nop; nop;
-1:
-	ld	[%g1], %g7
-	andcc	%g3, PSR_PIL, %g0
-	sub	%g7, %g2, %g2
-	bne	1f
-	 st	%g2, [%g1]
-	wr	%g3, 0x0, %psr
-	nop; nop; nop;
-1:
-	jmpl	%o7, %g0		/* NOTE: not + 8, see callers in atomic.h */
-	 mov	%g4, %o7
+	rd	%psr, %g3		! Keep the code small, old way was stupid
+	or	%g3, PSR_PIL, %g7	! Disable interrupts
+	wr	%g7, 0x0, %psr		! Set %psr
+	nop; nop; nop;			! Let the bits set
+#ifdef __SMP__
+1:	ldstub	[%g1 + 3], %g7		! Spin on the byte lock for SMP.
+	orcc	%g7, 0x0, %g0		! Did we get it?
+	bne	1b			! Nope...
+#endif
+	 ld	[%g1], %g7		! Load locked atomic_t
+	sra	%g7, 8, %g7		! Get signed 24-bit integer
+	sub	%g7, %g2, %g2		! Subtract argument
+	sll	%g2, 8, %g7		! Transpose back to atomic_t
+	st	%g7, [%g1]		! Clever: This releases the lock as well
+	wr	%g3, 0x0, %psr		! Restore original PSR_PIL
+	nop; nop; nop;			! Let the bits set
+	jmpl	%o7, %g0		! NOTE: not + 8, see callers in atomic.h
+	 mov	%g4, %o7		! Restore %o7
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/lib/locks.S linux/arch/sparc/lib/locks.S
--- v2.1.33/linux/arch/sparc/lib/locks.S	Mon Mar 17 14:54:22 1997
+++ linux/arch/sparc/lib/locks.S	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: locks.S,v 1.4 1997/03/04 16:26:41 jj Exp $
+/* $Id: locks.S,v 1.9 1997/04/14 05:38:41 davem Exp $
  * locks.S: SMP low-level lock primitives on Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
+#include <asm/spinlock.h>
 
 	.text
 	.align	4
@@ -24,38 +25,15 @@
 	.globl	___spinlock_waitfor
 ___spinlock_waitfor:
 1:	orcc	%g2, 0x0, %g0
-	bne	1b
+	bne,a	1b
 	 ldub	[%g1], %g2
 	ldstub	[%g1], %g2
 	jmpl	%o7 - 12, %g0
 	 mov	%g4, %o7
 
-	/* This is called when the kernel master lock holder changes,
-	 * caller's PC is in %o7, %o7 must be restored to the value
-	 * in %g4 when returning.  The interrupt receiver cpu is to
-	 * change to the new kernel lock holder before returning.
-	 * The current implementation assumes that irq_rcvreg is a
-	 * pointer to a word sized register which can be written with
-	 * the MID value of the cpu to receive undirected interrupts.
-	 * CPUID is in %g5, and mid_xlate is a byte table which translates
-	 * CPUID values into the corresponding MID.
-	 */
-	.globl	___become_idt
-___become_idt:
-#ifdef __SMP__
-	sethi	%hi(C_LABEL(mid_xlate)), %g2
-	or	%g2, %lo(C_LABEL(mid_xlate)), %g2
-	ldub	[%g5 + %g2], %g7
-	sethi	%hi(C_LABEL(irq_rcvreg)), %g2
-	ld	[%g2 + %lo(C_LABEL(irq_rcvreg))], %g2
-	st	%g7, [%g2]
-#endif
-	jmpl	%o7 + 8, %g0
-	 mov	%g4, %o7
-
 ___lk_busy_spin:
 	orcc	%g2, 0, %g0
-	bne	___lk_busy_spin
+	bne,a	___lk_busy_spin
 	 ldub	[%g1 + 0], %g2
 	b	1f
 	 ldstub	[%g1 + 0], %g2	
@@ -73,23 +51,34 @@
 1:	orcc	%g2, 0, %g0
 	bne,a	___lk_busy_spin
 	 ldub	[%g1 + 0], %g2
-	ldub	[%g1 + 2], %g2
-	cmp	%g2, %g5
-	be	2f
-	 stb	%g5, [%g1 + 1]
-	stb	%g5, [%g1 + 2]
-#ifdef __SMP__
-	set	C_LABEL(mid_xlate), %g2
-	ldub	[%g2 + %g5], %g7
-	sethi	%hi(C_LABEL(irq_rcvreg)), %g2
-	ld	[%g2 + %lo(C_LABEL(irq_rcvreg))], %g2
-	st	%g7, [%g2]
-#endif
-2:	mov	-1, %g2
+	stb	%g5, [%g1 + 1]
+	mov	-1, %g2
 	st	%g2, [%g6 + AOFF_task_lock_depth]
 	wr	%g3, 0x0, %psr
 	nop; nop; nop
 9:	jmpl	%o7 + 0x8, %g0
+	 mov	%g4, %o7
+
+	.globl	___lock_reaquire_kernel
+___lock_reaquire_kernel:
+	rd	%psr, %g3
+	or	%g3, PSR_PIL, %g7
+	wr	%g7, 0x0, %psr
+	nop; nop; nop
+	st	%g2, [%g6 + AOFF_task_lock_depth]
+	ldstub	[%g1 + 0], %g2
+1:	orcc	%g2, 0, %g0
+	be	3f
+	 ldub	[%g1 + 0], %g2
+2:	orcc	%g2, 0, %g0
+	bne,a	2b
+	 ldub	[%g1 + 0], %g2
+	b	1b
+	 ldstub	[%g1 + 0], %g2
+3:	stb	%g5, [%g1 + 1]
+	wr	%g3, 0x0, %psr
+	nop; nop; nop
+	jmpl	%o7 + 0x8, %g0
 	 mov	%g4, %o7
 
 #undef NO_PROC_ID
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/hypersparc.S linux/arch/sparc/mm/hypersparc.S
--- v2.1.33/linux/arch/sparc/mm/hypersparc.S	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc/mm/hypersparc.S	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: hypersparc.S,v 1.1 1997/03/10 09:16:52 davem Exp $
+/* $Id: hypersparc.S,v 1.3 1997/04/13 06:38:13 davem Exp $
  * hypersparc.S: High speed Hypersparc mmu/cache operations.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -31,7 +31,6 @@
 	.globl	hypersparc_flush_tlb_all, hypersparc_flush_tlb_mm
 	.globl	hypersparc_flush_tlb_range, hypersparc_flush_tlb_page
 
-	/* Verified... */
 hypersparc_flush_cache_all:
 	WINDOW_FLUSH(%g4, %g5)
 	sethi	%hi(vac_cache_size), %g4
@@ -46,7 +45,6 @@
 	 sta	%g0, [%g0] ASI_M_FLUSH_IWHOLE	! hyper_flush_whole_icache
 
 	/* We expand the window flush to get maximum performance. */
-	/* Verified... */
 hypersparc_flush_cache_mm:
 #ifndef __SMP__
 	ld	[%o0 + AOFF_mm_context], %g1
@@ -84,7 +82,6 @@
 	 sta	%g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE	! hyper_flush_whole_icache
 
 	/* The things we do for performance... */
-	/* Verified... */
 hypersparc_flush_cache_range:
 #ifndef __SMP__
 	ld	[%o0 + AOFF_mm_context], %g1
@@ -174,12 +171,12 @@
 	/* HyperSparc requires a valid mapping where we are about to flush
 	 * in order to check for a physical tag match during the flush.
 	 */
-	/* Verified... */
+	/* Verified, my ass... */
 hypersparc_flush_cache_page:
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
+	ld	[%o0 + AOFF_mm_context], %g2
 #ifndef __SMP__
-	ld	[%o0 + AOFF_mm_context], %g1
-	cmp	%g1, -1
+	cmp	%g2, -1
 	be	hypersparc_flush_cache_page_out
 #endif
 	WINDOW_FLUSH(%g4, %g5)
@@ -189,7 +186,7 @@
 	mov	SRMMU_CTX_REG, %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
 	lda	[%o3] ASI_M_MMUREGS, %o2
-	sta	%g1, [%o3] ASI_M_MMUREGS
+	sta	%g2, [%o3] ASI_M_MMUREGS
 	or	%o1, 0x400, %o5
 	lda	[%o5] ASI_M_FLUSH_PROBE, %g1
 	orcc	%g0, %g1, %g0
@@ -223,12 +220,15 @@
 	lda	[%g7] ASI_M_MMUREGS, %g0
 	sta	%o2, [%g4] ASI_M_MMUREGS
 hypersparc_flush_cache_page_out:
-hypersparc_flush_sig_insns:		/* This is "neat"... */
 	retl
 	 sta	%g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
 
+hypersparc_flush_sig_insns:
+	flush	%o2
+	retl
+	 flush	%o2 + 4
+
 	/* HyperSparc is copy-back. */
-	/* Verified... */
 hypersparc_flush_page_to_ram:
 hypersparc_flush_chunk:
 	sethi	%hi(vac_line_size), %g1
@@ -271,13 +271,11 @@
 	retl
 	 nop
 
-	/* Verified... */
 hypersparc_flush_tlb_all:
 	mov	0x400, %g1
 	retl
 	 sta	%g0, [%g1] ASI_M_FLUSH_PROBE
 
-	/* Verified... */
 hypersparc_flush_tlb_mm:
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o1
@@ -293,7 +291,6 @@
 	retl
 	 sta	%g5, [%g1] ASI_M_MMUREGS
 
-	/* Verified... */
 hypersparc_flush_tlb_range:
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
@@ -317,7 +314,6 @@
 	retl
 	 sta	%g5, [%g1] ASI_M_MMUREGS
 
-	/* Verified... */
 hypersparc_flush_tlb_page:
 	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 	mov	SRMMU_CTX_REG, %g1
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.1.33/linux/arch/sparc/mm/init.c	Sun Jan 26 02:07:09 1997
+++ linux/arch/sparc/mm/init.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.47 1997/01/02 14:14:28 jj Exp $
+/*  $Id: init.c,v 1.48 1997/04/12 04:28:37 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -72,10 +72,10 @@
 		total++;
 		if (PageReserved(mem_map + i))
 			reserved++;
-		else if (!mem_map[i].count)
+		else if (!atomic_read(&mem_map[i].count))
 			free++;
 		else
-			shared += mem_map[i].count-1;
+			shared += atomic_read(&mem_map[i].count) - 1;
 	}
 	printk("%d pages of RAM\n",total);
 	printk("%d free pages\n",free);
@@ -241,7 +241,7 @@
 				datapages++;
 			continue;
 		}
-		mem_map[MAP_NR(addr)].count = 1;
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
 		num_physpages++;
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (!initrd_start ||
@@ -272,7 +272,7 @@
 	addr = (unsigned long)(&__init_begin);
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		mem_map[MAP_NR(addr)].count = 1;
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
 		free_page(addr);
 	}
 	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
@@ -291,9 +291,9 @@
 		if (PageReserved(mem_map + i))
 			continue;
 		val->totalram++;
-		if (!mem_map[i].count)
+		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += mem_map[i].count-1;
+		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c
--- v2.1.33/linux/arch/sparc/mm/loadmmu.c	Mon Dec 30 01:59:58 1996
+++ linux/arch/sparc/mm/loadmmu.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.45 1996/12/30 06:16:28 davem Exp $
+/* $Id: loadmmu.c,v 1.46 1997/04/10 05:12:51 davem Exp $
  * loadmmu.c:  This code loads up all the mm function pointers once the
  *             machine type has been determined.  It also sets the static
  *             mmu values such as PAGE_NONE, etc.
@@ -41,9 +41,9 @@
 char *(*mmu_lockarea)(char *, unsigned long);
 void  (*mmu_unlockarea)(char *, unsigned long);
 
-char *(*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
+__u32 (*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
 void  (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
-void  (*mmu_release_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
+void  (*mmu_release_scsi_one)(__u32, unsigned long, struct linux_sbus *sbus);
 void  (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
 
 void  (*mmu_map_dma_area)(unsigned long addr, int len);
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.1.33/linux/arch/sparc/mm/srmmu.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc/mm/srmmu.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.132 1997/03/18 17:56:47 jj Exp $
+/* $Id: srmmu.c,v 1.135 1997/04/14 05:38:49 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -674,7 +674,7 @@
 	: "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
 	  "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
 	  "r" (vac_line_size), "i" (PAGE_SIZE)
-	: "g4", "g5");
+	: "g4", "g5", "cc");
 }
 
 static void srmmu_set_pte_nocache_cypress(pte_t *ptep, pte_t pteval)
@@ -1155,7 +1155,7 @@
 			      "r" (MXCC_SRCSTREAM),
 			      "r" (MXCC_DESSTREAM),
 			      "r" (MXCC_STREAM_SIZE),
-			      "i" (ASI_M_MXCC) : "g2", "g3");
+			      "i" (ASI_M_MXCC) : "g2", "g3", "cc");
 
 	/* This was handcoded after a look at the gcc output from
 	 *
@@ -1234,7 +1234,7 @@
 	2:	subcc	%0, 1, %0
 		bne	2b
 		 restore %%g0, %%g0, %%g0"
-	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4");
+	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4", "cc");
 	srmmu_flush_whole_tlb();
 	module_stats.invall++;
 }
@@ -1262,7 +1262,7 @@
 	: "r" (SRMMU_CTX_REG), "r" (0x300), "r" (mm->context),
 	  "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE), "0" (ctr),
 	  "i" (UWINMASK_OFFSET)
-	: "g4");
+	: "g4", "cc");
 	module_stats.invmm++;
 	FLUSH_END
 }
@@ -1283,7 +1283,7 @@
 	2:	subcc	%0, 1, %0
 		bne	2b
 		 restore %%g0, %%g0, %%g0"
-	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4");
+	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4", "cc");
 	start &= SRMMU_PGDIR_MASK;
 	size = SRMMU_PGDIR_ALIGN(end) - start;
 	__asm__ __volatile__("
@@ -1297,7 +1297,7 @@
 	: "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (start | 0x200),
 	  "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS),
 	  "i" (ASI_M_FLUSH_PROBE)
-	: "g5");
+	: "g5", "cc");
 	module_stats.invrnge++;
 	FLUSH_END
 }
@@ -1318,7 +1318,7 @@
 	2:	subcc	%0, 1, %0
 		bne	2b
 		 restore %%g0, %%g0, %%g0"
-	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4");
+	: "=&r" (ctr) : "0" (ctr), "i" (UWINMASK_OFFSET) : "g4", "cc");
 	__asm__ __volatile__("
 	lda	[%0] %3, %%g5
 	sta	%1, [%0] %3
@@ -1553,7 +1553,7 @@
 	: "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (start | 0x200),
 	  "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS),
 	  "i" (ASI_M_FLUSH_PROBE)
-	: "g5");
+	: "g5", "cc");
 	module_stats.invrnge++;
 	FLUSH_END
 }
@@ -1822,7 +1822,7 @@
 	sbus->iommu = (struct iommu_struct *)iommu;
 }
 
-static char *srmmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+static __u32 srmmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
 {
 	unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
 
@@ -1830,7 +1830,7 @@
 		flush_page_for_dma(page);
 		page += PAGE_SIZE;
 	}
-	return vaddr;
+	return (__u32)vaddr;
 }
 
 static void srmmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
@@ -1843,12 +1843,12 @@
 			flush_page_for_dma(page);
 			page += PAGE_SIZE;
 		}
-		sg[sz].dvma_addr = (char *) (sg[sz].addr);
+		sg[sz].dvma_addr = (__u32) (sg[sz].addr);
 		sz--;
 	}
 }
 
-static void srmmu_release_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+static void srmmu_release_scsi_one(__u32 vaddr, unsigned long len, struct linux_sbus *sbus)
 {
 }
 
@@ -2666,7 +2666,10 @@
 	mreg |= (HYPERSPARC_CMODE);
 
 	srmmu_set_mmureg(mreg);
+
+#if 0 /* I think this is bad news... -DaveM */
 	hyper_clear_all_tags();
+#endif
 
 	put_ross_icr(HYPERSPARC_ICCR_FTD | HYPERSPARC_ICCR_ICE);
 	hyper_flush_whole_icache();
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.1.33/linux/arch/sparc/mm/sun4c.c	Mon Mar 17 14:54:22 1997
+++ linux/arch/sparc/mm/sun4c.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.139 1997/01/31 08:05:59 davem Exp $
+/* $Id: sun4c.c,v 1.143 1997/04/11 00:42:14 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -23,8 +23,48 @@
 #include <asm/openprom.h>
 #include <asm/mmu_context.h>
 
+/* TODO: Make it such that interrupt handlers cannot dick with
+ *       the user segment lists, most of the cli/sti pairs can
+ *       disappear once that is taken care of.
+ */
+
+/* XXX Ok the real performance win, I figure, will be to use a combined hashing
+ * XXX and bitmap scheme to keep track of what we have mapped where.  The whole
+ * XXX incentive is to make it such that the range flushes can be serviced
+ * XXX always in near constant time. --DaveM
+ */
+
 extern int num_segmaps, num_contexts;
 
+/* Define this to get extremely anal debugging, undefine for performance. */
+/* #define DEBUG_SUN4C_MM */
+
+#define UWINMASK_OFFSET (const unsigned long)(&(((struct task_struct *)0)->tss.uwinmask))
+
+/* This is used in many routines below. */
+#define FUW_INLINE do {							\
+	register int ctr asm("g5");					\
+	ctr = 0;							\
+	__asm__ __volatile__("\n"					\
+	"1:	ld	[%%g6 + %2], %%g4	! flush user windows\n"	\
+	"	orcc	%%g0, %%g4, %%g0\n"				\
+	"	add	%0, 1, %0\n"					\
+	"	bne	1b\n"						\
+	"	 save	%%sp, -64, %%sp\n"				\
+	"2:	subcc	%0, 1, %0\n"					\
+	"	bne	2b\n"						\
+	"	 restore %%g0, %%g0, %%g0\n"				\
+	: "=&r" (ctr)							\
+	: "0" (ctr), "i" (UWINMASK_OFFSET)				\
+	: "g4", "cc");							\
+} while(0);
+
+/* That's it, we prom_halt() if the cache size is something other than 65536.
+ * So let's save some cycles and just use that everywhere except for that bootup
+ * sanity check.
+ */
+#define SUN4C_VAC_SIZE	65536
+
 #define SUN4C_KERNEL_BUCKETS 32
 
 #ifndef MAX
@@ -100,7 +140,7 @@
 
 	/* Clear 'valid' bit in all cache line tags */
 	begin = AC_CACHETAGS;
-	end = (AC_CACHETAGS + sun4c_vacinfo.num_bytes);
+	end = (AC_CACHETAGS + SUN4C_VAC_SIZE);
 	while(begin < end) {
 		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 				     "r" (begin), "i" (ASI_CONTROL));
@@ -108,83 +148,68 @@
 	}
 }
 
-/* Blow the entire current context out of the virtual cache. */
-static inline void sun4c_flush_context(void)
+/* Context level flush. */
+static inline void sun4c_flush_context_hw(void)
 {
-	extern unsigned long bcopy;
-	unsigned long begin, end, flags;
+	unsigned long end = SUN4C_VAC_SIZE;
+	unsigned pgsz = PAGE_SIZE;
 
 	ctxflushes++;
+	__asm__ __volatile__("
+1:	subcc	%0, %2, %0
+	bg	1b
+	 sta	%%g0, [%0] %3
+	nop; nop; nop;		! Weitek hwbug
+"	: "=&r" (end)
+	: "0" (end), "r" (pgsz), "i" (ASI_HWFLUSHCONTEXT)
+	: "cc");
+}
 
-	begin = ((unsigned long) &bcopy);
-	end = (begin + sun4c_vacinfo.num_bytes);
+/* Don't inline the software version as it eats too many cache lines if expanded. */
+static void sun4c_flush_context_sw(void)
+{
+	unsigned long nbytes = SUN4C_VAC_SIZE;
+	unsigned long lsize = sun4c_vacinfo.linesize;
 
-	save_and_cli(flags);
-	if(sun4c_vacinfo.linesize == 32) {
-		while(begin < end) {
-			__asm__ __volatile__("
-			ld	[%0 + 0x00], %%g0
-			ld	[%0 + 0x20], %%g0
-			ld	[%0 + 0x40], %%g0
-			ld	[%0 + 0x60], %%g0
-			ld	[%0 + 0x80], %%g0
-			ld	[%0 + 0xa0], %%g0
-			ld	[%0 + 0xc0], %%g0
-			ld	[%0 + 0xe0], %%g0
-			ld	[%0 + 0x100], %%g0
-			ld	[%0 + 0x120], %%g0
-			ld	[%0 + 0x140], %%g0
-			ld	[%0 + 0x160], %%g0
-			ld	[%0 + 0x180], %%g0
-			ld	[%0 + 0x1a0], %%g0
-			ld	[%0 + 0x1c0], %%g0
-			ld	[%0 + 0x1e0], %%g0
-			" : : "r" (begin));
-			begin += 512;
-		}
-	} else {
-		while(begin < end) {
-			__asm__ __volatile__("
-			ld	[%0 + 0x00], %%g0
-			ld	[%0 + 0x10], %%g0
-			ld	[%0 + 0x20], %%g0
-			ld	[%0 + 0x30], %%g0
-			ld	[%0 + 0x40], %%g0
-			ld	[%0 + 0x50], %%g0
-			ld	[%0 + 0x60], %%g0
-			ld	[%0 + 0x70], %%g0
-			ld	[%0 + 0x80], %%g0
-			ld	[%0 + 0x90], %%g0
-			ld	[%0 + 0xa0], %%g0
-			ld	[%0 + 0xb0], %%g0
-			ld	[%0 + 0xc0], %%g0
-			ld	[%0 + 0xd0], %%g0
-			ld	[%0 + 0xe0], %%g0
-			ld	[%0 + 0xf0], %%g0
-			" : : "r" (begin));
-			begin += 256;
-		}
-	}
-	restore_flags(flags);
+	ctxflushes++;
+	__asm__ __volatile__("
+	add	%2, %2, %%g1
+	add	%2, %%g1, %%g2
+	add	%2, %%g2, %%g3
+	add	%2, %%g3, %%g4
+	add	%2, %%g4, %%g5
+	add	%2, %%g5, %%o4
+	add	%2, %%o4, %%o5
+1:	subcc	%0, %%o5, %0
+	sta	%%g0, [%0] %3
+	sta	%%g0, [%0 + %2] %3
+	sta	%%g0, [%0 + %%g1] %3
+	sta	%%g0, [%0 + %%g2] %3
+	sta	%%g0, [%0 + %%g3] %3
+	sta	%%g0, [%0 + %%g4] %3
+	sta	%%g0, [%0 + %%g5] %3
+	bg	1b
+	 sta	%%g0, [%1 + %%o4] %3
+"	: "=&r" (nbytes)
+	: "0" (nbytes), "r" (lsize), "i" (ASI_FLUSHCTX)
+	: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
 }
 
 /* Scrape the segment starting at ADDR from the virtual cache. */
 static inline void sun4c_flush_segment(unsigned long addr)
 {
-	segflushes++;
-	addr &= SUN4C_REAL_PGDIR_MASK;
-
 	if(sun4c_get_segmap(addr) == invalid_segment)
 		return;
 
+	segflushes++;
 	if(sun4c_vacinfo.do_hwflushes) {
-		unsigned long end = (addr + sun4c_vacinfo.num_bytes);
+		unsigned long end = (addr + SUN4C_VAC_SIZE);
 
 		for( ; addr < end; addr += PAGE_SIZE)
-			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+			__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
 					     "r" (addr), "i" (ASI_HWFLUSHSEG));
 	} else {
-		unsigned long nbytes = sun4c_vacinfo.num_bytes;
+		unsigned long nbytes = SUN4C_VAC_SIZE;
 		unsigned long lsize = sun4c_vacinfo.linesize;
 
 		__asm__ __volatile__("add	%2, %2, %%g1\n\t"
@@ -209,12 +234,61 @@
 				     : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)
 				     : "0" (addr), "1" (nbytes), "2" (lsize),
 				       "i" (ASI_FLUSHSEG)
-				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5");
+				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
+	}
+}
+
+/* Call this version when you know hardware flushes are available. */
+static inline void sun4c_flush_segment_hw(unsigned long addr)
+{
+	if(sun4c_get_segmap(addr) != invalid_segment) {
+		unsigned long end;
+
+		segflushes++;
+		for(end = addr + SUN4C_VAC_SIZE; addr < end; addr += PAGE_SIZE)
+			__asm__ __volatile__("sta %%g0, [%0] %1"
+					     : : "r" (addr), "i" (ASI_HWFLUSHSEG));
+		/* Weitek POWER-UP hwbug workaround. */
+		__asm__ __volatile__("nop;nop;nop;	! Weitek hwbug");
+	}
+}
+
+/* Don't inline the software version as it eats too many cache lines if expanded. */
+static void sun4c_flush_segment_sw(unsigned long addr)
+{
+	if(sun4c_get_segmap(addr) != invalid_segment) {
+		unsigned long nbytes = SUN4C_VAC_SIZE;
+		unsigned long lsize = sun4c_vacinfo.linesize;
+
+		segflushes++;
+		__asm__ __volatile__("
+		add	%2, %2, %%g1
+		add	%2, %%g1, %%g2
+		add	%2, %%g2, %%g3
+		add	%2, %%g3, %%g4
+		add	%2, %%g4, %%g5
+		add	%2, %%g5, %%o4
+		add	%2, %%o4, %%o5
+1:		subcc	%1, %%o5, %1
+		sta	%%g0, [%0] %6
+		sta	%%g0, [%0 + %2] %6
+		sta	%%g0, [%0 + %%g1] %6
+		sta	%%g0, [%0 + %%g2] %6
+		sta	%%g0, [%0 + %%g3] %6
+		sta	%%g0, [%0 + %%g4] %6
+		sta	%%g0, [%0 + %%g5] %6
+		sta	%%g0, [%0 + %%o4] %6
+		bg	1b
+		 add	%0, %%o5, %0
+"		: "=&r" (addr), "=&r" (nbytes), "=&r" (lsize)
+		: "0" (addr), "1" (nbytes), "2" (lsize),
+		  "i" (ASI_FLUSHSEG)
+		: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
 	}
 }
 
 /* Bolix one page from the virtual cache. */
-static inline void sun4c_flush_page(unsigned long addr)
+static void sun4c_flush_page(unsigned long addr)
 {
 	addr &= PAGE_MASK;
 
@@ -224,7 +298,7 @@
 
 	pageflushes++;
 	if(sun4c_vacinfo.do_hwflushes) {
-		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
+		__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
 				     "r" (addr), "i" (ASI_HWFLUSHPAGE));
 	} else {
 		unsigned long left = PAGE_SIZE;
@@ -252,7 +326,57 @@
 				     : "=&r" (addr), "=&r" (left), "=&r" (lsize)
 				     : "0" (addr), "1" (left), "2" (lsize),
 				       "i" (ASI_FLUSHPG)
-				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5");
+				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
+	}
+}
+
+/* Again, hw-only and sw-only cache page-level flush variants. */
+static inline void sun4c_flush_page_hw(unsigned long addr)
+{
+	addr &= PAGE_MASK;
+	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
+	   _SUN4C_PAGE_VALID) {
+		pageflushes++;
+		__asm__ __volatile__("sta %%g0, [%0] %1"
+				     : : "r" (addr), "i" (ASI_HWFLUSHPAGE));
+		/* Weitek POWER-UP hwbug workaround. */
+		__asm__ __volatile__("nop;nop;nop;	! Weitek hwbug");
+	}
+}
+
+/* Don't inline the software version as it eats too many cache lines if expanded. */
+static void sun4c_flush_page_sw(unsigned long addr)
+{
+	addr &= PAGE_MASK;
+	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) ==
+	   _SUN4C_PAGE_VALID) {
+		unsigned long left = PAGE_SIZE;
+		unsigned long lsize = sun4c_vacinfo.linesize;
+
+		pageflushes++;
+		__asm__ __volatile__("
+		add	%2, %2, %%g1
+		add	%2, %%g1, %%g2
+		add	%2, %%g2, %%g3
+		add	%2, %%g3, %%g4
+		add	%2, %%g4, %%g5
+		add	%2, %%g5, %%o4
+		add	%2, %%o4, %%o5
+1:		subcc	%1, %%o5, %1
+		sta	%%g0, [%0] %6
+		sta	%%g0, [%0 + %2] %6
+		sta	%%g0, [%0 + %%g1] %6
+		sta	%%g0, [%0 + %%g2] %6
+		sta	%%g0, [%0 + %%g3] %6
+		sta	%%g0, [%0 + %%g4] %6
+		sta	%%g0, [%0 + %%g5] %6
+		sta	%%g0, [%0 + %%o4] %6
+		bg	1b
+		 add	%0, %%o5, %0
+"		: "=&r" (addr), "=&r" (left), "=&r" (lsize)
+		: "0" (addr), "1" (left), "2" (lsize),
+		  "i" (ASI_FLUSHPG)
+		: "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
 	}
 }
 
@@ -615,26 +739,33 @@
 	ring->num_entries++;
 }
 
-static inline void remove_ring(struct sun4c_mmu_ring *ring,
-			       struct sun4c_mmu_entry *entry)
+static inline void add_ring_ordered(struct sun4c_mmu_ring *ring,
+				    struct sun4c_mmu_entry *entry)
 {
-	struct sun4c_mmu_entry *next = entry->next;
+	struct sun4c_mmu_entry *head = &ring->ringhd;
+	unsigned long addr = entry->vaddr;
 
-	(next->prev = entry->prev)->next = next;
-	ring->num_entries--;
+	if(head->next != &ring->ringhd) {
+		while((head->next != &ring->ringhd) && (head->next->vaddr < addr))
+			head = head->next;
+	}
+	entry->prev = head;
+	(entry->next = head->next)->prev = entry;
+	head->next = entry;
+	ring->num_entries++;
 }
 
-static inline void recycle_ring(struct sun4c_mmu_ring *ring,
-			        struct sun4c_mmu_entry *entry)
+static inline void remove_ring(struct sun4c_mmu_ring *ring,
+			       struct sun4c_mmu_entry *entry)
 {
-	struct sun4c_mmu_entry *head = &ring->ringhd;
 	struct sun4c_mmu_entry *next = entry->next;
 
 	(next->prev = entry->prev)->next = next;
-	entry->prev = head;
-	(entry->next = head->next)->prev = entry;
-	head->next = entry;
-	/* num_entries stays the same */
+	ring->num_entries--;
+#ifdef DEBUG_SUN4C_MM
+	if(ring->num_entries < 0)
+		panic("sun4c: Ring num_entries < 0!");
+#endif
 }
 
 static inline void free_user_entry(int ctx, struct sun4c_mmu_entry *entry)
@@ -646,7 +777,7 @@
 static inline void assign_user_entry(int ctx, struct sun4c_mmu_entry *entry) 
 {
         remove_ring(&sun4c_ufree_ring, entry);
-        add_ring(sun4c_context_ring+ctx, entry);
+        add_ring_ordered(sun4c_context_ring+ctx, entry);
 }
 
 static inline void free_kernel_entry(struct sun4c_mmu_entry *entry,
@@ -724,24 +855,55 @@
 	}
 }
 
-static inline void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
+static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx)
 {
-	struct sun4c_mmu_entry *this_entry, *next_entry;
+	struct sun4c_mmu_entry *head = &crp->ringhd;
 	unsigned long flags;
-	int savectx = sun4c_get_context();
 
 	save_and_cli(flags);
-	this_entry = crp->ringhd.next;
-	flush_user_windows();
-	sun4c_set_context(ctx);
-	while(crp->num_entries) {
-		next_entry = this_entry->next;
-		sun4c_flush_segment(this_entry->vaddr);
-		sun4c_user_unmap(this_entry);
-		free_user_entry(ctx, this_entry);
-		this_entry = next_entry;
+	if(head->next != head) {
+		struct sun4c_mmu_entry *entry = head->next;
+		int savectx = sun4c_get_context();
+
+		FUW_INLINE
+		sun4c_set_context(ctx);
+		sun4c_flush_context_hw();
+		do {
+			struct sun4c_mmu_entry *next = entry->next;
+
+			sun4c_user_unmap(entry);
+			free_user_entry(ctx, entry);
+
+			entry = next;
+		} while(entry != head);
+		sun4c_set_context(savectx);
+	}
+	restore_flags(flags);
+}
+
+static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx)
+{
+	struct sun4c_mmu_entry *head = &crp->ringhd;
+	unsigned long flags;
+
+	save_and_cli(flags);
+	if(head->next != head) {
+		struct sun4c_mmu_entry *entry = head->next;
+		int savectx = sun4c_get_context();
+
+		FUW_INLINE
+		sun4c_set_context(ctx);
+		sun4c_flush_context_sw();
+		do {
+			struct sun4c_mmu_entry *next = entry->next;
+
+			sun4c_user_unmap(entry);
+			free_user_entry(ctx, entry);
+
+			entry = next;
+		} while(entry != head);
+		sun4c_set_context(savectx);
 	}
-	sun4c_set_context(savectx);
 	restore_flags(flags);
 }
 
@@ -749,17 +911,25 @@
 {
 	/* by using .prev we get a kind of "lru" algorithm */
 	struct sun4c_mmu_entry *entry = crp->ringhd.prev;
+	unsigned long flags;
 	int savectx = sun4c_get_context();
 
-	flush_user_windows();
+#ifdef DEBUG_SUN4C_MM
+	if(entry == &crp->ringhd)
+		panic("sun4c_demap_one: Freeing from empty ctx ring.");
+#endif
+	FUW_INLINE
+	save_and_cli(flags);
 	sun4c_set_context(ctx);
 	sun4c_flush_segment(entry->vaddr);
 	sun4c_user_unmap(entry);
 	free_user_entry(ctx, entry);
 	sun4c_set_context(savectx);
+	restore_flags(flags);
 }
 
-static int sun4c_user_taken_entries = 0;
+static int sun4c_user_taken_entries = 0;  /* This is how much we have.             */
+static int max_user_taken_entries = 0;    /* This limits us and prevents deadlock. */
 
 static inline struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
 {
@@ -800,6 +970,10 @@
 			sun4c_kfree_ring.num_entries,
 			sun4c_kernel_ring.num_entries);
 #endif
+#ifdef DEBUG_SUN4C_MM
+		if(sun4c_user_taken_entries < 0)
+			panic("sun4c_shrink_kernel_ring: taken < 0.");
+#endif
 	}
 	restore_flags(flags);
 }
@@ -813,25 +987,50 @@
 	struct ctx_list *next_one;
 	struct sun4c_mmu_ring *rp = 0;
 	unsigned char ctx;
+#ifdef DEBUG_SUN4C_MM
+	int lim = num_contexts;
+#endif
 
 	/* If some are free, return first one. */
-	if(sun4c_ufree_ring.num_entries)
+	if(sun4c_ufree_ring.num_entries) {
+#ifdef DEBUG_SUN4C_MM
+		if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
+			panic("sun4c_user_strategy: num_entries!=0 but ring empty.");
+#endif
 		return sun4c_ufree_ring.ringhd.next;
+	}
 
 	if (sun4c_user_taken_entries) {
 		sun4c_shrink_kernel_ring();
+#ifdef DEBUG_SUN4C_MM
+		if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
+			panic("sun4c_user_strategy: kernel shrunk but ufree empty.");
+#endif
 		return sun4c_ufree_ring.ringhd.next;
 	}
 
 	/* Grab one from the LRU context. */
 	next_one = ctx_used.next;
-	while (sun4c_context_ring[next_one->ctx_number].num_entries == 0)
+	while ((sun4c_context_ring[next_one->ctx_number].num_entries == 0)
+#ifdef DEBUG_SUN4C_MM
+	       && (--lim >= 0)
+#endif
+	       )
 		next_one = next_one->next;
 
+#ifdef DEBUG_SUN4C_MM
+	if(lim < 0)
+		panic("No user segmaps!");
+#endif
+
 	ctx = next_one->ctx_number;
 	rp = &sun4c_context_ring[ctx];
 
 	sun4c_demap_one(rp, ctx);
+#ifdef DEBUG_SUN4C_MM
+	if(sun4c_ufree_ring.ringhd.next == &sun4c_ufree_ring.ringhd)
+		panic("sun4c_user_strategy: demapped one but ufree empty.");
+#endif
 	return sun4c_ufree_ring.ringhd.next;
 }
 
@@ -839,13 +1038,34 @@
 {
 	struct sun4c_mmu_entry *entry;
 
+#if 0
+	printk("grow: ");
+#endif
+
+	/* Prevent deadlock condition. */
+	if(sun4c_user_taken_entries >= max_user_taken_entries) {
+#if 0
+		printk("deadlock avoidance, taken= %d max= %d\n",
+		       sun4c_user_taken_entries, max_user_taken_entries);
+#endif
+		return;
+	}
+
 	if (sun4c_ufree_ring.num_entries) {
 		entry = sun4c_ufree_ring.ringhd.next;
+#ifdef DEBUG_SUN4C_MM
+		if(entry == &sun4c_ufree_ring.ringhd)
+			panic("\nsun4c_grow_kernel_ring: num_entries!=0, ring empty.");
+#endif
         	remove_ring(&sun4c_ufree_ring, entry);
 		add_ring(&sun4c_kfree_ring, entry);
+#ifdef DEBUG_SUN4C_MM
+		if(sun4c_user_taken_entries < 0)
+			panic("\nsun4c_grow_kernel_ring: taken < 0.");
+#endif
 		sun4c_user_taken_entries++;
 #if 0
-		printk("grow: ufree= %d, kfree= %d, kernel= %d\n",
+		printk("ufree= %d, kfree= %d, kernel= %d\n",
 			sun4c_ufree_ring.num_entries,
 			sun4c_kfree_ring.num_entries,
 			sun4c_kernel_ring.num_entries);
@@ -856,12 +1076,14 @@
 static inline void alloc_user_segment(unsigned long address, unsigned char ctx)
 {
 	struct sun4c_mmu_entry *entry;
+	unsigned long flags;
 
-	address &= SUN4C_REAL_PGDIR_MASK;
+	save_and_cli(flags);
 	entry = sun4c_user_strategy();
+	entry->vaddr = (address & SUN4C_REAL_PGDIR_MASK);
 	assign_user_entry(ctx, entry);
-	entry->vaddr = address;
 	sun4c_user_map(entry);
+	restore_flags(flags);
 }
 
 /* This is now a fast in-window trap handler to avoid any and all races. */
@@ -896,6 +1118,8 @@
 
 struct task_bucket *sun4c_bucket[NR_TASKS];
 
+static int sun4c_lowbucket_avail;
+
 #define BUCKET_EMPTY     ((struct task_bucket *) 0)
 #define BUCKET_SIZE      (PAGE_SIZE << 2)
 #define BUCKET_SHIFT     14        /* log2(sizeof(struct task_bucket)) */
@@ -915,8 +1139,13 @@
 	addr &= SUN4C_REAL_PGDIR_MASK;
 	stolen = sun4c_user_strategy();
 	remove_ring(&sun4c_ufree_ring, stolen);
+	max_user_taken_entries--;
+#ifdef DEBUG_SUN4C_MM
+	if(max_user_taken_entries < 0)
+		panic("get_locked_segment: max_user_taken < 0.");
+#endif
 	stolen->vaddr = addr;
-	flush_user_windows();
+	FUW_INLINE
 	sun4c_kernel_map(stolen);
 	restore_flags(flags);
 }
@@ -931,60 +1160,52 @@
 	addr &= SUN4C_REAL_PGDIR_MASK;
 	pseg = sun4c_get_segmap(addr);
 	entry = &mmu_entry_pool[pseg];
-	flush_user_windows();
+
+	FUW_INLINE
 	sun4c_flush_segment(addr);
 	sun4c_kernel_unmap(entry);
 	add_ring(&sun4c_ufree_ring, entry);
+#ifdef DEBUG_SUN4C_MM
+	if(max_user_taken_entries < 0)
+		panic("free_locked_segment: max_user_taken < 0.");
+#endif
+	max_user_taken_entries++;
 	restore_flags(flags);
 }
 
 static inline void garbage_collect(int entry)
 {
-	unsigned long flags;
 	int start, end;
 
-	save_and_cli(flags);
-
 	/* 16 buckets per segment... */
 	entry &= ~15;
 	start = entry;
 	for(end = (start + 16); start < end; start++)
 		if(sun4c_bucket[start] != BUCKET_EMPTY)
-			goto done;
+			return;
+
 	/* Entire segment empty, release it. */
 	free_locked_segment(BUCKET_ADDR(entry));
-done:
-	restore_flags(flags);
 }
 
 static struct task_struct *sun4c_alloc_task_struct(void)
 {
-	unsigned long addr, page, flags;
+	unsigned long addr, page;
 	int entry;
 
-	save_and_cli(flags);
-
 	page = get_free_page(GFP_KERNEL);
-	if(!page) {
-		restore_flags(flags);
+	if(!page)
 		return (struct task_struct *) 0;
-	}
-	/* XXX Bahh, linear search too slow, use hash
-	 * XXX table in final implementation.  Or
-	 * XXX keep track of first free when we free
-	 * XXX a bucket... anything but this.
-	 */
-	for(entry = 0; entry < NR_TASKS; entry++)
+
+	for(entry = sun4c_lowbucket_avail; entry < NR_TASKS; entry++)
 		if(sun4c_bucket[entry] == BUCKET_EMPTY)
 			break;
 	if(entry == NR_TASKS) {
 		free_page(page);
-		restore_flags(flags);
 		return (struct task_struct *) 0;
 	}
-
-	/* Prevent an alias from occurring while the page is ours. */
-	sun4c_flush_page(page);
+	if(entry >= sun4c_lowbucket_avail)
+		sun4c_lowbucket_avail = entry + 1;
 
 	addr = BUCKET_ADDR(entry);
 	sun4c_bucket[entry] = (struct task_bucket *) addr;
@@ -992,8 +1213,6 @@
 		get_locked_segment(addr);
 	sun4c_put_pte(addr, BUCKET_PTE(page));
 
-	restore_flags(flags);
-
 	return (struct task_struct *) addr;
 }
 
@@ -1013,47 +1232,80 @@
 		return 0;
 	}
 
-	/* Prevent aliases from occurring while the pages are ours. */
-	sun4c_flush_page(page[0]);
-	sun4c_flush_page(page[1]);
-
 	saddr += PAGE_SIZE << 1;
 	sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
 	sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
 	return saddr;
 }
 
-static void sun4c_free_kernel_stack(unsigned long stack)
+static void sun4c_free_kernel_stack_hw(unsigned long stack)
 {
 	unsigned long page[2];
-	unsigned long flags;
 
-	save_and_cli(flags);
 	page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
 	page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
-	sun4c_flush_page(stack);
-	sun4c_flush_page(stack + PAGE_SIZE);
+
+	/* We are deleting a mapping, so the flushes here are mandatory. */
+	sun4c_flush_page_hw(stack);
+	sun4c_flush_page_hw(stack + PAGE_SIZE);
+
 	sun4c_put_pte(stack, 0);
 	sun4c_put_pte(stack + PAGE_SIZE, 0);
 	free_page(page[0]);
 	free_page(page[1]);
-	restore_flags(flags);
 }
 
-static void sun4c_free_task_struct(struct task_struct *tsk)
+static void sun4c_free_task_struct_hw(struct task_struct *tsk)
 {
 	unsigned long tsaddr = (unsigned long) tsk;
 	unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
-	unsigned long flags;
 	int entry = BUCKET_NUM(tsaddr);
 
-	save_and_cli(flags);
-	sun4c_flush_page(tsaddr);
+	/* We are deleting a mapping, so the flush here is mandatory. */
+	sun4c_flush_page_hw(tsaddr);
+
 	sun4c_put_pte(tsaddr, 0);
 	sun4c_bucket[entry] = BUCKET_EMPTY;
+	if(entry < sun4c_lowbucket_avail)
+		sun4c_lowbucket_avail = entry;
+
+	free_page(page);
+	garbage_collect(entry);
+}
+
+static void sun4c_free_kernel_stack_sw(unsigned long stack)
+{
+	unsigned long page[2];
+
+	page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
+	page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
+
+	/* We are deleting a mapping, so the flushes here are mandatory. */
+	sun4c_flush_page_sw(stack);
+	sun4c_flush_page_sw(stack + PAGE_SIZE);
+
+	sun4c_put_pte(stack, 0);
+	sun4c_put_pte(stack + PAGE_SIZE, 0);
+	free_page(page[0]);
+	free_page(page[1]);
+}
+
+static void sun4c_free_task_struct_sw(struct task_struct *tsk)
+{
+	unsigned long tsaddr = (unsigned long) tsk;
+	unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+	int entry = BUCKET_NUM(tsaddr);
+
+	/* We are deleting a mapping, so the flush here is mandatory. */
+	sun4c_flush_page_sw(tsaddr);
+
+	sun4c_put_pte(tsaddr, 0);
+	sun4c_bucket[entry] = BUCKET_EMPTY;
+	if(entry < sun4c_lowbucket_avail)
+		sun4c_lowbucket_avail = entry;
+
 	free_page(page);
 	garbage_collect(entry);
-	restore_flags(flags);
 }
 
 __initfunc(static void sun4c_init_buckets(void))
@@ -1066,6 +1318,7 @@
 	}
 	for(entry = 0; entry < NR_TASKS; entry++)
 		sun4c_bucket[entry] = BUCKET_EMPTY;
+	sun4c_lowbucket_avail = 0;
 }
 
 static unsigned long sun4c_iobuffer_start;
@@ -1151,6 +1404,8 @@
 	save_and_cli(flags);
 	while (npages != 0) {
 		--npages;
+
+		/* This mapping is marked non-cachable, no flush necessary. */
 		sun4c_put_pte(vpage, 0);
 		clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT,
 			  sun4c_iobuffer_map);
@@ -1176,39 +1431,37 @@
  * by implication and fool the page locking code above
  * if passed to by mistake.
  */
-static char *sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
 {
 	unsigned long page;
 
-	page = ((unsigned long) bufptr) & PAGE_MASK;
+	page = ((unsigned long)bufptr) & PAGE_MASK;
 	if(MAP_NR(page) > max_mapnr) {
 		sun4c_flush_page(page);
-		return bufptr; /* already locked */
+		return (__u32)bufptr; /* already locked */
 	}
-	return sun4c_lockarea(bufptr, len);
+	return (__u32)sun4c_lockarea(bufptr, len);
 }
 
 static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
 	while(sz >= 0) {
-		sg[sz].dvma_addr = sun4c_lockarea(sg[sz].addr, sg[sz].len);
+		sg[sz].dvma_addr = (__u32)sun4c_lockarea(sg[sz].addr, sg[sz].len);
 		sz--;
 	}
 }
 
-static void sun4c_release_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct linux_sbus *sbus)
 {
-	unsigned long page = (unsigned long) bufptr;
-
-	if(page < sun4c_iobuffer_start)
+	if(bufptr < sun4c_iobuffer_start)
 		return; /* On kernel stack or similar, see above */
-	sun4c_unlockarea(bufptr, len);
+	sun4c_unlockarea((char *)bufptr, len);
 }
 
 static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
 	while(sz >= 0) {
-		sun4c_unlockarea(sg[sz].dvma_addr, sg[sz].len);
+		sun4c_unlockarea((char *)sg[sz].dvma_addr, sg[sz].len);
 		sz--;
 	}
 }
@@ -1256,14 +1509,12 @@
 /* Cache flushing on the sun4c. */
 static void sun4c_flush_cache_all(void)
 {
-	extern unsigned long bcopy;
-	unsigned long begin, end, flags;
+	unsigned long begin, end;
 
-	begin = ((unsigned long) &bcopy);
-	end = (begin + sun4c_vacinfo.num_bytes);
+	FUW_INLINE
+	begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE);
+	end = (begin + SUN4C_VAC_SIZE);
 
-	save_and_cli(flags);
-	flush_user_windows();
 	if(sun4c_vacinfo.linesize == 32) {
 		while(begin < end) {
 			__asm__ __volatile__("
@@ -1309,106 +1560,236 @@
 			begin += 256;
 		}
 	}
-	restore_flags(flags);
 }
 
-static void sun4c_flush_cache_mm(struct mm_struct *mm)
+static void sun4c_flush_cache_mm_hw(struct mm_struct *mm)
 {
-	unsigned long flags;
-	int octx, new_ctx = mm->context;
+	int new_ctx = mm->context;
+
+	if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		unsigned long flags;
 
-	if(new_ctx != NO_CONTEXT) {
 		save_and_cli(flags);
-		octx = sun4c_get_context();
-		flush_user_windows();
-		sun4c_set_context(new_ctx);
-		sun4c_flush_context();
-		sun4c_set_context(octx);
+		if(head->next != head) {
+			struct sun4c_mmu_entry *entry = head->next;
+			int savectx = sun4c_get_context();
+
+			FUW_INLINE
+			sun4c_set_context(new_ctx);
+			sun4c_flush_context_hw();
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
+
+				sun4c_user_unmap(entry);
+				free_user_entry(new_ctx, entry);
+
+				entry = next;
+			} while(entry != head);
+			sun4c_set_context(savectx);
+		}
 		restore_flags(flags);
 	}
 }
 
-static void sun4c_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_cache_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	int size, size2, octx, i, new_ctx = mm->context;
-	unsigned long start2, end2, flags;
-	struct sun4c_mmu_entry *entry, *entry2;
+	int new_ctx = mm->context;
 	
 #if KGPROF_PROFILING
 	kgprof_profile();
 #endif
-
 	if(new_ctx != NO_CONTEXT) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		struct sun4c_mmu_entry *entry;
+		unsigned long flags;
+
+		FUW_INLINE
 		save_and_cli(flags);
 
-		size = end - start;
+		/* All user segmap chains are ordered on entry->vaddr. */
+		for(entry = head->next;
+		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		    entry = entry->next)
+			;
+
+		/* Tracing various job mixtures showed that this conditional
+		 * only passes ~35% of the time for most worse case situations,
+		 * therefore we avoid all of this gross overhead ~65% of the time.
+		 */
+		if((entry != head) && (entry->vaddr < end)) {
+			int octx = sun4c_get_context();
+			sun4c_set_context(new_ctx);
+
+			/* At this point, always, (start >= entry->vaddr) and
+			 * (entry->vaddr < end), once the latter condition
+			 * ceases to hold, or we hit the end of the list, we
+			 * exit the loop.  The ordering of all user allocated
+			 * segmaps makes this all work out so beautifully.
+			 */
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
+				unsigned long realend;
+
+				/* "realstart" is always >= entry->vaddr */
+				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
+				if(end < realend)
+					realend = end;
+				if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+					unsigned long page = entry->vaddr;
+					while(page < realend) {
+						sun4c_flush_page_hw(page);
+						page += PAGE_SIZE;
+					}
+				} else {
+					sun4c_flush_segment_hw(entry->vaddr);
+					sun4c_user_unmap(entry);
+					free_user_entry(new_ctx, entry);
+				}
+				entry = next;
+			} while((entry != head) && (entry->vaddr < end));
+			sun4c_set_context(octx);
+		}
+		restore_flags(flags);
+	}
+}
+
+/* XXX no save_and_cli/restore_flags needed, but put here if darkside still crashes */
+static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	int new_ctx = mm->context;
 
-		octx = sun4c_get_context();
-		flush_user_windows();
+	/* Sun4c has no separate I/D caches so cannot optimize for non
+	 * text page flushes.
+	 */
+	if(new_ctx != NO_CONTEXT) {
+		int octx = sun4c_get_context();
+
+		FUW_INLINE
 		sun4c_set_context(new_ctx);
+		sun4c_flush_page_hw(page);
+		sun4c_set_context(octx);
+	}
+}
+
+static void sun4c_flush_page_to_ram_hw(unsigned long page)
+{
+	sun4c_flush_page_hw(page);
+}
+
+static void sun4c_flush_cache_mm_sw(struct mm_struct *mm)
+{
+	int new_ctx = mm->context;
+
+	if(new_ctx != NO_CONTEXT && sun4c_context_ring[new_ctx].num_entries) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		unsigned long flags;
+
+		save_and_cli(flags);
+		if(head->next != head) {
+			struct sun4c_mmu_entry *entry = head->next;
+			int savectx = sun4c_get_context();
+
+			FUW_INLINE
+			sun4c_set_context(new_ctx);
+			sun4c_flush_context_sw();
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
 
-		entry = sun4c_context_ring[new_ctx].ringhd.next;
-		i = sun4c_context_ring[new_ctx].num_entries;
-		while (i--) {
-			entry2 = entry->next;
-			if (entry->vaddr < start || entry->vaddr >= end) 
-				goto next_entry;
-
-			start2 = MAX(start,entry->vaddr);
-			end2 = MIN(end,entry->vaddr+SUN4C_REAL_PGDIR_SIZE);
-			size2 = end2 - start2;
-
-			if (size2 <= (PAGE_SIZE << 3)) {
-				start2 &= PAGE_MASK;
-				while(start2 < end2) {
-					sun4c_flush_page(start2);
-					start2 += PAGE_SIZE;
-				}
-			} else {
-				start2 &= SUN4C_REAL_PGDIR_MASK;
-				sun4c_flush_segment(start2);
-
-				/* We are betting that the entry will not be 
-				 * needed for a while.
-				 */
 				sun4c_user_unmap(entry);
 				free_user_entry(new_ctx, entry);
-			}
 
-		next_entry:
-			entry = entry2;
+				entry = next;
+			} while(entry != head);
+			sun4c_set_context(savectx);
 		}
-		sun4c_set_context(octx);
 		restore_flags(flags);
 	}
 }
 
-static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+static void sun4c_flush_cache_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	int new_ctx = mm->context;
+	
+#if KGPROF_PROFILING
+	kgprof_profile();
+#endif
+	if(new_ctx != NO_CONTEXT) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		struct sun4c_mmu_entry *entry;
+		unsigned long flags;
+
+		FUW_INLINE
+		save_and_cli(flags);
+		/* All user segmap chains are ordered on entry->vaddr. */
+		for(entry = head->next;
+		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		    entry = entry->next)
+			;
+
+		/* Tracing various job mixtures showed that this conditional
+		 * only passes ~35% of the time for most worse case situations,
+		 * therefore we avoid all of this gross overhead ~65% of the time.
+		 */
+		if((entry != head) && (entry->vaddr < end)) {
+			int octx = sun4c_get_context();
+			sun4c_set_context(new_ctx);
+
+			/* At this point, always, (start >= entry->vaddr) and
+			 * (entry->vaddr < end), once the latter condition
+			 * ceases to hold, or we hit the end of the list, we
+			 * exit the loop.  The ordering of all user allocated
+			 * segmaps makes this all work out so beautifully.
+			 */
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
+				unsigned long realend;
+
+				/* "realstart" is always >= entry->vaddr */
+				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
+				if(end < realend)
+					realend = end;
+				if((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
+					unsigned long page = entry->vaddr;
+					while(page < realend) {
+						sun4c_flush_page_sw(page);
+						page += PAGE_SIZE;
+					}
+				} else {
+					sun4c_flush_segment_sw(entry->vaddr);
+					sun4c_user_unmap(entry);
+					free_user_entry(new_ctx, entry);
+				}
+				entry = next;
+			} while((entry != head) && (entry->vaddr < end));
+			sun4c_set_context(octx);
+		}
+		restore_flags(flags);
+	}
+}
+
+static void sun4c_flush_cache_page_sw(struct vm_area_struct *vma, unsigned long page)
 {
-	unsigned long flags;
 	struct mm_struct *mm = vma->vm_mm;
-	int octx, new_ctx = mm->context;
+	int new_ctx = mm->context;
 
 	/* Sun4c has no separate I/D caches so cannot optimize for non
 	 * text page flushes.
 	 */
 	if(new_ctx != NO_CONTEXT) {
-		save_and_cli(flags);
-		octx = sun4c_get_context();
-		flush_user_windows();
+		int octx = sun4c_get_context();
+
+		FUW_INLINE
 		sun4c_set_context(new_ctx);
-		sun4c_flush_page(page);
+		sun4c_flush_page_sw(page);
 		sun4c_set_context(octx);
-		restore_flags(flags);
 	}
 }
 
-/* Even though sun4c is write through, a virtual cache alias inconsistancy
- * can still occur with COW page handling so we must flush anyways.
- */
-static void sun4c_flush_page_to_ram(unsigned long page)
+static void sun4c_flush_page_to_ram_sw(unsigned long page)
 {
-	sun4c_flush_page(page);
+	sun4c_flush_page_sw(page);
 }
 
 /* Sun4c cache is unified, both instructions and data live there, so
@@ -1447,82 +1828,178 @@
 	restore_flags(flags);
 }
 
-static void sun4c_flush_tlb_mm(struct mm_struct *mm)
+static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm)
 {
-	struct sun4c_mmu_entry *this_entry, *next_entry;
-	struct sun4c_mmu_ring *crp;
-	unsigned long flags;
-	int savectx, new_ctx = mm->context;
+	int new_ctx = mm->context;
 
 	if(new_ctx != NO_CONTEXT) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		unsigned long flags;
+
 		save_and_cli(flags);
-		crp = &sun4c_context_ring[new_ctx];
-		savectx = sun4c_get_context();
-		this_entry = crp->ringhd.next;
-		flush_user_windows();
-		sun4c_set_context(new_ctx);
-		while(crp->num_entries) {
-			next_entry = this_entry->next;
-			sun4c_flush_segment(this_entry->vaddr);
-			sun4c_user_unmap(this_entry);
-			free_user_entry(new_ctx, this_entry);
-			this_entry = next_entry;
+		if(head->next != head) {
+			struct sun4c_mmu_entry *entry = head->next;
+			int savectx = sun4c_get_context();
+
+			FUW_INLINE
+			sun4c_set_context(new_ctx);
+			sun4c_flush_context_hw();
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
+
+				sun4c_user_unmap(entry);
+				free_user_entry(new_ctx, entry);
+
+				entry = next;
+			} while(entry != head);
+			sun4c_set_context(savectx);
+		}
+		restore_flags(flags);
+	}
+}
+
+static void sun4c_flush_tlb_range_hw(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	int new_ctx = mm->context;
+
+	if(new_ctx != NO_CONTEXT) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		struct sun4c_mmu_entry *entry;
+		unsigned long flags;
+#if KGPROF_PROFILING
+		kgprof_profile();
+#endif
+
+		save_and_cli(flags);
+		/* See commentary in sun4c_flush_cache_range_*(). */
+		for(entry = head->next;
+		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		    entry = entry->next)
+			;
+
+		if((entry != head) && (entry->vaddr < end)) {
+			int octx = sun4c_get_context();
+
+			/* This window flush is paranoid I think... -DaveM */
+			FUW_INLINE
+			sun4c_set_context(new_ctx);
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
+
+				sun4c_flush_segment_hw(entry->vaddr);
+				sun4c_user_unmap(entry);
+				free_user_entry(new_ctx, entry);
+
+				entry = next;
+			} while((entry != head) && (entry->vaddr < end));
+			sun4c_set_context(octx);
 		}
+		restore_flags(flags);
+	}
+}
+
+static void sun4c_flush_tlb_page_hw(struct vm_area_struct *vma, unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	int new_ctx = mm->context;
+
+	if(new_ctx != NO_CONTEXT) {
+		int savectx = sun4c_get_context();
+
+		FUW_INLINE
+		sun4c_set_context(new_ctx);
+		page &= PAGE_MASK;
+		sun4c_flush_page_hw(page);
+		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
+	}
+}
+
+static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm)
+{
+	int new_ctx = mm->context;
+
+	if(new_ctx != NO_CONTEXT) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		unsigned long flags;
+
+		save_and_cli(flags);
+		if(head->next != head) {
+			struct sun4c_mmu_entry *entry = head->next;
+			int savectx = sun4c_get_context();
+
+			FUW_INLINE
+			sun4c_set_context(new_ctx);
+			sun4c_flush_context_sw();
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
+
+				sun4c_user_unmap(entry);
+				free_user_entry(new_ctx, entry);
+
+				entry = next;
+			} while(entry != head);
+			sun4c_set_context(savectx);
+		}
 		restore_flags(flags);
 	}
 }
 
-static void sun4c_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void sun4c_flush_tlb_range_sw(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	struct sun4c_mmu_entry *entry, *entry2;
-	unsigned long flags;
-	int i, savectx, new_ctx = mm->context;
+	int new_ctx = mm->context;
 
-	if(new_ctx == NO_CONTEXT)
-		return;
+	if(new_ctx != NO_CONTEXT) {
+		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
+		struct sun4c_mmu_entry *entry;
+		unsigned long flags;
 
 #if KGPROF_PROFILING
-	kgprof_profile();
+		kgprof_profile();
 #endif
 
-	save_and_cli(flags);
-	savectx = sun4c_get_context();
-	flush_user_windows();
-	sun4c_set_context(new_ctx);
-	start &= SUN4C_REAL_PGDIR_MASK;
+		save_and_cli(flags);
+		/* See commentary in sun4c_flush_cache_range_*(). */
+		for(entry = head->next;
+		    (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
+		    entry = entry->next)
+			;
+
+		if((entry != head) && (entry->vaddr < end)) {
+			int octx = sun4c_get_context();
+
+			/* This window flush is paranoid I think... -DaveM */
+			FUW_INLINE
+			sun4c_set_context(new_ctx);
+			do {
+				struct sun4c_mmu_entry *next = entry->next;
 
-	entry = sun4c_context_ring[new_ctx].ringhd.next;
-	i = sun4c_context_ring[new_ctx].num_entries;
-	while (i--) {
-		entry2 = entry->next;
-		if (entry->vaddr >= start && entry->vaddr < end) {
-			sun4c_flush_segment(entry->vaddr);
-			sun4c_user_unmap(entry);
-			free_user_entry(new_ctx, entry);
+				sun4c_flush_segment_sw(entry->vaddr);
+				sun4c_user_unmap(entry);
+				free_user_entry(new_ctx, entry);
+
+				entry = next;
+			} while((entry != head) && (entry->vaddr < end));
+			sun4c_set_context(octx);
 		}
-		entry = entry2;
+		restore_flags(flags);
 	}
-	sun4c_set_context(savectx);
-	restore_flags(flags);
 }
 
-static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+static void sun4c_flush_tlb_page_sw(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	unsigned long flags;
-	int savectx, new_ctx = mm->context;
+	int new_ctx = mm->context;
 
 	if(new_ctx != NO_CONTEXT) {
-		save_and_cli(flags);
-		savectx = sun4c_get_context();
-		flush_user_windows();
+		int savectx = sun4c_get_context();
+
+		FUW_INLINE
 		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
-		sun4c_flush_page(page);
+		sun4c_flush_page_sw(page);
 		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
-		restore_flags(flags);
 	}
 }
 
@@ -1548,7 +2025,7 @@
 	sun4c_put_pte(virt_addr, 0);
 }
 
-static inline void sun4c_alloc_context(struct mm_struct *mm)
+static void sun4c_alloc_context_hw(struct mm_struct *mm)
 {
 	struct ctx_list *ctxp;
 
@@ -1563,74 +2040,114 @@
 	ctxp = ctx_used.next;
 	if(ctxp->ctx_mm == current->mm)
 		ctxp = ctxp->next;
+#ifdef DEBUG_SUN4C_MM
 	if(ctxp == &ctx_used)
 		panic("out of mmu contexts");
+#endif
 	remove_from_ctx_list(ctxp);
 	add_to_used_ctxlist(ctxp);
 	ctxp->ctx_mm->context = NO_CONTEXT;
 	ctxp->ctx_mm = mm;
 	mm->context = ctxp->ctx_number;
-	sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number],
+	sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number],
 			    ctxp->ctx_number);
 }
 
-#if some_day_soon /* We need some tweaking to start using this */
-extern void force_user_fault(unsigned long, int);
+static void sun4c_switch_to_context_hw(struct task_struct *tsk)
+{
+	struct ctx_list *ctx;
+
+	if(tsk->mm->context == NO_CONTEXT) {
+		sun4c_alloc_context_hw(tsk->mm);
+	} else {
+		/* Update the LRU ring of contexts. */
+		ctx = ctx_list_pool + tsk->mm->context;
+		remove_from_ctx_list(ctx);
+		add_to_used_ctxlist(ctx);
+	}
+	sun4c_set_context(tsk->mm->context);
+}
+
+static void sun4c_init_new_context_hw(struct mm_struct *mm)
+{
+	sun4c_alloc_context_hw(mm);
+	if(mm == current->mm)
+		sun4c_set_context(mm->context);
+}
 
-void sun4c_switch_heuristic(struct pt_regs *regs)
+static void sun4c_destroy_context_hw(struct mm_struct *mm)
 {
-	unsigned long sp = regs->u_regs[UREG_FP];
-	unsigned long sp2 = sp + REGWIN_SZ - 0x8;
+	struct ctx_list *ctx_old;
 
-	force_user_fault(regs->pc, 0);
-	force_user_fault(sp, 0);
-	if((sp&PAGE_MASK) != (sp2&PAGE_MASK))
-		force_user_fault(sp2, 0);
+	if(mm->context != NO_CONTEXT && mm->count == 1) {
+		sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
+		ctx_old = ctx_list_pool + mm->context;
+		remove_from_ctx_list(ctx_old);
+		add_to_free_ctxlist(ctx_old);
+		mm->context = NO_CONTEXT;
+	}
 }
+
+static void sun4c_alloc_context_sw(struct mm_struct *mm)
+{
+	struct ctx_list *ctxp;
+
+	ctxp = ctx_free.next;
+	if(ctxp != &ctx_free) {
+		remove_from_ctx_list(ctxp);
+		add_to_used_ctxlist(ctxp);
+		mm->context = ctxp->ctx_number;
+		ctxp->ctx_mm = mm;
+		return;
+	}
+	ctxp = ctx_used.next;
+	if(ctxp->ctx_mm == current->mm)
+		ctxp = ctxp->next;
+#ifdef DEBUG_SUN4C_MM
+	if(ctxp == &ctx_used)
+		panic("out of mmu contexts");
 #endif
+	remove_from_ctx_list(ctxp);
+	add_to_used_ctxlist(ctxp);
+	ctxp->ctx_mm->context = NO_CONTEXT;
+	ctxp->ctx_mm = mm;
+	mm->context = ctxp->ctx_number;
+	sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],
+			    ctxp->ctx_number);
+}
 
-static void sun4c_switch_to_context(struct task_struct *tsk)
+static void sun4c_switch_to_context_sw(struct task_struct *tsk)
 {
 	struct ctx_list *ctx;
-	unsigned long flags;
 
-	save_and_cli(flags);
 	if(tsk->mm->context == NO_CONTEXT) {
-		sun4c_alloc_context(tsk->mm);
-		goto set_context;
+		sun4c_alloc_context_sw(tsk->mm);
+	} else {
+		/* Update the LRU ring of contexts. */
+		ctx = ctx_list_pool + tsk->mm->context;
+		remove_from_ctx_list(ctx);
+		add_to_used_ctxlist(ctx);
 	}
-
-	/* Update the LRU ring of contexts. */
-	ctx = ctx_list_pool + tsk->mm->context;
-	remove_from_ctx_list(ctx);
-	add_to_used_ctxlist(ctx);
-
-set_context:
 	sun4c_set_context(tsk->mm->context);
-	restore_flags(flags);
 }
 
-static void sun4c_init_new_context(struct mm_struct *mm)
+static void sun4c_init_new_context_sw(struct mm_struct *mm)
 {
-	sun4c_alloc_context(mm);
+	sun4c_alloc_context_sw(mm);
 	if(mm == current->mm)
 		sun4c_set_context(mm->context);
 }
 
-static void sun4c_destroy_context(struct mm_struct *mm)
+static void sun4c_destroy_context_sw(struct mm_struct *mm)
 {
 	struct ctx_list *ctx_old;
 
 	if(mm->context != NO_CONTEXT && mm->count == 1) {
-		unsigned long flags;
-
-		save_and_cli(flags);
-		sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
+		sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
 		add_to_free_ctxlist(ctx_old);
 		mm->context = NO_CONTEXT;
-		restore_flags(flags);
 	}
 }
 
@@ -1657,6 +2174,8 @@
 		"kfreepsegs\t: %d\n"
 		"usedpsegs\t: %d\n"
 		"ufreepsegs\t: %d\n"
+		"user_taken\t: %d\n"
+		"max_taken\t: %d\n"
 		"context\t\t: %d flushes\n"
 		"segment\t\t: %d flushes\n"
 		"page\t\t: %d flushes\n",
@@ -1669,6 +2188,8 @@
 		sun4c_kfree_ring.num_entries,
 		used_user_entries,
 		sun4c_ufree_ring.num_entries,
+		sun4c_user_taken_entries,
+		max_user_taken_entries,
 		ctxflushes, segflushes, pageflushes);
 
 #if KGPROF_PROFILING
@@ -1971,31 +2492,20 @@
  *       now, so our ref/mod bit tracking quick userfaults eat a few more
  *       cycles than they used to.
  */
-void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
-	unsigned long offset, vaddr, start, flags;
+	struct inode *inode;
 	pgd_t *pgdp;
 	pte_t *ptep;
 
-	save_and_cli(flags);
-	address &= PAGE_MASK;
-	if(sun4c_get_segmap(address) == invalid_segment)
-		alloc_user_segment(address, sun4c_get_context());
-
-	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
-		struct vm_area_struct *vmaring;
-		struct inode *inode;
+	inode = vma->vm_inode;
+	if(inode) {
+		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
+		struct vm_area_struct *vmaring = inode->i_mmap; 
 		int alias_found = 0;
-
-		/* While on the other hand, this is very uncommon... */
-		inode = vma->vm_inode;
-		if(!inode)
-			goto done;
-
-		offset = (address & PAGE_MASK) - vma->vm_start;
-		vmaring = inode->i_mmap; 
 		do {
-			vaddr = vmaring->vm_start + offset;
+			unsigned long vaddr = vmaring->vm_start + offset;
+			unsigned long start;
 
 			if (S4CVAC_BADALIAS(vaddr, address)) {
 				alias_found++;
@@ -2007,14 +2517,10 @@
 					if(!ptep) goto next;
 
 					if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
-#if 1
-						printk("Fixing USER/USER alias [%ld:%08lx]\n",
-						       vmaring->vm_mm->context, start);
-#endif
-						sun4c_flush_cache_page(vmaring, start);
-						*ptep = __pte(pte_val(*ptep) |
-							      _SUN4C_PAGE_NOCACHE);
-						sun4c_flush_tlb_page(vmaring, start);
+						flush_cache_page(vmaring, start);
+						pte_val(*ptep) = (pte_val(*ptep) |
+								  _SUN4C_PAGE_NOCACHE);
+						flush_tlb_page(vmaring, start);
 					}
 				next:
 					start += PAGE_SIZE;
@@ -2025,11 +2531,24 @@
 		if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
 			pgdp = sun4c_pgd_offset(vma->vm_mm, address);
 			ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
-			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
+			pte_val(*ptep) = (pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
 			pte = pte_val(*ptep);
 		}
 	}
-done:
+}
+
+void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+	unsigned long flags;
+
+	save_and_cli(flags);
+	address &= PAGE_MASK;
+	if(sun4c_get_segmap(address) == invalid_segment)
+		alloc_user_segment(address, sun4c_get_context());
+
+	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
+		sun4c_vac_alias_fixup(vma, address, pte);
+
 	sun4c_put_pte(address, pte_val(pte));
 	restore_flags(flags);
 }
@@ -2045,7 +2564,7 @@
 	extern unsigned long sparc_iobase_vaddr;
 
 	kernel_end = (unsigned long) &end;
-	kernel_end += (SUN4C_REAL_PGDIR_SIZE * 3);
+	kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4);
 	kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
 	sun4c_probe_mmu();
 	invalid_segment = (num_segmaps - 1);
@@ -2083,6 +2602,9 @@
 	for(i = 0; i < num_segmaps; i++)
 		if(mmu_entry_pool[i].locked)
 			cnt++;
+
+	max_user_taken_entries = num_segmaps - cnt - 40 - 1;
+
 	printk("SUN4C: %d mmu entries for the kernel\n", cnt);
 	return start_mem;
 }
@@ -2114,21 +2636,40 @@
 	
 	/* Functions */
 	flush_cache_all = sun4c_flush_cache_all;
-	flush_cache_mm = sun4c_flush_cache_mm;
-	flush_cache_range = sun4c_flush_cache_range;
-	flush_cache_page = sun4c_flush_cache_page;
 
-	flush_tlb_all = sun4c_flush_tlb_all;
-	flush_tlb_mm = sun4c_flush_tlb_mm;
-	flush_tlb_range = sun4c_flush_tlb_range;
-	flush_tlb_page = sun4c_flush_tlb_page;
+	if(sun4c_vacinfo.do_hwflushes) {
+		flush_cache_mm = sun4c_flush_cache_mm_hw;
+		flush_cache_range = sun4c_flush_cache_range_hw;
+		flush_cache_page = sun4c_flush_cache_page_hw;
+		flush_page_to_ram = sun4c_flush_page_to_ram_hw;
+		flush_tlb_mm = sun4c_flush_tlb_mm_hw;
+		flush_tlb_range = sun4c_flush_tlb_range_hw;
+		flush_tlb_page = sun4c_flush_tlb_page_hw;
+		free_kernel_stack = sun4c_free_kernel_stack_hw;
+		free_task_struct = sun4c_free_task_struct_hw;
+		switch_to_context = sun4c_switch_to_context_hw;
+		destroy_context = sun4c_destroy_context_hw;
+		init_new_context = sun4c_init_new_context_hw;
+	} else {
+		flush_cache_mm = sun4c_flush_cache_mm_sw;
+		flush_cache_range = sun4c_flush_cache_range_sw;
+		flush_cache_page = sun4c_flush_cache_page_sw;
+		flush_page_to_ram = sun4c_flush_page_to_ram_sw;
+		flush_tlb_mm = sun4c_flush_tlb_mm_sw;
+		flush_tlb_range = sun4c_flush_tlb_range_sw;
+		flush_tlb_page = sun4c_flush_tlb_page_sw;
+		free_kernel_stack = sun4c_free_kernel_stack_sw;
+		free_task_struct = sun4c_free_task_struct_sw;
+		switch_to_context = sun4c_switch_to_context_sw;
+		destroy_context = sun4c_destroy_context_sw;
+		init_new_context = sun4c_init_new_context_sw;
+	}
 
-	flush_page_to_ram = sun4c_flush_page_to_ram;
+	flush_tlb_all = sun4c_flush_tlb_all;
 
 	flush_sig_insns = sun4c_flush_sig_insns;
 
 	set_pte = sun4c_set_pte;
-	switch_to_context = sun4c_switch_to_context;
 	pmd_align = sun4c_pmd_align;
 	pgdir_align = sun4c_pgdir_align;
 	vmalloc_start = sun4c_vmalloc_start;
@@ -2180,8 +2721,7 @@
 	pte_mkdirty = sun4c_pte_mkdirty;
 	pte_mkyoung = sun4c_pte_mkyoung;
 	update_mmu_cache = sun4c_update_mmu_cache;
-	destroy_context = sun4c_destroy_context;
-	init_new_context = sun4c_init_new_context;
+
 	mmu_lockarea = sun4c_lockarea;
 	mmu_unlockarea = sun4c_unlockarea;
 
@@ -2198,8 +2738,6 @@
 	/* Task struct and kernel stack allocating/freeing. */
 	alloc_kernel_stack = sun4c_alloc_kernel_stack;
 	alloc_task_struct = sun4c_alloc_task_struct;
-	free_kernel_stack = sun4c_free_kernel_stack;
-	free_task_struct = sun4c_free_task_struct;
 
 	quick_kernel_fault = sun4c_quick_kernel_fault;
 	mmu_info = sun4c_mmu_info;
diff -u --recursive --new-file v2.1.33/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c
--- v2.1.33/linux/arch/sparc/prom/misc.c	Thu Dec 19 01:03:33 1996
+++ linux/arch/sparc/prom/misc.c	Fri Apr 11 10:47:35 1997
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.12 1996/12/18 06:46:55 tridge Exp $
+/* $Id: misc.c,v 1.13 1997/04/10 05:12:59 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -92,6 +92,7 @@
 prom_halt(void)
 {
 	unsigned long flags;
+again:
 	save_flags(flags); cli();
 	(*(romvec->pv_halt))();
 	/* Never get here. */
@@ -99,6 +100,7 @@
 			     "r" (&current_set[smp_processor_id()]) :
 			     "memory");
 	restore_flags(flags);
+	goto again; /* PROM is out to get me -DaveM */
 }
 
 typedef void (*sfunc_t)(void);
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.1.33/linux/arch/sparc64/Makefile	Mon Apr  7 11:35:29 1997
+++ linux/arch/sparc64/Makefile	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 1997/03/14 21:04:39 jj Exp $
+# $Id: Makefile,v 1.14 1997/04/10 23:32:33 davem Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -17,13 +17,15 @@
 NM		= sparc64-linux-nm
 AR		= sparc64-linux-ar
 RANLIB		= sparc64-linux-ranlib
+ELF2AOUT64	= elf2aout64
 
 #
 # Uncomment the first CFLAGS if you are doing kgdb source level
 # debugging of the kernel to get the proper debugging information.
 
 #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 
-CFLAGS := $(CFLAGS) -pipe -fcall-used-g5 -fcall-used-g7
+CFLAGS := $(CFLAGS) -pipe -fno-sibling-call \
+          -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
 
 LINKFLAGS = -T arch/sparc64/vmlinux.lds
 
@@ -37,7 +39,11 @@
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \
 	$(TOPDIR)/arch/sparc64/lib/lib.a
 
+vmlinux.aout: vmlinux
+	$(ELF2AOUT64) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux
+
 archclean:
+	rm -f $(TOPDIR)/vmlinux.aout
 
 archdep:
 
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.1.33/linux/arch/sparc64/config.in	Mon Apr  7 11:35:29 1997
+++ linux/arch/sparc64/config.in	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.1 1996/12/27 17:28:19 davem Exp $
+# $Id: config.in,v 1.5 1997/04/10 17:06:08 jj Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -51,7 +51,8 @@
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.1.33/linux/arch/sparc64/defconfig	Mon Apr  7 11:35:29 1997
+++ linux/arch/sparc64/defconfig	Mon Apr 14 09:31:09 1997
@@ -5,14 +5,12 @@
 #
 # Code maturity level options
 #
-CONFIG_EXPERIMENTAL=y
+# CONFIG_EXPERIMENTAL is not set
 
 #
 # Loadable module support
 #
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KERNELD=y
+# CONFIG_MODULES is not set
 
 #
 # General setup
@@ -46,85 +44,51 @@
 #
 # Misc Linux/SPARC drivers
 #
-CONFIG_SUN_OPENPROMIO=m
-CONFIG_SUN_MOSTEK_RTC=y
-# CONFIG_SUN_BPP is not set
-
-#
-# Linux/SPARC audio subsystem (EXPERIMENTAL)
-#
-# CONFIG_SPARCAUDIO is not set
-# CONFIG_SPARCAUDIO_AMD7930 is not set
-# CONFIG_SPARCAUDIO_CS4231 is not set
-CONFIG_SUN_OPENPROMFS=m
+# CONFIG_SUN_OPENPROMIO is not set
+# CONFIG_SUN_MOSTEK_RTC is not set
+# CONFIG_SUN_OPENPROMFS is not set
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_JAVA=m
+CONFIG_BINFMT_ELF32=y
 
 #
 # Floppy, IDE, and other block devices
 #
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_STRIPED=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_LOOP is not set
 
 #
 # Networking options
 #
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_FIREWALL=y
-CONFIG_NET_ALIAS=y
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
 CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_FIREWALL=y
-# CONFIG_IP_FIREWALL_NETLINK is not set
-# CONFIG_IP_FIREWALL_VERBOSE is not set
-CONFIG_IP_MASQUERADE=y
-
-#
-# Protocol-specific masquerading support will be built as modules.
-#
-# CONFIG_IP_TRANSPARENT_PROXY is not set
-# CONFIG_IP_ALWAYS_DEFRAG is not set
+# CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
-# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=m
-# CONFIG_ARPD is not set
 
 #
 # (it is safe to leave these untouched)
 #
 # CONFIG_INET_PCTCP is not set
-CONFIG_INET_RARP=m
-# CONFIG_PATH_MTU_DISCOVERY is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
-CONFIG_IPV6=m
 
 #
 #  
 #
-CONFIG_IPX=m
-# CONFIG_IPX_INTERN is not set
-# CONFIG_IPX_PPROP_ROUTING is not set
-CONFIG_ATALK=m
-# CONFIG_IPDDP is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
 # CONFIG_AX25 is not set
-CONFIG_X25=m
-# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_LLC is not set
-# CONFIG_WAN_ROUTER is not set
 
 #
 # SCSI support
@@ -135,10 +99,10 @@
 # SCSI support type (disk, tape, CDrom)
 #
 CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_ST is not set
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -150,51 +114,43 @@
 # SCSI low-level drivers
 #
 CONFIG_SCSI_SUNESP=y
-CONFIG_SCSI_QLOGICPTI=m
+# CONFIG_SCSI_QLOGICPTI is not set
 
 #
 # Network device support
 #
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_PPP=m
-
-#
-# CCP compressors for PPP are only built as modules.
-#
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
+CONFIG_DUMMY=y
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
 CONFIG_SUNLANCE=y
-CONFIG_HAPPYMEAL=m
-CONFIG_SUNQE=m
-CONFIG_MYRI_SBUS=m
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNQE is not set
+# CONFIG_MYRI_SBUS is not set
 
 #
 # Filesystems
 #
 CONFIG_QUOTA=y
-CONFIG_MINIX_FS=m
+CONFIG_MINIX_FS=y
 CONFIG_EXT2_FS=y
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_UMSDOS_FS=m
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_RNFS_BOOTP=y
-CONFIG_RNFS_RARP=y
-CONFIG_SMB_FS=m
-CONFIG_SMB_WIN95=y
-CONFIG_NCP_FS=m
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
 CONFIG_ISO9660_FS=y
-CONFIG_HPFS_FS=m
-CONFIG_SYSV_FS=m
-CONFIG_AFFS_FS=m
-CONFIG_ROMFS_FS=m
-CONFIG_AMIGA_PARTITION=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.1.33/linux/arch/sparc64/kernel/Makefile	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/Makefile	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.7 1997/03/18 17:59:15 jj Exp $
+# $Id: Makefile,v 1.15 1997/04/10 07:53:30 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -16,10 +16,16 @@
 all: kernel.o head.o
 
 O_TARGET := kernel.o
-O_OBJS   := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o systbls.o traps.o entry.o devices.o auxio.o ioport.o # signal32.o
+O_OBJS   := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o \
+	    systbls.o traps.o entry.o devices.o auxio.o ioport.o \
+	    irq.o time.o sys_sparc.o sys_sparc32.o signal32.o
 OX_OBJS  := sparc64_ksyms.o
 
-head.o: head.S
+ifdef CONFIG_BINFMT_ELF32
+  O_OBJS += sparcelf32.o
+endif
+
+head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S
 	$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
 
 check_asm: dummy
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.1.33/linux/arch/sparc64/kernel/cpu.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/cpu.c	Fri Apr 11 10:47:36 1997
@@ -25,13 +25,17 @@
  * machine type value into consideration too.  I will fix this.
  */
 struct cpu_fp_info linux_sparc_fpu[] = {
-  { 0x17, 0x10, 0, "FIXME: UltraSparc I FPU"},
+  { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
+  { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
+  { 0x17, 0x12, 0, "UltraSparc III integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
 
 struct cpu_iu_info linux_sparc_chips[] = {
-  { 0x17, 0x10, "FIXME: UltraSparc I"},
+  { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
+  { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
+  { 0x17, 0x12, "TI UltraSparc III (Cheetah)"},  /* A guess... */
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- v2.1.33/linux/arch/sparc64/kernel/devices.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/devices.c	Fri Apr 11 10:47:36 1997
@@ -11,8 +11,8 @@
 
 #include <asm/page.h>
 #include <asm/oplib.h>
-#include <asm/smp.h>
 #include <asm/system.h>
+#include <asm/smp.h>
 
 struct prom_cpuinfo linux_cpus[NCPUS];
 int linux_num_cpus;
@@ -31,6 +31,8 @@
 
 	if(strcmp(node_str, "cpu") == 0) {
 		cpu_nds[0] = prom_root_node;
+		linux_cpus[0].prom_node = prom_root_node;
+		linux_cpus[0].mid = 0;
 		cpu_ctr++;
 	} else {
 		int scan;
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/dtlb_miss.S linux/arch/sparc64/kernel/dtlb_miss.S
--- v2.1.33/linux/arch/sparc64/kernel/dtlb_miss.S	Mon Mar 17 14:54:23 1997
+++ linux/arch/sparc64/kernel/dtlb_miss.S	Fri Apr 11 10:47:36 1997
@@ -1,93 +1,80 @@
-/* $Id: dtlb_miss.S,v 1.5 1997/02/25 20:00:02 jj Exp $
+/* $Id: dtlb_miss.S,v 1.11 1997/04/10 01:59:35 davem Exp $
  * dtlb_miss.S:	Data TLB miss code, this is included directly
  *              into the trap table.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
-	/* We are in the MMU globals, %g7 contains the physical
-	 * address of current->mm->pgd at all times.
-	 *
-	 * Many subtle things are done here.  The high bits of
-	 * the virtual address missed are most easily obtained
-	 * from the tag target (it is at address zero in ASI_IMMU
-	 * so no address formation is necessary to get at this).
-	 * This is used to compute the pgd and pmd table offsets.
-	 *
-	 * Even more clever is that physical page zero is always
-	 * a page full of zeroes.  This means we can just follow
-	 * through with all the page table traversals even if nothing
-	 * is mapped because we'll just do loads from page zero
-	 * and get yet another zero.  We only need to do the check
-	 * for the valid bit being set in the final pte we obtain.
-	 *
-	 * Furthermore, we set the TSB base register to the address
-	 * zero, and we use the 8KB tsb ptr to calculate the pte
-	 * offset.  Again it is at address zero in ASI_IMMU_TSB_8KB_PTR
-	 * so no address formation is necessary, saves more instructions.
-	 *
-	 * We use physical address accesses to get at the page
-	 * tables, and this is for two reasons.  This makes it
-	 * impossible to take a fault while we are servicing the
-	 * miss.  Also this physical bypass access only allocates
-	 * in the E-cache, and thus we prevent D-cache pollution
-	 * from the miss handlers probing the page tables.
-	 *
-	 * It looks very hairy and slow.  But I take only 1 more
-	 * overhead of loads from ram than the Solaris version, and
-	 * my version is one instruction quicker for a true TLB miss.
-	 * And more importantly, all true TLB misses under Linux will be
-	 * serviced in _constant_ time.  When using the TSB in the
-	 * manner it was intended to be used (like solaris does) the
-	 * overhead for a TLB miss is _indeterminate_ especially during
-	 * processes startup when the TSB is cold.
-	 *
-	 * XXX I think I can knock off two more instructions here...
-	 */
-
-	/* I-cache line 0 */
-	ldxa		[%g0] ASI_DMMU, %g1		! grab Tag Target either way
-	brlz,pn		%g1, 3f				! special kernel processing
-	 srlx		%g1, 8, %g3			! put high vaddr bits in place
-
-1:
-	and		%g3, %g2, %g3			! get offset
-	ldxa		[%g7 + %g3] ASI_PHYS_USE_EC, %g5! load pgd
-	sllx		%g1, 2, %g4			! begin pmd_offset formation
-	and		%g4, %g2, %g3			! and now mask it
-	ldxa		[%g5 + %g3] ASI_PHYS_USE_EC, %g4! load pmd
-	/* I-cache line 1 */
-	ldxa		[%g0] ASI_DMMU_TSB_8KB_PTR, %g1	! get 8KB pointer bits
-	srlx		%g1, 1, %g1			! shift right to get pte_offset
-	ldxa		[%g4 + %g1] ASI_PHYS_USE_EC, %g3! load pte
-	brlz,a,pt	%g3, 2f				! is valid bit clear?
-	 stxa		%g3, [%g0] ASI_DTLB_DATA_IN	! nope, load TTE into DTLB
-
-	ba,a,pt		%xcc, sparc64_dtlb_refbit_catch	! longer processing needed
-2:
-	retry						! return from trap
-
-#define KTTE_HIGH_BITS	_PAGE_VALID | _PAGE_SZ4MB
-#define KTTE_LOW_BITS	_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G
-
-	nop						! align next insn on cache line
-3:
-	/* I-cache line 2 */
-	srax		%g1, 19, %g5			! mask down high bits
-	cmp		%g5, -1				! if -1 this is VMALLOC area
-	be,pn		%xcc, 1b			! yep
-	 sethi		%uhi(KTTE_HIGH_BITS), %g4	! begin pte formation
-
-	sllx		%g1, 23, %g1			! begin masking for physpage
-	sllx		%g4, 32, %g4			! high protection TTE bits
-	or		%g4, (KTTE_LOW_BITS), %g4	! low protection TTE bits
-	srlx		%g1, 41, %g1			! put physpage into place
-	/* I-cache line 3 */
-	or		%g4, %g1, %g1			! finish TTE computation
-	stxa		%g1, [%g0] ASI_DTLB_DATA_IN	! load TTE into DTLB
-	retry						! return from trap
+/* The basic algorithm is:
+ *
+ * if(faulting_context != 0) {
+ *		pgd = pgd_offset(current->mm.pgd, fault_address);
+ * page_table_walk_continue:
+ *		pmd = pmd_offset(pgd, fault_address);
+ *		pte = pte_offset(pmd, fault_address);
+ *		if(pte & _PAGE_V) {
+ *			tlb_load(pte, fault_address);
+ *			return_from_trap();
+ *		}
+ *		goto longer_processing;
+ * } else {
+ *		if(fault_address >= KERNBASE &&
+ *		   fault_address < VMALLOC_START) {
+ *			tlb_load(__pa(fault_address) | PAGE_KERNEL);
+ *			return_from_trap();
+ *		} else {
+ *			pgd = pgd_offset(swapper_pg_dir, fault_address);
+ *			goto page_table_walk_continue;
+ *		}
+ * }
+ *
+ * This is optimized for user TLB misses on purpose.
+ */
 
-	nop; nop; nop; nop; nop;
+#define KERN_HIGHBITS	(_PAGE_VALID | _PAGE_SZ4MB)
+#define KERN_LOWBITS	(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
+#define KERN_LOWBITS_IO	(_PAGE_E | _PAGE_P | _PAGE_W)
+
+				/* ICACHE line 1 */
+  /*0x00*/	ldxa		[%g0] ASI_DMMU, %g1		! Get TAG_TARGET
+  /*0x04*/	srlx		%g1, 8, %g3			! Position PGD offset
+  /*0x08*/	srlx		%g1, 48, %g5			! Shift down CONTEXT bits
+  /*0x0c*/	and		%g3, %g2, %g3			! Mask PGD offset
+  /*0x10*/	sllx		%g1, 2, %g4			! Position PMD offset
+  /*0x14*/	brz,pn		%g5, 3f				! Context 0 == kernel
+  /*0x18*/	 and		%g4, %g2, %g4			! Mask PMD offset
+  /*0x1c*/	ldxa		[%g0] ASI_DMMU_TSB_8KB_PTR, %g1	! For PTE offset
+
+				/* ICACHE line 2 */
+  /*0x20*/	ldxa		[%g7 + %g3] ASI_PHYS_USE_EC, %g5	! Load PGD
+  /*0x24*/	srlx		%g1, 1, %g1				! PTE offset
+2:/*0x28*/	ldxa		[%g5 + %g4] ASI_PHYS_USE_EC, %g3	! Load PMD
+  /*0x2c*/	ldxa		[%g3 + %g1] ASI_PHYS_USE_EC, %g5	! Load PTE
+  /*0x30*/	brlz,a,pt	%g5, 1f					! Valid set?
+  /*0x34*/	 stxa		%g5, [%g0] ASI_DTLB_DATA_IN		! TLB load
+  /*0x38*/	ba,a,pt		%xcc, sparc64_dtlb_refbit_catch		! Nope...
+1:/*0x3c*/	retry							! Trap return
+
+3:				/* ICACHE line 3 */
+  /*0x40*/	sllx		%g1, 43, %g5		! This gets >= VMALLOC_START...
+  /*0x44*/	brlz,pn		%g5, 4f			! ...if now less than zero.
+  /*0x48*/	 andncc		%g1, 0x3ff, %g0		! Slick trick...
+  /*0x4c*/	be,pn		%xcc, 4f		! Yes, it is some PROM mapping
+  /*0x50*/	 srlx		%g5, 21, %g5		! This is now physical page
+  /*0x54*/	sethi		%uhi(KERN_HIGHBITS), %g1	! Construct PTE
+  /*0x58*/	sllx		%g1, 32, %g1			! Move priv bits up
+  /*0x5c*/	or		%g1, %g5, %g1			! Or in the page
+
+				/* ICACHE line 4 */
+  /*0x60*/	or		%g1, (KERN_LOWBITS), %g1	! Set low priv bits
+  /*0x64*/	stxa		%g1, [%g0] ASI_DTLB_DATA_IN	! TLB load
+  /*0x68*/	retry						! Trap return
+4:/*0x6c*/	ldxa		[%g0] ASI_DMMU_TSB_8KB_PTR, %g1	! For PTE offset
+  /*0x70*/	ldxa		[%g6 + %g3] ASI_PHYS_USE_EC, %g5	! Load kern PGD
+  /*0x74*/	ba,pt		%xcc, 2b			! Go back up top
+  /*0x78*/	 srlx		%g1, 1, %g1
+  /*0x7c*/	nop
 
-#undef KTTE_HIGH_BITS
-#undef KTTE_LOW_BITS
+#undef KERN_HIGHBITS
+#undef KERN_LOWBITS
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S
--- v2.1.33/linux/arch/sparc64/kernel/dtlb_prot.S	Mon Mar 17 14:54:23 1997
+++ linux/arch/sparc64/kernel/dtlb_prot.S	Fri Apr 11 10:47:36 1997
@@ -1,62 +1,56 @@
-/* $Id: dtlb_prot.S,v 1.5 1997/02/26 11:09:26 jj Exp $
- * dtlb_prot.S:	Fast TLB protection trap processing.
+/* $Id: dtlb_prot.S,v 1.10 1997/03/25 09:47:13 davem Exp $
+ * dtlb_prot.S:	Data TLB protection code, this is included directly
+ *              into the trap table.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
-	/* We are in the MMU globals, %g7 contains the physical
-	 * address of current->mm->pgd at all times.  %g2 is
-	 * also preloaded with the mask 0x1ff8 to make things
-	 * even quicker.
-	 *
-	 * Many subtle things are done here.  The high bits of
-	 * the virtual address missed are most easily obtained
-	 * from the tag target (it is at address zero in ASI_IMMU
-	 * so no address formation is necessary to get at this).
-	 * This is used to compute the pgd and pmd table offsets.
-	 *
-	 * Even more clever is that physical page zero is always
-	 * a page full of zeroes.  This means we can just follow
-	 * through with all the page table traversals even if nothing
-	 * is mapped because we'll just do loads from page zero
-	 * and get yet another zero.  We only need to do the check
-	 * for the valid bit being set in the final pte we obtain.
-	 *
-	 * Furthermore, we set the TSB base register to the address
-	 * zero, and we use the 8KB tsb ptr to calculate the pte
-	 * offset.  Again it is at address zero in ASI_IMMU_TSB_8KB_PTR
-	 * so no address formation is necessary, saves more instructions.
-	 *
-	 * We use physical address accesses to get at the page
-	 * tables, and this is for two reasons.  This makes it
-	 * impossible to take a fault while we are servicing the
-	 * miss.  Also this physical bypass access only allocates
-	 * in the E-cache, and thus we prevent D-cache pollution
-	 * from the miss handlers probing the page tables.
+	/* We know kernel never takes protection trap,
+	 * this makes this routine a lot easier than it
+	 * would be otherwise.
 	 */
 
-	/* I-cache line 0 */
-	ldxa		[%g0] ASI_DMMU, %g1
-	srlx		%g1, 8, %g3
-	and		%g3, %g2, %g3
-	ldxa		[%g7 + %g3] ASI_PHYS_USE_EC, %g5
-	sllx		%g1, 2, %g4
-	and		%g4, %g2, %g3
-	ldxa		[%g5 + %g3] ASI_PHYS_USE_EC, %g4
-	ldxa		[%g0] ASI_DMMU_TSB_8KB_PTR, %g1
-	/* I-cache line 1 */
-	srlx		%g1, 1, %g1
-	ldxa		[%g4 + %g1] ASI_PHYS_USE_EC, %g3
-	andcc		%g3, _PAGE_WRITE, %g0
-	be,pn		%xcc, sparc64_dtlb_fault
-	 or		%g3, (_PAGE_WRITE|_PAGE_W|_PAGE_MODIFIED|_PAGE_ACCESSED), %g3
-
-	/* Blamo... */
-	stxa		%g3, [%g4 + %g1] ASI_DMMU
-	stxa		%g3, [%g0] ASI_DTLB_DATA_IN
-	retry
-
-	/* I-cache line 2 */
-	nop; nop; nop; nop; nop; nop; nop; nop;
-	/* I-cache line 3 */
-	nop; nop; nop; nop; nop; nop; nop; nop;
+#define MODIFIED_BITS	(_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED)
+
+				/* ICACHE line 1 */
+  /*0x00*/	ldxa		[%g0] ASI_DMMU, %g1		! Get TAG_TARGET
+  /*0x04*/	srlx		%g1, 8, %g3			! Position PGD offset
+  /*0x08*/	sllx		%g1, 2, %g4			! Position PMD offset
+  /*0x0c*/	and		%g3, %g2, %g3			! Mask PGD offset
+  /*0x10*/	and		%g4, %g2, %g3			! Mask PMD offset
+  /*0x14*/	ldxa		[%g7 + %g3] ASI_PHYS_USE_EC, %g5	! Load PGD
+  /*0x18*/	ldxa		[%g5 + %g3] ASI_PHYS_USE_EC, %g4	! Load PMD
+  /*0x1c*/	ldxa		[%g0] ASI_DMMU_TSB_8KB_PTR, %g1		! For PTE offset
+
+				/* ICACHE line 2 */
+  /*0x20*/	srlx		%g1, 1, %g1				! PTE offset
+  /*0x24*/	ldxa		[%g4 + %g1] ASI_PHYS_USE_EC, %g3	! Load PTE
+  /*0x28*/	andcc		%g3, _PAGE_WRITE, %g0			! Writable?
+  /*0x2c*/	be,pt		%xcc, sparc64_dtlb_fault		! Nope...
+  /*0x30*/	 or		%g3, (MODIFIED_BITS), %g3		! Yes it is
+  /*0x34*/	mov		TLB_TAG_ACCESS, %g5			! Get the page
+  /*0x38*/	ldxa		[%g5] ASI_DMMU, %g1			! From MMU
+  /*0x3c*/	add		%g2, 7, %g5				! Compute mask
+
+				/* ICACHE line 3 */
+  /*0x40*/	andn		%g1, %g5, %g1				! Mask page
+  /*0x44*/	or		%g1, 0x10, %g1				! 2ndary Context
+  /*0x48*/	stxa		%g0, [%g1] ASI_DMMU_DEMAP		! TLB flush page
+  /*0x4c*/	membar		#Sync					! Synchronize
+  /*0x50*/	stxa		%g3, [%g4 + %g1] ASI_PHYS_USE_EC	! Update sw PTE
+  /*0x54*/	stxa		%g3, [%g0] ASI_DTLB_DATA_IN		! TLB load
+  /*0x58*/	retry							! Trap return
+  /*0x5c*/	nop
+
+				/* ICACHE line 4 */
+  /*0x60*/	nop
+  /*0x64*/	nop
+  /*0x68*/	nop
+  /*0x6c*/	nop
+  /*0x70*/	nop
+  /*0x74*/	nop
+  /*0x78*/	nop
+  /*0x7c*/	nop
+
+#undef MODIFIED_BITS
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.33/linux/arch/sparc64/kernel/entry.S	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/entry.S	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.1 1997/03/18 17:58:59 jj Exp $
+/* $Id: entry.S,v 1.14 1997/04/14 06:56:54 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -16,6 +16,7 @@
 #include <asm/ptrace.h>
 #include <asm/page.h>
 #include <asm/signal.h>
+#include <asm/pgtable.h>
 
 #define curptr      g6
 
@@ -23,6 +24,155 @@
 
 	.text
         .align  4
+/* FIXME: This is still debugging hack */
+	.globl	sparc64_dtlb_fault, sparc64_dtlb_refbit_catch, sparc64_itlb_refbit_catch
+sparc64_dtlb_fault:
+	rdpr	%pstate, %g1
+	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	call	sparc64_dtlb_fault_handler
+	 nop
+
+sparc64_dtlb_refbit_catch:
+	rdpr	%pstate, %g1
+	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	call	sparc64_dtlb_refbit_handler
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sparc64_itlb_refbit_catch:
+	rdpr	%pstate, %g1
+	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	call	sparc64_dtlb_refbit_handler
+	 nop
+
+	/* Note check out head.h, this code isn't even used for UP,
+	 * for SMP things will be different.  In particular the data
+	 * registers for cross calls will be:
+	 *
+	 * DATA 0: Address of function to call
+	 * DATA 1: Argument 1, place in %g6
+	 * DATA 2: Argument 2, place in %g7
+	 *
+	 * With this method we can do most of the cross-call tlb/cache
+	 * flushing in very quickly.
+	 */
+	.align	4
+	.globl	do_ivec
+do_ivec:
+	ldxa	[%g0] ASI_INTR_RECEIVE, %g1
+	andcc	%g1, 0x20, %g0
+	be,pn	%xcc, do_ivec_return
+	 mov	0x40, %g2
+
+	/* Load up Interrupt Vector Data 0 register. */
+	sethi	%uhi(ivector_to_mask), %g4
+	ldxa	[%g2] ASI_UDB_INTR_R, %g3
+	or	%g4, %ulo(ivector_to_mask), %g4
+	and	%g3, 0x7ff, %g3
+	sllx	%g4, 32, %g4
+	sethi	%hi(ivector_to_mask), %g5
+	sllx	%g3, 3, %g3
+	or	%g5, %lo(ivector_to_mask), %g5
+	add	%g5, %g4, %g4
+	ldx	[%g4 + %g3], %g2
+	brz,pn	%g2, do_ivec_spurious
+	 nop
+
+	/* No branches, worse case we don't know about this interrupt
+	 * yet, so we would just write a zero into the softint register
+	 * which is completely harmless.
+	 */
+	wr	%g2, 0x0, %set_softint
+
+do_ivec_return:
+	/* Acknowledge the UPA */
+	stxa	%g0, [%g0] ASI_INTR_RECEIVE
+	membar	#Sync
+	retry
+
+do_ivec_spurious:
+	stxa	%g0, [%g0] ASI_INTR_RECEIVE
+	rdpr	%pstate, %g1
+	wrpr	%g1, PSTATE_IG | PSTATE_AG, %pstate
+	ba,pt	%xcc, etrap
+	 rd	%pc, %g7
+	call	report_spurious_ivec
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt	%xcc, rtrap
+	 nop
+
+breakpoint_t:
+	.asciz	"Breakpoint Trap %lx\n"
+	.align	4
+	.globl	breakpoint_trap
+breakpoint_trap:
+	mov	%o0, %o1
+	sethi	%hi(breakpoint_t), %o0
+	or	%o0, %lo(breakpoint_t), %o0
+	call	prom_printf
+	 add	%o0, %g4, %o0
+	call	prom_cmdline
+	 nop
+	ba,a,pt	%xcc, rtrap
+
+	.globl	sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+
+sys_pipe:
+	sethi	%hi(sparc_pipe), %g1
+	add	%g1, %g4, %g1
+	jmpl	%g1 + %lo(sparc_pipe), %g0
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sys_nis_syscall:
+	sethi	%hi(c_sys_nis_syscall), %g1
+	add	%g1, %g4, %g1
+	jmpl	%g1 + %lo(c_sys_nis_syscall), %g0
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sys_execve:
+	sethi	%hi(sparc_execve), %g1
+	add	%g1, %g4, %g1
+	jmpl	%g1 + %lo(sparc_execve), %g0
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+
+sys_sigpause:
+	/* NOTE: %o0 has a correct value already */
+	call	do_sigpause
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
+	
+	ld	[%curptr + AOFF_task_flags], %l5
+	andcc	%l5, 0x20, %g0
+	be,pt	%icc, ret_sys_call
+	 clr	%o0
+	call	syscall_trace
+	 nop
+	ba,pt	%xcc, ret_sys_call
+	 clr	%o0
+
+	/* This is how fork() was meant to be done, 11 instruction entry. -DaveM */
+	.globl	sys_fork, sys_vfork, sys_clone
+sys_fork:
+sys_vfork:
+	mov	SIGCHLD, %o0
+	clr	%o1
+sys_clone:
+	mov	%o7, %l5
+	flushw
+	rdpr	%cwp, %o4
+	add	%sp, STACK_BIAS + REGWIN_SZ, %o2
+	brz,a	%o1, 1f
+	 mov	%fp, %o1
+1:
+	/* Don't try this at home. */
+	stx	%o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
+	call	do_fork
+	 add	%l5, 8, %o7
+
 linux_sparc_ni_syscall:
 	sethi	%hi(sys_ni_syscall), %l7
 	or	%l7, %lo(sys_ni_syscall), %l7
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S
--- v2.1.33/linux/arch/sparc64/kernel/etrap.S	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/etrap.S	Fri Apr 11 10:47:36 1997
@@ -1,64 +1,114 @@
-/* $Id: etrap.S,v 1.5 1997/03/13 08:24:01 jj Exp $
+/* $Id: etrap.S,v 1.10 1997/04/03 13:03:49 davem Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <asm/asi.h>
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
+#include <asm/spitfire.h>
+#include <asm/head.h>
+
+/* We assume that pstate, when entering this, has AG and IE bits set, MG and IG clear */
 
 	.text
-	.align	4
-	.globl	etrap
+	.align	32
+	.globl	etrap, etrap_irq
 etrap:
-	rdpr	%wstate, %g2
-	sethi	%uhi(current_set), %g6
-	andcc	%g2, 7, %g2
-	rdpr	%tstate, %g1
-	be,pn	%xcc, 1f		/* What happens more often? etrap when already in priv or from userland? */
-	 sllx	%g6, 32, %g6
-	/* Just when going from userland to privileged mode, we have to change this stuff. */
-	sll	%g2, 3, %g2
-	wrpr	%g2, %wstate
-	rdpr	%canrestore, %g5
-	wrpr	%g0, 0, %canrestore
-	wrpr	%g5, 0, %otherwin
+	rdpr		%pil, %g4
+etrap_irq:
+	rdpr		%wstate, %g5
+	sllx		%g4, 20, %g4
+	rdpr		%tstate, %g1
+	rdpr		%tpc, %g2
+	or		%g1, %g4, %g1
+	rdpr		%tnpc, %g3
+
+	/* What happens more often? etrap when already in priv or from userland? */
+	andcc		%g1, TSTATE_PRIV, %g0
+	bne,a,pn	%xcc, 1f
+	 sub		%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
+
+	/* Just when going from userland to privileged mode,
+	 * we have to change this stuff.
+	 *
+	 * Setup to run in NUCLEUS context, stash user context in
+	 * secondary for later trap return.  Note we must not change
+	 * trap level until PRIMARY_CONTEXT is set to zero, else
+	 * we fall out of NUCLEUS too soon and crash hard.
+	 */
+	mov		PRIMARY_CONTEXT, %g7
+	ldxa		[%g7] ASI_DMMU, %g4
+	mov		SECONDARY_CONTEXT, %g6
+	stxa		%g0, [%g7] ASI_DMMU
+	stxa		%g4, [%g6] ASI_DMMU
+	wrpr		%g0, 0x0, %tl
+
+	sll		%g5, 3, %g5
+	sethi		%uhi(KERNBASE), %g4
+	or		%g4, %ulo(KERNBASE), %g4
+	sethi		%hi(current_set), %g6
+	or		%g6, %lo(current_set), %g6
+	sllx		%g4, 32, %g4
+	wrpr		%g5, %wstate
+	rdpr		%canrestore, %g5
+	ldx		[%g6 + %g4], %g6
+#ifdef __SMP__
+/* FIXME: Fix the above insn for SMP */
+#endif
+	wrpr		%g0, 0, %canrestore
+	wrpr		%g5, 0, %otherwin
+	ba,pt		%xcc, 2f
+	 ldx		[%g6 + AOFF_task_saved_kernel_stack], %g5
 1:
-	sethi	%hi(current_set), %g4
-	or	%g4, %lo(current_set), %g4
-	rdpr	%tpc, %g2
-	rdpr	%tnpc, %g3
-	ldx	[%g6 + %g4], %g6
+	wrpr		%g0, 0x0, %tl
+2:
+	rd		%y, %g4
+	stx		%g1, [%g5 + REGWIN_SZ + PT_V9_TSTATE]
+	stx		%g2, [%g5 + REGWIN_SZ + PT_V9_TPC]
+	stx		%g3, [%g5 + REGWIN_SZ + PT_V9_TNPC]
+	stx		%g4, [%g5 + REGWIN_SZ + PT_V9_Y]
+	rdpr		%pstate, %g1
+	save		%g5, -STACK_BIAS, %sp
+	mov		%g1, %l1
+	mov		%g7, %l2
+	wrpr		%l1, PSTATE_AG, %pstate
+	stx		%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
+	stx		%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
+	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]
+	stx		%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]
+	stx		%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]
+	stx		%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6]
+	stx		%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]
+	stx		%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	stx		%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
+	stx		%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
+	stx		%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]
+	stx		%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]
+	stx		%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]
+	stx		%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6]
+	stx		%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
+	wrpr		%l1, (PSTATE_IE | PSTATE_AG), %pstate
+	sethi		%uhi(KERNBASE), %g4
+	or		%g4, %ulo(KERNBASE), %g4
+	sethi		%hi(current_set), %g6
+	or		%g6, %lo(current_set), %g6
+	sllx		%g4, 32, %g4
+	jmpl		%l2 + 0x4, %g0
+	 ldx		[%g6 + %g4], %g6
 #ifdef __SMP__
 /* FIXME: Fix the above insn for SMP */
 #endif
-	rd	%y, %g4
-	ldx	[%g6 + AOFF_task_tss + AOFF_thread_ksp], %g5
-	stx	%g1, [%g5 + REGWIN_SZ + PT_TSTATE]
-	stx	%g2, [%g5 + REGWIN_SZ + PT_TPC]
-	stx	%g3, [%g5 + REGWIN_SZ + PT_TNPC]
-	stx	%g4, [%g5 + REGWIN_SZ + PT_Y]
-	rdpr	%pstate, %g1
-	save	%g5, -STACK_BIAS, %sp
-	andn	%g1, (PSTATE_IG | PSTATE_MG | PSTATE_AG), %l1
-	wrpr	%g0, 0x0, %tl
-	mov	%g7, %l2
-	wrpr	%l1, 0x0, %pstate
-	stx	%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_G1]
-	stx	%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_G2]
-	stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_G3]
-	stx	%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_G4]
-	stx	%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_G5]
-	stx	%g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_G6]
-	stx	%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_G7]
-	stx	%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
-	stx	%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_I1]
-	stx	%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_I2]
-	stx	%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_I3]
-	stx	%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_I4]
-	stx	%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_I5]
-	stx	%i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_I6]
-	stx	%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_I7]
-	jmpl	%l2 + 0x4, %g0
-	 wrpr	%l1, PSTATE_IE, %pstate
+
+	.globl	etraptl1
+etraptl1:
+	rdpr	%tl, %g4
+	rdpr	%tstate, %g1
+	sub	%g4, 1, %g4
+	rdpr	%tpc, %g2
+	rdpr	%tnpc, %g3
+	wrpr	%g4, 0x0, %tl
+	ba,pt	%xcc, 1b
+	 sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g5
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/hack.S linux/arch/sparc64/kernel/hack.S
--- v2.1.33/linux/arch/sparc64/kernel/hack.S	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/hack.S	Fri Apr 11 10:47:36 1997
@@ -4,36 +4,10 @@
    to compile... */
 	.text
 	.align	8
-	.globl	__copy_user
-__copy_user:	retl;nop
-	.globl	__csum_partial_copy_sparc_generic
-__csum_partial_copy_sparc_generic:	retl;nop
 	.globl	_sigpause_common
 _sigpause_common:	retl;nop
-	.globl	_stext
-_stext:	retl;nop
-	.globl	auxio_register
-auxio_register:	retl;nop
-	.globl	bad_trap
-bad_trap:	retl;nop
-	.globl	bad_trap_tl1
-bad_trap_tl1:	retl;nop
 	.globl	breakpoint
 breakpoint:	retl;nop
-	.globl	breakpoint_trap
-breakpoint_trap:	retl;nop
-	.globl	csum_partial
-csum_partial:	retl;nop
-	.globl	ctx_free
-ctx_free:	.skip	32
-	.globl	ctx_list_pool
-ctx_list_pool:	.skip	32
-	.globl	ctx_used
-ctx_used:	.skip	32
-	.globl	destroy_context
-destroy_context:	retl;nop
-	.globl	disable_irq
-disable_irq:	retl;nop
 	.globl	do_cee
 do_cee:	retl;nop
 	.globl	do_cee_tl1
@@ -42,10 +16,6 @@
 do_dae:	retl;nop
 	.globl	do_dae_tl1
 do_dae_tl1:	retl;nop
-	.globl	do_dax
-do_dax:	retl;nop
-	.globl	do_dax_tl1
-do_dax_tl1:	retl;nop
 	.globl	do_div0
 do_div0:	retl;nop
 	.globl	do_div0_tl1
@@ -62,16 +32,10 @@
 do_fpother:	retl;nop
 	.globl	do_fpother_tl1
 do_fpother_tl1:	retl;nop
-	.globl	do_gettimeofday
-do_gettimeofday:	retl;nop
 	.globl	do_iae
 do_iae:	retl;nop
 	.globl	do_iae_tl1
 do_iae_tl1:	retl;nop
-	.globl	do_iax
-do_iax:	retl;nop
-	.globl	do_iax_tl1
-do_iax_tl1:	retl;nop
 	.globl	do_ill
 do_ill:	retl;nop
 	.globl	do_ill_tl1
@@ -80,10 +44,6 @@
 do_irq:	retl;nop
 	.globl	do_irq_tl1
 do_irq_tl1:	retl;nop
-	.globl	do_ivec
-do_ivec:	retl;nop
-	.globl	do_ivec_tl1
-do_ivec_tl1:	retl;nop
 	.globl	do_lddfmna
 do_lddfmna:	retl;nop
 	.globl	do_lddfmna_tl1
@@ -100,8 +60,6 @@
 do_privact:	retl;nop
 	.globl	do_privop
 do_privop:	retl;nop
-	.globl	do_settimeofday
-do_settimeofday:	retl;nop
 	.globl	do_signal
 do_signal:	retl;nop
 	.globl	do_stdfmna
@@ -116,80 +74,30 @@
 do_vaw:	retl;nop
 	.globl	do_vaw_tl1
 do_vaw_tl1:	retl;nop
-	.globl	enable_irq
-enable_irq:	retl;nop
 	.globl	floppy_hardint
 floppy_hardint:	retl;nop
-	.globl	flush_user_windows
-flush_user_windows:	retl;nop
-	.globl	free_irq
-free_irq:	retl;nop
 	.globl	get_cpuid
 get_cpuid:	retl;nop
-	.globl	get_irq_list
-get_irq_list:	retl;nop
 	.globl	getcc
 getcc:	retl;nop
 	.globl	halt
 halt:	retl;nop
 	.globl	indirect_syscall
 indirect_syscall:	retl;nop
-	.globl	init_IRQ
-init_IRQ:	retl;nop
 	.globl	install_linux_ticker
 install_linux_ticker:	retl;nop
 	.globl	install_obp_ticker
 install_obp_ticker:	retl;nop
-	.globl	iommu_init
-iommu_init:	retl;nop
-	.globl	linux32_syscall
-linux32_syscall:	retl;nop
-	.globl	linux64_syscall
-linux64_syscall:	retl;nop
 	.globl	linux_dbvec
 linux_dbvec:	retl;nop
 	.globl	linux_num_cpus
 linux_num_cpus:	retl;nop
-	.globl	load_mmu
-load_mmu:	retl;nop
-	.globl	mmu_get_scsi_one
-mmu_get_scsi_one:	retl;nop
-	.globl	mmu_get_scsi_sgl
-mmu_get_scsi_sgl:	retl;nop
-	.globl	mmu_info
-mmu_info:	retl;nop
-	.globl	mmu_lockarea
-mmu_lockarea:	retl;nop
-	.globl	mmu_release_scsi_one
-mmu_release_scsi_one:	retl;nop
-	.globl	mmu_release_scsi_sgl
-mmu_release_scsi_sgl:	retl;nop
-	.globl	mmu_unlockarea
-mmu_unlockarea:	retl;nop
-	.globl	mstk48t02_regs
-mstk48t02_regs:	retl;nop
 	.globl	netbsd_syscall
 netbsd_syscall:	retl;nop
-	.globl	probe_irq_off
-probe_irq_off:	retl;nop
-	.globl	probe_irq_on
-probe_irq_on:	retl;nop
-	.globl	request_fast_irq
-request_fast_irq:	retl;nop
-	.globl	request_irq
-request_irq:	retl;nop
 	.globl	setcc
 setcc:	retl;nop
 	.globl	solaris_syscall
 solaris_syscall:	retl;nop
-	.globl	sparc64_dtlb_fault
-sparc64_dtlb_fault:	retl;nop
-	.globl	sparc64_dtlb_refbit_catch
-sparc64_dtlb_refbit_catch:	retl;nop
-	.globl	sparc64_itlb_refbit_catch
-sparc64_itlb_refbit_catch:	retl;nop
-	.globl	spitfire_get_new_context
-spitfire_get_new_context:	retl;nop
 	.globl	sunos_mmap
 sunos_mmap:	retl;nop
 	.globl	sunos_syscall
@@ -198,22 +106,6 @@
 svr4_getcontext:	retl;nop
 	.globl	svr4_setcontext
 svr4_setcontext:	retl;nop
-	.globl	swapper_pg_dir
-swapper_pg_dir:	retl;nop
-	.globl	switch_to
-switch_to:	retl;nop
-	.globl	sys_call_table
-sys_call_table:	retl;nop
-	.globl	time_init
-time_init:	retl;nop
-	.globl	translate_namei
-translate_namei:	retl;nop
-	.globl	translate_open_namei
-translate_open_namei:	retl;nop
-	.globl	sparc_brk
-sparc_brk:	retl;nop
-	.globl	sparc_sigaction
-sparc_sigaction:	retl;nop
 	.globl	sunos_accept
 sunos_accept:	retl;nop
 	.globl	sunos_audit
@@ -306,41 +198,17 @@
 sunos_write:	retl;nop
 	.globl	sunos_writev
 sunos_writev:	retl;nop
-	.globl	sys_aplib
-sys_aplib:	retl;nop
-	.globl	sys_clone
-sys_clone:	retl;nop
-	.globl	sys_execve
-sys_execve:	retl;nop
-	.globl	sys_fork
-sys_fork:	retl;nop
-	.globl	sys_getpagesize
-sys_getpagesize:	retl;nop
-	.globl	sys_ipc
-sys_ipc:	retl;nop
-	.globl	sys_mmap
-sys_mmap:	retl;nop
-	.globl	sys_nis_syscall
-sys_nis_syscall:	retl;nop
-	.globl	sys_pipe
-sys_pipe:	retl;nop
 	.globl	sys_ptrace
 sys_ptrace:	retl;nop
-	.globl	sys_sigpause
-sys_sigpause:	retl;nop
 	.globl	sys_sigreturn
 sys_sigreturn:	retl;nop
 	.globl	sys_sigstack
 sys_sigstack:	retl;nop
 	.globl	sys_sigsuspend
 sys_sigsuspend:	retl;nop
-	.globl	sys_vfork
-sys_vfork:	retl;nop
 	.globl	syscall_trace
 syscall_trace:	retl;nop
-	.globl	sparc_ultra_mapioaddr
-sparc_ultra_mapioaddr:	retl;nop
-	.globl	sparc_ultra_unmapioaddr
-sparc_ultra_unmapioaddr:	retl;nop
-	.globl	mmu_map_dma_area
-mmu_map_dma_area:	retl;nop
+	.globl	sys32_ptrace
+sys32_ptrace:	retl;nop
+	.globl	do_sigpause
+do_sigpause:	retl;nop
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.1.33/linux/arch/sparc64/kernel/head.S	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/head.S	Fri Apr 11 10:47:36 1997
@@ -1,7 +1,7 @@
-/* $Id: head.S,v 1.17 1997/03/18 17:59:37 jj Exp $
+/* $Id: head.S,v 1.27 1997/04/04 00:49:49 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -15,6 +15,7 @@
 #include <asm/pgtable.h>
 #include <asm/errno.h>
 #include <asm/lsu.h>
+#include <asm/head.h>
 	
 /* This section from from _start to sparc64_boot_end should fit into
  * 0xffff.f800.0000.4000 to 0xffff.f800.0000.8000 and will be sharing space
@@ -24,9 +25,11 @@
  */
 
 	.text
-	.globl	start, _start
+	.globl	start, _start, stext, _stext
 _start:
 start:
+_stext:
+stext:
 bootup_user_stack:
 ! 0xfffff80000004000
 	b	sparc64_boot
@@ -63,6 +66,9 @@
 	 * PROM entry point is on %o4
 	 */
 sparc64_boot:
+	/* Typically PROM has already enabled both MMU's and both on-chip
+	 * caches, but we do it here anyway just to be paranoid.
+	 */
 	mov	(LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1
 	stxa	%g1, [%g0] ASI_LSU_CONTROL
 
@@ -70,8 +76,10 @@
 	 * Make sure we are in privileged mode, have address masking,
          * using the ordinary globals and have enabled floating
          * point.
-         */                                                                                
-
+	 *
+	 * Again, typically PROM has left %pil at 13 or similar, and
+	 * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate.
+         */
 	wrpr	%g0, 0xf, %pil			/* Interrupts off.           */
 	wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF), %pstate
 
@@ -90,7 +98,7 @@
 	set	current_pc, %g5
 	add	%g5, %g4, %g5
 	cmp	%g3, %g5
-	be	%xcc,sun4u_init
+	be	%xcc, sun4u_init
 	 nop
 
 create_mappings:
@@ -99,59 +107,149 @@
         sllx    %g5, 32, %g5
         or      %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
 
-	/* We aren't mapped in at KERNBASE, so we need to create
-	 * an I and D tlb entry to map KERNBASE to 0.  Both entries
-	 * are 4 Megs mappings and are locked in.
+	/* Base of physical memory cannot reliably be assumed to be
+	 * at 0x0!  Figure out where it happens to be. -DaveM
 	 */
-	set	TLB_TAG_ACCESS, %g3           /* 0x30 */
 
-	stxa	%g4, [%g3] ASI_IMMU           /* 0x50 */
-	stxa	%g5, [%g0] ASI_ITLB_DATA_IN   /* 0x54 */
-	membar  #Sync
+	/* Put PADDR tlb data mask into %g3. */
+	sethi	%uhi(_PAGE_PADDR), %g3
+	or	%g3, %ulo(_PAGE_PADDR), %g3
+	sllx	%g3, 32, %g3
+	sethi	%hi(_PAGE_PADDR), %g7
+	or	%g7, %lo(_PAGE_PADDR), %g7
+	or	%g3, %g7, %g3
 
-	/* Put KERNBASE into the I/D Tag Access Register (TAR) */
-	stxa	%g4, [%g3] ASI_DMMU           /* 0x58 */
-	stxa    %g5, [%g0] ASI_DTLB_DATA_IN
-	membar  #Sync
+	/* Walk through entire ITLB, looking for entry which maps
+	 * our %pc currently, stick PADDR from there into %g5 tlb data.
+	 */
+	clr	%l0			/* TLB entry walker. */
+	set	0x1fff, %l2		/* Page mask. */
+	rd	%pc, %l3
+	andn	%l3, %l2, %g2		/* vaddr comparator */
+1:
+	/* Yes, the nops seem to be necessary for now, don't ask me why. -DaveM */
+	ldxa	[%l0] ASI_ITLB_TAG_READ, %g1
+	nop
+	nop
+	nop
+	andn	%g1, %l2, %g1		/* Get vaddr */
+	cmp	%g1, %g2
+	be,a,pn	%xcc, got_tlbentry
+	 ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
+	cmp	%l1, (63 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+boot_failed:
+	/* Debugging 8-) */
+	set	0xdeadbeef, %g1
+	t	0x11
 
+got_tlbentry:
+	/* Nops here again, perhaps Cheetah/Blackbird are better behaved... */
+	nop
+	nop
 	nop
-	nop	
+	and	%g1, %g3, %g1		/* Mask to just get paddr bits.       */
+	sub	%g1, %g2, %g1		/* Get rid of %pc offset to get base. */
+
+	/* NOTE: We hold on to %g1 paddr base as we need it below to lock
+	 * NOTE: the PROM cif code into the TLB.
+	 */
+
+	or	%g5, %g1, %g5		/* Or it into TAG being built.        */
+
+	/* PROM never puts any TLB entries into the MMU with the lock bit
+	 * set.  So we gladly use tlb entry 63 for KERNBASE, 62 for
+	 * boot time locked PROM CIF handler page, we remove the locked
+	 * bit for the CIF page in paging_init().
+	 */
+	mov	TLB_TAG_ACCESS, %g3
+	mov	(63 << 3), %g7
+	stxa	%g4, [%g3] ASI_IMMU		/* KERNBASE into TLB TAG	*/
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS	/* TTE into TLB DATA		*/
 	membar	#Sync
-	
+
+	/* Same for DTLB */
+	stxa	%g4, [%g3] ASI_DMMU		/* KERNBASE into TLB TAG	*/
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS	/* TTE into TLB DATA		*/
+	membar	#Sync
+
+	/* Kill instruction prefetch queues. */
+	flush	%g4
+	membar	#Sync
+
 	ba,pt	%xcc, go_to_highmem
 	 nop
 
-/* Now do a non-relative jump so that PC is in high-memory */
 go_to_highmem:
-	set	sun4u_init, %g1
-	jmpl     %g1 + %g4, %g0
+	/* Now do a non-relative jump so that PC is in high-memory */
+	set	sun4u_init, %g2
+	jmpl     %g2 + %g4, %g0
 	 nop
 
 sun4u_init:
-	/* Remap our prom interface code */
-	sethi	%hi(__p1275_loc), %g7
-	or	%g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G | _PAGE_L), %g7
+	/* Set ctx 0 */
+	mov	PRIMARY_CONTEXT, %g7
+	stxa	%g0, [%g7] ASI_DMMU
+	membar	#Sync
+
+	mov	SECONDARY_CONTEXT, %g7
+	stxa	%g0, [%g7] ASI_DMMU
+	membar	#Sync
+
 	/* The lock bit has to be removed from this page later on, 
-	   but before firing up init we will use PROM a lot, so we
-	   lock it there now... */
+	 * but before firing up init we will use PROM a lot, so we
+	 * lock it there now...
+	 */
+
+	/* Compute PROM CIF interface page TTE. */
+	sethi	%hi(__p1275_loc), %g7
+	or	%g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_L), %g7
 	sethi	%uhi(_PAGE_VALID), %g5
 	sethi	%hi(0x8000), %g3
 	sllx	%g5, 32, %g5
 	mov	TLB_TAG_ACCESS, %g6
 	or	%g5, %g7, %g5
-	stxa	%g3, [%g6] ASI_IMMU
-	stxa	%g5, [%g0] ASI_ITLB_DATA_IN
+	add	%g5, %g1, %g5				/* Add in physbase. */
+
+	mov	(62 << 3), %g7				/* TLB entry 62		  */
+	stxa	%g3, [%g6] ASI_IMMU			/* CIF page into TLB TAG  */
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS		/* TTE into TLB DATA	  */
 	membar	#Sync
 
-	stxa	%g3, [%g6] ASI_DMMU
-	stxa	%g5, [%g0] ASI_DTLB_DATA_IN
+	/* Same for DTLB */
+	stxa	%g3, [%g6] ASI_DMMU			/* CIF page into TLB TAG  */
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS		/* TTE into TLB DATA	  */
 	membar	#Sync
+
+	/* Kill instruction prefetch queues. */
 	flush	%g3
+	membar	#Sync
 
-	nop
-	nop
+	/* We are now safely (we hope) in Nucleus context (0), rewrite
+	 * the KERNBASE TTE's so they no longer have the global bit set.
+	 * Don't forget to setup TAG_ACCESS first 8-)
+	 */
+	mov	TLB_TAG_ACCESS, %g2
+	stxa	%g4, [%g2] ASI_IMMU
+	stxa	%g4, [%g2] ASI_DMMU
+
+	mov	(63 << 3), %g7
+	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g1
+	andn	%g1, (_PAGE_G), %g1
+	stxa	%g1, [%g7] ASI_ITLB_DATA_ACCESS
 	membar	#Sync
-	
+
+	ldxa	[%g7] ASI_DTLB_DATA_ACCESS, %g1
+	andn	%g1, (_PAGE_G), %g1
+	stxa	%g1, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+
+	/* Kill instruction prefetch queues. */
+	flush	%g4
+	membar	#Sync
+
 	/* Compute the number of windows in this machine
 	 * store this in nwindows and nwindowsm1
 	 */
@@ -170,28 +268,12 @@
 	mov	%sp, %l6
 	mov	%o4, %l7
 
-#if 0
-/* This is to dangerous for now... To many traps unfilled yet... */
-	sethi	%hi(sparc64_ttable_tl0), %g5
-	add	%g5, %g4, %g5
-	wrpr	%g5, %tba
-#endif
-
 	sethi	%hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
 	or	%g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
 	add	%g5, %g4, %sp
 	mov	0, %fp
-	wrpr	%g0, PSTATE_PEF | PSTATE_PRIV, %pstate
 	wrpr	%g0, 0, %wstate
 	wrpr	%g0, 0x0, %tl
-	fzero	%f48
-	fzero	%f50
-	fzero	%f52
-	fzero	%f54
-	fzero	%f56
-	fzero	%f58
-	fzero	%f60
-	fzero	%f62
 
 	/* Clear the bss */
 	sethi	%hi(8191), %l2
@@ -211,6 +293,10 @@
 	blu,pt	%xcc, 1b
 	 add	%l0, %g4, %o0
 
+	/* Now clear empty_zero_page */
+	call	bzero_1page
+	 mov	%g4, %o0
+
 	mov	%l6, %o1			! OpenPROM stack
 	call	prom_init
 	 mov	%l7, %o0			! OpenPROM cif handler
@@ -219,6 +305,50 @@
 	call	start_kernel
 	 nop
 	/* Not reached... */
+
+	.globl	setup_tba
+setup_tba:
+	sethi	%hi(sparc64_ttable_tl0), %g5
+	add	%g5, %g4, %g5
+	wrpr	%g5, %tba
+
+	/* Set up MMU globals */
+	rdpr	%pstate, %o1
+	wrpr	%o1, PSTATE_MG, %pstate
+
+	/* PGD/PMD offset mask, used by TLB miss handlers. */
+	sethi	%hi(0x1ff8), %g2
+	or	%g2, %lo(0x1ff8), %g2
+
+	/* Kernel PGDIR used by TLB miss handlers. */
+	mov	%o0, %g6
+
+	/* To catch bootup bugs, this is user PGDIR for TLB miss handlers. */
+	clr	%g7
+
+	/* Setup Interrupt globals */
+	wrpr	%o1, PSTATE_IG, %pstate
+	sethi	%uhi(ivector_to_mask), %g4
+	or	%g4, %ulo(ivector_to_mask), %g4
+	sethi	%hi(ivector_to_mask), %g5
+	or	%g5, %lo(ivector_to_mask), %g5
+	or	%g5, %g4, %g1			/* IVECTOR table */
+	mov	0x40, %g2			/* INTR data 0 register */
+
+	andn	%o1, PSTATE_IE, %o1
+	wrpr	%g0, %g0, %wstate
+	wrpr	%o1, %g0, %pstate
+
+	/* Zap TSB BASE to zero with TSB_size==1. */
+	mov	TSB_REG, %o4
+	mov	1, %o5
+	stxa	%o5, [%o4] ASI_DMMU
+	stxa	%o5, [%o4] ASI_IMMU
+
+	membar	#Sync
+
+	retl
+	 nop
 
 sparc64_boot_end:
 	.skip	0x2000 + _start - sparc64_boot_end
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/ioport.c linux/arch/sparc64/kernel/ioport.c
--- v2.1.33/linux/arch/sparc64/kernel/ioport.c	Thu Mar 27 14:40:00 1997
+++ linux/arch/sparc64/kernel/ioport.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.2 1997/03/18 17:59:31 jj Exp $
+/* $Id: ioport.c,v 1.7 1997/04/10 05:13:01 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -22,6 +22,8 @@
 static unsigned long dvma_next_free   = DVMA_VADDR;
 unsigned long sparc_iobase_vaddr = IOBASE_VADDR;
 
+extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr);
+
 /*
  * sparc_alloc_io:
  * Map and allocates an obio device.
@@ -39,8 +41,8 @@
  *  The virtual address where the mapping actually took place.
  */
 
-void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
-		      unsigned bus_type, int rdonly)
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+		      u32 bus_type, int rdonly)
 {
 	unsigned long vaddr, base_address;
 	unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
@@ -74,7 +76,7 @@
 	base_address = vaddr;
 	/* Do the actual mapping */
 	for (; len > 0; len -= PAGE_SIZE) {
-		mapioaddr(addr, vaddr, rdonly);
+		mapioaddr(addr, vaddr, bus_type, rdonly);
 		vaddr += PAGE_SIZE;
 		addr += PAGE_SIZE;
 	}
@@ -103,8 +105,11 @@
  * at addresses above DVMA_VADDR it will grab them, this way it does not
  * now have to know the peculiarities of where to read the Lance data
  * from. (for example)
+ *
+ * Returns CPU visible address for the buffer returned, dvma_addr is
+ * set to the DVMA visible address.
  */
-void *sparc_dvma_malloc (int len, char *name)
+void *sparc_dvma_malloc (int len, char *name, __u32 *dvma_addr)
 {
 	unsigned long vaddr, base_address;
 
@@ -123,7 +128,8 @@
 	 * pages are now mapped dynamically to save space.
 	 */
 	base_address = vaddr;
-	mmu_map_dma_area(base_address, len);
+	mmu_map_dma_area(base_address, len, dvma_addr);
+
 	/* Assign the memory area. */
 	dvma_next_free = PAGE_ALIGN(dvma_next_free+len);
 
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.1.33/linux/arch/sparc64/kernel/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/irq.c	Mon Apr 14 09:31:09 1997
@@ -0,0 +1,638 @@
+/* $Id: irq.c,v 1.11 1997/04/14 05:38:59 davem Exp $
+ * irq.c: UltraSparc IRQ handling/init/registry.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/random.h> /* XXX ADD add_foo_randomness() calls... -DaveM */
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/sbus.h>
+#include <asm/iommu.h>
+#include <asm/upa.h>
+#include <asm/oplib.h>
+#include <asm/smp.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
+/* Internal flag, should not be visible elsewhere at all. */
+#define SA_SYSIO_MASKED		0x100
+
+/* UPA nodes send interrupt packet to UltraSparc with first data reg value
+ * low 5 bits holding the IRQ identifier being delivered.  We must translate
+ * this into a non-vector IRQ so we can set the softint on this cpu.  To
+ * make things even more swift we store the complete mask here.
+ */
+
+#define NUM_IVECS	2048	/* XXX may need more on sunfire/wildfire */
+
+unsigned long ivector_to_mask[NUM_IVECS];
+
+/* This is based upon code in the 32-bit Sparc kernel written mostly by
+ * David Redman (djhr@tadpole.co.uk).
+ */
+#define MAX_STATIC_ALLOC	4
+static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+static int static_irq_count = 0;
+
+static struct irqaction *irq_action[NR_IRQS+1] = {
+	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
+	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
+};
+
+int get_irq_list(char *buf)
+{
+	int i, len = 0;
+	struct irqaction *action;
+
+	for(i = 0; i < (NR_IRQS + 1); i++) {
+		if(!(action = *(i + irq_action)))
+			continue;
+		len += sprintf(buf + len, "%2d: %8d %c %s",
+			       i, kstat.interrupts[i],
+			       (action->flags & SA_INTERRUPT) ? '+' : ' ',
+			       action->name);
+		for(action = action->next; action; action = action->next) {
+			len += sprintf(buf+len, ",%s %s",
+				       (action->flags & SA_INTERRUPT) ? " +" : "",
+				       action->name);
+		}
+		len += sprintf(buf + len, "\n");
+	}
+	return len;
+}
+
+/* INO number to Sparc PIL level. */
+static unsigned char ino_to_pil[] = {
+	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 0 */
+	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 1 */
+	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 2 */
+	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 3 */
+	3, /* Onboard SCSI */
+	5, /* Onboard Ethernet */
+/*XXX*/	8, /* Onboard BPP */
+	0, /* Bogon */
+       13, /* Audio */
+/*XXX*/15, /* PowerFail */
+	0, /* Bogon */
+	0, /* Bogon */
+       12, /* Zilog Serial Channels (incl. Keyboard/Mouse lines) */
+       11, /* Floppy */
+	0, /* Spare Hardware (bogon for now) */
+	0, /* Keyboard (bogon for now) */
+	0, /* Mouse (bogon for now) */
+	0, /* Serial (bogon for now) */
+     0, 0, /* Bogon, Bogon */
+       10, /* Timer 0 */
+       11, /* Timer 1 */
+     0, 0, /* Bogon, Bogon */
+       15, /* Uncorrectable SBUS Error */
+       15, /* Correctable SBUS Error */
+       15, /* SBUS Error */
+/*XXX*/ 0, /* Power Management (bogon for now) */
+};
+
+/* INO number to IMAP register offset for SYSIO external IRQ's.
+ * This should conform to both Sunfire/Wildfire server and Fusion
+ * desktop designs.
+ */
+#define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
+#define bogon     ((unsigned long) -1)
+static unsigned long irq_offsets[] = {
+/* SBUS Slot 0 --> 3, level 1 --> 7 */
+offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
+offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
+offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),
+offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),offset(imap_slot1),
+offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),
+offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),offset(imap_slot2),
+offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),
+offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),offset(imap_slot3),
+/* Onboard devices (not relevant/used on SunFire). */
+offset(imap_scsi), offset(imap_eth), offset(imap_bpp), bogon,
+offset(imap_audio), offset(imap_pfail), bogon, bogon,
+offset(imap_kms), offset(imap_flpy), offset(imap_shw),
+offset(imap_kbd), offset(imap_ms), offset(imap_ser), bogon, bogon,
+offset(imap_tim0), offset(imap_tim1), bogon, bogon,
+offset(imap_ue), offset(imap_ce), offset(imap_sberr),
+offset(imap_pmgmt),
+};
+
+#undef bogon
+
+#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0]))
+
+/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO
+ * Interrupt Mapping register pointer, or NULL if none exists.
+ */
+static unsigned int *irq_to_imap(unsigned int irq)
+{
+	unsigned long offset;
+	struct sysio_regs *sregs;
+
+	if((irq == 14) ||
+	   (irq >= NUM_IRQ_ENTRIES) ||
+	   ((offset = irq_offsets[irq]) == ((unsigned long)-1)))
+		return NULL;
+	sregs = SBus_chain->iommu->sysio_regs;
+	offset += ((unsigned long) sregs);
+	return ((unsigned int *)offset) + 1;
+}
+
+/* Convert Interrupt Mapping register pointer to assosciated
+ * Interrupt Clear register pointer.
+ */
+static unsigned int *imap_to_iclr(unsigned int *imap)
+{
+	unsigned long diff;
+
+	diff = offset(iclr_unused0) - offset(imap_slot0);
+	return (unsigned int *) (((unsigned long)imap) + diff);
+}
+
+#undef offset
+
+/* For non-SBUS IRQ's we do nothing, else we must enable them in the
+ * appropriate SYSIO interrupt map registers.
+ */
+void enable_irq(unsigned int irq)
+{
+	unsigned long tid;
+	unsigned int *imap;
+
+	/* If this is for the tick interrupt, just ignore, note
+	 * that this is the one and only locally generated interrupt
+	 * source, all others come from external sources (essentially
+	 * any UPA device which is an interruptor).  (actually, on
+	 * second thought Ultra can generate local interrupts for
+	 * async memory errors and we may setup handlers for those
+	 * at some point as well)
+	 *
+	 * XXX See commentary below in request_irq() this assumption
+	 * XXX is broken and needs to be fixed.
+	 */
+	if(irq == 14)
+		return;
+
+	/* Check for bogons. */
+	imap = irq_to_imap(irq);
+	if(imap == NULL)
+		goto do_the_stb_watoosi;
+
+	/* We send it to our UPA MID, for SMP this will be different. */
+	__asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
+	tid = ((tid & UPA_CONFIG_MID) << 9);
+
+	/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
+	 * of this SYSIO's preconfigured IGN in the SYSIO Control
+	 * Register, the hardware just mirrors that value here.
+	 * However for Graphics and UPA Slave devices the full
+	 * SYSIO_IMAP_INR field can be set by the programmer here.
+	 * (XXX we will have to handle those for FFB etc. XXX)
+	 */
+	*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+	return;
+
+do_the_stb_watoosi:
+	printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq);
+	panic("Trying to enable bogon IRQ");
+}
+
+void disable_irq(unsigned int irq)
+{
+	unsigned int *imap;
+
+	/* XXX Grrr, I know this is broken... */
+	if(irq == 14)
+		return;
+
+	/* Check for bogons. */
+	imap = irq_to_imap(irq);
+	if(imap == NULL)
+		goto do_the_stb_watoosi;
+
+	/* NOTE: We do not want to futz with the IRQ clear registers
+	 *       and move the state to IDLE, the SCSI code does call
+	 *       disable_irq() to assure atomicity in the queue cmd
+	 *       SCSI adapter driver code.  Thus we'd lose interrupts.
+	 */
+	*imap &= ~(SYSIO_IMAP_VALID);
+	return;
+
+do_the_stb_watoosi:
+	printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq);
+	panic("Trying to enable bogon IRQ");
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, const char *name, void *dev_cookie)
+{
+	struct irqaction *action, *tmp = NULL;
+	unsigned long flags;
+	unsigned int cpu_irq, *imap, *iclr;
+	
+	/* XXX This really is not the way to do it, the "right way"
+	 * XXX is to have drivers set SA_SBUS or something like that
+	 * XXX in irqflags and we base our decision here on whether
+	 * XXX that flag bit is set or not.
+	 */
+	if(irq == 14)
+		cpu_irq = irq;
+	else
+		cpu_irq = ino_to_pil[irq];
+
+	if(!handler)
+	    return -EINVAL;
+
+	imap = irq_to_imap(irq);
+
+	action = *(cpu_irq + irq_action);
+	if(action) {
+		if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ))
+			for (tmp = action; tmp->next; tmp = tmp->next)
+				;
+		else
+			return -EBUSY;
+
+		if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
+			printk("Attempt to mix fast and slow interrupts on IRQ%d "
+			       "denied\n", irq);
+			return -EBUSY;
+		}   
+		action = NULL;		/* Or else! */
+	}
+
+	save_and_cli(flags);
+
+	/* If this is flagged as statically allocated then we use our
+	 * private struct which is never freed.
+	 */
+	if(irqflags & SA_STATIC_ALLOC)
+	    if(static_irq_count < MAX_STATIC_ALLOC)
+		action = &static_irqaction[static_irq_count++];
+	    else
+		printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
+		       "using kmalloc\n", irq, name);
+	
+	if(action == NULL)
+	    action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+						 GFP_KERNEL);
+	
+	if(!action) { 
+		restore_flags(flags);
+		return -ENOMEM;
+	}
+
+	if(imap) {
+		int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+
+		ivector_to_mask[ivindex] = (1<<cpu_irq);
+		iclr = imap_to_iclr(imap);
+		action->mask = (unsigned long) iclr;
+		irqflags |= SA_SYSIO_MASKED;
+	} else {
+		action->mask = 0;
+	}
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->name = name;
+	action->next = NULL;
+	action->dev_id = dev_cookie;
+
+	if(tmp)
+		tmp->next = action;
+	else
+		*(cpu_irq + irq_action) = action;
+
+	enable_irq(irq);
+	restore_flags(flags);
+	return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_cookie)
+{
+	struct irqaction *action;
+	struct irqaction *tmp = NULL;
+	unsigned long flags;
+	unsigned int cpu_irq;
+
+	if(irq == 14)
+		cpu_irq = irq;
+	else
+		cpu_irq = ino_to_pil[irq];
+	action = *(cpu_irq + irq_action);
+	if(!action->handler) {
+		printk("Freeing free IRQ %d\n", irq);
+		return;
+	}
+	if(dev_cookie) {
+		for( ; action; action = action->next) {
+			if(action->dev_id == dev_cookie)
+				break;
+			tmp = action;
+		}
+		if(!action) {
+			printk("Trying to free free shared IRQ %d\n", irq);
+			return;
+		}
+	} else if(action->flags & SA_SHIRQ) {
+		printk("Trying to free shared IRQ %d with NULL device cookie\n", irq);
+		return;
+	}
+
+	if(action->flags & SA_STATIC_ALLOC) {
+		printk("Attempt to free statically allocated IRQ %d (%s)\n",
+		       irq, action->name);
+		return;
+	}
+
+	save_and_cli(flags);
+	if(action && tmp)
+		tmp->next = action->next;
+	else
+		*(cpu_irq + irq_action) = action->next;
+
+	if(action->flags & SA_SYSIO_MASKED) {
+		unsigned int *imap = irq_to_imap(irq);
+		if(imap != NULL)
+			ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0;
+		else
+			printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
+	}
+
+	kfree(action);
+	if(!*(cpu_irq + irq_action))
+		disable_irq(irq);
+
+	restore_flags(flags);
+}
+
+/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
+unsigned int local_irq_count[NR_CPUS];
+atomic_t __sparc64_bh_counter;
+
+#ifdef __SMP__
+#error SMP not supported on sparc64 just yet
+#else
+
+#define irq_enter(cpu, irq)	(local_irq_count[cpu]++)
+#define irq_exit(cpu, irq)	(local_irq_count[cpu]--)
+
+#endif /* __SMP__ */
+
+void report_spurious_ivec(struct pt_regs *regs)
+{
+	printk("IVEC: Spurious interrupt vector received at (%016lx)\n",
+	       regs->tpc);
+	return;
+}
+
+void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
+{
+	int i;
+	struct irqaction *action;
+	unsigned int cpu_irq;
+
+	cpu_irq = irq & NR_IRQS;
+	action = *(cpu_irq + irq_action);
+
+	prom_printf("Unexpected IRQ[%d]: ", irq);
+	prom_printf("PC[%016lx] NPC[%016lx] FP[%016lx]\n",
+		    regs->tpc, regs->tnpc, regs->u_regs[14]);
+
+	if(action) {
+		prom_printf("Expecting: ");
+		for(i = 0; i < 16; i++) {
+			if(action->handler)
+				prom_printf("[%s:%d:0x%016lx] ", action->name,
+					    i, (unsigned long) action->handler);
+		}
+	}
+	prom_printf("AIEEE\n");
+	prom_printf("bogus interrupt received\n");
+	prom_cmdline ();
+}
+
+void handler_irq(int irq, struct pt_regs *regs)
+{
+	struct irqaction *action;
+	int cpu = smp_processor_id();
+
+	/* XXX */
+	if(irq != 14)
+		clear_softint(1 << irq);
+
+	irq_enter(cpu, irq);
+	action = *(irq + irq_action);
+	kstat.interrupts[irq]++;
+	do {
+		if(!action || !action->handler)
+			unexpected_irq(irq, 0, regs);
+		action->handler(irq, action->dev_id, regs);
+		if(action->flags & SA_SYSIO_MASKED)
+			*((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
+	} while((action = action->next) != NULL);
+	irq_exit(cpu, irq);
+}
+
+#ifdef CONFIG_BLK_DEV_FD
+extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs);
+
+void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
+{
+	struct irqaction *action = *(irq + irq_action);
+	int cpu = smp_processor_id();
+
+	irq_enter(cpu, irq);
+	floppy_interrupt(irq, dev_cookie, regs);
+	if(action->flags & SA_SYSIO_MASKED)
+		*((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
+	irq_exit(cpu, irq);
+}
+#endif
+
+/* XXX This needs to be written for floppy driver, and soon will be necessary
+ * XXX for serial driver as well.
+ */
+int request_fast_irq(unsigned int irq,
+		     void (*handler)(int, void *, struct pt_regs *),
+		     unsigned long irqflags, const char *name)
+{
+	return -1;
+}
+
+/* We really don't need these at all on the Sparc.  We only have
+ * stubs here because they are exported to modules.
+ */
+unsigned long probe_irq_on(void)
+{
+  return 0;
+}
+
+int probe_irq_off(unsigned long mask)
+{
+  return 0;
+}
+
+/* XXX This is a hack, make it per-cpu so that SMP port will work correctly
+ * XXX with mixed MHZ Ultras in the machine. -DaveM
+ */
+static unsigned long cpu_cfreq;
+static unsigned long tick_offset;
+
+/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
+static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	extern void timer_interrupt(int, void *, struct pt_regs *);
+	unsigned long compare;
+	
+	if (!(get_softint () & 1)) {
+		/* Just to be sure... */
+		clear_softint(1 << 14);
+		printk("Spurious level14 at %016lx\n", regs->tpc);
+		return;
+	}
+
+	timer_interrupt(irq, dev_id, regs);
+
+	/* Acknowledge INT_TIMER */
+	clear_softint(1 << 0);
+
+	/* Set up for next timer tick. */
+	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+			     "add	%0, %1, %0\n\t"
+			     "wr	%0, 0x0, %%tick_cmpr"
+			     : "=r" (compare)
+			     : "r" (tick_offset));
+}
+
+/* This is called from time_init() to get the jiffies timer going. */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
+{
+	int node, err;
+
+	/* XXX FIX this for SMP -JJ */
+	node = linux_cpus [0].prom_node;
+	cpu_cfreq = prom_getint(node, "clock-frequency");
+	tick_offset = cpu_cfreq / HZ;
+	err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC),
+			  "timer", NULL);
+	if(err) {
+		prom_printf("Serious problem, cannot register timer interrupt\n");
+		prom_halt();
+	} else {
+		unsigned long flags;
+
+		save_and_cli(flags);
+
+		__asm__ __volatile__("wr	%0, 0x0, %%tick_cmpr\n\t"
+				     "wrpr	%%g0, 0x0, %%tick"
+				     : /* No outputs */
+				     : "r" (tick_offset));
+				     
+		clear_softint (get_softint ());
+
+		restore_flags(flags);
+	}
+	sti();
+}
+
+/* We use this nowhere else, so only define it's layout here. */
+struct sun5_timer {
+	volatile u32 count0, _unused0;
+	volatile u32 limit0, _unused1;
+	volatile u32 count1, _unused2;
+	volatile u32 limit1, _unused3;
+} *prom_timers;
+
+static void map_prom_timers(void)
+{
+	unsigned int addr[3];
+	int tnode, err;
+
+	/* PROM timer node hangs out in the top level of device siblings... */
+	tnode = prom_finddevice("/counter-timer");
+
+	/* Assume if node is not present, PROM uses different tick mechanism
+	 * which we should not care about.
+	 */
+	if(tnode == 0) {
+		prom_timers = (struct sun5_timer *) 0;
+		prom_printf("AIEEE, no timers\n");
+		return;
+	}
+
+	/* If PROM is really using this, it must be mapped by him. */
+	err = prom_getproperty(tnode, "address", (char *)addr, sizeof(addr));
+	if(err == -1) {
+		prom_printf("PROM does not have timer mapped, trying to continue.\n");
+		prom_timers = (struct sun5_timer *) 0;
+		return;
+	}
+	prom_timers = (struct sun5_timer *) addr[0];
+}
+
+static void kill_prom_timer(void)
+{
+	if(!prom_timers)
+		return;
+
+	/* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14.
+	 * We turn both off here just to be paranoid.
+	 */
+	prom_timers->limit0 = 0;
+	prom_timers->limit1 = 0;
+}
+
+#if 0 /* Unused at this time. -DaveM */
+static void enable_prom_timer(void)
+{
+	if(!prom_timers)
+		return;
+
+	/* Set it to fire off every 10ms. */
+	prom_timers->limit1 = 0xa000270f;
+	prom_timers->count1 = 0;
+}
+#endif
+
+__initfunc(void init_IRQ(void))
+{
+	int i;
+
+	map_prom_timers();
+	kill_prom_timer();
+	for(i = 0; i < NUM_IVECS; i++)
+		ivector_to_mask[i] = 0;
+
+	/* We need to clear any IRQ's pending in the soft interrupt
+	 * registers, a spurious one could be left around from the
+	 * PROM timer which we just disabled.
+	 */
+	clear_softint(get_softint());
+
+	/* Now that ivector table is initialized, it is safe
+	 * to receive IRQ vector traps.  We will normally take
+	 * one or two right now, in case some device PROM used
+	 * to boot us wants to speak to us.  We just ignore them.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %%g1\n\t"
+			     "or	%%g1, %0, %%g1\n\t"
+			     "wrpr	%%g1, 0x0, %%pstate"
+			     : /* No outputs */
+			     : "i" (PSTATE_IE)
+			     : "g1");
+}
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/itlb_miss.S linux/arch/sparc64/kernel/itlb_miss.S
--- v2.1.33/linux/arch/sparc64/kernel/itlb_miss.S	Mon Mar 17 14:54:23 1997
+++ linux/arch/sparc64/kernel/itlb_miss.S	Fri Apr 11 10:47:36 1997
@@ -1,71 +1,49 @@
-/* $Id: itlb_miss.S,v 1.5 1997/02/25 20:00:05 jj Exp $
+/* $Id: itlb_miss.S,v 1.10 1997/03/26 12:24:18 davem Exp $
  * itlb_miss.S:	Instruction TLB miss code, this is included directly
  *              into the trap table.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
-	/* We are in the MMU globals, %g7 contains the physical
-	 * address of current->mm->pgd at all times.  %g2 is
-	 * also preloaded with the mask 0x1ff8 to make things
-	 * even quicker.
-	 *
-	 * Many subtle things are done here.  The high bits of
-	 * the virtual address missed are most easily obtained
-	 * from the tag target (it is at address zero in ASI_IMMU
-	 * so no address formation is necessary to get at this).
-	 * This is used to compute the pgd and pmd table offsets.
-	 *
-	 * Even more clever is that physical page zero is always
-	 * a page full of zeroes.  This means we can just follow
-	 * through with all the page table traversals even if nothing
-	 * is mapped because we'll just do loads from page zero
-	 * and get yet another zero.  We only need to do the check
-	 * for the valid bit being set in the final pte we obtain.
-	 *
-	 * Furthermore, we set the TSB base register to the address
-	 * zero, and we use the 8KB tsb ptr to calculate the pte
-	 * offset.  Again it is at address zero in ASI_IMMU_TSB_8KB_PTR
-	 * so no address formation is necessary, saves more instructions.
-	 *
-	 * We use physical address accesses to get at the page
-	 * tables, and this is for two reasons.  This makes it
-	 * impossible to take a fault while we are servicing the
-	 * miss.  Also this physical bypass access only allocates
-	 * in the E-cache, and thus we prevent D-cache pollution
-	 * from the miss handlers probing the page tables.
-	 *
-	 * It looks very hairy and slow.  But I take only 1 more
-	 * overhead of loads from ram than the Solaris version, and
-	 * my version is one instruction quicker for a true TLB miss.
-	 * And more importantly, all true TLB misses under Linux will be
-	 * serviced in _constant_ time.  When using the TSB in the
-	 * manner it was intended to be used (like solaris does) the
-	 * overhead for a TLB miss is _indeterminate_ especially during
-	 * processes startup when the TSB is cold.
-	 */
+/* Gratuitous comment. */
 
-	/* I-cache line 0 */
-	ldxa		[%g0] ASI_IMMU, %g1		! grab Tag Target
-	srlx		%g1, 8, %g3			! put high vaddr bits in place
-	and		%g3, %g2, %g3			! get offset
-	ldxa		[%g7 + %g3] ASI_PHYS_USE_EC, %g5! load pgd
-	sllx		%g1, 2, %g4			! begin pmd_offset formation
-	and		%g4, %g2, %g3			! and now mask it
-	ldxa		[%g5 + %g3] ASI_PHYS_USE_EC, %g4! load pmd
-	ldxa		[%g0] ASI_IMMU_TSB_8KB_PTR, %g1	! get 8KB pointer bits
-	/* I-cache line 1 */
-	srlx		%g1, 1, %g1			! shift right to get pte_offset
-	ldxa		[%g4 + %g1] ASI_PHYS_USE_EC, %g2! load pte
-	brlz,a,pt	%g2, 1f				! is valid bit clear?
-	 stxa		%g2, [%g0] ASI_ITLB_DATA_IN	! nope, load TTE into ITLB
+				/* ICACHE line 1 */
+  /*0x00*/	ldxa		[%g0] ASI_IMMU, %g1		! Get TAG_TARGET
+  /*0x04*/	srlx		%g1, 8, %g3			! Position PGD offset
+  /*0x08*/	srlx		%g1, 48, %g5			! Shift down CONTEXT bits
+  /*0x0c*/	and		%g3, %g2, %g3			! Mask PGD offset
+  /*0x10*/	sllx		%g1, 2, %g4			! Position PMD offset
+  /*0x14*/	ldxa		[%g0] ASI_IMMU_TSB_8KB_PTR, %g1	! For PTE offset
+  /*0x18*/	brz,pn		%g5, 3f				! Context 0 == kernel
+  /*0x1c*/	 and		%g4, %g2, %g4			! Mask PMD offset
 
-	ba,a,pt		%xcc, sparc64_itlb_refbit_catch	! longer processing needed
-1:
-	retry						! return from trap
+				/* ICACHE line 2 */
+  /*0x20*/	ldxa		[%g7 + %g3] ASI_PHYS_USE_EC, %g5	! Load user PGD
+  /*0x24*/	srlx		%g1, 1, %g1				! PTE offset
+  /*0x28*/	ldxa		[%g5 + %g4] ASI_PHYS_USE_EC, %g3	! Load PMD
+2:/*0x2c*/	ldxa		[%g3 + %g1] ASI_PHYS_USE_EC, %g5	! Load PTE
+  /*0x30*/	brlz,a,pt	%g5, 1f					! Valid set?
+  /*0x34*/	 stxa		%g5, [%g0] ASI_ITLB_DATA_IN		! TLB load
+  /*0x38*/	ba,a,pt		%xcc, sparc64_itlb_refbit_catch		! Nope...
+1:/*0x3c*/	retry							! Trap return
 
-	nop; nop;
-	/* I-cache line 2 */
-	nop; nop; nop; nop; nop; nop; nop; nop;
-	/* I-cache line 3 */
-	nop; nop; nop; nop; nop; nop; nop; nop;
+3:				/* ICACHE line 3 */
+  /*0x40*/	ldxa		[%g6 + %g3] ASI_PHYS_USE_EC, %g5	! Load kern PGD
+  /*0x44*/	srlx		%g1, 1, %g1				! PTE offset
+  /*0x48*/	ba,pt		%xcc, 2b				! Continue above
+  /*0x4c*/	 ldxa		[%g5 + %g4] ASI_PHYS_USE_EC, %g3	! Load PMD
+  /*0x50*/	nop
+  /*0x54*/	nop
+  /*0x58*/	nop
+  /*0x5c*/	nop
+
+				/* ICACHE line 4 */
+  /*0x60*/	nop
+  /*0x64*/	nop
+  /*0x68*/	nop
+  /*0x6c*/	nop
+  /*0x70*/	nop
+  /*0x74*/	nop
+  /*0x78*/	nop
+  /*0x7c*/	nop
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.1.33/linux/arch/sparc64/kernel/process.c	Mon Mar 17 14:54:23 1997
+++ linux/arch/sparc64/kernel/process.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.3 1997/03/04 16:26:56 jj Exp $
+/*  $Id: process.c,v 1.6 1997/04/07 18:57:07 jj Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -35,8 +35,7 @@
 #include <asm/processor.h>
 #include <asm/pstate.h>
 #include <asm/elf.h>
-
-extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+#include <asm/fpumacro.h>
 
 #ifndef __SMP__
 
@@ -149,13 +148,13 @@
 
 void show_regwindow(struct reg_window *rw)
 {
-	printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n"
-	       "l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n",
-	       rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
+	printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n",
+	       rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]);
+	printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n",
 	       rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
-	printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n"
-	       "i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n",
-	       rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
+	printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n",
+	       rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3]);
+	printk("i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n",
 	       rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
 }
 
@@ -205,13 +204,13 @@
 	unsigned *stk;
 	int i;
 
-	printk("l0: %08x l1: %08x l2: %08x l3: %08x\n"
-	       "l4: %08x l5: %08x l6: %08x l7: %08x\n",
-	       sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3],
+	printk("l0: %08x l1: %08x l2: %08x l3: %08x\n",
+	       sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3]);
+	printk("l4: %08x l5: %08x l6: %08x l7: %08x\n",
 	       sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]);
-	printk("i0: %08x i1: %08x i2: %08x i3: %08x\n"
-	       "i4: %08x i5: %08x fp: %08x ret_pc: %08x\n",
-	       sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3],
+	printk("i0: %08x i1: %08x i2: %08x i3: %08x\n",
+	       sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3]);
+	printk("i4: %08x i5: %08x fp: %08x ret_pc: %08x\n",
 	       sf->ins[4], sf->ins[5], sf->fp, sf->callers_pc);
 	printk("sp: %08x x0: %08x x1: %08x x2: %08x\n"
 	       "x3: %08x x4: %08x x5: %08x xx: %08x\n",
@@ -246,7 +245,9 @@
 	printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n",
 	       regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
 	       regs->u_regs[15]);
-	show_regwindow((struct reg_window *)regs->u_regs[14]);
+#if 0
+	show_regwindow((struct reg_window *)(regs->u_regs[14] + STACK_BIAS));
+#endif
 }
 
 void show_regs32(struct pt_regs32 *regs)
@@ -295,8 +296,6 @@
 
 	/* XXX missing: float_regs */
 	printk("fsr:               0x%016lx\n", tss->fsr);
-	printk("fpqdepth:          0x%016lx\n", tss->fpqdepth);
-	/* XXX missing: fpqueue */
 
 	printk("sstk_info.stack:   0x%016lx\n",
 	        (unsigned long)tss->sstk_info.the_stack);
@@ -313,33 +312,22 @@
  */
 void exit_thread(void)
 {
-#if 0
-	kill_user_windows();
 #ifndef __SMP__
 	if(last_task_used_math == current) {
 #else
 	if(current->flags & PF_USEDFPU) {
 #endif
-		/* Keep process from leaving FPU in a bogon state. */
-		put_psr(get_psr() | PSR_EF);
-		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
-		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
 #ifndef __SMP__
 		last_task_used_math = NULL;
 #else
 		current->flags &= ~PF_USEDFPU;
 #endif
 	}
-	mmu_exit_hook();
-#endif	
 }
 
 void flush_thread(void)
 {
-#if 0
-	kill_user_windows();
 	current->tss.w_saved = 0;
-	current->tss.uwinmask = 0;
 	current->tss.sstk_info.cur_status = 0;
 	current->tss.sstk_info.the_stack = 0;
 
@@ -350,18 +338,13 @@
 #else
 	if(current->flags & PF_USEDFPU) {
 #endif
-		/* Clean the fpu. */
-		put_psr(get_psr() | PSR_EF);
-		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
-		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
 #ifndef __SMP__
 		last_task_used_math = NULL;
 #else
 		current->flags &= ~PF_USEDFPU;
 #endif
 	}
-	mmu_flush_hook();
-#endif
+	
 	/* Now, this task is no longer a kernel thread. */
 	current->tss.flags &= ~SPARC_FLAG_KTHREAD;
 	current->tss.current_ds = USER_DS;
@@ -418,10 +401,10 @@
 static __inline__ struct sparc_stackf *
 clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
 {
-	unsigned long size;
 	struct sparc_stackf *sp;
 
 #if 0
+	unsigned long size;
 	size = ((unsigned long)src->fp) - ((unsigned long)src);
 	sp = (struct sparc_stackf *)(((unsigned long)dst) - size); 
 
@@ -452,7 +435,7 @@
 		struct task_struct *p, struct pt_regs *regs)
 {
 	struct pt_regs *childregs;
-	struct reg_window *new_stack;
+	struct reg_window *new_stack, *old_stack;
 	unsigned long stack_offset;
 
 #if 0
@@ -462,8 +445,7 @@
 	if(current->flags & PF_USEDFPU) {
 #endif
 		put_psr(get_psr() | PSR_EF);
-		fpsave(&p->tss.float_regs[0], &p->tss.fsr,
-		       &p->tss.fpqueue[0], &p->tss.fpqdepth);
+		fpsave(&p->tss.float_regs[0], &p->tss.fsr);
 #ifdef __SMP__
 		current->flags &= ~PF_USEDFPU;
 #endif
@@ -471,27 +453,28 @@
 #endif	
 
 	/* Calculate offset to stack_frame & pt_regs */
-	stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
+	stack_offset = (PAGE_SIZE - TRACEREG_SZ);
 
-#if 0
-	if(regs->psr & PSR_PS)
+	if(regs->tstate & TSTATE_PRIV)
 		stack_offset -= REGWIN_SZ;
-#endif		
+
 	childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
-	copy_regs(childregs, regs);
+	*childregs = *regs;
 	new_stack = (((struct reg_window *) childregs) - 1);
-	copy_regwin(new_stack, (((struct reg_window *) regs) - 1));
+	old_stack = (((struct reg_window *) regs) - 1);
+	*new_stack = *old_stack;
 
-#if 0
-	p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
-	p->tss.kpc = (((unsigned long) ret_from_syscall) - 0x8);
-	p->tss.kpsr = current->tss.fork_kpsr;
-	p->tss.kwim = current->tss.fork_kwim;
+	p->saved_kernel_stack = ((unsigned long) new_stack);
+	p->tss.ksp = p->saved_kernel_stack - STACK_BIAS;
+	p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
 	p->tss.kregs = childregs;
-#endif	
 
-#if 0
-	if(regs->psr & PSR_PS) {
+	/* Don't look... */
+	p->tss.cwp = regs->u_regs[UREG_G0];
+
+	/* tss.wstate was copied by do_fork() */
+
+	if(regs->tstate & TSTATE_PRIV) {
 		childregs->u_regs[UREG_FP] = p->tss.ksp;
 		p->tss.flags |= SPARC_FLAG_KTHREAD;
 		p->tss.current_ds = KERNEL_DS;
@@ -501,6 +484,7 @@
 		p->tss.flags &= ~SPARC_FLAG_KTHREAD;
 		p->tss.current_ds = USER_DS;
 
+#if 0
 		if (sp != current->tss.kregs->u_regs[UREG_FP]) {
 			struct sparc_stackf *childstack;
 			struct sparc_stackf *parentstack;
@@ -529,8 +513,8 @@
 
 			childregs->u_regs[UREG_FP] = (unsigned long)childstack;
 		}
+#endif
 	}
-#endif	
 
 	/* Set the return value for the child. */
 	childregs->u_regs[UREG_I0] = current->pid;
@@ -538,6 +522,13 @@
 
 	/* Set the return value for the parent. */
 	regs->u_regs[UREG_I1] = 0;
+#if 0
+	printk("CHILD register dump\n");
+	show_regs(childregs);
+	show_regwindow(new_stack);
+	while(1)
+		barrier();
+#endif
 	return 0;
 }
 
@@ -546,8 +537,8 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-	unsigned long first_stack_page;
 #if 0
+	unsigned long first_stack_page;
 	dump->magic = SUNOS_CORE_MAGIC;
 	dump->len = sizeof(struct user);
 	dump->regs.psr = regs->psr;
@@ -567,9 +558,6 @@
 	memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->tss.float_regs[0], (sizeof(unsigned long) * 32));
 	dump->fpu.fpstatus.fsr = current->tss.fsr;
 	dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
-	dump->fpu.fpstatus.fpq_count = current->tss.fpqdepth;
-	memcpy(&dump->fpu.fpstatus.fpq[0], &current->tss.fpqueue[0],
-	       ((sizeof(unsigned long) * 2) * 16));
 	dump->sigcode = current->tss.sig_desc;
 #endif	
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.1.33/linux/arch/sparc64/kernel/rtrap.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/kernel/rtrap.S	Fri Apr 11 10:47:36 1997
@@ -1,68 +1,83 @@
-/* $Id: rtrap.S,v 1.4 1997/03/13 16:24:55 jj Exp $
+/* $Id: rtrap.S,v 1.11 1997/04/03 13:03:50 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <asm/asi.h>
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
+#include <asm/spitfire.h>
+
+/* We assume here this is entered with AG, MG and IG bits in pstate clear */
 
 	.text
 	.align	4
 	.globl	rtrap
 rtrap:
-	sethi	%hi(intr_count), %l0
-	or	%l0, %lo(intr_count), %l0
-	ld	[%l0 + %g4], %l1
 	sethi	%hi(bh_active), %l2
-	brz,pt	%l1, 2f
-	 or	%l2, %lo(bh_active), %l2
+	or	%l2, %lo(bh_active), %l2
 	sethi	%hi(bh_mask), %l1
 	or	%l1, %lo(bh_mask), %l1
-1:
 	ldx	[%l2 + %g4], %l3
 	ldx	[%l1 + %g4], %l4
 	andcc	%l3, %l4, %g0
 	be,pt	%xcc, 2f
-	 mov	1, %l7
+	 nop
 	call	do_bottom_half
-	 st	%l7, [%l0 + %g4]
-	ba,pt	%xcc, 1b
-	 st	%g0, [%l0 + %g4]	
+	 nop
 2:
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %l1
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_TPC], %l2
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2
+	sethi	%hi(0xf << 20), %l4
 	andcc	%l1, TSTATE_PRIV, %l3
+	and	%l1, %l4, %l4
 	rdpr	%pstate, %l7
+	andn	%l1, %l4, %l1			/* XXX May not be needed -DaveM */
 	be,pt	%icc, to_user
 	 andn	%l7, PSTATE_IE, %l7
 3:
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_G1], %g1
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_G2], %g2
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_G3], %g3
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_G4], %g4
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_G5], %g5
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_G6], %g6
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_G7], %g7
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %i0
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I1], %i1
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I2], %i2
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I3], %i3
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I4], %i4
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I5], %i5
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I6], %i6
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_I7], %i7
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_Y], %o3
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %o2
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2
+	rdpr	%tl, %o4
 	wr	%o3, %g0, %y
+	add	%o4, 1, %o4
+
+	srl	%l4, 20, %l4
 	wrpr	%l7, %g0, %pstate
-	wrpr	%g0, 1, %tl
+	wrpr	%l4, 0x0, %pil
+	wrpr	%o4, %g0, %tl
 	wrpr	%l1, %g0, %tstate
 	wrpr	%l2, %g0, %tpc
 	brnz,pn	%l3, 1f
 	 wrpr	%o2, %g0, %tnpc
-	/* we came here from to_user, ie. we have now AG */
+
+	/* We came here from to_user, ie. we have now AG.
+	 * Also have to push user context back into primary.
+	 */
 	restore
+
+	mov	SECONDARY_CONTEXT, %g6
+	mov	PRIMARY_CONTEXT, %g7
+	ldxa	[%g6] ASI_DMMU, %g4
+	stxa	%g4, [%g7] ASI_DMMU
+
 	rdpr	%wstate, %g1
 	rdpr	%otherwin, %g2
 	srl	%g1, 3, %g1
@@ -77,7 +92,7 @@
 	sethi	%hi(need_resched), %l0
 	or	%l0, %lo(need_resched), %l0
 	ld	[%l0 + %g4], %l0
-	wrpr	%o4, PSTATE_IE, %pstate
+	wrpr	%l7, PSTATE_IE, %pstate
 	brz,pt	%l0, 1f
 	 ldx	[%g6 + AOFF_task_signal], %l0
 	call	schedule
@@ -85,7 +100,7 @@
 1:
 	ldx	[%g6 + AOFF_task_blocked], %o0
 	or	%l7, PSTATE_AG, %l7		! Will need this for setting back wstate
-	andcc	%l0, %o0, %g0
+	andncc	%l0, %o0, %g0
 	be,pt	%xcc, 3b
 	 mov	%l5, %o2  
 	mov	%l6, %o3
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.1.33/linux/arch/sparc64/kernel/setup.c	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/kernel/setup.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.1 1997/03/11 17:37:04 jj Exp $
+/*  $Id: setup.c,v 1.5 1997/04/04 00:49:52 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -96,7 +96,7 @@
 
 extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
 
-unsigned int boot_flags;
+unsigned int boot_flags = 0;
 #define BOOTME_DEBUG  0x1
 #define BOOTME_SINGLE 0x2
 #define BOOTME_KGDB   0x4
@@ -109,10 +109,12 @@
 
 void kernel_enter_debugger(void)
 {
+#if 0
 	if (boot_flags & BOOTME_KGDB) {
 		printk("KGDB: Entered\n");
 		breakpoint();
 	}
+#endif
 }
 
 int obp_system_intr(void)
@@ -205,7 +207,7 @@
 #endif
 			if (!strncmp(commands, "mem=", 4)) {
 				/*
-				 * "mem=XXX[kKmM] overrides the PROM-reported
+				 * "mem=XXX[kKmM]" overrides the PROM-reported
 				 * memory size.
 				 */
 				memory_size = simple_strtoul(commands + 4,
@@ -245,9 +247,14 @@
 char saved_command_line[256];
 char reboot_command[256];
 
+unsigned long phys_base;
+
+static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
+
 __initfunc(void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
+	unsigned long lowest_paddr;
 	int total, i;
 
 	/* Initialize PROM console and command line. */
@@ -271,11 +278,12 @@
 #endif	
 
 	idprom_init();
-	load_mmu();
 	total = prom_probe_memory();
-	*memory_start_p = (((unsigned long) &end));
 
+	lowest_paddr = 0xffffffffffffffffUL;
 	for(i=0; sp_banks[i].num_bytes != 0; i++) {
+		if(sp_banks[i].base_addr < lowest_paddr)
+			lowest_paddr = sp_banks[i].base_addr;
 		end_of_phys_memory = sp_banks[i].base_addr +
 			sp_banks[i].num_bytes;
 		if (memory_size) {
@@ -290,7 +298,19 @@
 	}
 	prom_setsync(prom_sync_me);
 
-	*memory_end_p = (end_of_phys_memory + KERNBASE);
+	/* In paging_init() we tip off this value to see if we need
+	 * to change init_mm.pgd to point to the real alias mapping.
+	 */
+	phys_base = lowest_paddr;
+
+	*memory_start_p = PAGE_ALIGN(((unsigned long) &end));
+	*memory_end_p = (end_of_phys_memory + PAGE_OFFSET);
+
+#ifndef NO_DAVEM_DEBUGGING
+	prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n",
+		    phys_base, *memory_start_p, *memory_end_p);
+#endif
+
 	if (!root_flags)
 		root_mountflags &= ~MS_RDONLY;
 	ROOT_DEV = to_kdev_t(root_dev);
@@ -302,7 +322,7 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (ramdisk_image) {
 		initrd_start = ramdisk_image;
-		if (initrd_start < KERNBASE) initrd_start += KERNBASE;
+		if (initrd_start < PAGE_OFFSET) initrd_start += PAGE_OFFSET;
 		initrd_end = initrd_start + ramdisk_size;
 		if (initrd_end > *memory_end_p) {
 			printk(KERN_CRIT "initrd extends beyond end of memory "
@@ -318,12 +338,11 @@
 #endif	
 
 	/* Due to stack alignment restrictions and assumptions... */
-#if 0	
 	init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
-	init_task.mm->mmap->vm_start = KERNBASE;
+	init_task.mm->mmap->vm_start = PAGE_OFFSET;
 	init_task.mm->mmap->vm_end = *memory_end_p;
 	init_task.mm->context = (unsigned long) NO_CONTEXT;
-#endif	
+	init_task.tss.kregs = &fake_swapper_regs;
 
 #ifdef CONFIG_SUN_SERIAL
 	*memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
@@ -334,7 +353,7 @@
 		serial_console = 0;
 #else
 		switch (console_fb) {
-		case 0: /* Let get our io devices from prom */
+		case 0: /* Let's get our io devices from prom */
 			{
 				int idev = prom_query_input_device();
 				int odev = prom_query_output_device();
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.1.33/linux/arch/sparc64/kernel/signal32.c	Mon Mar 17 14:54:23 1997
+++ linux/arch/sparc64/kernel/signal32.c	Fri Apr 11 10:47:36 1997
@@ -1,10 +1,11 @@
-/*  $Id: signal32.c,v 1.4 1997/03/03 16:51:46 jj Exp $
+/*  $Id: signal32.c,v 1.5 1997/04/07 18:57:09 jj Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *  Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *  Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
+ *  Copyright (C) 1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/sched.h>
@@ -21,16 +22,17 @@
 #include <asm/ptrace.h>
 #include <asm/svr4.h>
 #include <asm/pgtable.h>
+#include <asm/psrcompat.h>
+#include <asm/fpumacro.h>
+#include <asm/smp_lock.h>
 
 #define _S(nr) (1<<((nr)-1))
 
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
-asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options);
+#define synchronize_user_stack() do { } while (0)
 
-extern void fpsave32(unsigned long *fpregs, unsigned long *fsr,
-		     void *fpqueue, unsigned long *fpqdepth);
-extern void fpload32(unsigned long *fpregs, unsigned long *fsr);
+asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options);
 
 asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs,
 			 unsigned long orig_o0, int ret_from_syscall);
@@ -56,7 +58,7 @@
 	struct reg_window32 sig_window;
 	int sig_num;
 	int sig_code;
-	struct sigcontext32 *sig_scptr;
+	/* struct sigcontext32 * */ u32 sig_scptr;
 	int sig_address;
 	struct sigcontext32 sig_context;
 };
@@ -70,7 +72,7 @@
 struct new_signal_frame32 {
 	struct sparc_stackf32	ss;
 	__siginfo32_t		info;
-	__siginfo_fpu32_t	*fpu_save;
+	/* __siginfo_fpu32_t * */ u32 fpu_save;
 	unsigned int		insns [2];
 	__siginfo_fpu32_t	fpu_state;
 };
@@ -113,12 +115,16 @@
 
 asmlinkage void do_sigpause32(unsigned int set, struct pt_regs *regs)
 {
+	lock_kernel ();
 	_sigpause32_common(set, regs);
+	unlock_kernel ();
 }
 
 asmlinkage void do_sigsuspend32(struct pt_regs *regs)
 {
+	lock_kernel ();
 	_sigpause32_common(regs->u_regs[UREG_I0], regs);
+	unlock_kernel ();
 }
 
 
@@ -137,58 +143,59 @@
 	current->used_math = 1;
 	current->flags &= ~PF_USEDFPU;
 
-	copy_32bit_to_kernel_fpuregs(&current->tss.float_regs[0],
-				     &fpu->si_float_regs[0],
-				     (sizeof(unsigned int) * 32));
+	copy_from_user(&current->tss.float_regs[0],
+		       &fpu->si_float_regs[0],
+		       (sizeof(unsigned int) * 32));
 	__get_user(current->tss.fsr, &fpu->si_fsr);
-	__get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
-	if (current->tss.fpqdepth != 0)
-		copy_from_user(&current->tss.fpqueue[0],
-			       &fpu->si_fpqueue[0],
-			       ((sizeof(unsigned long) +
-			       (sizeof(unsigned long *)))*16));
 }
 
 void do_new_sigreturn32(struct pt_regs *regs)
 {
 	struct new_signal_frame32 *sf;
-	unsigned long up_tstate;
+	unsigned int psr, i;
+	unsigned pc, npc, fpu_save, mask;
 	
 	sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
 	/* 1. Make sure we are not getting garbage from the user */
 	if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
 		do_exit (SIGSEGV);
-		return;
 	}
 	if (((unsigned long) sf) & 3){
 		do_exit (SIGSEGV);
-		return;
 	}
-	if ((sf->info.si_regs.pc | sf->info.si_regs.npc) & 3){
+	get_user(pc, &sf->info.si_regs.pc);
+	__get_user(npc, &sf->info.si_regs.npc);
+	if ((pc | npc) & 3){
 		do_exit (SIGSEGV);
-		return;
 	}
+	regs->tpc = pc;
+	regs->tnpc = npc;
 
 	/* 2. Restore the state */
-	copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs,
-				     sizeof (struct pt_regs));
+	__get_user(regs->y, &sf->info.si_regs.y);
+	__get_user(psr, &sf->info.si_regs.psr);
+	for (i = 0; i < 16; i++)
+		__get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
 
 	/* User can only change condition codes and FPU enabling in %tstate. */
 	regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
-	regs->tstate |= psr_to_tstate_icc(sf->info.si_regs.psr);
-	regs->tstate |= (sf->info.si_regs.psr & PSR_EF);
+	regs->tstate |= psr_to_tstate_icc(psr);
+	if (psr & PSR_EF) regs->tstate |= TSTATE_PEF;
 
-	if (sf->fpu_save)
-		restore_fpu_state32(regs, sf->fpu_state);
-
-	current->blocked = sf->info.si_mask & _BLOCKABLE;
+	__get_user(fpu_save, &sf->fpu_save);
+	if (fpu_save)
+		restore_fpu_state32(regs, &sf->fpu_state);
+	__get_user(mask, &sf->info.si_mask);
+	current->blocked = mask & _BLOCKABLE;
+	unlock_kernel();
 }
 
 asmlinkage void do_sigreturn32(struct pt_regs *regs)
 {
 	struct sigcontext32 *scptr;
-	unsigned long pc, npc, psr;
+	unsigned pc, npc, psr;
 
+	lock_kernel ();
 	synchronize_user_stack();
 	if (current->tss.new_signal)
 		return do_new_sigreturn32(regs);
@@ -198,8 +205,8 @@
 	if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
 	   (((unsigned long) scptr) & 3)) {
 		printk("%s [%d]: do_sigreturn, scptr is invalid at "
-		       "pc<%08lx> scptr<%p>\n",
-		       current->comm, current->pid, regs->pc, scptr);
+		       "pc<%016lx> scptr<%p>\n",
+		       current->comm, current->pid, regs->tpc, scptr);
 		do_exit(SIGSEGV);
 	}
 	__get_user(pc, &scptr->sigc_pc);
@@ -211,22 +218,23 @@
 	current->blocked &= _BLOCKABLE;
 	__get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack);
 	current->tss.sstk_info.cur_status &= 1;
-	regs->pc = pc;
-	regs->npc = npc;
+	regs->tpc = pc;
+	regs->tnpc = npc;
 	__get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);
 	__get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0);
 	__get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1);
 
-	/* User can only change condition codes in %psr. */
+	/* User can only change condition codes in %tstate. */
 	__get_user(psr, &scptr->sigc_psr);
-	regs->psr &= ~(PSR_ICC);
-	regs->psr |= (psr & PSR_ICC);
+	regs->tstate &= ~(TSTATE_ICC);
+	regs->tstate |= psr_to_tstate_icc(psr);
+	unlock_kernel ();
 }
 
 /* Checks if the fp is valid */
 static int invalid_frame_pointer(void *fp, int fplen)
 {
-	if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen))
+	if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
 		return 1;
 	return 0;
 }
@@ -239,6 +247,9 @@
 	struct sigcontext32 *sc;
 	int window = 0;
 	int old_status = current->tss.sstk_info.cur_status;
+	unsigned psr;
+	int i;
+	u32 temp;
 
 	synchronize_user_stack();
 	sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP];
@@ -247,7 +258,7 @@
 #ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */
 		printk("%s [%d]: User has trashed signal stack\n",
 		       current->comm, current->pid);
-		printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n",
+		printk("Sigstack ptr %p handler at pc<%016lx> for sig<%d>\n",
 		       sframep, pc, signr);
 #endif
 		/* Don't change signal code and address, so that
@@ -265,10 +276,13 @@
 	__put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
 	__put_user(pc, &sc->sigc_pc);
 	__put_user(npc, &sc->sigc_npc);
-	__put_user(regs->psr, &sc->sigc_psr);
+	psr = tstate_to_psr (regs->tstate);
+	__put_user(psr, &sc->sigc_psr);
 	__put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
 	__put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
 	__put_user(current->tss.w_saved, &sc->sigc_oswins);
+#if 0
+/* w_saved is not currently used... */
 	if(current->tss.w_saved)
 		for(window = 0; window < current->tss.w_saved; window++) {
 			sc->sigc_spbuf[window] =
@@ -278,9 +292,12 @@
 			       sizeof(struct reg_window));
 		}
 	else
-		copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
-		       sizeof(struct reg_window));
-
+#endif	
+		for (i = 0; i < 16; i++) {
+			get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i));
+			put_user (temp, (((u32 *)sframep)+i));
+		}
+		       
 	current->tss.w_saved = 0; /* So process is allowed to execute. */
 	__put_user(signr, &sframep->sig_num);
 	if(signr == SIGSEGV ||
@@ -294,10 +311,10 @@
 		__put_user(0, &sframep->sig_code);
 		__put_user(0, &sframep->sig_address);
 	}
-	__put_user(sc, &sframep->sig_scptr);
+	__put_user((u64)sc, &sframep->sig_scptr);
 	regs->u_regs[UREG_FP] = (unsigned long) sframep;
-	regs->pc = (unsigned long) sa->sa_handler;
-	regs->npc = (regs->pc + 4);
+	regs->tpc = (unsigned long) sa->sa_handler;
+	regs->tnpc = (regs->tpc + 4);
 }
 
 
@@ -306,29 +323,20 @@
 {
 #ifdef __SMP__
 	if (current->flags & PF_USEDFPU) {
-		put_psr(get_psr() | PSR_EF);
-		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
-		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
-		regs->psr &= ~(PSR_EF);
+		fpsave32(&current->tss.float_regs[0], &current->tss.fsr);
+		regs->tstate &= ~(TSTATE_PEF);
 		current->flags &= ~(PF_USEDFPU);
 	}
 #else
 	if (current == last_task_used_math) {
-		put_psr(get_psr() | PSR_EF);
-		fpsave(&current->tss.float_regs[0], &current->tss.fsr,
-		       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+		fpsave32((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
 		last_task_used_math = 0;
-		regs->psr &= ~(PSR_EF);
+		regs->tstate &= ~(TSTATE_PEF);
 	}
 #endif
 	copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
 		     (sizeof(unsigned int) * 32));
 	__put_user(current->tss.fsr, &fpu->si_fsr);
-	__put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
-	if (current->tss.fpqdepth != 0)
-		copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
-			     ((sizeof(unsigned long) +
-			     (sizeof(unsigned long *)))*16));
 	current->used_math = 0;
 }
 
@@ -338,6 +346,8 @@
 {
 	struct new_signal_frame32 *sf;
 	int sigframe_size;
+	u32 psr, tmp;
+	int i;
 
 	/* 1. Make sure everything is clean */
 	synchronize_user_stack();
@@ -345,7 +355,7 @@
 	if (!current->used_math)
 		sigframe_size -= sizeof(__siginfo_fpu32_t);
 
-	sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
+	sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
 	
 	if (invalid_frame_pointer (sf, sigframe_size)){
 		do_exit(SIGILL);
@@ -360,21 +370,30 @@
 	}
 
 	/* 2. Save the current process state */
-	memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs));
+	put_user(regs->tpc, &sf->info.si_regs.pc);
+	__put_user(regs->tnpc, &sf->info.si_regs.npc);
+	__put_user(regs->y, &sf->info.si_regs.y);
+	psr = tstate_to_psr (regs->tstate);
+	__put_user(psr, &sf->info.si_regs.psr);
+	for (i = 0; i < 16; i++)
+		__put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
 
 	if (current->used_math) {
 		save_fpu_state32(regs, &sf->fpu_state);
-		sf->fpu_save = &sf->fpu_state;
+		__put_user((u64)&sf->fpu_state, &sf->fpu_save);
 	} else {
-		sf->fpu_save = NULL;
+		__put_user(0, &sf->fpu_save);
 	}
 
-	sf->info.si_mask = oldmask;
-	memcpy (sf, (char *)regs->u_regs [UREG_FP], sizeof(struct reg_window));
+	__put_user(oldmask, &sf->info.si_mask);
+	for (i = 0; i < sizeof(struct reg_window32)/4; i++) {
+		__get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i));
+		__put_user(tmp, (((u32 *)sf)+i));
+	}
 	
 	/* 3. return to kernel instructions */
-	sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn, %g1 */
-	sf->insns [1] = 0x91d02010; /* t 0x10 */
+	__put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
+	__put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
 
 	/* 4. signal handler back-trampoline and parameters */
 	regs->u_regs[UREG_FP] = (unsigned long) sf;
@@ -383,11 +402,12 @@
 	regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
 
 	/* 5. signal handler */
-	regs->pc = (unsigned long) sa->sa_handler;
-	regs->npc = (regs->pc + 4);
+	regs->tpc = (unsigned long) sa->sa_handler;
+	regs->tnpc = (regs->tpc + 4);
 
 	/* Flush instruction space. */
-	flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+	__asm__ __volatile__ ("flush %0; flush %0 + 4" : : "r" (&(sf->insns[0])));
+		
 }
 
 /* Setup a Solaris stack frame */
@@ -402,6 +422,8 @@
 	svr4_gwindows_t *gw;
 	svr4_ucontext_t *uc;
 	int window = 0;
+	unsigned psr;
+	int i;
 
 	synchronize_user_stack();
 	sfp = (svr4_signal_frame_t *) regs->u_regs[UREG_FP] - REGWIN_SZ;
@@ -432,14 +454,17 @@
 	__put_user(oldmask, &uc->sigmask.sigbits [0]);
 
 	/* Store registers */
-	__put_user(regs->pc, &((*gr) [SVR4_PC]));
-	__put_user(regs->npc, &((*gr) [SVR4_NPC]));
-	__put_user(regs->psr, &((*gr) [SVR4_PSR]));
+	__put_user(regs->tpc, &((*gr) [SVR4_PC]));
+	__put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
+	psr = tstate_to_psr (regs->tstate);
+	__put_user(psr, &((*gr) [SVR4_PSR]));
 	__put_user(regs->y, &((*gr) [SVR4_Y]));
 	
 	/* Copy g [1..7] and o [0..7] registers */
-	copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
-	copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
+	for (i = 0; i < 7; i++)
+		__put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+	for (i = 0; i < 8; i++)
+		__put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
 
 	/* Setup sigaltstack, FIXME */
 	__put_user(0xdeadbeef, &uc->stack.sp);
@@ -465,11 +490,13 @@
 	 *    These windows are just used in case synchronize_user_stack failed
 	 *    to flush the user windows.
 	 */
+#if 0	 
 	for(window = 0; window < current->tss.w_saved; window++) {
 		__put_user((int *) &(gw->win [window]), &gw->winptr [window]);
 		copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
 		__put_user(0, gw->winptr [window]);
 	}
+#endif	
 
 	/* 4. We just pay attention to the gw->count field on setcontext */
 	current->tss.w_saved = 0; /* So process is allowed to execute. */
@@ -483,23 +510,23 @@
 	__put_user(SVR4_SINOINFO, &si->siginfo.code);
 
 	regs->u_regs[UREG_FP] = (unsigned long) sfp;
-	regs->pc = (unsigned long) sa->sa_handler;
-	regs->npc = (regs->pc + 4);
+	regs->tpc = (unsigned long) sa->sa_handler;
+	regs->tnpc = (regs->tpc + 4);
 
 #ifdef DEBUG_SIGNALS
-	printk ("Solaris-frame: %x %x\n", (int) regs->pc, (int) regs->npc);
+	printk ("Solaris-frame: %x %x\n", (int) regs->tpc, (int) regs->tnpc);
 #endif
 	/* Arguments passed to signal handler */
 	if (regs->u_regs [14]){
-		struct reg_window *rw = (struct reg_window *) regs->u_regs [14];
+		struct reg_window32 *rw = (struct reg_window32 *) regs->u_regs [14];
 
 		__put_user(signr, &rw->ins [0]);
-		__put_user(si, &rw->ins [1]);
-		__put_user(uc, &rw->ins [2]);
-		__put_user(sfp, &rw->ins [6]);	/* frame pointer */
+		__put_user((u64)si, &rw->ins [1]);
+		__put_user((u64)uc, &rw->ins [2]);
+		__put_user((u64)sfp, &rw->ins [6]);	/* frame pointer */
 		regs->u_regs[UREG_I0] = signr;
-		regs->u_regs[UREG_I1] = (uint) si;
-		regs->u_regs[UREG_I2] = (uint) uc;
+		regs->u_regs[UREG_I1] = (u32)(u64) si;
+		regs->u_regs[UREG_I2] = (u32)(u64) uc;
 	}
 }
 
@@ -508,6 +535,7 @@
 {
 	svr4_gregset_t  *gr;
 	svr4_mcontext_t *mc;
+	int i;
 
 	synchronize_user_stack();
 	if (current->tss.w_saved){
@@ -525,14 +553,16 @@
 	__put_user(current->blocked, &uc->sigmask.sigbits [0]);
 
 	/* Store registers */
-	__put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
-	__put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]);
-	__put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]);
+	__put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
+	__put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
+	__put_user(tstate_to_psr(regs->tstate), &uc->mcontext.greg [SVR4_PSR]);
         __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
 	
 	/* Copy g [1..7] and o [0..7] registers */
-	copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
-	copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+	for (i = 0; i < 7; i++)
+		__put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+	for (i = 0; i < 8; i++)
+		__put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
 
 	/* Setup sigaltstack, FIXME */
 	__put_user(0xdeadbeef, &uc->stack.sp);
@@ -551,7 +581,8 @@
 {
 	struct thread_struct *tp = &current->tss;
 	svr4_gregset_t  *gr;
-	unsigned long pc, npc, psr;
+	u32 pc, npc, psr;
+	int i;
 	
 	/* Fixme: restore windows, or is this already taken care of in
 	 * svr4_setup_frame when sync_user_windows is done?
@@ -562,7 +593,7 @@
 		printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved);
 		do_exit(SIGSEGV);
 	}
-	if (((uint) c) & 3){
+	if (((unsigned long) c) & 3){
 		printk ("Unaligned structure passed\n");
 		do_exit (SIGSEGV);
 	}
@@ -585,16 +616,18 @@
 	    /* that we don't want it to mess with our PC and nPC */
 	__get_user(current->blocked, &c->sigmask.sigbits [0]);
 	current->blocked &= _BLOCKABLE;
-	regs->pc = pc;
-	regs->npc = npc | 1;
+	regs->tpc = pc;
+	regs->tnpc = npc | 1;
 	__get_user(regs->y, &((*gr) [SVR4_Y]));
 	__get_user(psr, &((*gr) [SVR4_PSR]));
-	regs->psr &= ~(PSR_ICC);
-	regs->psr |= (psr & PSR_ICC);
+	regs->tstate &= ~(TSTATE_ICC);
+	regs->tstate |= psr_to_tstate_icc(psr);
 
 	/* Restore g[1..7] and o[0..7] registers */
-	copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
-	copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
+	for (i = 0; i < 7; i++)
+		__put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+	for (i = 0; i < 8; i++)
+		__put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
 
 	return -EINTR;
 }
@@ -604,12 +637,12 @@
 				   int svr4_signal)
 {
 	if(svr4_signal)
-		setup_svr4_frame32(sa, regs->pc, regs->npc, regs, signr, oldmask);
+		setup_svr4_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask);
 	else {
 		if (current->tss.new_signal)
 			new_setup_frame32(sa, regs, signr, oldmask);
 		else
-			setup_frame32(sa, regs->pc, regs->npc, regs, signr, oldmask);
+			setup_frame32(sa, regs->tpc, regs->tnpc, regs, signr, oldmask);
 	}
 	if(sa->sa_flags & SA_ONESHOT)
 		sa->sa_handler = NULL;
@@ -624,7 +657,7 @@
 		case ERESTARTNOHAND:
 		no_system_call_restart:
 			regs->u_regs[UREG_I0] = EINTR;
-			regs->psr |= PSR_C;
+			regs->tstate |= TSTATE_ICARRY;
 			break;
 		case ERESTARTSYS:
 			if(!(sa->sa_flags & SA_RESTART))
@@ -632,8 +665,8 @@
 		/* fallthrough */
 		case ERESTARTNOINTR:
 			regs->u_regs[UREG_I0] = orig_i0;
-			regs->pc -= 4;
-			regs->npc -= 4;
+			regs->tpc -= 4;
+			regs->tnpc -= 4;
 	}
 }
 
@@ -730,4 +763,34 @@
 		regs->tnpc -= 4;
 	}
 	return 0;
+}
+
+struct sigstack32 {
+	u32 the_stack;
+	int cur_status;
+};
+
+asmlinkage int
+sys32_sigstack(struct sigstack32 *ssptr, struct sigstack32 *ossptr)
+{
+	int ret = -EFAULT;
+
+	lock_kernel();
+	/* First see if old state is wanted. */
+	if(ossptr) {
+		if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) ||
+		    __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status))
+			goto out;
+	}
+
+	/* Now see if we want to update the new state. */
+	if(ssptr) {
+		if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) ||
+		    __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status))
+			goto out;
+	}
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/sparcelf32.c linux/arch/sparc64/kernel/sparcelf32.c
--- v2.1.33/linux/arch/sparc64/kernel/sparcelf32.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/sparcelf32.c	Fri Apr 11 10:47:36 1997
@@ -0,0 +1,1280 @@
+/* sparcelf32.c: Support 32-bit Sparc ELF binaries on Ultra.
+ *
+ * This is just binfmt_elf.c with hooks so that the types are those
+ * for a 32-bit ELF binaries.
+ */
+
+/* This makes it work. */
+#define ELF_ARCH	EM_SPARC
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB;
+
+/*
+ * linux/fs/binfmt_elf.c
+ *
+ * These are the functions used to load ELF format executables as used
+ * on SVr4 machines.  Information on the format may be found in the book
+ * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
+ * Tools".
+ *
+ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
+ */
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/binfmts.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/shm.h>
+#include <linux/personality.h>
+#include <linux/elfcore.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+#include <linux/config.h>
+
+#define DLINFO_ITEMS 12
+
+#include <linux/elf.h>
+
+static int load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs);
+static int load_elf32_library(int fd);
+extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+extern void dump_thread(struct pt_regs *, struct user *);
+
+extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
+
+/*
+ * If we don't support core dumping, then supply a NULL so we
+ * don't even try.
+ */
+#ifdef USE_ELF_CORE_DUMP
+static int elf32_core_dump(long signr, struct pt_regs * regs);
+#else
+#define elf32_core_dump	NULL
+#endif
+
+#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
+#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
+
+static struct linux_binfmt elf32_format = {
+#ifndef MODULE
+	NULL, NULL, load_elf32_binary, load_elf32_library, elf32_core_dump
+#else
+	NULL, &__this_module, load_elf32_binary, load_elf32_library, elf32_core_dump
+#endif
+};
+
+static void set_brk(unsigned long start, unsigned long end)
+{
+	start = PAGE_ALIGN(start);
+	end = PAGE_ALIGN(end);
+	if (end <= start)
+		return;
+	do_mmap(NULL, start, end - start,
+		PROT_READ | PROT_WRITE | PROT_EXEC,
+		MAP_FIXED | MAP_PRIVATE, 0);
+}
+
+
+/* We need to explicitly zero any fractional pages
+   after the data section (i.e. bss).  This would
+   contain the junk from the file that should not
+   be in memory */
+
+
+static void padzero(unsigned long elf_bss)
+{
+	unsigned long nbyte;
+
+	nbyte = elf_bss & (PAGE_SIZE-1);
+	if (nbyte) {
+		nbyte = PAGE_SIZE - nbyte;
+		clear_user((void *) elf_bss, nbyte);
+	}
+}
+
+__u32 *create_elf32_tables(char *p, int argc, int envc,
+			   struct elfhdr * exec,
+			   unsigned long load_addr,
+			   unsigned long interp_load_addr, int ibcs)
+{
+	__u32 *argv, *envp;
+	__u32 *sp, *csp;
+
+	/*
+	 * Force 16 byte alignment here for generality.
+	 */
+	sp = (__u32 *) (~15UL & (unsigned long) p);
+	csp = sp;
+	csp -= exec ? DLINFO_ITEMS*2 : 2;
+	csp -= envc+1;
+	csp -= argc+1;
+	if (!(((unsigned long) csp) & 4))
+		sp--;
+
+	/*
+	 * Put the ELF interpreter info on the stack
+	 */
+#define NEW_AUX_ENT(nr, id, val) \
+	  __put_user ((id), sp+(nr*2)); \
+	  __put_user ((val), sp+(nr*2+1)); \
+
+	sp -= 2;
+	NEW_AUX_ENT(0, AT_NULL, 0);
+
+	if (exec) {
+		sp -= 11*2;
+
+	  NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
+	  NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr));
+	  NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum);
+	  NEW_AUX_ENT (3, AT_PAGESZ, PAGE_SIZE);
+	  NEW_AUX_ENT (4, AT_BASE, interp_load_addr);
+	  NEW_AUX_ENT (5, AT_FLAGS, 0);
+	  NEW_AUX_ENT (6, AT_ENTRY, (__u32) exec->e_entry);
+	  NEW_AUX_ENT (7, AT_UID, (__u32) current->uid);
+	  NEW_AUX_ENT (8, AT_EUID, (__u32) current->euid);
+	  NEW_AUX_ENT (9, AT_GID, (__u32) current->gid);
+	  NEW_AUX_ENT (10, AT_EGID, (__u32) current->egid);
+	}
+#undef NEW_AUX_ENT
+
+	sp -= envc+1;
+	envp = (__u32 *) sp;
+	sp -= argc+1;
+	argv = (__u32 *) sp;
+	if (!ibcs) {
+		__put_user(((__u32) envp),--sp);
+		__put_user(((__u32) argv),--sp);
+	}
+
+	__put_user((__u32)argc,--sp);
+	current->mm->arg_start = (unsigned long) p;
+	while (argc-->0) {
+		__put_user(((__u32)p),argv++);
+		p += strlen_user(p);
+	}
+	__put_user(NULL, argv);
+	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+	while (envc-->0) {
+		__put_user(((__u32)p),envp++);
+		p += strlen_user(p);
+	}
+	__put_user(NULL, envp);
+	current->mm->env_end = (unsigned long) p;
+	return sp;
+}
+
+
+/* This is much more generalized than the library routine read function,
+   so we keep this separate.  Technically the library read function
+   is only provided so that we can read a.out libraries that have
+   an ELF header */
+
+static unsigned long load_elf32_interp(struct elfhdr * interp_elf_ex,
+				       struct inode * interpreter_inode,
+				       unsigned long *interp_load_addr)
+{
+	struct file * file;
+	struct elf_phdr *elf_phdata  =  NULL;
+	struct elf_phdr *eppnt;
+	unsigned long load_addr;
+	int load_addr_set = 0;
+	int elf_exec_fileno;
+	int retval;
+	unsigned long last_bss, elf_bss;
+	unsigned long error;
+	int i;
+
+	elf_bss = 0;
+	last_bss = 0;
+	error = load_addr = 0;
+
+	/* First of all, some simple consistency checks */
+	if ((interp_elf_ex->e_type != ET_EXEC &&
+	    interp_elf_ex->e_type != ET_DYN) ||
+	   !elf_check_arch(interp_elf_ex->e_machine) ||
+	   (!interpreter_inode->i_op ||
+	    !interpreter_inode->i_op->default_file_ops->mmap)){
+		return ~0UL;
+	}
+
+	/* Now read in all of the header information */
+
+	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
+	    return ~0UL;
+
+	elf_phdata =  (struct elf_phdr *)
+		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
+			GFP_KERNEL);
+	if (!elf_phdata)
+	  return ~0UL;
+
+	/*
+	 * If the size of this structure has changed, then punt, since
+	 * we will be doing the wrong thing.
+	 */
+	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
+	  {
+	    kfree(elf_phdata);
+	    return ~0UL;
+	  }
+
+	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
+			   (char *) elf_phdata,
+			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
+
+	if (retval < 0) {
+		kfree (elf_phdata);
+		return retval;
+ 	}
+
+	elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+	if (elf_exec_fileno < 0) {
+	  kfree(elf_phdata);
+	  return ~0UL;
+	}
+
+	file = current->files->fd[elf_exec_fileno];
+
+	eppnt = elf_phdata;
+	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+	  if (eppnt->p_type == PT_LOAD) {
+	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+	    int elf_prot = 0;
+	    unsigned long vaddr = 0;
+	    unsigned long k;
+
+	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
+	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
+	    	elf_type |= MAP_FIXED;
+	    	vaddr = eppnt->p_vaddr;
+	    } else {
+		load_addr = get_unmapped_area(0, eppnt->p_filesz +
+					ELF_PAGEOFFSET(eppnt->p_vaddr));
+	    }
+
+	    error = do_mmap(file,
+			    load_addr + ELF_PAGESTART(vaddr),
+			    eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
+			    elf_prot,
+			    elf_type,
+			    eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+
+	    if (error > -1024UL) {
+	      /* Real error */
+	      sys_close(elf_exec_fileno);
+	      kfree(elf_phdata);
+	      return ~0UL;
+	    }
+
+	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+	      load_addr = error;
+	      load_addr_set = 1;
+	    }
+
+	    /*
+	     * Find the end of the file  mapping for this phdr, and keep
+	     * track of the largest address we see for this.
+	     */
+	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+	    if (k > elf_bss) elf_bss = k;
+
+	    /*
+	     * Do the same thing for the memory mapping - between
+	     * elf_bss and last_bss is the bss section.
+	     */
+	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+	    if (k > last_bss) last_bss = k;
+	  }
+
+	/* Now use mmap to map the library into memory. */
+
+	sys_close(elf_exec_fileno);
+
+	/*
+	 * Now fill out the bss section.  First pad the last page up
+	 * to the page boundary, and then perform a mmap to make sure
+	 * that there are zeromapped pages up to and including the last
+	 * bss page.
+	 */
+	padzero(elf_bss);
+	elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
+
+	/* Map the last of the bss segment */
+	if (last_bss > elf_bss)
+	  do_mmap(NULL, elf_bss, last_bss-elf_bss,
+		  PROT_READ|PROT_WRITE|PROT_EXEC,
+		  MAP_FIXED|MAP_PRIVATE, 0);
+	kfree(elf_phdata);
+
+	*interp_load_addr = load_addr;
+	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
+}
+
+static unsigned long load_aout32_interp(struct exec * interp_ex,
+			     struct inode * interpreter_inode)
+{
+  int retval;
+  unsigned long elf_entry;
+
+  current->mm->brk = interp_ex->a_bss +
+    (current->mm->end_data = interp_ex->a_data +
+     (current->mm->end_code = interp_ex->a_text));
+  elf_entry = interp_ex->a_entry;
+
+
+  if (N_MAGIC(*interp_ex) == OMAGIC) {
+    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+	    PROT_READ|PROT_WRITE|PROT_EXEC,
+	    MAP_FIXED|MAP_PRIVATE, 0);
+    retval = read_exec(interpreter_inode, 32, (char *) 0,
+		       interp_ex->a_text+interp_ex->a_data, 0);
+  } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
+    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+	    PROT_READ|PROT_WRITE|PROT_EXEC,
+	    MAP_FIXED|MAP_PRIVATE, 0);
+    retval = read_exec(interpreter_inode,
+		       N_TXTOFF(*interp_ex) ,
+		       (char *) N_TXTADDR(*interp_ex),
+		       interp_ex->a_text+interp_ex->a_data, 0);
+  } else
+    retval = -1;
+
+  if (retval >= 0)
+    do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1),
+	    interp_ex->a_bss,
+	    PROT_READ|PROT_WRITE|PROT_EXEC,
+	    MAP_FIXED|MAP_PRIVATE, 0);
+  if (retval < 0) return ~0UL;
+  return elf_entry;
+}
+
+/*
+ * These are the functions used to load ELF style executables and shared
+ * libraries.  There is no binary dependent code anywhere else.
+ */
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+
+static inline int
+do_load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+	struct elfhdr elf_ex;
+	struct elfhdr interp_elf_ex;
+	struct file * file;
+  	struct exec interp_ex;
+	struct inode *interpreter_inode;
+	unsigned long load_addr;
+	int load_addr_set = 0;
+	unsigned int interpreter_type = INTERPRETER_NONE;
+	unsigned char ibcs2_interpreter;
+	int i;
+	int old_fs;
+	int error;
+	struct elf_phdr * elf_ppnt, *elf_phdata;
+	int elf_exec_fileno;
+	unsigned long elf_bss, k, elf_brk;
+	int retval;
+	char * elf_interpreter;
+	unsigned long elf_entry, interp_load_addr = 0;
+	int status;
+	unsigned long start_code, end_code, end_data;
+	unsigned long elf_stack;
+	char passed_fileno[6];
+
+	ibcs2_interpreter = 0;
+	status = 0;
+	load_addr = 0;
+	elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
+
+	if (elf_ex.e_ident[0] != 0x7f ||
+	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
+		return  -ENOEXEC;
+	}
+
+
+	/* First of all, some simple consistency checks */
+	if ((elf_ex.e_type != ET_EXEC &&
+	    elf_ex.e_type != ET_DYN) ||
+	   (! elf_check_arch(elf_ex.e_machine)) ||
+	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+	    !bprm->inode->i_op->default_file_ops->mmap)){
+		return -ENOEXEC;
+	}
+
+	/* Now read in all of the header information */
+
+	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
+						 elf_ex.e_phnum, GFP_KERNEL);
+	if (elf_phdata == NULL) {
+		return -ENOMEM;
+	}
+
+	retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
+	if (retval < 0) {
+		kfree (elf_phdata);
+		return retval;
+	}
+
+	elf_ppnt = elf_phdata;
+
+	elf_bss = 0;
+	elf_brk = 0;
+
+	elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+
+	if (elf_exec_fileno < 0) {
+		kfree (elf_phdata);
+		return elf_exec_fileno;
+	}
+
+	file = current->files->fd[elf_exec_fileno];
+
+	elf_stack = ~0UL;
+	elf_interpreter = NULL;
+	start_code = ~0UL;
+	end_code = 0;
+	end_data = 0;
+
+	for(i=0;i < elf_ex.e_phnum; i++){
+		if (elf_ppnt->p_type == PT_INTERP) {
+		  	if ( elf_interpreter != NULL )
+			{
+				kfree (elf_phdata);
+				kfree(elf_interpreter);
+				sys_close(elf_exec_fileno);
+				return -EINVAL;
+			}
+
+			/* This is the program interpreter used for
+			 * shared libraries - for now assume that this
+			 * is an a.out format binary
+			 */
+
+			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
+							   GFP_KERNEL);
+			if (elf_interpreter == NULL) {
+				kfree (elf_phdata);
+				sys_close(elf_exec_fileno);
+				return -ENOMEM;
+			}
+
+			retval = read_exec(bprm->inode,elf_ppnt->p_offset,
+					   elf_interpreter,
+					   elf_ppnt->p_filesz, 1);
+			/* If the program interpreter is one of these two,
+			   then assume an iBCS2 image. Otherwise assume
+			   a native linux image. */
+			if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
+			    strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
+			  ibcs2_interpreter = 1;
+#if 0
+			printk("Using ELF interpreter %s\n", elf_interpreter);
+#endif
+			if (retval >= 0) {
+				old_fs = get_fs(); /* This could probably be optimized */
+				set_fs(get_ds());
+				retval = open_namei(elf_interpreter, 0, 0,
+						    &interpreter_inode, NULL);
+				set_fs(old_fs);
+			}
+
+			if (retval >= 0)
+				retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
+
+			if (retval >= 0) {
+				interp_ex = *((struct exec *) bprm->buf);		/* exec-header */
+				interp_elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
+
+			}
+			if (retval < 0) {
+				kfree (elf_phdata);
+				kfree(elf_interpreter);
+				sys_close(elf_exec_fileno);
+				return retval;
+			}
+		}
+		elf_ppnt++;
+	}
+
+	/* Some simple consistency checks for the interpreter */
+	if (elf_interpreter){
+		interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+
+		/* Now figure out which format our binary is */
+		if ((N_MAGIC(interp_ex) != OMAGIC) &&
+		    (N_MAGIC(interp_ex) != ZMAGIC) &&
+		    (N_MAGIC(interp_ex) != QMAGIC))
+		  interpreter_type = INTERPRETER_ELF;
+
+		if (interp_elf_ex.e_ident[0] != 0x7f ||
+		    strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
+		  interpreter_type &= ~INTERPRETER_ELF;
+
+		if (!interpreter_type)
+		  {
+		    kfree(elf_interpreter);
+		    kfree(elf_phdata);
+		    sys_close(elf_exec_fileno);
+		    return -ELIBBAD;
+		  }
+	}
+
+	/* OK, we are done with that, now set up the arg stuff,
+	   and then start this sucker up */
+
+	if (!bprm->sh_bang) {
+		char * passed_p;
+
+		if (interpreter_type == INTERPRETER_AOUT) {
+		  sprintf(passed_fileno, "%d", elf_exec_fileno);
+		  passed_p = passed_fileno;
+
+		  if (elf_interpreter) {
+		    bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
+		    bprm->argc++;
+		  }
+		}
+		if (!bprm->p) {
+			if (elf_interpreter) {
+			      kfree(elf_interpreter);
+			}
+			kfree (elf_phdata);
+			sys_close(elf_exec_fileno);
+			return -E2BIG;
+		}
+	}
+
+	/* OK, This is the point of no return */
+	flush_old_exec(bprm);
+
+	current->mm->end_data = 0;
+	current->mm->end_code = 0;
+	current->mm->start_mmap = ELF_START_MMAP;
+	current->mm->mmap = NULL;
+	elf_entry = (unsigned long) elf_ex.e_entry;
+
+	/* Do this so that we can load the interpreter, if need be.  We will
+	   change some of these later */
+	current->mm->rss = 0;
+	bprm->p = setup_arg_pages(bprm->p, bprm);
+	current->mm->start_stack = bprm->p;
+
+	/* Now we do a little grungy work by mmaping the ELF image into
+	   the correct location in memory.  At this point, we assume that
+	   the image should be loaded at fixed address, not at a variable
+	   address. */
+
+	old_fs = get_fs();
+	set_fs(get_ds());
+	for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
+		if (elf_ppnt->p_type == PT_LOAD) {
+			int elf_prot = 0;
+			if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
+			if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+			if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+
+			error = do_mmap(file,
+					ELF_PAGESTART(elf_ppnt->p_vaddr),
+					(elf_ppnt->p_filesz +
+					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
+					elf_prot,
+					(MAP_FIXED | MAP_PRIVATE |
+					 MAP_DENYWRITE | MAP_EXECUTABLE),
+					(elf_ppnt->p_offset -
+					 ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
+
+#ifdef LOW_ELF_STACK
+			if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
+				elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
+#endif
+
+			if (!load_addr_set) {
+			  load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
+			  load_addr_set = 1;
+			}
+			k = elf_ppnt->p_vaddr;
+			if (k < start_code) start_code = k;
+			k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+			if (k > elf_bss) elf_bss = k;
+#if 1
+			if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
+#else
+			if ( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
+#endif
+				end_code = k;
+			if (end_data < k) end_data = k;
+			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+			if (k > elf_brk) elf_brk = k;
+		}
+	}
+	set_fs(old_fs);
+
+	if (elf_interpreter) {
+		if (interpreter_type & 1)
+			elf_entry = load_aout32_interp(&interp_ex,
+						       interpreter_inode);
+		else if (interpreter_type & 2)
+			elf_entry = load_elf32_interp(&interp_elf_ex,
+						      interpreter_inode,
+						      &interp_load_addr);
+
+		iput(interpreter_inode);
+		kfree(elf_interpreter);
+
+		if (elf_entry == ~0UL) {
+			printk("Unable to load interpreter\n");
+			kfree(elf_phdata);
+			send_sig(SIGSEGV, current, 0);
+			return 0;
+		}
+	}
+
+	kfree(elf_phdata);
+
+	if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
+	current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
+
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_DEC_USE_COUNT(current->exec_domain->module);
+	if (current->binfmt && current->binfmt->module)
+		__MOD_DEC_USE_COUNT(current->binfmt->module);
+	current->exec_domain = lookup_exec_domain(current->personality);
+	current->binfmt = &elf32_format;
+	if (current->exec_domain && current->exec_domain->module)
+		__MOD_INC_USE_COUNT(current->exec_domain->module);
+	if (current->binfmt && current->binfmt->module)
+		__MOD_INC_USE_COUNT(current->binfmt->module);
+
+#ifndef VM_STACK_FLAGS
+	current->executable = bprm->inode;
+	bprm->inode->i_count++;
+#endif
+#ifdef LOW_ELF_STACK
+	current->start_stack = bprm->p = elf_stack - 4;
+#endif
+	current->suid = current->euid = current->fsuid = bprm->e_uid;
+	current->sgid = current->egid = current->fsgid = bprm->e_gid;
+	current->flags &= ~PF_FORKNOEXEC;
+	bprm->p = (unsigned long)
+	  create_elf32_tables((char *)bprm->p,
+			      bprm->argc,
+			      bprm->envc,
+			      (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
+			      load_addr,
+			      interp_load_addr,
+			      (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+	if (interpreter_type == INTERPRETER_AOUT)
+	  current->mm->arg_start += strlen(passed_fileno) + 1;
+	current->mm->start_brk = current->mm->brk = elf_brk;
+	current->mm->end_code = end_code;
+	current->mm->start_code = start_code;
+	current->mm->end_data = end_data;
+	current->mm->start_stack = bprm->p;
+
+	/* Calling set_brk effectively mmaps the pages that we need for the bss and break
+	   sections */
+	set_brk(elf_bss, elf_brk);
+
+	padzero(elf_bss);
+
+#if 0
+	printk("(start_brk) %x\n" , current->mm->start_brk);
+	printk("(end_code) %x\n" , current->mm->end_code);
+	printk("(start_code) %x\n" , current->mm->start_code);
+	printk("(end_data) %x\n" , current->mm->end_data);
+	printk("(start_stack) %x\n" , current->mm->start_stack);
+	printk("(brk) %x\n" , current->mm->brk);
+#endif
+
+	if ( current->personality == PER_SVR4 )
+	{
+		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
+		   and some applications "depend" upon this behavior.
+		   Since we do not have the power to recompile these, we
+		   emulate the SVr4 behavior.  Sigh.  */
+		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+				MAP_FIXED | MAP_PRIVATE, 0);
+	}
+
+#ifdef ELF_PLAT_INIT
+	/*
+	 * The ABI may specify that certain registers be set up in special
+	 * ways (on i386 %edx is the address of a DT_FINI function, for
+	 * example.  This macro performs whatever initialization to
+	 * the regs structure is required.
+	 */
+	ELF_PLAT_INIT(regs);
+#endif
+
+
+	start_thread32(regs, elf_entry, bprm->p);
+	if (current->flags & PF_PTRACED)
+		send_sig(SIGTRAP, current, 0);
+	return 0;
+}
+
+static int
+load_elf32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+	int retval;
+
+	MOD_INC_USE_COUNT;
+	retval = do_load_elf32_binary(bprm, regs);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+/* This is really simpleminded and specialized - we are loading an
+   a.out library that is given an ELF header. */
+
+static inline int
+do_load_elf32_library(int fd){
+	struct file * file;
+	struct elfhdr elf_ex;
+	struct elf_phdr *elf_phdata  =  NULL;
+	struct  inode * inode;
+	unsigned long len;
+	int elf_bss;
+	int retval;
+	unsigned long bss;
+	int error;
+	int i,j, k;
+
+	len = 0;
+	file = current->files->fd[fd];
+	inode = file->f_inode;
+	elf_bss = 0;
+
+	if (!file || !file->f_op)
+		return -EACCES;
+
+	/* seek to the beginning of the file */
+	if (file->f_op->llseek) {
+		if ((error = file->f_op->llseek(inode, file, 0, 0)) != 0)
+			return -ENOEXEC;
+	} else
+		file->f_pos = 0;
+
+	set_fs(KERNEL_DS);
+	error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex));
+	set_fs(USER_DS);
+	if (error != sizeof(elf_ex))
+		return -ENOEXEC;
+
+	if (elf_ex.e_ident[0] != 0x7f ||
+	    strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+		return -ENOEXEC;
+
+	/* First of all, some simple consistency checks */
+	if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+	   !elf_check_arch(elf_ex.e_machine) ||
+	   (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+		return -ENOEXEC;
+
+	/* Now read in all of the header information */
+
+	if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+		return -ENOEXEC;
+
+	elf_phdata =  (struct elf_phdr *)
+		kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+	if (elf_phdata == NULL)
+		return -ENOMEM;
+
+	retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+			   sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
+
+	j = 0;
+	for(i=0; i<elf_ex.e_phnum; i++)
+		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
+
+	if (j != 1)  {
+		kfree(elf_phdata);
+		return -ENOEXEC;
+	}
+
+	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+
+	/* Now use mmap to map the library into memory. */
+	error = do_mmap(file,
+			ELF_PAGESTART(elf_phdata->p_vaddr),
+			(elf_phdata->p_filesz +
+			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
+			PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+			(elf_phdata->p_offset -
+			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
+
+	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
+	if (k > elf_bss) elf_bss = k;
+
+	if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) {
+		kfree(elf_phdata);
+		return error;
+	}
+
+	padzero(elf_bss);
+
+	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1);
+	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+	if (bss > len)
+	  do_mmap(NULL, len, bss-len,
+		  PROT_READ|PROT_WRITE|PROT_EXEC,
+		  MAP_FIXED|MAP_PRIVATE, 0);
+	kfree(elf_phdata);
+	return 0;
+}
+
+static int load_elf32_library(int fd)
+{
+	int retval;
+
+	MOD_INC_USE_COUNT;
+	retval = do_load_elf32_library(fd);
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+/*
+ * Note that some platforms still use traditional core dumps and not
+ * the ELF core dump.  Each platform can select it as appropriate.
+ */
+#ifdef USE_ELF_CORE_DUMP
+
+/*
+ * ELF core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ */
+/*
+ * These are the only things you should do on a core-file: use only these
+ * functions to write out all the necessary info.
+ */
+static int dump_write(struct file *file, const void *addr, int nr)
+{
+	return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+}
+
+static int dump_seek(struct file *file, off_t off)
+{
+	if (file->f_op->llseek) {
+		if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
+			return 0;
+	} else
+		file->f_pos = off;
+	return 1;
+}
+
+/*
+ * Decide whether a segment is worth dumping; default is yes to be
+ * sure (missing info is worse than too much; etc).
+ * Personally I'd include everything, and use the coredump limit...
+ *
+ * I think we should skip something. But I am not sure how. H.J.
+ */
+static inline int maydump(struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
+		return 0;
+#if 1
+	if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
+		return 1;
+	if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
+		return 0;
+#endif
+	return 1;
+}
+
+#define roundup(x, y)  ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory */
+struct memelfnote
+{
+	const char *name;
+	int type;
+	unsigned int datasz;
+	void *data;
+};
+
+static int notesize(struct memelfnote *en)
+{
+	int sz;
+
+	sz = sizeof(struct elf_note);
+	sz += roundup(strlen(en->name), 4);
+	sz += roundup(en->datasz, 4);
+
+	return sz;
+}
+
+/* #define DEBUG */
+
+#define DUMP_WRITE(addr, nr)	\
+	do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
+#define DUMP_SEEK(off)	\
+	do { if (!dump_seek(file, (off))) return 0; } while(0)
+
+static int writenote(struct memelfnote *men, struct file *file)
+{
+	struct elf_note en;
+
+	en.n_namesz = strlen(men->name);
+	en.n_descsz = men->datasz;
+	en.n_type = men->type;
+
+	DUMP_WRITE(&en, sizeof(en));
+	DUMP_WRITE(men->name, en.n_namesz);
+	/* XXX - cast from long long to long to avoid need for libgcc.a */
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+	DUMP_WRITE(men->data, men->datasz);
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+
+	return 1;
+}
+#undef DUMP_WRITE
+#undef DUMP_SEEK
+
+#define DUMP_WRITE(addr, nr)	\
+	if (!dump_write(&file, (addr), (nr))) \
+		goto close_coredump;
+#define DUMP_SEEK(off)	\
+	if (!dump_seek(&file, (off))) \
+		goto close_coredump;
+/*
+ * Actual dumper
+ *
+ * This is a two-pass process; first we find the offsets of the bits,
+ * and then they are actually written out.  If we run out of core limit
+ * we just truncate.
+ */
+static int elf32_core_dump(long signr, struct pt_regs * regs)
+{
+	int has_dumped = 0;
+	struct file file;
+	struct inode *inode;
+	unsigned short fs;
+	char corefile[6+sizeof(current->comm)];
+	int segs;
+	int i;
+	size_t size;
+	struct vm_area_struct *vma;
+	struct elfhdr elf;
+	off_t offset = 0, dataoff;
+	int limit = current->rlim[RLIMIT_CORE].rlim_cur;
+	int numnote = 4;
+	struct memelfnote notes[4];
+	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
+	elf_fpregset_t fpu;		/* NT_PRFPREG */
+	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
+
+	if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1)
+		return 0;
+	current->dumpable = 0;
+
+#ifndef CONFIG_BINFMT_ELF32
+	MOD_INC_USE_COUNT;
+#endif
+
+	/* Count what's needed to dump, up to the limit of coredump size */
+	segs = 0;
+	size = 0;
+	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+		if (maydump(vma))
+		{
+			int sz = vma->vm_end-vma->vm_start;
+
+			if (size+sz >= limit)
+				break;
+			else
+				size += sz;
+		}
+
+		segs++;
+	}
+#ifdef DEBUG
+	printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
+#endif
+
+	/* Set up header */
+	memcpy(elf.e_ident, ELFMAG, SELFMAG);
+	elf.e_ident[EI_CLASS] = ELF_CLASS;
+	elf.e_ident[EI_DATA] = ELF_DATA;
+	elf.e_ident[EI_VERSION] = EV_CURRENT;
+	memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+
+	elf.e_type = ET_CORE;
+	elf.e_machine = ELF_ARCH;
+	elf.e_version = EV_CURRENT;
+	elf.e_entry = 0;
+	elf.e_phoff = sizeof(elf);
+	elf.e_shoff = 0;
+	elf.e_flags = 0;
+	elf.e_ehsize = sizeof(elf);
+	elf.e_phentsize = sizeof(struct elf_phdr);
+	elf.e_phnum = segs+1;		/* Include notes */
+	elf.e_shentsize = 0;
+	elf.e_shnum = 0;
+	elf.e_shstrndx = 0;
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	memcpy(corefile,"core.",5);
+#if 0
+	memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+	corefile[4] = '\0';
+#endif
+	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+		inode = NULL;
+		goto end_coredump;
+	}
+	if (!S_ISREG(inode->i_mode))
+		goto end_coredump;
+	if (!inode->i_op || !inode->i_op->default_file_ops)
+		goto end_coredump;
+	file.f_mode = 3;
+	file.f_flags = 0;
+	file.f_count = 1;
+	file.f_inode = inode;
+	file.f_pos = 0;
+	file.f_reada = 0;
+	file.f_op = inode->i_op->default_file_ops;
+	if (file.f_op->open)
+		if (file.f_op->open(inode,&file))
+			goto end_coredump;
+	if (!file.f_op->write)
+		goto close_coredump;
+	has_dumped = 1;
+	current->flags |= PF_DUMPCORE;
+
+	DUMP_WRITE(&elf, sizeof(elf));
+	offset += sizeof(elf);				/* Elf header */
+	offset += (segs+1) * sizeof(struct elf_phdr);	/* Program headers */
+
+	/*
+	 * Set up the notes in similar form to SVR4 core dumps made
+	 * with info from their /proc.
+	 */
+	memset(&psinfo, 0, sizeof(psinfo));
+	memset(&prstatus, 0, sizeof(prstatus));
+
+	notes[0].name = "CORE";
+	notes[0].type = NT_PRSTATUS;
+	notes[0].datasz = sizeof(prstatus);
+	notes[0].data = &prstatus;
+	prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
+	prstatus.pr_sigpend = current->signal;
+	prstatus.pr_sighold = current->blocked;
+	psinfo.pr_pid = prstatus.pr_pid = current->pid;
+	psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
+	psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
+	psinfo.pr_sid = prstatus.pr_sid = current->session;
+	prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
+	prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
+	prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
+	prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
+	prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
+	prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
+	prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
+	prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+
+	/*
+	 * This transfers the registers from regs into the standard
+	 * coredump arrangement, whatever that is.
+	 */
+#ifdef ELF_CORE_COPY_REGS
+	ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
+#else
+	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
+	{
+		printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n",
+			sizeof(elf_gregset_t), sizeof(struct pt_regs));
+	}
+	else
+		*(struct pt_regs *)&prstatus.pr_reg = *regs;
+#endif
+
+	notes[1].name = "CORE";
+	notes[1].type = NT_PRPSINFO;
+	notes[1].datasz = sizeof(psinfo);
+	notes[1].data = &psinfo;
+	psinfo.pr_state = current->state;
+	psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
+	psinfo.pr_zomb = psinfo.pr_sname == 'Z';
+	psinfo.pr_nice = current->priority-15;
+	psinfo.pr_flag = current->flags;
+	psinfo.pr_uid = current->uid;
+	psinfo.pr_gid = current->gid;
+	{
+		int i, len;
+
+		set_fs(fs);
+
+		len = current->mm->arg_end - current->mm->arg_start;
+		len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+		copy_from_user(&psinfo.pr_psargs,
+			      (const char *)current->mm->arg_start, len);
+		for(i = 0; i < len; i++)
+			if (psinfo.pr_psargs[i] == 0)
+				psinfo.pr_psargs[i] = ' ';
+		psinfo.pr_psargs[len] = 0;
+
+		set_fs(KERNEL_DS);
+	}
+	strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
+
+	notes[2].name = "CORE";
+	notes[2].type = NT_TASKSTRUCT;
+	notes[2].datasz = sizeof(*current);
+	notes[2].data = current;
+
+	/* Try to dump the fpu. */
+	prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
+	if (!prstatus.pr_fpvalid)
+	{
+		numnote--;
+	}
+	else
+	{
+		notes[3].name = "CORE";
+		notes[3].type = NT_PRFPREG;
+		notes[3].datasz = sizeof(fpu);
+		notes[3].data = &fpu;
+	}
+	
+	/* Write notes phdr entry */
+	{
+		struct elf_phdr phdr;
+		int sz = 0;
+
+		for(i = 0; i < numnote; i++)
+			sz += notesize(&notes[i]);
+
+		phdr.p_type = PT_NOTE;
+		phdr.p_offset = offset;
+		phdr.p_vaddr = 0;
+		phdr.p_paddr = 0;
+		phdr.p_filesz = sz;
+		phdr.p_memsz = 0;
+		phdr.p_flags = 0;
+		phdr.p_align = 0;
+
+		offset += phdr.p_filesz;
+		DUMP_WRITE(&phdr, sizeof(phdr));
+	}
+
+	/* Page-align dumped data */
+	dataoff = offset = roundup(offset, PAGE_SIZE);
+
+	/* Write program headers for segments dump */
+	for(vma = current->mm->mmap, i = 0;
+		i < segs && vma != NULL; vma = vma->vm_next) {
+		struct elf_phdr phdr;
+		size_t sz;
+
+		i++;
+
+		sz = vma->vm_end - vma->vm_start;
+
+		phdr.p_type = PT_LOAD;
+		phdr.p_offset = offset;
+		phdr.p_vaddr = vma->vm_start;
+		phdr.p_paddr = 0;
+		phdr.p_filesz = maydump(vma) ? sz : 0;
+		phdr.p_memsz = sz;
+		offset += phdr.p_filesz;
+		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
+		if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
+		if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+		phdr.p_align = PAGE_SIZE;
+
+		DUMP_WRITE(&phdr, sizeof(phdr));
+	}
+
+	for(i = 0; i < numnote; i++)
+		if (!writenote(&notes[i], &file))
+			goto close_coredump;
+
+	set_fs(fs);
+
+	DUMP_SEEK(dataoff);
+
+	for(i = 0, vma = current->mm->mmap;
+	    i < segs && vma != NULL;
+	    vma = vma->vm_next) {
+		unsigned long addr = vma->vm_start;
+		unsigned long len = vma->vm_end - vma->vm_start;
+
+		i++;
+		if (!maydump(vma))
+			continue;
+#ifdef DEBUG
+		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
+#endif
+		DUMP_WRITE((void *)addr, len);
+	}
+
+	if ((off_t) file.f_pos != offset) {
+		/* Sanity check */
+		printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
+		       (off_t) file.f_pos, offset);
+	}
+
+ close_coredump:
+	if (file.f_op->release)
+		file.f_op->release(inode,&file);
+
+ end_coredump:
+	set_fs(fs);
+	iput(inode);
+#ifndef CONFIG_BINFMT_ELF32
+	MOD_DEC_USE_COUNT;
+#endif
+	return has_dumped;
+}
+#endif		/* USE_ELF_CORE_DUMP */
+
+int init_elf32_binfmt(void)
+{
+	return register_binfmt(&elf32_format);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	/* Install the COFF, ELF and XOUT loaders.
+	 * N.B. We *rely* on the table being the right size with the
+	 * right number of free slots...
+	 */
+	return init_elf32_binfmt();
+}
+
+
+void cleanup_module( void)
+{
+	/* Remove the COFF and ELF loaders. */
+	unregister_binfmt(&elf32_format);
+}
+#endif
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.1.33/linux/arch/sparc64/kernel/sys_sparc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/sys_sparc.c	Fri Apr 11 10:47:36 1997
@@ -0,0 +1,270 @@
+/* $Id: sys_sparc.c,v 1.1 1997/04/09 08:25:18 jj Exp $
+ * linux/arch/sparc64/kernel/sys_sparc.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/sparc
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+/* XXX Make this per-binary type, this way we can detect the type of
+ * XXX a binary.  Every Sparc executable calls this very early on.
+ */
+asmlinkage unsigned long sys_getpagesize(void)
+{
+	return PAGE_SIZE;
+}
+
+extern asmlinkage unsigned long sys_brk(unsigned long brk);
+
+asmlinkage unsigned long sparc_brk(unsigned long brk)
+{
+	unsigned long ret;
+
+	lock_kernel();
+	if(brk >= 0x80000000000ULL) {	/* VM hole */
+		ret = current->mm->brk;
+		goto out;
+	}
+	ret = sys_brk(brk);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sparc_pipe(struct pt_regs *regs)
+{
+	int fd[2];
+	int error;
+
+	lock_kernel();
+	error = do_pipe(fd);
+	if (error)
+		goto out;
+	regs->u_regs[UREG_I1] = fd[1];
+	error = fd[0];
+out:
+	unlock_kernel();
+	return error;
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+
+asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long third, void *ptr, long fifth)
+{
+	int err;
+
+	lock_kernel();
+	/* No need for backward compatibility. We can start fresh... */
+
+	if (call <= SEMCTL)
+		switch (call) {
+		case SEMOP:
+			err = sys_semop (first, (struct sembuf *)ptr, second);
+			goto out;
+		case SEMGET:
+			err = sys_semget (first, second, (int)third);
+			goto out;
+		case SEMCTL: {
+			union semun fourth;
+			err = -EINVAL;
+			if (!ptr)
+				goto out;
+			err = -EFAULT;
+			if(get_user(fourth.__pad, (void **)ptr))
+				goto out;
+			err = sys_semctl (first, second, (int)third, fourth);
+			goto out;
+			}
+		default:
+			err = -EINVAL;
+			goto out;
+		}
+	if (call <= MSGCTL) 
+		switch (call) {
+		case MSGSND:
+			err = sys_msgsnd (first, (struct msgbuf *) ptr, 
+					  second, (int)third);
+			goto out;
+		case MSGRCV:
+			err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, (int)third);
+			goto out;
+		case MSGGET:
+			err = sys_msgget ((key_t) first, second);
+			goto out;
+		case MSGCTL:
+			err = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			goto out;
+		default:
+			err = -EINVAL;
+			goto out;
+		}
+	if (call <= SHMCTL) 
+		switch (call) {
+		case SHMAT:
+			err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+			goto out;
+		case SHMDT:
+			err = sys_shmdt ((char *)ptr);
+			goto out;
+		case SHMGET:
+			err = sys_shmget (first, second, (int)third);
+			goto out;
+		case SHMCTL:
+			err = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			goto out;
+		default:
+			err = -EINVAL;
+			goto out;
+		}
+	else
+		err = -EINVAL;
+out:
+	unlock_kernel();
+	return err;
+}
+
+extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
+
+/* Linux version of mmap */
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags, unsigned long fd,
+	unsigned long off)
+{
+	struct file * file = NULL;
+	unsigned long retval = -EBADF;
+
+	lock_kernel();
+	if (!(flags & MAP_ANONYMOUS)) {
+		if (fd >= NR_OPEN || !(file = current->files->fd[fd])){
+			goto out;
+	    }
+	}
+	retval = -ENOMEM;
+	if(!(flags & MAP_FIXED) && !addr) {
+		addr = get_unmapped_area(addr, len);
+		if(!addr){
+			goto out;
+		}
+	}
+
+	/* See asm-sparc64/uaccess.h */
+	retval = -EINVAL;
+	if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
+		goto out;
+
+	if(addr >= 0x80000000000ULL) {
+		retval = current->mm->brk;
+		goto out;
+	}
+
+	retval = do_mmap(file, addr, len, prot, flags, off);
+out:
+	unlock_kernel();
+	return retval;
+}
+
+/* we come to here via sys_nis_syscall so it can setup the regs argument */
+asmlinkage unsigned long
+c_sys_nis_syscall (struct pt_regs *regs)
+{
+	lock_kernel();
+	printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
+	show_regs (regs);
+	unlock_kernel();
+	return -ENOSYS;
+}
+
+/* #define DEBUG_SPARC_BREAKPOINT */
+
+asmlinkage void
+sparc_breakpoint (struct pt_regs *regs)
+{
+	lock_kernel();
+#ifdef DEBUG_SPARC_BREAKPOINT
+        printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
+#endif
+	force_sig(SIGTRAP, current);
+#ifdef DEBUG_SPARC_BREAKPOINT
+	printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
+#endif
+	unlock_kernel();
+}
+
+extern void check_pending(int signum);
+
+asmlinkage int
+sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
+{
+	struct sigaction new_sa, *p;
+	int err = -EINVAL;
+
+	lock_kernel();
+	if(signum < 0) {
+		current->tss.new_signal = 1;
+		signum = -signum;
+	}
+
+	if (signum<1 || signum>32)
+		goto out;
+	p = signum - 1 + current->sig->action;
+	if (action) {
+		err = -EINVAL;
+		if (signum==SIGKILL || signum==SIGSTOP)
+			goto out;
+		err = -EFAULT;
+		if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
+			goto out;	
+		if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
+			err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+			if (err)
+				goto out;
+		}
+	}
+
+	if (oldaction) {
+		err = -EFAULT;
+		if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
+			goto out;	
+	}
+
+	if (action) {
+		*p = new_sa;
+		check_pending(signum);
+	}
+
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
+}
+
+/* only AP+ systems have sys_aplib */
+asmlinkage int sys_aplib(void)
+{
+	return -ENOSYS;
+}
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.1.33/linux/arch/sparc64/kernel/sys_sparc32.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Fri Apr 11 10:47:36 1997
@@ -0,0 +1,831 @@
+/* $Id: sys_sparc32.c,v 1.3 1997/04/09 08:25:17 jj Exp $
+ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment.
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h> 
+#include <linux/signal.h>
+#include <linux/utime.h>
+#include <linux/resource.h>
+#include <linux/sched.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+
+#include <asm/types.h>
+#include <asm/poll.h>
+#include <asm/ipc.h>
+#include <asm/uaccess.h>
+
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will
+ * produce warnings */
+#define A(x) ((unsigned long)x)
+ 
+/* FIXME: All struct * etc. stuff should be examined and proper structure conversions
+ * added ASAP -JJ */
+
+extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+extern asmlinkage unsigned long sys_brk(unsigned long brk);
+extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off);
+extern asmlinkage int sys_bdflush(int func, long data);
+extern asmlinkage int sys_uselib(const char * library);
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev);
+extern asmlinkage int sys_mkdir(const char * pathname, int mode);
+extern asmlinkage int sys_rmdir(const char * pathname);
+extern asmlinkage int sys_unlink(const char * pathname);
+extern asmlinkage int sys_symlink(const char * oldname, const char * newname);
+extern asmlinkage int sys_link(const char * oldname, const char * newname);
+extern asmlinkage int sys_rename(const char * oldname, const char * newname);
+extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
+extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
+extern asmlinkage int sys_truncate(const char * path, unsigned long length);
+extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
+extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
+extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes);
+extern asmlinkage int sys_access(const char * filename, int mode);
+extern asmlinkage int sys_chdir(const char * filename);
+extern asmlinkage int sys_chroot(const char * filename);
+extern asmlinkage int sys_chmod(const char * filename, mode_t mode);
+extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group);
+extern asmlinkage int sys_open(const char * filename,int flags,int mode);
+extern asmlinkage int sys_creat(const char * pathname, int mode);
+extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
+extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int origin);
+extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count);
+extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
+extern asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count);
+extern asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count);
+extern asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count);
+extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
+extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
+extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
+extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
+extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
+extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz);
+extern asmlinkage int sys_sysfs(int option, ...);
+extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf);
+extern asmlinkage int sys_umount(char * name);
+extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void *data);
+extern asmlinkage int sys_syslog(int type, char * bug, int count);
+extern asmlinkage int sys_personality(unsigned long personality);
+extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
+extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options);
+extern asmlinkage int sys_sysinfo(struct sysinfo *info);
+extern asmlinkage int sys_getitimer(int which, struct itimerval *value);
+extern asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue);
+extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param);
+extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param);
+extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param);
+extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset);
+extern asmlinkage int sys_sigpending(sigset_t *set);
+extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler);
+extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg);
+extern asmlinkage int sys_acct(const char *name);
+extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+extern asmlinkage long sys_times(struct tms * tbuf);
+extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
+extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+extern asmlinkage int sys_uname(struct old_utsname * name);
+extern asmlinkage int sys_olduname(struct oldold_utsname * name);
+extern asmlinkage int sys_sethostname(char *name, int len);
+extern asmlinkage int sys_gethostname(char *name, int len);
+extern asmlinkage int sys_setdomainname(char *name, int len);
+extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
+extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
+extern asmlinkage int sys_time(int * tloc);
+extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
+extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern asmlinkage int sys_adjtimex(struct timex *txc_p);
+extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags);
+extern asmlinkage int sys_mlock(unsigned long start, size_t len);
+extern asmlinkage int sys_munlock(unsigned long start, size_t len);
+extern asmlinkage int sys_munmap(unsigned long addr, size_t len);
+extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot);
+extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags);
+extern asmlinkage int sys_swapoff(const char * specialfile);
+extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags);
+extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
+extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags);
+extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len);
+extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
+extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len); 
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
+extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen);
+extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
+extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags);
+extern asmlinkage int sys_socketcall(int call, unsigned long *args);
+
+asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
+{
+	return sys_ioperm((unsigned long)from, (unsigned long)num, on);
+}
+
+/*
+ * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
+ *
+ * This is really horribly ugly.
+ */
+
+asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+{
+	int version, err;
+
+	lock_kernel();
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	if (call <= SEMCTL)
+		switch (call) {
+		case SEMOP:
+			/* struct sembuf is the same on 32 and 64bit :)) */
+			err = sys_semop (first, (struct sembuf *)A(ptr), second);
+			goto out;
+		case SEMGET:
+			err = sys_semget (first, second, third);
+			goto out;
+		case SEMCTL: {
+			/* XXX union semun32 to union semun64 and back conversion */
+			union semun fourth;
+			err = -EINVAL;
+			if (!ptr)
+				goto out;
+			err = -EFAULT;
+			if(get_user(fourth.__pad, (void **)A(ptr)))
+				goto out;
+			err = sys_semctl (first, second, third, fourth);
+			goto out;
+			}
+		default:
+			err = -EINVAL;
+			goto out;
+		}
+	if (call <= MSGCTL) 
+		switch (call) {
+		case MSGSND:
+			/* XXX struct msgbuf has a long first :(( */
+			err = sys_msgsnd (first, (struct msgbuf *) A(ptr), 
+					  second, third);
+			goto out;
+		case MSGRCV:
+			switch (version) {
+			case 0: {
+				struct ipc_kludge tmp;
+				err = -EINVAL;
+				if (!ptr)
+					goto out;
+				err = -EFAULT;
+				if(copy_from_user(&tmp,(struct ipc_kludge *) ptr, sizeof (tmp)))
+					goto out;
+				err = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+				goto out;
+				}
+			case 1: default:
+				err = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+				goto out;
+			}
+		case MSGGET:
+			err = sys_msgget ((key_t) first, second);
+			goto out;
+		case MSGCTL:
+			err = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+			goto out;
+		default:
+			err = -EINVAL;
+			goto out;
+		}
+	if (call <= SHMCTL) 
+		switch (call) {
+		case SHMAT:
+			switch (version) {
+			case 0: default: {
+				ulong raddr;
+				err = sys_shmat (first, (char *) ptr, second, &raddr);
+				if (err)
+					goto out;
+				err = -EFAULT;
+				if(put_user (raddr, (ulong *) third))
+					goto out;
+				err = 0;
+				goto out;
+				}
+			case 1:	/* iBCS2 emulator entry point */
+				err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
+				goto out;
+			}
+		case SHMDT: 
+			err = sys_shmdt ((char *)ptr);
+			goto out;
+		case SHMGET:
+			err = sys_shmget (first, second, third);
+			goto out;
+		case SHMCTL:
+			err = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+			goto out;
+		default:
+			err = -EINVAL;
+			goto out;
+		}
+	else
+		err = -EINVAL;
+out:
+	unlock_kernel();
+	return err;
+}
+
+asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+{
+	return sys_mmap((unsigned long)addr, (unsigned long)len, (unsigned long)prot, (unsigned long)flags, 
+			(unsigned long)fd, (unsigned long)off);
+}
+
+asmlinkage int sys32_bdflush(int func, s32 data)
+{
+	return sys_bdflush(func, (long)data);
+}
+
+asmlinkage int sys32_uselib(u32 library)
+{
+	return sys_uselib((const char *)A(library));
+}
+
+asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	return sys_fcntl(fd, cmd, (unsigned long)arg);
+}
+
+asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	return sys_ioctl(fd, cmd, (unsigned long)arg);
+}
+
+asmlinkage int sys32_mknod(u32 filename, int mode, dev_t dev)
+{
+	return sys_mknod((const char *)A(filename), mode, dev);
+}
+
+asmlinkage int sys32_mkdir(u32 pathname, int mode)
+{
+	return sys_mkdir((const char *)A(pathname), mode);
+}
+
+asmlinkage int sys32_rmdir(u32 pathname)
+{
+	return sys_rmdir((const char *)A(pathname));
+}
+
+asmlinkage int sys32_unlink(u32 pathname)
+{
+	return sys_unlink((const char *)A(pathname));
+}
+
+asmlinkage int sys32_symlink(u32 oldname, u32 newname)
+{
+	return sys_symlink((const char *)A(oldname), (const char *)A(newname));
+}
+
+asmlinkage int sys32_link(u32 oldname, u32 newname)
+{
+	return sys_link((const char *)A(oldname), (const char *)A(newname));
+}
+
+asmlinkage int sys32_rename(u32 oldname, u32 newname)
+{
+	return sys_rename((const char *)A(oldname), (const char *)A(newname));
+}
+
+asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
+{
+	return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+}
+
+asmlinkage int sys32_statfs(u32 path, u32 buf)
+{
+	return sys_statfs((const char *)A(path), (struct statfs *)A(buf));
+}
+
+asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
+{
+	return sys_fstatfs(fd, (struct statfs *)A(buf));
+}
+
+asmlinkage int sys32_truncate(u32 path, u32 length)
+{
+	return sys_truncate((const char *)A(path), (unsigned long)length);
+}
+
+asmlinkage int sys32_ftruncate(unsigned int fd, u32 length)
+{
+	return sys_ftruncate(fd, (unsigned long)length);
+}
+
+asmlinkage int sys32_utime(u32 filename, u32 times)
+{
+	return sys_utime((char *)A(filename), (struct utimbuf *)A(times));
+}
+
+asmlinkage int sys32_utimes(u32 filename, u32 utimes)
+{
+	return sys_utimes((char *)A(filename), (struct timeval *)A(utimes));
+}
+
+asmlinkage int sys32_access(u32 filename, int mode)
+{
+	return sys_access((const char *)A(filename), mode);
+}
+
+asmlinkage int sys32_chdir(u32 filename)
+{
+	return sys_chdir((const char *)A(filename));
+}
+
+asmlinkage int sys32_chroot(u32 filename)
+{
+	return sys_chroot((const char *)A(filename));
+}
+
+asmlinkage int sys32_chmod(u32 filename, mode_t mode)
+{
+	return sys_chmod((const char *)A(filename), mode);
+}
+
+asmlinkage int sys32_chown(u32 filename, uid_t user, gid_t group)
+{
+	return sys_chown((const char *)A(filename), user, group);
+}
+
+asmlinkage int sys32_open(u32 filename, int flags, int mode)
+{
+	return sys_open((const char *)A(filename), flags, mode);
+}
+
+asmlinkage int sys32_creat(u32 pathname, int mode)
+{
+	return sys_creat((const char *)A(pathname), mode);
+}
+
+asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin)
+{
+	return sys_lseek(fd, (off_t)offset, origin);
+}
+
+asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, u32 offset_low, u32 result, unsigned int origin)
+{
+	return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, (loff_t *)A(result), origin);
+}
+
+asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count)
+{
+	return sys_read(fd, (char *)A(buf), (unsigned long)count);
+}
+
+asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count)
+{
+	return sys_write(fd, (const char *)A(buf), (unsigned long)count);
+}
+
+asmlinkage long sys32_readv(u32 fd, u32 vector, u32 count)
+{
+	return sys_readv((unsigned long)fd, (const struct iovec *)A(vector), (unsigned long)count);
+}
+
+asmlinkage long sys32_writev(u32 fd, u32 vector, u32 count)
+{
+	return sys_writev((unsigned long)fd, (const struct iovec *)A(vector), (unsigned long)count);
+}
+
+asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
+{
+	return sys_getdents(fd, (void *)A(dirent), count);
+}
+
+asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
+{
+	return sys_select(n, (fd_set *)A(inp), (fd_set *)A(outp), (fd_set *)A(exp), (struct timeval *)A(tvp));
+}
+
+asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout)
+{
+	return sys_poll((struct pollfd *)A(ufds), nfds, timeout);
+}
+
+asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
+{
+	return sys_newstat((char *)A(filename), (struct stat *)A(statbuf));
+}
+
+asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
+{
+	return sys_newlstat((char *)A(filename), (struct stat *)A(statbuf));
+}
+
+asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
+{
+	return sys_newfstat(fd, (struct stat *)A(statbuf));
+}
+
+asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz)
+{
+	return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz);
+}
+
+asmlinkage int sys32_sysfs(int option, ...)
+{
+        va_list args;
+	unsigned int x;
+	int ret;
+
+        va_start(args, option);
+        switch (option) {
+                case 1:
+			ret = sys_sysfs(option, (const char *)A(va_arg(args, u32)));
+			break;
+                case 2:
+			x = va_arg(args, unsigned int);
+			ret = sys_sysfs(option, x, (char *)A(va_arg(args, u32)));
+			break;
+                case 3:
+			ret = sys_sysfs(option);
+			break;
+	}
+        va_end(args);
+	return ret;
+}
+
+asmlinkage int sys32_ustat(dev_t dev, u32 ubuf)
+{
+	return sys_ustat(dev, (struct ustat *)A(ubuf));
+}
+
+asmlinkage int sys32_umount(u32 name)
+{
+	return sys_umount((char *)A(name));
+}
+
+asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data)
+{
+	return sys_mount((char *)A(dev_name), (char *)A(dir_name), (char *)A(type), 
+			 (unsigned long)new_flags, (void *)A(data));
+}
+
+asmlinkage int sys32_syslog(int type, u32 bug, int count)
+{
+	return sys_syslog(type, (char *)A(bug), count);
+}
+
+asmlinkage int sys32_personality(u32 personality)
+{
+	return sys_personality((unsigned long)personality);
+}
+
+asmlinkage int sys32_wait4(pid_t pid, u32 stat_addr, int options, u32 ru)
+{
+	return sys_wait4(pid, (unsigned int *)A(stat_addr), options, (struct rusage *)A(ru));
+}
+
+asmlinkage int sys32_waitpid(pid_t pid, u32 stat_addr, int options)
+{
+	return sys_waitpid(pid, (unsigned int *)A(stat_addr), options);
+}
+
+asmlinkage int sys32_sysinfo(u32 info)
+{
+	return sys_sysinfo((struct sysinfo *)A(info));
+}
+
+asmlinkage int sys32_getitimer(int which, u32 value)
+{
+	return sys_getitimer(which, (struct itimerval *)A(value));
+}
+
+asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue)
+{
+	return sys_setitimer(which, (struct itimerval *)A(value), (struct itimerval *)A(ovalue));
+}
+
+asmlinkage int sys32_sched_setscheduler(pid_t pid, int policy, u32 param)
+{
+	return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param));
+}
+
+asmlinkage int sys32_sched_setparam(pid_t pid, u32 param)
+{
+	return sys_sched_setparam(pid, (struct sched_param *)A(param));
+}
+
+asmlinkage int sys32_sched_getparam(pid_t pid, u32 param)
+{
+	return sys_sched_getparam(pid, (struct sched_param *)A(param));
+}
+
+asmlinkage int sys32_sched_rr_get_interval(pid_t pid, u32 interval)
+{
+	return sys_sched_rr_get_interval(pid, (struct timespec *)A(interval));
+}
+
+asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
+{
+	return sys_nanosleep((struct timespec *)A(rqtp), (struct timespec *)A(rmtp));
+}
+
+asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
+{
+	return sys_sigprocmask(how, (sigset_t *)A(set), (sigset_t *)A(oset));
+}
+
+asmlinkage int sys32_sigpending(u32 set)
+{
+	return sys_sigpending((sigset_t *)A(set));
+}
+
+asmlinkage unsigned long sys32_signal(int signum, u32 handler)
+{
+	return sys_signal(signum, (__sighandler_t)A(handler));
+}
+
+asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg)
+{
+	return sys_reboot(magic1, magic2, cmd, (void *)A(arg));
+}
+
+asmlinkage int sys32_acct(u32 name)
+{
+	return sys_acct((const char *)A(name));
+}
+
+asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
+{
+	return sys_getresuid((uid_t *)A(ruid), (uid_t *)A(euid), (uid_t *)A(suid));
+}
+
+asmlinkage long sys32_times(u32 tbuf)
+{
+	return sys_times((struct tms *)A(tbuf));
+}
+
+asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
+{
+	return sys_getgroups(gidsetsize, (gid_t *)A(grouplist));
+}
+
+asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
+{
+	return sys_setgroups(gidsetsize, (gid_t *)A(grouplist));
+}
+
+asmlinkage int sys32_newuname(u32 name)
+{
+	return sys_newuname((struct new_utsname *)A(name));
+}
+
+asmlinkage int sys32_uname(u32 name)
+{
+	return sys_uname((struct old_utsname *)A(name));
+}
+
+asmlinkage int sys32_olduname(u32 name)
+{
+	return sys_olduname((struct oldold_utsname *)A(name));
+}
+
+asmlinkage int sys32_sethostname(u32 name, int len)
+{
+	return sys_sethostname((char *)A(name), len);
+}
+
+asmlinkage int sys32_gethostname(u32 name, int len)
+{
+	return sys_gethostname((char *)A(name), len);
+}
+
+asmlinkage int sys32_setdomainname(u32 name, int len)
+{
+	return sys_setdomainname((char *)A(name), len);
+}
+
+asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
+{
+	return sys_getrlimit(resource, (struct rlimit *)A(rlim));
+}
+
+asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
+{
+	return sys_setrlimit(resource, (struct rlimit *)A(rlim));
+}
+
+asmlinkage int sys32_getrusage(int who, u32 ru)
+{
+	return sys_getrusage(who, (struct rusage *)A(ru));
+}
+
+asmlinkage int sys32_time(u32 tloc)
+{
+	return sys_time((int *)A(tloc));
+}
+
+asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
+{
+	return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
+}
+
+asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
+{
+	return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
+}
+
+asmlinkage int sys32_adjtimex(u32 txc_p)
+{
+	return sys_adjtimex((struct timex *)A(txc_p));
+}
+
+asmlinkage int sys32_msync(u32 start, u32 len, int flags)
+{
+	return sys_msync((unsigned long)start, (size_t)len, flags);
+}
+
+asmlinkage int sys32_mlock(u32 start, u32 len)
+{
+	return sys_mlock((unsigned long)start, (size_t)len);
+}
+
+asmlinkage int sys32_munlock(u32 start, u32 len)
+{
+	return sys_munlock((unsigned long)start, (size_t)len);
+}
+
+asmlinkage unsigned long sparc32_brk(u32 brk)
+{
+	return sys_brk((unsigned long)brk);
+}
+
+asmlinkage int sys32_munmap(u32 addr, u32 len)
+{
+	return sys_munmap((unsigned long)addr, (size_t)len);
+}
+
+asmlinkage int sys32_mprotect(u32 start, u32 len, u32 prot)
+{
+	return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot);
+}
+
+asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags)
+{
+	return sys_mremap((unsigned long)addr, (unsigned long)old_len, (unsigned long)new_len, (unsigned long)flags);
+}
+
+asmlinkage int sys32_swapoff(u32 specialfile)
+{
+	return sys_swapoff((const char *)A(specialfile));
+}
+
+asmlinkage int sys32_swapon(u32 specialfile, int swap_flags)
+{
+	return sys_swapon((const char *)A(specialfile), swap_flags);
+}
+
+asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen)
+{
+	return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen);
+}
+
+asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen)
+{
+	return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), (int *)A(upeer_addrlen));
+}
+
+asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen)
+{
+	return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen);
+}
+
+asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len)
+{
+	return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+}
+
+asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len)
+{
+	return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+}
+
+asmlinkage int sys32_send(int fd, u32 buff, u32 len, unsigned flags)
+{
+	return sys_send(fd, (void *)A(buff), (size_t)len, flags);
+}
+
+asmlinkage int sys32_sendto(int fd, u32 buff, u32 len, unsigned flags, u32 addr, int addr_len)
+{
+	return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, (struct sockaddr *)A(addr), addr_len);
+}
+
+asmlinkage int sys32_recv(int fd, u32 ubuf, u32 size, unsigned flags)
+{
+	return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags);
+}
+
+asmlinkage int sys32_recvfrom(int fd, u32 ubuf, u32 size, unsigned flags, u32 addr, u32 addr_len)
+{
+	return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, (struct sockaddr *)A(addr), (int *)A(addr_len));
+}
+ 
+asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
+{
+	return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen);
+}
+
+asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen)
+{
+	return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
+}
+
+asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
+{
+	return sys_sendmsg(fd, (struct msghdr *)A(msg), flags);
+}
+
+asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags)
+{
+	return sys_recvmsg(fd, (struct msghdr *)A(msg), flags);
+}
+
+asmlinkage int sys32_socketcall(int call, u32 args)
+{
+	return sys_socketcall(call, (unsigned long *)A(args));
+}
+
+extern void check_pending(int signum);
+
+asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction)
+{
+	struct sigaction32 new_sa, old_sa;
+	struct sigaction *p;
+	int err = -EINVAL;
+
+	lock_kernel();
+	if(signum < 0) {
+		current->tss.new_signal = 1;
+		signum = -signum;
+	}
+
+	if (signum<1 || signum>32)
+		goto out;
+	p = signum - 1 + current->sig->action;
+	if (action) {
+		err = -EINVAL;
+		if (signum==SIGKILL || signum==SIGSTOP)
+			goto out;
+		err = -EFAULT;
+		if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
+			goto out;
+		if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL && 
+		    ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
+			err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1);
+			if (err)
+				goto out;
+		}
+	}
+
+	if (oldaction) {
+		err = -EFAULT;
+		old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
+		old_sa.sa_mask = (sigset32_t)(p->sa_mask);
+		old_sa.sa_flags = (unsigned)(p->sa_flags);
+		old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
+		if (copy_to_user(A(oldaction), p, sizeof(struct sigaction32)))
+			goto out;	
+	}
+
+	if (action) {
+		p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
+		p->sa_mask = (sigset_t)(new_sa.sa_mask);
+		p->sa_flags = new_sa.sa_flags;
+		p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
+		check_pending(signum);
+	}
+
+	err = 0;
+out:
+	unlock_kernel();
+	return err;
+}
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.1.33/linux/arch/sparc64/kernel/systbls.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/kernel/systbls.S	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.2 1997/03/18 17:59:03 jj Exp $
+/* $Id: systbls.S,v 1.5 1997/04/09 08:25:16 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -16,63 +16,64 @@
 
 	.globl sys_call_table32
 sys_call_table32:
-/*0*/	.xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
-/*5*/	.xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/  .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/	.xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*0*/	.xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
+/*5*/	.xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
+/*10*/  .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
+/*15*/	.xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
 /*20*/	.xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/	.xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/	.xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
-	.xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
-/*40*/	.xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
-	.xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
-/*50*/	.xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
-	.xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/	.xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+/*25*/	.xword sys32_time, sys32_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/	.xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
+	.xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/	.xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
+	.xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
+/*50*/	.xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+	.xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys_execve
+/*60*/	.xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
 	.xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/	.xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
-	.xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
-/*80*/	.xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
-	.xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
-/*90*/	.xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+/*70*/	.xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+	.xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/	.xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+	.xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+/*90*/	.xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
 	.xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*100*/	.xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*110*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_nis_syscall
-/*120*/	.xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
-	.xword sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/	.xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
-	.xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/	.xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+	.xword sys_nis_syscall, sys_setreuid, sys_setregid, sys32_rename, sys32_truncate
+/*130*/	.xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+	.xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*150*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
-/*160*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
-	.xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+	.xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
+/*160*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
+	.xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+/*170*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
 	.xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_nis_syscall
-	.xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/	.xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
-	.xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
-/*200*/	.xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
-	.xword sys_nis_syscall, sys_socketcall, sys_syslog, sys_olduname, sys_nis_syscall
-/*210*/	.xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
-	.xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/	.xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
-	.xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/	.xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
-	.xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/	.xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/	.xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall
+/*180*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys_nis_syscall
+	.xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
+/*190*/	.xword sys_nis_syscall, sys32_personality, sys_prof, sys_break, sys_lock
+	.xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
+/*200*/	.xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old_readdir
+	.xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
+/*210*/	.xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
+	.xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*220*/	.xword sys_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid
+	.xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/	.xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+	.xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
+/*240*/	.xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+	.xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys_nanosleep
+/*250*/	.xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall
 	.xword sys_aplib, sys_nis_syscall
 
 	/* Now the 64-bit native Linux syscall table. */
 
-	.globl sys_call_table64
+	.globl sys_call_table64, sys_call_table
 sys_call_table64:
+sys_call_table:
 /*0*/	.xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
 /*5*/	.xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
 /*10*/  .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- v2.1.33/linux/arch/sparc64/kernel/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/time.c	Fri Apr 11 10:47:36 1997
@@ -0,0 +1,352 @@
+/* $Id: time.c,v 1.2 1997/04/10 03:02:35 davem Exp $
+ * time.c: UltraSparc timer and TOD clock support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Based largely on code which is:
+ *
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/init.h>
+
+#include <asm/oplib.h>
+#include <asm/mostek.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+struct mostek48t02 *mstk48t02_regs = 0;
+struct mostek48t08 *mstk48t08_regs = 0;
+struct mostek48t59 *mstk48t59_regs = 0;
+
+static int set_rtc_mmss(unsigned long);
+
+/* timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ *
+ * NOTE: On SUN5 systems the ticker interrupt comes in using 2
+ *       interrupts, one at level14 and one with softint bit 0.
+ */
+void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	/* last time the cmos clock got updated */
+	static long last_rtc_update=0;
+
+	do_timer(regs);
+
+	/* Determine when to update the Mostek clock. */
+	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec > 500000 - (tick >> 1) &&
+	    xtime.tv_usec < 500000 + (tick >> 1))
+	  if (set_rtc_mmss(xtime.tv_sec) == 0)
+	    last_rtc_update = xtime.tv_sec;
+	  else
+	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+	unsigned int day, unsigned int hour,
+	unsigned int min, unsigned int sec)
+{
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+	      year*365 - 719499
+	    )*24 + hour /* now have hours */
+	   )*60 + min /* now have minutes */
+	  )*60 + sec; /* finally seconds */
+}
+
+/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
+static void kick_start_clock(void)
+{
+	register struct mostek48t02 *regs = mstk48t02_regs;
+	unsigned char sec;
+	int i, count;
+
+	prom_printf("CLOCK: Clock was stopped. Kick start ");
+
+	/* Turn on the kick start bit to start the oscillator. */
+	regs->creg |= MSTK_CREG_WRITE;
+	regs->sec &= ~MSTK_STOP;
+	regs->hour |= MSTK_KICK_START;
+	regs->creg &= ~MSTK_CREG_WRITE;
+
+	/* Delay to allow the clock oscillator to start. */
+	sec = MSTK_REG_SEC(regs);
+	for (i = 0; i < 3; i++) {
+		while (sec == MSTK_REG_SEC(regs))
+			for (count = 0; count < 100000; count++)
+				/* nothing */ ;
+		prom_printf(".");
+		sec = regs->sec;
+	}
+	prom_printf("\n");
+
+	/* Turn off kick start and set a "valid" time and date. */
+	regs->creg |= MSTK_CREG_WRITE;
+	regs->hour &= ~MSTK_KICK_START;
+	MSTK_SET_REG_SEC(regs,0);
+	MSTK_SET_REG_MIN(regs,0);
+	MSTK_SET_REG_HOUR(regs,0);
+	MSTK_SET_REG_DOW(regs,5);
+	MSTK_SET_REG_DOM(regs,1);
+	MSTK_SET_REG_MONTH(regs,8);
+	MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
+	regs->creg &= ~MSTK_CREG_WRITE;
+
+	/* Ensure the kick start bit is off. If it isn't, turn it off. */
+	while (regs->hour & MSTK_KICK_START) {
+		prom_printf("CLOCK: Kick start still on!\n");
+		regs->creg |= MSTK_CREG_WRITE;
+		regs->hour &= ~MSTK_KICK_START;
+		regs->creg &= ~MSTK_CREG_WRITE;
+	}
+
+	prom_printf("CLOCK: Kick start procedure successful.\n");
+}
+
+/* Return nonzero if the clock chip battery is low. */
+static int has_low_battery(void)
+{
+	register struct mostek48t02 *regs = mstk48t02_regs;
+	unsigned char data1, data2;
+
+	data1 = regs->eeprom[0];	/* Read some data. */
+	regs->eeprom[0] = ~data1;	/* Write back the complement. */
+	data2 = regs->eeprom[0];	/* Read back the complement. */
+	regs->eeprom[0] = data1;	/* Restore the original value. */
+
+	return (data1 == data2);	/* Was the write blocked? */
+}
+
+/* XXX HACK HACK HACK, delete me soon */
+static struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
+static int XXX_sbus_nranges;
+
+/* Probe for the real time clock chip. */
+__initfunc(static void clock_probe(void))
+{
+	struct linux_prom_registers clk_reg[2];
+	char model[128];
+	int node, sbusnd, err;
+
+	node = prom_getchild(prom_root_node);
+	sbusnd = prom_searchsiblings(node, "sbus");
+	node = prom_getchild(sbusnd);
+
+	if(node == 0 || node == -1) {
+		prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n");
+		prom_halt();
+	}
+
+	/* XXX FIX ME */
+	err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges,
+			       sizeof(XXX_sbus_ranges));
+	if(err == -1) {
+		prom_printf("clock_probe: Cannot get XXX sbus ranges\n");
+		prom_halt();
+	}
+	XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges));
+
+	while(1) {
+		prom_getstring(node, "model", model, sizeof(model));
+		if(strcmp(model, "mk48t02") &&
+		   strcmp(model, "mk48t08") &&
+		   strcmp(model, "mk48t59")) {
+			node = prom_getsibling(node);
+			if(node == 0) {
+				prom_printf("clock_probe: Cannot find timer chip\n");
+				prom_halt();
+			}
+			continue;
+		}
+
+		err = prom_getproperty(node, "reg", (char *)clk_reg,
+				       sizeof(clk_reg));
+		if(err == -1) {
+			prom_printf("clock_probe: Cannot make Mostek\n");
+			prom_halt();
+		}
+
+		/* XXX fix me badly */
+		prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges);
+
+		if(model[5] == '0' && model[6] == '2') {
+			mstk48t02_regs = (struct mostek48t02 *)
+				sparc_alloc_io(clk_reg[0].phys_addr,
+					       (void *) 0, sizeof(*mstk48t02_regs),
+					       "clock", clk_reg[0].which_io, 0x0);
+		} else if(model[5] == '0' && model[6] == '8') {
+			mstk48t08_regs = (struct mostek48t08 *)
+				sparc_alloc_io(clk_reg[0].phys_addr,
+					       (void *) 0, sizeof(*mstk48t08_regs),
+					       "clock", clk_reg[0].which_io, 0x0);
+			mstk48t02_regs = &mstk48t08_regs->regs;
+		} else {
+			mstk48t59_regs = (struct mostek48t59 *)
+				sparc_alloc_io(clk_reg[0].phys_addr,
+					       (void *) 0, sizeof(*mstk48t59_regs),
+					       "clock", clk_reg[0].which_io, 0x0);
+			mstk48t02_regs = &mstk48t59_regs->regs;
+		}
+		break;
+	}
+
+	/* Report a low battery voltage condition. */
+	if (has_low_battery())
+		prom_printf("NVRAM: Low battery voltage!\n");
+
+	/* Kick start the clock if it is completely stopped. */
+	if (mstk48t02_regs->sec & MSTK_STOP)
+		kick_start_clock();
+}
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+#endif
+
+__initfunc(void time_init(void))
+{
+	extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+	unsigned int year, mon, day, hour, min, sec;
+	struct mostek48t02 *mregs;
+
+	do_get_fast_time = do_gettimeofday;
+
+	clock_probe();
+	init_timers(timer_interrupt);
+
+	mregs = mstk48t02_regs;
+	if(!mregs) {
+		prom_printf("Something wrong, clock regs not mapped yet.\n");
+		prom_halt();
+	}		
+
+	mregs->creg |= MSTK_CREG_READ;
+	sec = MSTK_REG_SEC(mregs);
+	min = MSTK_REG_MIN(mregs);
+	hour = MSTK_REG_HOUR(mregs);
+	day = MSTK_REG_DOM(mregs);
+	mon = MSTK_REG_MONTH(mregs);
+	year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+	xtime.tv_usec = 0;
+	mregs->creg &= ~MSTK_CREG_READ;
+}
+
+static __inline__ unsigned long do_gettimeoffset(void)
+{
+	unsigned long offset = 0;
+	unsigned int count;
+
+	/* XXX -DaveM */
+#if 0
+	count = (*master_l10_counter >> 10) & 0x1fffff;
+#else
+	count = 0;
+#endif
+
+	if(test_bit(TIMER_BH, &bh_active))
+		offset = 1000000;
+
+	return offset + count;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+
+	save_and_cli(flags);
+	*tv = xtime;
+	tv->tv_usec += do_gettimeoffset();
+	if(tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec++;
+	}
+	restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	cli();
+
+	tv->tv_usec -= do_gettimeoffset();
+	if(tv->tv_usec < 0) {
+		tv->tv_usec += 1000000;
+		tv->tv_sec--;
+	}
+
+	xtime = *tv;
+	time_state = TIME_BAD;
+	time_maxerror = 0x70000000;
+	time_esterror = 0x70000000;
+	sti();
+}
+
+static int set_rtc_mmss(unsigned long nowtime)
+{
+	int real_seconds, real_minutes, mostek_minutes;
+	struct mostek48t02 *regs = mstk48t02_regs;
+
+	/* Not having a register set can lead to trouble. */
+	if (!regs) 
+		return -1;
+
+	/* Read the current RTC minutes. */
+	regs->creg |= MSTK_CREG_READ;
+	mostek_minutes = MSTK_REG_MIN(regs);
+	regs->creg &= ~MSTK_CREG_READ;
+
+	/*
+	 * since we're only adjusting minutes and seconds,
+	 * don't interfere with hour overflow. This avoids
+	 * messing with unknown time zones but requires your
+	 * RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
+		real_minutes += 30;	/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - mostek_minutes) < 30) {
+		regs->creg |= MSTK_CREG_WRITE;
+		MSTK_SET_REG_SEC(regs,real_seconds);
+		MSTK_SET_REG_MIN(regs,real_minutes);
+		regs->creg &= ~MSTK_CREG_WRITE;
+	} else
+		return -1;
+
+	return 0;
+}
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.1.33/linux/arch/sparc64/kernel/traps.c	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/kernel/traps.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.1 1997/03/18 17:59:12 jj Exp $
+/* $Id: traps.c,v 1.5 1997/04/14 06:56:55 davem Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -42,6 +42,53 @@
 
 void syscall_trace_exit(struct pt_regs *regs)
 {
+}
+
+void sparc64_dtlb_fault_handler (void)
+{
+	printk ("sparc64_dtlb_fault_handler\n");
+	while (1);
+	/* Die for now... */
+}
+
+void sparc64_dtlb_refbit_handler (struct pt_regs *regs)
+{
+	printk ("sparc64_dtlb_refbit_handler[%016lx]\n", regs->tpc);
+	while (1);
+	/* Die for now... */
+}
+
+void sparc64_itlb_refbit_handler (void)
+{
+	printk ("sparc64_itlb_refbit_handler\n");
+	while (1);
+	/* Die for now... */
+}
+
+void bad_trap (struct pt_regs *regs, long lvl)
+{
+	printk ("Bad trap %d (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc);
+	while (1);
+	/* Die for now... */
+}
+
+void bad_trap_tl1 (struct pt_regs *regs, long lvl)
+{
+	printk ("Bad trap %d at tl1+ (tstate %016lx tpc %016lx tnpc %016lx)\n", lvl, regs->tstate, regs->tpc, regs->tnpc);
+	while (1);
+	/* Die for now... */
+}
+
+void data_access_exception (struct pt_regs *regs)
+{
+	printk ("Unhandled data access exception sfsr %016lx sfar %016lx\n", spitfire_get_dsfsr(), spitfire_get_sfar());
+	die_if_kernel("Data access exception", regs);
+}
+
+void instruction_access_exception (struct pt_regs *regs)
+{
+	printk ("Unhandled instruction access exception sfsr %016lx\n", spitfire_get_isfsr());
+	die_if_kernel("Instruction access exception", regs);
 }
 
 void instruction_dump (unsigned int *pc)
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.1.33/linux/arch/sparc64/kernel/ttable.S	Mon Mar 17 14:54:23 1997
+++ linux/arch/sparc64/kernel/ttable.S	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.5 1997/02/25 12:40:09 jj Exp $
+/* $Id: ttable.S,v 1.11 1997/03/25 09:47:21 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -9,7 +9,7 @@
 sparc64_ttable_tl0:
 tl0_resv000:	BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
 tl0_resv004:	BTRAP(0x4)  BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
-tl0_iax:	TRAP(do_iax)
+tl0_iax:	ACCESS_EXCEPTION_TRAP(instruction_access_exception)
 tl0_resv009:	BTRAP(0x9)
 tl0_iae:	TRAP(do_iae)
 tl0_resv00b:	BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
@@ -26,7 +26,7 @@
 tl0_div0:	TRAP(do_div0)
 tl0_resv029:	BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e)
 tl0_resv02f:	BTRAP(0x2f)
-tl0_dax:	TRAP(do_dax)
+tl0_dax:	ACCESS_EXCEPTION_TRAP(data_access_exception)
 tl0_resv031:	BTRAP(0x31)
 tl0_dae:	TRAP(do_dae)
 tl0_resv033:	BTRAP(0x33)
@@ -36,15 +36,18 @@
 tl0_privact:	TRAP(do_privact)
 tl0_resv038:	BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
 tl0_resv03e:	BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
-tl0_irq1:	TRAP_IRQ(do_irq, 1)  TRAP_IRQ(do_irq, 2)  TRAP_IRQ(do_irq, 3)
-tl0_irq4:	TRAP_IRQ(do_irq, 4)  TRAP_IRQ(do_irq, 5)  TRAP_IRQ(do_irq, 6)
-tl0_irq7:	TRAP_IRQ(do_irq, 7)  TRAP_IRQ(do_irq, 8)  TRAP_IRQ(do_irq, 9)
-tl0_irq10:	TRAP_IRQ(do_irq, 10) TRAP_IRQ(do_irq, 11) TRAP_IRQ(do_irq, 12)
-tl0_irq13:	TRAP_IRQ(do_irq, 13) TRAP_IRQ(do_irq, 14) TRAP_IRQ(do_irq, 15)
+tl0_irq1:	TRAP_IRQ(handler_irq, 1)  TRAP_IRQ(handler_irq, 2)
+tl0_irq3:	TRAP_IRQ(handler_irq, 3)  TRAP_IRQ(handler_irq, 4)
+tl0_irq5:	TRAP_IRQ(handler_irq, 5)  TRAP_IRQ(handler_irq, 6)
+tl0_irq7:	TRAP_IRQ(handler_irq, 7)  TRAP_IRQ(handler_irq, 8)
+tl0_irq9:	TRAP_IRQ(handler_irq, 9)  TRAP_IRQ(handler_irq, 10)
+tl0_irq11:	TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
+tl0_irq13:	TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14)
+tl0_irq15:	TRAP_IRQ(handler_irq, 15)
 tl0_resv050:	BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
 tl0_resv056:	BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
 tl0_resv05c:	BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f)
-tl0_ivec:	TRAP(do_ivec)
+tl0_ivec:	TRAP_IVEC
 tl0_paw:	TRAP(do_paw)
 tl0_vaw:	TRAP(do_vaw)
 tl0_cee:	TRAP(do_cee)
@@ -93,7 +96,7 @@
 tl0_bkpt:	BREAKPOINT_TRAP
 tl0_resv102:	BTRAP(0x102)
 tl0_flushw:	FLUSH_WINDOW_TRAP
-tl0_resv103:	BTRAP(0x103) BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107)
+tl0_resv104:	BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107)
 tl0_solaris:	SOLARIS_SYSCALL_TRAP
 tl0_netbsd:	NETBSD_SYSCALL_TRAP
 tl0_resv10a:	BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e)
@@ -126,43 +129,43 @@
 tl0_resv178:	BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c)
 tl0_resv17d:	BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f)
 #define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7)
-tl0_resv180:	BTRAPS(0x180)
-tl0_resv190:	BTRAPS(0x190)
-tl0_resv1a0:	BTRAPS(0x1a0)
-tl0_resv1b0:	BTRAPS(0x1b0)
-tl0_resv1c0:	BTRAPS(0x1c0)
-tl0_resv1d0:	BTRAPS(0x1d0)
-tl0_resv1e0:	BTRAPS(0x1e0)
-tl0_resv1f0:	BTRAPS(0x1f0)
+tl0_resv180:	BTRAPS(0x180) BTRAPS(0x188)
+tl0_resv190:	BTRAPS(0x190) BTRAPS(0x198)
+tl0_resv1a0:	BTRAPS(0x1a0) BTRAPS(0x1a8)
+tl0_resv1b0:	BTRAPS(0x1b0) BTRAPS(0x1b8)
+tl0_resv1c0:	BTRAPS(0x1c0) BTRAPS(0x1c8)
+tl0_resv1d0:	BTRAPS(0x1d0) BTRAPS(0x1d8)
+tl0_resv1e0:	BTRAPS(0x1e0) BTRAPS(0x1e8)
+tl0_resv1f0:	BTRAPS(0x1f0) BTRAPS(0x1f8)
 
 sparc64_ttable_tl1:
 tl1_resv000:	BOOT_KERNEL    BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3)
 tl1_resv004:	BTRAPTL1(0x4)  BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7)
-tl1_iax:	TRAP(do_iax_tl1)
+tl1_iax:	ACCESS_EXCEPTION_TRAPTL1(instruction_access_exception)
 tl1_resv009:	BTRAPTL1(0x9)
-tl1_iae:	TRAP(do_iae_tl1)
+tl1_iae:	TRAPTL1(do_iae_tl1)
 tl1_resv00b:	BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf)
-tl1_ill:	TRAP(do_ill_tl1)
+tl1_ill:	TRAPTL1(do_ill_tl1)
 tl1_privop:	BTRAPTL1(0x11)
 tl1_resv012:	BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15)
 tl1_resv016:	BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19)
 tl1_resv01a:	BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d)
 tl1_resv01e:	BTRAPTL1(0x1e) BTRAPTL1(0x1f)
-tl1_fpdis:	TRAP(do_fpdis_tl1)
-tl1_fpieee:	TRAP(do_fpieee_tl1)
-tl1_fpother:	TRAP(do_fpother_tl1)
-tl1_tof:	TRAP(do_tof_tl1)
+tl1_fpdis:	TRAPTL1(do_fpdis_tl1)
+tl1_fpieee:	TRAPTL1(do_fpieee_tl1)
+tl1_fpother:	TRAPTL1(do_fpother_tl1)
+tl1_tof:	TRAPTL1(do_tof_tl1)
 tl1_cwin:	CLEAN_WINDOW
-tl1_div0:	TRAP(do_div0_tl1)
+tl1_div0:	TRAPTL1(do_div0_tl1)
 tl1_resv029:	BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c)
 tl1_resv02d:	BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f)
-tl1_dax:	TRAP(do_dax_tl1)
+tl1_dax:	ACCESS_EXCEPTION_TRAPTL1(data_access_exception)
 tl1_resv031:	BTRAPTL1(0x31)
-tl1_dae:	TRAP(do_dae_tl1)
+tl1_dae:	TRAPTL1(do_dae_tl1)
 tl1_resv033:	BTRAPTL1(0x33)
-tl1_mna:	TRAP(do_mna_tl1)
-tl1_lddfmna:	TRAP(do_lddfmna_tl1)
-tl1_stdfmna:	TRAP(do_stdfmna_tl1)
+tl1_mna:	TRAPTL1(do_mna_tl1)
+tl1_lddfmna:	TRAPTL1(do_lddfmna_tl1)
+tl1_stdfmna:	TRAPTL1(do_stdfmna_tl1)
 tl1_privact:	BTRAPTL1(0x37)
 tl1_resv038:	BTRAPTL1(0x38) BTRAPTL1(0x39) BTRAPTL1(0x3a) BTRAPTL1(0x3b)
 tl1_resv03c:	BTRAPTL1(0x3c) BTRAPTL1(0x3d) BTRAPTL1(0x3e) BTRAPTL1(0x3f)
@@ -177,10 +180,10 @@
 tl1_resv054:	BTRAPTL1(0x54) BTRAPTL1(0x55) BTRAPTL1(0x56) BTRAPTL1(0x57)
 tl1_resv058:	BTRAPTL1(0x58) BTRAPTL1(0x59) BTRAPTL1(0x5a) BTRAPTL1(0x5b)
 tl1_resv05c:	BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f)
-tl1_ivec:	TRAP(do_ivec_tl1)
-tl1_paw:	TRAP(do_paw_tl1)
-tl1_vaw:	TRAP(do_vaw_tl1)
-tl1_cee:	TRAP(do_cee_tl1)
+tl1_ivec:	TRAP_IVEC
+tl1_paw:	TRAPTL1(do_paw_tl1)
+tl1_vaw:	TRAPTL1(do_vaw_tl1)
+tl1_cee:	TRAPTL1(do_cee_tl1)
 tl1_iamiss:
 #include	"itlb_miss.S"
 tl1_damiss:
@@ -228,40 +231,22 @@
 /* Unless we are going to have software trap insns in the kernel code, we
  * don't need this. For now we just save 8KB.
  */
+
+#define BTRAPSTL1(x) BTRAPTL1(x) BTRAPTL1(x+1) BTRAPTL1(x+2) BTRAPTL1(x+3) BTRAPTL1(x+4) BTRAPTL1(x+5) BTRAPTL1(x+6) BTRAPTL1(x+7)
+
 tl1_sunos:	BTRAPTL1(0x100)
 tl1_bkpt:	BREAKPOINT_TRAP
 tl1_resv102:	BTRAPTL1(0x102)
 tl1_flushw:	FLUSH_WINDOW_TRAP
-tl1_resv103:	BTRAPTL1(0x103) BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106)
+tl1_resv104:	BTRAPTL1(0x104) BTRAPTL1(0x105) BTRAPTL1(0x106)
 tl1_resv107:	BTRAPTL1(0x107) BTRAPTL1(0x108) BTRAPTL1(0x109) BTRAPTL1(0x10a)
 tl1_resv10b:	BTRAPTL1(0x10b) BTRAPTL1(0x10c) BTRAPTL1(0x10d) BTRAPTL1(0x10e)
-tl1_resv10f:	BTRAPTL1(0x10f) BTRAPTL1(0x110) BTRAPTL1(0x111) BTRAPTL1(0x112)
-tl1_resv113:	BTRAPTL1(0x113) BTRAPTL1(0x114) BTRAPTL1(0x115) BTRAPTL1(0x116)
-tl1_resv117:	BTRAPTL1(0x117) BTRAPTL1(0x118) BTRAPTL1(0x119) BTRAPTL1(0x11a)
-tl1_resv11b:	BTRAPTL1(0x11b) BTRAPTL1(0x11c) BTRAPTL1(0x11d) BTRAPTL1(0x11e)
-tl1_resv11f:	BTRAPTL1(0x11f) BTRAPTL1(0x120) BTRAPTL1(0x121) BTRAPTL1(0x122)
-tl1_resv123:	BTRAPTL1(0x123) BTRAPTL1(0x124) BTRAPTL1(0x125) BTRAPTL1(0x126)
-tl1_solindir:	BTRAPTL1(0x127) BTRAPTL1(0x128) BTRAPTL1(0x129) BTRAPTL1(0x12a)
-tl1_resv12b:	BTRAPTL1(0x12b) BTRAPTL1(0x12c) BTRAPTL1(0x12d) BTRAPTL1(0x12e)
-tl1_resv12f:	BTRAPTL1(0x12f) BTRAPTL1(0x130) BTRAPTL1(0x131) BTRAPTL1(0x132)
-tl1_resv133:	BTRAPTL1(0x133) BTRAPTL1(0x134) BTRAPTL1(0x135) BTRAPTL1(0x136)
-tl1_resv137:	BTRAPTL1(0x137) BTRAPTL1(0x138) BTRAPTL1(0x139) BTRAPTL1(0x13a)
-tl1_resv13b:	BTRAPTL1(0x13b) BTRAPTL1(0x13c) BTRAPTL1(0x13d) BTRAPTL1(0x13e)
-tl1_resv13f:	BTRAPTL1(0x13f) BTRAPTL1(0x140) BTRAPTL1(0x141) BTRAPTL1(0x142)
-tl1_resv143:	BTRAPTL1(0x143) BTRAPTL1(0x144) BTRAPTL1(0x145) BTRAPTL1(0x146)
-tl1_resv147:	BTRAPTL1(0x147) BTRAPTL1(0x148) BTRAPTL1(0x149) BTRAPTL1(0x14a)
-tl1_resv14b:	BTRAPTL1(0x14b) BTRAPTL1(0x14c) BTRAPTL1(0x14d) BTRAPTL1(0x14e)
-tl1_resv14f:	BTRAPTL1(0x14f) BTRAPTL1(0x150) BTRAPTL1(0x151) BTRAPTL1(0x152)
-tl1_resv153:	BTRAPTL1(0x153) BTRAPTL1(0x154) BTRAPTL1(0x155) BTRAPTL1(0x156)
-tl1_resv157:	BTRAPTL1(0x157) BTRAPTL1(0x158) BTRAPTL1(0x159) BTRAPTL1(0x15a)
-tl1_resv15b:	BTRAPTL1(0x15b) BTRAPTL1(0x15c) BTRAPTL1(0x15d) BTRAPTL1(0x15e)
-tl1_resv15f:	BTRAPTL1(0x15f) BTRAPTL1(0x160) BTRAPTL1(0x161) BTRAPTL1(0x162)
-tl1_resv163:	BTRAPTL1(0x163) BTRAPTL1(0x164) BTRAPTL1(0x165) BTRAPTL1(0x166)
-tl1_resv167:	BTRAPTL1(0x167) BTRAPTL1(0x168) BTRAPTL1(0x169) BTRAPTL1(0x16a)
-tl1_resv16b:	BTRAPTL1(0x16b) BTRAPTL1(0x16c) BTRAPTL1(0x16d) BTRAPTL1(0x16e)
-tl1_resv16f:	BTRAPTL1(0x16f) BTRAPTL1(0x170) BTRAPTL1(0x171) BTRAPTL1(0x172)
-tl1_resv173:	BTRAPTL1(0x173) BTRAPTL1(0x174) BTRAPTL1(0x175) BTRAPTL1(0x176)
-tl1_resv177:	BTRAPTL1(0x177) BTRAPTL1(0x178) BTRAPTL1(0x179) BTRAPTL1(0x17a)
-tl1_resv17b:	BTRAPTL1(0x17b) BTRAPTL1(0x17c)	BTRAPTL1(0x17d) BTRAPTL1(0x17e)
-tl1_resv17f:	BTRAPTL1(0x17f)
+tl1_resv10f:	BTRAPTL1(0x10f) 
+tl1_resv110:	BTRAPSTL1(0x110) BTRAPSTL1(0x118)
+tl1_resv120:	BTRAPSTL1(0x120) BTRAPSTL1(0x128)
+tl1_resv130:	BTRAPSTL1(0x130) BTRAPSTL1(0x138)
+tl1_resv140:	BTRAPSTL1(0x140) BTRAPSTL1(0x148)
+tl1_resv150:	BTRAPSTL1(0x150) BTRAPSTL1(0x158)
+tl1_resv160:	BTRAPSTL1(0x160) BTRAPSTL1(0x168)
+tl1_resv170:	BTRAPSTL1(0x170) BTRAPSTL1(0x178)
 #endif
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile
--- v2.1.33/linux/arch/sparc64/lib/Makefile	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/Makefile	Fri Apr 11 10:47:36 1997
@@ -1,11 +1,12 @@
-# $Id: Makefile,v 1.5 1997/03/14 21:04:27 jj Exp $
+# $Id: Makefile,v 1.7 1997/04/07 18:57:05 jj Exp $
 # Makefile for Sparc library files..
 #
 
 CFLAGS := $(CFLAGS) -ansi
 
 OBJS  = memset.o blockops.o locks.o memcpy.o strlen.o strncmp.o \
-	memscan.o strncpy_from_user.o strlen_user.o memcmp.o
+	memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
+	copy_to_user.o copy_from_user.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
@@ -17,6 +18,12 @@
 memset.o: memset.S
 	$(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S
 
+copy_to_user.o: copy_to_user.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o copy_to_user.o copy_to_user.S
+
+copy_from_user.o: copy_from_user.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o copy_from_user.o copy_from_user.S
+
 memcpy.o: memcpy.S
 	$(CC) -D__ASSEMBLY__ -ansi -c -o memcpy.o memcpy.S
 
@@ -31,6 +38,9 @@
 
 locks.o: locks.S
 	$(CC) -D__ASSEMBLY__ -ansi -c -o locks.o locks.S
+
+checksum.o: checksum.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o checksum.o checksum.S
 
 memscan.o: memscan.S
 	$(CC) -D__ASSEMBLY__ -ansi -c -o memscan.o memscan.S
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.1.33/linux/arch/sparc64/lib/blockops.S	Mon Mar 17 14:54:23 1997
+++ linux/arch/sparc64/lib/blockops.S	Fri Apr 11 10:47:36 1997
@@ -1,33 +1,32 @@
-/* $Id: blockops.S,v 1.3 1997/02/25 20:00:10 jj Exp $
+/* $Id: blockops.S,v 1.5 1997/03/26 18:34:28 jj Exp $
  * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <asm/asi.h>
 
-/* FIXME: Write this. */
-#define BZERO_TEST
-
 	/* Zero out 256 bytes of memory at (buf + offset). */
 #define BLAST_BLOCK(buf, offset)				\
 	stda		%f48, [buf + offset + 0x00] %asi;	\
 	stda		%f48, [buf + offset + 0x40] %asi;	\
 	stda		%f48, [buf + offset + 0x80] %asi;	\
-	stda		%f48, [buf + offset + 0xc0] %asi;	\
+	stda		%f48, [buf + offset + 0xc0] %asi;
 
-	/* Copy 32 bytes of memory at (src + offset) to
+	/* Copy 256 bytes of memory at (src + offset) to
 	 * (dst + offset).
 	 */
-#define MIRROR_BLOCK(dst, src, offset, t0, t1, t2, t3)		\
-	ldx		[src + offset + 0x18], t0;		\
-	ldx		[src + offset + 0x10], t1;		\
-	ldx		[src + offset + 0x08], t2;		\
-	ldx		[src + offset + 0x00], t3;		\
-	stx		t0, [dst + offset + 0x18];		\
-	stx		t1, [dst + offset + 0x10];		\
-	stx		t2, [dst + offset + 0x08];		\
-	stx		t3, [dst + offset + 0x00];
+#define MIRROR_BLOCK(dst, src, offset, sync)			\
+	ldda		[src + offset + 0x000] %asi, %f0;	\
+	ldda		[src + offset + 0x040] %asi, %f16;	\
+	ldda		[src + offset + 0x080] %asi, %f32;	\
+	ldda		[src + offset + 0x0c0] %asi, %f48;	\
+	membar		sync;					\
+	stda		%f0, [dst + offset + 0x000] %asi;	\
+	stda		%f16, [dst + offset + 0x040] %asi;	\
+	stda		%f32, [dst + offset + 0x080] %asi;	\
+	stda		%f48, [dst + offset + 0x0c0] %asi;
 
 	.text
 	.align	4
@@ -38,7 +37,17 @@
 	mov		%o0, %o1
 	wr		%g0, ASI_BLK_P, %asi
 	mov		0x10, %g2
-	BZERO_TEST
+
+	membar		#Sync|#StoreLoad
+
+	fzero		%f48
+	fzero		%f50
+	fzero		%f52
+	fzero		%f54
+	fzero		%f56
+	fzero		%f58
+	fzero		%f60
+	fzero		%f62
 1:
 	BLAST_BLOCK(%o0, 0x000)
 	BLAST_BLOCK(%o0, 0x100)
@@ -48,6 +57,8 @@
 	bne,pt		%icc, 1b
 	 add		%o0, 0x400, %o0
 
+	membar		#Sync|#LoadStore|#StoreStore
+
 	retl
 	 mov		%o1, %o0
 
@@ -56,7 +67,15 @@
 	mov		%o0, %o1
 	wr		%g0, ASI_BLK_P, %asi
 	mov		0x08, %g2
-	BZERO_TEST
+	membar		#Sync|#StoreLoad
+	fzero		%f48
+	fzero		%f50
+	fzero		%f52
+	fzero		%f54
+	fzero		%f56
+	fzero		%f58
+	fzero		%f60
+	fzero		%f62
 1:
 	BLAST_BLOCK(%o0, 0x000)
 	BLAST_BLOCK(%o0, 0x100)
@@ -66,27 +85,54 @@
 	bne,pt		%icc, 1b
 	 add		%o0, 0x400, %o0
 
+	membar		#Sync|#LoadStore|#StoreStore
+
 	retl
 	 mov		%o1, %o0
 
+	.globl		__bfill64
+__bfill64:
+	/* %o0 = buf */
+	stx		%o1, [%sp + 0x7ff + 128]
+	wr		%g0, ASI_BLK_P, %asi
+	mov		0x08, %g2
+	ldd		[%sp + 0x7ff + 128], %f48
+	membar		#Sync|#StoreLoad
+	fmovd		%f48, %f50
+	fmovd		%f48, %f52
+	fmovd		%f48, %f54
+	fmovd		%f48, %f56
+	fmovd		%f48, %f58
+	fmovd		%f48, %f60
+	fmovd		%f48, %f62
+1:
+	BLAST_BLOCK(%o0, 0x000)
+	BLAST_BLOCK(%o0, 0x100)
+	BLAST_BLOCK(%o0, 0x200)
+	BLAST_BLOCK(%o0, 0x300)
+	subcc		%g2, 1, %g2
+	bne,pt		%icc, 1b
+	 add		%o0, 0x400, %o0
+
+	retl
+	 membar		#Sync|#LoadStore|#StoreStore
+
 	.globl		__copy_1page
 __copy_1page:
 	/* %o0 = dst, %o1 = src */
-	or		%g0, 0x10, %g1
+	or		%g0, 0x08, %g1
+	wr		%g0, ASI_BLK_P, %asi
+	membar		#Sync|#StoreLoad
 1:
-	MIRROR_BLOCK(%o0, %o1, 0x00, %o2, %o3, %o4, %o5)
-	MIRROR_BLOCK(%o0, %o1, 0x20, %o2, %o3, %o4, %o5)
-	MIRROR_BLOCK(%o0, %o1, 0x40, %o2, %o3, %o4, %o5)
-	MIRROR_BLOCK(%o0, %o1, 0x60, %o2, %o3, %o4, %o5)
-	MIRROR_BLOCK(%o0, %o1, 0x80, %o2, %o3, %o4, %o5)
-	MIRROR_BLOCK(%o0, %o1, 0xa0, %o2, %o3, %o4, %o5)
-	MIRROR_BLOCK(%o0, %o1, 0xc0, %o2, %o3, %o4, %o5)
-	MIRROR_BLOCK(%o0, %o1, 0xe0, %o2, %o3, %o4, %o5)
+	MIRROR_BLOCK(%o0, %o1, 0x000, #Sync)
+	MIRROR_BLOCK(%o0, %o1, 0x100, #Sync)
+	MIRROR_BLOCK(%o0, %o1, 0x200, #Sync)
+	MIRROR_BLOCK(%o0, %o1, 0x300, #Sync)
 	subcc		%g1, 1, %g1
-	add		%o0, 0x100, %o0
+	add		%o0, 0x400, %o0
 	bne,pt		%icc, 1b
-	 add		%o1, 0x100, %o1
+	 add		%o1, 0x400, %o1
 
 	retl
-	 nop
+	 membar		#Sync|#LoadStore|#StoreStore
 
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S
--- v2.1.33/linux/arch/sparc64/lib/checksum.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/checksum.S	Fri Apr 11 10:47:36 1997
@@ -15,6 +15,7 @@
 
 #include <asm/errno.h>
 #include <asm/head.h>
+#include <asm/ptrace.h>
 
 #define CSUM_BIGCHUNK(buf, offset, sum, t0, t1, t2, t3, t4, t5)	\
 	ldd	[buf + offset + 0x00], t0;			\
@@ -78,8 +79,8 @@
 	/* The common case is to get called with a nicely aligned
 	 * buffer of size 0x20.  Follow the code path for that case.
 	 */
-	.globl	C_LABEL(csum_partial)
-C_LABEL(csum_partial):			/* %o0=buf, %o1=len, %o2=sum */
+	.globl	csum_partial
+csum_partial:						/* %o0=buf, %o1=len, %o2=sum */
 	andcc	%o0, 0x7, %g0				! alignment problems?
 	be,pt	%icc, csum_partial_fix_aligned		! yep, handle it
 	 andn	%o1, 0x7f, %o3				! num loop iterations
@@ -140,8 +141,8 @@
 	retl						! get outta here
 	 sllx	%g4, 32, %g4				! give gfp back
 
-	.globl C_LABEL(__csum_partial_copy_start), C_LABEL(__csum_partial_copy_end)
-C_LABEL(__csum_partial_copy_start):
+	.globl __csum_partial_copy_start, __csum_partial_copy_end
+__csum_partial_copy_start:
 
 #define EX(x,y,a,b,z)                           \
 98:     x,y;                                    \
@@ -288,8 +289,8 @@
 	 * out of you, game over, lights out.
 	 */
 	.align	8
-	.globl	C_LABEL(__csum_partial_copy_sparc_generic)
-C_LABEL(__csum_partial_copy_sparc_generic):
+	.globl	__csum_partial_copy_sparc_generic
+__csum_partial_copy_sparc_generic:
 					/* %o0=src, %o1=dest, %g1=len, %g7=sum */
 	xor	%o0, %o1, %o4		! get changing bits
 	andcc	%o4, 3, %g0		! check for mismatched alignment
@@ -460,7 +461,7 @@
 4:	addcc	%g7, %g5, %g7
 	retl	
 	 addc	%g0, %g7, %o0
-C_LABEL(__csum_partial_copy_end):
+__csum_partial_copy_end:
 
         .section .fixup,#alloc,#execinstr
         .align  4
@@ -514,7 +515,7 @@
 	sub	%o1, 0x70, %o1
 	add	%o3, 0x70, %o3
 	clr	%o2
-	movne	%g2, 8, %o2
+	movrnz	%g2, 8, %o2
 	ba,pt	%xcc, 31f
 	 sub	%o3, %o2, %o3
 96:
@@ -538,7 +539,7 @@
         mov     %i5, %o0
         mov     %i7, %o1
         mov	%i4, %o2
-        call    C_LABEL(lookup_fault)
+        call    lookup_fault
 	 mov	%g7, %i4
 	cmp	%o0, 2
 	bne,pn	%icc, 1f
@@ -547,17 +548,17 @@
 	 mov	%i0, %o1
 	mov	%i1, %o0
 5:
-	call	C_LABEL(__memcpy)
+	call	__memcpy
 	 mov	%i2, %o2
 	brnz,a,pn %o0, 2f
 	 add	%i3, %i2, %i3
 	add	%i1, %i2, %i1
 2:
 	mov	%i1, %o0
-	call	C_LABEL(__bzero)
+	call	__bzero
 	 mov	%i3, %o1
 1:
-	ldx	[%sp + 264], %o2		! struct_ptr of parent
+	ldx	[%sp + STACK_BIAS + 264], %o2		! struct_ptr of parent
 	st	%i5, [%o2]
 	ret
 	 restore
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/copy_from_user.S linux/arch/sparc64/lib/copy_from_user.S
--- v2.1.33/linux/arch/sparc64/lib/copy_from_user.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/copy_from_user.S	Fri Apr 11 10:47:36 1997
@@ -0,0 +1,456 @@
+/* copy_user.S: Sparc optimized copy_from_user code.
+ *
+ *  Copyright(C) 1995 Linus Torvalds
+ *  Copyright(C) 1996 David S. Miller
+ *  Copyright(C) 1996 Eddie C. Dost
+ *  Copyright(C) 1996,1997 Jakub Jelinek
+ *
+ * derived from:
+ *	e-mail between David and Eddie.
+ *
+ * Returns 0 if successful, otherwise count of bytes not copied yet
+ *
+ * FIXME: This code should be optimized for sparc64... -jj
+ */
+
+#include <asm/ptrace.h>
+#include <asm/asi.h>
+
+#define EX(x,y,a,b,z) 				\
+98: 	x,y;					\
+	.section .fixup,z##alloc,z##execinstr;	\
+	.align	4;				\
+99:	retl;					\
+	 a, b, %o0;				\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 99b;			\
+	.text;					\
+	.align	4
+
+#define EX2(x,y,c,d,e,a,b,z) 			\
+98: 	x,y;					\
+	.section .fixup,z##alloc,z##execinstr;	\
+	.align	4;				\
+99:	c, d, e;				\
+	retl;					\
+	 a, b, %o0;				\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 99b;			\
+	.text;					\
+	.align	4
+
+#define EXO2(x,y,z) 				\
+98: 	x,##y;					\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 97f;			\
+	.text;					\
+	.align	4
+
+#define EXT(start,end,handler,z) 		\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	start, 0, end, handler;		\
+	.text;					\
+	.align	4
+
+/* Please do not change following macros unless you change logic used
+ * in .fixup at the end of this file as well
+ */
+
+/* Both these macros have to start with exactly the same insn */
+#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+	ldda	[%src + offset + 0x00] %asi, %t0; \
+	ldda	[%src + offset + 0x08] %asi, %t2; \
+	ldda	[%src + offset + 0x10] %asi, %t4; \
+	ldda	[%src + offset + 0x18] %asi, %t6; \
+	st	%t0, [%dst + offset + 0x00]; \
+	st	%t1, [%dst + offset + 0x04]; \
+	st	%t2, [%dst + offset + 0x08]; \
+	st	%t3, [%dst + offset + 0x0c]; \
+	st	%t4, [%dst + offset + 0x10]; \
+	st	%t5, [%dst + offset + 0x14]; \
+	st	%t6, [%dst + offset + 0x18]; \
+	st	%t7, [%dst + offset + 0x1c];
+
+#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+	ldda	[%src + offset + 0x00] %asi, %t0; \
+	ldda	[%src + offset + 0x08] %asi, %t2; \
+	ldda	[%src + offset + 0x10] %asi, %t4; \
+	ldda	[%src + offset + 0x18] %asi, %t6; \
+	std	%t0, [%dst + offset + 0x00]; \
+	std	%t2, [%dst + offset + 0x08]; \
+	std	%t4, [%dst + offset + 0x10]; \
+	std	%t6, [%dst + offset + 0x18];
+
+#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
+	ldda	[%src - offset - 0x10] %asi, %t0; \
+	ldda	[%src - offset - 0x08] %asi, %t2; \
+	st	%t0, [%dst - offset - 0x10]; \
+	st	%t1, [%dst - offset - 0x0c]; \
+	st	%t2, [%dst - offset - 0x08]; \
+	st	%t3, [%dst - offset - 0x04];
+
+#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
+	lduha	[%src + offset + 0x00] %asi, %t0; \
+	lduha	[%src + offset + 0x02] %asi, %t1; \
+	lduha	[%src + offset + 0x04] %asi, %t2; \
+	lduha	[%src + offset + 0x06] %asi, %t3; \
+	sth	%t0, [%dst + offset + 0x00]; \
+	sth	%t1, [%dst + offset + 0x02]; \
+	sth	%t2, [%dst + offset + 0x04]; \
+	sth	%t3, [%dst + offset + 0x06];
+
+#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
+	lduba	[%src - offset - 0x02] %asi, %t0; \
+	lduba	[%src - offset - 0x01] %asi, %t1; \
+	stb	%t0, [%dst - offset - 0x02]; \
+	stb	%t1, [%dst - offset - 0x01];
+
+	.text
+	.align	4
+
+	.globl	__copy_from_user
+dword_align:
+	andcc	%o1, 1, %g0
+	be	4f
+	 andcc	%o1, 2, %g0
+
+	EXO2(lduba [%o1] %asi, %g2,#)
+	add	%o1, 1, %o1
+	stb	%g2, [%o0]
+	sub	%o2, 1, %o2
+	bne	3f
+	 add	%o0, 1, %o0
+
+	EXO2(lduha [%o1] %asi, %g2,#)
+	add	%o1, 2, %o1
+	sth	%g2, [%o0]
+	sub	%o2, 2, %o2
+	ba,pt	%xcc, 3f
+	 add	%o0, 2, %o0
+4:
+	EXO2(lduha [%o1] %asi, %g2,#)
+	add	%o1, 2, %o1
+	sth	%g2, [%o0]
+	sub	%o2, 2, %o2
+	ba,pt	%xcc, 3f
+	 add	%o0, 2, %o0
+
+__copy_from_user:	/* %o0=dst %o1=src %o2=len */
+	wr	%g0, ASI_S, %asi
+	xor	%o0, %o1, %o4
+1:
+	andcc	%o4, 3, %o5
+2:
+	bne,pn	%icc, cannot_optimize
+	 cmp	%o2, 15
+
+	bleu,pn	%xcc, short_aligned_end
+	 andcc	%o1, 3, %g0
+
+	bne,pn	%icc, dword_align
+3:
+	 andcc	%o1, 4, %g0
+
+	be,pt	%icc, 2f
+	 mov	%o2, %g1
+
+	EXO2(lda [%o1] %asi, %o4,#)
+	sub	%g1, 4, %g1
+	st	%o4, [%o0]
+	add	%o1, 4, %o1
+	add	%o0, 4, %o0
+2:
+	andcc	%g1, 0xffffffffffffff80, %g7
+	be,pn	%xcc, 3f
+	 andcc	%o0, 4, %g0
+
+	be,pn	%icc, ldd_std + 4
+5:
+	MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+80:
+	EXT(5b, 80b, 50f,#)
+	subcc	%g7, 128, %g7
+	add	%o1, 128, %o1
+	bne,pt	%xcc, 5b
+	 add	%o0, 128, %o0
+3:
+	andcc	%g1, 0x70, %g7
+	be,pn	%icc, copy_user_table_end
+	 andcc	%g1, 8, %g0
+100:
+	rd	%pc, %o5
+	srl	%g7, 1, %o4
+	add	%g7, %o4, %o4
+	add	%o1, %g7, %o1
+	sub	%o5, %o4, %o5
+	jmpl	%o5 + (copy_user_table_end - 100b), %g0
+	 add	%o0, %g7, %o0
+
+copy_user_table:
+	MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+copy_user_table_end:
+	EXT(copy_user_table, copy_user_table_end, 51f,#)
+	be,pt	%icc, copy_user_last7
+	 andcc	%g1, 4, %g0
+
+	EX(ldda	[%o1] %asi, %g2, and %g1, 0xf,#)
+	add	%o0, 8, %o0
+	add	%o1, 8, %o1
+	st	%g2, [%o0 - 0x08]
+	st	%g3, [%o0 - 0x04]
+copy_user_last7:
+	be,pn	%icc, 1f
+	 andcc	%g1, 2, %g0
+
+	EX(lda	[%o1] %asi, %g2, and %g1, 7,#)
+	add	%o1, 4, %o1
+	st	%g2, [%o0]
+	add	%o0, 4, %o0
+1:
+	be,pn	%icc, 1f
+	 andcc	%g1, 1, %g0
+
+	EX(lduha [%o1] %asi, %g2, and %g1, 3,#)
+	add	%o1, 2, %o1
+	sth	%g2, [%o0]
+	add	%o0, 2, %o0
+1:
+	be,pn	%icc, 1f
+	 nop
+
+	EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
+	stb	%g2, [%o0]
+1:
+	retl
+ 	 clr	%o0
+
+ldd_std:
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+81:
+	EXT(ldd_std, 81b, 52f,#)
+	subcc	%g7, 128, %g7
+	add	%o1, 128, %o1
+	bne,pt	%xcc, ldd_std
+	add	%o0, 128, %o0
+
+	andcc	%g1, 0x70, %g7
+	be,pn	%icc, copy_user_table_end
+	 andcc	%g1, 8, %g0
+101:
+	rd	%pc, %o5
+	srl	%g7, 1, %o4
+	add	%g7, %o4, %o4
+	add	%o1, %g7, %o1
+	sub	%o5, %o4, %o5
+	jmpl	%o5 + (copy_user_table_end - 101b), %g0
+	 add	%o0, %g7, %o0
+
+cannot_optimize:
+	bleu	short_end
+	 cmp	%o5, 2
+
+	bne	byte_chunk
+	 and	%o2, 0xfffffffffffffff0, %o3
+	 
+	andcc	%o1, 1, %g0
+	be	10f
+	 nop
+
+	EXO2(lduba [%o1] %asi, %g2,#)
+	add	%o1, 1, %o1
+	stb	%g2, [%o0]
+	sub	%o2, 1, %o2
+	andcc	%o2, 0xfffffffffffffff0, %o3
+	be	short_end
+	 add	%o0, 1, %o0
+10:
+	MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+	MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
+82:
+	EXT(10b, 82b, 53f,#)
+	subcc	%o3, 0x10, %o3
+	add	%o1, 0x10, %o1
+	bne	10b
+	 add	%o0, 0x10, %o0
+	ba,pt	%xcc, 2f
+	 and	%o2, 0xe, %o3
+	
+byte_chunk:
+	MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
+83:
+	EXT(byte_chunk, 83b, 54f,#)
+	subcc	%o3, 0x10, %o3
+	add	%o1, 0x10, %o1
+	bne,pt	%xcc, byte_chunk
+	 add	%o0, 0x10, %o0
+
+short_end:
+	and	%o2, 0xe, %o3
+2:
+	rd	%pc, %o5
+	sll	%o3, 3, %o4
+	add	%o0, %o3, %o0
+	sub	%o5, %o4, %o5
+	add	%o1, %o3, %o1
+	jmpl	%o5 + (short_table_end - 2b), %g0
+	 andcc	%o2, 1, %g0
+84:
+	MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
+short_table_end:
+	EXT(84b, short_table_end, 55f,#)
+	be	1f
+	 nop
+	EX(lduba [%o1] %asi, %g2, add %g0, 1,#)
+	stb	%g2, [%o0]
+1:
+	retl
+ 	 clr	%o0
+
+short_aligned_end:
+	bne	short_end
+	 andcc	%o2, 8, %g0
+
+	be	1f
+	 andcc	%o2, 4, %g0
+
+	EXO2(lda [%o1 + 0x00] %asi, %g2,#)
+	EX(lda	[%o1 + 0x04] %asi, %g3, sub %o2, 4,#)
+	add	%o1, 8, %o1
+	st	%g2, [%o0 + 0x00]
+	st	%g3, [%o0 + 0x04]
+	add	%o0, 8, %o0
+1:
+	ba,pt	%xcc, copy_user_last7
+	 mov	%o2, %g1
+
+	.section .fixup,#alloc,#execinstr
+	.align	4
+97:
+	retl
+	 mov	%o2, %o0
+/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
+50:
+/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
+ * happens. This is derived from the amount ldd reads, st stores, etc.
+ * x = g2 % 12;
+ * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4)
+ */
+	cmp	%g2, 12
+	bcs	1f
+	 cmp	%g2, 24
+	bcs	2f
+	 cmp	%g2, 36
+	bcs	3f
+	 nop
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+3:
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+2:
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+1:
+	cmp	%g2, 4
+	bcs,a	1f
+	 sll	%g2, 3, %g2
+	sub	%g2, 4, %g2
+	sll	%g2, 2, %g2
+1:
+	and	%g1, 0x7f, %o0
+	add	%o0, %g7, %o0
+	retl
+	 sub	%o0, %g2, %o0
+51:
+/* i = 41 - g2; j = i % 6;
+ * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8;	
+ */
+	neg	%g2
+	and	%g1, 0xf, %g1
+	add	%g2, 41, %g2
+1:
+	cmp	%g2, 6
+	bcs,a	2f
+	 cmp	%g2, 4
+	add	%g1, 16, %g1
+	b	1b
+	 sub	%g2, 6, %g2
+2:
+	bcs,a	3f
+	 inc	%g2
+	sub	%g2, 3, %g2
+	b	2f
+	 sll	%g2, 3, %g2
+3:
+	sll	%g2, 2, %g2
+2:
+	retl
+	 add	%g1, %g2, %o0
+52:
+/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */
+	and	%g2, 0xfffffffffffffff8, %g4
+	and	%g2, 3, %g2
+	sll	%g4, 2, %g4
+	sll	%g2, 3, %g2
+	add	%g2, %g4, %g2
+	b,a	1b
+53:
+/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */
+	and	%g2, 3, %g4
+	and	%g2, 0xfffffffffffffff8, %g2
+	sll	%g4, 1, %g4
+	add	%g2, %g4, %g2
+	and	%o2, 0xf, %o0
+	add	%o0, %o3, %o0
+	retl
+	 sub	%o0, %g2, %o0
+54:
+/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */
+	srl	%g2, 2, %o4
+	and	%g2, 1, %o1
+	sll	%o4, 1, %o4
+	and	%o2, 0xf, %o2
+	sub	%o3, %o1, %o3
+	sub	%o2, %o4, %o2
+	retl
+	 add	%o2, %o3, %o0
+55:
+/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */
+	neg	%g2
+	and	%o2, 1, %o2
+	add	%g2, 27, %g2
+	srl	%g2, 2, %o1
+	and	%g2, 1, %g2
+	sll	%o1, 1, %o1
+	add	%o2, %g2, %o0
+	retl
+	 add	%o0, %o1, %o0
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/copy_to_user.S linux/arch/sparc64/lib/copy_to_user.S
--- v2.1.33/linux/arch/sparc64/lib/copy_to_user.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/copy_to_user.S	Fri Apr 11 10:47:36 1997
@@ -0,0 +1,456 @@
+/* copy_user.S: Sparc optimized copy_to_user code.
+ *
+ *  Copyright(C) 1995 Linus Torvalds
+ *  Copyright(C) 1996 David S. Miller
+ *  Copyright(C) 1996 Eddie C. Dost
+ *  Copyright(C) 1996,1997 Jakub Jelinek
+ *
+ * derived from:
+ *	e-mail between David and Eddie.
+ *
+ * Returns 0 if successful, otherwise count of bytes not copied yet
+ *
+ * FIXME: This code should be optimized for sparc64... -jj
+ */
+
+#include <asm/ptrace.h>
+#include <asm/asi.h>
+
+#define EX(x,y,a,b,z) 				\
+98: 	x,y;					\
+	.section .fixup,z##alloc,z##execinstr;	\
+	.align	4;				\
+99:	retl;					\
+	 a, b, %o0;				\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 99b;			\
+	.text;					\
+	.align	4
+
+#define EX2(x,y,c,d,e,a,b,z) 			\
+98: 	x,y;					\
+	.section .fixup,z##alloc,z##execinstr;	\
+	.align	4;				\
+99:	c, d, e;				\
+	retl;					\
+	 a, b, %o0;				\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 99b;			\
+	.text;					\
+	.align	4
+
+#define EXO2(x,y,z) 				\
+98: 	x,##y;					\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 97f;			\
+	.text;					\
+	.align	4
+
+#define EXT(start,end,handler,z) 		\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	start, 0, end, handler;		\
+	.text;					\
+	.align	4
+
+/* Please do not change following macros unless you change logic used
+ * in .fixup at the end of this file as well
+ */
+
+/* Both these macros have to start with exactly the same insn */
+#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+	ldd	[%src + offset + 0x00], %t0; \
+	ldd	[%src + offset + 0x08], %t2; \
+	ldd	[%src + offset + 0x10], %t4; \
+	ldd	[%src + offset + 0x18], %t6; \
+	sta	%t0, [%dst + offset + 0x00] %asi; \
+	sta	%t1, [%dst + offset + 0x04] %asi; \
+	sta	%t2, [%dst + offset + 0x08] %asi; \
+	sta	%t3, [%dst + offset + 0x0c] %asi; \
+	sta	%t4, [%dst + offset + 0x10] %asi; \
+	sta	%t5, [%dst + offset + 0x14] %asi; \
+	sta	%t6, [%dst + offset + 0x18] %asi; \
+	sta	%t7, [%dst + offset + 0x1c] %asi;
+
+#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+	ldd	[%src + offset + 0x00], %t0; \
+	ldd	[%src + offset + 0x08], %t2; \
+	ldd	[%src + offset + 0x10], %t4; \
+	ldd	[%src + offset + 0x18], %t6; \
+	stda	%t0, [%dst + offset + 0x00] %asi; \
+	stda	%t2, [%dst + offset + 0x08] %asi; \
+	stda	%t4, [%dst + offset + 0x10] %asi; \
+	stda	%t6, [%dst + offset + 0x18] %asi;
+
+#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
+	ldd	[%src - offset - 0x10], %t0; \
+	ldd	[%src - offset - 0x08], %t2; \
+	sta	%t0, [%dst - offset - 0x10] %asi; \
+	sta	%t1, [%dst - offset - 0x0c] %asi; \
+	sta	%t2, [%dst - offset - 0x08] %asi; \
+	sta	%t3, [%dst - offset - 0x04] %asi;
+
+#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
+	lduh	[%src + offset + 0x00], %t0; \
+	lduh	[%src + offset + 0x02], %t1; \
+	lduh	[%src + offset + 0x04], %t2; \
+	lduh	[%src + offset + 0x06], %t3; \
+	stha	%t0, [%dst + offset + 0x00] %asi; \
+	stha	%t1, [%dst + offset + 0x02] %asi; \
+	stha	%t2, [%dst + offset + 0x04] %asi; \
+	stha	%t3, [%dst + offset + 0x06] %asi;
+
+#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
+	ldub	[%src - offset - 0x02], %t0; \
+	ldub	[%src - offset - 0x01], %t1; \
+	stba	%t0, [%dst - offset - 0x02] %asi; \
+	stba	%t1, [%dst - offset - 0x01] %asi;
+
+	.text
+	.align	4
+
+	.globl	__copy_to_user
+dword_align:
+	andcc	%o1, 1, %g0
+	be	4f
+	 andcc	%o1, 2, %g0
+
+	ldub	[%o1], %g2
+	add	%o1, 1, %o1
+	EXO2(stba %g2, [%o0] %asi,#)
+	sub	%o2, 1, %o2
+	bne	3f
+	 add	%o0, 1, %o0
+
+	lduh	[%o1], %g2
+	add	%o1, 2, %o1
+	EXO2(stha %g2, [%o0] %asi,#)
+	sub	%o2, 2, %o2
+	ba,pt	%xcc, 3f
+	 add	%o0, 2, %o0
+4:
+	lduh	[%o1], %g2
+	add	%o1, 2, %o1
+	EXO2(stha %g2, [%o0] %asi,#)
+	sub	%o2, 2, %o2
+	ba,pt	%xcc, 3f
+	 add	%o0, 2, %o0
+
+__copy_to_user:	/* %o0=dst %o1=src %o2=len */
+	wr	%g0, ASI_S, %asi
+	xor	%o0, %o1, %o4
+1:
+	andcc	%o4, 3, %o5
+2:
+	bne,pn	%icc, cannot_optimize
+	 cmp	%o2, 15
+
+	bleu,pn	%xcc, short_aligned_end
+	 andcc	%o1, 3, %g0
+
+	bne,pn	%icc, dword_align
+3:
+	 andcc	%o1, 4, %g0
+
+	be,pt	%icc, 2f
+	 mov	%o2, %g1
+
+	ld	[%o1], %o4
+	sub	%g1, 4, %g1
+	EXO2(sta %o4, [%o0] %asi,#)
+	add	%o1, 4, %o1
+	add	%o0, 4, %o0
+2:
+	andcc	%g1, 0xffffffffffffff80, %g7
+	be,pn	%xcc, 3f
+	 andcc	%o0, 4, %g0
+
+	be,pn	%icc, ldd_std + 4
+5:
+	MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+80:
+	EXT(5b, 80b, 50f,#)
+	subcc	%g7, 128, %g7
+	add	%o1, 128, %o1
+	bne,pt	%xcc, 5b
+	 add	%o0, 128, %o0
+3:
+	andcc	%g1, 0x70, %g7
+	be,pn	%icc, copy_user_table_end
+	 andcc	%g1, 8, %g0
+100:
+	rd	%pc, %o5
+	srl	%g7, 1, %o4
+	add	%g7, %o4, %o4
+	add	%o1, %g7, %o1
+	sub	%o5, %o4, %o5
+	jmpl	%o5 + (copy_user_table_end - 100b), %g0
+	 add	%o0, %g7, %o0
+
+copy_user_table:
+	MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+copy_user_table_end:
+	EXT(copy_user_table, copy_user_table_end, 51f,#)
+	be,pt	%icc, copy_user_last7
+	 andcc	%g1, 4, %g0
+
+	ldd	[%o1], %g2
+	add	%o0, 8, %o0
+	add	%o1, 8, %o1
+	EX(sta	%g2, [%o0 - 0x08] %asi, and %g1, 0xf,#)
+	EX2(sta	%g3, [%o0 - 0x04] %asi, and %g1, 0xf, %g1, sub %g1, 4,#)
+copy_user_last7:
+	be,pn	%icc, 1f
+	 andcc	%g1, 2, %g0
+
+	ld	[%o1], %g2
+	add	%o1, 4, %o1
+	EX(sta	%g2, [%o0] %asi, and %g1, 7,#)
+	add	%o0, 4, %o0
+1:
+	be,pn	%icc, 1f
+	 andcc	%g1, 1, %g0
+
+	lduh	[%o1], %g2
+	add	%o1, 2, %o1
+	EX(stha	%g2, [%o0] %asi, and %g1, 3,#)
+	add	%o0, 2, %o0
+1:
+	be,pn	%icc, 1f
+	 nop
+
+	ldub	[%o1], %g2
+	EX(stba	%g2, [%o0] %asi, add %g0, 1,#)
+1:
+	retl
+ 	 clr	%o0
+
+ldd_std:
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+81:
+	EXT(ldd_std, 81b, 52f,#)
+	subcc	%g7, 128, %g7
+	add	%o1, 128, %o1
+	bne,pt	%xcc, ldd_std
+	add	%o0, 128, %o0
+
+	andcc	%g1, 0x70, %g7
+	be,pn	%icc, copy_user_table_end
+	 andcc	%g1, 8, %g0
+101:
+	rd	%pc, %o5
+	srl	%g7, 1, %o4
+	add	%g7, %o4, %o4
+	add	%o1, %g7, %o1
+	sub	%o5, %o4, %o5
+	jmpl	%o5 + (copy_user_table_end - 101b), %g0
+	 add	%o0, %g7, %o0
+
+cannot_optimize:
+	bleu	short_end
+	 cmp	%o5, 2
+
+	bne	byte_chunk
+	 and	%o2, 0xfffffffffffffff0, %o3
+	 
+	andcc	%o1, 1, %g0
+	be	10f
+	 nop
+
+	ldub [%o1], %g2
+	add	%o1, 1, %o1
+	EXO2(stba %g2, [%o0] %asi,#)
+	sub	%o2, 1, %o2
+	andcc	%o2, 0xfffffffffffffff0, %o3
+	be	short_end
+	 add	%o0, 1, %o0
+10:
+	MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+	MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
+82:
+	EXT(10b, 82b, 53f,#)
+	subcc	%o3, 0x10, %o3
+	add	%o1, 0x10, %o1
+	bne	10b
+	 add	%o0, 0x10, %o0
+	ba,pt	%xcc, 2f
+	 and	%o2, 0xe, %o3
+	
+byte_chunk:
+	MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
+83:
+	EXT(byte_chunk, 83b, 54f,#)
+	subcc	%o3, 0x10, %o3
+	add	%o1, 0x10, %o1
+	bne,pt	%xcc, byte_chunk
+	 add	%o0, 0x10, %o0
+
+short_end:
+	and	%o2, 0xe, %o3
+2:
+	rd	%pc, %o5
+	sll	%o3, 3, %o4
+	add	%o0, %o3, %o0
+	sub	%o5, %o4, %o5
+	add	%o1, %o3, %o1
+	jmpl	%o5 + (short_table_end - 2b), %g0
+	 andcc	%o2, 1, %g0
+84:
+	MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
+short_table_end:
+	EXT(84b, short_table_end, 55f,#)
+	be	1f
+	 nop
+	ldub	[%o1], %g2
+	EX(stba	%g2, [%o0] %asi, add %g0, 1,#)
+1:
+	retl
+ 	 clr	%o0
+
+short_aligned_end:
+	bne	short_end
+	 andcc	%o2, 8, %g0
+
+	be	1f
+	 andcc	%o2, 4, %g0
+
+	ld	[%o1 + 0x00], %g2
+	ld	[%o1 + 0x04], %g3
+	add	%o1, 8, %o1
+	EXO2(sta %g2, [%o0 + 0x00] %asi,#)
+	EX(sta	%g3, [%o0 + 0x04] %asi, sub %o2, 4,#)
+	add	%o0, 8, %o0
+1:
+	ba,pt	%xcc, copy_user_last7
+	 mov	%o2, %g1
+
+	.section .fixup,#alloc,#execinstr
+	.align	4
+97:
+	retl
+	 mov	%o2, %o0
+/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
+50:
+/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
+ * happens. This is derived from the amount ldd reads, st stores, etc.
+ * x = g2 % 12;
+ * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4)
+ */
+	cmp	%g2, 12
+	bcs	1f
+	 cmp	%g2, 24
+	bcs	2f
+	 cmp	%g2, 36
+	bcs	3f
+	 nop
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+3:
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+2:
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+1:
+	cmp	%g2, 4
+	bcs,a	1f
+	 sll	%g2, 3, %g2
+	sub	%g2, 4, %g2
+	sll	%g2, 2, %g2
+1:
+	and	%g1, 0x7f, %o0
+	add	%o0, %g7, %o0
+	retl
+	 sub	%o0, %g2, %o0
+51:
+/* i = 41 - g2; j = i % 6;
+ * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8;	
+ */
+	neg	%g2
+	and	%g1, 0xf, %g1
+	add	%g2, 41, %g2
+1:
+	cmp	%g2, 6
+	bcs,a	2f
+	 cmp	%g2, 4
+	add	%g1, 16, %g1
+	b	1b
+	 sub	%g2, 6, %g2
+2:
+	bcs,a	3f
+	 inc	%g2
+	sub	%g2, 3, %g2
+	b	2f
+	 sll	%g2, 3, %g2
+3:
+	sll	%g2, 2, %g2
+2:
+	retl
+	 add	%g1, %g2, %o0
+52:
+/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */
+	and	%g2, 0xfffffffffffffff8, %g4
+	and	%g2, 3, %g2
+	sll	%g4, 2, %g4
+	sll	%g2, 3, %g2
+	add	%g2, %g4, %g2
+	b,a	1b
+53:
+/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */
+	and	%g2, 3, %g4
+	and	%g2, 0xfffffffffffffff8, %g2
+	sll	%g4, 1, %g4
+	add	%g2, %g4, %g2
+	and	%o2, 0xf, %o0
+	add	%o0, %o3, %o0
+	retl
+	 sub	%o0, %g2, %o0
+54:
+/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */
+	srl	%g2, 2, %o4
+	and	%g2, 1, %o1
+	sll	%o4, 1, %o4
+	and	%o2, 0xf, %o2
+	sub	%o3, %o1, %o3
+	sub	%o2, %o4, %o2
+	retl
+	 add	%o2, %o3, %o0
+55:
+/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */
+	neg	%g2
+	and	%o2, 1, %o2
+	add	%g2, 27, %g2
+	srl	%g2, 2, %o1
+	and	%g2, 1, %g2
+	sll	%o1, 1, %o1
+	add	%o2, %g2, %o0
+	retl
+	 add	%o0, %o1, %o0
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/memcmp.S linux/arch/sparc64/lib/memcmp.S
--- v2.1.33/linux/arch/sparc64/lib/memcmp.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/memcmp.S	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: memcmp.S,v 1.1 1997/03/14 21:04:23 jj Exp $
+/* $Id: memcmp.S,v 1.2 1997/04/01 03:43:18 davem Exp $
  * Sparc64 optimized memcmp code.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -20,7 +20,7 @@
 	brnz,pn	%o4, 3f
 	 addcc	%o3, 1, %o3
 	bne,a,pt %xcc, 1b
-	 ldub	[%o0 + %o3], %o5
+	 ldub	[%o0 + %o3], %o4
 2:
 	retl
 	 clr	%o0
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/memcpy.S linux/arch/sparc64/lib/memcpy.S
--- v2.1.33/linux/arch/sparc64/lib/memcpy.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/memcpy.S	Fri Apr 11 10:47:36 1997
@@ -394,21 +394,21 @@
 	lduw		[%o1], %o3
 	add		%o0, -8, %o0
 	lduw		[%o1 + 4], %o4
-	b		8f
+	ba,pt		%xcc, 8f
 	 add		%g3, 1, %g3
 2:
 	lduw		[%o1], %o4
 	add		%o0, -12, %o0
 	lduw		[%o1 + 4], %o5
 	add		%g3, 2, %g3
-	b		9f
+	ba,pt		%xcc, 9f
 	 add		%o1, -4, %o1
 3:
 	lduw		[%o1], %g1
 	add		%o0, -4, %o0
 	lduw		[%o1 + 4], %o3
 	srl		%o2, 2, %g3
-	b		7f
+	ba,pt		%xcc, 7f
 	 add		%o1, 4, %o1
 4:
 	lduw		[%o1], %o5
@@ -522,5 +522,5 @@
 	stw		%g3, [%o0 + 0x04]
 	add		%o0, 8, %o0
 1:
-	b		81b
+	ba,pt		%xcc, 81b
 	 mov		%o2, %g1
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/lib/memset.S linux/arch/sparc64/lib/memset.S
--- v2.1.33/linux/arch/sparc64/lib/memset.S	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/lib/memset.S	Fri Apr 11 10:47:36 1997
@@ -7,6 +7,7 @@
  * occurs and we were called as clear_user.
  */
 
+#include <asm/asi.h>
 #include <asm/ptrace.h>
 
 #define EX(x,y,a,b,z) 				\
@@ -32,29 +33,29 @@
  * in the .fixup section below as well.
  * Store 64 bytes at (BASE + OFFSET) using value SOURCE. */
 #define ZERO_BIG_BLOCK(base, offset, source)    \
-	stx	source, [base + offset + 0x00]; \
-	stx	source, [base + offset + 0x08]; \
-	stx	source, [base + offset + 0x10]; \
-	stx	source, [base + offset + 0x18]; \
-	stx	source, [base + offset + 0x20]; \
-	stx	source, [base + offset + 0x28]; \
-	stx	source, [base + offset + 0x30]; \
-	stx	source, [base + offset + 0x38];
+	stxa	source, [base + offset + 0x00] %asi; \
+	stxa	source, [base + offset + 0x08] %asi; \
+	stxa	source, [base + offset + 0x10] %asi; \
+	stxa	source, [base + offset + 0x18] %asi; \
+	stxa	source, [base + offset + 0x20] %asi; \
+	stxa	source, [base + offset + 0x28] %asi; \
+	stxa	source, [base + offset + 0x30] %asi; \
+	stxa	source, [base + offset + 0x38] %asi;
 
 #define ZERO_LAST_BLOCKS(base, offset, source)	\
-	stx	source, [base - offset - 0x38]; \
-	stx	source, [base - offset - 0x30]; \
-	stx	source, [base - offset - 0x28]; \
-	stx	source, [base - offset - 0x20]; \
-	stx	source, [base - offset - 0x18]; \
-	stx	source, [base - offset - 0x10]; \
-	stx	source, [base - offset - 0x08]; \
-	stx	source, [base - offset - 0x00];
+	stxa	source, [base - offset - 0x38] %asi; \
+	stxa	source, [base - offset - 0x30] %asi; \
+	stxa	source, [base - offset - 0x28] %asi; \
+	stxa	source, [base - offset - 0x20] %asi; \
+	stxa	source, [base - offset - 0x18] %asi; \
+	stxa	source, [base - offset - 0x10] %asi; \
+	stxa	source, [base - offset - 0x08] %asi; \
+	stxa	source, [base - offset - 0x00] %asi;
 
 	.text
 	.align 4
 
-	.globl	__bzero, __memset
+	.globl	__bzero, __memset, __bzero_noasi
 	.globl	memset, __memset_start, __memset_end
 __memset_start:
 __memset:
@@ -65,10 +66,13 @@
 	sll	%g3, 16, %g2
 	or	%g3, %g2, %g3
 	mov	%o2, %o1
+	wr	%g0, ASI_P, %asi
 	sllx	%g3, 32, %g2
 	ba,pt	%xcc, 1f
 	 or	%g3, %g2, %g3
 __bzero:
+	wr	%g0, ASI_P, %asi
+__bzero_noasi:
 	mov	%g0, %g3
 1:
 	cmp	%o1, 7
@@ -80,13 +84,13 @@
 
 	cmp	%o2, 3
 	be,pn	%icc, 2f
-	 EX(stb	%g3, [%o0], sub %o1, 0,#)
+	 EX(stba	%g3, [%o0] %asi, sub %o1, 0,#)
 
 	cmp	%o2, 2
 	be,pt	%icc, 2f
-	 EX(stb	%g3, [%o0 + 0x01], sub %o1, 1,#)
+	 EX(stba	%g3, [%o0 + 0x01] %asi, sub %o1, 1,#)
 
-	EX(stb	%g3, [%o0 + 0x02], sub %o1, 2,#)
+	EX(stba	%g3, [%o0 + 0x02] %asi, sub %o1, 2,#)
 2:
 	sub	%o2, 4, %o2
 	sub	%o0, %o2, %o0
@@ -96,7 +100,7 @@
 	be,a,pt	%icc, 2f
 	 andncc	%o1, 0x7f, %o3
 
-	EX(st	%g3, [%o0], sub %o1, 0,#)
+	EX(sta	%g3, [%o0] %asi, sub %o1, 0,#)
 	sub	%o1, 4, %o1
 	add	%o0, 4, %o0
 	andncc	%o1, 0x7f, %o3		! Now everything is 8 aligned and o1 is len to run
@@ -132,17 +136,17 @@
 	be,pn	%icc, 1f
 	 andcc	%o1, 2, %g0
 
-	EX(st	%g3, [%o0], and %o1, 7,#)
+	EX(sta	%g3, [%o0] %asi, and %o1, 7,#)
 	add	%o0, 4, %o0
 1:
 	be,pn	%icc, 1f
 	 andcc	%o1, 1, %g0
 
-	EX(sth	%g3, [%o0], and %o1, 3,#)
+	EX(stha	%g3, [%o0] %asi, and %o1, 3,#)
 	add	%o0, 2, %o0
 1:
 	bne,a,pn %icc, 8f
-	 EX(stb	%g3, [%o0], and %o1, 1,#)
+	 EX(stba	%g3, [%o0] %asi, and %o1, 1,#)
 8:
 	retl
 	 clr	%o0
@@ -155,7 +159,7 @@
 	 add	%o0, 1, %o0
 	subcc	%o1, 1, %o1
 	bne,a,pt %icc, 8b
-	 EX(stb	%g3, [%o0 - 1], add %o1, 1,#)
+	 EX(stba	%g3, [%o0 - 1] %asi, add %o1, 1,#)
 0:
 	retl
 	 clr	%o0
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.1.33/linux/arch/sparc64/mm/init.c	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/mm/init.c	Mon Apr 14 09:31:09 1997
@@ -1,7 +1,7 @@
-/*  $Id: init.c,v 1.4 1997/03/18 17:59:48 jj Exp $
+/*  $Id: init.c,v 1.22 1997/04/12 04:28:48 davem Exp $
  *  arch/sparc64/mm/init.c
  *
- *  Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
  *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
  
@@ -13,12 +13,25 @@
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/iommu.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/vaddrs.h>
 
 extern void show_net_buffers(void);
 extern unsigned long device_scan(unsigned long);
 
 struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 
+/* Ugly, but necessary... -DaveM */
+unsigned long phys_base, null_pmd_table, null_pte_table;
+
+extern unsigned long empty_null_pmd_table;
+extern unsigned long empty_null_pte_table;
+
+unsigned long tlb_context_cache = CTX_FIRST_VERSION;
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -32,16 +45,25 @@
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-pmd_t *__bad_pagetable(void)
+pmd_t *__bad_pmd(void)
+{
+	pmd_t *pmdp = (pmd_t *) &empty_bad_pmd_table;
+
+	__init_pmd(pmdp);
+	return pmdp;
+}
+
+pte_t *__bad_pte(void)
 {
-	memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
-	return (pmd_t *) EMPTY_PGT;
+	memset((void *) &empty_bad_pte_table, 0, PAGE_SIZE);
+	return (pte_t *) (((unsigned long)&empty_bad_pte_table) + phys_base);
 }
 
 pte_t __bad_page(void)
 {
-	memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
-	return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
+	memset((void *) &empty_bad_page, 0, PAGE_SIZE);
+	return pte_mkdirty(mk_pte((((unsigned long) &empty_bad_page)+phys_base),
+				  PAGE_SHARED));
 }
 
 void show_mem(void)
@@ -57,10 +79,10 @@
 		total++;
 		if (PageReserved(mem_map + i))
 			reserved++;
-		else if (!mem_map[i].count)
+		else if (!atomic_read(&mem_map[i].count))
 			free++;
 		else
-			shared += mem_map[i].count-1;
+			shared += atomic_read(&mem_map[i].count) - 1;
 	}
 	printk("%d pages of RAM\n",total);
 	printk("%d free pages\n",free);
@@ -72,33 +94,520 @@
 #endif
 }
 
-__initfunc(unsigned long sparc_context_init(unsigned long start_mem, int numctx))
+/* IOMMU support, the ideas are right, the code should be cleaned a bit still... */
+
+/* XXX Also, play with the streaming buffers at some point, both
+ * XXX Fusion and Sunfire both have them aparently... -DaveM
+ */
+
+/* This keeps track of pages used in sparc_alloc_dvma() invocations. */
+static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, };
+static unsigned long dvma_pages_current_offset = 0;
+static int dvma_pages_current_index = 0;
+
+__initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
+				    unsigned long memory_end, struct linux_sbus *sbus))
+{
+	struct iommu_struct *iommu;
+	struct sysio_regs *sregs;
+	struct linux_prom_registers rprop[2];
+	unsigned long impl, vers;
+	unsigned long control, tsbbase;
+	unsigned long *iopte;
+	int err, i;
+
+	err = prom_getproperty(iommu_node, "reg", (char *)rprop,
+			       sizeof(rprop));
+	if(err == -1) {
+		prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
+		prom_halt();
+	}
+	sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr,
+						     (void *)0,
+						     sizeof(struct sysio_regs),
+						     "SYSIO Regs",
+						     rprop[0].which_io, 0x0);
+
+	memory_start = (memory_start + 7) & ~7;
+	iommu = (struct iommu_struct *) memory_start;
+	memory_start += sizeof(struct iommu_struct);
+	iommu->sysio_regs = sregs;
+	sbus->iommu = iommu;
+
+	control = sregs->iommu_control;
+	impl = (control & IOMMU_CTRL_IMPL) >> 60;
+	vers = (control & IOMMU_CTRL_VERS) >> 56;
+	printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+	       (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
+	
+	control &= ~(IOMMU_CTRL_TSBSZ);
+	control |= (IOMMU_TSBSZ_64K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+
+	/* Use only 64k pages, things are layed out in the 32-bit SBUS
+	 * address space like this:
+	 *
+	 * 0x00000000	----------------------------------------
+	 *		| Direct physical mappings for most    |
+	 *              | DVMA to paddr's within this range    |
+	 * 0xf0000000   ----------------------------------------
+	 * 		| For mappings requested via           |
+	 *              | sparc_alloc_dvma()		       |
+	 * 0xffffffff	----------------------------------------
+	 */
+	tsbbase = PAGE_ALIGN(memory_start);
+	memory_start = (tsbbase + ((64 * 1024) * 8));
+	iommu->page_table = (iopte_t *) tsbbase;
+	iopte = (unsigned long *) tsbbase;
+
+	/* Setup aliased mappings... */
+	for(i = 0; i < (65536 - 4096); i++) {
+		*iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+		*iopte |= (i << 16);
+		iopte++;
+	}
+
+	/* Clear all sparc_alloc_dvma() maps. */
+	for( ; i < 65536; i++)
+		*iopte++ = 0;
+
+	sregs->iommu_tsbbase = __pa(tsbbase);
+	sregs->iommu_control = control;
+
+	return memory_start;
+}
+
+void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
+{
+	struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	/* Find out if we need to grab some pages. */
+	if(!dvma_map_pages[dvma_pages_current_index] ||
+	   ((dvma_pages_current_offset + len) > (1 << 16))) {
+		unsigned long *iopte;
+		unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0);
+		int i;
+
+		if(!newpages)
+			panic("AIEEE cannot get DVMA pages.");
+
+		memset((char *)newpages, 0, (1 << 16));
+
+		if(!dvma_map_pages[dvma_pages_current_index]) {
+			dvma_map_pages[dvma_pages_current_index] = newpages;
+			i = dvma_pages_current_index;
+		} else {
+			dvma_map_pages[dvma_pages_current_index + 1] = newpages;
+			i = dvma_pages_current_index + 1;
+		}
+
+		/* Stick it in the IOMMU. */
+		i = (65536 - 4096) + i;
+		iopte = (unsigned long *)(iommu->page_table + i);
+		*iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+		*iopte |= __pa(newpages);
+	}
+
+	/* Get this out of the way. */
+	*dvma_addr = (__u32) ((0xf0000000) +
+			      (dvma_pages_current_index << 16) +
+			      (dvma_pages_current_offset));
+
+	while(len > 0) {
+		while((len > 0) && (dvma_pages_current_offset < (1 << 16))) {
+			pte_t pte;
+			unsigned long the_page =
+				dvma_map_pages[dvma_pages_current_index] +
+				dvma_pages_current_offset;
+
+			/* Map the CPU's view. */
+			pgdp = pgd_offset(init_task.mm, addr);
+			pmdp = pmd_alloc_kernel(pgdp, addr);
+			ptep = pte_alloc_kernel(pmdp, addr);
+			pte = mk_pte(the_page, PAGE_KERNEL);
+			set_pte(ptep, pte);
+
+			dvma_pages_current_offset += PAGE_SIZE;
+			addr += PAGE_SIZE;
+			len -= PAGE_SIZE;
+		}
+		dvma_pages_current_index++;
+		dvma_pages_current_offset = 0;
+	}
+}
+
+__u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+	__u32 sbus_addr = (__u32) __pa(vaddr);
+
+	if((sbus_addr < 0xf0000000) &&
+	   ((sbus_addr + len) < 0xf0000000))
+		return sbus_addr;
+
+	/* "can't happen"... GFP_DMA assures this. */
+	panic("Very high scsi_one mappings should never happen.");
+        return (__u32)0;
+}
+
+void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+	while(sz >= 0) {
+		__u32 page = (__u32) __pa(((unsigned long) sg[sz].addr));
+		if((page < 0xf0000000) &&
+		   (page + sg[sz].len) < 0xf0000000) {
+			sg[sz].dvma_addr = page;
+		} else {
+			/* "can't happen"... GFP_DMA assures this. */
+			panic("scsi_sgl high mappings should never happen.");
+		}
+		sz--;
+	}
+}
+
+char *mmu_info(void)
+{
+	return "MMU Type: Spitfire\n\tFIXME: Write this\n";
+}
+
+static unsigned long mempool;
+
+struct linux_prom_translation {
+	unsigned long virt;
+	unsigned long size;
+	unsigned long data;
+};
+
+#define MAX_TRANSLATIONS 64
+static void inherit_prom_mappings(void)
 {
-	int ctx;
+	struct linux_prom_translation transl[MAX_TRANSLATIONS];
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	int node, n, i;
+
+	node = prom_finddevice("/virtual-memory");
+	if ((n = prom_getproperty(node, "translations", (char *) transl,
+				  sizeof(transl))) == -1) {
+		prom_printf("Couldn't get translation property\n");
+		prom_halt();
+	}
+	n = n / sizeof(transl[0]);
 
-	ctx_list_pool = (struct ctx_list *) start_mem;
-	start_mem += (numctx * sizeof(struct ctx_list));
-	/* Context 0 is reserved for PROM and uaccess stuff */
-	for(ctx = 1; ctx < numctx; ctx++) {
-		struct ctx_list *clist;
-
-		clist = (ctx_list_pool + ctx);
-		clist->ctx_number = ctx;
-		clist->ctx_mm = 0;
-	}
-	ctx_free.next = ctx_free.prev = &ctx_free;
-	ctx_used.next = ctx_used.prev = &ctx_used;
-	for(ctx = 1; ctx < numctx; ctx++)
-		add_to_free_ctxlist(ctx_list_pool + ctx);
-	return start_mem;
+	for (i = 0; i < n; i++) {
+		unsigned long vaddr;
+		
+		if (transl[i].virt >= 0xf0000000 && transl[i].virt < 0x100000000) {
+			for (vaddr = transl[i].virt;
+			     vaddr < transl[i].virt + transl[i].size;
+			     vaddr += PAGE_SIZE) {
+				pgdp = pgd_offset(init_task.mm, vaddr);
+				if (pgd_none(*pgdp)) {
+					pmdp = sparc_init_alloc(&mempool,
+							 PMD_TABLE_SIZE);
+					__init_pmd(pmdp);
+					pgd_set(pgdp, pmdp);
+				}
+				pmdp = pmd_offset(pgdp, vaddr);
+				if (pmd_none(*pmdp)) {
+					ptep = sparc_init_alloc(&mempool,
+							 PTE_TABLE_SIZE);
+					pmd_set(pmdp, ptep);
+				}
+				ptep = pte_offset(pmdp, vaddr);
+				set_pte (ptep, __pte(transl[i].data | _PAGE_MODIFIED));
+				transl[i].data += PAGE_SIZE;
+			}
+		}
+	}
+}
+
+static void inherit_locked_prom_mappings(void)
+{
+	int i;
+	int dtlb_seen = 0;
+	int itlb_seen = 0;
+
+	/* Fucking losing PROM has more mappings in the TLB, but
+	 * it (conveniently) fails to mention any of these in the
+	 * translations property.  The only ones that matter are
+	 * the locked PROM tlb entries, so we impose the following
+	 * irrecovable rule on the PROM, it is allowed 1 locked
+	 * entry in the ITLB and 1 in the DTLB.  We move those
+	 * (if necessary) up into tlb entry 62.
+	 *
+	 * Supposedly the upper 16GB of the address space is
+	 * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED
+	 * SOMEWHERE!!!!!!!!!!!!!!!!!  Furthermore the entire interface
+	 * used between the client program and the firmware on sun5
+	 * systems to coordinate mmu mappings is also COMPLETELY
+	 * UNDOCUMENTED!!!!!! Thanks S(t)un!
+	 */
+	for(i = 0; i < 62; i++) {
+		unsigned long data;
+
+		data = spitfire_get_dtlb_data(i);
+		if(!dtlb_seen && (data & _PAGE_L)) {
+			unsigned long tag = spitfire_get_dtlb_tag(i);
+			__asm__ __volatile__("stxa %%g0, [%0] %1"
+					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+			membar("#Sync");
+			spitfire_put_dtlb_data(i, 0x0UL);
+			membar("#Sync");
+
+			/* Re-install it. */
+			__asm__ __volatile__("stxa %0, [%1] %2"
+					     : : "r" (tag), "r" (TLB_TAG_ACCESS),
+					         "i" (ASI_DMMU));
+			membar("#Sync");
+			spitfire_put_dtlb_data(62, data);
+			membar("#Sync");
+			dtlb_seen = 1;
+			if(itlb_seen)
+				break;
+		}
+		data = spitfire_get_itlb_data(i);
+		if(!itlb_seen && (data & _PAGE_L)) {
+			unsigned long tag = spitfire_get_itlb_tag(i);
+			__asm__ __volatile__("stxa %%g0, [%0] %1"
+					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+			membar("#Sync");
+			spitfire_put_itlb_data(i, 0x0UL);
+			membar("#Sync");
+
+			/* Re-install it. */
+			__asm__ __volatile__("stxa %0, [%1] %2"
+					     : : "r" (tag), "r" (TLB_TAG_ACCESS),
+					         "i" (ASI_IMMU));
+			membar("#Sync");
+			spitfire_put_itlb_data(62, data);
+			membar("#Sync");
+			itlb_seen = 1;
+			if(dtlb_seen)
+				break;
+		}
+	}
+}
+
+__initfunc(static void
+allocate_ptable_skeleton(unsigned long start, unsigned long end))
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	while (start < end) {
+		pgdp = pgd_offset(init_task.mm, start);
+		if (pgd_none(*pgdp)) {
+			pmdp = sparc_init_alloc(&mempool,
+						PMD_TABLE_SIZE);
+			__init_pmd(pmdp);
+			pgd_set(pgdp, pmdp);
+		}
+		pmdp = pmd_offset(pgdp, start);
+		if (pmd_none(*pmdp)) {
+			ptep = sparc_init_alloc(&mempool,
+						PTE_TABLE_SIZE);
+			pmd_set(pmdp, ptep);
+		}
+		start = (start + PMD_SIZE) & PMD_MASK;
+	}
+}
+
+/*
+ * Create a mapping for an I/O register.  Have to make sure the side-effect
+ * bit is set.
+ */
+ 
+void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
+			   int bus, int rdonly)
+{
+	pgd_t *pgdp = pgd_offset(init_task.mm, virt_addr);
+	pmd_t *pmdp = pmd_offset(pgdp, virt_addr);
+	pte_t *ptep = pte_offset(pmdp, virt_addr);
+	pte_t pte;
+
+	physaddr &= PAGE_MASK;
+
+	if(rdonly)
+		pte = mk_pte_phys(physaddr, __pgprot(pg_iobits));
+	else
+		pte = mk_pte_phys(physaddr, __pgprot(pg_iobits | __DIRTY_BITS));
+
+#if 0
+	prom_printf("IOMAP: vaddr[%016lx]paddr[%016lx]ptep[%016lx]pte[%016lx])\n",
+		    virt_addr, physaddr, (unsigned long) ptep, pte_val(pte));
+	prom_printf("IOMAP: pgd[%016lx,%016lx]\n",
+		    (unsigned long) pgdp, pgd_val(*pgdp));
+	prom_printf("IOMAP: pmd[%016lx,%016lx]\n",
+		    (unsigned long) pmdp, pmd_val(*pmdp));
+#endif
+
+	set_pte(ptep, pte);
+}
+
+void sparc_ultra_unmapioaddr(unsigned long virt_addr)
+{
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+
+	pgdp = pgd_offset(init_task.mm, virt_addr);
+	pmdp = pmd_offset(pgdp, virt_addr);
+	ptep = pte_offset(pmdp, virt_addr);
+
+	/* No need to flush uncacheable page. */
+	pte_clear(ptep);
+}
+
+void sparc_ultra_dump_itlb(void)
+{
+        int slot;
+
+        prom_printf ("Contents of itlb:\n");
+        for (slot = 0; slot < 64; slot+=2) {
+        	prom_printf ("%2x:%016lx,%016lx    %2x:%016lx,%016lx\n", 
+        		slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
+        		slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1));
+        }
+}
+
+void sparc_ultra_dump_dtlb(void)
+{
+        int slot;
+
+        prom_printf ("Contents of dtlb:\n");
+        for (slot = 0; slot < 64; slot+=2) {
+        	prom_printf ("%2x:%016lx,%016lx    %2x:%016lx,%016lx\n", 
+        		slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
+        		slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1));
+        }
 }
 
 /* paging_init() sets up the page tables */
 
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
 __initfunc(unsigned long 
 paging_init(unsigned long start_mem, unsigned long end_mem))
 {
-	return device_scan (start_mem);
+	extern unsigned long __p1275_loc;
+	extern unsigned long phys_base;
+	extern void setup_tba(unsigned long kpgdir);
+	extern void __bfill64(void *, unsigned long);
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep, pte;
+	int i;
+
+	/* Must create 2nd locked DTLB entry if physical ram starts at
+	 * 4MB absolute or higher, kernel image has been placed in the
+	 * right place at PAGE_OFFSET but references to start_mem and pages
+	 * will be to the perfect alias mapping, so set it up now.
+	 */
+	if(phys_base >= (4 * 1024 * 1024)) {
+		unsigned long alias_base = phys_base + PAGE_OFFSET;
+		unsigned long pte;
+		unsigned long flags;
+
+		/* We assume physical memory starts at some 4mb multiple,
+		 * if this were not true we wouldn't boot up to this point
+		 * anyways.
+		 */
+		pte  = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
+		pte |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
+		save_flags(flags); cli();
+		__asm__ __volatile__("
+		stxa	%1, [%0] %3
+		stxa	%2, [%5] %4
+		membar	#Sync
+		flush	%%g4
+		nop
+		nop
+		nop"
+		: /* No outputs */
+		: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pte),
+		  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
+		: "memory");
+		restore_flags(flags);
+
+		/* Now set kernel pgd to upper alias so physical page computations
+		 * work.
+		 */
+		init_mm.pgd += (phys_base / (sizeof(pgd_t *)));
+	}
+
+	null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + phys_base);
+	null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + phys_base);
+
+	pmdp = (pmd_t *) &empty_null_pmd_table;
+	for(i = 0; i < 1024; i++)
+		pmd_val(pmdp[i]) = null_pte_table;
+
+	memset((void *) &empty_null_pte_table, 0, PAGE_SIZE);
+
+	/* Now can init the kernel/bad page tables. */
+	__bfill64((void *)swapper_pg_dir, null_pmd_table);
+	__bfill64((void *)&empty_bad_pmd_table, null_pte_table);
+
+	/* We use mempool to create page tables, therefore adjust it up
+	 * such that __pa() macros etc. work.
+	 */
+	mempool = PAGE_ALIGN(start_mem) + phys_base;
+
+	/* FIXME: This should be done much nicer.
+	 * Just now we allocate 64M for each.
+	 */
+	allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_VADDR + 0x4000000);
+	allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000);
+	inherit_prom_mappings();
+	allocate_ptable_skeleton(0, 0x8000 + PAGE_SIZE);
+
+	/* Map prom interface page. */
+	pgdp = pgd_offset(init_task.mm, 0x8000);
+	pmdp = pmd_offset(pgdp, 0x8000);
+	ptep = pte_offset(pmdp, 0x8000);
+	pte  = mk_pte(((unsigned long)&__p1275_loc)+phys_base, PAGE_KERNEL);
+	set_pte(ptep, pte);
+
+	/* Ok, we can use our TLB miss and window trap handlers safely. */
+	setup_tba((unsigned long)init_mm.pgd);
+
+	/* Kill locked PROM interface page mapping, the mapping will
+	 * re-enter on the next PROM interface call via our TLB miss
+	 * handlers.
+	 */
+	spitfire_flush_dtlb_primary_page(0x8000);
+	membar("#Sync");
+	spitfire_flush_itlb_primary_page(0x8000);
+	membar("#Sync");
+
+	/* Really paranoid. */
+	flushi(PAGE_OFFSET);
+	membar("#Sync");
+
+	/* Cleanup the extra locked TLB entry we created since we have the
+	 * nice TLB miss handlers of ours installed now.
+	 */
+	if(phys_base >= (4 * 1024 * 1024)) {
+		/* We only created DTLB mapping of this stuff. */
+		spitfire_flush_dtlb_nucleus_page(phys_base + PAGE_OFFSET);
+		membar("#Sync");
+
+		/* Paranoid */
+		flushi(PAGE_OFFSET);
+		membar("#Sync");
+	}
+
+	inherit_locked_prom_mappings();
+
+	flush_tlb_all();
+
+	start_mem = free_area_init(PAGE_ALIGN(mempool), end_mem);
+
+	return device_scan (PAGE_ALIGN (start_mem));
 }
 
 extern int min_free_pages;
@@ -110,10 +619,10 @@
 	unsigned long addr, tmp2 = 0;
 
 	for(addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
-		if(addr >= KERNBASE && addr < start_mem)
+		if(addr >= PAGE_OFFSET && addr < start_mem)
 			addr = start_mem;
 		for(tmp2=0; sp_banks[tmp2].num_bytes != 0; tmp2++) {
-			unsigned long phys_addr = (addr - PAGE_OFFSET);
+			unsigned long phys_addr = __pa(addr);
 			unsigned long base = sp_banks[tmp2].base_addr;
 			unsigned long limit = base + sp_banks[tmp2].num_bytes;
 
@@ -129,19 +638,17 @@
 	int codepages = 0;
 	int datapages = 0;
 	unsigned long tmp2, addr;
+	unsigned long data_end;
 	extern char etext;
 
-	/* Saves us work later. */
-	memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
-
 	end_mem &= PAGE_MASK;
 	max_mapnr = MAP_NR(end_mem);
 	high_memory = (void *) end_mem;
 
 	start_mem = PAGE_ALIGN(start_mem);
-	num_physpages = (start_mem - KERNBASE) >> PAGE_SHIFT;
+	num_physpages = (start_mem - phys_base - PAGE_OFFSET) >> PAGE_SHIFT;
 
-	addr = KERNBASE;
+	addr = PAGE_OFFSET;
 	while(addr < start_mem) {
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (initrd_below_start_ok && addr >= initrd_start && addr < initrd_end)
@@ -153,15 +660,16 @@
 	}
 
 	taint_real_pages(start_mem, end_mem);
+	data_end = start_mem - phys_base;
 	for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
 		if(PageReserved(mem_map + MAP_NR(addr))) {
-			if ((addr < (unsigned long) &etext) && (addr >= KERNBASE))
+			if ((addr < (unsigned long) &etext) && (addr >= PAGE_OFFSET))
 				codepages++;
-			else if((addr < start_mem) && (addr >= KERNBASE))
+			else if((addr < data_end) && (addr >= PAGE_OFFSET))
 				datapages++;
 			continue;
 		}
-		mem_map[MAP_NR(addr)].count = 1;
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
 		num_physpages++;
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (!initrd_start ||
@@ -172,7 +680,7 @@
 
 	tmp2 = nr_free_pages << PAGE_SHIFT;
 
-	printk("Memory: %luk available (%dk kernel code, %dk data) [%08lx,%08lx]\n",
+	printk("Memory: %luk available (%dk kernel code, %dk data) [%016lx,%016lx]\n",
 	       tmp2 >> 10,
 	       codepages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem);
@@ -182,6 +690,11 @@
 		min_free_pages = 16;
 	free_pages_low = min_free_pages + (min_free_pages >> 1);
 	free_pages_high = min_free_pages + min_free_pages;
+
+#if 0
+	printk("Done in mem_init() halting\n");
+	prom_cmdline();
+#endif
 }
 
 void free_initmem (void)
@@ -192,7 +705,7 @@
 	addr = (unsigned long)(&__init_begin);
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		mem_map[MAP_NR(addr)].count = 1;
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
 		free_page(addr);
 	}
 	printk ("Freeing unused kernel memory: %dk freed\n", (unsigned)((&__init_end - &__init_begin) >> 10));
@@ -211,9 +724,9 @@
 		if (PageReserved(mem_map + i))
 			continue;
 		val->totalram++;
-		if (!mem_map[i].count)
+		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += mem_map[i].count-1;
+		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/init.c linux/arch/sparc64/prom/init.c
--- v2.1.33/linux/arch/sparc64/prom/init.c	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/prom/init.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.6 1997/03/11 17:37:11 jj Exp $
+/* $Id: init.c,v 1.7 1997/03/24 17:43:59 jj Exp $
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
@@ -69,14 +69,11 @@
 		    ((buffer[6] - '0') << 8) |
 		    (buffer[8] - '0');
 		    
-	prom_printf ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4);
+	printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4);
 	
 	prom_meminit();
 
 	prom_ranges_init();
-
-	printk("PROMLIB: Sun IEEE Boot Prom %s\n",
-	       buffer + 4);
 
 	/* Initialization successful. */
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c
--- v2.1.33/linux/arch/sparc64/prom/misc.c	Mon Mar 17 14:54:24 1997
+++ linux/arch/sparc64/prom/misc.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.4 1997/03/04 16:27:11 jj Exp $
+/* $Id: misc.c,v 1.6 1997/04/10 05:13:05 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -40,6 +40,7 @@
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
  */
+/* XXX Fix the pre and post calls as it locks up my Ultra at the moment -DaveM */
 void
 prom_cmdline(void)
 {
@@ -48,20 +49,24 @@
 	extern void install_linux_ticker(void);
 	unsigned long flags;
     
-	kernel_enter_debugger();
+	/* kernel_enter_debugger(); */
 #ifdef CONFIG_SUN_CONSOLE
+#if 0
 	if(!serial_console)
 		console_restore_palette ();
 #endif
-	install_obp_ticker();
+#endif
+	/* install_obp_ticker(); */
 	save_flags(flags); cli();
 	p1275_cmd ("enter", P1275_INOUT(0,0));
 	restore_flags(flags);
-	install_linux_ticker();
+	/* install_linux_ticker(); */
 #ifdef CONFIG_SUN_CONSOLE
+#if 0
 	if(!serial_console)
 		set_palette ();
 #endif
+#endif
 }
 
 /* Drop into the prom, but completely terminate the program.
@@ -70,7 +75,9 @@
 void
 prom_halt(void)
 {
+again:
 	p1275_cmd ("exit", P1275_INOUT(0,0));
+	goto again; /* PROM is out to get me -DaveM */
 }
 
 /* Set prom sync handler to call function 'funcp'. */
@@ -118,4 +125,10 @@
 prom_getprev(void)
 {
 	return prom_prev;
+}
+
+/* Install Linux trap table so PROM uses that instead of it's own. */
+void prom_set_trap_table(unsigned long tba)
+{
+	p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c
--- v2.1.33/linux/arch/sparc64/prom/p1275.c	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/prom/p1275.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.7 1997/03/18 17:59:55 jj Exp $
+/* $Id: p1275.c,v 1.8 1997/04/03 09:29:21 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -10,8 +10,8 @@
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/spitfire.h>
 #include <asm/system.h>
+#include <asm/spitfire.h>
 #include <asm/pstate.h>
 
 /* If you change layout of this structure, please change the prom_doit
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/ranges.c linux/arch/sparc64/prom/ranges.c
--- v2.1.33/linux/arch/sparc64/prom/ranges.c	Thu Mar 27 14:40:01 1997
+++ linux/arch/sparc64/prom/ranges.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: ranges.c,v 1.2 1997/03/18 17:59:57 jj Exp $
+/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -66,7 +66,7 @@
 {
 }
 
-__initfunc(void prom_sbus_ranges_init(struct linux_sbus *sbus))
+__initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus))
 {
 	int success;
 	
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/prom/tree.c linux/arch/sparc64/prom/tree.c
--- v2.1.33/linux/arch/sparc64/prom/tree.c	Mon Mar 17 14:54:24 1997
+++ linux/arch/sparc64/prom/tree.c	Fri Apr 11 10:47:36 1997
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.4 1997/03/04 16:27:14 jj Exp $
+/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -18,12 +18,18 @@
  * direct descendent.
  */
 __inline__ int
+__prom_getchild(int node)
+{
+	return p1275_cmd ("child", P1275_INOUT(1, 1), node);
+}
+
+__inline__ int
 prom_getchild(int node)
 {
 	long cnode;
 
 	if(node == -1) return 0;
-	cnode = p1275_cmd ("child", P1275_INOUT(1, 1), node);
+	cnode = __prom_getchild(node);
 	if(cnode == -1) return 0;
 	return (int)cnode;
 }
@@ -43,12 +49,18 @@
  * at this level of depth in the tree.
  */
 __inline__ int
+__prom_getsibling(int node)
+{
+	return p1275_cmd ("peer", P1275_INOUT(1, 1), node);
+}
+
+__inline__ int
 prom_getsibling(int node)
 {
 	long sibnode;
 
 	if(node == -1) return 0;
-	sibnode = p1275_cmd ("peer", P1275_INOUT(1, 1), node);
+	sibnode = __prom_getsibling(node);
 	if(sibnode == -1) return 0;
 	return (int)sibnode;
 }
diff -u --recursive --new-file v2.1.33/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds
--- v2.1.33/linux/arch/sparc64/vmlinux.lds	Thu Mar 27 14:40:02 1997
+++ linux/arch/sparc64/vmlinux.lds	Fri Apr 11 10:47:36 1997
@@ -1,12 +1,12 @@
 /* ld script to make UltraLinux kernel */
 OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc")
-OUTPUT_ARCH(sparc:v9)
+OUTPUT_ARCH(sparc:v9a)
 ENTRY(_start)
 
 SECTIONS
 {
   empty_zero_page = 0xfffff80000000000;
-  empty_bad_page =  0xfffff80000002000;
+  swapper_pg_dir =  0xfffff80000002000;
   . = 0x4000;
   .text 0xfffff80000004000 :
   {
@@ -53,7 +53,15 @@
    *(.bss)
    *(COMMON)
    . = ALIGN(8192);
-   empty_bad_page_table = .;
+   empty_bad_pmd_table = .;
+   . += 8192;
+   empty_bad_pte_table = .;
+   . += 8192;
+   empty_null_pmd_table = .;
+   . += 8192;
+   empty_null_pte_table = .;
+   . += 8192;
+   empty_bad_page = .;
    . += 8192;
   }
   _end = . ;
diff -u --recursive --new-file v2.1.33/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.33/linux/drivers/block/floppy.c	Fri Apr  4 08:52:17 1997
+++ linux/drivers/block/floppy.c	Mon Apr 14 10:49:11 1997
@@ -1676,7 +1676,7 @@
 		} while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2);
 	}
 	if (handler) {
-		if(intr_count >= 2)
+		if (in_interrupt())
 			schedule_bh( (void *)(void *) handler);
 		else
 			handler();
diff -u --recursive --new-file v2.1.33/linux/drivers/cdrom/Makefile linux/drivers/cdrom/Makefile
--- v2.1.33/linux/drivers/cdrom/Makefile	Wed Dec 18 05:57:28 1996
+++ linux/drivers/cdrom/Makefile	Mon Apr 14 09:26:35 1997
@@ -153,10 +153,10 @@
 endif #CONFIG_BLK_DEV_IDECD
 
 ifdef USE_GENERIC_CD
-L_OBJS += cdrom.o
+LX_OBJS += cdrom.o
 else
   ifdef USE_MODULAR_GENERIC_CD
-  M_OBJS += cdrom.o
+  MX_OBJS += cdrom.o
   endif
 endif #The Makefile configuration for the generic cdrom interface
   
diff -u --recursive --new-file v2.1.33/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.33/linux/drivers/cdrom/cdrom.c	Fri Apr  4 08:52:18 1997
+++ linux/drivers/cdrom/cdrom.c	Mon Apr 14 09:38:37 1997
@@ -1,9 +1,9 @@
 /* cdrom.c. Common ioctl and open routines for various Linux cdrom drivers. -*- linux-c -*-
-   Copyright (c) 1996 David van Leeuwen. 
+   Copyright (c) 1996, 1997 David A. van Leeuwen.
 
    The routines in the file should provide an interface between
    software accessing cdroms and the various drivers that implement
-   specific hardware devices. 
+   specific hardware devices.
 
  */
 
@@ -21,9 +21,29 @@
 #include <linux/cdrom.h>
 #include <linux/ucdrom.h>
 
+/* define CHECKTYPE if you want to check for audio/data cdrom. You
+   must use cd player programs that respect the O_NONBLOCK option for
+   opening the cdrom-device for ioctl-commanding only. (See
+   Documentation/cdrom/cdrom-standard.tex). Patches for a number of cd
+   players (CDplayer-2.0, cd-console-1.1, workbone-2.3, cdtool-1.0,
+   cdp-0.33, cdplayer-0.4, cdthing-1.4, lyn0.8a, playcd-1.0) can be
+   found in directory
+
+	ftp://ftp.gwdg.de/pub/linux/cdrom/drivers/cm206/
+
+   A runtime configuration program "checktype.c" to allow for cdrom
+   medium type checking can be found at the same location.
+
+   In order to be able to get neat system errors like "No medium
+   found" or "Wrong medium type" upon attempting to mount/play an
+   empty slot, mount an audio disc or play a data disc, you need to
+   have a new libc.5.so.  */
+#undef CHECKTYPE
+
 #define FM_WRITE	0x2                 /* file mode write bit */
 
-#define VERSION "Generic CD-ROM driver, v 1.21 1996/11/08 03:24:49"
+#define VERSION "$Id: cdrom.c,v 1.7 1997/02/27 22:14:26 david Exp $"
+#define REVISION "$Revision: 1.7 $"
 
 /* Not-exported routines. */
 static int cdrom_open(struct inode *ip, struct file *fp);
@@ -34,19 +54,19 @@
 
 struct file_operations cdrom_fops =
 {
-        NULL,                           /* lseek */
-        block_read,                     /* read - general block-dev read */
-        block_write,                    /* write - general block-dev write */
-        NULL,                           /* readdir */
-        NULL,                           /* poll */
-        cdrom_ioctl,                    /* ioctl */
-        NULL,                           /* mmap */
-        cdrom_open,                     /* open */
-        cdrom_release,                  /* release */
-        NULL,                           /* fsync */
-        NULL,                           /* fasync */
-        cdrom_media_changed,            /* media_change */
-        NULL                            /* revalidate */
+	NULL,                           /* lseek */
+	block_read,                     /* read - general block-dev read */
+	block_write,                    /* write - general block-dev write */
+	NULL,                           /* readdir */
+	NULL,                           /* poll */
+	cdrom_ioctl,                    /* ioctl */
+	NULL,                           /* mmap */
+	cdrom_open,                     /* open */
+	cdrom_release,                  /* release */
+	NULL,                           /* fsync */
+	NULL,                           /* fasync */
+	cdrom_media_changed,            /* media_change */
+	NULL                            /* revalidate */
 };
 
 static struct cdrom_device_info *cdromdevs[MAX_BLKDEV] = {
@@ -62,68 +82,71 @@
 #define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
 
 /* We don't use $name$ yet, but it could be used for the /proc
- * filesystem in the future, or for other purposes.  
+ * filesystem in the future, or for other purposes.
  */
 int register_cdrom(struct cdrom_device_info *cdi, char *name)
 {
-        int major = MAJOR (cdi->dev);
-        struct cdrom_device_ops *cdo = cdi->ops;
-        int *change_capability = (int *)&cdo->capability; /* hack */
-
-        if (major < 0 || major >= MAX_BLKDEV)
-                return -1;
-        if (cdo->open == NULL || cdo->release == NULL)
-                return -2;
-        ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
-        ENSURE(lock_door, CDC_LOCK);
-        ENSURE(select_speed, CDC_SELECT_SPEED);
-        ENSURE(select_disc, CDC_SELECT_DISC);
-        ENSURE(get_last_session, CDC_MULTI_SESSION);
-        ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
-        ENSURE(media_changed, CDC_MEDIA_CHANGED);
-        if (cdromdevs[major]==NULL) cdo->n_minors = 0;
-        else cdo->n_minors++; 
-        cdi->next = cdromdevs[major];
-        cdromdevs[major] = cdi;
-        cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
-        cdi->mc_flags = 0;
-        return 0;
+	int major = MAJOR (cdi->dev);
+	struct cdrom_device_ops *cdo = cdi->ops;
+	int *change_capability = (int *)&cdo->capability; /* hack */
+
+	if (major < 0 || major >= MAX_BLKDEV)
+		return -1;
+	if (cdo->open == NULL || cdo->release == NULL)
+		return -2;
+	ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
+	ENSURE(lock_door, CDC_LOCK);
+	ENSURE(select_speed, CDC_SELECT_SPEED);
+	ENSURE(select_disc, CDC_SELECT_DISC);
+	ENSURE(get_last_session, CDC_MULTI_SESSION);
+	ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
+	ENSURE(media_changed, CDC_MEDIA_CHANGED);
+	if (cdromdevs[major]==NULL) cdo->n_minors = 0;
+	else cdo->n_minors++;
+	cdi->next = cdromdevs[major];
+	cdromdevs[major] = cdi;
+	cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
+#ifdef CHECKTYPE
+	cdi->options |= CDO_CHECK_TYPE;
+#endif
+	cdi->mc_flags = 0;
+	return 0;
 }
 #undef ENSURE
 
 int unregister_cdrom(struct cdrom_device_info *unreg)
 {
-        struct cdrom_device_info *cdi, *prev;
-        int major = MAJOR (unreg->dev);
+	struct cdrom_device_info *cdi, *prev;
+	int major = MAJOR (unreg->dev);
 
-        if (major < 0 || major >= MAX_BLKDEV)
-                return -1;
+	if (major < 0 || major >= MAX_BLKDEV)
+		return -1;
 
-        prev = NULL;
-        cdi = cdromdevs[major];
-        while (cdi != NULL && cdi->dev != unreg->dev) {
-                prev = cdi;
-                cdi = cdi->next;
-        }
-
-        if (cdi == NULL)
-                return -2;
-        if (prev)
-                prev->next = cdi->next;
-        else
-                cdromdevs[major] = cdi->next;
-        cdi->ops->n_minors--;
-        return 0;
+	prev = NULL;
+	cdi = cdromdevs[major];
+	while (cdi != NULL && cdi->dev != unreg->dev) {
+		prev = cdi;
+		cdi = cdi->next;
+	}
+
+	if (cdi == NULL)
+		return -2;
+	if (prev)
+		prev->next = cdi->next;
+	else
+		cdromdevs[major] = cdi->next;
+	cdi->ops->n_minors--;
+	return 0;
 }
 
 static
 struct cdrom_device_info *cdrom_find_device (kdev_t dev)
 {
-        struct cdrom_device_info *cdi = cdromdevs[MAJOR (dev)];
+	struct cdrom_device_info *cdi = cdromdevs[MAJOR (dev)];
 
-        while (cdi != NULL && cdi->dev != dev)
-                cdi = cdi->next;
-        return cdi;
+	while (cdi != NULL && cdi->dev != dev)
+		cdi = cdi->next;
+	return cdi;
 }
 
 /* We use the open-option O_NONBLOCK to indicate that the
@@ -141,83 +164,88 @@
 int cdrom_open(struct inode *ip, struct file *fp)
 {
 	kdev_t dev = ip->i_rdev;
-        struct cdrom_device_info *cdi = cdrom_find_device(dev);
-        int purpose = !!(fp->f_flags & O_NONBLOCK);
-        int ret=0;
-
-        if (cdi == NULL)
-                return -ENODEV;
-        if (fp->f_mode & FM_WRITE)
-                return -EROFS;				
-        purpose = purpose || !(cdi->options & CDO_USE_FFLAGS);
-        if (cdi->use_count || purpose) 
-                ret = cdi->ops->open(cdi, purpose); 
-        else 
-                ret = open_for_data(cdi);
-        if (!ret) cdi->use_count++;
-        return ret;
+	struct cdrom_device_info *cdi = cdrom_find_device(dev);
+	int purpose = !!(fp->f_flags & O_NONBLOCK);
+	int ret=0;
+
+	if (cdi == NULL)
+		return -ENODEV;
+	if (fp->f_mode & FM_WRITE)
+		return -EROFS;
+	purpose = purpose || !(cdi->options & CDO_USE_FFLAGS);
+	if (cdi->use_count || purpose)
+		ret = cdi->ops->open(cdi, purpose);
+	else
+		ret = open_for_data(cdi);
+	if (!ret) cdi->use_count++;
+	return ret;
 }
 
 static
 int open_for_data(struct cdrom_device_info * cdi)
 {
-        int ret;
-        struct cdrom_device_ops *cdo = cdi->ops;
-        if (cdo->drive_status != NULL) {
-                int ds = cdo->drive_status(cdi, CDSL_CURRENT);
-                if (ds == CDS_TRAY_OPEN) {
-                        /* can/may i close it? */
-                        if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
-                            cdi->options & CDO_AUTO_CLOSE) {
-                                if (cdo->tray_move(cdi,0))
-                                        return -EIO;
-                        } else
-                                return -ENXIO; /* can't close: too bad */
-                        ds = cdo->drive_status(cdi, CDSL_CURRENT);
-                        if (ds == CDS_NO_DISC)
-                                return -ENXIO;
-                }
-        }
-        if (cdo->disc_status != NULL) {
-                int ds = cdo->disc_status(cdi);
-                if (ds == CDS_NO_DISC)
-                        return -ENXIO;
-                if (cdi->options & CDO_CHECK_TYPE &&
-                    ds != CDS_DATA_1)
-                        return -ENODATA;
-        }
-        /* all is well, we can open the device */
-        ret = cdo->open(cdi, 0); /* open for data */
-        if (cdo->capability & ~cdi->mask & CDC_LOCK &&
-            cdi->options & CDO_LOCK)
-                cdo->lock_door(cdi, 1);
-        return ret;
+	int ret;
+	struct cdrom_device_ops *cdo = cdi->ops;
+	if (cdo->drive_status != NULL) {
+		int ds = cdo->drive_status(cdi, CDSL_CURRENT);
+		if (ds == CDS_TRAY_OPEN) {
+			/* can/may i close it? */
+			if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
+			    cdi->options & CDO_AUTO_CLOSE) {
+				if (cdo->tray_move(cdi,0))
+					return -EIO;
+			} else
+				return -ENOMEDIUM; /* can't close: too bad */
+			ds = cdo->drive_status(cdi, CDSL_CURRENT);
+			if (ds == CDS_NO_DISC)
+				return -ENOMEDIUM;
+		}
+	}
+	if (cdo->disc_status != NULL) {
+		int ds = cdo->disc_status(cdi);
+		if (ds == CDS_NO_DISC)
+			return -ENOMEDIUM;
+		if (cdi->options & CDO_CHECK_TYPE &&
+		    ds != CDS_DATA_1)
+			return -EMEDIUMTYPE;
+	}
+	/* all is well, we can open the device */
+	ret = cdo->open(cdi, 0); /* open for data */
+	if (cdo->capability & ~cdi->mask & CDC_LOCK &&
+	    cdi->options & CDO_LOCK)
+		cdo->lock_door(cdi, 1);
+	return ret;
 }
 
 /* Admittedly, the logic below could be performed in a nicer way. */
 static
 int cdrom_release(struct inode *ip, struct file *fp)
 {
-        kdev_t dev = ip->i_rdev;
-        struct cdrom_device_info *cdi = cdrom_find_device (dev);
-        struct cdrom_device_ops *cdo;
-	
-        if (cdi == NULL)
-                return 0;
-        cdo = cdi->ops;        
-        if (cdi->use_count == 1 &&      /* last process that closes dev*/
-            cdi->options & CDO_LOCK &&  
-            cdo->capability & ~cdi->mask & CDC_LOCK) 
-                cdo->lock_door(cdi, 0);
-        cdo->release(cdi);
-        if (cdi->use_count > 0) cdi->use_count--;
-        if (cdi->use_count == 0) {      /* last process that closes dev*/
-                sync_dev(dev);
-                invalidate_buffers(dev);
-                if (cdi->options & CDO_AUTO_EJECT &&
-                    cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
-                        cdo->tray_move(cdi, 1);
-        }
+	kdev_t dev = ip->i_rdev;
+	struct cdrom_device_info *cdi = cdrom_find_device (dev);
+	struct cdrom_device_ops *cdo;
+	int opened_for_data;
+
+	if (cdi == NULL)
+		return 0;
+	opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
+		!(fp && fp->f_flags & O_NONBLOCK);
+	cdo = cdi->ops;
+	if (cdi->use_count == 1 &&      /* last process that closes dev*/
+	    opened_for_data &&
+	    cdi->options & CDO_LOCK &&
+	    cdo->capability & ~cdi->mask & CDC_LOCK)
+		cdo->lock_door(cdi, 0);
+	cdo->release(cdi);
+	if (cdi->use_count > 0) cdi->use_count--;
+	if (cdi->use_count == 0) {      /* last process that closes dev*/
+		sync_dev(dev);
+		invalidate_buffers(dev);
+		if (opened_for_data &&
+		    cdi->options & CDO_AUTO_EJECT &&
+		    cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
+			cdo->tray_move(cdi, 1);
+	}
 	return 0;
 }
 
@@ -230,37 +258,37 @@
 static
 int media_changed(struct cdrom_device_info *cdi, int queue)
 {
-        unsigned int mask = (1 << (queue & 1));
-        int ret = !!(cdi->mc_flags & mask);
+	unsigned int mask = (1 << (queue & 1));
+	int ret = !!(cdi->mc_flags & mask);
 
-        /* changed since last call? */
-        if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
-                cdi->mc_flags = 0x3;    /* set bit on both queues */
-                ret |= 1;
-        }
-        cdi->mc_flags &= ~mask;         /* clear bit */
-        return ret;
+	/* changed since last call? */
+	if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
+		cdi->mc_flags = 0x3;    /* set bit on both queues */
+		ret |= 1;
+	}
+	cdi->mc_flags &= ~mask;         /* clear bit */
+	return ret;
 }
 
 static
 int cdrom_media_changed(kdev_t dev)
 {
-        struct cdrom_device_info *cdi = cdrom_find_device (dev);
-        if (cdi == NULL)
-                return -ENODEV;
-        if (cdi->ops->media_changed == NULL)
-                return -EINVAL;
-        return media_changed(cdi, 0);
+	struct cdrom_device_info *cdi = cdrom_find_device (dev);
+	if (cdi == NULL)
+		return -ENODEV;
+	if (cdi->ops->media_changed == NULL)
+		return -EINVAL;
+	return media_changed(cdi, 0);
 }
 
 /* Requests to the low-level drivers will /always/ be done in the
-   following format convention: 
+   following format convention:
 
    CDROM_LBA: all data-related requests.
-   CDROM_MSF: all audio-related requests. 
+   CDROM_MSF: all audio-related requests.
 
    However, a low-level implementation is allowed to refuse this
-   request, and return information in its own favorite format.  
+   request, and return information in its own favorite format.
 
    It doesn't make sense /at all/ to ask for a play_audio in LBA
    format, or ask for multi-session info in MSF format. However, for
@@ -271,22 +299,22 @@
 
 static
 void sanitize_format(union cdrom_addr *addr,
-                     u_char * curr, u_char requested)
+		     u_char * curr, u_char requested)
 {
-        if (*curr == requested)
-                return;                 /* nothing to be done! */
-        if (requested == CDROM_LBA) {
-                addr->lba = (int) addr->msf.frame +
-                        75 * (addr->msf.second - 2 + 60 * addr->msf.minute);
-        } else {                        /* CDROM_MSF */
-                int lba = addr->lba;
-                addr->msf.frame = lba % 75;
-                lba /= 75;
-                lba += 2;
-                addr->msf.second = lba % 60;
-                addr->msf.minute = lba / 60;
-        }
-        *curr = requested;
+	if (*curr == requested)
+		return;                 /* nothing to be done! */
+	if (requested == CDROM_LBA) {
+		addr->lba = (int) addr->msf.frame +
+			75 * (addr->msf.second - 2 + 60 * addr->msf.minute);
+	} else {                        /* CDROM_MSF */
+		int lba = addr->lba;
+		addr->msf.frame = lba % 75;
+		lba /= 75;
+		lba += 2;
+		addr->msf.second = lba % 60;
+		addr->msf.minute = lba / 60;
+	}
+	*curr = requested;
 }
 
 /* All checking and format change makes this code really hard to read!
@@ -296,7 +324,7 @@
  * shouldn't be in inner loops.
  */
 #define GETARG(type, x) { \
-        int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \
+	int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \
 	    if (ret) return ret; \
 	    copy_from_user(&x, (type *) arg, sizeof x); }
 #define PUTARG(type, x) { \
@@ -318,238 +346,286 @@
  * memory-verification is performed for these ioctls.
  */
 static
+int check_for_audio_disc(struct cdrom_device_info * cdi,
+			 struct cdrom_device_ops * cdo);
+
+static
 int cdrom_ioctl(struct inode *ip, struct file *fp,
-                unsigned int cmd, unsigned long arg)
+		unsigned int cmd, unsigned long arg)
 {
-        kdev_t dev = ip->i_rdev;
-        struct cdrom_device_info *cdi = cdrom_find_device (dev);
-        struct cdrom_device_ops *cdo;
-
-        if (cdi == NULL)
-                return -ENODEV;
-        cdo = cdi->ops;
-        /* the first few commands do not deal with audio capabilities, but
-           only with routines in cdrom device operations. */
-        switch (cmd) {
-                /* maybe we should order cases after statistics of use? */
-
-        case CDROMMULTISESSION: 
-        {
-                struct cdrom_multisession ms_info;
-                u_char requested_format;
-                if (!(cdo->capability & CDC_MULTI_SESSION))
-                        return -EINVAL;
-                GETARG(struct cdrom_multisession, ms_info);
-                requested_format = ms_info.addr_format;
-                ms_info.addr_format = CDROM_LBA;
-                cdo->get_last_session(cdi, &ms_info);
-                sanitize_format(&ms_info.addr, &ms_info.addr_format, 
-                                requested_format);
-                PUTARG(struct cdrom_multisession, ms_info);
-                return 0;
-        }
-                
-        case CDROMEJECT:
-                if (cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) {
+	kdev_t dev = ip->i_rdev;
+	struct cdrom_device_info *cdi = cdrom_find_device (dev);
+	struct cdrom_device_ops *cdo;
+
+	if (cdi == NULL)
+		return -ENODEV;
+	cdo = cdi->ops;
+	/* the first few commands do not deal with audio capabilities, but
+	   only with routines in cdrom device operations. */
+	switch (cmd) {
+		/* maybe we should order cases after statistics of use? */
+
+	case CDROMMULTISESSION:
+	{
+		struct cdrom_multisession ms_info;
+		u_char requested_format;
+		if (!(cdo->capability & CDC_MULTI_SESSION))
+			return -EINVAL;
+		GETARG(struct cdrom_multisession, ms_info);
+		requested_format = ms_info.addr_format;
+		ms_info.addr_format = CDROM_LBA;
+		cdo->get_last_session(cdi, &ms_info);
+		sanitize_format(&ms_info.addr, &ms_info.addr_format,
+				requested_format);
+		PUTARG(struct cdrom_multisession, ms_info);
+		return 0;
+	}
+
+	case CDROMEJECT:
+		if (cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) {
 			if (cdi->use_count == 1) {
-			        if (cdo->capability & ~cdi->mask & CDC_LOCK)
+				if (cdo->capability & ~cdi->mask & CDC_LOCK)
 					cdo->lock_door(cdi, 0);
 				return cdo->tray_move(cdi, 1);
 			} else
 				return -EBUSY;
 		} else
-                        return -EINVAL;
-		
-        case CDROMCLOSETRAY:
-                if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)
+			return -EINVAL;
+
+	case CDROMCLOSETRAY:
+		if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)
 			return cdo->tray_move(cdi, 0);
-                else
-                        return -EINVAL;
-                
-        case CDROMEJECT_SW:
-                cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
-                if (arg)
-                        cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
-                return 0;
-
-        case CDROM_MEDIA_CHANGED:
-        	if (cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED) {
-                	if (arg == CDSL_CURRENT)
-                        	return media_changed(cdi, 1);
-                	else if ((int)arg < cdi->capacity &&
-                                 cdo->capability & ~cdi->mask
-                                 &CDC_SELECT_DISC)
-                        	return cdo->media_changed (cdi, arg);
-                        else
-                        	return -EINVAL;
-                }
-                else
-                        return -EINVAL;
-                
-        case CDROM_SET_OPTIONS:
-                cdi->options |= (int) arg;
-                return cdi->options;
-		
-        case CDROM_CLEAR_OPTIONS:
-                cdi->options &= ~(int) arg;
-                return cdi->options;
-                
-        case CDROM_SELECT_SPEED:
-                if ((int)arg <= cdi->speed &&
-                    cdo->capability & ~cdi->mask & CDC_SELECT_SPEED)
-                        return cdo->select_speed(cdi, arg);
-                else
-                        return -EINVAL;
-
-        case CDROM_SELECT_DISC:
-                if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
-                	return cdo->select_disc(cdi, arg);
-                if ((int)arg < cdi->capacity &&
-                    cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+		else
+			return -EINVAL;
+
+	case CDROMEJECT_SW:
+		cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
+		if (arg)
+			cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
+		return 0;
+
+	case CDROM_MEDIA_CHANGED:
+		if (cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED) {
+			if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+			    || arg == CDSL_CURRENT)
+				/* cannot select disc or select current disc */
+				return media_changed(cdi, 1);
+			if ((unsigned int)arg < cdi->capacity)
+				return cdo->media_changed (cdi, arg);
+			return -EINVAL;
+		} else
+			return -EINVAL;
+
+	case CDROM_SET_OPTIONS:
+		cdi->options |= (int) arg;
+		return cdi->options;
+
+	case CDROM_CLEAR_OPTIONS:
+		cdi->options &= ~(int) arg;
+		return cdi->options;
+
+	case CDROM_SELECT_SPEED:
+		if ((int)arg <= cdi->speed &&
+		    cdo->capability & ~cdi->mask & CDC_SELECT_SPEED)
+			return cdo->select_speed(cdi, arg);
+		else
+			return -EINVAL;
+
+	case CDROM_SELECT_DISC:
+		if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
 			return cdo->select_disc(cdi, arg);
-                else
+		if ((int)arg < cdi->capacity &&
+		    cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+			return cdo->select_disc(cdi, arg);
+		else
 			return -EINVAL;
-		
+
 /* The following function is implemented, although very few audio
  * discs give Universal Product Code information, which should just be
  * the Medium Catalog Number on the box.  Note, that the way the code
  * is written on the CD is /not/ uniform across all discs!
  */
-        case CDROM_GET_MCN: {
-                struct cdrom_mcn mcn;
-                if (!(cdo->capability & CDC_MCN))
-                        return -EINVAL;
-                if (!cdo->get_mcn(cdi, &mcn)) {
-                        PUTARG(struct cdrom_mcn, mcn);
-                        return 0;
-                }
-                return -EINVAL;
-        }
-                
-        case CDROM_DRIVE_STATUS:
-                if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
-                	return cdo->drive_status(cdi, arg);
-                if (cdo->drive_status == NULL ||
-                            ! (cdo->capability & ~cdi->mask & CDC_SELECT_DISC
-                            && (int)arg < cdi->capacity)) 
-                	return -EINVAL;
-                else
+	case CDROM_GET_MCN: {
+		struct cdrom_mcn mcn;
+		if (!(cdo->capability & CDC_MCN))
+			return -EINVAL;
+		if (!cdo->get_mcn(cdi, &mcn)) {
+			PUTARG(struct cdrom_mcn, mcn);
+			return 0;
+		}
+		return -EINVAL;
+	}
+
+	case CDROM_DRIVE_STATUS:
+		if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
+			return cdo->drive_status(cdi, arg);
+		if (cdo->drive_status == NULL ||
+			    ((cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+			    && (int)arg >= cdi->capacity))
+			return -EINVAL;
+		else
 			return cdo->drive_status(cdi, arg);
-		
-        case CDROM_DISC_STATUS:
+
+	case CDROM_DISC_STATUS:
 		if (cdo->disc_status == NULL)
 			return -EINVAL;
 		else
 			return cdo->disc_status(cdi);
 
-        case CDROM_CHANGER_NSLOTS:
-        	return cdi->capacity;
+	case CDROM_CHANGER_NSLOTS:
+		return cdi->capacity;
 
 /* The following is not implemented, because there are too many
  * different data type. We could support /1/ raw mode, that is large
  * enough to hold everything.
  */
-		
+
 #if 0
-        case CDROMREADMODE1: {
-                struct cdrom_msf msf;
-                char buf[CD_FRAMESIZE];
-                GETARG(struct cdrom_msf, msf);
-                if (!cdo->read_audio(dev, cmd, &msf, &buf, cdi)) {
-                        PUTARG(char *, buf);
-                        return 0;
-                }
-                return -EINVAL;
-        }
+	case CDROMREADMODE1: {
+		struct cdrom_msf msf;
+		char buf[CD_FRAMESIZE];
+		GETARG(struct cdrom_msf, msf);
+		if (!cdo->read_audio(dev, cmd, &msf, &buf, cdi)) {
+			PUTARG(char *, buf);
+			return 0;
+		}
+		return -EINVAL;
+	}
 #endif
 	} /* switch */
-	
+
 /* Now all the audio-ioctls follow, they are all routed through the
    same call audio_ioctl(). */
 
-	if (cdo->capability & CDC_PLAY_AUDIO)
+#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret
+
+	if (cdo->capability & CDC_PLAY_AUDIO) {
+		int ret;
 		switch (cmd) {
-                case CDROMSUBCHNL: 
-                {
-                        struct cdrom_subchnl q;
-                        u_char requested, back;
-                        GETARG(struct cdrom_subchnl, q);
-                        requested = q.cdsc_format;
-                        q.cdsc_format = CDROM_MSF;
-                        if (!cdo->audio_ioctl(cdi, cmd, &q)) {
-                                back = q.cdsc_format; /* local copy */
-                                sanitize_format(&q.cdsc_absaddr, &back,
-                                requested);
-                                sanitize_format(&q.cdsc_reladdr,
-                                &q.cdsc_format, requested);
-                                PUTARG(struct cdrom_subchnl, q);
-                                return 0;
-                        } else
-                                return -EINVAL;
-                }
-                case CDROMREADTOCHDR: {
-                        struct cdrom_tochdr header;
-                        GETARG(struct cdrom_tochdr, header);
-                        if (!cdo->audio_ioctl(cdi, cmd, &header)) {
-                                PUTARG(struct cdrom_tochdr, header);
-                                return 0;
-                        } else
-                                return -EINVAL;
-                }
-                case CDROMREADTOCENTRY: {
-                        struct cdrom_tocentry entry;
-                        u_char requested_format;
-                        GETARG(struct cdrom_tocentry, entry);
-                        requested_format = entry.cdte_format;
-                        /* make interface to low-level uniform */
-                        entry.cdte_format = CDROM_MSF; 
-                        if (!(cdo->audio_ioctl(cdi, cmd, &entry))) {
-                                sanitize_format(&entry.cdte_addr,
-                                &entry.cdte_format, requested_format);
-                                PUTARG(struct cdrom_tocentry, entry);
-                                return 0;
-                        } else
-                                return -EINVAL;
-                }
-                case CDROMPLAYMSF: {
-                        struct cdrom_msf msf;
-                        GETARG(struct cdrom_msf, msf);
-                        return cdo->audio_ioctl(cdi, cmd, &msf);
-                }
-                case CDROMPLAYTRKIND: {
-                        struct cdrom_ti track_index;
-                        GETARG(struct cdrom_ti, track_index);
-                        return cdo->audio_ioctl(cdi, cmd, &track_index);
-                }
-                case CDROMVOLCTRL: {
-                        struct cdrom_volctrl volume;
-                        GETARG(struct cdrom_volctrl, volume);
-                        return cdo->audio_ioctl(cdi, cmd, &volume);
-                }
-                case CDROMVOLREAD: {
-                        struct cdrom_volctrl volume;
-                        if (!cdo->audio_ioctl(cdi, cmd, &volume)) {
-                                PUTARG(struct cdrom_volctrl, volume);
-                                return 0;
-                        }
-                        return -EINVAL;
-                }
-                case CDROMSTART:
-                case CDROMSTOP:
-                case CDROMPAUSE:
-                case CDROMRESUME:
+		case CDROMSUBCHNL:
+		{
+			struct cdrom_subchnl q;
+			u_char requested, back;
+			GETARG(struct cdrom_subchnl, q);
+			requested = q.cdsc_format;
+			q.cdsc_format = CDROM_MSF;
+			if (!cdo->audio_ioctl(cdi, cmd, &q)) {
+				back = q.cdsc_format; /* local copy */
+				sanitize_format(&q.cdsc_absaddr, &back,
+				requested);
+				sanitize_format(&q.cdsc_reladdr,
+				&q.cdsc_format, requested);
+				PUTARG(struct cdrom_subchnl, q);
+				return 0;
+			} else
+				return -EINVAL;
+		}
+		case CDROMREADTOCHDR: {
+			struct cdrom_tochdr header;
+			GETARG(struct cdrom_tochdr, header);
+			CHECKAUDIO;
+			if (!cdo->audio_ioctl(cdi, cmd, &header)) {
+				PUTARG(struct cdrom_tochdr, header);
+				return 0;
+			} else
+				return -EINVAL;
+		}
+		case CDROMREADTOCENTRY: {
+			struct cdrom_tocentry entry;
+			u_char requested_format;
+			GETARG(struct cdrom_tocentry, entry);
+			requested_format = entry.cdte_format;
+			/* make interface to low-level uniform */
+			entry.cdte_format = CDROM_MSF;
+			if (!(cdo->audio_ioctl(cdi, cmd, &entry))) {
+				sanitize_format(&entry.cdte_addr,
+				&entry.cdte_format, requested_format);
+				PUTARG(struct cdrom_tocentry, entry);
+				return 0;
+			} else
+				return -EINVAL;
+		}
+		case CDROMPLAYMSF: {
+			struct cdrom_msf msf;
+			GETARG(struct cdrom_msf, msf);
+			CHECKAUDIO;
+			return cdo->audio_ioctl(cdi, cmd, &msf);
+		}
+		case CDROMPLAYTRKIND: {
+			struct cdrom_ti track_index;
+			GETARG(struct cdrom_ti, track_index);
+			CHECKAUDIO;
+			return cdo->audio_ioctl(cdi, cmd, &track_index);
+		}
+		case CDROMVOLCTRL: {
+			struct cdrom_volctrl volume;
+			GETARG(struct cdrom_volctrl, volume);
+			return cdo->audio_ioctl(cdi, cmd, &volume);
+		}
+		case CDROMVOLREAD: {
+			struct cdrom_volctrl volume;
+			if (!cdo->audio_ioctl(cdi, cmd, &volume)) {
+				PUTARG(struct cdrom_volctrl, volume);
+				return 0;
+			}
+			return -EINVAL;
+		}
+		case CDROMSTART:
+			CHECKAUDIO;
+		case CDROMSTOP:
+		case CDROMPAUSE:
+		case CDROMRESUME:
 			return cdo->audio_ioctl(cdi, cmd, NULL);
 		} /* switch */
+	}
 
 	if (cdo->dev_ioctl != NULL)     /* device specific ioctls? */
 		return cdo->dev_ioctl(cdi, cmd, arg);
 	return -EINVAL;
 }
 
+/* This code is similar to that in open_for_data. The routine is called
+   in case a audio play operation is requested. It doesn't make much sense
+   do do this on a data disc.
+ */
+int check_for_audio_disc(struct cdrom_device_info * cdi,
+			 struct cdrom_device_ops * cdo)
+{
+	if (!(cdi->options & CDO_CHECK_TYPE))
+		return 0;
+	if (cdo->drive_status != NULL) {
+		int ds = cdo->drive_status(cdi, CDSL_CURRENT);
+		if (ds == CDS_TRAY_OPEN) {
+			/* can/may i close it? */
+			if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
+			    cdi->options & CDO_AUTO_CLOSE) {
+				if (cdo->tray_move(cdi,0))
+					return -EIO;
+			} else
+				return -ENOMEDIUM; /* can't close: too bad */
+			ds = cdo->drive_status(cdi, CDSL_CURRENT);
+			if (ds == CDS_NO_DISC)
+				return -ENOMEDIUM;
+		}
+		if (cdo->disc_status != NULL) {
+			ds = cdo->disc_status(cdi);
+			if (ds == CDS_NO_DISC)
+				return -ENOMEDIUM;
+			if (ds != CDS_AUDIO)
+				return -EMEDIUMTYPE;
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(register_cdrom);
+EXPORT_SYMBOL(unregister_cdrom);
+EXPORT_SYMBOL(cdrom_fops);
+
 #ifdef MODULE
 int init_module(void)
 {
-	printk(KERN_INFO "Module inserted: " VERSION "\n");
+	printk(KERN_INFO "Module cdrom: Generic CDROM driver " REVISION "\n");
 	return 0;
 }
 
@@ -564,6 +640,6 @@
 /*
  * Local variables:
  * comment-column: 40
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I. -I/usr/src/linux-obj/include -Wall -Wstrict-prototypes -O2 -m486 -c cdrom.c -o cdrom.o"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o cdrom.o cdrom.c"
  * End:
  */
diff -u --recursive --new-file v2.1.33/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.1.33/linux/drivers/char/lp.c	Sun Apr 13 10:18:20 1997
+++ linux/drivers/char/lp.c	Sun Apr 13 09:23:31 1997
@@ -14,6 +14,7 @@
 
 #include <linux/module.h>
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
diff -u --recursive --new-file v2.1.33/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v2.1.33/linux/drivers/char/n_tty.c	Tue Mar  4 10:25:23 1997
+++ linux/drivers/char/n_tty.c	Fri Apr 11 22:12:34 1997
@@ -707,7 +707,7 @@
 
 	if (!tty->read_buf) {
 		tty->read_buf = (unsigned char *)
-			get_free_page(intr_count ? GFP_ATOMIC : GFP_KERNEL);
+			get_free_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
 		if (!tty->read_buf)
 			return -ENOMEM;
 	}
diff -u --recursive --new-file v2.1.33/linux/drivers/char/selection.c linux/drivers/char/selection.c
--- v2.1.33/linux/drivers/char/selection.c	Sun Apr 13 10:18:20 1997
+++ linux/drivers/char/selection.c	Fri Apr 11 10:37:40 1997
@@ -32,6 +32,8 @@
 /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
 #define isspace(c)	((c) == ' ')
 
+extern void poke_blanked_console(void);
+
 /* Variables for selection control. */
 /* Use a dynamic buffer, instead of static (Dec 1994) */
        int sel_cons = 0;		/* must not be disallocated */
@@ -118,7 +120,7 @@
 	int sel_mode, new_sel_start, new_sel_end, spc;
 	char *bp, *obp;
 	int i, ps, pe;
-	
+
 	do_unblank_screen();
 	poke_blanked_console();
 
@@ -289,7 +291,7 @@
 	int	c = sel_buffer_lth;
 	int	l;
 	struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
-	
+
 	if (!bp || !c)
 		return 0;
 	poke_blanked_console();
diff -u --recursive --new-file v2.1.33/linux/drivers/char/tga.c linux/drivers/char/tga.c
--- v2.1.33/linux/drivers/char/tga.c	Fri Apr  4 08:52:19 1997
+++ linux/drivers/char/tga.c	Sun Apr 13 09:23:31 1997
@@ -10,6 +10,7 @@
  * This module exports the console io support for DEC's TGA
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.1.33/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.1.33/linux/drivers/char/vt.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/char/vt.c	Sun Apr 13 09:23:31 1997
@@ -9,6 +9,7 @@
  *  Some code moved for less code duplication - Andi Kleen - Mar 1997
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.33/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.1.33/linux/drivers/net/3c505.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/net/3c505.c	Fri Apr 11 10:50:45 1997
@@ -450,7 +450,9 @@
 			return TRUE;
 			break;
 		case ASF_PCB_NAK:
-			printk("%s: send_pcb got NAK\n", dev->name);
+#ifdef ELP_DEBUG
+			printk(KERN_DEBUG "%s: send_pcb got NAK\n", dev->name);
+#endif
 			goto abort;
 			break;
 		}
diff -u --recursive --new-file v2.1.33/linux/drivers/net/de4x5.c.lock~ linux/drivers/net/de4x5.c.lock~
--- v2.1.33/linux/drivers/net/de4x5.c.lock~	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/de4x5.c.lock~	Mon Apr 14 13:59:30 1997
@@ -0,0 +1 @@
+torvalds@penguin.transmeta.com
\ No newline at end of file
diff -u --recursive --new-file v2.1.33/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.1.33/linux/drivers/net/de600.c	Fri Apr  4 08:52:20 1997
+++ linux/drivers/net/de600.c	Mon Apr 14 09:31:09 1997
@@ -804,8 +804,8 @@
   	sk->max_unacked = DE600_MAX_WINDOW - DE600_TCP_WINDOW_DIFF;
  */
 
-	if (sk->rmem_alloc >= sk->rcvbuf-2*DE600_MIN_WINDOW) return(0);
-	amt = min((sk->rcvbuf-sk->rmem_alloc)/2/*-DE600_MIN_WINDOW*/, DE600_MAX_WINDOW);
+	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf-2*DE600_MIN_WINDOW) return(0);
+	amt = min((sk->rcvbuf-atomic_read(&sk->rmem_alloc))/2/*-DE600_MIN_WINDOW*/, DE600_MAX_WINDOW);
 	if (amt < 0) return(0);
 	return(amt);
   }
diff -u --recursive --new-file v2.1.33/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.1.33/linux/drivers/net/eepro100.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/net/eepro100.c	Mon Apr 14 09:31:09 1997
@@ -1620,7 +1620,7 @@
 			printk("%s: Allocating a setup frame of size %d.\n",
 				   dev->name, sp->mc_setup_frm_len);
 			sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len,
-									   intr_count ? GFP_ATOMIC : GFP_KERNEL);
+									   in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
 			if (sp->mc_setup_frm == NULL) {
 			  printk("%s: Failed to allocate a setup frame.\n", dev->name);
 				sp->rx_mode = -1; /* We failed, try again. */
diff -u --recursive --new-file v2.1.33/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v2.1.33/linux/drivers/net/loopback.c	Fri Apr  4 08:52:21 1997
+++ linux/drivers/net/loopback.c	Mon Apr 14 09:31:09 1997
@@ -74,7 +74,7 @@
 	 *	instead are lobbed from tx queue to rx queue 
 	 */
 
-	if(skb->users != 1)
+	if(atomic_read(&skb->users) != 1)
 	{
 	  	struct sk_buff *skb2=skb;
 	  	skb=skb_clone(skb, GFP_ATOMIC);		/* Clone the buffer */
diff -u --recursive --new-file v2.1.33/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c
--- v2.1.33/linux/drivers/net/myri_sbus.c	Thu Mar 27 14:40:04 1997
+++ linux/drivers/net/myri_sbus.c	Fri Apr 11 22:12:34 1997
@@ -262,7 +262,7 @@
 	int gfp_flags = GFP_KERNEL;
 	int i;
 
-	if(from_irq || intr_count)
+	if(from_irq || in_interrupt())
 		gfp_flags = GFP_ATOMIC;
 
 	myri_clean_rings(mp);
@@ -534,7 +534,7 @@
 {
 	struct myri_eth *mp = (struct myri_eth *) dev->priv;
 
-	return myri_init(mp, intr_count);
+	return myri_init(mp, in_interrupt());
 }
 
 static int myri_close(struct device *dev)
@@ -570,7 +570,7 @@
 			DTX(("resetting, return 0\n"));
 			printk("%s: transmit timed out, resetting\n", dev->name);
 			mp->enet_stats.tx_errors++;
-			myri_init(mp, intr_count);
+			myri_init(mp, in_interrupt());
 			dev->tbusy = 0;
 			dev->trans_start = jiffies;
 			return 0;
diff -u --recursive --new-file v2.1.33/linux/drivers/net/scc.c linux/drivers/net/scc.c
--- v2.1.33/linux/drivers/net/scc.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/net/scc.c	Sun Apr 13 09:23:31 1997
@@ -133,6 +133,7 @@
 
 /* ----------------------------------------------------------------------- */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.1.33/linux/drivers/net/shaper.c linux/drivers/net/shaper.c
--- v2.1.33/linux/drivers/net/shaper.c	Mon Apr  7 11:35:29 1997
+++ linux/drivers/net/shaper.c	Fri Apr 11 10:47:37 1997
@@ -87,7 +87,7 @@
 	/*
 	 *	Lock in an interrupt may fail
 	 */
-	if(sh->locked && intr_count)
+	if(sh->locked && in_interrupt())
 	{
 		restore_flags(flags);
 		return 0;
@@ -438,7 +438,7 @@
 	return sh->rebuild_header(skb);
 }
 
-static int shaper_cache(struct dst_entry *dst, struct dst_entry *neigh, struct hh_cache *hh)
+static int shaper_cache(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh)
 {
 	struct shaper *sh=dst->dev->priv;
 	struct device *tmp;
diff -u --recursive --new-file v2.1.33/linux/drivers/net/shaper.h linux/drivers/net/shaper.h
--- v2.1.33/linux/drivers/net/shaper.h	Sun Feb  2 05:18:42 1997
+++ linux/drivers/net/shaper.h	Fri Apr 11 10:47:37 1997
@@ -33,7 +33,7 @@
 		void *saddr,
 		unsigned len);
 	int  (*rebuild_header)(struct sk_buff *skb);
-	int (*hard_header_cache)(struct dst_entry *dst, struct dst_entry *neigh,
+	int (*hard_header_cache)(struct dst_entry *dst, struct neighbour *neigh,
 		struct hh_cache *hh);
 	void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char *  haddr);
 	struct net_device_stats* (*get_stats)(struct device *dev);
diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.1.33/linux/drivers/net/sunhme.c	Thu Mar 27 14:40:04 1997
+++ linux/drivers/net/sunhme.c	Fri Apr 11 22:12:35 1997
@@ -921,7 +921,7 @@
 	struct device *dev = hp->dev;
 	int i, gfp_flags = GFP_KERNEL;
 
-	if(from_irq || intr_count)
+	if(from_irq || in_interrupt())
 		gfp_flags = GFP_ATOMIC;
 
 	HMD(("happy_meal_init_rings: counters to zero, "));
@@ -960,7 +960,7 @@
 static void sun4c_happy_meal_init_rings(struct happy_meal *hp)
 {
 	struct hmeal_init_block *hb = hp->happy_block;
-	struct hmeal_buffers *hbufs = hp->sun4c_buffers;
+	__u32 hbufs = hp->s4c_buf_dvma;
 	int i;
 
 	HMD(("happy_meal_init_rings: counters to zero, "));
@@ -968,9 +968,7 @@
 
 	HMD(("init rxring, "));
 	for(i = 0; i < RX_RING_SIZE; i++) {
-		unsigned char *this_buf = &hbufs->rx_buf[i][0];
-
-		hb->happy_meal_rxd[i].rx_addr = (unsigned int) this_buf;
+		hb->happy_meal_rxd[i].rx_addr = hbufs + hbuf_offset(rx_buf, i);
 		hb->happy_meal_rxd[i].rx_flags =
 			(RXFLAG_OWN | ((SUN4C_RX_BUFF_SIZE - RX_OFFSET) << 16));
 	}
@@ -1190,8 +1188,8 @@
 
 	/* Set the RX and TX ring ptrs. */
 	HMD(("ring ptrs\n"));
-	erxregs->rx_ring = (unsigned long) &hp->happy_block->happy_meal_rxd[0];
-	etxregs->tx_ring = (unsigned long) &hp->happy_block->happy_meal_txd[0];
+	erxregs->rx_ring = hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0);
+	etxregs->tx_ring = hp->hblock_dvma + hblock_offset(happy_meal_txd, 0);
 
 	/* Set the supported SBUS burst sizes. */
 	HMD(("happy_meal_init: bursts<"));
@@ -1690,6 +1688,7 @@
 	struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0];
 	struct happy_meal_rxd *this;
 	struct hmeal_buffers *hbufs = hp->sun4c_buffers;
+	__u32 hbufs_dvma = hp->s4c_buf_dvma;
 	int elem = hp->rx_new, drops = 0;
 
 	RXD(("RX<"));
@@ -1698,6 +1697,7 @@
 		struct sk_buff *skb;
 		unsigned int flags = this->rx_flags;
 		unsigned char *thisbuf = &hbufs->rx_buf[elem][0];
+		__u32 thisbuf_dvma = hbufs_dvma + hbuf_offset(rx_buf, elem);
 		int len = flags >> 16;
 
 		RXD(("[%d ", elem));
@@ -1731,7 +1731,7 @@
 			}
 		}
 		/* Return the buffer to the Happy Meal. */
-		this->rx_addr = (unsigned int) thisbuf;
+		this->rx_addr = thisbuf_dvma;
 		this->rx_flags =
 			(RXFLAG_OWN | ((SUN4C_RX_BUFF_SIZE - RX_OFFSET) << 16));
 
@@ -1929,6 +1929,7 @@
 {
 	struct happy_meal *hp = (struct happy_meal *) dev->priv;
 	struct hmeal_buffers *hbufs = hp->sun4c_buffers;
+	__u32 txbuf_dvma, hbufs_dvma = hp->s4c_buf_dvma;
 	unsigned char *txbuf;
 	int len, entry;
 
@@ -1968,7 +1969,8 @@
 	memcpy(txbuf, skb->data, len);
 
 	SXD(("SX<l[%d]e[%d]>", len, entry));
-	hp->happy_block->happy_meal_txd[entry].tx_addr = (unsigned int) txbuf;
+	txbuf_dvma = hbufs_dvma + hbuf_offset(tx_buf, entry);
+	hp->happy_block->happy_meal_txd[entry].tx_addr = txbuf_dvma;
 	hp->happy_block->happy_meal_txd[entry].tx_flags =
 		(TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE));
 	hp->tx_new = NEXT_TX(entry);
@@ -2153,11 +2155,13 @@
 					      "burst-sizes", 0x00);
 
 	hp->happy_block = (struct hmeal_init_block *)
-		sparc_dvma_malloc(PAGE_SIZE, "Happy Meal Init Block");
+		sparc_dvma_malloc(PAGE_SIZE, "Happy Meal Init Block",
+				  &hp->hblock_dvma);
 
 	if(sparc_cpu_model == sun4c)
 		hp->sun4c_buffers = (struct hmeal_buffers *)
-		    sparc_dvma_malloc(sizeof(struct hmeal_buffers), "Happy Meal Bufs");
+		    sparc_dvma_malloc(sizeof(struct hmeal_buffers), "Happy Meal Bufs",
+				      &hp->s4c_buf_dvma);
 	else
 		hp->sun4c_buffers = 0;
 
diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.1.33/linux/drivers/net/sunhme.h	Mon Mar 17 14:54:26 1997
+++ linux/drivers/net/sunhme.h	Fri Apr 11 10:47:37 1997
@@ -475,6 +475,9 @@
 	struct happy_meal_txd happy_meal_txd[TX_RING_MAXSIZE];
 };
 
+#define hblock_offset(mem, elem) \
+((__u32)((unsigned long)(&(((struct hmeal_init_block *)0)->mem[elem]))))
+
 #define SUN4C_PKT_BUF_SZ	1546
 #define SUN4C_RX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
 #define SUN4C_TX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
@@ -484,6 +487,9 @@
 	char	rx_buf[RX_RING_SIZE][SUN4C_RX_BUFF_SIZE];
 };
 
+#define hbuf_offset(mem, elem) \
+((__u32)((unsigned long)(&(((struct hmeal_buffers *)0)->mem[elem][0]))))
+
 /* Now software state stuff. */
 enum happy_transceiver {
 	external = 0,
@@ -507,14 +513,17 @@
 	struct hmeal_bigmacregs  *bigmacregs;     /* I said NO SOLARIS with my bigmac! */
 	struct hmeal_tcvregs     *tcvregs;        /* MIF transceiver regs              */
 
-	struct hmeal_init_block  *happy_block;    /* RX and TX descriptors             */
+	struct hmeal_init_block  *happy_block;    /* RX and TX descriptors (CPU addr)  */
+	__u32                     hblock_dvma;    /* DVMA visible address happy block  */
 
 	struct sk_buff           *rx_skbs[RX_RING_SIZE];
 	struct sk_buff           *tx_skbs[TX_RING_SIZE];
 
 	int rx_new, tx_new, rx_old, tx_old;
 
-	struct hmeal_buffers     *sun4c_buffers;
+	/* We may use this for Ultra as well, will have to see, maybe not. */
+	struct hmeal_buffers     *sun4c_buffers;  /* CPU visible address.              */
+	__u32                     s4c_buf_dvma;   /* DVMA visible address.             */
 
 	unsigned int              happy_flags;    /* Driver state flags                */
 	enum happy_transceiver    tcvr_type;      /* Kind of transceiver in use        */
diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.1.33/linux/drivers/net/sunlance.c	Thu Mar 27 14:40:04 1997
+++ linux/drivers/net/sunlance.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.56 1997/03/14 21:04:45 jj Exp $
+/* $Id: sunlance.c,v 1.61 1997/04/10 06:40:54 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -212,10 +212,17 @@
 	char   rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
 };
 
+#define libdesc_offset(rt, elem) \
+((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem])))))
+
+#define libbuff_offset(rt, elem) \
+((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem][0])))))
+
 struct lance_private {
 	char *name;
 	volatile struct lance_regs *ll;
 	volatile struct lance_init_block *init_block;
+	__u32 init_block_dvma;
     
 	int rx_new, tx_new;
 	int rx_old, tx_old;
@@ -265,13 +272,14 @@
 static void load_csrs (struct lance_private *lp)
 {
 	volatile struct lance_regs *ll = lp->ll;
-	volatile struct lance_init_block *ib = lp->init_block;
+	__u32 ib_dvma = lp->init_block_dvma;
 	int leptr;
 
-	if(lp->pio_buffer)
-		leptr = 0;
-	else
-		leptr = LANCE_ADDR (ib);
+	/* This is right now because when we are using a PIO buffered
+	 * init block, init_block_dvma is set to zero. -DaveM
+	 */
+	leptr = LANCE_ADDR (ib_dvma);
+
 	ll->rap = LE_CSR1;
 	ll->rdp = (leptr & 0xFFFF);
 	ll->rap = LE_CSR2;
@@ -291,14 +299,15 @@
 {
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 	volatile struct lance_init_block *ib = lp->init_block;
-	volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
+	__u32 ib_dvma = lp->init_block_dvma;
+	__u32 aib; /* for LANCE_ADDR computations */
 	int leptr;
 	int i;
     
-	if(lp->pio_buffer)
-		aib = 0;
-	else
-		aib = ib;
+	/* This is right now because when we are using a PIO buffered
+	 * init block, init_block_dvma is set to zero. -DaveM
+	 */
+	aib = ib_dvma;
 
 	/* Lock out other processes while setting up hardware */
 	dev->tbusy = 1;
@@ -309,6 +318,7 @@
 
 	/* Copy the ethernet address to the lance init block
 	 * Note that on the sparc you need to swap the ethernet address.
+	 * Note also we want the CPU ptr of the init_block here.
 	 */
 	ib->phys_addr [0] = dev->dev_addr [1];
 	ib->phys_addr [1] = dev->dev_addr [0];
@@ -322,7 +332,7 @@
     
 	/* Setup the Tx ring entries */
 	for (i = 0; i <= TX_RING_SIZE; i++) {
-		leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
+		leptr = LANCE_ADDR(aib + libbuff_offset(tx_buf, i));
 		ib->btx_ring [i].tmd0      = leptr;
 		ib->btx_ring [i].tmd1_hadr = leptr >> 16;
 		ib->btx_ring [i].tmd1_bits = 0;
@@ -336,7 +346,7 @@
 	if (ZERO)
 		printk ("RX rings:\n");
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
+		leptr = LANCE_ADDR(aib + libbuff_offset(rx_buf, i));
 
 		ib->brx_ring [i].rmd0      = leptr;
 		ib->brx_ring [i].rmd1_hadr = leptr >> 16;
@@ -350,14 +360,14 @@
 	/* Setup the initialization block */
     
 	/* Setup rx descriptor pointer */
-	leptr = LANCE_ADDR(&aib->brx_ring);
+	leptr = LANCE_ADDR(aib + libdesc_offset(brx_ring, 0));
 	ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);
 	ib->rx_ptr = leptr;
 	if (ZERO)
 		printk ("RX ptr: %8.8x\n", leptr);
     
 	/* Setup tx descriptor pointer */
-	leptr = LANCE_ADDR(&aib->btx_ring);
+	leptr = LANCE_ADDR(aib + libdesc_offset(btx_ring, 0));
 	ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);
 	ib->tx_ptr = leptr;
 	if (ZERO)
@@ -662,7 +672,7 @@
 
 	/* On the 4m, setup the ledma to provide the upper bits for buffers */
 	if (lp->ledma)
-		lp->ledma->regs->dma_test = ((unsigned int) lp->init_block)
+		lp->ledma->regs->dma_test = ((unsigned long) lp->init_block)
 						& 0xff000000;
 
 	lance_init_ring (dev);
@@ -747,7 +757,7 @@
 		lp->ledma->regs->cond_reg |= DMA_RST_ENET;
 		udelay (200);
 		lp->ledma->regs->cond_reg &= ~DMA_RST_ENET;
-		lp->ledma->regs->dma_test = ((unsigned int) lp->init_block)
+		lp->ledma->regs->dma_test = ((unsigned long) lp->init_block)
 						& 0xff000000;
 	}
 	lance_init_ring (dev);
@@ -966,23 +976,25 @@
 			     sdev->reg_addrs[0].which_io, 0x0);
 
 	/* Make certain the data structures used by the LANCE are aligned. */
-	dev->priv = (void *)(((int)dev->priv + 7) & ~7);
+	dev->priv = (void *)(((unsigned long)dev->priv + 7) & ~7);
 	lp = (struct lance_private *) dev->priv;
-
 	if (lebuffer){
 		prom_apply_sbus_ranges (lebuffer->my_bus,
 					&lebuffer->reg_addrs [0],
 					lebuffer->num_registers,
 					lebuffer);
+
 		lp->init_block = (void *)
 			sparc_alloc_io (lebuffer->reg_addrs [0].phys_addr, 0,
 				sizeof (struct lance_init_block), "lebuffer", 
 				lebuffer->reg_addrs [0].which_io, 0);
+		lp->init_block_dvma = 0;
+
 		lp->pio_buffer = 1;
 	} else {
 		lp->init_block = (void *)
 			sparc_dvma_malloc (sizeof (struct lance_init_block),
-				   lancedma);
+					   lancedma, &lp->init_block_dvma);
 		lp->pio_buffer = 0;
 	}
 	lp->busmaster_regval = prom_getintdefault(sdev->prom_node,
@@ -1059,7 +1071,7 @@
 	}
 
 	/* This should never happen. */
-	if ((int)(lp->init_block->brx_ring) & 0x07) {
+	if ((unsigned long)(lp->init_block->brx_ring) & 0x07) {
 		printk("%s: ERROR: Rx and Tx rings not on even boundary.\n",
 		       dev->name);
 		return ENODEV;
diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.1.33/linux/drivers/net/sunqe.c	Thu Mar 27 14:40:04 1997
+++ linux/drivers/net/sunqe.c	Fri Apr 11 22:12:35 1997
@@ -131,7 +131,7 @@
 	struct device *dev = qep->dev;
 	int i, gfp_flags = GFP_KERNEL;
 
-	if(from_irq || intr_count)
+	if(from_irq || in_interrupt())
 		gfp_flags = GFP_ATOMIC;
 
 	qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0;
@@ -150,6 +150,8 @@
 
 		skb_put(skb, ETH_FRAME_LEN);
 		skb_reserve(skb, 34);
+
+		/* FIX FOR ULTRA */
 		qb->qe_rxd[i].rx_addr = (unsigned int) skb->data;
 		qb->qe_rxd[i].rx_flags =
 			(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
@@ -163,6 +165,7 @@
 {
 	struct qe_init_block *qb = qep->qe_block;
 	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
+	__u32 qbufs_dvma = qep->s4c_buf_dvma;
 	int i;
 
 	qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0;
@@ -173,7 +176,7 @@
 		qb->qe_rxd[i].rx_flags = qb->qe_rxd[i].rx_addr = 0;
 
 	for(i = 0; i < SUN4C_RX_RING_SIZE; i++) {
-		qb->qe_rxd[i].rx_addr = (unsigned int) &qbufs->rx_buf[i][0];
+		qb->qe_rxd[i].rx_addr = qbufs_dvma + qebuf_offset(rx_buf, i);
 		qb->qe_rxd[i].rx_flags =
 			(RXD_OWN | ((SUN4C_RX_BUFF_SIZE) & RXD_LENGTH));
 	}
@@ -197,8 +200,8 @@
 		return -EAGAIN;
 
 	/* Setup initial rx/tx init block pointers. */
-	cregs->rxds = (unsigned int) &qep->qe_block->qe_rxd[0];
-	cregs->txds = (unsigned int) &qep->qe_block->qe_txd[0];
+	cregs->rxds = qep->qblock_dvma + qib_offset(qe_rxd, 0);
+	cregs->txds = qep->qblock_dvma + qib_offset(qe_txd, 0);
 
 	/* Enable the various irq's. */
 	cregs->rimask = 0;
@@ -507,6 +510,8 @@
 			new_skb->dev = qep->dev;
 			skb_put(new_skb, ETH_FRAME_LEN);
 			skb_reserve(new_skb, 34);
+
+			/* FIX FOR ULTRA */
 			rxbase[elem].rx_addr = (unsigned int) new_skb->data;
 			rxbase[elem].rx_flags =
 				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
@@ -552,6 +557,7 @@
 	struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
 	struct qe_rxd *this;
 	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
+	__u32 qbufs_dvma = qep->s4c_buf_dvma;
 	int elem = qep->rx_new, drops = 0;
 
 	this = &rxbase[elem];
@@ -559,6 +565,8 @@
 		struct sk_buff *skb;
 		unsigned char *this_qbuf =
 			qbufs->rx_buf[elem & (SUN4C_RX_RING_SIZE - 1)];
+		__u32 this_qbuf_dvma = qbufs_dvma +
+			qebuf_offset(rx_buf, (elem & (SUN4C_RX_RING_SIZE - 1)));
 		struct qe_rxd *end_rxd =
 			&rxbase[(elem+SUN4C_RX_RING_SIZE)&(RX_RING_SIZE-1)];
 		unsigned int flags = this->rx_flags;
@@ -585,7 +593,7 @@
 				qep->net_stats.rx_packets++;
 			}
 		}
-		end_rxd->rx_addr = (unsigned int) this_qbuf;
+		end_rxd->rx_addr = this_qbuf_dvma;
 		end_rxd->rx_flags = (RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH));
 		
 		elem = NEXT_RX(elem);
@@ -727,6 +735,7 @@
 
 	qep->tx_skbs[entry] = skb;
 
+	/* FIX FOR ULTRA */
 	qep->qe_block->qe_txd[entry].tx_addr = (unsigned long) skb->data;
 	qep->qe_block->qe_txd[entry].tx_flags =
 		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));
@@ -745,6 +754,7 @@
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
 	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
+	__u32 txbuf_dvma, qbufs_dvma = qep->s4c_buf_dvma;
 	unsigned char *txbuf;
 	int len, entry;
 
@@ -763,13 +773,15 @@
 	entry = qep->tx_new;
 
 	txbuf = &qbufs->tx_buf[entry & (SUN4C_TX_RING_SIZE - 1)][0];
+	txbuf_dvma = qbufs_dvma +
+		qebuf_offset(tx_buf, (entry & (SUN4C_TX_RING_SIZE - 1)));
 
 	/* Avoid a race... */
 	qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE;
 
 	memcpy(txbuf, skb->data, len);
 
-	qep->qe_block->qe_txd[entry].tx_addr = (unsigned int) txbuf;
+	qep->qe_block->qe_txd[entry].tx_addr = txbuf_dvma;
 	qep->qe_block->qe_txd[entry].tx_flags =
 		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));
 	qep->tx_new = NEXT_TX(entry);
@@ -1054,12 +1066,14 @@
 		}
 
 		qeps[i]->qe_block = (struct qe_init_block *)
-			sparc_dvma_malloc(PAGE_SIZE, "QE Init Block");
+			sparc_dvma_malloc(PAGE_SIZE, "QE Init Block",
+					  &qeps[i]->qblock_dvma);
 
 		if(sparc_cpu_model == sun4c)
 			qeps[i]->sun4c_buffers = (struct sunqe_buffers *)
 				sparc_dvma_malloc(sizeof(struct sunqe_buffers),
-						  "QE RX/TX Buffers");
+						  "QE RX/TX Buffers",
+						  &qeps[i]->s4c_buf_dvma);
 		else
 			qeps[i]->sun4c_buffers = 0;
 
diff -u --recursive --new-file v2.1.33/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h
--- v2.1.33/linux/drivers/net/sunqe.h	Mon Mar 17 14:54:26 1997
+++ linux/drivers/net/sunqe.h	Fri Apr 11 10:47:37 1997
@@ -317,6 +317,9 @@
 	struct qe_txd qe_txd[TX_RING_MAXSIZE];
 };
 
+#define qib_offset(mem, elem) \
+((__u32)((unsigned long)(&(((struct qe_init_block *)0)->mem[elem]))))
+
 struct sunqe;
 
 struct sunqec {
@@ -341,6 +344,9 @@
 	char	rx_buf[SUN4C_RX_RING_SIZE][SUN4C_RX_BUFF_SIZE];
 };
 
+#define qebuf_offset(mem, elem) \
+((__u32)((unsigned long)(&(((struct sunqe_buffers *)0)->mem[elem][0]))))
+
 #define SUN4C_NEXT_RX(num)	(((num) + 1) & (SUN4C_RX_RING_SIZE - 1))
 #define SUN4C_NEXT_TX(num)	(((num) + 1) & (SUN4C_TX_RING_SIZE - 1))
 #define SUN4C_PREV_RX(num)	(((num) - 1) & (SUN4C_RX_RING_SIZE - 1))
@@ -350,17 +356,19 @@
 	struct qe_creg            *qcregs;           /* QEC per-channel Registers      */
 	struct qe_mregs           *mregs;            /* Per-channel MACE Registers     */
 	struct qe_init_block      *qe_block;         /* RX and TX descriptors          */
+	__u32                      qblock_dvma;      /* RX and TX descriptors          */
 
 	struct sk_buff            *rx_skbs[RX_RING_SIZE];
 	struct sk_buff            *tx_skbs[TX_RING_SIZE];
 
 	int                        rx_new, tx_new, rx_old, tx_old;
 
-	struct sunqe_buffers      *sun4c_buffers;
+	struct sunqe_buffers      *sun4c_buffers; /* CPU visible address.  */
+	__u32                      s4c_buf_dvma;  /* DVMA visible address. */
 
 	struct sunqec             *parent;
 
-	struct net_device_stats   net_stats;   /* Statistical counters               */
+	struct net_device_stats   net_stats;     /* Statistical counters               */
 	struct linux_sbus_device  *qe_sbusdev;   /* QE's SBUS device struct            */
 	struct device             *dev;          /* QE's netdevice struct              */
 	int                        channel;      /* Who am I?                          */
diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_init.c linux/drivers/pnp/parport_init.c
--- v2.1.33/linux/drivers/pnp/parport_init.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/pnp/parport_init.c	Sun Apr 13 09:23:31 1997
@@ -9,10 +9,12 @@
  *              and Philip Blundell <Philip.Blundell@pobox.com>
  */
 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/tasks.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <linux/module.h>
 #include <linux/parport.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -761,8 +763,10 @@
 #undef PORT
 	}
 
+#ifdef CONFIG_PNP_PARPORT_AUTOPROBE
 	for (pb = parport_enumerate(); pb; pb = pb->next)
 		parport_probe_one(pb);
+#endif
 
 	return 0;
 }
diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c
--- v2.1.33/linux/drivers/pnp/parport_probe.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/pnp/parport_probe.c	Fri Apr 11 10:37:40 1997
@@ -5,6 +5,7 @@
  *             Philip Blundell <Philip.Blundell@pobox.com>
  */
 
+#include <linux/tasks.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
@@ -20,7 +21,6 @@
 #include <linux/lp.h>
 
 #include <asm/uaccess.h>
-
 #undef DEBUG_PROBE
 
 static inline int read_nibble(struct parport *port) 
diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_procfs.c linux/drivers/pnp/parport_procfs.c
--- v2.1.33/linux/drivers/pnp/parport_procfs.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/pnp/parport_procfs.c	Sun Apr 13 09:23:31 1997
@@ -8,10 +8,12 @@
  *              and Philip Blundell <Philip.Blundell@pobox.com>
  */
 
+#include <linux/tasks.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
+#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.1.33/linux/drivers/pnp/parport_share.c linux/drivers/pnp/parport_share.c
--- v2.1.33/linux/drivers/pnp/parport_share.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/pnp/parport_share.c	Fri Apr 11 10:50:49 1997
@@ -9,6 +9,7 @@
  *              and Philip Blundell <Philip.Blundell@pobox.com>
  */
 
+#include <linux/tasks.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
@@ -64,7 +65,7 @@
 	if (new.dma >= 0) {
 		if (request_dma(new.dma, new.name)) {
 			printk(KERN_INFO "%s: unable to claim DMA %d\n", 
-			       new.name, new..dma);
+			       new.name, new.dma);
 			release_region(new.base, new.size);
 			if( new.modes & PARPORT_MODE_ECR )
 				release_region(new.base+0x400, 3);
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- v2.1.33/linux/drivers/sbus/audio/audio.c	Mon Mar 17 14:54:28 1997
+++ linux/drivers/sbus/audio/audio.c	Fri Apr 11 10:47:37 1997
@@ -105,7 +105,6 @@
 	struct sparcaudio_driver *drv = (struct sparcaudio_driver *)arg;
 	unsigned long flags;
 
-	printk(KERN_DEBUG "sparcaudio: next buffer (of=%d)\n",drv->output_front);
 	save_and_cli(flags);
 	drv->ops->start_output(drv,
 			       drv->output_buffers[drv->output_front],
@@ -123,7 +122,6 @@
 	/* If the output queue is empty, shutdown the driver. */
 	if (drv->output_count == 0) {
 		/* Stop the lowlevel driver from outputing. */
-		printk("sparcaudio: lowlevel driver shutdown\n");
 		drv->ops->stop_output(drv);
 		drv->output_active = 0;
 
@@ -184,7 +182,6 @@
 	while (count > 0) {
 		/* Check to make sure that an output buffer is available. */
 		if (driver->output_count == driver->num_output_buffers) {
-			printk(KERN_DEBUG "sparcaudio: waiting for free buffer\n");
 			interruptible_sleep_on(&driver->output_write_wait);
 			if (current->signal & ~current->blocked)
 				return bytes_written > 0 ? bytes_written : -EINTR;
@@ -198,9 +195,6 @@
 		copy_from_user_ret(driver->output_buffers[driver->output_rear],
 			       buf, bytes_to_copy, -EFAULT);
 
-		printk(KERN_DEBUG "Stuffing %d in %d\n",
-			 bytes_to_copy, driver->output_rear);
-
 		/* Update the queue pointers. */
 		buf += bytes_to_copy;
 		count -= bytes_to_copy;
@@ -212,7 +206,6 @@
 		/* If the low-level driver is not active, activate it. */
 		save_and_cli(flags);
 		if (! driver->output_active) {
-			printk(KERN_DEBUG "sparcaudio: activating lowlevel driver\n");
 			driver->ops->start_output(driver, driver->output_buffers[driver->output_front],
 						  driver->output_sizes[driver->output_front]);
 			driver->output_active = 1;
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in
--- v2.1.33/linux/drivers/sbus/char/Config.in	Mon Mar 17 14:54:28 1997
+++ linux/drivers/sbus/char/Config.in	Fri Apr 11 10:47:37 1997
@@ -39,4 +39,8 @@
 comment 'Misc Linux/SPARC drivers'
 tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO
 tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC
-tristate 'Bidirectional parallel port support' CONFIG_SUN_BPP
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Bidirectional parallel port support (EXPERIMENTAL)' CONFIG_SUN_BPP
+  tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
+fi
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v2.1.33/linux/drivers/sbus/char/Makefile	Mon Mar 17 14:54:28 1997
+++ linux/drivers/sbus/char/Makefile	Fri Apr 11 10:47:37 1997
@@ -73,5 +73,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_SUN_VIDEOPIX),y)
+O_OBJS += vfc.o
+else
+  ifeq ($(CONFIG_SUN_VIDEOPIX),m)
+  M_OBJS += vfc.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
+vfc.o: vfc_dev.o vfc_i2c.o
+	$(LD) -r -o vfc.o vfc_dev.o vfc_i2c.o
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/bwtwo.c linux/drivers/sbus/char/bwtwo.c
--- v2.1.33/linux/drivers/sbus/char/bwtwo.c	Thu Mar 27 14:40:05 1997
+++ linux/drivers/sbus/char/bwtwo.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: bwtwo.c,v 1.10 1997/03/12 23:25:15 ecd Exp $
+/* $Id: bwtwo.c,v 1.12 1997/04/10 03:02:40 davem Exp $
  * bwtwo.c: bwtwo console driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -143,10 +143,10 @@
 	0x10, 0x20,	0
 };
 
-__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, uint bwtwo, int bw2_io,
+__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, unsigned long bwtwo, int bw2_io,
 			     struct linux_sbus_device *sbdp))
 {
-	printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
+	printk ("bwtwo%d at 0x%8.8x\n", slot, (uint)bwtwo);
 	fb->type.fb_cmsize = 0;
 	fb->mmap = bwtwo_mmap;
 	fb->loadcmap = 0;
@@ -155,8 +155,9 @@
 	fb->blank = bwtwo_blank;
 	fb->unblank = bwtwo_unblank;
 
-	fb->info.bwtwo.regs = sparc_alloc_io ((void *)bwtwo +
-		BWTWO_REGISTER_OFFSET, 0, sizeof (struct bwtwo_regs),
+	fb->info.bwtwo.regs =
+		sparc_alloc_io ((u32)(bwtwo + BWTWO_REGISTER_OFFSET),
+				0, sizeof (struct bwtwo_regs),
 		"bwtwo_regs", bw2_io, 0);
 
 	if (!prom_getbool(sbdp->prom_node, "width")) {
@@ -200,7 +201,7 @@
 	}
 
 	if(!fb->base)
-		fb->base = (unsigned long) sparc_alloc_io((void *)bwtwo, 0,
+		fb->base = (unsigned long) sparc_alloc_io((u32)bwtwo, 0,
 		  ((fb->type.fb_depth*fb->type.fb_height*fb->type.fb_width)/8),
 		  "bwtwo_fbase", bw2_io, 0);
 
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/cgfourteen.c linux/drivers/sbus/char/cgfourteen.c
--- v2.1.33/linux/drivers/sbus/char/cgfourteen.c	Mon Dec 30 02:00:04 1996
+++ linux/drivers/sbus/char/cgfourteen.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: cgfourteen.c,v 1.17 1996/12/23 10:16:00 ecd Exp $
+/* $Id: cgfourteen.c,v 1.18 1997/03/24 17:44:27 jj Exp $
  * cgfourteen.c: Sun SparcStation console support.
  *
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -424,7 +424,7 @@
 	*mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK));
 }
 
-__initfunc(void cg14_setup (fbinfo_t *fb, int slot, int con_node, uint cg14, int cg14_io))
+__initfunc(void cg14_setup (fbinfo_t *fb, int slot, int con_node, unsigned long cg14, int cg14_io))
 {
 	struct cg14_info *cg14info;
 	uint bases [2];
@@ -468,5 +468,5 @@
 	/* If the bit is turned on, the card has 8 mb of ram, otherwise just 4 */
 	cg14info->ramsize = (regs->vca & CG14_VCA_8MB_MASK ? 8 : 4) * 1024 * 1024;
 	printk ("cgfourteen%d at 0x%8.8x with %d megs of RAM rev=%d, impl=%d\n",
-		slot, cg14, cg14info->ramsize/(1024*1024), regs->rev >> 4, regs->rev & 0xf);
+		slot, (uint)cg14, cg14info->ramsize/(1024*1024), regs->rev >> 4, regs->rev & 0xf);
 }
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c
--- v2.1.33/linux/drivers/sbus/char/cgsix.c	Mon Mar 17 14:54:28 1997
+++ linux/drivers/sbus/char/cgsix.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: cgsix.c,v 1.22 1997/02/02 02:12:41 ecd Exp $
+/* $Id: cgsix.c,v 1.26 1997/04/10 03:02:40 davem Exp $
  * cgsix.c: cgsix frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -246,38 +246,38 @@
 		switch (vma->vm_offset+page){
 		case CG6_TEC:
 			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.tec);
+			map_offset = get_phys ((unsigned long)fb->info.cg6.tec);
 			break;
 		case CG6_FBC:
 			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.fbc);
+			map_offset = get_phys ((unsigned long)fb->info.cg6.fbc);
 			break;
 		case CG6_FHC:
 			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.fhc);
+			map_offset = get_phys ((unsigned long)fb->info.cg6.fhc);
 			break;
 		case CG6_THC:
 			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.thc);
+			map_offset = get_phys ((unsigned long)fb->info.cg6.thc);
 			break;
 		case CG6_BTREGS:
 			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.bt);
+			map_offset = get_phys ((unsigned long)fb->info.cg6.bt);
 			break;
 			
 		case CG6_DHC:
 			map_size = PAGE_SIZE * 40;
-			map_offset = get_phys ((uint)fb->info.cg6.dhc);
+			map_offset = get_phys ((unsigned long)fb->info.cg6.dhc);
 			break;
 			
 		case CG6_ROM:
 			map_size = PAGE_SIZE * 16;
-			map_offset = get_phys ((uint)fb->info.cg6.rom);
+			map_offset = get_phys ((unsigned long)fb->info.cg6.rom);
 			break;
 
 		case CG6_RAM:
 			map_size = size-page;
-			map_offset = get_phys ((uint) fb->base);
+			map_offset = get_phys ((unsigned long) fb->base);
 			if (map_size < fb->type.fb_size)
 				map_size = fb->type.fb_size;
 			break;
@@ -422,7 +422,7 @@
 	cg6->bt->control |= 0x03 << 24;
 }
 
-__initfunc(void cg6_setup (fbinfo_t *fb, int slot, uint cg6, int cg6_io))
+__initfunc(void cg6_setup (fbinfo_t *fb, int slot, unsigned long cg6, int cg6_io))
 {
 	struct cg6_info *cg6info;
 	unsigned int rev, cpu, conf;
@@ -447,23 +447,24 @@
 	cg6info = (struct cg6_info *) &fb->info.cg6;
 
 	/* Map the hardware registers */
-	cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
+	cg6info->bt = sparc_alloc_io ((u32)(cg6+CG6_BROOKTREE_OFFSET), 0,
 		 sizeof (struct bt_regs), "cgsix_dac", cg6_io, 0);
-	cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
+	cg6info->fhc = sparc_alloc_io ((u32)(cg6+CG6_FHC_OFFSET), 0,
 		 sizeof (int), "cgsix_fhc", cg6_io, 0);
-	cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
+	cg6info->thc = sparc_alloc_io ((u32)(cg6+CG6_THC_OFFSET), 0,
 		 sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
-	cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
+	cg6info->tec = sparc_alloc_io ((u32)(cg6+CG6_TEC_OFFSET), 0,
 		 sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
-	cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
+	cg6info->dhc = sparc_alloc_io ((u32)(cg6+CG6_DHC_OFFSET), 0,
 		 0x40000, "cgsix_dhc", cg6_io, 0);
-	cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
+	cg6info->fbc = sparc_alloc_io ((u32)(cg6+CG6_FBC_OFFSET), 0,
 		 0x1000, "cgsix_fbc", cg6_io, 0);
-	cg6info->rom = sparc_alloc_io ((void *) cg6+CG6_ROM_OFFSET, 0,
+	cg6info->rom = sparc_alloc_io ((u32)(cg6+CG6_ROM_OFFSET), 0,
 		 0x10000, "cgsix_rom", cg6_io, 0);
-	if (!fb->base){
-		fb->base = (uint) sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
-                    fb->type.fb_size, "cgsix_ram", cg6_io, 0);
+	if (!fb->base) {
+		fb->base = (unsigned long)
+			sparc_alloc_io ((u32)(cg6+CG6_RAM_OFFSET), 0,
+					fb->type.fb_size, "cgsix_ram", cg6_io, 0);
 	}
 	if (slot == sun_prom_console_id)
 		fb_restore_palette = cg6_restore_palette;
@@ -481,7 +482,7 @@
 	printk("TEC Rev %x ",
 		(cg6info->thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) &
 		CG6_THC_MISC_REV_MASK);
-
+		
 	/* Get FHC Revision */
 	conf = *(cg6info->fhc);
 
@@ -497,16 +498,18 @@
 	rev = conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK;
 	printk("Rev %x\n", rev);
 
-	if (slot && sun_prom_console_id == slot) return;
-	
+	if (slot && sun_prom_console_id == slot)
+		return;
+
 	/* Reset the cg6 */
 	cg6_reset(fb);
 	
-	if (!slot)
-	/* Enable Video */
+	if (!slot) {
+		/* Enable Video */
 		cg6_unblank(fb);
-	else
+	} else {
 		cg6_blank(fb);
+	}
 }
 
 extern unsigned char vga_font[];
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/cgthree.c linux/drivers/sbus/char/cgthree.c
--- v2.1.33/linux/drivers/sbus/char/cgthree.c	Thu Mar 27 14:40:05 1997
+++ linux/drivers/sbus/char/cgthree.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: cgthree.c,v 1.12 1997/03/11 23:44:24 ecd Exp $
+/* $Id: cgthree.c,v 1.16 1997/04/10 03:02:41 davem Exp $
  * cgtree.c: cg3 frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -25,6 +25,16 @@
 #include "cg_common.h"
 
 
+/* Control Register Constants */
+#define CG3_CR_ENABLE_INTS	0x80
+#define CG3_CR_ENABLE_VIDEO	0x40
+#define CG3_CR_ENABLE_TIMING	0x20
+#define CG3_CR_ENABLE_CURCMP	0x10
+#define CG3_CR_XTAL_MASK	0x0c
+#define CG3_CR_DIVISOR_MASK	0x03
+
+/* Status Register Constants */
+#define CG3_SR_PENDING_INT	0x80
 #define CG3_SR_RES_MASK		0x70
 #define CG3_SR_1152_900_76_A	0x40
 #define CG3_SR_1152_900_76_B	0x60
@@ -125,6 +135,19 @@
         return 0;
 }
 
+static void
+cg3_blank (fbinfo_t *fb)
+{
+	fb->info.cg3.regs->control &= ~CG3_CR_ENABLE_VIDEO;
+}
+
+static void
+cg3_unblank (fbinfo_t *fb)
+{
+        fb->info.cg3.regs->control |= CG3_CR_ENABLE_VIDEO;
+}
+
+
 static u8 cg3regvals_66hz[] __initdata = {	/* 1152 x 900, 66 Hz */
 	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
 	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
@@ -155,7 +178,7 @@
 };
 
 
-__initfunc(void cg3_setup (fbinfo_t *fb, int slot, uint cg3, int cg3_io,
+__initfunc(void cg3_setup (fbinfo_t *fb, int slot, unsigned long cg3, int cg3_io,
 			   struct linux_sbus_device *sbdp))
 {
 	struct cg3_info *cg3info = (struct cg3_info *) &fb->info.cg3;
@@ -177,10 +200,10 @@
 				}
 			}
 		}
-		printk ("cgRDI%d at 0x%8.8x\n", slot, cg3);
+		printk ("cgRDI%d at 0x%8.8x\n", slot, (uint)cg3);
 		cg3info->cgrdi = 1;
 	} else {
-		printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
+		printk ("cgthree%d at 0x%8.8x\n", slot, (uint)cg3);
 		cg3info->cgrdi = 0;
 	}
 	
@@ -191,9 +214,11 @@
 	fb->postsetup = sun_cg_postsetup;
 	fb->ioctl = 0; /* no special ioctls */
 	fb->reset = 0;
+	fb->blank = cg3_blank;
+	fb->unblank = cg3_unblank;
 
 	/* Map the card registers */
-	cg3info->regs = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
+	cg3info->regs = sparc_alloc_io ((u32)(cg3+CG3_REGS), 0,
 		 sizeof (struct cg3_regs),"cg3_regs", cg3_io, 0);
 
 	if (!prom_getbool(sbdp->prom_node, "width")) {
@@ -233,7 +258,7 @@
 	}
 
 	if (!fb->base){
-		fb->base=(uint) sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
+		fb->base=(uint) sparc_alloc_io ((u32)(cg3+CG3_RAM), 0,
 				    fb->type.fb_size, "cg3_ram", cg3_io, 0);
 	}
 }
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/fb.h linux/drivers/sbus/char/fb.h
--- v2.1.33/linux/drivers/sbus/char/fb.h	Thu Mar 27 14:40:05 1997
+++ linux/drivers/sbus/char/fb.h	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: fb.h,v 1.23 1997/03/12 23:25:16 ecd Exp $
+/* $Id: fb.h,v 1.24 1997/03/24 17:44:15 jj Exp $
  * fb.h: contains the definitions of the structures that various sun
  *       frame buffer can use to do console driver stuff.
  *
@@ -197,12 +197,12 @@
 
 #define FB_DEV(x) (MINOR(x) / 32)
 
-extern void cg3_setup (fbinfo_t *, int, uint, int, struct linux_sbus_device *);
-extern void cg6_setup (fbinfo_t *, int, uint, int);
-extern void cg14_setup (fbinfo_t *, int, int, uint, int);
-extern void bwtwo_setup (fbinfo_t *, int, uint, int,
+extern void cg3_setup (fbinfo_t *, int, unsigned long, int, struct linux_sbus_device *);
+extern void cg6_setup (fbinfo_t *, int, unsigned long, int);
+extern void cg14_setup (fbinfo_t *, int, int, unsigned long, int);
+extern void bwtwo_setup (fbinfo_t *, int, unsigned long, int,
 			 struct linux_sbus_device *);
-extern void leo_setup (fbinfo_t *, int, uint, int);
-extern void tcx_setup (fbinfo_t *, int, int, uint, struct linux_sbus_device *);
+extern void leo_setup (fbinfo_t *, int, unsigned long, int);
+extern void tcx_setup (fbinfo_t *, int, int, unsigned long, struct linux_sbus_device *);
 
 #endif __SPARC_FB_H_
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c
--- v2.1.33/linux/drivers/sbus/char/leo.c	Mon Mar 17 14:54:28 1997
+++ linux/drivers/sbus/char/leo.c	Fri Apr 11 10:47:37 1997
@@ -1,7 +1,8 @@
-/* $Id: leo.c,v 1.11 1997/02/02 02:12:44 ecd Exp $
+/* $Id: leo.c,v 1.14 1997/04/10 17:06:09 jj Exp $
  * leo.c: SUNW,leo 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz)
  */
  
 #include <linux/kd.h>
@@ -508,7 +509,7 @@
 	return memory_start + (256*4*3) + 256 + 256*3;
 }
 
-__initfunc(void leo_setup (fbinfo_t *fb, int slot, uint leo, int leo_io))
+__initfunc(void leo_setup (fbinfo_t *fb, int slot, unsigned long leo, int leo_io))
 {
 	struct leo_info *leoinfo;
 	int i;
@@ -542,25 +543,25 @@
 
 	leoinfo->offset = leo;
 	/* Map the hardware registers */
-	leoinfo->lc_ss0_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS0_KRN, 0,
+	leoinfo->lc_ss0_krn = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS0_KRN), 0,
 		 PAGE_SIZE,"leo_lc_ss0_krn", fb->space, 0);
-	leoinfo->lc_ss0_usr = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS0_USR, 0,
+	leoinfo->lc_ss0_usr = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS0_USR), 0,
 		 PAGE_SIZE,"leo_lc_ss0_usr", fb->space, 0);
-	leoinfo->lc_ss1_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS1_KRN, 0,
+	leoinfo->lc_ss1_krn = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS1_KRN), 0,
 		 PAGE_SIZE,"leo_lc_ss1_krn", fb->space, 0);
-	leoinfo->lc_ss1_usr = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS1_USR, 0,
+	leoinfo->lc_ss1_usr = sparc_alloc_io((u32)(leo + LEO_OFF_LC_SS1_USR), 0,
 		 PAGE_SIZE,"leo_lc_ss1_usr", fb->space, 0);
-	leoinfo->ld_ss0 = sparc_alloc_io ((void *) leo + LEO_OFF_LD_SS0, 0,
+	leoinfo->ld_ss0 = sparc_alloc_io((u32)(leo + LEO_OFF_LD_SS0), 0,
 		 PAGE_SIZE,"leo_ld_ss0", fb->space, 0);
-	leoinfo->ld_ss1 = sparc_alloc_io ((void *) leo + LEO_OFF_LD_SS1, 0,
+	leoinfo->ld_ss1 = sparc_alloc_io((u32)(leo + LEO_OFF_LD_SS1), 0,
 		 PAGE_SIZE,"leo_ld_ss1", fb->space, 0);
-	leoinfo->ld_gbl = sparc_alloc_io ((void *) leo + LEO_OFF_LD_GBL, 0,
+	leoinfo->ld_gbl = sparc_alloc_io((u32)(leo + LEO_OFF_LD_GBL), 0,
 		 PAGE_SIZE,"leo_ld_gbl", fb->space, 0);
-	leoinfo->lx_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LX_KRN, 0,
+	leoinfo->lx_krn = sparc_alloc_io((u32)(leo + LEO_OFF_LX_KRN), 0,
 		 PAGE_SIZE,"leo_lx_krn", fb->space, 0);
-	leoinfo->cursor = sparc_alloc_io ((void *) leo + LEO_OFF_LX_CURSOR, 0,
+	leoinfo->cursor = sparc_alloc_io((u32)(leo + LEO_OFF_LX_CURSOR), 0,
 		 sizeof(struct leo_cursor),"leo_lx_crsr", fb->space, 0);
-	fb->base = (long)sparc_alloc_io ((void *) leo + LEO_OFF_SS0, 0,
+	fb->base = (long)sparc_alloc_io((u32)(leo + LEO_OFF_SS0), 0,
 		 0x800000,"leo_ss0", fb->space, 0);
 	
 	leoinfo->ld_ss0->unk = 0xffff;
@@ -617,24 +618,16 @@
 		do { \
 			i = us->csr; \
 		} while (i & 0x20000000); \
-		ss->fg = (attr >> 4)<<24; \
-		ss->planemask = 0xff000000; \
+		ss->fg = (attr & 0xf) << 24; \
+		ss->bg = (attr >> 4) << 24; \
 		ss->rop = 0x310040; \
-		us->extent = (count*8-1) | (15<<11); \
-		i = us->attrs; \
-		us->fill = (x) | ((y) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0); \
-		do { \
-			i = us->csr; \
-		} while (i & 0x20000000); \
-		ss->fg = (attr & 0xf)<<24; \
-		us->fontc2 = ~(0); \
+		ss->planemask = 0xff000000; \
+		us->fontc2 = 0xFFFFFFFE; \
 		us->attrs = 4; \
-		us->fontc = ~(0); \
-		us->extent = ((u16)x) | (y << 16); \
-		us->src = ((u16)(x + (count << 3))) | ((y + 16) << 16);
+		us->fontc = 0xFF000000;
 #define GX_BLITC_END \
 	}
-	
+
 static void leo_blitc(unsigned short charattr, int xoff, int yoff)
 {
 	unsigned char attrib = CHARATTR_TO_SUNCOLOR(charattr);
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c
--- v2.1.33/linux/drivers/sbus/char/rtc.c	Fri Apr  4 08:52:22 1997
+++ linux/drivers/sbus/char/rtc.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.9 1997/01/26 07:13:40 davem Exp $
+/* $Id: rtc.c,v 1.10 1997/04/03 08:47:55 davem Exp $
  *
  * Linux/SPARC Real Time Clock Driver
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c
--- v2.1.33/linux/drivers/sbus/char/suncons.c	Thu Mar 27 14:40:05 1997
+++ linux/drivers/sbus/char/suncons.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.53 1997/03/15 07:47:50 davem Exp $
+/* $Id: suncons.c,v 1.58 1997/04/04 00:50:04 davem Exp $
  *
  * suncons.c: Sun SparcStation console support.
  *
@@ -257,10 +257,10 @@
 		return; /* Don't paint anything on fb which is not ours,
 			   but turn off the hw cursor in such case */
 	
-	save_and_cli(flags);
+	__save_and_cli(flags);
 
 	if(cursor_pos == -1) {
-		restore_flags (flags);
+		__restore_flags (flags);
 		return;
 	}
 	switch (con_depth){
@@ -287,7 +287,7 @@
 		break;
 	}
 	cursor_pos = -1;
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 void
@@ -316,13 +316,13 @@
 		return;
 	}
 
-	save_and_cli(flags);
+	__save_and_cli(flags);
 
 	idx = (pos - video_mem_base) >> 1;
 	oldpos = cursor_pos;
 	if (!deccm) {
 		hide_cursor ();
-		restore_flags (flags);
+		__restore_flags (flags);
 		return;
 	}
 	cursor_pos = idx;
@@ -366,7 +366,7 @@
 	}
 	default:
 	}
-	restore_flags(flags);
+	__restore_flags(flags);
 }
 
 /*
@@ -434,7 +434,12 @@
 	putconsxy(0, q);
 	ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20 + 11 * (linux_num_cpus - 1);
 
-	for (p = "Linux/SPARC version " UTS_RELEASE; *p; p++, ush++) {
+#ifdef __sparc_v9__
+	p = "Linux/UltraSPARC version " UTS_RELEASE;
+#else
+	p = "Linux/SPARC version " UTS_RELEASE;
+#endif
+	for (; *p; p++, ush++) {
 		*ush = (attr << 8) + *p;
 		sun_blitc (*ush, (unsigned long) ush);
 	}
@@ -846,7 +851,7 @@
 __initfunc(static void
 	   sparc_framebuffer_setup(int primary, int con_node,
 				   int type, struct linux_sbus_device *sbdp, 
-				   uint base, uint con_base, int prom_fb,
+				   uint base, unsigned long con_base, int prom_fb,
 				   int parent_node))
 {
 	static int frame_buffers = 1;
@@ -865,7 +870,8 @@
 	
 	if (prom_fb) sun_prom_console_id = n;
 		
-	if (sbdp) io = sbdp->reg_addrs [0].which_io;
+	if (sbdp)
+		io = sbdp->reg_addrs [0].which_io;
 
 	/* Fill in common fb information */
 	fbinfo [n].type.fb_type   = type;
@@ -880,7 +886,10 @@
 	fbinfo [n].type.fb_size   = PAGE_ALIGN((linebytes) * (fbinfo [n].type.fb_height));
 	fbinfo [n].space = io;
 	fbinfo [n].blanked = 0;
-	fbinfo [n].base = con_base;
+	if (con_base >= PAGE_OFFSET)
+		fbinfo [n].base = con_base;
+	else
+		fbinfo [n].base = 0;
 	fbinfo [n].cursor.hwsize.fbx = 32;
 	fbinfo [n].cursor.hwsize.fby = 32;
 	fbinfo [n].proc_entry.node = parent_node;
@@ -1016,7 +1025,8 @@
 	int cg14 = 0;
 	char prom_name[40];	
 	int type;
-	uint con_base;
+	unsigned long con_base;
+	u32 tmp;
 	u32 prom_console_node = 0;
 
 	for (i = 0; i < FRAME_BUFFERS; i++)
@@ -1115,7 +1125,8 @@
 			prom_apply_sbus_ranges (sbdp->my_bus, &sbdp->reg_addrs [0],
 						sbdp->num_registers, sbdp);
 
-			propl = prom_getproperty(con_node, "address", (char *) &con_base, 4);
+			propl = prom_getproperty(con_node, "address", (char *) &tmp, 4);
+			con_base = tmp;
 			if (propl != 4) con_base = 0;
 			propl = prom_getproperty(con_node, "emulation", prom_name, sizeof (prom_name));
 			if (propl < 0 || propl >= sizeof (prom_name)) {
@@ -1277,7 +1288,7 @@
 		
 		dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx));
 
-		save_and_cli(flags);
+		__save_and_cli(flags);
 		if ((!(charattr & 0xf000)) ^ (idx == cursor_pos)) {
 			for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
 				*dst = ~(*font_row);
@@ -1285,7 +1296,7 @@
 			for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
 				*dst = *font_row;
 		}
-		restore_flags(flags);
+		__restore_flags(flags);
 		break;
 	}
 	case 8: {
@@ -1329,12 +1340,12 @@
 				BLITC_SPACE
 				BLITC_SPACE
 					: : "r" (cpl), "r" (x3), "r" (x1), "r" (x2));
-			save_and_cli (flags);
+			__save_and_cli (flags);
 			if (idx != cursor_pos)
 				__asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (dst), "r" (cpl));
 			else
 				__asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (under_cursor), "i" (8));
-			restore_flags (flags);
+			__restore_flags (flags);
 #else
 			bgmask = attrib >> 4;
 			bgmask |= bgmask << 8;
@@ -1345,7 +1356,7 @@
         	                *(dst+1) = bgmask;
                 	}
                 	/* Prevent cursor spots left on the screen */
-			save_and_cli(flags);
+			__save_and_cli(flags);
 			if (idx != cursor_pos) {
 	                	*dst = bgmask;
         	        	*(dst+1) = bgmask;
@@ -1358,7 +1369,7 @@
                 		under_cursor [2] = bgmask;
 	                	under_cursor [3] = bgmask;
         	        }
-	                restore_flags(flags);
+	                __restore_flags(flags);
 #endif
 		} else /* non-space */ {
 			fgmask = attrib & 0x0f;
@@ -1430,12 +1441,12 @@
 			/* Prepare the data the bottom line (and put it into g2,g3) */
 			__asm__ __volatile__ (BLITC_BODYEND : : "r" (fontm_bits), "r" (fgmask), "r" (bgmask),
 								"r" (x3), "r" (x4));
-			save_and_cli(flags);
+			__save_and_cli(flags);
 			if (idx != cursor_pos)
 				__asm__ __volatile__ (BLITC_STORE : : "r" (dst), "r" (cpl));
 			else
 				__asm__ __volatile__ (BLITC_STORE : : "r" (under_cursor), "i" (8));
-			restore_flags (flags);
+			__restore_flags (flags);
 #else
 	                for(j = 0; j < CHAR_HEIGHT - 2; j++, font_row++, dst += ipl) {
         	                rowbits = *font_row;
@@ -1458,7 +1469,7 @@
 	                data4 = (data4 & fgmask) | (~data4 & bgmask);
         	        
                 	/* Prevent cursor spots left on the screen */
-			save_and_cli(flags);
+			__save_and_cli(flags);
 			
 			if (idx != cursor_pos) {
 	                	*dst = data;
@@ -1473,7 +1484,7 @@
 	                	under_cursor [3] = data4;
         	        }
                 	
-	                restore_flags(flags);
+	                __restore_flags(flags);
 #endif
 		}
 		break;
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c
--- v2.1.33/linux/drivers/sbus/char/sunfb.c	Fri Apr  4 08:52:22 1997
+++ linux/drivers/sbus/char/sunfb.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: sunfb.c,v 1.21 1997/03/14 21:04:53 jj Exp $
+/* $Id: sunfb.c,v 1.22 1997/04/03 08:47:56 davem Exp $
  * sunfb.c: Sun generic frame buffer support.
  *
  * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.1.33/linux/drivers/sbus/char/sunkbd.c	Fri Apr  4 08:52:22 1997
+++ linux/drivers/sbus/char/sunkbd.c	Fri Apr 11 10:47:37 1997
@@ -383,7 +383,7 @@
 	    e0_keys[scancode - 128];
 }
 
-void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
+void sunkbd_inchar(unsigned char ch, struct pt_regs *regs);
 static void keyboard_timer (unsigned long ignored);
 
 static struct timer_list
@@ -400,7 +400,7 @@
 	save_flags(flags); cli();
 
 	/* Auto repeat: send regs = 0 to indicate autorepeat */
-	sunkbd_inchar (last_keycode, 0, 0);
+	sunkbd_inchar (last_keycode, 0);
 	del_timer (&auto_repeat_timer);
 	if (kbd_rate_ticks) {
 		auto_repeat_timer.expires = jiffies + kbd_rate_ticks;
@@ -411,7 +411,7 @@
 
 /* #define SKBD_DEBUG */
 /* This is our keyboard 'interrupt' routine. */
-void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
+void sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
 {
 	unsigned char keycode;
 	char up_flag;                          /* 0 or SUNKBD_UBIT */
@@ -1393,7 +1393,7 @@
 kbd_close (struct inode *i, struct file *f)
 {
 	if (--kbd_active)
-		return;
+		return 0;
 
 	if (kbd_redirected)
 		kbd_table [kbd_opened-1].kbdmode = VC_XLATE;
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v2.1.33/linux/drivers/sbus/char/sunmouse.c	Fri Apr  4 08:52:22 1997
+++ linux/drivers/sbus/char/sunmouse.c	Fri Apr 11 10:47:37 1997
@@ -188,7 +188,7 @@
  * the Mouse zs8530 channel.
  */
 void
-sun_mouse_inbyte(unsigned char byte, unsigned char status)
+sun_mouse_inbyte(unsigned char byte)
 {
 	signed char mvalue;
 	int d;
@@ -204,8 +204,6 @@
 		push_char (byte);
 		return;
 	}
-	/* Check for framing errors and parity errors */
-	/* XXX TODO XXX */
 
 	/* If the mouse sends us a byte from 0x80 to 0x87
 	 * we are starting at byte zero in the transaction
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v2.1.33/linux/drivers/sbus/char/sunserial.c	Mon Mar 17 14:54:28 1997
+++ linux/drivers/sbus/char/sunserial.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.27 1997/03/04 19:33:55 davem Exp $
+/* $Id: sunserial.c,v 1.37 1997/04/12 23:33:14 ecd Exp $
  * serial.c: Serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -39,6 +39,8 @@
 #define KEYBOARD_LINE 0x2
 #define MOUSE_LINE    0x3
 
+extern struct wait_queue * keypress_wait;
+
 struct sun_zslayout **zs_chips;
 struct sun_zschannel **zs_channels;
 struct sun_zschannel *zs_conschan;
@@ -66,8 +68,8 @@
 #define SUNKBD_UP      0x80
 #define SUNKBD_A       0x4d
 
-extern void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs);
-extern void sun_mouse_inbyte(unsigned char byte, unsigned char status);
+extern void sunkbd_inchar(unsigned char ch, struct pt_regs *regs);
+extern void sun_mouse_inbyte(unsigned char byte);
 
 static unsigned char kgdb_regs[16] = {
 	0, 0, 0,                     /* write 0, 1, 2 */
@@ -173,7 +175,7 @@
  */
 static int baud_table[] = {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 0 };
+	9600, 19200, 38400, 76800, 0 };
 
 /* 
  * Reading and writing Zilog8530 registers.  The delays are to make this
@@ -206,9 +208,20 @@
 {
 	unsigned long flags;
 	struct sun_zschannel *channel = info->zs_channel;
+	unsigned char stat;
+	int i;
 
+	for (i = 0; i < 1000; i++) {
+		stat = read_zsreg(channel, R1);
+		if (stat & ALL_SNT)
+			break;
+		udelay(100);
+	}
+	write_zsreg(channel, R3, 0);
+	ZS_CLEARSTAT(channel);
 	ZS_CLEARERR(channel);
 	ZS_CLEARFIFO(channel);
+
 	/* Load 'em up */
 	save_flags(flags); cli();
 	if (info->channelA)
@@ -231,7 +244,7 @@
 	write_zsreg(channel, R5, regs[R5]);
 	write_zsreg(channel, R15, regs[R15]);
 	write_zsreg(channel, R0, RES_EXT_INT);
-	write_zsreg(channel, R0, RES_EXT_INT);
+	write_zsreg(channel, R0, ERR_RES);
 	write_zsreg(channel, R1, regs[R1]);
 	write_zsreg(channel, R9, regs[R9]);
 	restore_flags(flags);
@@ -349,18 +362,6 @@
 	return;
 }
 
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct sun_zschannel *zsc)
-{
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	zsc->control = ERR_RES;
-	udelay(5);
-	zsc->control = RES_H_IUS;
-	udelay(5);
-	restore_flags(flags);
-}
 
 /*
  * ----------------------------------------------------------------------
@@ -391,7 +392,7 @@
 				  int event)
 {
 	info->event |= 1 << event;
-	queue_task_irq_off(&info->tqueue, &tq_serial);
+	queue_task(&info->tqueue, &tq_serial);
 	mark_bh(SERIAL_BH);
 }
 
@@ -402,90 +403,86 @@
 	struct tty_struct *tty = info->tty;
 	unsigned char ch, stat;
 
-	ch = (info->zs_channel->data) & info->parity_mask;
-	udelay(5);
-	stat = read_zsreg(info->zs_channel, R1);
-	udelay(5);
+	do {
+		ch = (info->zs_channel->data) & info->parity_mask;
+		udelay(5);
 
-	/* If this is the console keyboard, we need to handle
-	 * L1-A's here.
-	 */
-	if(info->cons_keyb) {
-		if(ch == SUNKBD_RESET) {
-			l1a_state.kbd_id = 1;
-			l1a_state.l1_down = 0;
-		} else if(l1a_state.kbd_id) {
-			l1a_state.kbd_id = 0;
-		} else if(ch == SUNKBD_L1) {
-			l1a_state.l1_down = 1;
-		} else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
-			l1a_state.l1_down = 0;
-		} else if(ch == SUNKBD_A && l1a_state.l1_down) {
-			/* whee... */
-			batten_down_hatches();
-			/* Clear the line and continue execution... */
-			rs_recv_clear(info->zs_channel);
-			l1a_state.l1_down = 0;
-			l1a_state.kbd_id = 0;
+		/* If this is the console keyboard, we need to handle
+		 * L1-A's here.
+		 */
+		if(info->cons_keyb) {
+			if(ch == SUNKBD_RESET) {
+				l1a_state.kbd_id = 1;
+				l1a_state.l1_down = 0;
+			} else if(l1a_state.kbd_id) {
+				l1a_state.kbd_id = 0;
+			} else if(ch == SUNKBD_L1) {
+				l1a_state.l1_down = 1;
+			} else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
+				l1a_state.l1_down = 0;
+			} else if(ch == SUNKBD_A && l1a_state.l1_down) {
+				/* whee... */
+				batten_down_hatches();
+				/* Continue execution... */
+				l1a_state.l1_down = 0;
+				l1a_state.kbd_id = 0;
+				return;
+			}
+			sunkbd_inchar(ch, regs);
 			return;
 		}
-		rs_recv_clear(info->zs_channel);
-		sunkbd_inchar(ch, stat, regs);
-
-		return;
-	}
-	if(info->cons_mouse) {
-		rs_recv_clear(info->zs_channel);
-		sun_mouse_inbyte(ch, stat);
-		return;
-	}
-	if(info->is_cons) {
-		if(ch==0) { /* whee, break received */
-			batten_down_hatches();
-			rs_recv_clear(info->zs_channel);
+		if(info->cons_mouse) {
+			sun_mouse_inbyte(ch);
 			return;
+		}
+		if(info->is_cons) {
+			if(ch==0) {
+				/* whee, break received */
+				batten_down_hatches();
+				/* Continue execution... */
+				return;
 #if 0
-		} else if (ch == 1) {
-			show_state();
-			return;
-		} else if (ch == 2) {
-			show_buffers();
-			return;
+			} else if (ch == 1) {
+				show_state();
+				return;
+			} else if (ch == 2) {
+				show_buffers();
+				return;
 #endif
+			}
+			/* It is a 'keyboard interrupt' ;-) */
+			wake_up(&keypress_wait);
+		}
+		/* Look for kgdb 'stop' character, consult the gdb
+		 * documentation for remote target debugging and
+		 * arch/sparc/kernel/sparc-stub.c to see how all this works.
+		 */
+		if((info->kgdb_channel) && (ch =='\003')) {
+			breakpoint();
+			return;
 		}
-		/* It is a 'keyboard interrupt' ;-) */
-		wake_up(&keypress_wait);
-	}
-	/* Look for kgdb 'stop' character, consult the gdb documentation
-	 * for remote target debugging and arch/sparc/kernel/sparc-stub.c
-	 * to see how all this works.
-	 */
-	if((info->kgdb_channel) && (ch =='\003')) {
-		breakpoint();
-		goto clear_and_exit;
-	}
 
-	if(!tty)
-		goto clear_and_exit;
+		if(!tty)
+			return;
 
-	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-		queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
-	tty->flip.count++;
-	if(stat & PAR_ERR)
-		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
-	else if(stat & Rx_OVR)
-		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-	else if(stat & CRC_ERR)
-		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
-	else
-		*tty->flip.flag_buf_ptr++ = 0; /* XXX */
-	*tty->flip.char_buf_ptr++ = ch;
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			break;
 
-	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+		tty->flip.count++;
+		*tty->flip.flag_buf_ptr++ = 0;
+		*tty->flip.char_buf_ptr++ = ch;
 
-clear_and_exit:
-	rs_recv_clear(info->zs_channel);
-	return;
+		/* Check if we have another character... */
+		stat = info->zs_channel->control;
+		udelay(5);
+		if (!(stat & Rx_CH_AV))
+			break;
+
+		/* ... and see if it is clean. */
+		stat = read_zsreg(info->zs_channel, R1);
+	} while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR)));
+
+	queue_task(&tty->flip.tqueue, &tq_timer);
 }
 
 static _INLINE_ void transmit_chars(struct sun_serial *info)
@@ -496,14 +493,14 @@
 		/* Send next char */
 		zs_put_char(info->zs_channel, info->x_char);
 		info->x_char = 0;
-		goto clear_and_return;
+		return;
 	}
 
 	if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
 		/* That's peculiar... */
 		info->zs_channel->control = RES_Tx_P;
 		udelay(5);
-		goto clear_and_return;
+		return;
 	}
 
 	/* Send char */
@@ -517,14 +514,7 @@
 	if(info->xmit_cnt <= 0) {
 		info->zs_channel->control = RES_Tx_P;
 		udelay(5);
-		goto clear_and_return;
 	}
-
-clear_and_return:
-	/* Clear interrupt */
-	info->zs_channel->control = RES_H_IUS;
-	udelay(5);
-	return;
 }
 
 static _INLINE_ void status_handle(struct sun_serial *info)
@@ -537,9 +527,6 @@
 	/* Clear status condition... */
 	info->zs_channel->control = RES_EXT_INT;
 	udelay(5);
-	/* Clear the interrupt */
-	info->zs_channel->control = RES_H_IUS;
-	udelay(5);
 
 #if 0
 	if(status & DCD) {
@@ -568,50 +555,106 @@
 	return;
 }
 
+static _INLINE_ void special_receive(struct sun_serial *info)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch, stat;
+
+	stat = read_zsreg(info->zs_channel, R1);
+	if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) {
+		ch = info->zs_channel->data;
+		udelay(5);
+	}
+
+	if (!tty)
+		goto clear;
+
+	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+		goto done;
+
+	tty->flip.count++;
+	if(stat & PAR_ERR)
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+	else if(stat & Rx_OVR)
+		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+	else if(stat & CRC_ERR)
+		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+
+done:
+	queue_task(&tty->flip.tqueue, &tq_timer);
+clear:
+	info->zs_channel->control = ERR_RES;
+	udelay(5);
+}
+
+
 /*
  * This is the serial driver's generic interrupt routine
  */
 void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct sun_serial * info = (struct sun_serial *)dev_id;
+	struct sun_serial *info;
 	unsigned char zs_intreg;
 	int i;
 
+	info = (struct sun_serial *)dev_id;
 	for (i = 0; i < NUM_SERIAL; i++) {
-		zs_intreg = read_zsreg(info->zs_channel, 3);
+		zs_intreg = read_zsreg(info->zs_next->zs_channel, 2);
+		zs_intreg &= STATUS_MASK;
 
-		/* NOTE: The read register 3, which holds the irq status,
+		/* NOTE: The read register 2, which holds the irq status,
 		 *       does so for both channels on each chip.  Although
-		 *       the status value itself must be read from the A
-		 *       channel and is only valid when read from channel A.
-		 *       Yes... broken hardware...
+		 *       the status value itself must be read from the B
+		 *       channel and is only valid when read from channel B.
+		 *       When read from channel A, read register 2 contains
+		 *       the value written to write register 2.
 		 */
-#define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT)
-#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
 
 		/* Channel A -- /dev/ttya or /dev/kbd, could be the console */
-		if(zs_intreg & CHAN_A_IRQMASK) {
-			if (zs_intreg & CHARxIP)
-				receive_chars(info, regs);
-			if (zs_intreg & CHATxIP)
-				transmit_chars(info);
-			if (zs_intreg & CHAEXT)
-				status_handle(info);
+		if (zs_intreg == CHA_Rx_AVAIL) {
+			receive_chars(info, regs);
+			return;
+		}
+		if(zs_intreg == CHA_Tx_EMPTY) {
+			transmit_chars(info);
+			return;
+		}
+		if (zs_intreg == CHA_EXT_STAT) {
+			status_handle(info);
+			return;
+		}
+		if (zs_intreg == CHA_SPECIAL) {
+			special_receive(info);
+			return;
 		}
-
-		info=info->zs_next;
 
 		/* Channel B -- /dev/ttyb or /dev/mouse, could be the console */
-		if(zs_intreg & CHAN_B_IRQMASK) {
-			if (zs_intreg & CHBRxIP)
-				receive_chars(info, regs);
-			if (zs_intreg & CHBTxIP)
-				transmit_chars(info);
-			if (zs_intreg & CHBEXT)
-				status_handle(info);
+		if(zs_intreg == CHB_Rx_AVAIL) {
+			receive_chars(info->zs_next, regs);
+			return;
+		}
+		if(zs_intreg == CHB_Tx_EMPTY) {
+			transmit_chars(info->zs_next);
+			return;
 		}
+		if (zs_intreg == CHB_EXT_STAT) {
+			status_handle(info->zs_next);
+			return;
+		}
+
+		/* NOTE: The default value for the IRQ status in read register
+		 *       2 in channel B is CHB_SPECIAL, so we need to look at
+		 *       read register 3 in channel A to check if this is a
+		 *       real interrupt, or just the default value.
+		 *       Yes... broken hardware...
+		 */
 
-		info = info->zs_next;
+		zs_intreg = read_zsreg(info->zs_channel, 3);
+		if (zs_intreg & CHBRxIP) {
+			special_receive(info->zs_next);
+			return;
+		}
+		info = info->zs_next->zs_next;
 	}
 }
 
@@ -811,6 +854,7 @@
 {
 	unsigned short port;
 	unsigned cflag;
+	int	quot = 0;
 	int	i;
 	int	brg;
 
@@ -821,13 +865,30 @@
 		return;
 	i = cflag & CBAUD;
 	if (cflag & CBAUDEX) {
-		/* XXX CBAUDEX is not obeyed.
-		 * It is impossible at a 32bits SPARC.
-		 * But we have to report this to user ... someday.
-		 */
-		i = B9600;
+		i &= ~CBAUDEX;
+		if (i != 1)
+			info->tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			i += 15;
 	}
-	if (baud_table[i]) {
+	if (i == 15) {
+		if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_HI)
+			i += 1;
+		if ((info->flags & ZILOG_SPD_MASK) == ZILOG_SPD_CUST)
+			quot = info->custom_divisor;
+	}
+	if (quot) {
+		info->zs_baud = info->baud_base / quot;
+		info->clk_divisor = 16;
+
+		info->curregs[4] = X16CLK;
+		info->curregs[11] = TCBR | RCBR;
+		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+		info->curregs[12] = (brg & 255);
+		info->curregs[13] = ((brg >> 8) & 255);
+		info->curregs[14] = BRSRC | BRENAB;
+		zs_rtsdtr(info, 1);
+	} else if (baud_table[i]) {
 		info->zs_baud = baud_table[i];
 		info->clk_divisor = 16;
 
@@ -837,8 +898,10 @@
 		info->curregs[12] = (brg & 255);
 		info->curregs[13] = ((brg >> 8) & 255);
 		info->curregs[14] = BRSRC | BRENAB;
-	/* } else { */
-	/* XXX */
+		zs_rtsdtr(info, 1);
+	} else {
+		zs_rtsdtr(info, 0);
+		return;
 	}
 
 	/* byte size and parity */
@@ -902,7 +965,7 @@
 void kbd_put_char(unsigned char ch)
 {
 	struct sun_zschannel *chan = zs_kbdchan;
-	int flags;
+	unsigned long flags;
 
 	if(!chan)
 		return;
@@ -915,7 +978,7 @@
 void mouse_put_char(char ch)
 {
 	struct sun_zschannel *chan = zs_mousechan;
-	int flags;
+	unsigned long flags;
 
 	if(!chan)
 		return;
@@ -930,7 +993,7 @@
 static void rs_put_char(char ch)
 {
 	struct sun_zschannel *chan = zs_conschan;
-	int flags;
+	unsigned long flags;
 
 	if(!chan)
 		return;
@@ -984,7 +1047,7 @@
 
 		rs_put_char(c);
 
-		save_flags(flags);  cli();
+		cli();
 		left = MIN(info->xmit_cnt, left-1);
 	}
 
@@ -1262,6 +1325,7 @@
 	info->baud_base = new_serial.baud_base;
 	info->flags = ((info->flags & ~ZILOG_FLAGS) |
 			(new_serial.flags & ZILOG_FLAGS));
+	info->custom_divisor = new_serial.custom_divisor;
 	info->type = new_serial.type;
 	info->close_delay = new_serial.close_delay;
 	info->closing_wait = new_serial.closing_wait;
@@ -1292,6 +1356,56 @@
 	return 0;
 }
 
+static int get_modem_info(struct sun_serial * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+
+	cli();
+	status = info->zs_channel->control;
+	sti();
+	result =  ((info->curregs[5] & RTS) ? TIOCM_RTS : 0)
+		| ((info->curregs[5] & DTR) ? TIOCM_DTR : 0)
+		| ((status  & DCD) ? TIOCM_CAR : 0)
+		| ((status  & SYNC) ? TIOCM_DSR : 0)
+		| ((status  & CTS) ? TIOCM_CTS : 0);
+	put_user_ret(result, value, -EFAULT);
+	return 0;
+}
+
+static int set_modem_info(struct sun_serial * info, unsigned int cmd,
+			  unsigned int *value)
+{
+	unsigned int arg;
+
+	get_user_ret(arg, value, -EFAULT);
+	switch (cmd) {
+	case TIOCMBIS: 
+		if (arg & TIOCM_RTS)
+			info->curregs[5] |= RTS;
+		if (arg & TIOCM_DTR)
+			info->curregs[5] |= DTR;
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->curregs[5] &= ~RTS;
+		if (arg & TIOCM_DTR)
+			info->curregs[5] &= ~DTR;
+		break;
+	case TIOCMSET:
+		info->curregs[5] = ((info->curregs[5] & ~(RTS | DTR))
+			     | ((arg & TIOCM_RTS) ? RTS : 0)
+			     | ((arg & TIOCM_DTR) ? DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	cli();
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+	return 0;
+}
+
 /*
  * This routine sends a break character out the serial port.
  */
@@ -1341,7 +1455,8 @@
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
 			return 0;
 		case TIOCGSOFTCAR:
-			put_user_ret(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg, -EFAULT);
+			put_user_ret(C_CLOCAL(tty) ? 1 : 0,
+				     (unsigned long *) arg, -EFAULT);
 			return 0;
 		case TIOCSSOFTCAR:
 			get_user_ret(arg, (unsigned long *) arg, -EFAULT);
@@ -1349,6 +1464,12 @@
 				((tty->termios->c_cflag & ~CLOCAL) |
 				 (arg ? CLOCAL : 0));
 			return 0;
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
 		case TIOCGSERIAL:
 			return get_serial_info(info,
 					       (struct serial_struct *) arg);
@@ -1736,7 +1857,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.27 $";
+	char *revision = "$Revision: 1.37 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -1752,12 +1873,12 @@
  *       Zilogs, what the second does, I don't know. It does work
  *       with using only the first number of each property.
  */
-static inline struct sun_zslayout *get_zs(int chip)
+static struct sun_zslayout *get_zs(int chip)
 {
 	struct linux_prom_irqs tmp_irq[2];
-	unsigned long paddr = 0;
-	unsigned long vaddr[2] = { 0, 0 };
-	int zsnode, tmpnode, iospace, slave, len;
+	unsigned int paddr = 0;
+	unsigned int vaddr[2] = { 0, 0 };
+	int zsnode, tmpnode, iospace, slave, len, seen, sun4u_irq;
 	static int irq = 0;
 
 #if CONFIG_AP1000
@@ -1784,7 +1905,7 @@
 		if(!irq)
 			zilog_irq = irq = 12;
 		vaddr[0] = (unsigned long)
-				sparc_alloc_io((char *) paddr, 0, 8,
+				sparc_alloc_io(paddr, 0, 8,
 					       "Zilog Serial", iospace, 0);
 	} else {
 		/* Can use the prom for other machine types */
@@ -1806,6 +1927,10 @@
 			}
 			if (!tmpnode)
 				panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1);
+		} else if (sparc_cpu_model == sun4u) {
+			tmpnode = prom_searchsiblings(zsnode, "sbus");
+			if(tmpnode)
+				zsnode = prom_getchild(tmpnode);
 		} else {
 			tmpnode = prom_searchsiblings(zsnode, "obio");
 			if(tmpnode)
@@ -1813,35 +1938,42 @@
 		}
 		if(!zsnode)
 			panic("get_zs no zs serial prom node");
+		seen = 0;
 		while(zsnode) {
 			zsnode = prom_searchsiblings(zsnode, "zs");
 			slave = prom_getintdefault(zsnode, "slave", -1);
-			if(slave==chip) {
+			if((slave == chip) ||
+			   (sparc_cpu_model == sun4u && seen == chip)) {
 				/* The one we want */
 				len = prom_getproperty(zsnode, "address",
 						       (void *) vaddr,
 						       sizeof(vaddr));
-        			if (len % sizeof(unsigned long)) {
+        			if (len % sizeof(unsigned int)) {
 					prom_printf("WHOOPS:  proplen for %s "
 						"was %d, need multiple of "
 						"%d\n", "address", len,
-						sizeof(unsigned long));
+						sizeof(unsigned int));
 					panic("zilog: address property");
 				}
 				zs_nodes[chip] = zsnode;
-				len = prom_getproperty(zsnode, "intr",
-						       (char *) tmp_irq,
-						       sizeof(tmp_irq));
-        			if (len % sizeof(struct linux_prom_irqs)) {
-					prom_printf("WHOOPS:  proplen for %s "
-						"was %d, need multiple of "
-						"%d\n", "address", len,
-						sizeof(struct linux_prom_irqs));
-					panic("zilog: address property");
+				if(sparc_cpu_model == sun4u) {
+					len = prom_getproperty(zsnode, "interrupts",
+							       (char *) &sun4u_irq,
+							       sizeof(tmp_irq));
+					tmp_irq[0].pri = sun4u_irq;
+				} else {
+					len = prom_getproperty(zsnode, "intr",
+							       (char *) tmp_irq,
+							       sizeof(tmp_irq));
+					if (len % sizeof(struct linux_prom_irqs)) {
+						prom_printf(
+						      "WHOOPS:  proplen for %s "
+						      "was %d, need multiple of "
+						      "%d\n", "address", len,
+						      sizeof(struct linux_prom_irqs));
+						panic("zilog: address property");
+					}
 				}
-#ifdef OLD_STYLE_IRQ
-				tmp_irq[0].pri &= 0xf;
-#endif
 				if(!irq) {
 					irq = zilog_irq = tmp_irq[0].pri;
 				} else {
@@ -1851,6 +1983,7 @@
 				break;
 			}
 			zsnode = prom_getsibling(zsnode);
+			seen++;
 		}
 		if(!zsnode)
 			panic("get_zs whee chip not found");
@@ -2037,8 +2170,8 @@
 rs_cons_check(struct sun_serial *ss, int channel)
 {
 	int i, o, io;
-	static consout_registered = 0;
-	static msg_printed = 0;
+	static int consout_registered = 0;
+	static int msg_printed = 0;
 
 	i = o = io = 0;
 
@@ -2144,7 +2277,8 @@
 
 __initfunc(int rs_init(void))
 {
-	int chip, channel, brg, i, flags;
+	int chip, channel, brg, i;
+	unsigned long flags;
 	struct sun_serial *info;
 	char dummy;
 
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/sunserial.h linux/drivers/sbus/char/sunserial.h
--- v2.1.33/linux/drivers/sbus/char/sunserial.h	Fri Dec 13 01:37:37 1996
+++ linux/drivers/sbus/char/sunserial.h	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: sunserial.h,v 1.5 1996/10/16 13:13:41 zaitcev Exp $
+/* $Id: sunserial.h,v 1.9 1997/04/12 23:33:12 ecd Exp $
  * serial.h: Definitions for the Sparc Zilog serial driver.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -68,9 +68,7 @@
 #define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
 
 #define ZILOG_SPD_MASK	0x0030
-#define ZILOG_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_HI	0x0010	/* Use 76800 instead of 38400 bps */
 #define ZILOG_SPD_CUST	0x0030  /* Use user-specified divisor */
 
 #define ZILOG_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
@@ -366,7 +364,7 @@
 #define	ZCOUNT		0x2	/* Zero count */
 #define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
 #define	DCD		0x8	/* DCD */
-#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	SYNC		0x10	/* Sync/hunt */
 #define	CTS		0x20	/* CTS */
 #define	TxEOM		0x40	/* Tx underrun */
 #define	BRK_ABRT	0x80	/* Break/Abort */
@@ -389,6 +387,15 @@
 #define	END_FR		0x80	/* End of Frame (SDLC) */
 
 /* Read Register 2 (channel b only) - Interrupt vector */
+#define CHB_Tx_EMPTY	0x00
+#define CHB_EXT_STAT	0x02
+#define CHB_Rx_AVAIL	0x04
+#define CHB_SPECIAL	0x06
+#define CHA_Tx_EMPTY	0x08
+#define CHA_EXT_STAT	0x0a
+#define CHA_Rx_AVAIL	0x0c
+#define CHA_SPECIAL	0x0e
+#define STATUS_MASK	0x0e
 
 /* Read Register 3 (interrupt pending register) ch a only */
 #define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
@@ -414,6 +421,9 @@
 
 /* Misc macros */
 #define ZS_CLEARERR(channel)    do { channel->control = ERR_RES; \
+				     udelay(5); } while(0)
+
+#define ZS_CLEARSTAT(channel)   do { channel->control = RES_EXT_INT; \
 				     udelay(5); } while(0)
 
 #define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c
--- v2.1.33/linux/drivers/sbus/char/tcx.c	Mon Dec 30 02:00:05 1996
+++ linux/drivers/sbus/char/tcx.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.9 1996/12/23 10:16:17 ecd Exp $
+/* $Id: tcx.c,v 1.11 1997/04/10 03:02:43 davem Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -272,7 +272,7 @@
 	tcx->bt->control |= 0x03 << 24;
 }
 
-__initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, uint tcx, struct linux_sbus_device *sbdp))
+__initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, unsigned long tcx, struct linux_sbus_device *sbdp))
 {
 	struct tcx_info *tcxinfo;
 	int i;
@@ -299,15 +299,16 @@
 		tcxinfo->tcx_offsets [i] = (long)(sbdp->reg_addrs [i].phys_addr);
 		
 	/* Map the hardware registers */
-	tcxinfo->bt = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_BROOKTREE_OFFSET], 0,
+	tcxinfo->bt = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_BROOKTREE_OFFSET], 0,
 		 sizeof (struct bt_regs),"tcx_dac", fb->space, 0);
-	tcxinfo->thc = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_THC_OFFSET], 0,
+	tcxinfo->thc = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_THC_OFFSET], 0,
 		 sizeof (struct tcx_thc), "tcx_thc", fb->space, 0);
-	tcxinfo->tec = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
+	tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
 		 sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
 	if (!fb->base){
-		fb->base = (uint) sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
-                    fb->type.fb_size, "tcx_ram", fb->space, 0);
+		fb->base = (uint)
+			sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
+				       fb->type.fb_size, "tcx_ram", fb->space, 0);
 	}
 	
 	if (prom_getbool (node, "hw-cursor")) {
@@ -336,8 +337,10 @@
 		tcxinfo->tcx_sizes[5] = i << 3;
 		tcxinfo->tcx_sizes[6] = i << 3;
 		fb->type.fb_depth = 24;
-		tcxinfo->tcx_cplane = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_CONTROLPLANE_OFFSET], 0,
-		 	tcxinfo->tcx_sizes [TCX_CONTROLPLANE_OFFSET], "tcx_cplane", fb->space, 0);
+		tcxinfo->tcx_cplane =
+		   sparc_alloc_io((u32)tcxinfo->tcx_offsets[TCX_CONTROLPLANE_OFFSET], 0,
+				  tcxinfo->tcx_sizes [TCX_CONTROLPLANE_OFFSET],
+				  "tcx_cplane", fb->space, 0);
 	}
 	
 	/* Initialize Brooktree DAC */
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc.h linux/drivers/sbus/char/vfc.h
--- v2.1.33/linux/drivers/sbus/char/vfc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/vfc.h	Fri Apr 11 10:47:37 1997
@@ -0,0 +1,171 @@
+#ifndef _LINUX_VFC_H_
+#define _LINUX_VFC_H_
+
+/*
+ * The control register for the vfc is at offset 0x4000
+ * The first field ram bank is located at offset 0x5000
+ * The second field ram bank is at offset 0x7000
+ * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) 
+ *    data and transmit register.
+ * i2c_s1 controls register s1 of the PCF8584
+ * i2c_write seems to be similar to i2c_write but I am not 
+ *    quite sure why sun uses it
+ * 
+ * I am also not sure whether or not you can read the fram bank as a
+ * whole or whether you must read each word individually from offset
+ * 0x5000 as soon as I figure it out I will update this file */
+
+struct vfc_regs {
+	char pad1[0x4000];
+	unsigned int control;  /* Offset 0x4000 */
+	char pad2[0xffb];      /* from offset 0x4004 to 0x5000 */
+	unsigned int fram_bank1; /* Offset 0x5000 */
+	char pad3[0xffb];        /* from offset 0x5004 to 0x6000 */
+	unsigned int i2c_reg; /* Offset 0x6000 */
+	unsigned int i2c_magic2; /* Offset 0x6004 */
+	unsigned int i2c_s1;  /* Offset 0x6008 */
+	unsigned int i2c_write; /* Offset 0x600c */
+	char pad4[0xff0];     /* from offset 0x6010 to 0x7000 */
+	unsigned int fram_bank2; /* Offset 0x7000 */
+	char pad5[0x1000];
+};
+
+#define VFC_SAA9051_NR (13)
+#define VFC_SAA9051_ADDR (0x8a)
+	/* The saa9051 returns the following for its status 
+	 * bit 0 - 0
+	 * bit 1 - SECAM color detected (1=found,0=not found)
+	 * bit 2 - COLOR detected (1=found,0=not found)
+	 * bit 3 - 0
+	 * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL))
+	 * bit 5 - 1
+	 * bit 6 - horizontal frequency lock (1=transmitter found,
+	 *                                    0=no transmitter)
+	 * bit 7 - Power on reset bit (1=reset,0=at least one successful 
+	 *                                       read of the status byte)
+	 */
+
+#define VFC_SAA9051_PONRES (0x80)
+#define VFC_SAA9051_HLOCK (0x40)
+#define VFC_SAA9051_FD (0x10)
+#define VFC_SAA9051_CD (0x04)
+#define VFC_SAA9051_CS (0x02)
+
+
+/* The various saa9051 sub addresses */
+
+#define VFC_SAA9051_IDEL (0) 
+#define VFC_SAA9051_HSY_START (1)
+#define VFC_SAA9051_HSY_STOP (2)
+#define VFC_SAA9051_HC_START (3)
+#define VFC_SAA9051_HC_STOP (4)
+#define VFC_SAA9051_HS_START (5)
+#define VFC_SAA9051_HORIZ_PEAK (6)
+#define VFC_SAA9051_HUE (7)
+#define VFC_SAA9051_C1 (8)
+#define VFC_SAA9051_C2 (9)
+#define VFC_SAA9051_C3 (0xa)
+#define VFC_SAA9051_SECAM_DELAY (0xb)
+
+
+/* Bit settings for saa9051 sub address 0x06 */
+
+#define VFC_SAA9051_AP1 (0x01)
+#define VFC_SAA9051_AP2 (0x02)
+#define VFC_SAA9051_COR1 (0x04)
+#define VFC_SAA9051_COR2 (0x08)
+#define VFC_SAA9051_BP1 (0x10)
+#define VFC_SAA9051_BP2 (0x20)
+#define VFC_SAA9051_PF (0x40)
+#define VFC_SAA9051_BY (0x80)
+
+
+/* Bit settings for saa9051 sub address 0x08 */
+
+#define VFC_SAA9051_CCFR0 (0x01)
+#define VFC_SAA9051_CCFR1 (0x02)
+#define VFC_SAA9051_YPN (0x04)
+#define VFC_SAA9051_ALT (0x08)
+#define VFC_SAA9051_CO (0x10)
+#define VFC_SAA9051_VTR (0x20)
+#define VFC_SAA9051_FS (0x40)
+#define VFC_SAA9051_HPLL (0x80)
+
+
+/* Bit settings for saa9051 sub address 9 */
+
+#define VFC_SAA9051_SS0 (0x01)
+#define VFC_SAA9051_SS1 (0x02)
+#define VFC_SAA9051_AFCC (0x04)
+#define VFC_SAA9051_CI (0x08)
+#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */
+#define VFC_SAA9051_OEC (0x20)
+#define VFC_SAA9051_OEY (0x40)
+#define VFC_SAA9051_VNL (0x80)
+
+
+/* Bit settings for saa9051 sub address 0x0A */
+
+#define VFC_SAA9051_YDL0 (0x01)
+#define VFC_SAA9051_YDL1 (0x02)
+#define VFC_SAA9051_YDL2 (0x04)
+#define VFC_SAA9051_SS2 (0x08)
+#define VFC_SAA9051_SS3 (0x10)
+#define VFC_SAA9051_YC (0x20)
+#define VFC_SAA9051_CT (0x40)
+#define VFC_SAA9051_SYC (0x80)
+
+
+#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1])
+#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\
+					    (a)->saa9051_state_array,\
+					    VFC_SAA9051_NR))
+
+
+struct vfc_dev {
+	volatile struct vfc_regs *regs;
+	struct vfc_regs *phys_regs;
+	unsigned int control_reg;
+	struct semaphore device_lock_sem;
+	struct timer_list poll_timer;
+	struct wait_queue *poll_wait;
+	int instance;
+	int busy;
+	unsigned long which_io;
+	unsigned char saa9051_state_array[VFC_SAA9051_NR];
+};
+
+extern struct vfc_dev **vfc_dev_lst;
+
+void captstat_reset(struct vfc_dev *);
+void memptr_reset(struct vfc_dev *);
+
+int vfc_pcf8584_init(struct vfc_dev *);
+void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long);
+void vfc_i2c_delay(struct vfc_dev *);
+int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ;
+int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ;
+int vfc_i2c_reset_bus(struct vfc_dev *);
+int vfc_init_i2c_bus(struct vfc_dev *);
+void vfc_lock_device(struct vfc_dev *);
+void vfc_unlock_device(struct vfc_dev *);
+
+#define VFC_CONTROL_DIAGMODE  0x10000000
+#define VFC_CONTROL_MEMPTR    0x20000000
+#define VFC_CONTROL_CAPTURE   0x02000000
+#define VFC_CONTROL_CAPTRESET 0x04000000
+
+#define VFC_STATUS_CAPTURE    0x08000000
+
+#ifdef VFC_DEBUG
+#define VFC_DEBUG_PRINTK(a) printk a
+#else
+#define VFC_DEBUG_PRINTK(a)
+#endif
+
+#endif /* _LINUX_VFC_H_ */
+
+
+
+
+
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.1.33/linux/drivers/sbus/char/vfc_dev.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/vfc_dev.c	Fri Apr 11 10:47:37 1997
@@ -0,0 +1,693 @@
+/*
+ * drivers/sbus/char/vfc_dev.c
+ *
+ * Driver for the Videopix Frame Grabber.
+ * 
+ * In order to use the VFC you need to progeam the video controller
+ * chip. This chip is the Phillips SAA9051.  You need to call their
+ * documentation ordering line to get the docs.
+ *
+ * Their is very little documentation on the VFC itself.  There is
+ * some useful info that can be found in the manuals that come with
+ * the card.  I will hopefully write some better docs at a later date.
+ *
+ * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sbus.h>
+#include <asm/delay.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+#define VFC_MAJOR (60)
+
+#if 0
+#define VFC_DEBUG
+#endif
+
+#include "vfc.h"
+#include <asm/vfc_ioctls.h>
+
+struct vfc_dev **vfc_dev_lst;
+static char vfcstr[]="vfc";
+static unsigned char saa9051_init_array[VFC_SAA9051_NR]=
+{ 0x00, 0x64, 0x72, 0x52,
+  0x36, 0x18, 0xff, 0x20,
+  0xfc, 0x77, 0xe3, 0x50,
+  0x3e};
+
+void vfc_lock_device(struct vfc_dev *dev) {
+	down(&dev->device_lock_sem);
+}
+
+void vfc_unlock_device(struct vfc_dev *dev) {
+	up(&dev->device_lock_sem);
+}
+
+
+void vfc_captstat_reset(struct vfc_dev *dev) 
+{
+	dev->control_reg |= VFC_CONTROL_CAPTRESET;
+	dev->regs->control=dev->control_reg;
+	dev->control_reg &= ~VFC_CONTROL_CAPTRESET;
+	dev->regs->control=dev->control_reg;
+	dev->control_reg |= VFC_CONTROL_CAPTRESET;
+	dev->regs->control=dev->control_reg;
+	return;
+}
+
+void vfc_memptr_reset(struct vfc_dev *dev) 
+{
+	dev->control_reg |= VFC_CONTROL_MEMPTR;
+	dev->regs->control = dev->control_reg; 
+	dev->control_reg &= ~VFC_CONTROL_MEMPTR;
+	dev->regs->control = dev->control_reg; 
+	dev->control_reg |= VFC_CONTROL_MEMPTR; 
+	dev->regs->control = dev->control_reg; 
+	return;
+}
+
+int vfc_csr_init(struct vfc_dev *dev)
+{
+	dev->control_reg = 0x80000000;
+	dev->regs->control = dev->control_reg;
+	udelay(200); 
+	dev->control_reg &= ~0x80000000;
+	dev->regs->control = dev->control_reg;
+	udelay(100); 
+	dev->regs->i2c_magic2 = 0x0f000000; 
+
+	vfc_memptr_reset(dev);
+
+	dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
+	dev->control_reg &= ~VFC_CONTROL_CAPTURE;
+	dev->control_reg |= 0x40000000;
+	dev->regs->control=dev->control_reg; 
+
+	vfc_captstat_reset(dev);
+
+	return 0;
+}
+
+int vfc_saa9051_init(struct vfc_dev *dev)
+{
+	int i;
+	for(i=0;i<VFC_SAA9051_NR;i++) {
+		dev->saa9051_state_array[i]=saa9051_init_array[i];
+	}
+	vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR,
+			dev->saa9051_state_array, VFC_SAA9051_NR);
+	return 0;
+}
+
+int init_vfc_hw(struct vfc_dev *dev) 
+{
+	vfc_lock_device(dev);
+	vfc_csr_init(dev);
+
+	vfc_pcf8584_init(dev);
+	vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic
+				  sun code above*/
+	vfc_saa9051_init(dev);
+	vfc_unlock_device(dev);
+	return 0; 
+}
+
+int init_vfc_devstruct(struct vfc_dev *dev, int instance) 
+{
+	dev->instance=instance;
+	dev->device_lock_sem=MUTEX;
+	dev->control_reg=0;
+	dev->poll_wait=NULL;
+	dev->busy=0;
+	/* initialize the timer struct */
+	return 0;
+}
+
+int init_vfc_device(struct linux_sbus_device *sdev,struct vfc_dev *dev,
+		    int instance) {
+	struct linux_prom_registers reg;
+	if(!dev) {
+		printk(KERN_ERR "VFC: Bogus pointer passed\n");
+		return -ENOMEM;
+	}
+	printk("Initializing vfc%d\n",instance);
+	dev->regs=NULL;
+	memcpy(&reg,&sdev->reg_addrs[0],sizeof(struct linux_prom_registers));
+	prom_apply_sbus_ranges(sdev->my_bus, &reg, sdev->num_registers, sdev);
+	dev->regs=sparc_alloc_io(reg.phys_addr, 0,
+				 sizeof(struct vfc_regs), vfcstr, 
+				 reg.which_io, 0x0);
+	dev->which_io=reg.which_io;
+	dev->phys_regs=(struct vfc_regs *)reg.phys_addr;
+	if(!dev->regs) return -EIO;
+
+	printk("vfc%d: registers mapped at phys_addr: 0x%lx\n    virt_addr: 0x%lx\n",
+	       instance,(unsigned long)reg.phys_addr,(unsigned long)dev->regs);
+
+	if(init_vfc_devstruct(dev,instance)) return -EINVAL;
+	if(init_vfc_hw(dev)) return -EIO;
+
+	return 0;
+}
+
+
+struct vfc_dev *vfc_get_dev_ptr(int instance) 
+{
+	return vfc_dev_lst[instance];
+}
+
+static int vfc_open(struct inode *inode, struct file *file) 
+{
+	struct vfc_dev *dev;
+	dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+	if(!dev) return -ENODEV;
+	if(dev->busy) return -EBUSY;
+	dev->busy=1;
+	MOD_INC_USE_COUNT;
+	vfc_lock_device(dev);
+	
+	vfc_csr_init(dev);
+	vfc_pcf8584_init(dev);
+	vfc_init_i2c_bus(dev);
+	vfc_saa9051_init(dev);
+	vfc_memptr_reset(dev);
+	vfc_captstat_reset(dev);
+	
+	vfc_unlock_device(dev);
+	return 0;
+}
+
+static int vfc_release(struct inode *inode,struct file *file) 
+{
+	struct vfc_dev *dev;
+	dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+	if(!dev) return -EINVAL;
+	if(!dev->busy) return 0;
+	dev->busy=0;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) 
+{
+	struct vfc_debug_inout inout;
+	unsigned char *buffer;
+
+	switch(cmd) {
+	case VFC_I2C_SEND:
+		if(copy_from_user(&inout, (void *)arg, sizeof(inout))) 
+			return -EFAULT;
+
+		buffer = kmalloc(inout.len*sizeof(char), GFP_KERNEL);
+		if (!buffer)
+			return -ENOMEM;
+		if(copy_from_user(buffer, inout.buffer, inout.len*sizeof(char))) {
+			kfree_s(buffer,inout.len);
+			return -EFAULT;
+		}
+
+		vfc_lock_device(dev);
+		inout.ret=
+			vfc_i2c_sendbuf(dev,inout.addr & 0xff,
+					inout.buffer,inout.len);
+		if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
+			kfree_s(buffer,inout.len);
+			return -EFAULT;
+		}
+		vfc_unlock_device(dev);
+
+		kfree_s(buffer, inout.len);
+
+		break;
+	case VFC_I2C_RECV:
+
+		if(copy_from_user(&inout, (void *)arg, sizeof(inout)))
+			return -EFAULT;
+
+		buffer = kmalloc(inout.len, GFP_KERNEL);
+		if (!buffer)
+			return -ENOMEM;
+		memset(buffer,0,inout.len*sizeof(char));
+		vfc_lock_device(dev);
+		inout.ret=
+			vfc_i2c_recvbuf(dev,inout.addr & 0xff
+					,buffer,inout.len);
+		vfc_unlock_device(dev);
+		
+		if(copy_to_user(inout.buffer, buffer, inout.len)) {
+			kfree_s(buffer,inout.len);
+			return -EFAULT;
+		}
+		if(copy_to_user((void *)arg,&inout,sizeof(inout))) {
+			kfree_s(buffer,inout.len);
+			return -EFAULT;
+		}
+		kfree_s(buffer,inout.len);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int vfc_capture_start(struct vfc_dev *dev) 
+{
+	vfc_captstat_reset(dev);
+	dev->control_reg=dev->regs->control;
+	if((dev->control_reg & VFC_STATUS_CAPTURE)) {
+		printk(KERN_ERR "vfc%d: vfc capture status not reset\n",
+		       dev->instance);
+		return -EIO;
+	}
+
+	vfc_lock_device(dev);
+	dev->control_reg &= ~VFC_CONTROL_CAPTURE;
+	dev->regs->control=dev->control_reg;
+	dev->control_reg |= VFC_CONTROL_CAPTURE;
+	dev->regs->control=dev->control_reg;
+	dev->control_reg &= ~VFC_CONTROL_CAPTURE;
+	dev->regs->control=dev->control_reg;
+	vfc_unlock_device(dev);
+
+	return 0;
+}
+
+int vfc_capture_poll(struct vfc_dev *dev) 
+{
+	int timeout=1000;
+	while(!timeout--) {
+		if((dev->regs->control & VFC_STATUS_CAPTURE)) break;
+		vfc_i2c_delay_no_busy(dev,100);
+	}
+	if(!timeout) {
+		printk(KERN_WARNING "vfc%d: capture timed out\n", dev->instance);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+
+
+static int vfc_set_control_ioctl(struct inode *inode, struct file *file, 
+			  struct vfc_dev *dev, unsigned long arg) 
+{
+	int setcmd,ret=0;
+	if(copy_from_user(&setcmd,(void *)arg,sizeof(unsigned int)))
+		return -EFAULT;
+#if 0
+	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
+			  dev->instance,setcmd));
+#endif
+	switch(setcmd) {
+	case MEMPRST:
+		vfc_lock_device(dev);
+		vfc_memptr_reset(dev);
+		vfc_unlock_device(dev);
+		ret=0;
+		break;
+	case CAPTRCMD:
+		vfc_capture_start(dev);
+		vfc_capture_poll(dev);
+		break;
+	case DIAGMODE:
+		if(suser()) {
+			vfc_lock_device(dev);
+			dev->control_reg |= VFC_CONTROL_DIAGMODE;
+			dev->regs->control = dev->control_reg;
+			vfc_unlock_device(dev);
+			ret=0;
+		} else ret=-EPERM; 
+		break;
+	case NORMMODE:
+		vfc_lock_device(dev);
+		dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
+		dev->regs->control = dev->control_reg;
+		vfc_unlock_device(dev);
+		ret=0;
+		break;
+	case CAPTRSTR:
+		vfc_capture_start(dev);
+		ret=0;
+		break;
+	case CAPTRWAIT:
+		vfc_capture_poll(dev);
+		ret=0;
+		break;
+	default:
+		ret=-EINVAL;
+	}
+	return ret;
+}
+
+
+int vfc_port_change_ioctl(struct inode *inode, struct file *file, 
+			  struct vfc_dev *dev, unsigned long arg) 
+{
+	int ret=0;
+	int cmd;
+	if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
+		VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+				  "vfc_port_change_ioctl\n",dev->instance));
+		return -EFAULT;
+	}
+	
+	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
+			  dev->instance,cmd));
+
+	switch(cmd) {
+	case 1:
+	case 2:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; 
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e;
+		break;
+	case 3:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
+		break;
+	default:
+		ret=-EINVAL;
+		return ret;
+		break;
+	}
+
+	switch(cmd) {
+	case 1:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0 | VFC_SAA9051_SS1;
+		break;
+	case 2:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &= ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; 
+		break;
+	case 3:
+		break;
+	default:
+		ret=-EINVAL;
+		return ret;
+		break;
+	}
+	VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2);
+	ret=vfc_update_saa9051(dev);
+	udelay(500);
+	VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2);
+	ret=vfc_update_saa9051(dev);
+	return ret;
+}
+
+int vfc_set_video_ioctl(struct inode *inode, struct file *file, 
+			struct vfc_dev *dev, unsigned long arg) 
+{
+	int ret=0;
+	int cmd;
+	if(copy_from_user(&cmd, (void *)arg, sizeof(unsigned int))) {
+		VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+				  "vfc_set_video_ioctl\n",dev->instance));
+		return -EFAULT;
+	}
+	
+	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
+			  dev->instance,cmd));
+	switch(cmd) {
+
+	case STD_NTSC:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | 
+			VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS;
+		ret=vfc_update_saa9051(dev);
+		break;
+	case STD_PAL:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | 
+							VFC_SAA9051_CCFR1 | 
+							VFC_SAA9051_CCFR0 |
+							VFC_SAA9051_FS);
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT;
+		ret=vfc_update_saa9051(dev);
+		break;
+
+	case COLOR_ON:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO;
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &= ~(VFC_SAA9051_BY | VFC_SAA9051_PF);
+		ret=vfc_update_saa9051(dev);
+		break;
+	case MONO:
+		VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO);
+		VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |= VFC_SAA9051_BY | VFC_SAA9051_PF;
+		ret=vfc_update_saa9051(dev);
+		break;
+	default:
+		ret=-EINVAL;
+		break;
+	}
+	return ret;
+}
+
+int vfc_get_video_ioctl(struct inode *inode, struct file *file, 
+			struct vfc_dev *dev, unsigned long arg) 
+{
+	int ret=0;
+	unsigned int status=NO_LOCK;
+	unsigned char buf[1];
+
+	if(vfc_i2c_recvbuf(dev,VFC_SAA9051_ADDR,buf,1)) {
+		printk(KERN_ERR "vfc%d: Unable to get status\n",dev->instance);
+		return -EIO;
+	}
+
+	if(buf[0] & VFC_SAA9051_HLOCK) {
+		status = NO_LOCK;
+	} else if(buf[0] & VFC_SAA9051_FD) {
+		if(buf[0] & VFC_SAA9051_CD)
+			status=NTSC_COLOR;
+		else
+			status=NTSC_NOCOLOR;
+	} else {
+		if(buf[0] & VFC_SAA9051_CD)
+			status=PAL_COLOR;
+		else
+			status=PAL_NOCOLOR;
+	}
+	VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; buf[0]=%x\n",dev->instance,
+			  status,buf[0]));
+	if(copy_to_user((void *)arg,&status,sizeof(unsigned int))) {
+		VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
+				 "vfc_get_video_ioctl\n",dev->instance));
+		return -EFAULT;
+	}
+	return ret;
+}
+
+static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	      unsigned long arg) 
+{
+	int ret=0;
+	unsigned int tmp;
+	struct vfc_dev *dev;
+
+	dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+	if(!dev) return -ENODEV;
+	
+	switch(cmd & 0x0000ffff) {
+	case VFCGCTRL:
+#if 0
+		VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n",dev->instance));
+#endif
+		tmp=dev->regs->control;
+		if(copy_to_user((void *)arg,&tmp,sizeof(unsigned int)))
+			return -EFAULT;
+		ret=0;
+		break;
+	case VFCSCTRL:
+		ret=vfc_set_control_ioctl(inode, file, dev, arg);
+		break;
+	case VFCGVID:
+		ret=vfc_get_video_ioctl(inode,file,dev,arg);
+		break;
+	case VFCSVID:
+		ret=vfc_set_video_ioctl(inode,file,dev,arg);
+		break;
+	case VFCHUE:
+#if 0
+		VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n",dev->instance));
+#endif
+
+		if(copy_from_user(&tmp,(void *)arg,sizeof(unsigned int))) {
+			VFC_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
+					  "to IOCTL(VFCHUE)",dev->instance));
+			ret=-EFAULT;
+		} else {
+			VFC_SAA9051_SA(dev,VFC_SAA9051_HUE)=tmp;
+			vfc_update_saa9051(dev);
+			ret=0;
+		}
+		break;
+	case VFCPORTCHG:
+		ret=vfc_port_change_ioctl(inode, file, dev, arg);
+		break;
+	case VFCRDINFO:
+		ret=-EINVAL;
+		VFC_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n",dev->instance));
+		break;
+	default:
+		ret=vfc_debug(vfc_get_dev_ptr(MINOR(inode->i_rdev)),
+			      cmd,arg);
+		break;
+	}
+	return ret;
+}
+
+static int vfc_mmap(struct inode *inode, struct file *file, 
+	     struct vm_area_struct *vma) 
+{
+	unsigned int map_size,ret,map_offset;
+	struct vfc_dev *dev;
+	
+	dev=vfc_get_dev_ptr(MINOR(inode->i_rdev));
+	if(!dev) return -ENODEV;
+	
+	map_size=vma->vm_end - vma->vm_start;
+	if(map_size > sizeof(struct vfc_regs)) 
+		map_size=sizeof(struct vfc_regs);
+
+
+	if(vma->vm_offset & ~PAGE_MASK) return -ENXIO;
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE;
+	map_offset=(unsigned int)dev->phys_regs;
+	ret=io_remap_page_range(vma->vm_start,map_offset,map_size, 
+				vma->vm_page_prot, dev->which_io);
+	if(ret) return -EAGAIN;
+	vma->vm_inode=inode;
+	inode->i_count++;
+	return 0;
+}
+
+static long long vfc_lseek(struct inode *inode, struct file *file, 
+	      long long offset, int origin) 
+{
+	return -ESPIPE;
+}
+
+static struct file_operations vfc_fops = {
+	vfc_lseek,        /* vfc_lseek */
+	NULL,        /* vfc_write */
+	NULL,        /* vfc_read */
+	NULL,        /* vfc_readdir */
+	NULL,        /* vfc_poll */
+	vfc_ioctl,   
+	vfc_mmap, 
+	vfc_open,
+	vfc_release,
+};
+
+
+static int vfc_probe(void)
+{
+	struct linux_sbus *bus;
+	struct linux_sbus_device *sdev = NULL;
+	int ret;
+	int instance=0,cards=0;
+
+	for_all_sbusdev(sdev,bus) {
+		if (strcmp(sdev->prom_name,"vfc") == 0) {
+			cards++;
+			continue;
+		}
+	}
+
+	if (!cards)
+		return -ENODEV;
+
+	vfc_dev_lst=(struct vfc_dev **)kmalloc(sizeof(struct vfc_dev *)*
+					       (cards+1),
+					       GFP_KERNEL);
+	if(!vfc_dev_lst)
+		return -ENOMEM;
+	memset(vfc_dev_lst,0,sizeof(struct vfc_dev *)*(cards+1));
+	vfc_dev_lst[cards]=NULL;
+
+	ret=register_chrdev(VFC_MAJOR,vfcstr,&vfc_fops);
+	if(ret) {
+		printk(KERN_ERR "Unable to get major number %d\n",VFC_MAJOR);
+		kfree(vfc_dev_lst);
+		return -EIO;
+	}
+
+	instance=0;
+	for_all_sbusdev(sdev,bus) {
+		if (strcmp(sdev->prom_name,"vfc") == 0) {
+			vfc_dev_lst[instance]=(struct vfc_dev *)
+				kmalloc(sizeof(struct vfc_dev), GFP_KERNEL);
+			if(vfc_dev_lst[instance] == NULL) return -ENOMEM;
+			ret=init_vfc_device(sdev,
+					    vfc_dev_lst[instance],
+					    instance);
+			if(ret) {
+				printk(KERN_ERR "Unable to initialize"
+				       " vfc%d device\n",instance);
+			} else {
+			}
+		
+			instance++;
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+#else 
+int vfc_init(void)
+#endif
+{
+#ifdef MODULE
+	register_symtab(0);
+#endif
+	return vfc_probe();
+}
+
+#ifdef MODULE
+static void deinit_vfc_device(struct vfc_dev *dev)
+{
+	if(!dev) return;
+	sparc_free_io((void *)dev->regs,sizeof(struct vfc_regs));
+	kfree(dev);
+}
+
+void cleanup_module(void)
+{
+	struct vfc_dev **devp;
+	unregister_chrdev(VFC_MAJOR,vfcstr);
+	for(devp=vfc_dev_lst;*devp;devp++) {
+		deinit_vfc_device(*devp);
+	}
+	kfree(vfc_dev_lst);
+	return;
+}
+#endif
+
+
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc_i2c.c linux/drivers/sbus/char/vfc_i2c.c
--- v2.1.33/linux/drivers/sbus/char/vfc_i2c.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/vfc_i2c.c	Fri Apr 11 10:47:37 1997
@@ -0,0 +1,319 @@
+/*
+ * drivers/sbus/char/vfc_i2c.c
+ *
+ * Driver for the Videopix Frame Grabber.
+ * 
+ * Functions that support the Phillips i2c(I squared C) bus on the vfc
+ *  Documentation for the Phillips I2C bus can be found on the 
+ *  phillips home page
+ *
+ * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
+ *
+ */
+
+/* NOTE: It seems to me that the documentation regarding the
+pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
+Based on the information on the I2C bus itself and the remainder of
+the Phillips docs the following algorithims apper to be correct.  I am
+fairly certain that the flowcharts in the phillips docs are wrong. */
+
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sbus.h>
+
+#if 0
+#define VFC_DEBUG
+#endif
+
+#include "vfc.h"
+#include "vfc_i2c.h"
+
+#define VFC_I2C_READ (0x1)
+#define VFC_I2C_WRITE (0x0)
+     
+/****** 
+  The i2c bus controller chip on the VFC is a pcd8584t, but
+  phillips claims it doesn't exist.  As far as I can tell it is
+  identical to the PCF8584 so I treat it like it is the pcf8584.
+  
+  NOTE: The pcf8584 only cares
+  about the msb of the word you feed it 
+*****/
+
+int vfc_pcf8584_init(struct vfc_dev *dev) 
+{
+	dev->regs->i2c_s1=RESET;        /* This will also choose
+					   register S0_OWN so we can set it*/
+
+	dev->regs->i2c_reg=0x55000000;  /* the pcf8584 shifts this
+					   value left one bit and uses
+					   it as its i2c bus address */
+	dev->regs->i2c_s1=SELECT(S2);
+	dev->regs->i2c_reg=0x14000000;  /* this will set the i2c bus at
+					   the same speed sun uses,
+					   and set another magic bit */
+	
+	dev->regs->i2c_s1=CLEAR_I2C_BUS;   /* enable the serial port,
+					   idle the i2c bus and set
+					   the data reg to s0 */
+	udelay(100);
+	return 0;
+}
+
+void vfc_i2c_delay_wakeup(struct vfc_dev *dev) 
+{
+	wake_up(&dev->poll_wait);
+}
+
+void vfc_i2c_delay_no_busy(struct vfc_dev *dev,unsigned long usecs) 
+{
+	dev->poll_timer.next = NULL;
+	dev->poll_timer.prev = NULL;
+	dev->poll_timer.expires = jiffies + 
+		((unsigned long)usecs*(HZ))/1000000;
+	dev->poll_timer.data=(unsigned long)dev;
+	dev->poll_timer.function=(void *)(unsigned long)vfc_i2c_delay_wakeup;
+	add_timer(&dev->poll_timer);
+	sleep_on(&dev->poll_wait);
+	del_timer(&dev->poll_timer);
+}
+
+void inline vfc_i2c_delay(struct vfc_dev *dev) 
+{ 
+	vfc_i2c_delay_no_busy(dev,100);
+}
+
+int vfc_init_i2c_bus(struct vfc_dev *dev)
+{
+	dev->regs->i2c_s1= ENABLE_SERIAL | ACK;
+	vfc_i2c_reset_bus(dev);
+	return 0;
+}
+
+int vfc_i2c_reset_bus(struct vfc_dev *dev) 
+{
+	VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
+			  dev->instance));
+	if(!dev) return -EINVAL;
+	if(!dev->regs) return -EINVAL;
+	dev->regs->i2c_s1=SEND_I2C_STOP;
+	dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
+	vfc_i2c_delay(dev);
+	dev->regs->i2c_s1=CLEAR_I2C_BUS;
+	VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
+			  dev->instance, dev->regs->i2c_s1));
+	return 0;
+}
+
+int vfc_i2c_wait_for_bus(struct vfc_dev *dev) 
+{
+	int timeout=1000; 
+
+	while(!(dev->regs->i2c_s1 & BB)) {
+		if(!(timeout--)) return -ETIMEDOUT;
+		vfc_i2c_delay(dev);
+	}
+	return 0;
+}
+
+int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack)
+{
+	int timeout=1000; 
+	int s1;
+
+	while((s1=dev->regs->i2c_s1) & PIN) {
+		if(!(timeout--)) return -ETIMEDOUT;
+		vfc_i2c_delay(dev);
+	}
+	if(ack==VFC_I2C_ACK_CHECK) {
+		if(s1 & LRB) return -EIO; 
+	}
+	return 0;
+}
+
+#define SHIFT(a) ((a) << 24)
+int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr, char mode) 
+{ 
+	int ret,raddr;
+#if 1
+	dev->regs->i2c_s1=SEND_I2C_STOP;
+	dev->regs->i2c_s1=SELECT(S0) | ENABLE_SERIAL;
+	vfc_i2c_delay(dev);
+#endif
+
+	switch(mode) {
+	case VFC_I2C_READ:
+		dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr | 0x1);
+		VFC_DEBUG_PRINTK(("vfc%d: recieving from i2c addr 0x%x\n",
+				  dev->instance,addr | 0x1));
+		break;
+	case VFC_I2C_WRITE:
+		dev->regs->i2c_reg=raddr=SHIFT((unsigned int)addr & ~0x1);
+		VFC_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
+				  dev->instance,addr & ~0x1));
+		break;
+	default:
+		return -EINVAL;
+	}
+	dev->regs->i2c_s1 = SEND_I2C_START;
+	vfc_i2c_delay(dev);
+	ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait
+							    for the
+							    i2c send
+							    to finish
+							    here but
+							    Sun
+							    doesn't,
+							    hmm */
+	if(ret) {
+		printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n",
+		       dev->instance);
+		return ret;
+	} else if(mode == VFC_I2C_READ) {
+		if((ret=dev->regs->i2c_reg & 0xff000000) != raddr) {
+			printk(KERN_WARNING 
+			       "vfc%d: returned slave address "
+			       "mismatch(%x,%x)\n",
+			       dev->instance,raddr,ret);
+		}
+	}	
+	return 0;
+}
+
+int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte) 
+{
+	int ret;
+	dev->regs->i2c_reg=SHIFT((unsigned int)*byte);
+
+	ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); 
+	switch(ret) {
+	case -ETIMEDOUT: 
+		printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n",
+		       dev->instance);
+		break;
+	case -EIO:
+		ret=XMIT_LAST_BYTE;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte, int last) 
+{
+	int ret;
+	if(last) {
+		dev->regs->i2c_reg=NEGATIVE_ACK;
+		VFC_DEBUG_PRINTK((KERN_DEBUG "vfc%d: sending negative ack\n",
+				  dev->instance));
+	} else {
+		dev->regs->i2c_s1=ACK;
+	}
+
+	ret=vfc_i2c_wait_for_pin(dev,VFC_I2C_NO_ACK_CHECK);
+	if(ret) {
+		printk(KERN_ERR "vfc%d: "
+		       "VFC recv byte timed out\n",dev->instance);
+	}
+	*byte=(dev->regs->i2c_reg) >> 24;
+	return ret;
+}
+
+int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
+		    char *buf, int count)
+{
+	int ret,last;
+
+	if(!(count && buf && dev && dev->regs) ) return -EINVAL;
+
+	if((ret=vfc_i2c_wait_for_bus(dev))) {
+		printk(KERN_ERR "vfc%d: VFC I2C bus busy\n",dev->instance);
+		return ret;
+	}
+
+	if((ret=vfc_i2c_xmit_addr(dev,addr,VFC_I2C_READ))) {
+		dev->regs->i2c_s1=SEND_I2C_STOP;
+		vfc_i2c_delay(dev);
+		return ret;
+	}
+	
+	last=0;
+	while(count--) {
+		if(!count) last=1;
+		if((ret=vfc_i2c_recv_byte(dev,buf,last))) {
+			printk(KERN_ERR "vfc%d: "
+			       "VFC error while recieving byte\n",
+			       dev->instance);
+		}
+		buf++;
+	}
+	
+	dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
+	vfc_i2c_delay(dev);
+	return ret;
+}
+
+int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, 
+		    char *buf, int count) 
+{
+	int ret;
+	
+	if(!(buf && dev && dev->regs) ) return -EINVAL;
+	
+	if((ret=vfc_i2c_wait_for_bus(dev))) {
+		printk(KERN_ERR "vfc%d: VFC I2C bus busy\n",dev->instance);
+		return ret;
+	}
+	
+	if((ret=vfc_i2c_xmit_addr(dev,addr,VFC_I2C_WRITE))) {
+		dev->regs->i2c_s1=SEND_I2C_STOP;
+		vfc_i2c_delay(dev);
+		return ret;
+	}
+	
+	while(count--) {
+		ret=vfc_i2c_xmit_byte(dev,buf);
+		switch(ret) {
+		case XMIT_LAST_BYTE:
+			VFC_DEBUG_PRINTK(("vfc%d: "
+					  "Reciever ended transmission with "
+					  " %d bytes remaining\n",
+					  dev->instance,count));
+			ret=0;
+			goto done;
+			break;
+		case 0:
+			break;
+		default:
+			printk(KERN_ERR "vfc%d: "
+			       "VFC error while sending byte\n",dev->instance);
+			break;
+		}
+		buf++;
+	}
+done:
+	dev->regs->i2c_s1=SEND_I2C_STOP | ACK;
+	
+	vfc_i2c_delay(dev);
+	return ret;
+}
+
+
+
+
+
+
+
+
+
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/vfc_i2c.h linux/drivers/sbus/char/vfc_i2c.h
--- v2.1.33/linux/drivers/sbus/char/vfc_i2c.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/vfc_i2c.h	Fri Apr 11 10:47:37 1997
@@ -0,0 +1,44 @@
+#ifndef _LINUX_VFC_I2C_H_
+#define _LINUX_VFC_I2C_H_
+
+/* control bits */
+#define PIN  (0x80000000)
+#define ESO  (0x40000000)
+#define ES1  (0x20000000)
+#define ES2  (0x10000000)
+#define ENI  (0x08000000)
+#define STA  (0x04000000)
+#define STO  (0x02000000)
+#define ACK  (0x01000000)
+
+/* status bits */
+#define STS  (0x20000000)
+#define BER  (0x10000000)
+#define LRB  (0x08000000)
+#define AAS  (0x04000000)
+#define LAB  (0x02000000)
+#define BB   (0x01000000)
+
+#define SEND_I2C_START (PIN | ESO | STA)
+#define SEND_I2C_STOP (PIN | ESO | STO)
+#define CLEAR_I2C_BUS (PIN | ESO | ACK)
+#define NEGATIVE_ACK ((ESO) & ~ACK)
+
+#define SELECT(a) (a)
+#define S0 (PIN | ESO | ES1)
+#define S0_OWN (PIN)
+#define S2 (PIN | ES1)
+#define S3 (PIN | ES2)
+
+#define ENABLE_SERIAL (PIN | ESO)
+#define DISABLE_SERIAL (PIN)
+#define RESET (PIN)
+
+#define XMIT_LAST_BYTE (1)
+#define VFC_I2C_ACK_CHECK (1)
+#define VFC_I2C_NO_ACK_CHECK (0)
+
+#endif /* _LINUX_VFC_I2C_H_ */
+
+
+
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c
--- v2.1.33/linux/drivers/sbus/char/weitek.c	Mon Dec 30 02:00:05 1996
+++ linux/drivers/sbus/char/weitek.c	Fri Apr 11 10:47:37 1997
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.7 1996/12/23 10:16:18 ecd Exp $
+/* $Id: weitek.c,v 1.8 1997/03/24 17:44:26 jj Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -95,11 +95,11 @@
 }
 #endif
 
-__initfunc(void weitek_setup(fbinfo_t *fb, int slot, uint addr, int io))
+__initfunc(void weitek_setup(fbinfo_t *fb, int slot, unsigned long addr, int io))
 {
 	extern struct screen_info screen_info;
 	
-	printk ("weitek%d at 0x%8.8x\n", slot, addr);
+	printk ("weitek%d at 0x%8.8x\n", slot, (uint)addr);
 	
 	/* Fill in parameters we left out */
 	fb->type.fb_type	= FBTYPE_NOTSUN1;
@@ -114,4 +114,3 @@
 	    prom_printf ("Missing mapping routine and no address found\n");
 	}
 }
-
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c
--- v2.1.33/linux/drivers/sbus/dvma.c	Thu Mar 27 14:40:05 1997
+++ linux/drivers/sbus/dvma.c	Fri Apr 11 10:47:37 1997
@@ -110,7 +110,8 @@
 			printk("Revision 1 PLUS ");
 			break;
 		default:
-			printk("unknown dma version");
+			printk("unknown dma version %x",
+			       (dma->regs->cond_reg)&DMA_DEVICE_ID);
 			dma->allocated = 1;
 			break;
 		}
diff -u --recursive --new-file v2.1.33/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.1.33/linux/drivers/sbus/sbus.c	Thu Mar 27 14:40:05 1997
+++ linux/drivers/sbus/sbus.c	Fri Apr 11 10:47:38 1997
@@ -35,6 +35,7 @@
  */
 
 /* #define DEBUG_FILL */
+
 __initfunc(static void
 fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev))
 {
@@ -63,7 +64,9 @@
 	sbus_dev->ranges_applied = 0;
 
 	base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr;
-	if(base>=SUN_SBUS_BVADDR || sparc_cpu_model == sun4m) {
+	if(base>=SUN_SBUS_BVADDR ||
+	   sparc_cpu_model == sun4m ||
+	   sparc_cpu_model == sun4u) {
 		/* Ahh, we can determine the slot and offset */
 		sbus_dev->slot = sbus_dev_slot(base);
 		sbus_dev->offset = sbus_dev_offset(base);
@@ -80,7 +83,6 @@
 		/* That surely sucked */
 	}
 	sbus_dev->sbus_addr = (unsigned long) sbus_dev->reg_addrs[0].phys_addr;
-
 	if(len>(sizeof(struct linux_prom_registers)*PROMREG_MAX)) {
 		prom_printf("WHOOPS:  I got too many register addresses for %s  len=%d\n",
 		       sbus_dev->prom_name, len);
@@ -98,39 +100,58 @@
 	}
 	sbus_dev->num_vaddrs = (len/4);
   
-	len = prom_getproperty(nd, "intr", (void *)sbus_dev->irqs,
-			       sizeof(sbus_dev->irqs));
-	if (len == -1) len=0;
-	if (len&7) {
-		prom_printf("Grrr, I didn't get a multiple of 8 proplen for "
-		       "device %s got %d\n", sbus_dev->prom_name, len);
-		len=0;
-	}
-	sbus_dev->num_irqs=(len/8);
-#if OLD_STYLE_IRQ
-	/* Grrr, V3 prom tries to be efficient */
-	for(len=0; len<sbus_dev->num_irqs; len++) {
-		sbus_dev->irqs[len].pri &= 0xf;
+	if(sparc_cpu_model == sun4u) {
+		len = prom_getproperty(nd, "interrupts", (void *)&sbus_dev->irqs[0].pri,
+				       sizeof(sbus_dev->irqs[0].pri));
+		if((len == -1) || (len == 0)) {
+			sbus_dev->irqs[0].pri = 0;
+			sbus_dev->num_irqs = 0;
+		} else {
+			sbus_dev->num_irqs = 1;
+		}
+	} else {
+		len = prom_getproperty(nd, "intr", (void *)sbus_dev->irqs,
+				       sizeof(sbus_dev->irqs));
+		if (len == -1) len=0;
+		if (len&7) {
+			prom_printf("Grrr, I didn't get a multiple of 8 proplen for "
+				    "device %s got %d\n", sbus_dev->prom_name, len);
+			len=0;
+		}
+		sbus_dev->num_irqs=(len/8);
+		if(sbus_dev->num_irqs == 0)
+			sbus_dev->irqs[0].pri=0;
 	}
-#endif
-	if(sbus_dev->num_irqs == 0) sbus_dev->irqs[0].pri=0;
-
 #ifdef DEBUG_FILL
+#ifdef __sparc_v9__
+	prom_printf("Found %s at SBUS slot %x offset %016lx irq-level %d\n",
+	       sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset,
+	       sbus_dev->irqs[0].pri);
+	prom_printf("Base address %016lx\n", sbus_dev->sbus_addr);
+#else
 	prom_printf("Found %s at SBUS slot %x offset %08lx irq-level %d\n",
 	       sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset,
 	       sbus_dev->irqs[0].pri);
 	prom_printf("Base address %08lx\n", sbus_dev->sbus_addr);
+#endif
 	prom_printf("REGISTERS: Probed %d register(s)\n", sbus_dev->num_registers);
 	for(len=0; len<sbus_dev->num_registers; len++)
+#ifdef __sparc_v9__
 		prom_printf("Regs<%d> at address<%08lx> IO-space<%d> size<%d "
 		       "bytes, %d words>\n", (int) len,
 		       (unsigned long) sbus_dev->reg_addrs[len].phys_addr,
 		       sbus_dev->reg_addrs[len].which_io,
 		       sbus_dev->reg_addrs[len].reg_size,
 		       (sbus_dev->reg_addrs[len].reg_size/4));
+#else
+		prom_printf("Regs<%d> at address<%016lx> IO-space<%d> size<%d "
+		       "bytes, %d words>\n", (int) len,
+		       (unsigned long) sbus_dev->reg_addrs[len].phys_addr,
+		       sbus_dev->reg_addrs[len].which_io,
+		       sbus_dev->reg_addrs[len].reg_size,
+		       (sbus_dev->reg_addrs[len].reg_size/4));
+#endif
 #endif
-
-	return;
 }
 
 /* This routine gets called from whoever needs the sbus first, to scan
@@ -149,6 +170,12 @@
 #ifdef CONFIG_SUN_MOSTEK_RTC
 extern int rtc_init(void);
 #endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
 
 __initfunc(static unsigned long 
 sbus_do_child_siblings(unsigned long memory_start, int start_node,
@@ -200,7 +227,14 @@
 
 	/* Finding the first sbus is a special case... */
 	iommund = 0;
-	if (sparc_cpu_model == sun4d) {
+	if(sparc_cpu_model == sun4u) {
+		/* IOMMU "hides" inside SBUS/SYSIO node. */
+		iommund = nd = prom_searchsiblings(topnd, "sbus");
+		if(nd == 0) {
+			prom_printf("YEEE, UltraSparc sbus not found\n");
+			prom_halt();
+		}
+	} else if(sparc_cpu_model == sun4d) {
 		if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 ||
 		   (nd = prom_getchild(iommund)) == 0 ||
 		   (nd = prom_searchsiblings(nd, "sbi")) == 0) {
@@ -309,7 +343,12 @@
 		memory_start = dvma_init(sbus, memory_start);
 
 		num_sbus++;
-		if (sparc_cpu_model == sun4d) {
+		if(sparc_cpu_model == sun4u) {
+			this_sbus = prom_getsibling(this_sbus);
+			if(!this_sbus)
+				break;
+			this_sbus = prom_searchsiblings(this_sbus, "sbus");
+		} else if(sparc_cpu_model == sun4d) {
 			iommund = prom_getsibling(iommund);
 			if(!iommund) break;
 			iommund = prom_searchsiblings(iommund, "io-unit");
@@ -336,8 +375,15 @@
 #ifdef CONFIG_SUN_MOSTEK_RTC
 	rtc_init();
 #endif
+#ifdef CONFIG_SPARCAUDIO
+	sparcaudio_init();
+#endif
 #ifdef CONFIG_SUN_BPP
 	bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+	if (sparc_cpu_model == sun4u)
+		auxio_probe ();
 #endif
 	return memory_start;
 }
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/AM53C974.h linux/drivers/scsi/AM53C974.h
--- v2.1.33/linux/drivers/scsi/AM53C974.h	Mon Apr  7 11:35:29 1997
+++ linux/drivers/scsi/AM53C974.h	Fri Apr 11 10:50:49 1997
@@ -27,6 +27,8 @@
 #ifndef AM53C974_H
 #define AM53C974_H
 
+#include <scsi/scsicam.h>
+
 struct AM53C974_hostdata {
     volatile unsigned       in_reset:1;          /* flag, says bus reset pending */
     volatile unsigned       aborted:1;           /* flag, says aborted */
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.33/linux/drivers/scsi/Config.in	Sun Apr 13 10:18:21 1997
+++ linux/drivers/scsi/Config.in	Fri Apr 11 10:50:49 1997
@@ -71,7 +71,7 @@
   fi
 fi
 if [ "$CONFIG_MCA" = "y" ]; then
-  bool 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA
+  dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI
 fi
 if [ "$CONFIG_PNP_PARPORT" != "n" ]; then
   dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PNP_PARPORT
@@ -79,7 +79,6 @@
     int  '  Pedantic EPP-checking'   CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
     int  '  EPP timeout'             CONFIG_SCSI_PPA_EPP_TIME 128
   fi
-  dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI
 fi
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.33/linux/drivers/scsi/Makefile	Mon Mar 17 14:54:29 1997
+++ linux/drivers/scsi/Makefile	Fri Apr 11 10:50:49 1997
@@ -10,6 +10,7 @@
 L_OBJS   := 
 M_OBJS   := 
 MX_OBJS  := 
+MIX_OBJS :=
 MOD_LIST_NAME := SCSI_MODULES
 SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
 
@@ -45,7 +46,7 @@
   endif
 else
   ifeq ($(CONFIG_SCSI),m)
-    MX_OBJS += scsi_syms.o
+    MIX_OBJS += scsi_syms.o
     M_OBJS += scsi_mod.o
   endif
 endif
@@ -412,9 +413,9 @@
 ncr53c8xx.o : ncr53c8xx.c
 	$(CC) $(CFLAGS) -c ncr53c8xx.c
 
-scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
+scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
 		scsicam.o scsi_proc.o
-	$(LD) $(LD_RFLAG) -r -o $@ $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+	$(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
 
 sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR)
 	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR)
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c
--- v2.1.33/linux/drivers/scsi/atari_NCR5380.c	Fri Dec 20 01:20:02 1996
+++ linux/drivers/scsi/atari_NCR5380.c	Fri Apr 11 10:47:38 1997
@@ -1026,7 +1026,7 @@
      * If we're not in an interrupt, we can call NCR5380_main()
      * unconditionally, because it cannot be already running.
      */
-    if (intr_count > 0 || ((flags >> 8) & 7) >= 6)
+    if (in_interrupt() || ((flags >> 8) & 7) >= 6)
 	queue_main();
     else
 	NCR5380_main();
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v2.1.33/linux/drivers/scsi/atari_scsi.c	Fri Dec 20 01:20:02 1996
+++ linux/drivers/scsi/atari_scsi.c	Fri Apr 11 10:47:38 1997
@@ -549,11 +549,11 @@
 	save_flags(oldflags);
 	cli();
 
-	while( intr_count == 0 && falcon_got_lock && stdma_others_waiting() )
+	while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
 		sleep_on( &falcon_fairness_wait );
 
 	while (!falcon_got_lock) {
-		if (intr_count > 0)
+		if (in_interrupt())
 			panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
 		if (!falcon_trying_lock) {
 			falcon_trying_lock = 1;
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.1.33/linux/drivers/scsi/esp.c	Mon Mar 17 14:54:29 1997
+++ linux/drivers/scsi/esp.c	Mon Apr 14 09:31:09 1997
@@ -32,7 +32,6 @@
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
-#include <asm/vaddrs.h>
 #include <asm/io.h>
 #include <asm/idprom.h>
 
@@ -170,7 +169,6 @@
 
 /* Forward declarations. */
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
-static void esp_done(struct Sparc_ESP *esp, int error);
 
 /* Debugging routines */
 struct esp_cmdstrings {
@@ -693,6 +691,7 @@
 			esp->ehost = esp_host;
 			esp->edev = esp_dev;
 			esp->esp_id = nesps++;
+
 			/* Put into the chain of esp chips detected */
 			if(espchain) {
 				elink = espchain;
@@ -769,13 +768,15 @@
 			if(!eregs)
 				panic("ESP registers unmappable");
 			esp->esp_command =
-				sparc_dvma_malloc(16, "ESP DVMA Cmd Block");
-			if(!esp->esp_command)
+				sparc_dvma_malloc(16, "ESP DVMA Cmd Block",
+						  &esp->esp_command_dvma);
+			if(!esp->esp_command || !esp->esp_command_dvma)
 				panic("ESP DVMA transport area unmappable");
 
 			/* Set up the irq's etc. */
 			esp->ehost->base = (unsigned char *) esp->eregs;
-			esp->ehost->io_port = (unsigned int) esp->eregs;
+			esp->ehost->io_port =
+				esp->edev->reg_addrs[0].phys_addr;
 			esp->ehost->n_io_port = (unsigned char)
 				esp->edev->reg_addrs[0].reg_size;
 			esp->ehost->irq = esp->irq = esp->edev->irqs[0].pri;
@@ -1256,8 +1257,9 @@
 	int lun, target;
 	int i;
 
-	/* Hold off if we've been reselected. */
-	if(esp->disconnected_SC && DMA_IRQ_P(dregs)) return;
+	/* Hold off if we've been reselected or an IRQ is showing... */
+	if(esp->disconnected_SC || DMA_IRQ_P(dregs))
+		return;
 
 	/* Grab first member of the issue queue. */
 	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
@@ -1479,7 +1481,7 @@
 		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
 		tmp &= ~(DMA_ST_WRITE);
 		dregs->cnt = 16;
-		dregs->st_addr = esp->esp_command;
+		dregs->st_addr = esp->esp_command_dvma;
 		dregs->cond_reg = tmp;
 	} else {
 		/* Set up the DMA and ESP counters */
@@ -1490,7 +1492,7 @@
 			if(i) /* Workaround ESC gate array SBUS rerun bug. */
 				dregs->cnt = (PAGE_SIZE);
 		}
-		dregs->st_addr = esp->esp_command;
+		dregs->st_addr = esp->esp_command_dvma;
 
 		/* Tell ESP to "go". */
 		esp_cmd(esp, eregs, the_esp_command);
@@ -1503,9 +1505,6 @@
 	struct Sparc_ESP *esp;
 	struct sparc_dma_registers *dregs;
 	unsigned long flags;
-	int don;
-
-	save_flags(flags); cli();
 
 	/* Set up func ptr and initial driver cmd-phase. */
 	SCpnt->scsi_done = done;
@@ -1514,10 +1513,6 @@
 	esp = (struct Sparc_ESP *) SCpnt->host->hostdata;
 	dregs = esp->dregs;
 
-	don = (dregs->cond_reg & DMA_INT_ENAB);
-	if(don)
-		DMA_INTSOFF(dregs);
-
 	/* We use the scratch area. */
 	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
 	ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
@@ -1528,10 +1523,13 @@
 			(struct scatterlist *) SCpnt->request_buffer;
 		SCpnt->SCp.buffers_residual = 0;
 		/* Sneaky. */
-		SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
-			mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
-					 SCpnt->SCp.this_residual,
-					 esp->edev->my_bus);
+		SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
+							   SCpnt->SCp.this_residual,
+							   esp->edev->my_bus);
+		/* XXX The casts are extremely gross, but with 64-bit kernel
+		 * XXX and 32-bit SBUS what am I to do? -DaveM
+		 */
+		SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in);
 	} else {
 		ESPQUEUE(("use_sg "));
 #ifdef DEBUG_ESP_SG
@@ -1544,7 +1542,8 @@
 		mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
 				 SCpnt->SCp.buffers_residual,
 				 esp->edev->my_bus);
-		SCpnt->SCp.ptr              = (char *) SCpnt->SCp.buffer->dvma_address;
+		/* XXX Again these casts are sick... -DaveM */
+		SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address);
 	}
 	SCpnt->SCp.Status           = CHECK_CONDITION;
 	SCpnt->SCp.Message          = 0xff;
@@ -1559,12 +1558,12 @@
 		append_SC(&esp->issue_SC, SCpnt);
 	}
 
+	save_and_cli(flags);
+
 	/* Run it now if we can. */
 	if(!esp->current_SC && !esp->resetting_bus)
 		esp_exec_cmd(esp);
 
-	if(don)
-		DMA_INTSON(dregs);
 	restore_flags(flags);
 	return 0;
 }
@@ -1597,7 +1596,7 @@
 #endif
 
 	ESPLOG(("esp%d: dumping state\n", esp->esp_id));
-	ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%p>\n",
+	ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n",
 		esp->esp_id, dregs->cond_reg, dregs->st_addr));
 	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
 		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
@@ -1648,8 +1647,6 @@
 	int don;
 
 	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
-	save_flags(flags); cli();
-
 	esp_dump_state(esp, eregs, dregs);
 
 	/* Wheee, if this is the current command on the bus, the
@@ -1658,6 +1655,7 @@
 	 * in the driver and timeout because the eventual phase change
 	 * will cause the ESP to (eventually) give an interrupt.
 	 */
+	save_and_cli(flags);
 	if(esp->current_SC == SCptr) {
 		esp->cur_msgout[0] = ABORT;
 		esp->msgout_len = 1;
@@ -1666,13 +1664,16 @@
 		restore_flags(flags);
 		return SCSI_ABORT_PENDING;
 	}
+	restore_flags(flags);
 
 	/* If it is still in the issue queue then we can safely
 	 * call the completion routine and report abort success.
 	 */
 	don = (dregs->cond_reg & DMA_INT_ENAB);
-	if(don)
+	if(don) {
 		DMA_INTSOFF(dregs);
+		synchronize_irq();
+	}
 	if(esp->issue_SC) {
 		Scsi_Cmnd **prev, *this;
 		for(prev = (&esp->issue_SC), this = esp->issue_SC;
@@ -1684,10 +1685,8 @@
 				this->host_scribble = NULL;
 				this->result = DID_ABORT << 16;
 				this->done(this);
-				cli();
 				if(don)
 					DMA_INTSON(dregs);
-				restore_flags(flags);
 				return SCSI_ABORT_SUCCESS;
 			}
 		}
@@ -1698,12 +1697,8 @@
 	 * on the bus at this time.  So, we let the SCSI code wait
 	 * a little bit and try again later.
 	 */
-	if(esp->current_SC) {
-		if(don)
-			DMA_INTSON(dregs);
-		restore_flags(flags);
+	if(esp->current_SC)
 		return SCSI_ABORT_BUSY;
-	}
 
 	/* It's disconnected, we have to reconnect to re-establish
 	 * the nexus and tell the device to abort.  However, we really
@@ -1712,9 +1707,6 @@
 	 * happens, we are really hung so reset the bug.
 	 */
 
-	if(don)
-		DMA_INTSON(dregs);
-	restore_flags(flags);
 	return SCSI_ABORT_SNOOZE;
 }
 
@@ -1733,14 +1725,12 @@
 }
 
 /* Internal ESP done function. */
-static inline void esp_done(struct Sparc_ESP *esp, int error)
+static void esp_done(struct Sparc_ESP *esp, int error)
 {
-	unsigned long flags;
 	Scsi_Cmnd *done_SC;
 
 	if(esp->current_SC) {
-		/* Critical section... */
-		save_flags(flags); cli();
+		unsigned long flags;
 
 		done_SC = esp->current_SC;
 		esp->current_SC = NULL;
@@ -1748,7 +1738,7 @@
 		/* Free dvma entry. */
 		if(!done_SC->use_sg) {
 			/* Sneaky. */
-			mmu_release_scsi_one((char *)done_SC->SCp.have_data_in,
+			mmu_release_scsi_one(done_SC->SCp.have_data_in,
 					     done_SC->request_bufflen,
 					     esp->edev->my_bus);
 		} else {
@@ -1765,27 +1755,15 @@
 		}
 
 		done_SC->result = error;
-		if(done_SC->scsi_done)
-			done_SC->scsi_done(done_SC);
-		else
-			panic("esp: esp->current_SC->scsi_done() == NULL");
+		done_SC->scsi_done(done_SC);
 
-		/* There is a window of time within the scsi_done() path
-		 * of execution where interrupts are turned back on full
-		 * blast and left that way.  During that time we could
-		 * reconnect to a disconnected command, then we'd bomb
-		 * out below.  We could also end up executing two commands
-		 * at _once_.  ...just so you know why the cli() is here...
-		 */
-
-		cli(); /* GRRR!!! */
+		save_and_cli(flags);
 
 		/* Bus is free, issue any commands in the queue. */
 		if(esp->issue_SC && !esp->current_SC)
 			esp_exec_cmd(esp);
 
 		restore_flags(flags);
-		/* End of critical section... */
 	} else {
 		/* Panic is safe as current_SC is null so we may still
 		 * be able to accept more commands to sync disk buffers.
@@ -1951,7 +1929,7 @@
 
 /* Now some dma helpers. */
 static inline void dma_setup(struct sparc_dma_registers *dregs, enum dvma_rev drev,
-			     char *addr, int count, int write)
+			     __u32 addr, int count, int write)
 {
 	unsigned long nreg = dregs->cond_reg;
 	if(write)
@@ -1962,8 +1940,8 @@
 	dregs->cond_reg = nreg;
 	if(drev == dvmaesc1) {
 		/* This ESC gate array sucks! */
-		unsigned long src = ((unsigned long) addr);
-		unsigned long dest = src + count;
+		__u32 src = addr;
+		__u32 dest = src + count;
 
 		if(dest & (PAGE_SIZE - 1))
 			count = PAGE_ALIGN(count);
@@ -1991,13 +1969,16 @@
 
 static inline void dma_invalidate(struct sparc_dma_registers *dregs, enum dvma_rev drev)
 {
-	unsigned long tmp;
+	unsigned int tmp;
 
 	if(drev == dvmahme) {
 		/* SMCC can bite me. */
 		tmp = dregs->cond_reg;
 		dregs->cond_reg = DMA_RST_SCSI;
-		tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
+
+		/* This would explain a lot. */
+		tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB);
+
 		tmp &= ~(DMA_ENABLE|DMA_ST_WRITE);
 		dregs->cond_reg = 0;
 		dregs->cond_reg = tmp;
@@ -2021,14 +2002,14 @@
 
 static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev)
 {
-	unsigned long base, end, sz;
+	__u32 base, end, sz;
 
 	if(drev == dvmarev3) {
 		sz = sp->SCp.this_residual;
 		if(sz > 0x1000000)
 			sz = 0x1000000;
 	} else {
-		base = (unsigned long) sp->SCp.ptr;
+		base = ((__u32)sp->SCp.ptr);
 		base &= (0x1000000 - 1);
 		end = (base + sp->SCp.this_residual);
 		if(end > 0x1000000)
@@ -2239,8 +2220,7 @@
 				 struct sparc_dma_registers *dregs,
 				 int fifo_count)
 {
-	int rval = (((unsigned long)dregs->st_addr) -
-		    ((unsigned long)esp->esp_command));
+	int rval = dregs->st_addr - esp->esp_command_dvma;
 
 	if(esp->dma->revision == dvmarev1)
 		rval -= (4 - ((dregs->cond_reg & DMA_READ_AHEAD)>>11));
@@ -2252,26 +2232,7 @@
 	++sp->SCp.buffer;
 	--sp->SCp.buffers_residual;
 	sp->SCp.this_residual = sp->SCp.buffer->length;
-	sp->SCp.ptr = sp->SCp.buffer->dvma_address;
-}
-
-/* Complete a command, this is the only way to safely finish
- * a command with disconnected commands or a reset interrupt
- * pending because scsi_done() can enable interrupts full blast.
- */
-static inline void safe_esp_done(struct Sparc_ESP *esp,
-				 struct sparc_dma_registers *dregs,
-				 int error)
-{
-	int before = 0;
-
-	if(dregs->cond_reg & DMA_INT_ENAB) {
-		before = 1;
-		DMA_INTSOFF(dregs);
-	}
-	esp_done(esp, error);
-	if(before)
-		DMA_INTSON(dregs);
+	sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
 }
 
 /* Please note that the way I've coded these routines is that I _always_
@@ -2318,11 +2279,11 @@
 			tmp |= DMA_ST_WRITE;
 		else
 			tmp &= ~(DMA_ST_WRITE);
-		dregs->st_addr = SCptr->SCp.ptr;
+		dregs->st_addr = ((__u32)SCptr->SCp.ptr);
 		dregs->cond_reg = tmp;
 	} else {
 		esp_setcount(eregs, hmuch, 0);
-		dma_setup(dregs, esp->dma->revision, SCptr->SCp.ptr,
+		dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr),
 			  hmuch, (thisphase == in_datain));
 		ESPDATA(("DMA|TI --> do_intr_end\n"));
 		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
@@ -2361,6 +2322,11 @@
 		/* Please go to msgout phase, please please please... */
 		ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
 			esp->esp_id));
+#ifdef __SMP__
+		ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id,
+			local_irq_count[0], local_irq_count[1],
+			local_irq_count[2], local_irq_count[3]));
+#endif
 		return esp_do_phase_determine(esp, eregs, dregs);
 	}	
 
@@ -2443,6 +2409,11 @@
 		ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
 			esp->esp_id,
 			SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+#ifdef __SMP__
+		ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id,
+			local_irq_count[0], local_irq_count[1],
+			local_irq_count[2], local_irq_count[3]));
+#endif
 		bytes_sent = 0;
 	}
 
@@ -2536,9 +2507,9 @@
 				SCptr->device->sync = 0;
 		}
 		ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
-		safe_esp_done(esp, dregs, ((SCptr->SCp.Status & 0xff) |
-					   ((SCptr->SCp.Message & 0xff)<<8) |
-					   (DID_OK << 16)));
+		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
+			       ((SCptr->SCp.Message & 0xff)<<8) |
+			       (DID_OK << 16)));
 	} else if(esp->prevmsgin == DISCONNECT) {
 		/* Normal disconnect. */
 		esp_cmd(esp, eregs, ESP_CMD_ESEL);
@@ -2785,7 +2756,7 @@
 				dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
 				if(esp->dma->revision == dvmaesc1)
 					dregs->cnt = 0x1000;
-				dregs->st_addr = esp->esp_command;
+				dregs->st_addr = esp->esp_command_dvma;
 				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ);
 			} else {
 				/* Using DVMA for status/message bytes is
@@ -2834,7 +2805,7 @@
 			/* We didn't expect this to happen at all. */
 			ESPLOG(("device is bolixed\n"));
 			esp_advance_phase(SCptr, in_tgterror);
-			safe_esp_done(esp, dregs, (DID_ERROR << 16));
+			esp_done(esp, (DID_ERROR << 16));
 			break;
 
 		case BUS_DEVICE_RESET:
@@ -2843,13 +2814,13 @@
 			dp->sync_min_period = 0;
 			dp->sync = 0;
 			esp_advance_phase(SCptr, in_resetdev);
-			safe_esp_done(esp, dregs, (DID_RESET << 16));
+			esp_done(esp, (DID_RESET << 16));
 			break;
 
 		case ABORT:
 			ESPLOG(("device abort successful\n"));
 			esp_advance_phase(SCptr, in_abortone);
-			safe_esp_done(esp, dregs, (DID_ABORT << 16));
+			esp_done(esp, (DID_ABORT << 16));
 			break;
 
 		};
@@ -3088,13 +3059,13 @@
 			 * Therefore, we assume that if we've talked successfully
 			 * to this target before, bad parity is the problem.
 			 */
-			safe_esp_done(esp, dregs, (DID_PARITY << 16));
+			esp_done(esp, (DID_PARITY << 16));
 		} else {
 			/* Else, there really isn't anyone there. */
 			ESPMISC(("esp: selection failure, maybe nobody there?\n"));
 			ESPMISC(("esp: target %d lun %d\n",
 				 SCptr->target, SCptr->lun));
-			safe_esp_done(esp, dregs, (DID_BAD_TARGET << 16));
+			esp_done(esp, (DID_BAD_TARGET << 16));
 		}
 		return do_intr_end;
 	}
@@ -3542,7 +3513,7 @@
 		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
 		tmp &= ~(DMA_ST_WRITE);
 		dregs->cnt = i;
-		dregs->st_addr = &esp->esp_command[0];
+		dregs->st_addr = esp->esp_command_dvma;
 		dregs->cond_reg = tmp;
 	} else {
 		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
@@ -3590,7 +3561,7 @@
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			dma_setup(dregs, esp->dma->revision,
-				  (char *) esp->esp_command, 2, 0);
+				  esp->esp_command_dvma, 2, 0);
 			esp_setcount(eregs, 2, 0);
 			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
@@ -3607,7 +3578,7 @@
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			dma_setup(dregs, esp->dma->revision,
-				  (char *) esp->esp_command, 4, 0);
+				  esp->esp_command_dvma, 4, 0);
 			esp_setcount(eregs, 4, 0);
 			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
@@ -3625,7 +3596,7 @@
 			esp_cmd(esp, eregs, ESP_CMD_TI);
 		} else {
 			dma_setup(dregs, esp->dma->revision,
-				  (char *) esp->esp_command, 5, 0);
+				  esp->esp_command_dvma, 5, 0);
 			esp_setcount(eregs, 5, 0);
 			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
@@ -3794,8 +3765,6 @@
 	dregs = esp->dregs;
 	SCptr = esp->current_SC;
 
-	DMA_IRQ_ENTRY(esp->dma, dregs);
-
 	/* Check for errors. */
 	esp->sreg = eregs->esp_status;
 	esp->sreg &= (~ESP_STAT_INTR);
@@ -3842,7 +3811,7 @@
 		 * translation it did get pointed to a bogus
 		 * page.  Ho hum...
 		 */
-		ESPLOG(("esp%d: DMA error %08lx\n", esp->esp_id,
+		ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
 			dregs->cond_reg));
 
 		/* DMA gate array itself must be reset to clear the
@@ -3874,6 +3843,9 @@
 
 	esp->ireg = eregs->esp_intrpt;   /* Unlatch intr and stat regs */
 
+	/* This cannot be done until this very moment. -DaveM */
+	synchronize_irq();
+
 	/* No current cmd is only valid at this point when there are
 	 * commands off the bus or we are trying a reset.
 	 */
@@ -3988,13 +3960,10 @@
 		/* Tricky, we don't want to cause any more commands to
 		 * go out until we clear all the live cmds by hand.
 		 */
-		if(!DMA_ISBROKEN(esp->dma))
-			DMA_INTSOFF(dregs);
 		if(esp->current_SC) {
 			Scsi_Cmnd *SCptr = esp->current_SC;
 			if(!SCptr->use_sg)
-				mmu_release_scsi_one((char *)
-						     SCptr->SCp.have_data_in,
+				mmu_release_scsi_one(SCptr->SCp.have_data_in,
 						     SCptr->request_bufflen,
 						     esp->edev->my_bus);
 			else
@@ -4003,16 +3972,15 @@
 						     SCptr->use_sg - 1,
 						     esp->edev->my_bus);
 			SCptr->result = (DID_RESET << 16);
+
 			SCptr->scsi_done(SCptr);
-			cli();
 		}
 		esp->current_SC = NULL;
 		if(esp->disconnected_SC) {
 			Scsi_Cmnd *SCptr;
 			while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
 				if(!SCptr->use_sg)
-					mmu_release_scsi_one((char *)
-							     SCptr->SCp.have_data_in,
+					mmu_release_scsi_one(SCptr->SCp.have_data_in,
 							     SCptr->request_bufflen,
 							     esp->edev->my_bus);
 				else
@@ -4021,13 +3989,11 @@
 							     SCptr->use_sg - 1,
 							     esp->edev->my_bus);
 				SCptr->result = (DID_RESET << 16);
+
 				SCptr->scsi_done(SCptr);
-				cli();
 			}
 		}
 		esp->resetting_bus = 0;
-		if(!DMA_ISBROKEN(esp->dma))
-			DMA_INTSON(dregs);
 
 		if(esp->current_SC) {
 			printk("esp%d: weird weird weird, current_SC not NULL after "
@@ -4051,35 +4017,71 @@
 	goto again;
 
 esp_handle_done:
-	DMA_IRQ_EXIT(esp->dma, dregs);
 	return;
 }
 
+#ifndef __SMP__
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
 	struct Sparc_ESP *esp;
-	static int running = 0;
 	int again;
 
-	/* It is ok to take irq's on one esp while the other
-	 * is amidst the processing of a reset.
-	 */
-	running++;
-	if(running > esps_running)
-		ESPLOG(("esp_intr: yieee, recursive interrupt!\n"));
-
-	/* Handle all ESP interrupts showing */
+	/* Handle all ESP interrupts showing at this IRQ level. */
 repeat:
 	again = 0;
 	for_each_esp(esp) {
-		if(DMA_IRQ_P(esp->dregs)) {
-			again = 1;
-			ESPIRQ(("I%d(", esp->esp_id));
-			esp_handle(esp);
-			ESPIRQ((")"));
+		/* XXX Ultra: This is gross, what we really need
+		 * XXX is a sbusirq_to_sparc_pil() function, call
+		 * XXX that and stick the result in the esp soft
+		 * XXX state structure. -DaveM
+		 */
+#ifndef __sparc_v9__
+		if((esp->irq & 0xf) == irq) {
+#endif
+			if(DMA_IRQ_P(esp->dregs)) {
+				again = 1;
+
+				DMA_INTSOFF(esp->dregs);
+
+				ESPIRQ(("I%d(", esp->esp_id));
+				esp_handle(esp);
+				ESPIRQ((")"));
+
+				DMA_INTSON(esp->dregs);
+			}
+#ifndef __sparc_v9__
 		}
+#endif
 	}
 	if(again)
 		goto repeat;
-	running--;
 }
+#else
+
+#ifdef __sparc_v9__
+#error Dave you need to fix some things first...
+#endif
+
+/* For SMP we only service one ESP on the list list at our IRQ level! */
+static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	struct Sparc_ESP *esp;
+
+	/* Handle all ESP interrupts showing at this IRQ level. */
+	for_each_esp(esp) {
+		if((esp->irq & 0xf) == irq) {
+			if(DMA_IRQ_P(esp->dregs)) {
+				DMA_INTSOFF(esp->dregs);
+
+				ESPIRQ(("I[%d:%d](",
+					smp_processor_id(), esp->esp_id));
+				esp_handle(esp);
+				ESPIRQ((")"));
+
+				DMA_INTSON(esp->dregs);
+				return;
+			}
+		}
+	}
+}
+#endif
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/esp.h linux/drivers/scsi/esp.h
--- v2.1.33/linux/drivers/scsi/esp.h	Sun Jan 26 02:07:18 1997
+++ linux/drivers/scsi/esp.h	Mon Apr 14 11:43:13 1997
@@ -108,7 +108,8 @@
    * of the command types ESP doesn't understand, esp_scmdp keeps track of
    * which byte we are sending, esp_scmdleft says how many bytes to go.
    */
-  volatile unchar *esp_command;           /* Location of command */
+  volatile unchar *esp_command;           /* Location of command (CPU view)  */
+  __u32            esp_command_dvma;      /* Location of command (DVMA view) */
   unsigned char esp_clen;                 /* Length of this command */
   unsigned char esp_slowcmd;
   unsigned char *esp_scmdp;
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.1.33/linux/drivers/scsi/ibmmca.c	Fri Apr  4 08:52:23 1997
+++ linux/drivers/scsi/ibmmca.c	Sun Apr 13 09:23:31 1997
@@ -46,6 +46,7 @@
 
 #include <linux/module.h>
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.1.33/linux/drivers/scsi/ppa.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/scsi/ppa.c	Fri Apr 11 10:50:49 1997
@@ -1193,7 +1193,7 @@
 		hreg->n_io_port = ports;
 		hreg->dma_channel = -1;
 		hreg->unique_id = i;
-		ppa_hosts[i]..host = hreg->host_no;
+		ppa_hosts[i].host = hreg->host_no;
 		nhosts++;
 	}
 	if (nhosts == 0)
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.1.33/linux/drivers/scsi/qlogicpti.c	Mon Mar 17 14:54:30 1997
+++ linux/drivers/scsi/qlogicpti.c	Mon Apr 14 09:31:09 1997
@@ -283,8 +283,8 @@
 
 	param[0] = MBOX_INIT_RES_QUEUE;
 	param[1] = RES_QUEUE_LEN + 1;
-	param[2] = (u_short) (((u_int) qpti->res)>>16);
-	param[3] = (u_short) (((u_int) qpti->res) & 0xffff);
+	param[2] = (u_short) (qpti->res_dvma >> 16);
+	param[3] = (u_short) (qpti->res_dvma & 0xffff);
 	param[4] = param[5] = 0;
 	if(qlogicpti_mbox_command(qpti, param, 1)) {
 		printk(KERN_EMERG "qlogicpti%d: Cannot init response queue.\n",
@@ -295,8 +295,8 @@
 
 	param[0] = MBOX_INIT_REQ_QUEUE;
 	param[1] = QLOGICISP_REQ_QUEUE_LEN + 1;
-	param[2] = (u_short) (((u_int) qpti->req)>>16);
-	param[3] = (u_short) (((u_int) qpti->req) & 0xffff);
+	param[2] = (u_short) (qpti->req_dvma >> 16);
+	param[3] = (u_short) (qpti->req_dvma & 0xffff);
 	param[4] = param[5] = 0;
 	if(qlogicpti_mbox_command(qpti, param, 1)) {
 		printk(KERN_EMERG "qlogicpti%d: Cannot init request queue.\n",
@@ -417,6 +417,7 @@
 
 	/* Load the firmware. */
 #ifndef MODULE
+	/* XXX THIS SHIT DOES NOT WORK ON ULTRA... FIXME -DaveM */
 	dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0],
 						 (sizeof(u_short) * risc_code_length01));
 	param[0] = MBOX_LOAD_RAM;
@@ -431,6 +432,7 @@
 		restore_flags(flags);
 		return 1;
 	}
+	/* XXX THIS SHIT DOES NOT WORK ON ULTRA... FIXME -DaveM */
 	mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01));
 #else
 	for(i = 0; i < risc_code_length01; i++) {
@@ -698,10 +700,12 @@
 
 #define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
 
-			qpti->res = sparc_dvma_malloc(QSIZE(RES_QUEUE_LEN),
-						      "PTISP Response Queue");
-			qpti->req = sparc_dvma_malloc(QSIZE(QLOGICISP_REQ_QUEUE_LEN),
-						      "PTISP Request Queue");
+			qpti->res_cpu = sparc_dvma_malloc(QSIZE(RES_QUEUE_LEN),
+							  "PTISP Response Queue",
+							  &qpti->res_dvma);
+			qpti->req_cpu = sparc_dvma_malloc(QSIZE(QLOGICISP_REQ_QUEUE_LEN),
+							  "PTISP Request Queue",
+							  &qpti->req_dvma);
 
 #undef QSIZE
 
@@ -834,7 +838,7 @@
 			struct Continuation_Entry *cont;
 
 			++cmd->hdr.entry_cnt;
-			cont = (struct Continuation_Entry *) &qpti->req[in_ptr];
+			cont = (struct Continuation_Entry *) &qpti->req_cpu[in_ptr];
 			in_ptr = NEXT_REQ_PTR(in_ptr);
 			if(in_ptr == out_ptr) {
 				printk(KERN_EMERG "qlogicpti: Unexpected request queue overflow\n");
@@ -856,9 +860,13 @@
 			sg_count -= n;
 		}
 	} else {
-		Cmnd->SCp.ptr = mmu_get_scsi_one((char *)Cmnd->request_buffer,
-						 Cmnd->request_bufflen,
-						 qpti->qdev->my_bus);
+		/* XXX Casts are extremely gross, but with 64-bit cpu addresses
+		 * XXX and 32-bit SBUS DVMA addresses what am I to do? -DaveM
+		 */
+		Cmnd->SCp.ptr = (char *)((unsigned long)
+					 mmu_get_scsi_one((char *)Cmnd->request_buffer,
+							  Cmnd->request_bufflen,
+							  qpti->qdev->my_bus));
 
 		cmd->dataseg[0].d_base = (u_int) Cmnd->SCp.ptr;
 		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
@@ -892,7 +900,7 @@
 	struct qlogicpti_regs *qregs = qpti->qregs;
 	u_int in_ptr = qpti->req_in_ptr;
 	u_int out_ptr = qregs->mbox4;
-	struct Command_Entry *cmd = (struct Command_Entry *) &qpti->req[in_ptr];
+	struct Command_Entry *cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr];
 
 	Cmnd->scsi_done = done;
 	in_ptr = NEXT_REQ_PTR(in_ptr);
@@ -909,7 +917,7 @@
 			printk(KERN_EMERG "qlogicpti%d: request queue overflow\n", qpti->qpti_id);
 			return 1;
 		}
-		cmd = (struct Command_Entry *) &qpti->req[in_ptr];
+		cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr];
 		in_ptr = NEXT_REQ_PTR(in_ptr);
 	}
 	cmd_frob(cmd, Cmnd, qpti);
@@ -1029,7 +1037,7 @@
 			/* This looks like a network driver! */
 			out_ptr = qpti->res_out_ptr;
 			while(out_ptr != in_ptr) {
-				sts = (struct Status_Entry *) &qpti->res[out_ptr];
+				sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr];
 				out_ptr = NEXT_RES_PTR(out_ptr);
 				Cmnd = (Scsi_Cmnd *) sts->handle; /* but_to_virt?!?! */
 				if(sts->completion_status == CS_RESET_OCCURRED ||
@@ -1052,8 +1060,7 @@
 							     Cmnd->use_sg - 1,
 							     qpti->qdev->my_bus);
 				else
-					mmu_release_scsi_one((char *)
-							     Cmnd->SCp.ptr,
+					mmu_release_scsi_one((__u32)Cmnd->SCp.ptr,
 							     Cmnd->request_bufflen,
 							     qpti->qdev->my_bus);
 
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/qlogicpti.h linux/drivers/scsi/qlogicpti.h
--- v2.1.33/linux/drivers/scsi/qlogicpti.h	Sun Jan 26 02:07:19 1997
+++ linux/drivers/scsi/qlogicpti.h	Fri Apr 11 10:47:38 1997
@@ -456,8 +456,10 @@
 	struct qlogicpti_regs    *qregs;                /* Adapter registers          */
 	u_int	                  req_in_ptr;		/* index of next request slot */
 	u_int	                  res_out_ptr;		/* index of next result slot  */
-	struct pti_queue_entry   *res;                  /* Pointer to RESPONSE dvma   */
-	struct pti_queue_entry   *req;                  /* Pointer to REQUEST dvma    */
+	struct pti_queue_entry   *res_cpu;              /* Ptr to RESPONSE bufs (CPU) */
+	__u32                     res_dvma;             /* Ptr to RESPONSE bufs (DVMA)*/
+	struct pti_queue_entry   *req_cpu;              /* Ptr to REQUEST bufs (CPU)  */
+	__u32                     req_dvma;             /* Ptr to REQUEST bufs (DVMA) */
 	int                       cmd_count[MAX_TARGETS];
 	unsigned long             tag_ages[MAX_TARGETS];
 	long	                  send_marker;		/* must we send a marker?     */
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.1.33/linux/drivers/scsi/scsi.h	Mon Apr  7 11:35:30 1997
+++ linux/drivers/scsi/scsi.h	Mon Apr 14 11:43:13 1997
@@ -23,6 +23,7 @@
 
 #include <linux/random.h>
 
+#include <asm/hardirq.h>
 
 /*
  * Some defs, in case these are not defined elsewhere.
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v2.1.33/linux/drivers/scsi/sr.h	Thu Nov 14 05:26:48 1996
+++ linux/drivers/scsi/sr.h	Mon Apr 14 09:26:00 1997
@@ -56,6 +56,8 @@
 #ifdef CONFIG_BLK_DEV_SR_VENDOR
 void sr_vendor_init(int minor);
 int sr_cd_check(struct cdrom_device_info*);
+int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest);
+
 #endif
 
 #endif
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.1.33/linux/drivers/scsi/sr_ioctl.c	Thu Dec 12 06:54:19 1996
+++ linux/drivers/scsi/sr_ioctl.c	Mon Apr 14 09:26:00 1997
@@ -69,16 +69,7 @@
 	    printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n");
 	    break;
 	default:
-	    printk("SCSI CD error: host %d id %d lun %d return code = %03x\n", 
-		   scsi_CDs[target].device->host->host_no, 
-		   scsi_CDs[target].device->id,
-		   scsi_CDs[target].device->lun,
-		   result);
-	    printk("\tSense class %x, sense error %x, extended sense %x\n",
-		   sense_class(SCpnt->sense_buffer[0]), 
-		   sense_error(SCpnt->sense_buffer[0]),
-		   SCpnt->sense_buffer[2] & 0xf);
-	    
+	    print_sense("sr", SCpnt);
 	};
     
     result = SCpnt->result;
@@ -94,7 +85,7 @@
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
         u_char  sr_cmd[10];
-        
+
         sr_cmd[0] = START_STOP;
         sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device -> lun) << 5);
         sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
@@ -121,11 +112,11 @@
                         SCSI_IOCTL_TEST_UNIT_READY,0))
                 return CDS_DISC_OK;
 
-#if 0
-        /* Enable this if you want to try auto-close. Is'nt enabled by
-         * default because it does'nt work perfectly (no way to
-         * difference between "tray open" and "tray closed, no disk"),
-         * and for caddy drives this is useless anyway. */
+#if 1
+	/* Tell tray is open if the drive is not ready.  Seems there is
+	 * no way to check whenever the tray is really open, but this way
+	 * we get auto-close-on-open work. And it seems to have no ill
+         * effects with caddy drives... */
         return CDS_TRAY_OPEN;
 #else
         return CDS_NO_DISC;
@@ -168,7 +159,8 @@
                         struct cdrom_multisession* ms_info)
 {
         ms_info->addr.lba=scsi_CDs[MINOR(cdi->dev)].ms_offset;
-        ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag;
+        ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag ||
+            scsi_CDs[MINOR(cdi->dev)].ms_offset > 0;
 
 	return 0;
 }
@@ -516,8 +508,10 @@
         return -EINVAL;
     }
 
+#if 0
     if (result)
         printk("DEBUG: sr_audio: result for ioctl %x: %x\n",cmd,result);
+#endif
     
     return result;
 }
@@ -530,10 +524,44 @@
     target = MINOR(cdi->dev);
     
     switch (cmd) {
+    /* these are compatible with the ide-cd driver */
+    case CDROMREADRAW:
+    case CDROMREADMODE1:
     case CDROMREADMODE2:
+
+#if CONFIG_BLK_DEV_SR_VENDOR 
+    {
+	unsigned char      *raw;
+        struct cdrom_msf   msf;
+        int                blocksize, lba, rc;
+
+        if (cmd == CDROMREADMODE1)
+                blocksize = CD_FRAMESIZE;       /* 2048 */
+        else if (cmd == CDROMREADMODE2)
+                blocksize = CD_FRAMESIZE_RAW0;  /* 2336 */
+        else
+		/* some SCSI drives do not allow this one */
+                blocksize = CD_FRAMESIZE_RAW;   /* 2352 */
+
+	if (copy_from_user(&msf,(void*)arg,sizeof(msf)))
+		return -EFAULT;
+	if (!(raw = scsi_malloc(2048+512)))
+        	return -ENOMEM;
+
+	lba = (((msf.cdmsf_min0 * CD_SECS) + msf.cdmsf_sec0)
+			* CD_FRAMES + msf.cdmsf_frame0) - CD_BLOCK_OFFSET;
+	rc = sr_read_sector(target, lba, blocksize, raw);
+	if (!rc)
+		if (copy_to_user((void*)arg, raw, blocksize))
+			rc = -EFAULT;
+
+	scsi_free(raw,2048+512);
+	return rc;
+    }
+#else
 	return -EINVAL;
-    case CDROMREADMODE1:
-	return -EINVAL;	
+#endif
+
 	
     case BLKRAGET:
 	if (!arg)
diff -u --recursive --new-file v2.1.33/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.1.33/linux/drivers/scsi/sr_vendor.c	Tue Nov 12 22:11:17 1996
+++ linux/drivers/scsi/sr_vendor.c	Mon Apr 14 09:26:00 1997
@@ -7,6 +7,23 @@
  * be exact: there is'nt anything in my draft copy).
  *
  *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
+ *
+ * --------------------------------------------------------------------------
+ *
+ * support for XA/multisession-CD's
+ * 
+ *   - NEC:     Detection and support of multisession CD's.
+ *     
+ *   - TOSHIBA: Detection and support of multisession CD's.
+ *              Some XA-Sector tweaking, required for older drives.
+ *
+ *   - SONY:	Detection and support of multisession CD's.
+ *              added by Thomas Quinot <operator@melchior.cuivre.fdn.fr>
+ *
+ *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC: known to work with SONY code.
+ *
+ *   - HP:	Much like SONY, but a little different... (Thomas)
+ *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
  */
 
 #include <linux/errno.h>
@@ -27,9 +44,11 @@
 #define VENDOR_NEC             2
 #define VENDOR_TOSHIBA         3
 #define VENDOR_SONY_LIKE       4   /* much drives are Sony compatible */
-#define VENDOR_HP              5
+#define VENDOR_HP              5   /* HP Writers, others too ?? */
 
+#if 0
 #define DEBUG
+#endif
 
 void
 sr_vendor_init(int minor)
@@ -37,9 +56,13 @@
 	char *vendor = scsi_CDs[minor].device->vendor;
 	char *model  = scsi_CDs[minor].device->model;
 		
-	if (!strncmp (vendor, "NEC", 3)) {
+	if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) &&
+	    scsi_CDs[minor].device->type == TYPE_WORM) {
+		scsi_CDs[minor].vendor = VENDOR_HP;
+
+	} else if (!strncmp (vendor, "NEC", 3)) {
 		scsi_CDs[minor].vendor = VENDOR_NEC;
-		if (!strncmp (model,"CD-ROM DRIVE:25", 15) ||
+		if (!strncmp (model,"CD-ROM DRIVE:25", 15)  ||
 		    !strncmp (model,"CD-ROM DRIVE:36", 15)  ||
 		    !strncmp (model,"CD-ROM DRIVE:83", 15)  ||
 		    !strncmp (model,"CD-ROM DRIVE:84 ",16))
@@ -49,45 +72,102 @@
 	} else if (!strncmp (vendor, "TOSHIBA", 7)) {
 		scsi_CDs[minor].vendor = VENDOR_TOSHIBA;
 		
-	} else if (!strncmp (vendor, "HP", 2)) {
-		scsi_CDs[minor].vendor = VENDOR_HP;
-		
 	} else {
 		/* most drives can handled like sony ones, so we take
 		 * it as default */
 		scsi_CDs[minor].vendor = VENDOR_SONY_LIKE;
+#ifdef DEBUG
+		printk(KERN_DEBUG
+		       "sr: using \"Sony group\" multisession code\n");
+#endif
 	}
 }
 
 
+/* small handy function for switching block length using MODE SELECT,
+ * used by sr_read_sector() */
 
-/*
- * support for XA/multisession-CD's
- * 
- *   - NEC:     Detection and support of multisession CD's.
- *     
- *   - TOSHIBA: Detection and support of multisession CD's.
- *              Some XA-Sector tweaking, required for older drives.
- *
- *   - SONY:	Detection and support of multisession CD's.
- *              added by Thomas Quinot <operator@melchior.cuivre.fdn.fr>
- *
- *   - PIONEER, HITACHI, PLEXTOR, MATSHITA: known to work with SONY code.
+static int
+set_density_and_blocklength(int minor, unsigned char *buffer,
+			    int density, int blocklength)
+{
+	unsigned char		cmd[12];    /* the scsi-command */
+	struct ccs_modesel_head	*modesel;
+	int			rc;
+
+	memset(cmd,0,12);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
+	cmd[4] = 12;
+	modesel = (struct ccs_modesel_head*)buffer;
+	memset(modesel,0,sizeof(*modesel));
+	modesel->block_desc_length = 0x08;
+	modesel->density           = density;
+	modesel->block_length_med  = (blocklength >> 8 ) & 0xff;
+	modesel->block_length_lo   =  blocklength        & 0xff;
+	rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel));
+#ifdef DEBUG
+	if (rc)
+		printk("sr: switching blocklength to %d bytes failed\n",
+		       blocklength);
+#endif
+	return rc;
+}
+
+
+/* read a sector with other than 2048 bytes length 
+ * dest is assumed to be allocated with scsi_malloc
  *
- *   - HP:	Much like SONY, but a little different... (Thomas)
- *              HP-Writers only ???
+ * XXX maybe we have to do some locking here.
  */
 
+int
+sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
+{
+	unsigned char   *buffer;    /* the buffer for the ioctl */
+	unsigned char   cmd[12];    /* the scsi-command */
+	int             rc, density;
+
+	density = (scsi_CDs[minor].vendor == VENDOR_TOSHIBA) ? 0x83 : 0;
+
+	buffer = (unsigned char *) scsi_malloc(512);
+	if (!buffer) return -ENOMEM;
+
+	rc = set_density_and_blocklength(minor, buffer, density, blksize);
+	if (!rc) {
+		memset(cmd,0,12);
+		cmd[0] = READ_10;
+		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[2] = (unsigned char)(lba >> 24) & 0xff;
+		cmd[3] = (unsigned char)(lba >> 16) & 0xff;
+		cmd[4] = (unsigned char)(lba >>  8) & 0xff;
+		cmd[5] = (unsigned char) lba        & 0xff;
+		cmd[8] = 1;
+		rc = sr_do_ioctl(minor, cmd, dest, blksize);
+		set_density_and_blocklength(minor, buffer, density, 2048);
+	}
+	
+	scsi_free(buffer, 512);
+	return rc;
+}
+
+
+/* This function gets called after a media change. Checks if the CD is
+   multisession, asks for offset etc. */
+
 #define BCD_TO_BIN(x)    ((((int)x & 0xf0) >> 4)*10 + ((int)x & 0x0f))
 
 int sr_cd_check(struct cdrom_device_info *cdi)
 {
 	unsigned long   sector,min,sec,frame;
-	unsigned char   *buffer;    /* the buffer for the ioctl */
-	unsigned char   cmd[12];    /* the scsi-command */
+	unsigned char   *buffer;     /* the buffer for the ioctl */
+	unsigned char   *raw_sector; 
+	unsigned char   cmd[12];     /* the scsi-command */
 	int             rc,is_xa,no_multi,minor;
 
 	minor = MINOR(cdi->dev);
+	if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
+		return 0;
 	
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
@@ -116,7 +196,6 @@
 		sec    = BCD_TO_BIN(buffer[16]);
 		frame  = BCD_TO_BIN(buffer[17]);
 		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
-		is_xa  = (buffer[14] == 0xb0);
 		break;
 		
 	case VENDOR_TOSHIBA:
@@ -141,36 +220,6 @@
 		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
 		if (sector)
 			sector -= CD_BLOCK_OFFSET;
-		is_xa  = (buffer[0] == 0x20);
-#if 0
-		/* this is required for some CD's:
-		 *   - Enhanced-CD (Hardware tells wrong XA-flag)
-		 *   - these broken non-XA multisession CD's
-		 */
-		if (is_xa == 0 && sector != 0) {
-			printk(KERN_WARNING "Warning: multisession offset "
-			       "found, setting XA-flag\n");
-			is_xa = 1;
-		}
-#endif
-		/* now the XA-Sector tweaking: set_density... */
-		memset(cmd,0,12);
-		cmd[0] = MODE_SELECT;
-		cmd[1] = (scsi_CDs[minor].device->lun << 5)
-			| (1 << 4);
-		cmd[4] = 12;
-		memset(buffer,0,12);
-		buffer[ 3] = 0x08;
-		buffer[ 4] = 0x83;
-		buffer[10] = 0x08;
-		rc = sr_do_ioctl(minor, cmd, buffer, 12);
-		if (rc != 0) {
-			break;
-		}
-#if 0
-		/* shoult'nt be required any more */
-		scsi_CDs[minor].needs_sector_size = 1;
-#endif
 		break;
 
 	case VENDOR_HP:
@@ -209,15 +258,10 @@
 		sector = buffer[11] + (buffer[10] << 8) +
 			(buffer[9] << 16) + (buffer[8] << 24);
 #endif
-		is_xa = !!sector;
 		break;
 
 	case VENDOR_SONY_LIKE:
 		/* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */
-#ifdef DEBUG
-		printk(KERN_DEBUG
-		       "sr: use \"Sony group\" multisession code\n");
-#endif
 		memset(cmd,0,12);
 		cmd[0] = READ_TOC;
 		cmd[1] = (scsi_CDs[minor].device->lun << 5);
@@ -227,7 +271,7 @@
 		if (rc != 0) {
 			break;
 		}
-		if ((buffer[0] << 8) + buffer[1] != 0x0a) {
+		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
 			printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n");
 			no_multi = 1;
 			break;
@@ -238,7 +282,6 @@
 			/* ignore sector offsets from first track */
 			sector = 0;
 		}
-		is_xa = !!sector;
 		break;
 		
 	case VENDOR_CAN_NOT_HANDLE:
@@ -255,19 +298,39 @@
 		no_multi = 1;
 		break;
 	}
-    
+   
+	scsi_CDs[minor].xa_flag = 0;
+	if (CDS_AUDIO != sr_disk_status(cdi)) { 
+	    /* read a sector in raw mode to check the sector format */
+	    raw_sector = (unsigned char *) scsi_malloc(2048+512);
+	    if (!buffer) return -ENOMEM;
+	    if (0 == sr_read_sector(minor,sector+16,CD_FRAMESIZE_RAW1,
+				    raw_sector)){
+		is_xa = (raw_sector[3] == 0x02);
+		if (sector > 0 && !is_xa)
+			printk(KERN_INFO "sr: broken CD found: It is "
+			       "multisession, but has'nt XA sectors\n");
+	    } else {
+		/* read a raw sector failed for some reason. */
+		is_xa = (sector > 0);
+	    }
+	    scsi_free(raw_sector, 2048+512);
+	}
 #ifdef DEBUG
-	if (sector)
-		printk(KERN_DEBUG
-		       "sr: multisession CD detected, offset: %lu\n",sector);
+	else printk("sr: audio CD found\n");
 #endif
 
 	scsi_CDs[minor].ms_offset = sector;
 	scsi_CDs[minor].xa_flag = is_xa;
 	if (no_multi)
 		cdi->mask |= CDC_MULTI_SESSION;
-	
-	scsi_free(buffer, 512);
 
+#ifdef DEBUG
+	printk(KERN_DEBUG
+	       "sr: multisession offset=%lu, XA=%s\n",
+	       sector,is_xa ? "yes" : "no");
+#endif
+
+	scsi_free(buffer, 512);
 	return rc;
 }
diff -u --recursive --new-file v2.1.33/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c
--- v2.1.33/linux/fs/binfmt_em86.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/binfmt_em86.c	Fri Apr 11 10:37:41 1997
@@ -20,13 +20,13 @@
 
 static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
 {
-	char *cp, *interp, *i_name, *i_arg;
+	char *interp, *i_name, *i_arg;
 	int retval;
 	struct elfhdr	elf_ex;
 
 	/* Make sure this is a Linux/Intel ELF executable... */
 	elf_ex = *((struct elfhdr *)bprm->buf);
-	
+
         if (elf_ex.e_ident[0] != 0x7f ||
             strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
                 return  -ENOEXEC;
diff -u --recursive --new-file v2.1.33/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.33/linux/fs/buffer.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/buffer.c	Mon Apr 14 09:31:09 1997
@@ -583,7 +583,7 @@
 	    buffer_protected(bh) || buffer_locked(bh))
 		return 0;
 			 
-	if (mem_map[MAP_NR((unsigned long) bh->b_data)].count != 1 ||
+	if (atomic_read(&mem_map[MAP_NR((unsigned long) bh->b_data)].count) != 1 ||
 	    buffer_dirty(bh)) {
 		refile_buffer(bh);
 		return 0;
@@ -1304,7 +1304,7 @@
 	int *p, nr[PAGE_SIZE/512];
 	int i;
 
-	page->count++;
+	atomic_inc(&page->count);
 	set_bit(PG_locked, &page->flags);
 	set_bit(PG_free_after, &page->flags);
 	
@@ -1426,7 +1426,7 @@
 	buffermem -= PAGE_SIZE;
 	mem_map[MAP_NR(page)].buffers = NULL;
 	free_page(page);
-	return !mem_map[MAP_NR(page)].count;
+	return !atomic_read(&mem_map[MAP_NR(page)].count);
 }
 
 /* ================== Debugging =================== */
@@ -1536,7 +1536,7 @@
 		ndirty = 0;
 		nwritten = 0;
 	repeat:
-	
+
 		bh = lru_list[nlist];
 		if(bh) 
 			 for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
@@ -1678,7 +1678,7 @@
 			 ndirty = 0;
 			 refilled = 0;
 		 repeat:
-		 	
+
 			 bh = lru_list[nlist];
 			 if(bh) 
 				  for (i = nr_buffers_type[nlist]; i-- > 0 && ndirty < bdf_prm.b_un.ndirty; 
diff -u --recursive --new-file v2.1.33/linux/fs/exec.c linux/fs/exec.c
--- v2.1.33/linux/fs/exec.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/exec.c	Fri Apr 11 10:47:38 1997
@@ -71,6 +71,10 @@
 	init_elf_binfmt();
 #endif
 
+#ifdef CONFIG_BINFMT_ELF32
+	init_elf32_binfmt();
+#endif
+
 #ifdef CONFIG_BINFMT_AOUT
 	init_aout_binfmt();
 #endif
diff -u --recursive --new-file v2.1.33/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.1.33/linux/fs/fat/misc.c	Tue Jan 14 16:46:07 1997
+++ linux/fs/fat/misc.c	Sat Apr 12 12:24:19 1997
@@ -258,6 +258,9 @@
 {
 	int day,year,nl_day,month;
 
+	if (sys_tz.tz_dsttime) {
+		unix_date += 3600;
+	}
 	unix_date -= sys_tz.tz_minuteswest*60;
 	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
 	    (((unix_date/3600) % 24) << 11);
diff -u --recursive --new-file v2.1.33/linux/fs/inode.c linux/fs/inode.c
--- v2.1.33/linux/fs/inode.c	Sun Apr 13 10:18:21 1997
+++ linux/fs/inode.c	Mon Apr 14 09:31:09 1997
@@ -529,7 +529,7 @@
 	best->i_count = 1;
 	best->i_nlink = 1;
 	best->i_version = ++event;
-	best->i_sem.count = 1;
+	sema_init(&best->i_sem, 1);
 	best->i_ino = ++ino;
 	best->i_dev = 0;
 	nr_free_inodes--;
diff -u --recursive --new-file v2.1.33/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.1.33/linux/fs/isofs/dir.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/isofs/dir.c	Fri Apr 11 10:37:41 1997
@@ -172,7 +172,7 @@
 			 * entries should terminate with a null size
 			 * or end exactly at the end of the sector.
 			 */
-		        printk("next_offset (%x) > bufsize (%x)\n",
+		        printk("next_offset (%x) > bufsize (%lx)\n",
 			       offset,bufsize);
 			break;
 		}
diff -u --recursive --new-file v2.1.33/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.1.33/linux/fs/isofs/inode.c	Sun Apr 13 10:18:22 1997
+++ linux/fs/isofs/inode.c	Fri Apr 11 10:37:41 1997
@@ -393,7 +393,7 @@
 	if(    (blocksize != 0)
 	    && (orig_zonesize < blocksize) )
 	  {
-	      printk("Logical zone size(%ld) < hardware blocksize(%ld)\n", 
+	      printk("Logical zone size(%d) < hardware blocksize(%u)\n",
 		     orig_zonesize, blocksize);
 	      goto out;
 
@@ -549,12 +549,12 @@
 	     * the page with useless information without generating any
 	     * I/O errors.
 	     */
-	    max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1) 
+	    max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
 	      & ~(PAGE_SIZE - 1);
 	    if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset )
 	      {
 
-		printk("_isofs_bmap: block>= EOF(%d, %d)\n", block, 
+		printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block,
 		       inode->i_size);
 	      }
 	    return 0;
diff -u --recursive --new-file v2.1.33/linux/fs/nfs/Makefile linux/fs/nfs/Makefile
--- v2.1.33/linux/fs/nfs/Makefile	Mon Apr  7 11:35:30 1997
+++ linux/fs/nfs/Makefile	Mon Apr 14 09:31:09 1997
@@ -12,7 +12,7 @@
 	    nfs2xdr.o
 
 ifdef CONFIG_ROOT_NFS
-  O_OBJS += nfsroot.o
+  O_OBJS += nfsroot.o mount_clnt.o
 endif
 
 M_OBJS   := $(O_TARGET)
diff -u --recursive --new-file v2.1.33/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.33/linux/fs/nfs/inode.c	Sun Apr 13 10:18:22 1997
+++ linux/fs/nfs/inode.c	Mon Apr 14 09:31:09 1997
@@ -83,12 +83,14 @@
 void
 nfs_put_super(struct super_block *sb)
 {
+	struct nfs_server *server = &sb->u.nfs_sb.s_server;
 	struct rpc_clnt	*rpc;
 
-	if ((rpc = sb->u.nfs_sb.s_server.client) != NULL)
+	if ((rpc = server->client) != NULL)
 		rpc_shutdown_client(rpc);
 
-	lockd_down();		/* release rpc.lockd */
+	if (!(server->flags & NFS_MOUNT_NONLM))
+		lockd_down();	/* release rpc.lockd */
 	rpciod_down();		/* release rpciod */
 	lock_super(sb);
 	sb->s_dev = 0;
@@ -230,7 +232,8 @@
 
 	if ((sb->s_mounted = nfs_fhget(sb, &data->root, NULL)) != NULL) {
 		/* We're airborne */
-		lockd_up();
+		if (!(server->flags & NFS_MOUNT_NONLM))
+			lockd_up();
 		return sb;
 	}
 
diff -u --recursive --new-file v2.1.33/linux/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c
--- v2.1.33/linux/fs/nfs/mount_clnt.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nfs/mount_clnt.c	Mon Apr 14 09:31:09 1997
@@ -0,0 +1,141 @@
+/*
+ * linux/fs/nfs/mount_clnt.c
+ *
+ * MOUNT client to support NFSroot.
+ *
+ * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/uio.h>
+#include <linux/net.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/nfs_fs.h>
+
+#ifdef RPC_DEBUG
+# define NFSDBG_FACILITY	NFSDBG_ROOT
+#endif
+
+/*
+#define MOUNT_PROGRAM		100005
+#define MOUNT_VERSION		1
+#define MOUNT_MNT		1
+#define MOUNT_UMNT		3
+ */
+
+static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *);
+extern struct rpc_program	mnt_program;
+
+struct mnt_fhstatus {
+	unsigned int		status;
+	struct nfs_fh *		fh;
+};
+
+/*
+ * Obtain an NFS file handle for the given host and path
+ */
+int
+nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+{
+	struct rpc_clnt		*mnt_clnt;
+	struct mnt_fhstatus	result = { 0, fh };
+	char			hostname[32];
+	int			status;
+
+	dprintk("NFS:      nfs_mount(%08lx:%s)\n",
+			ntohl(addr->sin_addr.s_addr), path);
+
+	strcpy(hostname, in_ntoa(addr->sin_addr.s_addr));
+	if (!(mnt_clnt = mnt_create(hostname, addr)))
+		return -EACCES;
+
+	status = rpc_call(mnt_clnt, NFS_MNTPROC_MNT, path, &result, 0);
+	return status < 0? status : (result.status? -EACCES : 0);
+}
+
+static struct rpc_clnt *
+mnt_create(char *hostname, struct sockaddr_in *srvaddr)
+{
+	struct rpc_xprt	*xprt;
+	struct rpc_clnt	*clnt;
+
+	if (!(xprt = xprt_create_proto(IPPROTO_UDP, srvaddr, NULL)))
+		return NULL;
+
+	clnt = rpc_create_client(xprt, hostname,
+				&mnt_program, NFS_MNT_VERSION,
+				RPC_AUTH_NULL);
+	if (!clnt) {
+		xprt_destroy(xprt);
+	} else {
+		clnt->cl_softrtry = 1;
+		clnt->cl_chatty   = 1;
+		clnt->cl_oneshot  = 1;
+	}
+	return clnt;
+}
+
+/*
+ * XDR encode/decode functions for MOUNT
+ */
+static int
+xdr_error(struct rpc_rqst *req, u32 *p, void *dummy)
+{
+	return -EIO;
+}
+
+static int
+xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
+{
+	p = xdr_encode_string(p, path);
+
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+{
+	if ((res->status = ntohl(*p++)) == 0)
+		memcpy(res->fh, p, sizeof(*res->fh));
+	return 0;
+}
+
+#define MNT_dirpath_sz		(1 + 256)
+#define MNT_fhstatus_sz		(1 + 8)
+
+static struct rpc_procinfo	mnt_procedures[2] = {
+	{ "mnt_null",
+		(kxdrproc_t) xdr_error,	
+		(kxdrproc_t) xdr_error,	0, 0 },
+	{ "mnt_mount",
+		(kxdrproc_t) xdr_encode_dirpath,	
+		(kxdrproc_t) xdr_decode_fhstatus,
+		MNT_dirpath_sz, MNT_fhstatus_sz },
+};
+
+static struct rpc_version	mnt_version1 = {
+	1, 2, mnt_procedures
+};
+
+static struct rpc_version *	mnt_version[] = {
+	NULL,
+	&mnt_version1,
+};
+
+static struct rpc_stat		mnt_stats;
+
+struct rpc_program	mnt_program = {
+	"mount",
+	NFS_MNT_PROGRAM,
+	sizeof(mnt_version)/sizeof(mnt_version[0]),
+	mnt_version,
+	&mnt_stats,
+};
diff -u --recursive --new-file v2.1.33/linux/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c
--- v2.1.33/linux/fs/nfs/nfs2xdr.c	Sun Apr 13 10:18:22 1997
+++ linux/fs/nfs/nfs2xdr.c	Mon Apr 14 09:31:09 1997
@@ -416,6 +416,7 @@
 		if ((void *) (entry+1) > (void *) string) {
 			printk(KERN_NOTICE "NFS: should not happen in %s!\n",
 					__FUNCTION__);
+			printk(KERN_NOTICE "NFS: len = %d, entry+1=%p, string=%p\n", len, entry+1, string);
 			break;
 		}
 
diff -u --recursive --new-file v2.1.33/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.1.33/linux/fs/nfs/nfsroot.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfs/nfsroot.c	Mon Apr 14 09:31:09 1997
@@ -51,6 +51,9 @@
  *				without giving a path name. Fix BOOTP request
  *				for domainname (domainname is NIS domain, not
  *				DNS domain!). Skip dummy devices for BOOTP.
+ *	Jacek Zapala	:	Fixed a bug which prevented server-ip address
+ *				from nfsroot parameter from being used.
+ *	Olaf Kirch	:	Adapted to new NFS code.
  *
  */
 
@@ -81,8 +84,10 @@
 #include <net/ax25.h>	/* For AX25_P_IP */
 #endif
 #include <linux/skbuff.h>
+#include <linux/ip.h>
 #include <linux/socket.h>
 #include <linux/route.h>
+#include <linux/sunrpc/clnt.h>
 #include <linux/nfs.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
@@ -91,11 +96,13 @@
 #include <net/sock.h>
 
 #include <asm/segment.h>
+#include <asm/uaccess.h>
 
+#define NFSDBG_FACILITY		NFSDBG_ROOT
 /* Range of privileged ports */
-#define STARTPORT	600
-#define ENDPORT		1023
-#define NPORTS		(ENDPORT - STARTPORT + 1)
+#define STARTPORT		600
+#define ENDPORT			1023
+#define NPORTS			(ENDPORT - STARTPORT + 1)
 
 
 /* Define the timeout for waiting for a RARP/BOOTP reply */
@@ -119,10 +126,10 @@
 /* IP configuration */
 static struct device *root_dev = NULL;	/* Device selected for booting */
 static char user_dev_name[IFNAMSIZ];	/* Name of user-selected boot device */
-static struct sockaddr_in myaddr;	/* My IP address */
-static struct sockaddr_in server;	/* Server IP address */
-static struct sockaddr_in gateway;	/* Gateway IP address */
-static struct sockaddr_in netmask;	/* Netmask for local subnet */
+static __u32 myaddr;			/* My IP address */
+static __u32 servaddr;			/* Server IP address */
+static __u32 gateway;			/* Gateway IP address */
+static __u32 netmask;			/* Netmask for local subnet */
 
 
 /* BOOTP/RARP variables */
@@ -130,7 +137,7 @@
 static int rarp_flag;			/* User said: Use RARP! */
 static int bootp_dev_count = 0;		/* Number of devices allowing BOOTP */
 static int rarp_dev_count = 0;		/* Number of devices allowing RARP */
-static struct sockaddr_in rarp_serv;	/* IP address of RARP server */
+static __u32 rarp_serv;			/* IP address of RARP server */
 
 #if defined(CONFIG_RNFS_BOOTP) || defined(CONFIG_RNFS_RARP)
 #define CONFIG_RNFS_DYNAMIC		/* Enable dynamic IP config */
@@ -143,8 +150,9 @@
 
 /* NFS-related data */
 static struct nfs_mount_data nfs_data;		/* NFS mount info */
-static char nfs_path[NFS_MAXPATHLEN] = "";	/* Name of directory to mount */
-static int nfs_port;				/* Port to connect to for NFS */
+static char	nfs_path[NFS_MAXPATHLEN];	/* Name of directory to mount */
+static int	nfs_port;			/* Port to connect to for NFS */
+static int	mount_port;			/* Mount daemon port number */
 
 
 /* Yes, we use sys_socket, but there's no include file for it */
@@ -193,9 +201,7 @@
 			bootp_dev_count++;
 			if (!(dev->flags & IFF_NOARP))
 				rarp_dev_count++;
-#ifdef NFSROOT_DEBUG
-			printk(KERN_NOTICE "Root-NFS: Opened %s\n", dev->name);
-#endif
+			dprintk("Root-NFS: Opened %s\n", dev->name);
 		}
 	}
 	*last = NULL;
@@ -207,6 +213,58 @@
 	return 0;
 }
 
+static inline void
+set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port)
+{
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = addr;
+	sin->sin_port = port;
+}
+
+static int
+root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw)
+{
+	struct rtentry	route;
+	unsigned long	oldfs;
+	int		err;
+
+	route.rt_dev = dev->name;
+	route.rt_mtu = dev->mtu;
+	route.rt_flags = RTF_UP;
+	set_sockaddr((struct sockaddr_in *) &route.rt_dst, dest & mask, 0);
+	set_sockaddr((struct sockaddr_in *) &route.rt_genmask, mask, 0);
+
+	if (gw != 0) {
+		set_sockaddr((struct sockaddr_in *) &route.rt_gateway, gw, 0);
+		route.rt_flags |= RTF_GATEWAY;
+		if ((gw ^ myaddr) & netmask) {
+			printk(KERN_ERR "Root-NFS: Gateway not on local network!\n");
+			return -ENETUNREACH;
+		}
+	}
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = ip_rt_ioctl(op, &route);
+	set_fs(oldfs);
+	printk(KERN_NOTICE "%s route %s %s %s: res %d\n",
+			(op == SIOCADDRT? "add" : "del"),
+			in_ntoa(dest), in_ntoa(mask), in_ntoa(gw), err);
+
+	return err;
+}
+
+static int
+root_dev_add_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway)
+{
+	return root_dev_chg_route(SIOCADDRT, dev, dest, mask, gateway);
+}
+
+static int
+root_dev_del_route(struct device *dev, __u32 dest, __u32 mask, __u32 gateway)
+{
+	return root_dev_chg_route(SIOCDELRT, dev, dest, mask, gateway);
+}
 
 /*
  *  Restore the state of all devices. However, keep the root device open
@@ -290,7 +348,7 @@
 	unsigned long sip, tip;
 	unsigned char *sha, *tha;		/* s for "source", t for "target" */
 
-	/* If this test doesn't pass, its not IP, or we should ignore it anyway */
+	/* If this test doesn't pass, it's not IP, or we should ignore it anyway */
 	if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) {
 		kfree_skb(skb, FREE_READ);
 		return 0;
@@ -328,8 +386,8 @@
 	}
 	/* Discard packets which are not from specified server. */
 	if (rarp_flag && !bootp_flag &&
-	    rarp_serv.sin_addr.s_addr != INADDR_NONE &&
-	    rarp_serv.sin_addr.s_addr != sip) {
+	    rarp_serv != INADDR_NONE &&
+	    rarp_serv != sip) {
 		kfree_skb(skb, FREE_READ);
 		return 0;
 	}
@@ -348,14 +406,10 @@
 	sti();
 	root_dev = dev;
 
-	if (myaddr.sin_addr.s_addr == INADDR_NONE) {
-		myaddr.sin_family = dev->family;
-		myaddr.sin_addr.s_addr = tip;
-	}
-	if (server.sin_addr.s_addr == INADDR_NONE) {
-		server.sin_family = dev->family;
-		server.sin_addr.s_addr = sip;
-	}
+	if (myaddr == INADDR_NONE)
+		myaddr = tip;
+	if (servaddr == INADDR_NONE)
+		servaddr = sip;
 	kfree_skb(skb, FREE_READ);
 	return 0;
 }
@@ -393,10 +447,8 @@
 
 static struct device *bootp_dev = NULL;	/* Device selected as best BOOTP target */
 
-static int bootp_xmit_fd = -1;		/* Socket descriptor for transmit */
-static struct socket *bootp_xmit_sock;	/* The socket itself */
-static int bootp_recv_fd = -1;		/* Socket descriptor for receive */
-static struct socket *bootp_recv_sock;	/* The socket itself */
+static struct socket *bootp_xmit_sock;	/* BOOTP send socket */
+static struct socket *bootp_recv_sock;	/* BOOTP receive socket */
 
 struct bootp_pkt {		/* BOOTP packet format */
 	u8 op;			/* 1=request, 2=reply */
@@ -460,18 +512,8 @@
  */
 static int root_add_bootp_route(void)
 {
-	struct rtentry route;
-
-	memset(&route, 0, sizeof(route));
-	route.rt_dev = bootp_dev->name;
-	route.rt_mss = bootp_dev->mtu;
-	route.rt_flags = RTF_UP;
-	((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0;
-	((struct sockaddr_in *) &(route.rt_dst)) -> sin_family = AF_INET;
-	((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0;
-	((struct sockaddr_in *) &(route.rt_genmask)) -> sin_family = AF_INET;
-	if (ip_rt_new(&route)) {
-		printk(KERN_ERR "BOOTP: Adding of route failed!\n");
+	if (root_dev_add_route(bootp_dev, 0, 0, 0) < 0) {
+		printk(KERN_ERR "BOOTP: Failed to add route\n");
 		return -1;
 	}
 	bootp_have_route = 1;
@@ -484,14 +526,7 @@
  */
 static int root_del_bootp_route(void)
 {
-	struct rtentry route;
-
-	if (!bootp_have_route)
-		return 0;
-	memset(&route, 0, sizeof(route));
-	((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0;
-	((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0;
-	if (ip_rt_kill(&route)) {
+	if (bootp_have_route && root_dev_del_route(bootp_dev, 0, 0, 0) < 0) {
 		printk(KERN_ERR "BOOTP: Deleting of route failed!\n");
 		return -1;
 	}
@@ -503,21 +538,13 @@
 /*
  *  Open UDP socket.
  */
-static int root_open_udp_sock(int *fd, struct socket **sock)
+static int root_open_udp_sock(struct socket **sock)
 {
-	struct file *file;
-	struct inode *inode;
+	int	err;
 
-	*fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-	if (*fd >= 0) {
-		file = current->files->fd[*fd];
-		inode = file->f_inode;
-		*sock = &inode->u.socket_i;
-		return 0;
-	}
-
-	printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n");
-	return -1;
+	if ((err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, sock)) < 0)
+		printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n");
+	return err;
 }
 
 
@@ -529,9 +556,7 @@
 	struct sockaddr_in sa;
 	int result;
 
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = htonl(addr);
-	sa.sin_port = htons(port);
+	set_sockaddr(&sa, htonl(addr), htonl(port));
 	result = sock->ops->connect(sock, (struct sockaddr *) &sa, sizeof(sa), 0);
 	if (result < 0) {
 		printk(KERN_ERR "BOOTP: connect() failed\n");
@@ -549,9 +574,7 @@
 	struct sockaddr_in sa;
 	int result;
 
-	sa.sin_family = AF_INET;
-	sa.sin_addr.s_addr = htonl(addr);
-	sa.sin_port = htons(port);
+	set_sockaddr(&sa, htonl(addr), htonl(port));
 	result = sock->ops->bind(sock, (struct sockaddr *) &sa, sizeof(sa));
 	if (result < 0) {
 		printk(KERN_ERR "BOOTP: bind() failed\n");
@@ -575,12 +598,12 @@
 	set_fs(get_ds());
 	iov.iov_base = buf;
 	iov.iov_len = size;
-	msg.msg_name = NULL;
+	memset(&msg, 0, sizeof(msg));
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
-	msg.msg_accrights = NULL;
-	result = sock->ops->sendmsg(sock, &msg, size, 0, 0);
+	result = sock_sendmsg(sock, &msg, size);
 	set_fs(oldfs);
+
 	return (result != size);
 }
 
@@ -599,12 +622,11 @@
 	set_fs(get_ds());
 	iov.iov_base = buf;
 	iov.iov_len = size;
-	msg.msg_name = NULL;
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_flags = MSG_DONTWAIT;
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
-	msg.msg_accrights = NULL;
-	msg.msg_namelen = 0;
-	result = sock->ops->recvmsg(sock, &msg, size, O_NONBLOCK, 0, &msg.msg_namelen);
+	result = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT);
 	set_fs(oldfs);
 	return result;
 }
@@ -643,10 +665,10 @@
  */
 static void root_bootp_close(void)
 {
-	if (bootp_xmit_fd != -1)
-		sys_close(bootp_xmit_fd);
-	if (bootp_recv_fd != -1)
-		sys_close(bootp_recv_fd);
+	if (bootp_xmit_sock)
+		sock_release(bootp_xmit_sock);
+	if (bootp_recv_sock)
+		sock_release(bootp_recv_sock);
 	root_del_bootp_route();
 	root_free_bootp();
 }
@@ -695,6 +717,7 @@
 	xmit_bootp->hlen = best_dev->addr_len;
 	memcpy(xmit_bootp->hw_addr, best_dev->dev_addr, best_dev->addr_len);
 	root_bootp_init_ext(xmit_bootp->vendor_area);
+
 #ifdef NFSROOT_BOOTP_DEBUG
 	{
 		int x;
@@ -714,14 +737,14 @@
 		return -1;
 
 	/* Open the sockets */
-	if (root_open_udp_sock(&bootp_xmit_fd, &bootp_xmit_sock) ||
-	    root_open_udp_sock(&bootp_recv_fd, &bootp_recv_sock))
+	if (root_open_udp_sock(&bootp_xmit_sock) ||
+	    root_open_udp_sock(&bootp_recv_sock))
 		return -1;
 
 	/* Bind/connect the sockets */
-	((struct sock *) bootp_xmit_sock->data) -> broadcast = 1;
-	((struct sock *) bootp_xmit_sock->data) -> reuse = 1;
-	((struct sock *) bootp_recv_sock->data) -> reuse = 1;
+	bootp_xmit_sock->sk->broadcast = 1;
+	bootp_xmit_sock->sk->reuse = 1;
+	bootp_recv_sock->sk->reuse = 1;
 	if (root_bind_udp_sock(bootp_recv_sock, INADDR_ANY, 68) ||
 	    root_bind_udp_sock(bootp_xmit_sock, INADDR_ANY, 68) ||
 	    root_connect_udp_sock(bootp_xmit_sock, INADDR_BROADCAST, 67))
@@ -761,9 +784,9 @@
  */
 static void root_do_bootp_ext(u8 *ext)
 {
+#ifdef NFSROOT_BOOTP_DEBUG
 	u8 *c;
 
-#ifdef NFSROOT_BOOTP_DEBUG
 	printk("BOOTP: Got extension %02x",*ext);
 	for(c=ext+2; c<ext+2+ext[1]; c++)
 		printk(" %02x", *c);
@@ -772,12 +795,12 @@
 
 	switch (*ext++) {
 		case 1:		/* Subnet mask */
-			if (netmask.sin_addr.s_addr == INADDR_NONE)
-				memcpy(&netmask.sin_addr.s_addr, ext+1, 4);
+			if (netmask == INADDR_NONE)
+				memcpy(&netmask, ext+1, 4);
 			break;
 		case 3:		/* Default gateway */
-			if (gateway.sin_addr.s_addr == INADDR_NONE)
-				memcpy(&gateway.sin_addr.s_addr, ext+1, 4);
+			if (gateway == INADDR_NONE)
+				memcpy(&gateway, ext+1, 4);
 			break;
 		case 12:	/* Host name */
 			root_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
@@ -810,9 +833,7 @@
 	    recv_bootp->htype != xmit_bootp->htype ||
 	    recv_bootp->hlen != xmit_bootp->hlen ||
 	    recv_bootp->xid != xmit_bootp->xid) {
-#ifdef NFSROOT_BOOTP_DEBUG
-		printk("?");
-#endif
+		dprintk("?");
 		return;
 		}
 
@@ -827,9 +848,9 @@
 	root_dev = bootp_dev;
 
 	/* Extract basic fields */
-	myaddr.sin_addr.s_addr = recv_bootp->your_ip;
-	if (server.sin_addr.s_addr==INADDR_NONE)
-		server.sin_addr.s_addr = recv_bootp->server_ip;
+	myaddr = recv_bootp->your_ip;
+	if (servaddr==INADDR_NONE)
+		servaddr = recv_bootp->server_ip;
 
 	/* Parse extensions */
 	if (recv_bootp->vendor_area[0] == 99 &&	/* Check magic cookie */
@@ -983,14 +1004,28 @@
 	printk(" OK\n");
 	printk(KERN_NOTICE "Root-NFS: Got %s answer from %s, ",
 		(pkt_arrived == ARRIVED_BOOTP) ? "BOOTP" : "RARP",
-		in_ntoa(server.sin_addr.s_addr));
-	printk("my address is %s\n", in_ntoa(myaddr.sin_addr.s_addr));
+		in_ntoa(servaddr));
+	printk("my address is %s\n", in_ntoa(myaddr));
 
 	return 0;
 }
 #endif
 
-
+/* Get default netmask - used to be exported from net/ipv4 */
+static unsigned long
+ip_get_mask(unsigned long addr)
+{
+	if (!addr)
+		return 0;
+	addr = ntohl(addr);
+	if (IN_CLASSA(addr))
+		return htonl(IN_CLASSA_NET);
+	if (IN_CLASSB(addr))
+		return htonl(IN_CLASSB_NET);
+	if (IN_CLASSC(addr))
+		return htonl(IN_CLASSC_NET);
+	return 0;
+}
 
 /***************************************************************************
 
@@ -1060,22 +1095,24 @@
 			break;
 		if (*cp == '.' || octets == 3)
 			octets++;
+		if (octets < 4)
+			cp++;
 		cq = cp;
 	}
 	if (octets == 4 && (*cp == ':' || *cp == '\0')) {
 		if (*cp == ':')
 			*cp++ = '\0';
-		server.sin_addr.s_addr = in_aton(name);
+		servaddr = in_aton(name);
 		name = cp;
 	}
 
 	/* Clear the nfs_data structure and setup the server hostname */
 	memset(&nfs_data, 0, sizeof(nfs_data));
-	strncpy(nfs_data.hostname, in_ntoa(server.sin_addr.s_addr),
+	strncpy(nfs_data.hostname, in_ntoa(servaddr),
 						sizeof(nfs_data.hostname)-1);
 
 	/* Set the name of the directory to mount */
-	if (nfs_path[0] == '\0' || !strncmp(name, "default", 7))
+	if (nfs_path[0] == '\0' || strncmp(name, "default", 7))
 		strncpy(buf, name, NFS_MAXPATHLEN);
 	else
 		strncpy(buf, nfs_path, NFS_MAXPATHLEN);
@@ -1083,7 +1120,7 @@
 		*options++ = '\0';
 	if (!strcmp(buf, "default"))
 		strcpy(buf, NFS_ROOT);
-	cp = in_ntoa(myaddr.sin_addr.s_addr);
+	cp = in_ntoa(myaddr);
 	if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
 		printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
 		return -1;
@@ -1094,10 +1131,11 @@
 
 	/* Set some default values */
 	nfs_port          = -1;
-	nfs_data.version  = NFS_MOUNT_VERSION;
-	nfs_data.flags    = 0;
+	nfs_data.version  = NFS_MNT_VERSION;
+	nfs_data.flags    = NFS_MOUNT_NONLM;	/* No lockd in nfs root yet */
 	nfs_data.rsize    = NFS_DEF_FILE_IO_BUFFER_SIZE;
 	nfs_data.wsize    = NFS_DEF_FILE_IO_BUFFER_SIZE;
+	nfs_data.bsize	  = 0;
 	nfs_data.timeo    = 7;
 	nfs_data.retrans  = 3;
 	nfs_data.acregmin = 3;
@@ -1135,17 +1173,17 @@
 /*
  *  Tell the user what's going on.
  */
-#ifdef NFSROOT_DEBUG
+#ifdef NFSROOT_BOOTP
 static void root_nfs_print(void)
 {
 #define IN_NTOA(x) (((x) == INADDR_NONE) ? "none" : in_ntoa(x))
 
 	printk(KERN_NOTICE "Root-NFS: IP config: dev=%s, ",
 		root_dev ? root_dev->name : "none");
-	printk("local=%s, ", IN_NTOA(myaddr.sin_addr.s_addr));
-	printk("server=%s, ", IN_NTOA(server.sin_addr.s_addr));
-	printk("gw=%s, ", IN_NTOA(gateway.sin_addr.s_addr));
-	printk("mask=%s, ", IN_NTOA(netmask.sin_addr.s_addr));
+	printk("local=%s, ", IN_NTOA(myaddr));
+	printk("server=%s, ", IN_NTOA(servaddr));
+	printk("gw=%s, ", IN_NTOA(gateway));
+	printk("mask=%s, ", IN_NTOA(netmask));
 	printk("host=%s, domain=%s\n",
 		system_utsname.nodename[0] ? system_utsname.nodename : "none",
 		system_utsname.domainname[0] ? system_utsname.domainname : "none");
@@ -1189,10 +1227,7 @@
 	int num = 0;
 
 	/* Clear all addresses and strings */
-	myaddr.sin_family = server.sin_family = rarp_serv.sin_family =
-	    gateway.sin_family = netmask.sin_family = AF_INET;
-	myaddr.sin_addr.s_addr = server.sin_addr.s_addr = rarp_serv.sin_addr.s_addr =
-	    gateway.sin_addr.s_addr = netmask.sin_addr.s_addr = INADDR_NONE;
+	myaddr = servaddr = rarp_serv = gateway = netmask = INADDR_NONE;
 	system_utsname.nodename[0] = '\0';
 	system_utsname.domainname[0] = '\0';
 	user_dev_name[0] = '\0';
@@ -1215,26 +1250,24 @@
 		if ((cp = strchr(ip, ':')))
 			*cp++ = '\0';
 		if (strlen(ip) > 0) {
-#ifdef NFSROOT_DEBUG
-			printk(KERN_NOTICE "Root-NFS: Config string num %d is \"%s\"\n",
+			dprintk("Root-NFS: Config string num %d is \"%s\"\n",
 								num, ip);
-#endif
 			switch (num) {
 			case 0:
-				if ((myaddr.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
-					myaddr.sin_addr.s_addr = INADDR_NONE;
+				if ((myaddr = in_aton(ip)) == INADDR_ANY)
+					myaddr = INADDR_NONE;
 				break;
 			case 1:
-				if ((server.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
-					server.sin_addr.s_addr = INADDR_NONE;
+				if ((servaddr = in_aton(ip)) == INADDR_ANY)
+					servaddr = INADDR_NONE;
 				break;
 			case 2:
-				if ((gateway.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
-					gateway.sin_addr.s_addr = INADDR_NONE;
+				if ((gateway = in_aton(ip)) == INADDR_ANY)
+					gateway = INADDR_NONE;
 				break;
 			case 3:
-				if ((netmask.sin_addr.s_addr = in_aton(ip)) == INADDR_ANY)
-					netmask.sin_addr.s_addr = INADDR_NONE;
+				if ((netmask = in_aton(ip)) == INADDR_ANY)
+					netmask = INADDR_NONE;
 				break;
 			case 4:
 				if ((dp = strchr(ip, '.'))) {
@@ -1264,7 +1297,7 @@
 		ip = cp;
 		num++;
 	}
-	rarp_serv = server;
+	rarp_serv = servaddr;
 }
 
 
@@ -1273,22 +1306,20 @@
  */
 static int root_nfs_setup(void)
 {
-	struct rtentry route;
-
 	/* Set the default system name in case none was previously found */
 	if (!system_utsname.nodename[0]) {
-		strncpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr), __NEW_UTS_LEN);
+		strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN);
 		system_utsname.nodename[__NEW_UTS_LEN] = '\0';
 	}
 
 	/* Set the correct netmask */
-	if (netmask.sin_addr.s_addr == INADDR_NONE)
-		netmask.sin_addr.s_addr = ip_get_mask(myaddr.sin_addr.s_addr);
+	if (netmask == INADDR_NONE)
+		netmask = ip_get_mask(myaddr);
 
 	/* Setup the device correctly */
-	root_dev->family     = myaddr.sin_family;
-	root_dev->pa_addr    = myaddr.sin_addr.s_addr;
-	root_dev->pa_mask    = netmask.sin_addr.s_addr;
+	root_dev->family     = AF_INET;
+	root_dev->pa_addr    = myaddr;
+	root_dev->pa_mask    = netmask;
 	root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask;
 	root_dev->pa_dstaddr = 0;
 
@@ -1300,32 +1331,18 @@
 	 * gatewayed default route. Note that this gives sufficient network
 	 * setup even for full system operation in all common cases.
 	 */
-	memset(&route, 0, sizeof(route));	/* Local subnet route */
-	route.rt_dev = root_dev->name;
-	route.rt_mss = root_dev->mtu;
-	route.rt_flags = RTF_UP;
-	*((struct sockaddr_in *) &(route.rt_dst)) = myaddr;
-	(((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr &= netmask.sin_addr.s_addr;
-	*((struct sockaddr_in *) &(route.rt_genmask)) = netmask;
-	if (ip_rt_new(&route)) {
+	if (root_dev_add_route(root_dev, myaddr, netmask, 0))
+	{
 		printk(KERN_ERR "Root-NFS: Adding of local route failed!\n");
 		return -1;
 	}
 
-	if (gateway.sin_addr.s_addr != INADDR_NONE) {	/* Default route */
-		(((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr = INADDR_ANY;
-		(((struct sockaddr_in *) &(route.rt_genmask)))->sin_addr.s_addr = INADDR_ANY;
-		*((struct sockaddr_in *) &(route.rt_gateway)) = gateway;
-		route.rt_flags |= RTF_GATEWAY;
-		if ((gateway.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) {
-			printk(KERN_ERR "Root-NFS: Gateway not on local network!\n");
-			return -1;
-		}
-		if (ip_rt_new(&route)) {
+	if (gateway != INADDR_NONE) {	/* Default route */
+		if (root_dev_add_route(root_dev, INADDR_ANY, INADDR_ANY, gateway)) {
 			printk(KERN_ERR "Root-NFS: Adding of default route failed!\n");
 			return -1;
 		}
-	} else if ((server.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) {
+	} else if ((servaddr ^ myaddr) & netmask) {
 		printk(KERN_ERR "Root-NFS: Boot server not on local network and no default gateway configured!\n");
 		return -1;
 	}
@@ -1340,6 +1357,10 @@
  */
 int nfs_root_init(char *nfsname, char *nfsaddrs)
 {
+#ifdef NFSROOT_DEBUG
+	nfs_debug |= NFSDBG_ROOT;
+#endif
+
 	/*
 	 * Decode IP addresses and other configuration info contained
 	 * in the nfsaddrs string (which came from the kernel command
@@ -1365,8 +1386,8 @@
 	 * in the (diskless) system and if the server is on another subnet.
 	 * If only one interface is installed, the routing is obvious.
 	 */
-	if ((myaddr.sin_addr.s_addr == INADDR_NONE ||
-	     server.sin_addr.s_addr == INADDR_NONE ||
+	if ((myaddr == INADDR_NONE ||
+	     servaddr == INADDR_NONE ||
 	     (open_base != NULL && open_base->next != NULL))
 #ifdef CONFIG_RNFS_DYNAMIC
 		&& root_auto_config() < 0
@@ -1420,206 +1441,50 @@
 	       Routines to actually mount the root directory
 
  ***************************************************************************/
-
-static struct file  *nfs_file;		/* File descriptor pointing to inode */
-static struct inode *nfs_sock_inode;	/* Inode containing socket */
-static int *rpc_packet = NULL;		/* RPC packet */
-
-
-/*
- *  Open a UDP socket.
- */
-static int root_nfs_open(void)
-{
-	/* Open the socket */
-	if ((nfs_data.fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
-		printk(KERN_ERR "Root-NFS: Cannot open UDP socket for NFS!\n");
-		return -1;
-	}
-	nfs_file = current->files->fd[nfs_data.fd];
-	nfs_sock_inode = nfs_file->f_inode;
-	return 0;
-}
-
-
-/*
- *  Close the UDP file descriptor. If nfs_read_super is successful, it
- *  increases the reference count, so we can simply close the file, and
- *  the socket keeps open.
- */
-static void root_nfs_close(void)
-{
-	/*
-	 * The following close doesn't touch the server structure, which
-	 * now contains a file pointer pointing into nowhere. The system
-	 * _should_ crash as soon as someone tries to select on the root
-	 * filesystem. Haven't tried it yet - we can still change it back
-	 * to the old way of keeping a static copy of all important data
-	 * structures, including their pointers. At least this should be
-	 * checked out _carefully_ before going into a public release
-	 * kernel.  -  GK
-	 */
-	sys_close(nfs_data.fd);
-}
-
-
-/*
- *  Find a suitable listening port and bind to it
- */
-static int root_nfs_bind(void)
-{
-	int res = -1;
-	short port = STARTPORT;
-	struct sockaddr_in *sin = &myaddr;
-	int i;
-
-	if (nfs_sock_inode->u.socket_i.ops->bind) {
-		for (i = 0; i < NPORTS && res < 0; i++) {
-			sin->sin_port = htons(port++);
-			if (port > ENDPORT) {
-				port = STARTPORT;
-			}
-			res = nfs_sock_inode->u.socket_i.ops->bind(&nfs_sock_inode->u.socket_i,
-						(struct sockaddr *)sin,
-						sizeof(struct sockaddr_in));
-		}
-	}
-	if (res < 0) {
-		printk(KERN_ERR "Root-NFS: Cannot find a suitable listening port\n");
-		root_nfs_close();
-		return -1;
-	}
-#ifdef NFSROOT_DEBUG
-	printk(KERN_NOTICE "Root-NFS: Binding to listening port %d\n", port);
-#endif
-	return 0;
-}
-
-
-/*
- *  Send an RPC request and wait for the answer
- */
-static int *root_nfs_call(int *end)
-{
-	struct socket *sock;
-	int dummylen;
-	static struct nfs_server s = {
-		0,			/* struct file *	 */
-		0,			/* struct rsock *	 */
-		{
-		    0, "",
-		},			/* toaddr		 */
-		0,			/* lock			 */
-		NULL,			/* wait queue		 */
-		NFS_MOUNT_SOFT,		/* flags		 */
-		0, 0,			/* rsize, wsize		 */
-		0,			/* timeo		 */
-		0,			/* retrans		 */
-		3 * HZ, 60 * HZ, 30 * HZ, 60 * HZ, "\0"
-	};
-
-	s.file = nfs_file;
-	sock = &((nfs_file->f_inode)->u.socket_i);
-
-	/* Extract the other end of the socket into s->toaddr */
-	sock->ops->getname(sock, &(s.toaddr), &dummylen, 1);
-	((struct sockaddr_in *) &s.toaddr)->sin_port   = server.sin_port;
-	((struct sockaddr_in *) &s.toaddr)->sin_family = server.sin_family;
-	((struct sockaddr_in *) &s.toaddr)->sin_addr.s_addr = server.sin_addr.s_addr;
-
-	s.rsock = rpc_makesock(nfs_file);
-	s.flags = nfs_data.flags;
-	s.rsize = nfs_data.rsize;
-	s.wsize = nfs_data.wsize;
-	s.timeo = nfs_data.timeo * HZ / 10;
-	s.retrans = nfs_data.retrans;
-	strcpy(s.hostname, nfs_data.hostname);
-
-	/*
-	 * First connect the UDP socket to a server port, then send the
-	 * packet out, and finally check whether the answer is OK.
-	 */
-	if (nfs_sock_inode->u.socket_i.ops->connect &&
-	    nfs_sock_inode->u.socket_i.ops->connect(&nfs_sock_inode->u.socket_i,
-						(struct sockaddr *) &server,
-						sizeof(struct sockaddr_in),
-						nfs_file->f_flags) < 0)
-		return NULL;
-	if (nfs_rpc_call(&s, rpc_packet, end, nfs_data.wsize) < 0)
-		return NULL;
-	return rpc_verify(rpc_packet);
-}
-
-
-/*
- *  Create an RPC packet header
- */
-static int *root_nfs_header(int proc, int program, int version)
-{
-	int groups[] = { 0, NOGROUP };
-
-	if (rpc_packet == NULL) {
-		if (!(rpc_packet = kmalloc(nfs_data.wsize + 1024, GFP_NFS))) {
-			printk(KERN_ERR "Root-NFS: Cannot allocate UDP buffer\n");
-			return NULL;
-		}
-	}
-	return rpc_header(rpc_packet, proc, program, version, 0, 0, groups);
-}
-
-
 /*
  *  Query server portmapper for the port of a daemon program
  */
-static int root_nfs_get_port(int program, int version)
+static int root_nfs_getport(int program, int version)
 {
-	int *p;
-
-	/* Prepare header for portmap request */
-	server.sin_port = htons(NFS_PMAP_PORT);
-	p = root_nfs_header(NFS_PMAP_PROC, NFS_PMAP_PROGRAM, NFS_PMAP_VERSION);
-	if (!p)
-		return -1;
+	struct sockaddr_in	sin;
 
-	/* Set arguments for portmapper */
-	*p++ = htonl(program);
-	*p++ = htonl(version);
-	*p++ = htonl(IPPROTO_UDP);
-	*p++ = 0;
-
-	/* Send request to server portmapper */
-	if ((p = root_nfs_call(p)) == NULL)
-		return -1;
-
-	return ntohl(*p);
+printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n",
+	program, version, in_ntoa(servaddr));
+	set_sockaddr(&sin, servaddr, 0);
+	return rpc_getport_external(&sin, program, version, IPPROTO_UDP);
 }
 
 
 /*
  *  Get portnumbers for mountd and nfsd from server
+ *  The RPC layer does support portmapper queries; the only reason to
+ *  keep this code is that we may want to use fallback ports. But is there
+ *  actually someone who does not run portmap?
  */
 static int root_nfs_ports(void)
 {
-	int port;
+	int	port;
 
 	if (nfs_port < 0) {
-		if ((port = root_nfs_get_port(NFS_NFS_PROGRAM, NFS_NFS_VERSION)) < 0) {
-			printk(KERN_ERR "Root-NFS: Unable to get nfsd port number from server, using default\n");
-			port = NFS_NFS_PORT;
+		if ((port = root_nfs_getport(NFS_PROGRAM, NFS_VERSION)) < 0) {
+			printk(KERN_ERR "Root-NFS: Unable to get nfsd port "
+					"number from server, using default\n");
+			port = NFS_PORT;
 		}
 		nfs_port = port;
-#ifdef NFSROOT_DEBUG
-		printk(KERN_NOTICE "Root-NFS: Portmapper on server returned %d as nfsd port\n", port);
-#endif
+		dprintk("Root-NFS: Portmapper on server returned %d "
+			"as nfsd port\n", port);
 	}
-	if ((port = root_nfs_get_port(NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION)) < 0) {
-		printk(KERN_ERR "Root-NFS: Unable to get mountd port number from server, using default\n");
-		port = NFS_MOUNT_PORT;
+
+	if ((port = root_nfs_getport(NFS_MNT_PROGRAM, NFS_MNT_VERSION)) < 0) {
+		printk(KERN_ERR "Root-NFS: Unable to get mountd port "
+				"number from server, using default\n");
+		port = NFS_MNT_PORT;
 	}
-	server.sin_port = htons(port);
-#ifdef NFSROOT_DEBUG
-	printk(KERN_NOTICE "Root-NFS: Portmapper on server returned %d as mountd port\n", port);
-#endif
+
+	mount_port = htons(port);
+	dprintk("Root-NFS: Portmapper on server returned %d "
+		"as mountd port\n", port);
 
 	return 0;
 }
@@ -1631,40 +1496,16 @@
  */
 static int root_nfs_get_handle(void)
 {
-	int len, status, *p;
-
-	/* Prepare header for mountd request */
-	p = root_nfs_header(NFS_MOUNT_PROC, NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION);
-	if (!p) {
-		root_nfs_close();
-		return -1;
-	}
+	struct sockaddr_in sin;
+	int		status;
 
-	/* Set arguments for mountd */
-	len = strlen(nfs_path);
-	*p++ = htonl(len);
-	memcpy(p, nfs_path, len);
-	len = (len + 3) >> 2;
-	p[len] = 0;
-	p += len;
-
-	/* Send request to server mountd */
-	if ((p = root_nfs_call(p)) == NULL) {
-		root_nfs_close();
-		return -1;
-	}
-	status = ntohl(*p++);
-	if (status == 0) {
-		nfs_data.root = *((struct nfs_fh *) p);
-		printk(KERN_NOTICE "Root-NFS: Got file handle for %s via RPC\n", nfs_path);
-	} else {
-		printk(KERN_ERR "Root-NFS: Server returned error %d while mounting %s\n",
-			status, nfs_path);
-		root_nfs_close();
-		return -1;
-	}
+	set_sockaddr(&sin, servaddr, mount_port);
+	status = nfs_mount(&sin, nfs_path, &nfs_data.root);
+	if (status < 0)
+		printk(KERN_ERR "Root-NFS: Server returned error %d "
+				"while mounting %s\n", status, nfs_path);
 
-	return 0;
+	return status;
 }
 
 
@@ -1673,23 +1514,12 @@
  */
 static int root_nfs_do_mount(struct super_block *sb)
 {
-	/* First connect to the nfsd port on the server */
-	server.sin_port = htons(nfs_port);
-	nfs_data.addr = server;
-	if (nfs_sock_inode->u.socket_i.ops->connect &&
-	    nfs_sock_inode->u.socket_i.ops->connect(&nfs_sock_inode->u.socket_i,
-						(struct sockaddr *) &server,
-						sizeof(struct sockaddr_in),
-						nfs_file->f_flags) < 0) {
-		root_nfs_close();
-		return -1;
-	}
+	/* Pass the server address to NFS */
+	set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port);
 
 	/* Now (finally ;-)) read the super block for mounting */
-	if (nfs_read_super(sb, &nfs_data, 1) == NULL) {
-		root_nfs_close();
+	if (nfs_read_super(sb, &nfs_data, 1) == NULL)
 		return -1;
-	}
 	return 0;
 }
 
@@ -1700,16 +1530,11 @@
  */
 int nfs_root_mount(struct super_block *sb)
 {
-	if (root_nfs_open() < 0)
-		return -1;
-	if (root_nfs_bind() < 0)
-		return -1;
 	if (root_nfs_ports() < 0)
 		return -1;
 	if (root_nfs_get_handle() < 0)
 		return -1;
 	if (root_nfs_do_mount(sb) < 0)
 		return -1;
-	root_nfs_close();
 	return 0;
 }
diff -u --recursive --new-file v2.1.33/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.1.33/linux/fs/nfs/read.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfs/read.c	Mon Apr 14 09:31:09 1997
@@ -189,7 +189,7 @@
 
 	if (result >= 0) {
 		inode->i_count++;
-		page->count++;
+		atomic_inc(&page->count);
 		return 0;
 	}
 
@@ -219,7 +219,7 @@
 	dprintk("NFS: nfs_readpage %08lx\n", page_address(page));
 	set_bit(PG_locked, &page->flags);
 	address = page_address(page);
-	page->count++;
+	atomic_inc(&page->count);
 	if (!IS_SWAPFILE(inode) && !PageError(page)
 	 && NFS_SERVER(inode)->rsize >= PAGE_SIZE)
 		error = nfs_readpage_async(inode, page);
diff -u --recursive --new-file v2.1.33/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.1.33/linux/fs/nfs/write.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfs/write.c	Mon Apr 14 09:31:09 1997
@@ -339,7 +339,7 @@
 	wreq->wb_offset = offset;
 	wreq->wb_bytes  = bytes;
 	inode->i_count++;
-	page->count++;
+	atomic_inc(&page->count);
 
 	append_write_request(&NFS_WRITEBACK(inode), wreq);
 
@@ -399,7 +399,7 @@
 	struct page		*page = req->wb_page;
 
 	add_wait_queue(&page->wait, &wait);
-	page->count++;
+	atomic_inc(&page->count);
 repeat:
 	current->state = TASK_INTERRUPTIBLE;
 	if (PageLocked(page)) {
diff -u --recursive --new-file v2.1.33/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- v2.1.33/linux/fs/nfsd/nfssvc.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfsd/nfssvc.c	Mon Apr 14 09:31:09 1997
@@ -35,7 +35,8 @@
 
 #define NFSDDBG_FACILITY	NFSDDBG_SVC
 #define NFSD_BUFSIZE		(1024 + NFSSVC_MAXBLKSIZE)
-#define BLOCKABLE_SIGS		(~(_S(SIGKILL - 1) | _S(SIGSTOP - 1)))
+#define BLOCKABLE_SIGS		(~(_S(SIGKILL) | _S(SIGSTOP)))
+#define SHUTDOWN_SIGS		(_S(SIGKILL)|_S(SIGINT)|_S(SIGTERM))
 #define _S(sig)			(1 << ((sig) - 1))
 
 extern struct svc_program	nfsd_program;
@@ -107,6 +108,7 @@
 	sprintf(current->comm, "nfsd");
 
 	oldumask = current->fs->umask;		/* Set umask to 0.  */
+	current->blocked |= ~SHUTDOWN_SIGS;
 	current->fs->umask = 0;
 	nfssvc_boot = xtime;			/* record boot time */
 	lockd_up();				/* start lockd */
@@ -150,8 +152,16 @@
 		exp_unlock();
 	} while (err >= 0);
 
-	if (err != -EINTR)
+	if (err != -EINTR) {
 		printk(KERN_WARNING "nfsd: terminating on error %d\n", -err);
+	} else {
+		unsigned int	signo;
+
+		for (signo = 0; signo < 32; signo++)
+			if (current->signal & current->blocked & (1<<signo))
+				break;
+		printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
+	}
 
 	/* Release lockd */
 	lockd_down();
diff -u --recursive --new-file v2.1.33/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.33/linux/fs/nfsd/vfs.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfsd/vfs.c	Mon Apr 14 09:31:09 1997
@@ -29,7 +29,7 @@
 #include <linux/in.h>
 #include <linux/unistd.h>
 #include <linux/malloc.h>
-#include <netinet/in.h>
+#include <linux/in.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -837,7 +837,7 @@
 		return 0;
 
 	if ((err = nfsd_open(rqstp, fhp, S_IFDIR, OPEN_READ, &file)) != 0)
-		return nfserrno(-err);
+		return err;
 
 	if (!file.f_op->readdir) {
 		nfsd_close(&file);
diff -u --recursive --new-file v2.1.33/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.33/linux/fs/proc/array.c	Thu Mar 27 14:40:06 1997
+++ linux/fs/proc/array.c	Mon Apr 14 11:54:33 1997
@@ -123,7 +123,6 @@
 	&proc_kcore_operations, 
 };
 
-
 /*
  * This function accesses profiling information. The returned data is
  * binary: the sampling step and the actual contents of the profile
@@ -155,16 +154,38 @@
 	return read;
 }
 
-/* Writing to /proc/profile resets the counters */
+#ifdef __SMP__
+
+extern int setup_profiling_timer (unsigned int multiplier);
+
+/*
+ * Writing to /proc/profile resets the counters
+ *
+ * Writing a 'profiling multiplier' value into it also re-sets the profiling
+ * interrupt frequency, on architectures that support this.
+ */
 static long write_profile(struct inode * inode, struct file * file,
 	const char * buf, unsigned long count)
 {
-    int i=prof_len;
+	int i=prof_len;
 
-    while (i--)
-	    prof_buffer[i]=0UL;
-    return count;
+	if (count==sizeof(int)) {
+		unsigned int multiplier;
+
+		if (copy_from_user(&multiplier, buf, sizeof(int)))
+			return -EFAULT;
+
+		if (setup_profiling_timer(multiplier))
+			return -EINVAL;
+	}
+  
+	while (i--)
+		prof_buffer[i]=0UL;
+	return count;
 }
+#else
+#define write_profile NULL
+#endif
 
 static struct file_operations proc_profile_operations = {
 	NULL,           /* lseek */
@@ -801,7 +822,7 @@
 			++*dirty;
 		if (MAP_NR(pte_page(page)) >= max_mapnr)
 			continue;
-		if (mem_map[MAP_NR(pte_page(page))].count > 1)
+		if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1)
 			++*shared;
 	} while (address < end);
 }
diff -u --recursive --new-file v2.1.33/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v2.1.33/linux/fs/proc/mem.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/proc/mem.c	Mon Apr 14 09:31:09 1997
@@ -298,7 +298,7 @@
 
 		set_pte(src_table, pte_mkdirty(*src_table));
 		set_pte(dest_table, *src_table);
-		mem_map[MAP_NR(pte_page(*src_table))].count++;
+		atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count);
 
 		stmp += PAGE_SIZE;
 		dtmp += PAGE_SIZE;
diff -u --recursive --new-file v2.1.33/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.33/linux/fs/proc/openpromfs.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/proc/openpromfs.c	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.12 1997/01/26 07:14:18 davem Exp $
+/* $Id: openpromfs.c,v 1.13 1997/04/03 08:49:25 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.1.33/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.1.33/linux/fs/romfs/inode.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/romfs/inode.c	Mon Apr 14 09:31:09 1997
@@ -373,7 +373,7 @@
 	int result = -EIO;
 
 	buf = page_address(page);
-	page->count++;
+	atomic_inc(&page->count);
 	offset = page->offset;
 	if (offset < inode->i_size) {
 		avail = inode->i_size-offset;
diff -u --recursive --new-file v2.1.33/linux/fs/super.c linux/fs/super.c
--- v2.1.33/linux/fs/super.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/super.c	Mon Apr 14 09:31:09 1997
@@ -99,7 +99,7 @@
 	memset(lptr, 0, sizeof(struct vfsmount));
 
 	lptr->mnt_dev = dev;
-	lptr->mnt_sem.count = 1;
+	sema_init(&lptr->mnt_sem, 1);
 	if (dev_name && !getname(dev_name, &tmp)) {
 		if ((lptr->mnt_devname =
 		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h
--- v2.1.33/linux/include/asm-alpha/atomic.h	Fri Apr  4 08:52:24 1997
+++ linux/include/asm-alpha/atomic.h	Mon Apr 14 09:31:09 1997
@@ -9,7 +9,16 @@
  * than regular operations.
  */
 
-typedef int atomic_t;
+#ifdef __SMP__
+typedef struct { volatile int counter; } atomic_t;
+#else
+typedef struct { int counter; } atomic_t;
+#endif
+
+#define ATOMIC_INIT	{ 0 }
+
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v)		(((v)->counter) = i)
 
 /*
  * Make sure gcc doesn't try to be clever and move things around
@@ -24,7 +33,7 @@
  * branch back to restart the operation.
  */
 
-extern __inline__ void atomic_add(atomic_t i, atomic_t * v)
+extern __inline__ void atomic_add(int i, atomic_t * v)
 {
 	unsigned long temp;
 	__asm__ __volatile__(
@@ -39,7 +48,7 @@
 	:"Ir" (i), "m" (__atomic_fool_gcc(v)));
 }
 
-extern __inline__ void atomic_sub(atomic_t i, atomic_t * v)
+extern __inline__ void atomic_sub(int i, atomic_t * v)
 {
 	unsigned long temp;
 	__asm__ __volatile__(
@@ -57,7 +66,7 @@
 /*
  * Same as above, but return the result value
  */
-extern __inline__ long atomic_add_return(atomic_t i, atomic_t * v)
+extern __inline__ long atomic_add_return(int i, atomic_t * v)
 {
 	long temp, result;
 	__asm__ __volatile__(
@@ -74,7 +83,7 @@
 	return result;
 }
 
-extern __inline__ long atomic_sub_return(atomic_t i, atomic_t * v)
+extern __inline__ long atomic_sub_return(int i, atomic_t * v)
 {
 	long temp, result;
 	__asm__ __volatile__(
diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/checksum.h linux/include/asm-alpha/checksum.h
--- v2.1.33/linux/include/asm-alpha/checksum.h	Tue Mar  4 10:25:26 1997
+++ linux/include/asm-alpha/checksum.h	Fri Apr 11 10:37:41 1997
@@ -53,7 +53,7 @@
  * this is a new version of the above that records errors it finds in *errp,
  * but continues and zeros the rest of the buffer.
  */
-unsigned int csum_partial_copy_from_user(char *src, char *dst, int len, unsigned int sum, int *errp);
+unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errp);
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.1.33/linux/include/asm-alpha/hardirq.h	Fri Apr  4 08:52:24 1997
+++ linux/include/asm-alpha/hardirq.h	Mon Apr 14 14:10:37 1997
@@ -1,20 +1,24 @@
 #ifndef _ALPHA_HARDIRQ_H
 #define _ALPHA_HARDIRQ_H
 
+#include <linux/tasks.h>
+
 extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt()  (local_irq_count[smp_processor_id()] != 0)
+#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	((cpu) == 0)
+#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
 
 #define hardirq_enter(cpu)	(local_irq_count[cpu]++)
 #define hardirq_exit(cpu)	(local_irq_count[cpu]--)
 
+#define synchronize_irq()	do { } while (0)
+
 #else
 
-#error FIXME
+#error No habla alpha SMP
 
 #endif /* __SMP__ */
 #endif /* _ALPHA_HARDIRQ_H */
diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.1.33/linux/include/asm-alpha/io.h	Sun Oct  6 22:55:48 1996
+++ linux/include/asm-alpha/io.h	Thu Apr 10 14:03:51 1997
@@ -38,7 +38,8 @@
  */
 extern inline void set_hae(unsigned long new_hae)
 {
-	unsigned long ipl = swpipl(7);
+	unsigned long ipl;
+	swpipl(ipl,7);
 	hae.cache = new_hae;
 	*hae.reg = new_hae;
 	mb();
diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.1.33/linux/include/asm-alpha/semaphore.h	Wed Jan 15 18:47:21 1997
+++ linux/include/asm-alpha/semaphore.h	Mon Apr 14 09:31:09 1997
@@ -15,12 +15,29 @@
 	struct wait_queue * wait;
 };
 
-#define MUTEX ((struct semaphore) { 1, 0, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+#define MUTEX ((struct semaphore) { { 1 }, { 0 }, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL })
 
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
+
+#define sema_init(sem, val)	atomic_set(&((sem)->count), val)
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	save_flags(flags);
+	cli();
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	}
+	restore_flags(flags);
+	return ret;
+}
 
 /*
  * This isn't quite as clever as the x86 side, but the gp register
diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h
--- v2.1.33/linux/include/asm-alpha/softirq.h	Fri Apr  4 08:52:24 1997
+++ linux/include/asm-alpha/softirq.h	Mon Apr 14 09:31:09 1997
@@ -1,9 +1,12 @@
 #ifndef _ALPHA_SOFTIRQ_H
 #define _ALPHA_SOFTIRQ_H
 
-/*
- * Software interrupts..
+/* The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
  */
+extern atomic_t __alpha_bh_counter;
+
 #define get_active_bhs()	(bh_mask & bh_active)
 
 static inline void clear_active_bhs(unsigned long x)
@@ -21,11 +24,60 @@
 	:"Ir" (x), "m" (bh_active));
 }
 
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	bh_base[nr] = routine;
+	bh_mask_count[nr] = 0;
+	bh_mask |= 1 << nr;
+}
+
+extern inline void mark_bh(int nr)
+{
+	set_bit(nr, &bh_active);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+	bh_mask &= ~(1 << nr);
+	bh_mask_count[nr]++;
+}
+
+extern inline void enable_bh(int nr)
+{
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
+}
+
+/*
+ * start_bh_atomic/end_bh_atomic also nest
+ * naturally by using a counter
+ */
+extern inline void start_bh_atomic(void)
+{
+#ifdef __SMP__
+	atomic_inc(&__alpha_bh_counter);
+	synchronize_irq();
+#else
+	atomic_inc(&__alpha_bh_counter);
+#endif
+}
+
+extern inline void end_bh_atomic(void)
+{
+	atomic_dec(&__alpha_bh_counter);
+}
+
 #ifndef __SMP__
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock()	(intr_count ? 0 : ((intr_count=1),1))
-#define softirq_endlock()	(intr_count = 0)
+#define softirq_trylock()	(atomic_read(&__alpha_bh_counter) ? \
+				0 : \
+				((atomic_set(&__alpha_bh_counter,1)),1))
+#define softirq_endlock()	(atomic_set(&__alpha_bh_counter, 0))
 
 #else
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h
--- v2.1.33/linux/include/asm-alpha/uaccess.h	Sun Jan 26 02:07:46 1997
+++ linux/include/asm-alpha/uaccess.h	Fri Apr 11 10:37:44 1997
@@ -352,10 +352,27 @@
  * Complex access routines
  */
 
+#define __copy_to_user(to,from,n)   __copy_tofrom_user_nocheck((to),(from),(n))
+#define __copy_from_user(to,from,n) __copy_tofrom_user_nocheck((to),(from),(n))
+
 #define copy_to_user(to,from,n)   __copy_tofrom_user((to),(from),(n),__cu_to)
 #define copy_from_user(to,from,n) __copy_tofrom_user((to),(from),(n),__cu_from)
 
 extern void __copy_user(void);
+
+#define __copy_tofrom_user_nocheck(to,from,n)				\
+({									\
+	register void * __cu_to __asm__("$6") = (to);			\
+	register const void * __cu_from __asm__("$7") = (from);		\
+	register long __cu_len __asm__("$0") = (n);			\
+	__asm__ __volatile__(						\
+		"jsr $28,(%3),__copy_user"				\
+		: "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)	\
+		: "r" (__copy_user), "0" (__cu_len),			\
+		  "1" (__cu_from), "2" (__cu_to)			\
+		: "$1","$2","$3","$4","$5","$28","memory");		\
+	__cu_len;							\
+})
 
 #define __copy_tofrom_user(to,from,n,v)					    \
 ({									    \
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h
--- v2.1.33/linux/include/asm-i386/atomic.h	Thu Mar 27 14:40:06 1997
+++ linux/include/asm-i386/atomic.h	Mon Apr 14 11:20:54 1997
@@ -19,9 +19,18 @@
  */
 #define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
 
-typedef int atomic_t;
+#ifdef __SMP__
+typedef struct { volatile int counter; } atomic_t;
+#else
+typedef struct { int counter; } atomic_t;
+#endif
 
-static __inline__ void atomic_add(atomic_t i, volatile atomic_t *v)
+#define ATOMIC_INIT	{ 0 }
+
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v,i)		(((v)->counter) = (i))
+
+static __inline__ void atomic_add(int i, volatile atomic_t *v)
 {
 	__asm__ __volatile__(
 		LOCK "addl %1,%0"
@@ -29,7 +38,7 @@
 		:"ir" (i), "m" (__atomic_fool_gcc(v)));
 }
 
-static __inline__ void atomic_sub(atomic_t i, volatile atomic_t *v)
+static __inline__ void atomic_sub(int i, volatile atomic_t *v)
 {
 	__asm__ __volatile__(
 		LOCK "subl %1,%0"
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/errno.h linux/include/asm-i386/errno.h
--- v2.1.33/linux/include/asm-i386/errno.h	Wed Jul  3 21:28:57 1996
+++ linux/include/asm-i386/errno.h	Mon Apr 14 09:34:53 1997
@@ -126,4 +126,7 @@
 #define	EREMOTEIO	121	/* Remote I/O error */
 #define	EDQUOT		122	/* Quota exceeded */
 
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+
 #endif
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h
--- v2.1.33/linux/include/asm-i386/hardirq.h	Mon Apr  7 11:35:31 1997
+++ linux/include/asm-i386/hardirq.h	Mon Apr 14 14:08:53 1997
@@ -1,12 +1,14 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
+#include <linux/tasks.h>
+
 extern unsigned int local_irq_count[NR_CPUS];
 #define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	((cpu)==0)	/* always true */
+#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
 
 #define hardirq_enter(cpu)	(local_irq_count[cpu]++)
@@ -16,9 +18,11 @@
 
 #else
 
+#include <asm/atomic.h>
+
 extern unsigned char global_irq_holder;
 extern unsigned volatile int global_irq_lock;
-extern unsigned volatile int global_irq_count;
+extern atomic_t global_irq_count;
 
 static inline void release_irqlock(int cpu)
 {
@@ -48,7 +52,7 @@
 	__save_flags(flags);
 	__cli();
 	atomic_inc(&global_irq_count);
-	if (global_irq_count != 1 || test_bit(0,&global_irq_lock)) {
+	if (atomic_read(&global_irq_count) != 1 || test_bit(0,&global_irq_lock)) {
 		atomic_dec(&global_irq_count);
 		__restore_flags(flags);
 		return 0;
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/io.h linux/include/asm-i386/io.h
--- v2.1.33/linux/include/asm-i386/io.h	Fri Apr  4 08:52:25 1997
+++ linux/include/asm-i386/io.h	Mon Apr 14 11:42:11 1997
@@ -1,8 +1,6 @@
 #ifndef _ASM_IO_H
 #define _ASM_IO_H
 
-#include <linux/vmalloc.h>
-
 /*
  * This file contains the definitions for the x86 IO instructions
  * inb/inw/inl/outb/outw/outl and the "string versions" of the same
@@ -168,6 +166,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/vmalloc.h>
 #include <asm/page.h>
 
 #define __io_virt(x)		((void *)(PAGE_OFFSET | (unsigned long)(x)))
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v2.1.33/linux/include/asm-i386/irq.h	Sun Apr 13 10:18:22 1997
+++ linux/include/asm-i386/irq.h	Sun Apr 13 20:41:16 1997
@@ -72,6 +72,24 @@
 	"iret"
 
 /*
+ * Some fast irq handlers might want to access saved registers (mostly
+ * cs or flags)
+ */
+
+struct fast_irq_regs {
+	long ecx;
+	long edx;
+	long eax;
+	int  xds;
+	int  xes;
+	long eip;
+	int  xcs;
+	long eflags;
+	long esp;
+	int  xss;
+};
+
+/*
  * The "inb" instructions are not needed, but seem to change the timings
  * a bit - without them it seems that the harddisk driver won't work on
  * all hardware. Arghh.
@@ -161,12 +179,13 @@
 __asm__( \
 "\n"__ALIGN_STR"\n" \
 SYMBOL_NAME_STR(x) ":\n\t" \
-	SAVE_MOST \
-	"movl %esp,%eax\n\t" \
-	"pushl %eax\n\t" \
+	"pushl $-1\n\t" \
+        SAVE_ALL \
+        "movl %esp,%eax\n\t" \
+        "pushl %eax\n\t" \
 	"call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
-	"addl $4,%esp\n\t" \
-	RESTORE_MOST);
+        "addl $4,%esp\n\t" \
+	"jmp ret_from_intr\n");
 
 #endif /* __SMP__ */
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.1.33/linux/include/asm-i386/semaphore.h	Wed Jan 15 18:47:21 1997
+++ linux/include/asm-i386/semaphore.h	Mon Apr 14 11:20:59 1997
@@ -19,14 +19,17 @@
  *
  */
 
+#include <asm/system.h>
+#include <asm/atomic.h>
+
 struct semaphore {
-	int count;
+	atomic_t count;
 	int waking;
 	struct wait_queue * wait;
 };
 
-#define MUTEX ((struct semaphore) { 1, 0, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+#define MUTEX ((struct semaphore) { { 1 }, 0, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { { 0 }, 0, NULL })
 
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
@@ -34,6 +37,44 @@
 
 extern void __down(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
+
+#define sema_init(sem, val)	atomic_set(&((sem)->count), (val))
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ *
+ * This is trivially done with load_locked/store_cond,
+ * but on the x86 we need an external synchronizer.
+ * Currently this is just the global interrupt lock,
+ * bah. Go for a smaller spinlock some day.
+ *
+ * (On the other hand this shouldn't be in any critical
+ * path, so..)
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	sem->waking++;
+	restore_flags(flags);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	save_flags(flags);
+	cli();
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	}
+	restore_flags(flags);
+	return ret;
+}
 
 /*
  * This is ugly, but we want the default case to fall through.
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/softirq.h linux/include/asm-i386/softirq.h
--- v2.1.33/linux/include/asm-i386/softirq.h	Thu Mar 27 14:40:06 1997
+++ linux/include/asm-i386/softirq.h	Mon Apr 14 11:42:12 1997
@@ -1,34 +1,93 @@
 #ifndef __ASM_SOFTIRQ_H
 #define __ASM_SOFTIRQ_H
 
-/*
- * Software interrupts..
- */
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
 #define get_active_bhs()	(bh_mask & bh_active)
 #define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
 
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	bh_base[nr] = routine;
+	bh_mask_count[nr] = 0;
+	bh_mask |= 1 << nr;
+}
+
+extern inline void mark_bh(int nr)
+{
+	set_bit(nr, &bh_active);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+	bh_mask &= ~(1 << nr);
+	bh_mask_count[nr]++;
+}
+
+extern inline void enable_bh(int nr)
+{
+	if (!--bh_mask_count[nr])
+		bh_mask |= 1 << nr;
+}
+
 #ifdef __SMP__
 
+/*
+ * The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+extern atomic_t __intel_bh_counter;
+
+extern inline void start_bh_atomic(void)
+{
+	atomic_inc(&__intel_bh_counter);
+	synchronize_irq();
+}
+
+extern inline void end_bh_atomic(void)
+{
+	atomic_dec(&__intel_bh_counter);
+}
+
 /* These are for the irq's testing the lock */
 static inline int softirq_trylock(void)
 {
-	atomic_inc(&intr_count);
-	if (intr_count != 1) {
-		atomic_dec(&intr_count);
+	atomic_inc(&__intel_bh_counter);
+	if (atomic_read(&__intel_bh_counter) != 1) {
+		atomic_dec(&__intel_bh_counter);
 		return 0;
 	}
 	return 1;
 }
 
-#define softirq_endlock()	atomic_dec(&intr_count)
+#define softirq_endlock()	atomic_dec(&__intel_bh_counter)
 
 #else
 
-/* These are for the irq's testing the lock */
-#define softirq_trylock()	(intr_count ? 0 : ((intr_count=1),1))
-#define softirq_endlock()	(intr_count = 0)
+extern int __intel_bh_counter;
+
+extern inline void start_bh_atomic(void)
+{
+	__intel_bh_counter++;
+	barrier();
+}
 
+extern inline void end_bh_atomic(void)
+{
+	barrier();
+	__intel_bh_counter--;
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock()	(__intel_bh_counter ? 0 : (__intel_bh_counter=1))
+#define softirq_endlock()	(__intel_bh_counter = 0)
 
-#endif
+#endif	/* SMP */
 
-#endif
+#endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.1.33/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.33/linux/include/asm-i386/system.h	Mon Apr  7 11:35:31 1997
+++ linux/include/asm-i386/system.h	Sun Apr 13 10:01:22 1997
@@ -73,7 +73,6 @@
 		__asm__ __volatile__("fwait"); \
 		prev->flags&=~PF_USEDFPU;	 \
 	} \
-	prev->processor = NO_PROC_ID; \
 	current_set[this_cpu] = next; \
 __asm__("ljmp %0\n\t" \
 	: /* no output */ \
diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/atomic.h linux/include/asm-m68k/atomic.h
--- v2.1.33/linux/include/asm-m68k/atomic.h	Mon May  6 02:44:32 1996
+++ linux/include/asm-m68k/atomic.h	Mon Apr 14 09:31:09 1997
@@ -10,14 +10,18 @@
  * We do not have SMP m68k systems, so we don't have to deal with that.
  */
 
-typedef int atomic_t;
+typedef struct { int counter; } atomic_t;
+#define ATOMIC_INIT	{ 0 }
 
-static __inline__ void atomic_add(atomic_t i, atomic_t *v)
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v)		(((v)->counter) = i)
+
+static __inline__ void atomic_add(int i, atomic_t *v)
 {
 	__asm__ __volatile__("addl %1,%0" : : "m" (*v), "id" (i));
 }
 
-static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
+static __inline__ void atomic_sub(int i, atomic_t *v)
 {
 	__asm__ __volatile__("subl %1,%0" : : "m" (*v), "id" (i));
 }
diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/errno.h linux/include/asm-m68k/errno.h
--- v2.1.33/linux/include/asm-m68k/errno.h	Wed Sep 25 00:47:41 1996
+++ linux/include/asm-m68k/errno.h	Mon Apr 14 09:34:53 1997
@@ -126,4 +126,7 @@
 #define	EREMOTEIO	121	/* Remote I/O error */
 #define	EDQUOT		122	/* Quota exceeded */
 
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+
 #endif /* _M68K_ERRNO_H */
diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.1.33/linux/include/asm-m68k/ide.h	Thu Mar 27 14:40:07 1997
+++ linux/include/asm-m68k/ide.h	Mon Apr 14 09:31:09 1997
@@ -479,7 +479,7 @@
 #ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		if (*ide_lock == 0) {
-			if (intr_count > 0)
+			if (in_interrupt() > 0)
 				panic( "Falcon IDE hasn't ST-DMA lock in interrupt" );
 			stdma_lock(handler, data);
 			*ide_lock = 1;
@@ -506,12 +506,12 @@
 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA)
 #define	ide_sti()					\
     do {						\
-	if (!intr_count) sti();				\
+	if (!in_interrupt()) sti();			\
     } while(0)
 #elif defined(CONFIG_ATARI)
-#define	ide_sti()					\
-    do {						\
-	if (!MACH_IS_ATARI || !intr_count) sti();	\
+#define	ide_sti()						\
+    do {							\
+	if (!MACH_IS_ATARI || !in_interrupt()) sti();		\
     } while(0)
 #else /* !defined(CONFIG_ATARI) */
 #define	ide_sti()	sti()
diff -u --recursive --new-file v2.1.33/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.1.33/linux/include/asm-m68k/semaphore.h	Fri Nov 22 05:56:36 1996
+++ linux/include/asm-m68k/semaphore.h	Mon Apr 14 09:31:09 1997
@@ -26,6 +26,23 @@
 extern void __down(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
+#define sema_init(sem, val)	((sem)->count = val)
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	save_flags(flags);
+	cli();
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	}
+	restore_flags(flags);
+	return ret;
+}
+
 /*
  * This is ugly, but we want the default case to fall through.
  * "down_failed" is a special asm handler that calls the C
diff -u --recursive --new-file v2.1.33/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.1.33/linux/include/asm-mips/processor.h	Sun Jan 26 02:07:46 1997
+++ linux/include/asm-mips/processor.h	Mon Apr 14 09:31:09 1997
@@ -19,7 +19,7 @@
  */
 extern char wait_available;		/* only available on R4[26]00 */
 
-extern unsigned long intr_count;
+extern atomic_t intr_count;
 extern unsigned long event;
 
 /*
diff -u --recursive --new-file v2.1.33/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h
--- v2.1.33/linux/include/asm-ppc/atomic.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/atomic.h	Mon Apr 14 09:31:09 1997
@@ -5,13 +5,18 @@
 #ifndef _ASM_PPC_ATOMIC_H_ 
 #define _ASM_PPC_ATOMIC_H_
 
-typedef int atomic_t;
+typedef struct { int counter; } atomic_t;
+#define ATOMIC_INIT	{ 0 }
+
 /*
  * Make sure gcc doesn't try to be clever and move things around
  * on us. We need to use _exactly_ the address the user gave us,
  * not some alias that contains the same information.
  */
 #define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v)		(((v)->counter) = i)
 
 #define atomic_dec_return(v) ({atomic_sub(1,(v));(v);})
 #define atomic_inc_return(v) ({atomic_add(1,(v));(v);})
diff -u --recursive --new-file v2.1.33/linux/include/asm-ppc/errno.h linux/include/asm-ppc/errno.h
--- v2.1.33/linux/include/asm-ppc/errno.h	Mon May 27 02:00:59 1996
+++ linux/include/asm-ppc/errno.h	Mon Apr 14 09:34:53 1997
@@ -124,6 +124,9 @@
 #define	EREMOTEIO	121	/* Remote I/O error */
 #define	EDQUOT		122	/* Quota exceeded */
 
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+
 /* Should never be seen by user programs */
 #define ERESTARTSYS	512
 #define ERESTARTNOINTR	513
diff -u --recursive --new-file v2.1.33/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.1.33/linux/include/asm-ppc/semaphore.h	Wed Dec 18 00:54:10 1996
+++ linux/include/asm-ppc/semaphore.h	Mon Apr 14 09:31:09 1997
@@ -18,6 +18,23 @@
 extern void atomic_add(int c, int *v);
 extern void atomic_sub(int c, int *v);
 
+#define sema_init(sem, val)	atomic_set(&((sem)->count), val)
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	save_flags(flags);
+	cli();
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	}
+	restore_flags(flags);
+	return ret;
+}
+
 extern inline void down(struct semaphore * sem)
 {
   for (;;)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h
--- v2.1.33/linux/include/asm-sparc/atomic.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/atomic.h	Mon Apr 14 09:31:09 1997
@@ -6,7 +6,14 @@
 #ifndef __ARCH_SPARC_ATOMIC__
 #define __ARCH_SPARC_ATOMIC__
 
-typedef int atomic_t;
+#ifdef __SMP__
+/* This is a temporary measure. -DaveM */
+typedef struct { volatile int counter; } atomic_t;
+#else
+typedef struct { int counter; } atomic_t;
+#endif
+
+#define ATOMIC_INIT	{ 0 }
 
 #ifdef __KERNEL__
 #include <asm/system.h>
@@ -15,19 +22,38 @@
 /* We do the bulk of the actual work out of line in two common
  * routines in assembler, see arch/sparc/lib/atomic.S for the
  * "fun" details.
+ *
+ * For SMP the trick is you embed the spin lock byte within
+ * the word, use the low byte so signedness is easily retained
+ * via a quick arithmetic shift.  It looks like this:
+ *
+ *	----------------------------------------
+ *	| signed 24-bit counter value |  lock  |  atomic_t
+ *	----------------------------------------
+ *	 31                          8 7      0
  */
 
+static __inline__ int atomic_read(atomic_t *v)
+{
+	int val;
+
+	__asm__ __volatile__("sra	%1, 0x8, %0"
+			     : "=r" (val)
+			     : "r" (v->counter));
+	return val;
+}
+#define atomic_set(v, i)	(((v)->counter) = ((i) << 8))
+
 /* Make sure gcc doesn't try to be clever and move things around
  * on us. We need to use _exactly_ the address the user gave us,
  * not some alias that contains the same information.
  */
 #define __atomic_fool_gcc(x) ((struct { int a[100]; } *)x)
 
-static __inline__ void atomic_add(atomic_t i, atomic_t *v)
+static __inline__ void atomic_add(int i, atomic_t *v)
 {
 	register atomic_t *ptr asm("g1");
-	register atomic_t increment asm("g2");
-
+	register int increment asm("g2");
 	ptr = (atomic_t *) __atomic_fool_gcc(v);
 	increment = i;
 
@@ -37,13 +63,13 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (increment)
 	: "0" (increment), "r" (ptr)
-	: "g3", "g4", "g7", "memory");
+	: "g3", "g4", "g7", "memory", "cc");
 }
 
-static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
+static __inline__ void atomic_sub(int i, atomic_t *v)
 {
 	register atomic_t *ptr asm("g1");
-	register atomic_t increment asm("g2");
+	register int increment asm("g2");
 
 	ptr = (atomic_t *) __atomic_fool_gcc(v);
 	increment = i;
@@ -54,13 +80,13 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (increment)
 	: "0" (increment), "r" (ptr)
-	: "g3", "g4", "g7", "memory");
+	: "g3", "g4", "g7", "memory", "cc");
 }
 
-static __inline__ int atomic_add_return(atomic_t i, atomic_t *v)
+static __inline__ int atomic_add_return(int i, atomic_t *v)
 {
 	register atomic_t *ptr asm("g1");
-	register atomic_t increment asm("g2");
+	register int increment asm("g2");
 
 	ptr = (atomic_t *) __atomic_fool_gcc(v);
 	increment = i;
@@ -71,15 +97,15 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (increment)
 	: "0" (increment), "r" (ptr)
-	: "g3", "g4", "g7", "memory");
+	: "g3", "g4", "g7", "memory", "cc");
 
 	return increment;
 }
 
-static __inline__ int atomic_sub_return(atomic_t i, atomic_t *v)
+static __inline__ int atomic_sub_return(int i, atomic_t *v)
 {
 	register atomic_t *ptr asm("g1");
-	register atomic_t increment asm("g2");
+	register int increment asm("g2");
 
 	ptr = (atomic_t *) __atomic_fool_gcc(v);
 	increment = i;
@@ -90,7 +116,7 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (increment)
 	: "0" (increment), "r" (ptr)
-	: "g3", "g4", "g7", "memory");
+	: "g3", "g4", "g7", "memory", "cc");
 
 	return increment;
 }
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v2.1.33/linux/include/asm-sparc/bitops.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/bitops.h	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.43 1997/01/25 04:42:51 davem Exp $
+/* $Id: bitops.h,v 1.46 1997/04/13 06:38:24 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -99,7 +99,6 @@
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
-
 	ADDR = ((unsigned long *) addr) + (nr >> 5);
 	mask = 1 << (nr & 31);
 	__asm__ __volatile__("
@@ -108,7 +107,7 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7");
+	: "g3", "g4", "g5", "g7", "cc");
 
 	return mask;
 }
@@ -126,7 +125,7 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7");
+	: "g3", "g4", "g5", "g7", "cc");
 
 	return mask;
 }
@@ -144,7 +143,7 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7");
+	: "g3", "g4", "g5", "g7", "cc");
 
 	return mask;
 }
@@ -276,7 +275,7 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7");
+	: "g3", "g4", "g5", "g7", "cc");
 
 	return mask;
 }
@@ -294,7 +293,7 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7");
+	: "g3", "g4", "g5", "g7", "cc");
 
 	return mask;
 }
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/checksum.h linux/include/asm-sparc/checksum.h
--- v2.1.33/linux/include/asm-sparc/checksum.h	Thu Mar 27 14:40:07 1997
+++ linux/include/asm-sparc/checksum.h	Fri Apr 11 10:47:38 1997
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.26 1997/03/14 07:54:47 davem Exp $ */
+/* $Id: checksum.h,v 1.27 1997/04/11 00:42:18 davem Exp $ */
 #ifndef __SPARC_CHECKSUM_H
 #define __SPARC_CHECKSUM_H
 
@@ -154,7 +154,7 @@
 			     "xnor\t%%g0, %0, %0"
 			     : "=r" (sum), "=&r" (iph)
 			     : "r" (ihl), "1" (iph)
-			     : "g2", "g3", "g4");
+			     : "g2", "g3", "g4", "cc");
 	return sum;
 }
 
@@ -178,7 +178,8 @@
 			     "xnor\t%%g0, %0, %0"
 			     : "=r" (sum), "=r" (saddr)
 			     : "r" (daddr), "r" ((proto<<16)+len), "0" (sum),
-			     "1" (saddr));
+			       "1" (saddr)
+			     : "cc");
 	return sum;
 }
 
@@ -192,7 +193,8 @@
 			     "addx\t%1, %%g0, %1\n\t"
 			     "xnor\t%%g0, %1, %0"
 			     : "=&r" (sum), "=r" (tmp)
-			     : "0" (sum), "1" (sum<<16));
+			     : "0" (sum), "1" (sum<<16)
+			     : "cc");
 	return sum;
 }
 
@@ -228,7 +230,7 @@
 		: "=&r" (sum)
 		: "r" (saddr), "r" (daddr), 
 		  "r"(htonl((__u32) (len))), "r"(htonl(proto)), "r"(sum)
-		: "g2", "g3", "g4");
+		: "g2", "g3", "g4", "cc");
 
 	return csum_fold(sum);
 }
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/delay.h linux/include/asm-sparc/delay.h
--- v2.1.33/linux/include/asm-sparc/delay.h	Sat Nov  9 00:29:18 1996
+++ linux/include/asm-sparc/delay.h	Fri Apr 11 10:47:38 1997
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.8 1996/01/28 02:09:21 davem Exp $
+/* $Id: delay.h,v 1.9 1997/04/11 00:42:19 davem Exp $
  * delay.h: Linux delay routines on the Sparc.
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu).
@@ -15,7 +15,8 @@
 			     "1: bne 1b\n\t"
 			     "subcc %0, 1, %0\n" :
 			     "=&r" (loops) :
-			     "0" (loops));
+			     "0" (loops) :
+			     "cc");
 }
 
 /* This is too messy with inline asm on the Sparc. */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h
--- v2.1.33/linux/include/asm-sparc/dma.h	Thu Mar 27 14:40:07 1997
+++ linux/include/asm-sparc/dma.h	Fri Apr 11 10:47:38 1997
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.23 1997/03/14 21:05:20 jj Exp $
+/* $Id: dma.h,v 1.24 1997/04/10 05:13:21 davem Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
 #define _ASM_SPARC_DMA_H
 
 #include <linux/kernel.h>
+#include <linux/types.h>
 
 #include <asm/vac-ops.h>  /* for invalidate's, etc. */
 #include <asm/sbus.h>
@@ -28,10 +29,10 @@
 
 /* Structure to describe the current status of DMA registers on the Sparc */
 struct sparc_dma_registers {
-  __volatile__ unsigned long cond_reg;   /* DMA condition register */
-  __volatile__ char * st_addr;           /* Start address of this transfer */
-  __volatile__ unsigned long cnt;        /* How many bytes to transfer */
-  __volatile__ unsigned long dma_test;   /* DMA test register */
+  __volatile__ __u32 cond_reg;	/* DMA condition register */
+  __volatile__ __u32 st_addr;	/* Start address of this transfer */
+  __volatile__ __u32 cnt;	/* How many bytes to transfer */
+  __volatile__ __u32 dma_test;	/* DMA test register */
 };
 
 /* DVMA chip revisions */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h
--- v2.1.33/linux/include/asm-sparc/hardirq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc/hardirq.h	Mon Apr 14 09:31:09 1997
@@ -0,0 +1,72 @@
+/* hardirq.h: 32-bit Sparc hard IRQ support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_HARDIRQ_H
+#define __SPARC_HARDIRQ_H
+
+#include <linux/tasks.h>
+
+extern unsigned int local_irq_count[NR_CPUS];
+#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
+#define hardirq_depth()	(local_irq_count[smp_processor_id()])
+
+#ifndef __SMP__
+
+#define hardirq_trylock(cpu)	(++local_irq_count[cpu], (cpu)==0)
+#define hardirq_endlock(cpu)	(--local_irq_count[cpu])
+
+#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
+#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
+
+#define synchronize_irq()	do { } while(0)
+
+#else /* __SMP__ */
+
+#include <asm/atomic.h>
+#include <asm/spinlock.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+
+extern unsigned char global_irq_holder;
+extern spinlock_t global_irq_lock;
+extern atomic_t global_irq_count;
+
+#define release_irqlock(cpu)				\
+do {	if(global_irq_holder == (unsigned char) cpu) {	\
+		global_irq_holder = NO_PROC_ID;		\
+		spin_unlock(&global_irq_lock);		\
+	}						\
+} while(0)
+
+/* Ordering of the counter bumps is _deadly_ important. */
+#define hardirq_enter(cpu) \
+	do { ++local_irq_count[cpu]; atomic_inc(&global_irq_count); } while(0)
+
+#define hardirq_exit(cpu) \
+	do { atomic_dec(&global_irq_count); --local_irq_count[cpu]; } while(0)
+
+#define hardirq_trylock(cpu)					\
+({	unsigned long flags; int ret = 1;			\
+	__save_flags(flags);					\
+	__cli();						\
+	if(atomic_add_return(1, &global_irq_count) != 1 ||	\
+	   global_irq_lock) {					\
+		atomic_dec(&global_irq_count);			\
+		__restore_flags(flags);				\
+		ret = 0;					\
+	} else {						\
+		++local_irq_count[cpu];				\
+		__sti();					\
+	}							\
+	ret;							\
+})
+
+#define hardirq_endlock(cpu) do { __cli(); hardirq_exit(cpu); __sti(); } while(0)
+
+extern void synchronize_irq(void);
+
+#endif /* __SMP__ */
+
+#endif /* __SPARC_HARDIRQ_H */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- v2.1.33/linux/include/asm-sparc/io.h	Fri Dec 13 01:37:40 1996
+++ linux/include/asm-sparc/io.h	Fri Apr 11 10:47:38 1997
@@ -1,8 +1,9 @@
-/* $Id: io.h,v 1.11 1996/11/19 11:26:14 davem Exp $ */
+/* $Id: io.h,v 1.14 1997/04/10 05:13:22 davem Exp $ */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
 #include <linux/kernel.h>
+#include <linux/types.h>
 
 #include <asm/page.h>      /* IO address mapping routines need this */
 #include <asm/system.h>
@@ -135,9 +136,19 @@
 	return;
 }
 
-extern void *sparc_alloc_io (void *, void *, int, char *, int, int);
-extern void sparc_free_io (void *, int);
-extern void *sparc_dvma_malloc (int, char *);
+extern void *sparc_alloc_io (u32 pa, void *va, int sz, char *name, u32 io, int rdonly);
+extern void sparc_free_io (void *vaddr, int sz);
+extern void *_sparc_dvma_malloc (int sz, char *name);
+
+/* Returns CPU visible address, dvmaaddr_p is a pointer to where
+ * the DVMA visible (ie. SBUS/PSYCO+PCI) address should be stored.
+ */
+static __inline__ void *sparc_dvma_malloc(int size, char *name, __u32 *dvmaaddr_p)
+{
+	void *cpuaddr = _sparc_dvma_malloc(size, name);
+	*dvmaaddr_p = (__u32) cpuaddr;
+	return cpuaddr;
+}
 
 #define virt_to_phys(x) __pa((unsigned long)(x))
 #define phys_to_virt(x) __va((unsigned long)(x))
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h
--- v2.1.33/linux/include/asm-sparc/irq.h	Sat Nov  9 11:40:09 1996
+++ linux/include/asm-sparc/irq.h	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.14 1996/08/29 09:48:18 davem Exp $
+/* $Id: irq.h,v 1.15 1997/04/14 05:39:28 davem Exp $
  * irq.h: IRQ registers on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,8 @@
  */
 extern void (*disable_irq)(unsigned int);
 extern void (*enable_irq)(unsigned int);
+extern void (*disable_pil_irq)(unsigned int);
+extern void (*enable_pil_irq)(unsigned int);
 extern void (*clear_clock_irq)( void );
 extern void (*clear_profile_irq)( void );
 extern void (*load_profile_irq)( unsigned int timeout );
@@ -122,5 +124,6 @@
 #define	SUN4M_INT_SBUSBITS	0x00003F80	  /* sbus int bits */
 
 #define SUN4M_INT_SBUS(x)	(1 << (x+7))
+#define SUN4M_INT_VME(x)	(1 << (x))
 
 #endif
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/openprom.h linux/include/asm-sparc/openprom.h
--- v2.1.33/linux/include/asm-sparc/openprom.h	Sat Nov  9 00:29:48 1996
+++ linux/include/asm-sparc/openprom.h	Fri Apr 11 10:47:38 1997
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.19 1996/09/25 03:51:08 davem Exp $ */
+/* $Id: openprom.h,v 1.20 1997/04/10 06:41:06 davem Exp $ */
 #ifndef __SPARC_OPENPROM_H
 #define __SPARC_OPENPROM_H
 
@@ -186,9 +186,9 @@
 #define PROMINTR_MAX    15
 
 struct linux_prom_registers {
-	int which_io;         /* is this in OBIO space? */
-	char *phys_addr;      /* The physical address of this register */
-	int reg_size;         /* How many bytes does this register take up? */
+	unsigned int which_io;         /* is this in OBIO space? */
+	unsigned int phys_addr;        /* The physical address of this register */
+	unsigned int reg_size;         /* How many bytes does this register take up? */
 };
 
 struct linux_prom_irqs {
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.1.33/linux/include/asm-sparc/pgtable.h	Mon Dec 30 01:59:59 1996
+++ linux/include/asm-sparc/pgtable.h	Fri Apr 11 10:47:38 1997
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.58 1996/12/30 06:17:03 davem Exp $ */
+/* $Id: pgtable.h,v 1.59 1997/04/10 05:13:23 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -39,11 +39,11 @@
 	char *addr;
 	char *__dont_touch;
 	unsigned int len;
-	char *dvma_addr;
+	__u32 dvma_addr;
 };
-extern char *(*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
+extern __u32 (*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
 extern void  (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
-extern void  (*mmu_release_scsi_one)(char *, unsigned long, struct linux_sbus *sbus);
+extern void  (*mmu_release_scsi_one)(__u32, unsigned long, struct linux_sbus *sbus);
 extern void  (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus);
 
 extern void  (*mmu_map_dma_area)(unsigned long addr, int len);
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/pgtsun4c.h linux/include/asm-sparc/pgtsun4c.h
--- v2.1.33/linux/include/asm-sparc/pgtsun4c.h	Mon Dec 23 00:13:53 1996
+++ linux/include/asm-sparc/pgtsun4c.h	Fri Apr 11 10:47:38 1997
@@ -1,4 +1,4 @@
-/* $Id: pgtsun4c.h,v 1.33 1996/12/20 07:55:04 davem Exp $
+/* $Id: pgtsun4c.h,v 1.34 1997/03/23 03:47:08 davem Exp $
  * pgtsun4c.h:  Sun4c specific pgtable.h defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -112,8 +112,6 @@
   __asm__ __volatile__("\n\tstba %1, [%0] %2; nop; nop; nop;\n\t" : :
 		       "r" (addr), "r" (entry),
 		       "i" (ASI_SEGMAP));
-
-  return;
 }
 
 extern __inline__ unsigned long sun4c_get_pte(unsigned long addr)
@@ -131,8 +129,6 @@
   __asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : :
 		       "r" (addr), 
 		       "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE));
-
-  return;
 }
 
 extern __inline__ int sun4c_get_context(void)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/psr.h linux/include/asm-sparc/psr.h
--- v2.1.33/linux/include/asm-sparc/psr.h	Fri Dec 13 01:37:40 1996
+++ linux/include/asm-sparc/psr.h	Fri Apr 11 10:47:38 1997
@@ -1,4 +1,4 @@
-/* $Id: psr.h,v 1.13 1996/12/10 06:06:36 davem Exp $
+/* $Id: psr.h,v 1.14 1997/04/11 00:42:19 davem Exp $
  * psr.h: This file holds the macros for masking off various parts of
  *        the processor status register on the Sparc. This is valid
  *        for Version 8. On the V9 this is renamed to the PSTATE
@@ -62,7 +62,7 @@
 		nop
 "	: /* no outputs */
 	: "r" (new_psr)
-	: "memory");
+	: "memory", "cc");
 }
 
 /* Get the %fsr register.  Be careful, make sure the floating point
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/scatterlist.h linux/include/asm-sparc/scatterlist.h
--- v2.1.33/linux/include/asm-sparc/scatterlist.h	Mon Dec 30 01:59:59 1996
+++ linux/include/asm-sparc/scatterlist.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: scatterlist.h,v 1.1 1996/12/24 07:38:48 davem Exp $ */
+/* $Id: scatterlist.h,v 1.2 1997/04/10 05:13:24 davem Exp $ */
 #ifndef _SPARC_SCATTERLIST_H
 #define _SPARC_SCATTERLIST_H
 
@@ -8,7 +8,7 @@
 			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
 
-    char * dvma_address; /* A place to hang host-specific addresses at. */
+    __u32 dvma_address; /* A place to hang host-specific addresses at. */
 };
 
 #define ISA_DMA_THRESHOLD (~0UL)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h
--- v2.1.33/linux/include/asm-sparc/semaphore.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc/semaphore.h	Mon Apr 14 09:31:09 1997
@@ -13,12 +13,29 @@
 	struct wait_queue * wait;
 };
 
-#define MUTEX ((struct semaphore) { 1, 0, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+#define MUTEX ((struct semaphore) { { (1 << 8) }, { 0 }, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL })
 
 extern void __down(struct semaphore * sem);
 extern int __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
+
+#define sema_init(sem, val)	atomic_set(&((sem)->count), val)
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	save_flags(flags);
+	cli();
+	if (atomic_read(&sem->waking) > 0) {
+		atomic_dec(&sem->waking);
+		ret = 1;
+	}
+	restore_flags(flags);
+	return ret;
+}
 
 /* This isn't quite as clever as the x86 side, I'll be fixing this
  * soon enough.
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.1.33/linux/include/asm-sparc/smp.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/smp.h	Mon Apr 14 09:31:09 1997
@@ -29,6 +29,8 @@
 
 struct cpuinfo_sparc {
 	unsigned long udelay_val; /* that's it */
+	unsigned short next;
+	unsigned short mid;
 };
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
@@ -36,7 +38,6 @@
 struct klock_info {
 	unsigned char kernel_flag;
 	unsigned char akp;
-	unsigned char irq_udt;
 };
 
 extern struct klock_info klock_info;
@@ -51,11 +52,6 @@
 extern int smp_found_cpus;
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
-extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
-extern void smp_message_irq(void);
-extern unsigned long ipi_count;
-
-extern void print_lock_state(void);
 
 typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
 		       unsigned long, unsigned long);
@@ -69,8 +65,6 @@
 extern void smp_store_cpu_info(int id);
 extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
 			   unsigned long arg3, unsigned long arg4, unsigned long arg5);
-extern void smp_capture(void);
-extern void smp_release(void);
 
 extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
 extern __inline__ void xc1(smpfunc_t func, unsigned long arg1)
@@ -89,6 +83,7 @@
 
 extern __volatile__ int cpu_number_map[NR_CPUS];
 extern __volatile__ int cpu_logical_map[NR_CPUS];
+extern unsigned long smp_proc_in_lock[NR_CPUS];
 
 extern __inline__ int smp_processor_id(void)
 {
@@ -101,8 +96,6 @@
 	return cpuid;
 }
 
-
-extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
 extern __volatile__ int smp_process_available;
 
 extern __inline__ int smp_swap(volatile int *addr, int value)
@@ -148,7 +141,6 @@
 #endif /* !(__ASSEMBLY__) */
 
 /* Sparc specific messages. */
-#define MSG_CAPTURE            0x0004       /* Park a processor. */
 #define MSG_CROSS_CALL         0x0005       /* run func on cpus */
 
 /* Empirical PROM processor mailbox constants.  If the per-cpu mailbox
@@ -162,7 +154,6 @@
 #define MBOX_IDLECPU2         0xFD
 #define MBOX_STOPCPU2         0xFE
 
-
 #define NO_PROC_ID            0xFF
 
 #define PROC_CHANGE_PENALTY     20
@@ -170,11 +161,6 @@
 #define SMP_FROM_INT		1
 #define SMP_FROM_SYSCALL	2
 
-#else /* !(__SMP__) */
-
-#define smp_capture()		do { } while(0)
-#define smp_release()		do { } while(0)
- 
 #endif /* !(__SMP__) */
 
 #endif /* !(_SPARC_SMP_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/smp_lock.h linux/include/asm-sparc/smp_lock.h
--- v2.1.33/linux/include/asm-sparc/smp_lock.h	Mon Mar 17 14:54:31 1997
+++ linux/include/asm-sparc/smp_lock.h	Fri Apr 11 10:47:39 1997
@@ -1,6 +1,6 @@
-/* smp_lock.h: SMP locking primitives on Sparc.
+/* smp_lock.h: 32-bit Sparc SMP master lock primitives.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef __SPARC_SMPLOCK_H
@@ -10,26 +10,46 @@
 #include <asm/ptrace.h>
 
 #ifndef __SMP__
-#define lock_kernel()		do { } while(0)
-#define unlock_kernel()		do { } while(0)
 
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED
+#define lock_kernel()				do { } while(0)
+#define unlock_kernel()				do { } while(0)
+#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
+#define reaquire_kernel_lock(task, cpu, depth)	do { } while(0)
 
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		do { } while(0)
-#define spin_trylock(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-
-#define spin_lock_cli(lock)		\
-({	unsigned long flags;		\
-	save_flags(flags); cli();	\
-	return flags;			\
-})
-
-#define spin_unlock_restore(lock, flags)	restore_flags(flags)
 #else
 
+#include <asm/hardirq.h>
+
+/* Release global kernel lock and global interrupt lock */
+#define release_kernel_lock(task, cpu, depth)		\
+do {							\
+	if((depth = (task)->lock_depth) != 0) {		\
+		__cli();				\
+		(task)->lock_depth = 0;			\
+		klock_info.akp = NO_PROC_ID;		\
+		klock_info.kernel_flag = 0;		\
+	}						\
+	release_irqlock(cpu);				\
+	__sti();					\
+} while(0)
+
+/* Do not fuck with this without consulting arch/sparc/lib/locks.S first! */
+#define reaquire_kernel_lock(task, cpu, depth)					\
+do {										\
+	if(depth) {								\
+		register struct klock_info *klip asm("g1");			\
+		register int proc asm("g5");					\
+		klip = &klock_info;						\
+		proc = cpu;							\
+		__asm__ __volatile__("mov	%%o7, %%g4\n\t"			\
+				     "call	___lock_reaquire_kernel\n\t"	\
+				     " mov	%2, %%g2"			\
+				     : /* No outputs. */			\
+				     : "r" (klip), "r" (proc), "r" (depth)	\
+				     : "g2", "g3", "g4", "g7", "memory", "cc");	\
+	}									\
+} while(0)
+
 /* The following acquire and release the master kernel global lock,
  * the idea is that the usage of this mechanmism becomes less and less
  * as time goes on, to the point where they are no longer needed at all
@@ -41,13 +61,27 @@
 {
 	register struct klock_info *klip asm("g1");
 	register int proc asm("g5");
-	klip = &klock_info; proc = smp_processor_id();
+	klip = &klock_info;
+	proc = smp_processor_id();
+
+#if 1 /* Debugging */
+	if(local_irq_count[proc]) {
+		__label__ l1;
+l1:		printk("lock from interrupt context at %p\n", &&l1);
+	}
+	if(proc == global_irq_holder) {
+		__label__ l2;
+l2:		printk("Ugh at %p\n", &&l2);
+		sti();
+	}
+#endif
+
 	__asm__ __volatile__("
 	mov	%%o7, %%g4
 	call	___lock_kernel
 	 ld	[%%g6 + %0], %%g2
 "	: : "i" (AOFF_task_lock_depth), "r" (klip), "r" (proc)
-	: "g2", "g3", "g4", "g7", "memory");
+	: "g2", "g3", "g4", "g7", "memory", "cc");
 }
 
 /* Release kernel global lock. */
@@ -60,89 +94,7 @@
 	call	___unlock_kernel
 	 ld	[%%g6 + %0], %%g2
 "	: : "i" (AOFF_task_lock_depth), "r" (klip)
-	: "g2", "g3", "g4", "memory");
-}
-
-/* Simple spin lock operations.  There are two variants, one clears IRQ's
- * on the local processor, one does not.
- */
-
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED	0
-
-extern __inline__ void spin_lock_init(spinlock_t *lock)
-{
-	*lock = 0;
-}
-
-extern __inline__ void spin_lock(spinlock_t *lock)
-{
-	register spinlock_t *lp asm("g1");
-	lp = lock;
-	__asm__ __volatile__("
-	ldstub	[%%g1], %%g2
-	orcc	%%g2, 0x0, %%g0
-	be	1f
-	 mov	%%o7, %%g4
-	call	___spinlock_waitfor
-	 ldub	[%%g1], %%g2
-1:"	: /* no outputs */
-	: "r" (lp)
-	: "g2", "g4", "memory");
-}
-
-extern __inline__ int spin_trylock(spinlock_t *lock)
-{
-	unsigned int result;
-
-	__asm__ __volatile__("
-	ldstub	[%1], %0
-"	: "=r" (result) : "r" (lock) : "memory");
-
-	return (result == 0);
-}
-
-extern __inline__ void spin_unlock(spinlock_t *lock)
-{
-	__asm__ __volatile__("stb	%%g0, [%0]" : : "r" (lock) : "memory");
-}
-
-/* These variants clear interrupts and return save_flags() style flags
- * to the caller when acquiring a lock.  To release the lock you must
- * pass the lock pointer as well as the flags returned from the acquisition
- * routine when releasing the lock.
- */
-extern __inline__ unsigned long spin_lock_cli(spinlock_t *lock)
-{
-	register spinlock_t *lp asm("g1");
-	register unsigned long flags asm("g3");
-	lp = lock;
-	__asm__ __volatile__("
-	rd	%%psr, %%g3
-	or	%%g3, %1, %%g4
-	wr	%%g4, 0, %%psr
-	nop; nop; nop;
-	ldstub	[%%g1], %%g2
-	orcc	%%g2, 0x0, %%g0
-	be	1f
-	 mov	%%o7, %%g4
-	call	___spinlock_waitfor
-	 ldub	[%%g1], %%g2
-1:"	: "=r" (flags)
-	: "i" (PSR_PIL), "r" (lp)
-	: "g2", "g4", "memory");
-	return flags;
-}
-
-extern __inline__ void spin_unlock_restore(spinlock_t *lock, unsigned long flags)
-{
-	__asm__ __volatile__("
-	stb	%%g0, [%0]
-	wr	%1, 0, %%psr
-	nop; nop; nop;
-"	: /* no outputs */
-	: "r" (lock), "r" (flags)
-	: "memory");
+	: "g2", "g3", "g4", "memory", "cc");
 }
 
 #endif /* !(__SPARC_SMPLOCK_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/softirq.h linux/include/asm-sparc/softirq.h
--- v2.1.33/linux/include/asm-sparc/softirq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc/softirq.h	Mon Apr 14 09:31:09 1997
@@ -0,0 +1,115 @@
+/* softirq.h: 32-bit Sparc soft IRQ support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_SOFTIRQ_H
+#define __SPARC_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+/* The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+extern atomic_t __sparc_bh_counter;
+
+/* Linus, I'd _really_ like to get rid of this synchronize_irq() -DaveM */
+#define start_bh_atomic() \
+	do { atomic_inc(&__sparc_bh_counter); synchronize_irq(); } while(0)
+
+#define end_bh_atomic()		atomic_dec(&__sparc_bh_counter)
+
+#define get_active_bhs()	(bh_mask & bh_active)
+
+#ifdef __SMP__
+
+#include <asm/spinlock.h>
+
+extern spinlock_t global_bh_lock;
+
+#define init_bh(nr, routine)				\
+do {	unsigned long flags;				\
+	int ent = nr;					\
+	spin_lock_irqsave(&global_bh_lock, flags);	\
+	bh_base[ent] = routine;				\
+	bh_mask_count[ent] = 0;				\
+	bh_mask |= 1 << ent;				\
+	spin_unlock_irqrestore(&global_bh_lock, flags);	\
+} while(0)
+
+#define mark_bh(nr)					\
+do {	unsigned long flags;				\
+	spin_lock_irqsave(&global_bh_lock, flags);	\
+	bh_active |= (1 << nr);				\
+	spin_unlock_irqrestore(&global_bh_lock, flags);	\
+} while(0)
+
+#define disable_bh(nr)					\
+do {	unsigned long flags;				\
+	int ent = nr;					\
+	spin_lock_irqsave(&global_bh_lock, flags);	\
+	bh_mask &= ~(1 << ent);				\
+	bh_mask_count[ent]++;				\
+	spin_unlock_irqrestore(&global_bh_lock, flags);	\
+} while(0)
+
+#define enable_bh(nr)					\
+do {	unsigned long flags;				\
+	int ent = nr;					\
+	spin_lock_irqsave(&global_bh_lock, flags);	\
+	if (!--bh_mask_count[ent])			\
+		bh_mask |= 1 << ent;			\
+	spin_unlock_irqrestore(&global_bh_lock, flags);	\
+} while(0)
+
+#define softirq_trylock()					\
+({								\
+	int ret = 1;						\
+	if(atomic_add_return(1, &__sparc_bh_counter) != 1) {	\
+		atomic_dec(&__sparc_bh_counter);		\
+		ret = 0;					\
+	}							\
+	ret;							\
+})
+#define softirq_endlock()	atomic_dec(&__sparc_bh_counter)
+#define clear_active_bhs(mask)				\
+do {	unsigned long flags;				\
+	spin_lock_irqsave(&global_bh_lock, flags);	\
+	bh_active &= ~(mask);				\
+	spin_unlock_irqrestore(&global_bh_lock, flags);	\
+} while(0)
+
+#else /* !(__SMP__) */
+
+#define softirq_trylock() \
+	(atomic_read(&__sparc_bh_counter) ? 0 : ((atomic_set(&__sparc_bh_counter,1)),1))
+
+#define softirq_endlock()	(atomic_set(&__sparc_bh_counter, 0))
+#define clear_active_bhs(x)	(bh_active &= ~(x))
+
+#define init_bh(nr, routine)	\
+do {	int ent = nr;		\
+	bh_base[ent] = routine;	\
+	bh_mask_count[ent] = 0;	\
+	bh_mask |= 1 << ent;	\
+} while(0)
+
+#define mark_bh(nr)		(bh_active |= (1 << (nr)))
+
+#define disable_bh(nr)		\
+do {	int ent = nr;		\
+	bh_mask &= ~(1 << ent);	\
+	bh_mask_count[ent]++;	\
+} while(0)
+
+#define enable_bh(nr)			\
+do {	int ent = nr;			\
+	if (!--bh_mask_count[ent])	\
+		bh_mask |= 1 << ent;	\
+} while(0)
+
+#endif /* __SMP__ */
+
+#endif /* __SPARC_SOFTIRQ_H */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h
--- v2.1.33/linux/include/asm-sparc/spinlock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc/spinlock.h	Fri Apr 11 10:47:39 1997
@@ -0,0 +1,132 @@
+/* spinlock.h: 32-bit Sparc spinlock support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_SPINLOCK_H
+#define __SPARC_SPINLOCK_H
+
+#ifndef __ASSEMBLY__
+
+#ifndef __SMP__
+
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { }
+
+#define spin_lock_init(lock)	do { } while(0)
+#define spin_lock(lock)		do { } while(0)
+#define spin_trylock(lock)	do { } while(0)
+#define spin_unlock(lock)	do { } while(0)
+#define spin_lock_irq(lock)	cli()
+#define spin_unlock_irq(lock)	sti()
+
+#define spin_lock_irqsave(lock, flags)		save_and_cli(flags)
+#define spin_unlock_irqrestore(lock, flags)	restore_flags(flags)
+
+#else /* !(__SMP__) */
+
+#include <asm/psr.h>
+
+typedef unsigned char spinlock_t;
+#define SPIN_LOCK_UNLOCKED	0
+
+extern __inline__ void spin_lock(spinlock_t *lock)
+{
+	register spinlock_t *lp asm("g1");
+	lp = lock;
+	__asm__ __volatile__("
+	ldstub	[%%g1], %%g2
+	orcc	%%g2, 0x0, %%g0
+	be	1f
+	 mov	%%o7, %%g4
+	call	___spinlock_waitfor
+	 ldub	[%%g1], %%g2
+1:"	: /* no outputs */
+	: "r" (lp)
+	: "g2", "g4", "memory", "cc");
+}
+
+extern __inline__ int spin_trylock(spinlock_t *lock)
+{
+	unsigned int result;
+	__asm__ __volatile__("ldstub [%1], %0"
+			     : "=r" (result)
+			     : "r" (lock)
+			     : "memory");
+	return (result == 0);
+}
+
+extern __inline__ void spin_unlock(spinlock_t *lock)
+{
+	__asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory");
+}
+
+extern __inline__ void spin_lock_irq(spinlock_t *lock)
+{
+	register spinlock_t *lp asm("g1");
+	lp = lock;
+	__asm__ __volatile__("
+	rd	%%psr, %%g2
+	or	%%g2, %0, %%g2
+	wr	%%g2, 0x0, %%psr
+	nop; nop; nop;
+	ldstub	[%%g1], %%g2
+	orcc	%%g2, 0x0, %%g0
+	be	1f
+	 mov	%%o7, %%g4
+	call	___spinlock_waitfor
+	 ldub	[%%g1], %%g2
+1:"	: /* No outputs */
+	: "i" (PSR_PIL), "r" (lp)
+	: "g2", "g4", "memory", "cc");
+}
+
+extern __inline__ void spin_unlock_irq(spinlock_t *lock)
+{
+	__asm__ __volatile__("
+	rd	%%psr, %%g2
+	andn	%%g2, %1, %%g2
+	stb	%%g0, [%0]
+	wr	%%g2, 0x0, %%psr
+	nop; nop; nop;
+"	: /* No outputs. */
+	: "r" (lock), "i" (PSR_PIL)
+	: "g2", "memory");
+}
+
+#define spin_lock_irqsave(lock, flags)		\
+do {						\
+	register spinlock_t *lp asm("g1");	\
+	lp = lock;				\
+	__asm__ __volatile__(			\
+	"rd	%%psr, %0\n\t"			\
+	"or	%0, %1, %%g2\n\t"		\
+	"wr	%%g2, 0x0, %%psr\n\t"		\
+	"nop; nop; nop;\n\t"			\
+	"ldstub	[%%g1], %%g2\n\t"		\
+	"orcc	%%g2, 0x0, %%g0\n\t"		\
+	"be	1f\n\t"				\
+	" mov	%%o7, %%g4\n\t"			\
+	"call	___spinlock_waitfor\n\t"	\
+	" ldub	[%%g1], %%g2\n\t"		\
+"1:"	: "=r" (flags)				\
+	: "i" (PSR_PIL), "r" (lp)		\
+	: "g2", "g4", "memory", "cc");		\
+} while(0)
+
+extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
+{
+	__asm__ __volatile__("
+	stb	%%g0, [%0]
+	wr	%1, 0x0, %%psr
+	nop; nop; nop;
+"	: /* No outputs. */
+	: "r" (lock), "r" (flags)
+	: "memory", "cc");
+}
+
+#endif /* __SMP__ */
+
+#endif /* !(__ASSEMBLY__) */
+
+#endif /* __SPARC_SPINLOCK_H */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.1.33/linux/include/asm-sparc/system.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc/system.h	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.53 1997/03/19 14:53:43 davem Exp $ */
+/* $Id: system.h,v 1.56 1997/04/14 05:39:30 davem Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
@@ -11,10 +11,10 @@
 #include <asm/oplib.h>
 #include <asm/psr.h>
 #include <asm/ptrace.h>
-#endif
 
 #define EMPTY_PGT       (&empty_bad_page)
 #define EMPTY_PGE	(&empty_bad_page_table)
+#endif /* __KERNEL__ */
 
 #ifndef __ASSEMBLY__
 
@@ -32,6 +32,9 @@
   ap1000      = 0x07, /* almost a sun4m */
 };
 
+/* Really, userland should not be looking at any of this... */
+#ifdef __KERNEL__
+
 extern enum sparc_cpu sparc_cpu_model;
 
 extern unsigned long empty_bad_page;
@@ -54,7 +57,6 @@
 
 #ifdef __SMP__
 #define SWITCH_ENTER \
-	cli(); \
 	if(prev->flags & PF_USEDFPU) { \
 		put_psr(get_psr() | PSR_EF); \
 		fpsave(&prev->tss.float_regs[0], &prev->tss.fsr, \
@@ -63,11 +65,9 @@
 		prev->tss.kregs->psr &= ~PSR_EF; \
 	}
 
-#define SWITCH_EXIT sti();
 #define SWITCH_DO_LAZY_FPU
 #else
 #define SWITCH_ENTER
-#define SWITCH_EXIT
 #define SWITCH_DO_LAZY_FPU if(last_task_used_math != next) next->tss.kregs->psr&=~PSR_EF;
 #endif
 
@@ -93,7 +93,9 @@
 	"rd	%%wim, %%g5\n\t"							\
 	"wr	%%g4, 0x20, %%psr\n\t"							\
 	"nop\n\t"									\
+	"mov	%5, %%g7\n\t"								\
 	"std	%%g4, [%%g6 + %2]\n\t"							\
+	"st	%%g7, [%%g6 + %6]\n\t"							\
 	"ldd	[%1 + %2], %%g4\n\t"							\
 	"mov	%1, %%g6\n\t"								\
 	"st	%1, [%0]\n\t"								\
@@ -109,12 +111,14 @@
 	"nop\n\t"									\
 	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
 	" nop\n\t" : : "r" (&(current_set[smp_processor_id()])), "r" (next),		\
-	"i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)),		\
-	"i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
-	"r" (task_pc) : "g1", "g2", "g3", "g4", "g5", "g7", "l2", "l3",			\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)),		\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
+	  "r" (task_pc), "i" (255),							\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->processor))		\
+	: "g1", "g2", "g3", "g4", "g5", "g7", "l2", "l3",				\
 	"l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2",	\
 	"o3");										\
-here: SWITCH_EXIT } while(0)
+here:  } while(0)
 
 /* Changing the IRQ level on the Sparc.   We now avoid writing the psr
  * whenever possible.
@@ -128,10 +132,10 @@
 		nop
 "		: /* no outputs */
 		: "r" (__orig_psr)
-		: "memory");
+		: "memory", "cc");
 }
 
-extern __inline__ void cli(void)
+extern __inline__ void __cli(void)
 {
 	unsigned long tmp;
 
@@ -150,7 +154,7 @@
 		: "memory");
 }
 
-extern __inline__ void sti(void)
+extern __inline__ void __sti(void)
 {
 	unsigned long tmp;
 
@@ -195,7 +199,7 @@
 1:
 "		: "=r" (retval), "=r" (tmp1), "=r" (tmp2)
 		: "r" (__new_psr), "i" (PSR_PIL)
-		: "memory");
+		: "memory", "cc");
 
 	return retval;
 }
@@ -223,9 +227,31 @@
 
 extern char spdeb_buf[256];
 
-#define save_flags(flags)	((flags) = getipl())
-#define save_and_cli(flags)	((flags) = read_psr_and_cli())
-#define restore_flags(flags)	setipl((flags))
+#define __save_flags(flags)	((flags) = getipl())
+#define __save_and_cli(flags)	((flags) = read_psr_and_cli())
+#define __restore_flags(flags)	setipl((flags))
+
+#ifdef __SMP__
+
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x)	  ((x)=__global_save_flags())
+#define restore_flags(x)  __global_restore_flags(x)
+#define save_and_cli(x)   do { (x)=__global_save_flags(); __global_cli(); } while(0)
+
+#else
+
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+
+#endif
 
 /* XXX Change this if we ever use a PSO mode kernel. */
 #define mb()  __asm__ __volatile__ ("" : : : "memory")
@@ -246,7 +272,7 @@
 	 add	%%o7, 8, %%o7
 "	: "=&r" (ret)
 	: "0" (ret), "r" (ptr)
-	: "g3", "g4", "g7", "memory");
+	: "g3", "g4", "g7", "memory", "cc");
 
 	return ret;
 }
@@ -267,6 +293,8 @@
 }
 
 extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
+
+#endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/termbits.h linux/include/asm-sparc/termbits.h
--- v2.1.33/linux/include/asm-sparc/termbits.h	Mon Mar 17 14:54:32 1997
+++ linux/include/asm-sparc/termbits.h	Fri Apr 11 10:47:39 1997
@@ -115,44 +115,40 @@
 #define WRAP    0x00020000  /* SUNOS specific */
 
 /* c_cflag bit meaning */
-#define CBAUD	0x0000000f
-#define  B0	0x00000000   /* hang up */
-#define  B50	0x00000001
-#define  B75	0x00000002
-#define  B110	0x00000003
-#define  B134	0x00000004
-#define  B150	0x00000005
-#define  B200	0x00000006
-#define  B300	0x00000007
-#define  B600	0x00000008
-#define  B1200	0x00000009
-#define  B1800	0x0000000a
-#define  B2400	0x0000000b
-#define  B4800	0x0000000c
-#define  B9600	0x0000000d
-#define  B19200	0x0000000e
-#define  B38400	0x0000000f
-#define EXTA    B19200
-#define EXTB    B38400
-#define  CSIZE  0x00000030
-#define   CS5	0x00000000
-#define   CS6	0x00000010
-#define   CS7	0x00000020
-#define   CS8	0x00000030
-#define CSTOPB	0x00000040
-#define CREAD	0x00000080
-#define PARENB	0x00000100
-#define PARODD	0x00000200
-#define HUPCL	0x00000400
-#define CLOCAL	0x00000800
-/* We'll never see these speeds with the Zilogs' but for completeness... */
-#define CBAUDEX 0x00010000
-#define  B57600  0x00010001
-#define  B115200 0x00010002
-#define  B230400 0x00010003
-#define  B460800 0x00010004
-#define CIBAUD	  0x000f0000  /* input baud rate (not used) */
-#define CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define CBAUD	  0x0000100f
+#define  B0	  0x00000000   /* hang up */
+#define  B50	  0x00000001
+#define  B75	  0x00000002
+#define  B110	  0x00000003
+#define  B134	  0x00000004
+#define  B150	  0x00000005
+#define  B200	  0x00000006
+#define  B300	  0x00000007
+#define  B600	  0x00000008
+#define  B1200	  0x00000009
+#define  B1800	  0x0000000a
+#define  B2400	  0x0000000b
+#define  B4800	  0x0000000c
+#define  B9600	  0x0000000d
+#define  B19200	  0x0000000e
+#define  B38400	  0x0000000f
+#define EXTA      B19200
+#define EXTB      B38400
+#define  CSIZE    0x00000030
+#define   CS5	  0x00000000
+#define   CS6	  0x00000010
+#define   CS7	  0x00000020
+#define   CS8	  0x00000030
+#define CSTOPB	  0x00000040
+#define CREAD	  0x00000080
+#define PARENB	  0x00000100
+#define PARODD	  0x00000200
+#define HUPCL	  0x00000400
+#define CLOCAL	  0x00000800
+#define CBAUDEX   0x00001000
+#define  B76800   0x00001001
+#define CIBAUD	  0x100f0000  /* input baud rate (not used) */
+#define CMSPAR	  0x40000000  /* mark or space (stick) parity */
 #define CRTSCTS	  0x80000000  /* flow control */
 
 /* c_lflag bits */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h
--- v2.1.33/linux/include/asm-sparc/uaccess.h	Mon Mar 17 14:54:33 1997
+++ linux/include/asm-sparc/uaccess.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.11 1997/02/06 18:57:10 jj Exp $
+/* $Id: uaccess.h,v 1.13 1997/04/11 00:42:22 davem Exp $
  * uaccess.h: User space memore access functions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -157,7 +157,7 @@
 #define __put_user_asm(x,size,addr,ret)					\
 __asm__ __volatile__(							\
 	"/* Put user asm, inline. */\n"					\
-"1:\t"	"st"#size " %1, [%2]\n\t"					\
+"1:\t"	"st"#size " %1, %2\n\t"						\
 	"clr	%0\n"							\
 "2:\n\n\t"								\
 	".section .fixup,#alloc,#execinstr\n\t"				\
@@ -170,23 +170,23 @@
 	".align	4\n\t"							\
 	".word	1b, 3b\n\t"						\
 	".previous\n\n\t"						\
-       : "=&r" (ret) : "r" (x), "r" (__m(addr)),			\
+       : "=&r" (ret) : "r" (x), "m" (*__m(addr)),			\
 	 "i" (-EFAULT))
 
 #define __put_user_asm_ret(x,size,addr,ret,foo)				\
 if (__builtin_constant_p(ret) && ret == -EFAULT)			\
 __asm__ __volatile__(							\
 	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size " %1, [%2]\n\n\t"					\
+"1:\t"	"st"#size " %1, %2\n\n\t"					\
 	".section __ex_table,#alloc\n\t"				\
 	".align	4\n\t"							\
 	".word	1b, __ret_efault\n\n\t"					\
 	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "r" (__m(addr)));			\
+       : "=r" (foo) : "r" (x), "m" (*__m(addr)));			\
 else									\
 __asm__ __volatile(							\
 	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size " %1, [%2]\n\n\t"					\
+"1:\t"	"st"#size " %1, %2\n\n\t"					\
 	".section .fixup,#alloc,#execinstr\n\t"				\
 	".align	4\n"							\
 "3:\n\t"								\
@@ -197,7 +197,7 @@
 	".align	4\n\t"							\
 	".word	1b, 3b\n\n\t"						\
 	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ret))
+       : "=r" (foo) : "r" (x), "m" (*__m(addr)), "i" (ret))
 
 extern int __put_user_bad(void);
 
@@ -244,7 +244,7 @@
 #define __get_user_asm(x,size,addr,ret)					\
 __asm__ __volatile__(							\
 	"/* Get user asm, inline. */\n"					\
-"1:\t"	"ld"#size " [%2], %1\n\t"					\
+"1:\t"	"ld"#size " %2, %1\n\t"						\
 	"clr	%0\n"							\
 "2:\n\n\t"								\
 	".section .fixup,#alloc,#execinstr\n\t"				\
@@ -258,23 +258,23 @@
 	".align	4\n\t"							\
 	".word	1b, 3b\n\n\t"						\
 	".previous\n\t"							\
-       : "=&r" (ret), "=&r" (x) : "r" (__m(addr)),			\
+       : "=&r" (ret), "=&r" (x) : "m" (*__m(addr)),			\
 	 "i" (-EFAULT))
 
 #define __get_user_asm_ret(x,size,addr,retval)				\
 if (__builtin_constant_p(retval) && retval == -EFAULT)			\
 __asm__ __volatile__(							\
 	"/* Get user asm ret, inline. */\n"				\
-"1:\t"	"ld"#size " [%1], %0\n\n\t"					\
+"1:\t"	"ld"#size " %1, %0\n\n\t"					\
 	".section __ex_table,#alloc\n\t"				\
 	".align	4\n\t"							\
 	".word	1b,__ret_efault\n\n\t"					\
 	".previous\n\t"							\
-       : "=&r" (x) : "r" (__m(addr)));					\
+       : "=&r" (x) : "m" (*__m(addr)));					\
 else									\
 __asm__ __volatile__(							\
 	"/* Get user asm ret, inline. */\n"				\
-"1:\t"	"ld"#size " [%1], %0\n\n\t"					\
+"1:\t"	"ld"#size " %1, %0\n\n\t"					\
 	".section .fixup,#alloc,#execinstr\n\t"				\
 	".align	4\n"							\
 "3:\n\t"								\
@@ -285,7 +285,7 @@
 	".align	4\n\t"							\
 	".word	1b, 3b\n\n\t"						\
 	".previous\n\t"							\
-       : "=&r" (x) : "r" (__m(addr)), "i" (retval))
+       : "=&r" (x) : "m" (*__m(addr)), "i" (retval))
 
 extern int __get_user_bad(void);
 
@@ -351,7 +351,8 @@
 	 mov %1, %%o0
 	mov %%o0, %0 
 	" : "=r" (ret) : "r" (addr), "r" (size) :
-	"o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+	"o0", "o1", "o2", "o3", "o4", "o5", "o7",
+	"g1", "g2", "g3", "g4", "g5", "g7", "cc");
   return ret;
 }
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v2.1.33/linux/include/asm-sparc/unistd.h	Fri Apr  4 08:52:25 1997
+++ linux/include/asm-sparc/unistd.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.29 1997/02/04 07:14:17 miguel Exp $ */
+/* $Id: unistd.h,v 1.32 1997/04/11 00:42:23 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -113,35 +113,35 @@
 #define __NR_setdopt             94 /* SunOS Specific                              */
 #define __NR_fsync               95 /* Common                                      */
 #define __NR_setpriority         96 /* Common                                      */
-#define __NR_socket              97 /* SunOS Specific                              */
-#define __NR_connect             98 /* SunOS Specific                              */
-#define __NR_accept              99 /* SunOS Specific                              */
+#define __NR_socket              97 /* Common                                      */
+#define __NR_connect             98 /* Common                                      */
+#define __NR_accept              99 /* Common                                      */
 #define __NR_getpriority        100 /* Common                                      */
-#define __NR_send               101 /* SunOS Specific                              */
-#define __NR_recv               102 /* SunOS Specific                              */
+#define __NR_send               101 /* Common                                      */
+#define __NR_recv               102 /* Common                                      */
 /* #define __NR_ni_syscall      103    ENOSYS under SunOS                          */
-#define __NR_bind               104 /* SunOS Specific                              */
-#define __NR_setsockopt         105 /* SunOS Specific                              */
-#define __NR_listen             106 /* SunOS Specific                              */
+#define __NR_bind               104 /* Common                                      */
+#define __NR_setsockopt         105 /* Common                                      */
+#define __NR_listen             106 /* Common                                      */
 /* #define __NR_ni_syscall      107    ENOSYS under SunOS                          */
 #define __NR_sigvec             108 /* SunOS Specific                              */
 #define __NR_sigblock           109 /* SunOS Specific                              */
 #define __NR_sigsetmask         110 /* SunOS Specific                              */
 #define __NR_sigpause           111 /* SunOS Specific                              */
 #define __NR_sigstack           112 /* SunOS Specific                              */
-#define __NR_recvmsg            113 /* SunOS Specific                              */
-#define __NR_sendmsg            114 /* SunOS Specific                              */
+#define __NR_recvmsg            113 /* Common                                      */
+#define __NR_sendmsg            114 /* Common                                      */
 #define __NR_vtrace             115 /* SunOS Specific                              */
 #define __NR_gettimeofday       116 /* Common                                      */
 #define __NR_getrusage          117 /* Common                                      */
-#define __NR_getsockopt         118 /* SunOS Specific                              */
+#define __NR_getsockopt         118 /* Common                                      */
 /* #define __NR_ni_syscall      119    ENOSYS under SunOS                          */
 #define __NR_readv              120 /* Common                                      */
 #define __NR_writev             121 /* Common                                      */
 #define __NR_settimeofday       122 /* Common                                      */
 #define __NR_fchown             123 /* Common                                      */
 #define __NR_fchmod             124 /* Common                                      */
-#define __NR_recvfrom           125 /* SunOS Specific                              */
+#define __NR_recvfrom           125 /* Common                                      */
 #define __NR_setreuid           126 /* Common                                      */
 #define __NR_setregid           127 /* Common                                      */
 #define __NR_rename             128 /* Common                                      */
@@ -149,15 +149,15 @@
 #define __NR_ftruncate          130 /* Common                                      */
 #define __NR_flock              131 /* Common                                      */
 /* #define __NR_ni_syscall      132    ENOSYS under SunOS                          */
-#define __NR_sendto             133 /* SunOS Specific                              */
-#define __NR_shutdown           134 /* SunOS Specific                              */
-#define __NR_socketpair         135 /* SunOS Specific                              */
+#define __NR_sendto             133 /* Common                                      */
+#define __NR_shutdown           134 /* Common                                      */
+#define __NR_socketpair         135 /* Common                                      */
 #define __NR_mkdir              136 /* Common                                      */
 #define __NR_rmdir              137 /* Common                                      */
 #define __NR_utimes             138 /* SunOS Specific                              */
 /* #define __NR_ni_syscall      139    ENOSYS under SunOS                          */
 #define __NR_adjtime            140 /* SunOS Specific                              */
-#define __NR_getpeername        141 /* SunOS Specific                              */
+#define __NR_getpeername        141 /* Common                                      */
 #define __NR_gethostid          142 /* SunOS Specific                              */
 /* #define __NR_ni_syscall      143    ENOSYS under SunOS                          */
 #define __NR_getrlimit          144 /* Common                                      */
@@ -166,7 +166,7 @@
 /* #define __NR_ni_syscall      147    ENOSYS under SunOS                          */
 /* #define __NR_ni_syscall      148    ENOSYS under SunOS                          */
 /* #define __NR_ni_syscall      149    ENOSYS under SunOS                          */
-#define __NR_getsockname        150 /* SunOS Specific                              */
+#define __NR_getsockname        150 /* Common                                      */
 #define __NR_getmsg             151 /* SunOS Specific                              */
 #define __NR_putmsg             152 /* SunOS Specific                              */
 #define __NR_poll               153 /* Common                                      */
@@ -285,7 +285,7 @@
 		      "1:\n\t" \
 		      : "=r" (__res)\
 		      : "0" (__NR_##name) \
-		      : "g1", "o0"); \
+		      : "g1", "o0", "cc"); \
 if (__res < -255 || __res >= 0) \
     return (type) __res; \
 errno = -__res; \
@@ -305,7 +305,7 @@
 		      "1:\n\t" \
 		      : "=r" (__res), "=r" ((long)(arg1)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)) \
-		      : "g1", "o0"); \
+		      : "g1", "o0", "cc"); \
 if (__res < -255 || __res >= 0) \
 	return (type) __res; \
 errno = -__res; \
@@ -326,7 +326,7 @@
 		      "1:\n\t" \
 		      : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
-		      : "g1", "o0", "o1"); \
+		      : "g1", "o0", "o1", "cc"); \
 if (__res < -255 || __res >= 0) \
 	return (type) __res; \
 errno = -__res; \
@@ -350,7 +350,7 @@
 		        "=r" ((long)(arg3)) \
 		      : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
 		        "3" ((long)(arg3)) \
-		      : "g1", "o0", "o1", "o2"); \
+		      : "g1", "o0", "o1", "o2", "cc"); \
 if (__res < -255 || __res>=0) \
 	return (type) __res; \
 errno = -__res; \
@@ -375,7 +375,7 @@
 		        "=r" ((long)(arg3)), "=r" ((long)(arg4)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
 		        "3" ((long)(arg3)),"4" ((long)(arg4)) \
-		      : "g1", "o0", "o1", "o2", "o3"); \
+		      : "g1", "o0", "o1", "o2", "o3", "cc"); \
 if (__res < -255 || __res>=0) \
 	return (type) __res; \
 errno = -__res; \
@@ -403,7 +403,7 @@
 		      : "r" ((long)(arg1)),"r" ((long)(arg2)), \
 		        "r" ((long)(arg3)),"r" ((long)(arg4)),"r" ((long)(arg5)), \
 		        "i" (__NR_##name)  \
-		      : "g1", "o0", "o1", "o2", "o3", "o4"); \
+		      : "g1", "o0", "o1", "o2", "o3", "o4", "cc"); \
 if (__res < -255 || __res>=0) \
 	return (type) __res; \
 errno = -__res; \
@@ -474,7 +474,7 @@
 			   "=r" (retval) :
 			   "i" (__NR_clone), "r" (flags | CLONE_VM),
 			   "i" (__NR_exit),  "r" (fn), "r" (arg) :
-			   "g1", "g2", "g3", "o0", "o1", "memory");
+			   "g1", "g2", "g3", "o0", "o1", "memory", "cc");
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/vfc_ioctls.h linux/include/asm-sparc/vfc_ioctls.h
--- v2.1.33/linux/include/asm-sparc/vfc_ioctls.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc/vfc_ioctls.h	Fri Apr 11 10:47:39 1997
@@ -0,0 +1,58 @@
+/* Copyright (c) 1996 by Manish Vachharajani */
+
+#ifndef _LINUX_VFC_IOCTLS_H_
+#define	_LINUX_VFC_IOCTLS_H_
+
+	/* IOCTLs */
+#define VFC_IOCTL(a)          (('j' << 8) | a)
+#define VFCGCTRL	(VFC_IOCTL (0))	        /* get vfc attributes */
+#define VFCSCTRL	(VFC_IOCTL (1))  	/* set vfc attributes */
+#define VFCGVID		(VFC_IOCTL (2)) 	/* get video decoder attributes */
+#define VFCSVID		(VFC_IOCTL (3))	        /* set video decoder attributes */
+#define VFCHUE		(VFC_IOCTL (4))   	/* set hue */
+#define VFCPORTCHG	(VFC_IOCTL (5))  	/* change port */
+#define VFCRDINFO	(VFC_IOCTL (6))  	/* read info */
+
+	/* Options for setting the vfc attributes and status */
+#define MEMPRST		0x1	/* reset FIFO ptr. */
+#define CAPTRCMD	0x2	/* start capture and wait */
+#define DIAGMODE	0x3	/* diag mode */
+#define NORMMODE	0x4	/* normal mode */
+#define CAPTRSTR	0x5	/* start capture */
+#define CAPTRWAIT	0x6	/* wait for capture to finish */
+
+
+	/* Options for the decoder */
+#define STD_NTSC	0x1	/* NTSC mode */
+#define STD_PAL		0x2	/* PAL mode */
+#define COLOR_ON	0x3	/* force color ON */
+#define MONO		0x4	/* force color OFF */
+
+	/* Values returned by ioctl 2 */
+
+#define NO_LOCK	        1
+#define NTSC_COLOR	2
+#define NTSC_NOCOLOR    3
+#define PAL_COLOR	4
+#define PAL_NOCOLOR	5
+
+/* Not too sure what this does yet */
+	/* Options for setting Field number */
+#define ODD_FIELD	0x1
+#define EVEN_FIELD	0x0
+#define ACTIVE_ONLY     0x2
+#define NON_ACTIVE	0x0
+
+/* Debug options */
+#define VFC_I2C_SEND 0
+#define VFC_I2C_RECV 1
+
+struct vfc_debug_inout
+{
+	unsigned long addr;
+	unsigned long ret;
+	unsigned long len;
+	unsigned char *buffer;
+};
+
+#endif /* _LINUX_VFC_IOCTLS_H_ */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h
--- v2.1.33/linux/include/asm-sparc/viking.h	Fri Dec 13 01:37:40 1996
+++ linux/include/asm-sparc/viking.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: viking.h,v 1.17 1996/11/24 17:11:51 ecd Exp $
+/* $Id: viking.h,v 1.18 1997/04/11 00:42:23 davem Exp $
  * viking.h:  Defines specific to the GNU/Viking MBUS module.
  *            This is SRMMU stuff.
  *
@@ -191,7 +191,7 @@
 			      "1:\n\t" : :
 			      "r" (mreg), "r" (mxcc_creg),
 			      "r" (MXCC_CREG), "i" (ASI_M_MMUREGS),
-			      "i" (ASI_M_MXCC) : "g2");
+			      "i" (ASI_M_MXCC) : "g2", "cc");
 	*mregp = mreg;
 	*mxcc_cregp = mxcc_creg;
 }
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/a.out.h linux/include/asm-sparc64/a.out.h
--- v2.1.33/linux/include/asm-sparc64/a.out.h	Mon Dec 30 02:00:02 1996
+++ linux/include/asm-sparc64/a.out.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: a.out.h,v 1.2 1996/12/28 18:39:49 davem Exp $ */
+/* $Id: a.out.h,v 1.3 1997/04/07 18:57:14 jj Exp $ */
 #ifndef __SPARC64_A_OUT_H__
 #define __SPARC64_A_OUT_H__
 
@@ -32,14 +32,14 @@
                          (x).a_drsize)
 
 /* Where does text segment go in memory after being loaded? */
-#define N_TXTADDR(x)    (((N_MAGIC(x) == ZMAGIC) &&        \
-	                 ((x).a_entry < SPARC_PGSIZE)) ?   \
+#define N_TXTADDR(x)    (unsigned long)(((N_MAGIC(x) == ZMAGIC) &&      \
+	                 ((x).a_entry < SPARC_PGSIZE)) ?   		\
                           0 : SPARC_PGSIZE)
 
 /* And same for the data segment.. */
 #define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ?         \
                       (N_TXTADDR(x) + (x).a_text)  \
-                       : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+                       : (unsigned long)(_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
 
 #define N_TRSIZE(a)	((a).a_trsize)
 #define N_DRSIZE(a)	((a).a_drsize)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h
--- v2.1.33/linux/include/asm-sparc64/asm_offsets.h	Mon Mar 17 14:54:33 1997
+++ linux/include/asm-sparc64/asm_offsets.h	Fri Apr 11 10:47:39 1997
@@ -53,116 +53,116 @@
 #define AOFF_task_ngroups	0x000000e0
 #define ASIZ_task_ngroups	0x00000004
 #define AOFF_task_groups	0x000000e4
-#define ASIZ_task_groups	0x00000040
-#define AOFF_task_p_opptr	0x00000128
+#define ASIZ_task_groups	0x00000080
+#define AOFF_task_p_opptr	0x00000168
 #define ASIZ_task_p_opptr	0x00000008
-#define AOFF_task_p_pptr	0x00000130
+#define AOFF_task_p_pptr	0x00000170
 #define ASIZ_task_p_pptr	0x00000008
-#define AOFF_task_p_cptr	0x00000138
+#define AOFF_task_p_cptr	0x00000178
 #define ASIZ_task_p_cptr	0x00000008
-#define AOFF_task_p_ysptr	0x00000140
+#define AOFF_task_p_ysptr	0x00000180
 #define ASIZ_task_p_ysptr	0x00000008
-#define AOFF_task_p_osptr	0x00000148
+#define AOFF_task_p_osptr	0x00000188
 #define ASIZ_task_p_osptr	0x00000008
-#define AOFF_task_wait_chldexit	0x00000150
+#define AOFF_task_wait_chldexit	0x00000190
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_uid	0x00000158
+#define AOFF_task_uid	0x00000198
 #define ASIZ_task_uid	0x00000002
-#define AOFF_task_euid	0x0000015a
+#define AOFF_task_euid	0x0000019a
 #define ASIZ_task_euid	0x00000002
-#define AOFF_task_suid	0x0000015c
+#define AOFF_task_suid	0x0000019c
 #define ASIZ_task_suid	0x00000002
-#define AOFF_task_fsuid	0x0000015e
+#define AOFF_task_fsuid	0x0000019e
 #define ASIZ_task_fsuid	0x00000002
-#define AOFF_task_gid	0x00000160
+#define AOFF_task_gid	0x000001a0
 #define ASIZ_task_gid	0x00000002
-#define AOFF_task_egid	0x00000162
+#define AOFF_task_egid	0x000001a2
 #define ASIZ_task_egid	0x00000002
-#define AOFF_task_sgid	0x00000164
+#define AOFF_task_sgid	0x000001a4
 #define ASIZ_task_sgid	0x00000002
-#define AOFF_task_fsgid	0x00000166
+#define AOFF_task_fsgid	0x000001a6
 #define ASIZ_task_fsgid	0x00000002
-#define AOFF_task_timeout	0x00000168
+#define AOFF_task_timeout	0x000001a8
 #define ASIZ_task_timeout	0x00000008
-#define AOFF_task_policy	0x00000170
+#define AOFF_task_policy	0x000001b0
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000178
+#define AOFF_task_rt_priority	0x000001b8
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000180
+#define AOFF_task_it_real_value	0x000001c0
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000188
+#define AOFF_task_it_prof_value	0x000001c8
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000190
+#define AOFF_task_it_virt_value	0x000001d0
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000198
+#define AOFF_task_it_real_incr	0x000001d8
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x000001a0
+#define AOFF_task_it_prof_incr	0x000001e0
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x000001a8
+#define AOFF_task_it_virt_incr	0x000001e8
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x000001b0
+#define AOFF_task_real_timer	0x000001f0
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_utime	0x000001d8
+#define AOFF_task_utime	0x00000218
 #define ASIZ_task_utime	0x00000008
-#define AOFF_task_stime	0x000001e0
+#define AOFF_task_stime	0x00000220
 #define ASIZ_task_stime	0x00000008
-#define AOFF_task_cutime	0x000001e8
+#define AOFF_task_cutime	0x00000228
 #define ASIZ_task_cutime	0x00000008
-#define AOFF_task_cstime	0x000001f0
+#define AOFF_task_cstime	0x00000230
 #define ASIZ_task_cstime	0x00000008
-#define AOFF_task_start_time	0x000001f8
+#define AOFF_task_start_time	0x00000238
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_min_flt	0x00000200
+#define AOFF_task_min_flt	0x00000240
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x00000208
+#define AOFF_task_maj_flt	0x00000248
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x00000210
+#define AOFF_task_nswap	0x00000250
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x00000218
+#define AOFF_task_cmin_flt	0x00000258
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x00000220
+#define AOFF_task_cmaj_flt	0x00000260
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x00000228
+#define AOFF_task_cnswap	0x00000268
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_swap_address	0x00000238
+#define AOFF_task_swap_address	0x00000278
 #define ASIZ_task_swap_address	0x00000008
-#define AOFF_task_old_maj_flt	0x00000240
+#define AOFF_task_old_maj_flt	0x00000280
 #define ASIZ_task_old_maj_flt	0x00000008
-#define AOFF_task_dec_flt	0x00000248
+#define AOFF_task_dec_flt	0x00000288
 #define ASIZ_task_dec_flt	0x00000008
-#define AOFF_task_swap_cnt	0x00000250
+#define AOFF_task_swap_cnt	0x00000290
 #define ASIZ_task_swap_cnt	0x00000008
-#define AOFF_task_rlim	0x00000258
+#define AOFF_task_rlim	0x00000298
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x000002f8
+#define AOFF_task_used_math	0x00000338
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000002fa
+#define AOFF_task_comm	0x0000033a
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x0000030c
+#define AOFF_task_link_count	0x0000034c
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000310
+#define AOFF_task_tty	0x00000350
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000318
+#define AOFF_task_semundo	0x00000358
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000320
+#define AOFF_task_semsleeping	0x00000360
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_ldt	0x00000328
+#define AOFF_task_ldt	0x00000368
 #define ASIZ_task_ldt	0x00000008
-#define AOFF_task_tss	0x00000340
-#define ASIZ_task_tss	0x00000700
-#define AOFF_task_fs	0x00000a40
+#define AOFF_task_tss	0x00000380
+#define ASIZ_task_tss	0x00000600
+#define AOFF_task_fs	0x00000980
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x00000a48
+#define AOFF_task_files	0x00000988
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x00000a50
+#define AOFF_task_mm	0x00000990
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sig	0x00000a58
+#define AOFF_task_sig	0x00000998
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_processor	0x00000a60
+#define AOFF_task_processor	0x000009a0
 #define ASIZ_task_processor	0x00000004
-#define AOFF_task_last_processor	0x00000a64
+#define AOFF_task_last_processor	0x000009a4
 #define ASIZ_task_last_processor	0x00000004
-#define AOFF_task_lock_depth	0x00000a68
+#define AOFF_task_lock_depth	0x000009a8
 #define ASIZ_task_lock_depth	0x00000004
 #define AOFF_mm_count	0x00000000
 #define ASIZ_mm_count	0x00000004
@@ -212,35 +212,35 @@
 #define ASIZ_thread_float_regs	0x00000100
 #define AOFF_thread_fsr	0x00000100
 #define ASIZ_thread_fsr	0x00000008
-#define AOFF_thread_fpqdepth	0x00000108
-#define ASIZ_thread_fpqdepth	0x00000008
-#define AOFF_thread_fpqueue	0x00000110
-#define ASIZ_thread_fpqueue	0x00000100
-#define AOFF_thread_user_globals	0x00000210
-#define ASIZ_thread_user_globals	0x00000040
-#define AOFF_thread_ksp	0x00000250
+#define AOFF_thread_ksp	0x00000108
 #define ASIZ_thread_ksp	0x00000008
-#define AOFF_thread_kpc	0x00000258
+#define AOFF_thread_kpc	0x00000110
 #define ASIZ_thread_kpc	0x00000008
-#define AOFF_thread_reg_window	0x00000260
+#define AOFF_thread_wstate	0x00000118
+#define ASIZ_thread_wstate	0x00000008
+#define AOFF_thread_cwp	0x00000120
+#define ASIZ_thread_cwp	0x00000008
+#define AOFF_thread_reg_window	0x00000130
 #define ASIZ_thread_reg_window	0x00000400
-#define AOFF_thread_rwbuf_stkptrs	0x00000660
+#define AOFF_thread_rwbuf_stkptrs	0x00000530
 #define ASIZ_thread_rwbuf_stkptrs	0x00000040
-#define AOFF_thread_w_saved	0x000006a0
+#define AOFF_thread_w_saved	0x00000570
 #define ASIZ_thread_w_saved	0x00000008
-#define AOFF_thread_flags	0x000006a8
+#define AOFF_thread_flags	0x00000578
 #define ASIZ_thread_flags	0x00000008
-#define AOFF_thread_sig_address	0x000006b0
+#define AOFF_thread_sig_address	0x00000580
 #define ASIZ_thread_sig_address	0x00000008
-#define AOFF_thread_sig_desc	0x000006b8
+#define AOFF_thread_sig_desc	0x00000588
 #define ASIZ_thread_sig_desc	0x00000008
-#define AOFF_thread_sstk_info	0x000006c0
+#define AOFF_thread_sstk_info	0x00000590
 #define ASIZ_thread_sstk_info	0x00000010
-#define AOFF_thread_current_ds	0x000006d0
+#define AOFF_thread_current_ds	0x000005a0
 #define ASIZ_thread_current_ds	0x00000004
-#define AOFF_thread_new_signal	0x000006d4
+#define AOFF_thread_new_signal	0x000005a4
 #define ASIZ_thread_new_signal	0x00000004
-#define AOFF_thread_core_exec	0x000006d8
+#define AOFF_thread_kregs	0x000005a8
+#define ASIZ_thread_kregs	0x00000008
+#define AOFF_thread_core_exec	0x000005b0
 #define ASIZ_thread_core_exec	0x00000020
 
 #endif /* __ASM_OFFSETS_H__ */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h
--- v2.1.33/linux/include/asm-sparc64/atomic.h	Fri Dec 13 01:37:41 1996
+++ linux/include/asm-sparc64/atomic.h	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.6 1996/12/12 15:40:22 davem Exp $
+/* $Id: atomic.h,v 1.13 1997/04/14 06:56:57 davem Exp $
  * atomic.h: Thankfully the V9 is at least reasonable for this
  *           stuff.
  *
@@ -14,73 +14,81 @@
  */
 #define __atomic_fool_gcc(x) ((struct { int a[100]; } *)x)
 
-typedef int atomic_t;
+typedef struct { int counter; } atomic_t;
+#define ATOMIC_INIT	{ 0 }
 
-extern __inline__ void atomic_add(atomic_t i, atomic_t *v)
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v, i)	(((v)->counter) = i)
+
+extern __inline__ void atomic_add(int i, atomic_t *v)
 {
 	unsigned long temp0, temp1;
 	__asm__ __volatile__("
-	lduw		[%2], %0
+	lduw		[%3], %0
 1:
-	add		%0, %3, %1
-	cas		[%2], %0, %1
+	add		%0, %2, %1
+	cas		[%3], %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduw		[%2], %0
+	 lduw		[%3], %0
 2:
-" 	: "=&r" (temp0), "=&r" (temp1), "=r" (__atomic_fool_gcc(v))
-	: "ir" (i), "r" (__atomic_fool_gcc(v)));
+" 	: "=&r" (temp0), "=&r" (temp1)
+	: "HIr" (i), "r" (__atomic_fool_gcc(v))
+	: "cc");
 }
 
-extern __inline__ void atomic_sub(atomic_t i, atomic_t *v)
+extern __inline__ void atomic_sub(int i, atomic_t *v)
 {
 	unsigned long temp0, temp1;
 	__asm__ __volatile__("
-	lduw		[%2], %0
+	lduw		[%3], %0
 1:
-	sub		%0, %3, %1
-	cas		[%2], %0, %1
+	sub		%0, %2, %1
+	cas		[%3], %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduw		[%2], %0
+	 lduw		[%3], %0
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=r" (__atomic_fool_gcc(v))
-	: "ir" (i), "r" (__atomic_fool_gcc(v)));
+"	: "=&r" (temp0), "=&r" (temp1)
+	: "HIr" (i), "r" (__atomic_fool_gcc(v))
+	: "cc");
 }
 
 /* Same as above, but return the result value. */
-extern __inline__ long atomic_add_return(atomic_t i, atomic_t *v)
+extern __inline__ int atomic_add_return(int i, atomic_t *v)
 {
-	long temp0, result;
+	unsigned long temp0, oldval;
 	__asm__ __volatile__("
-	lduw		[%2], %0
+	lduw		[%3], %0
 1:
-	add		%0, %3, %1
-	cas		[%2], %0, %1
+	add		%0, %2, %1
+	cas		[%3], %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduw		[%2], %0
+	 lduw		[%3], %0
 2:
-"	: "=&r" (temp0), "=&r" (result), "=r" (__atomic_fool_gcc(v))
-	: "ir" (i), "r" (__atomic_fool_gcc(v)));
-	return result;
+"	: "=&r" (temp0), "=&r" (oldval)
+	: "HIr" (i), "r" (__atomic_fool_gcc(v))
+	: "cc");
+	return (((int)oldval) + 1);
 }
 
-extern __inline__ long atomic_sub_return(atomic_t i, atomic_t *v)
+extern __inline__ int atomic_sub_return(int i, atomic_t *v)
 {
-	long temp0, result;
+	unsigned long temp0, oldval;
 	__asm__ __volatile__("
-	lduw		[%2], %0
+	lduw		[%3], %0
 1:
-	sub		%0, %3, %1
-	cas		[%2], %0, %1
+	sub		%0, %2, %1
+	cas		[%3], %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduw		[%2], %0
+	 lduw		[%3], %0
 2:
-"	: "=&r" (temp0), "=&r" (result), "=r" (__atomic_fool_gcc(v))
-	: "ir" (i), "r" (__atomic_fool_gcc(v)));
-	return result;
+"	: "=&r" (temp0), "=&r" (oldval)
+	: "HIr" (i), "r" (__atomic_fool_gcc(v))
+	: "cc");
+	return (((int)oldval) - 1);
 }
 
 #define atomic_dec_return(v) atomic_sub_return(1,(v))
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.1.33/linux/include/asm-sparc64/bitops.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/bitops.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.7 1997/03/14 21:05:38 jj Exp $
+/* $Id: bitops.h,v 1.11 1997/04/10 23:32:42 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -26,18 +26,19 @@
 	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
 
 	__asm__ __volatile__("
-	lduw		[%2], %0
+	lduw		[%4], %0
 1:
-	andcc		%0, %4, %3
+	andcc		%0, %3, %2
 	bne,pn		%%icc, 2f
-	 xor		%0, %4, %1
-	cas 		[%2], %0, %1
+	 xor		%0, %3, %1
+	cas 		[%4], %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduw		[%2], %0
+	 lduw		[%4], %0
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
-	: "ir" (1UL << (nr & 31)), "r" (m));
+"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+	: "HIr" (1UL << (nr & 31)), "r" (m)
+	: "cc");
 	return oldbit != 0;
 }
 
@@ -48,18 +49,19 @@
 	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
 
 	__asm__ __volatile__("
-	lduw		[%2], %0
+	lduw		[%4], %0
 1:
-	andcc		%0, %4, %3
+	andcc		%0, %3, %2
 	be,pn		%%icc, 2f
-	 xor		%0, %4, %1
-	cas 		[%2], %0, %1
+	 xor		%0, %3, %1
+	cas 		[%4], %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduw		[%2], %0
+	 lduw		[%4], %0
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
-	: "ir" (1UL << (nr & 31)), "r" (m));
+"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+	: "HIr" (1UL << (nr & 31)), "r" (m)
+	: "cc");
 	return oldbit != 0;
 }
 
@@ -70,16 +72,17 @@
 	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
 
 	__asm__ __volatile__("
-	lduw		[%2], %0
+	lduw		[%4], %0
 1:
-	andcc		%0, %4, %3
-	xor		%0, %4, %1
-	cas 		[%2], %0, %1
+	and		%0, %3, %2
+	xor		%0, %3, %1
+	cas 		[%4], %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduw		[%2], %0
-"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
-	: "ir" (1UL << (nr & 31)), "r" (m));
+	 lduw		[%4], %0
+"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+	: "HIr" (1UL << (nr & 31)), "r" (m)
+	: "cc");
 	return oldbit != 0;
 }
 
@@ -154,18 +157,19 @@
 	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
 
 	__asm__ __volatile__("
-	lduwa		[%2] %6, %0
+	lduwa		[%4] %5, %0
 1:
-	andcc		%0, %4, %3
+	andcc		%0, %3, %2
 	bne,pn		%%icc, 2f
-	 xor		%0, %4, %1
-	casa 		[%2] %6, %0, %1
+	 xor		%0, %3, %1
+	casa 		[%4] %5, %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduwa		[%2] %6, %0
+	 lduwa		[%4] %5, %0
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
-	: "ir" (1UL << (nr & 31)), "2" (m), "i" (ASI_PL));
+"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+	: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
+	: "cc");
 	return oldbit != 0;
 }
 
@@ -176,18 +180,19 @@
 	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
 
 	__asm__ __volatile__("
-	lduwa		[%2] %6, %0
+	lduwa		[%4] %5, %0
 1:
-	andcc		%0, %4, %3
+	andcc		%0, %3, %2
 	be,pn		%%icc, 2f
-	 xor		%0, %4, %1
-	casa 		[%2] %6, %0, %1
+	 xor		%0, %3, %1
+	casa 		[%4] %5, %0, %1
 	cmp		%0, %1
 	bne,a,pn	%%icc, 1b
-	 lduwa		[%2] %6, %0
+	 lduwa		[%4] %5, %0
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
-	: "ir" (1UL << (nr & 31)), "2" (m), "i" (ASI_PL));
+"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+	: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
+	: "cc");
 	return oldbit != 0;
 }
 
@@ -259,6 +264,12 @@
 #define ext2_test_bit  			test_le_bit
 #define ext2_find_first_zero_bit	find_first_zero_le_bit
 #define ext2_find_next_zero_bit		find_next_zero_le_bit
+
+/* Bitmap functions for the minix filesystem.  */
+#define minix_set_bit(nr,addr) set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h
--- v2.1.33/linux/include/asm-sparc64/checksum.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/checksum.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.5 1997/03/18 18:00:28 jj Exp $ */
+/* $Id: checksum.h,v 1.6 1997/04/10 23:32:43 davem Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -153,7 +153,7 @@
 	xnor		%%g0, %0, %0
 "	: "=r" (sum), "=&r" (iph)
 	: "r" (ihl), "1" (iph)
-	: "g2", "g3", "g7");
+	: "g2", "g3", "g7", "cc");
 	return sum;
 }
 
@@ -177,7 +177,8 @@
 	addc		%0, %%g0, %0
 	xnor		%%g0, %0, %0
 "	: "=r" (sum), "=r" (saddr)
-	: "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr));
+	: "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr)
+	: "cc");
 	return sum;
 }
 
@@ -192,7 +193,8 @@
 	addc		%1, %%g0, %1
 	xnor		%%g0, %1, %0
 "	: "=&r" (sum), "=r" (tmp)
-	: "0" (sum), "1" (sum<<16));
+	: "0" (sum), "1" (sum<<16)
+	: "cc");
 	return sum;
 }
 
@@ -227,7 +229,7 @@
 "	: "=&r" (sum)
 	: "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))),
 	  "r"(htonl(proto)), "r"(sum)
-	: "g2", "g3", "g7");
+	: "g2", "g3", "g7", "cc");
 
 	return csum_fold(sum);
 }
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/delay.h linux/include/asm-sparc64/delay.h
--- v2.1.33/linux/include/asm-sparc64/delay.h	Fri Dec 13 01:37:41 1996
+++ linux/include/asm-sparc64/delay.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.3 1996/12/12 15:53:48 davem Exp $
+/* $Id: delay.h,v 1.4 1997/04/10 23:32:44 davem Exp $
  * delay.h: Linux delay routines on the V9.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu).
@@ -17,7 +17,8 @@
 	bne,pt	%%xcc, 1b
 	 subcc	%0, 1, %0
 "	: "=&r" (loops)
-	: "0" (loops));
+	: "0" (loops)
+	: "cc");
 }
 
 extern __inline__ void udelay(unsigned long usecs)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h
--- v2.1.33/linux/include/asm-sparc64/dma.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/dma.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.3 1997/03/14 21:05:36 jj Exp $
+/* $Id: dma.h,v 1.7 1997/04/10 05:13:28 davem Exp $
  * include/asm-sparc64/dma.h
  *
  * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
 #define _ASM_SPARC64_DMA_H
 
 #include <linux/kernel.h>
+#include <linux/types.h>
 
 #include <asm/sbus.h>
 #include <asm/delay.h>
@@ -17,7 +18,7 @@
  * things can compile.
  */
 #define MAX_DMA_CHANNELS 8
-#define MAX_DMA_ADDRESS  ((0x100000000) + PAGE_OFFSET)
+#define MAX_DMA_ADDRESS  ((0xf0000000) + PAGE_OFFSET)
 #define DMA_MODE_READ    1
 #define DMA_MODE_WRITE   2
 
@@ -27,10 +28,10 @@
 
 /* Structure to describe the current status of DMA registers on the Sparc */
 struct sparc_dma_registers {
-  __volatile__ unsigned int cond_reg;   /* DMA condition register */
-  __volatile__ char * st_addr;          /* Start address of this transfer */
-  __volatile__ unsigned int cnt;        /* How many bytes to transfer */
-  __volatile__ unsigned int dma_test;   /* DMA test register */
+  __volatile__ __u32 cond_reg;	/* DMA condition register */
+  __volatile__ __u32 st_addr;	/* Start address of this transfer */
+  __volatile__ __u32 cnt;	/* How many bytes to transfer */
+  __volatile__ __u32 dma_test;	/* DMA test register */
 };
 
 /* DVMA chip revisions */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h
--- v2.1.33/linux/include/asm-sparc64/elf.h	Mon Dec 30 02:00:02 1996
+++ linux/include/asm-sparc64/elf.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.2 1996/12/26 13:25:25 davem Exp $ */
+/* $Id: elf.h,v 1.3 1997/04/04 00:50:12 davem Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -23,9 +23,11 @@
 /*
  * These are used to set parameters in the core dumps.
  */
+#ifndef ELF_ARCH
 #define ELF_ARCH	EM_SPARC64
 #define ELF_CLASS	ELFCLASS64
 #define ELF_DATA	ELFDATA2MSB;
+#endif
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	4096
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/fbio.h linux/include/asm-sparc64/fbio.h
--- v2.1.33/linux/include/asm-sparc64/fbio.h	Fri Dec 13 01:37:46 1996
+++ linux/include/asm-sparc64/fbio.h	Fri Apr 11 10:47:39 1997
@@ -45,7 +45,10 @@
 };
 #define FBIOGTYPE _IOR('F', 0, struct fbtype)
 
-/* Used by FBIOPUTCMAP */
+/* Used by FBIOPUTCMAP
+ *
+ * XXX 32-bit binary compatability item... -DaveM
+ */
 struct  fbcmap {
         int             index;          /* first element (0 origin) */
         int             count;
@@ -98,6 +101,7 @@
 #define FB_CUR_SETSHAPE 0x10	/* set shape */
 #define FB_CUR_SETALL   0x1F	/* all of the above */
 
+/* XXX 32-bit binary compatability item... -DaveM */
 struct fbcursor {
         short set;              /* what to set, choose from the list above */
         short enable;           /* cursor on/off */
@@ -136,6 +140,7 @@
 	__u32	wi_attrs;
 	__u32	wi_values[32];
 };
+/* XXX 32-bit binary compatability item... -DaveM */
 struct fb_wid_list {
 	__u32	wl_flags;
 	__u32	wl_count;
@@ -178,6 +183,7 @@
  	__u32	index;
 };
 
+/* XXX 32-bit binary compatability item... -DaveM */
 struct leo_clut {
 #define LEO_CLUT_WAIT	0x00000001	/* Not yet implemented */
  	__u32	flag;
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h
--- v2.1.33/linux/include/asm-sparc64/fcntl.h	Fri Dec 13 01:37:46 1996
+++ linux/include/asm-sparc64/fcntl.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: fcntl.h,v 1.1 1996/11/20 15:28:41 davem Exp $ */
+/* $Id: fcntl.h,v 1.2 1997/04/04 00:50:15 davem Exp $ */
 #ifndef _SPARC64_FCNTL_H
 #define _SPARC64_FCNTL_H
 
@@ -48,6 +48,7 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
+/* XXX 32-bit binary compatability item... -DaveM */
 struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/firehose.h linux/include/asm-sparc64/firehose.h
--- v2.1.33/linux/include/asm-sparc64/firehose.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/firehose.h	Fri Apr 11 10:47:39 1997
@@ -0,0 +1,139 @@
+/* $Id: firehose.h,v 1.1 1997/04/11 02:38:47 davem Exp $
+ * firehose.h: Defines for the Fire Hose Controller (FHC) found
+ *             on Sunfire/Wildfire systems.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_FIREHOSE_H
+#define _SPARC64_FIREHOSE_H
+
+#include <linux/types.h>
+
+/* XXX I have not fully verified the register sizes in this file yet... -DaveM */
+
+/* Fire Hose Controller Internal Registers */
+struct fhc_internal_regs {
+/*0x0000*/	u32	fhc_id;		/* FHC ID Register			*/
+		u32	_unused1[3];
+/*0x0010*/	u32	fhc_rcs;	/* FHC Reset Control/Status Register	*/
+		u32	_unused2[3];
+/*0x0020*/	u32	fhc_control;	/* FHC Control Register			*/
+		u32	_unused3[3];
+/*0x0030*/	u32	fhc_bsr;	/* FHC Board Status Register		*/
+		u32	_unused4[3];
+/*0x0040*/	u32	fhc_ecc;	/* FHC ECC Control Register (16 bits)	*/
+		u32	_unused5[43];
+/*0x00f0*/	u32	fhc_jtag_ctrl;	/* FHC JTAG Control Register		*/
+		u32	_unused6[3];
+/*0x0100*/	u32	fhc_jtag_cmd;	/* FHC JTAG Command Register		*/
+};
+
+/* Part of same space of regs, but mapped seperately in PROM reg property
+ * for the FHC, thus we have the following few structs...
+ */
+struct fhc_ign_reg {
+/*0x2000*/	u64	fhc_ign;	/* FHC Interrupt Group Number		*/
+};
+
+struct fhc_fanfail_regs {
+/*0x4000*/	u64	fhc_ff_imap;	/* FHC FanFail Interrupt Map		*/
+		u64	_unused1;
+/*0x4010*/	u64	fhc_ff_istate;	/* FHC FanFail Interrupt State		*/
+};
+
+struct fhc_system_regs {
+/*0x6000*/	u64	fhc_sys_imap;	/* FHC System Interrupt Map		*/
+		u64	_unused1;
+/*0x6010*/	u64	fhc_sys_istate;	/* FHC System Interrupt State		*/
+};
+
+struct fhc_uart_regs {
+/*0x8000*/	u64	fhc_uart_imap;	/* FHC UART Interrupt Map		*/
+		u64	_unused1;
+/*0x8010*/	u64	fhc_uart_istate;/* FHC UART Interrupt State		*/
+};
+
+struct fhc_tod_regs {
+/*0xa000*/	u64	fhc_tod_imap;	/* FHC TOD Interrupt Map		*/
+		u64	_unused1;
+/*0xa010*/	u64	fhc_tod_istate;	/* FHC TOD Interrupt State		*/
+};
+
+/* All of the above. */
+struct fhc_regs {
+	struct fhc_internal_regs	*pregs;
+	struct fhc_ign_reg		*ireg;
+	struct fhc_fanfil_regs		*ffregs;
+	struct fhc_system_regs		*sregs;
+	struct fhc_uart_regs		*uregs;
+	struct fhc_tod_regs		*tregs;
+};
+
+/* FHC ID Register */
+#define FHC_ID_VERS		0xf0000000 /* Version of this FHC		*/
+#define FHC_ID_PARTID		0x0ffff000 /* Part ID code (0x0f9f == FHC)	*/
+#define FHC_ID_MANUF		0x0000007e /* Manufacturer (0x3e == SUN's JEDEC)*/
+#define FHC_ID_RESV		0x00000001 /* Read as one			*/
+
+/* FHC Control Register */
+#define FHC_CONTROL_ICS		0x00100000 /* Ignore Centerplane Signals	*/
+#define FHC_CONTROL_FRST	0x00080000 /* Fatal Error Reset Enable		*/
+#define FHC_CONTROL_LFAT	0x00040000 /* AC/DC signalled a local error	*/
+#define FHC_CONTROL_SLINE	0x00010000 /* Firmware Synchronization Line	*/
+#define FHC_CONTROL_DCD		0x00008000 /* DC-->DC Converter Disable		*/
+#define FHC_CONTROL_POFF	0x00004000 /* AC/DC Controller PLL Disable	*/
+#define FHC_CONTROL_FOFF	0x00002000 /* FHC Controller PLL Disable	*/
+#define FHC_CONTROL_AOFF	0x00001000 /* CPU A SRAM/SBD Low Power Mode	*/
+#define FHC_CONTROL_BOFF	0x00000800 /* CPU B SRAM/SBD Low Power Mode	*/
+#define FHC_CONTROL_PSOFF	0x00000400 /* Turns off this FHC's power supply	*/
+#define FHC_CONTROL_IXIST	0x00000200 /* 0=FHC tells clock board it exists	*/
+#define FHC_CONTROL_XMSTR	0x00000100 /* 1=Causes this FHC to be XIR master*/
+#define FHC_CONTROL_LLED	0x00000040 /* 0=Left LED ON			*/
+#define FHC_CONTROL_MLED	0x00000020 /* 1=Middle LED ON			*/
+#define FHC_CONTROL_RLED	0x00000010 /* 1=Right LED			*/
+#define FHC_CONTROL_BPINS	0x00000003 /* Spare Bidirectional Pins		*/
+
+/* FHC Reset Control/Status Register */
+#define FHC_RCS_POR		0x80000000 /* Last reset was a power cycle	*/
+#define FHC_RCS_SPOR		0x40000000 /* Last reset was sw power on reset	*/
+#define FHC_RCS_SXIR		0x20000000 /* Last reset was sw XIR reset	*/
+#define FHC_RCS_BPOR		0x10000000 /* Last reset was due to POR button	*/
+#define FHC_RCS_BXIR		0x08000000 /* Last reset was due to XIR button	*/
+#define FHC_RCS_WEVENT		0x04000000 /* CPU reset was due to wakeup event	*/
+#define FHC_RCS_CFATAL		0x02000000 /* Centerplane Fatal Error signalled	*/
+#define FHC_RCS_FENAB		0x01000000 /* Fatal errors elicit system reset	*/
+
+/* FHC Board Status Register */
+#define FHC_BSD_DA64		0x00040000 /* Port A: 0=128bit 1=64bit data path */
+#define FHC_BSD_DB64		0x00020000 /* Port B: 0=128bit 1=64bit data path */
+#define FHC_BSD_BID		0x0001e000 /* Board ID                           */
+#define FHC_BSD_SA		0x00001c00 /* Port A UPA Speed (from the pins)   */
+#define FHC_BSD_SB		0x00000380 /* Port B UPA Speed (from the pins)   */
+#define FHC_BSD_NDIAG		0x00000040 /* Not in Diag Mode                   */
+#define FHC_BSD_NTBED		0x00000020 /* Not in TestBED Mode                */
+#define FHC_BSD_NIA		0x0000001c /* Jumper, bit 18 in PROM space       */
+#define FHC_BSD_SI		0x00000001 /* Spare input pin value              */
+
+/* FHC then has an Interrupt Group Number register, essentially this is a 32-bit
+ * register with the low 5 bits specifying the IGN of this FHC for interrupt
+ * generation purposes, it is a product of the BoardID/Pins seen by the FHC
+ * at power on time.  I suspect the firmware really sets this value though
+ * during POST.  On board FHC devices generate fixed INO interrupt packet
+ * values, of course these are concatenated with the IGN before it reaches the
+ * CPU:
+ *
+ *	IRQ Source		INO Value
+ *	----------------------------------------
+ *	"System" Interrupt	0x38
+ *	Zilogs			0x39
+ *	Mostek			0x3a
+ *	Fan Failure		0x3b
+ *	Spare 1			0x3c
+ *	Spare 2			0x3d
+ *
+ * Consult the sysio.h header for the layout of the Interrupt Mapping and
+ * Interrupt Clear register bits as they are the same. -DaveM
+ */
+
+#endif /* !(_SPARC64_FIREHOSE_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/fpumacro.h linux/include/asm-sparc64/fpumacro.h
--- v2.1.33/linux/include/asm-sparc64/fpumacro.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/fpumacro.h	Fri Apr 11 10:47:39 1997
@@ -0,0 +1,53 @@
+/* fpumacro.h: FPU related macros.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#ifndef _SPARC64_FPUMACRO_H
+#define _SPARC64_FPUMACRO_H
+
+extern __inline__ void fpsave32(unsigned long *fpregs, unsigned long *fsr)
+{
+	__asm__ __volatile__ ("
+	wr	%%g0, %2, %%asi
+	stx	%%fsr, [%1]
+	stda	%%f0, [%0] %%asi
+	stda	%%f16, [%0 + 64] %%asi
+	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+extern __inline__ void fpload32(unsigned long *fpregs, unsigned long *fsr)
+{
+	__asm__ __volatile__ ("
+	wr	%%g0, %2, %%asi
+	ldda	[%0] %%asi, %%f0
+	ldda	[%0 + 64] %%asi, %%f16
+	ldx	[%1], %%fsr
+	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+extern __inline__ void fpsave(unsigned long *fpregs, unsigned long *fsr)
+{
+	__asm__ __volatile__ ("
+	wr	%%g0, %2, %%asi
+	stx	%%fsr, [%1]
+	stda	%%f0, [%0] %%asi
+	stda	%%f16, [%0 + 64] %%asi
+	stda	%%f32, [%0 + 128] %%asi
+	stda	%%f48, [%0 + 192] %%asi
+	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+extern __inline__ void fpload(unsigned long *fpregs, unsigned long *fsr)
+{
+	__asm__ __volatile__ ("
+	wr	%%g0, %2, %%asi
+	ldda	[%0] %%asi, %%f0
+	ldda	[%0 + 64] %%asi, %%f16
+	ldda	[%0 + 128] %%asi, %%f32
+	ldda	[%0 + 192] %%asi, %%f48
+	ldx	[%1], %%fsr
+	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+#endif /* !(_SPARC64_FPUMACRO_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.1.33/linux/include/asm-sparc64/hardirq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/hardirq.h	Mon Apr 14 09:31:09 1997
@@ -0,0 +1,29 @@
+/* hardirq.h: 64-bit Sparc hard IRQ support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_HARDIRQ_H
+#define __SPARC64_HARDIRQ_H
+
+#include <linux/tasks.h>
+
+extern unsigned int local_irq_count[NR_CPUS];
+#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
+#define hardirq_depth()	(local_irq_count[smp_processor_id()])
+
+#ifdef __SMP__
+#error SMP not supported on sparc64
+#else /* !(__SMP__) */
+
+#define hardirq_trylock(cpu)	(++local_irq_count[cpu], (cpu)==0)
+#define hardirq_endlock(cpu)	(--local_irq_count[cpu])
+
+#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
+#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
+
+#define synchronize_irq()	do { } while(0)
+
+#endif /* __SMP__ */
+
+#endif /* !(__SPARC64_HARDIRQ_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h
--- v2.1.33/linux/include/asm-sparc64/head.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/head.h	Fri Apr 11 10:47:39 1997
@@ -1,10 +1,13 @@
-/* $Id: head.h,v 1.7 1997/03/18 18:00:36 jj Exp $ */
+/* $Id: head.h,v 1.16 1997/04/08 11:03:13 davem Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
-#define KERNBASE    0xfffff80000000000
+#include <asm/pstate.h>
+
+#define KERNBASE    0xFFFFF80000000000
 #define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
 
+/* We need a "cleaned" instruction... */
 #define CLEAN_WINDOW							\
 	clr	%o0;	clr	%o1;	clr	%o2;	clr	%o3;	\
 	clr	%o4;	clr	%o5;	clr	%o6;	clr	%o7;	\
@@ -12,7 +15,7 @@
 	clr	%l4;	clr	%l5;	clr	%l6;	clr	%l7;	\
 	rdpr %cleanwin, %g1; 		add %g1, 1, %g1;		\
 	wrpr %g1, 0x0, %cleanwin;	retry;				\
-	nop;		nop;		nop;		nop;
+	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
 
 #define TRAP(routine)					\
 	ba,pt	%xcc, etrap;				\
@@ -24,6 +27,32 @@
 	nop;						\
 	nop;
 
+#define TRAP_NOSAVE(routine)				\
+	ba,pt	%xcc, routine;				\
+	 nop;						\
+	nop; nop; nop; nop; nop; nop;
+
+#define TRAPTL1(routine)				\
+	ba,pt	%xcc, etraptl1;				\
+	 rd	%pc, %g7;				\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 nop;						\
+	nop;						\
+	nop;
+	
+/* Just for testing */
+#define PROM_TRAP					\
+	rd	%pc, %g1;				\
+	sethi	%uhi(KERNBASE), %g4;			\
+	sethi	%hi(0xf0000000-0x8000), %g2;		\
+	sllx	%g4, 32, %g4;				\
+	add	%g1, %g2, %g1;				\
+	sub	%g1, %g4, %g1;				\
+	jmpl	%g1 + %g0, %g0;				\
+	nop;
+
 #define TRAP_ARG(routine, arg)				\
 	ba,pt	%xcc, etrap;				\
 	 rd	%pc, %g7;				\
@@ -34,6 +63,16 @@
 	 nop;						\
 	nop;
 	
+#define TRAPTL1_ARG(routine, arg)			\
+	ba,pt	%xcc, etraptl1;				\
+	 rd	%pc, %g7;				\
+	add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	call	routine;				\
+	 mov	arg, %o1;				\
+	ba,pt	%xcc, rtrap;				\
+	 nop;						\
+	nop;
+	
 #define SYSCALL_TRAP(routine, systbl)			\
 	ba,pt	%xcc, etrap;				\
 	 rd	%pc, %g7;				\
@@ -42,6 +81,25 @@
 	 or	%l7, %lo(systbl), %l7;			\
 	nop; nop; nop;
 	
+#define ACCESS_EXCEPTION_TRAP(routine)			\
+	rdpr	%pstate, %g1;				\
+	wrpr	%g1, PSTATE_MG|PSTATE_AG, %pstate;	\
+	ba,pt	%xcc, etrap;				\
+	 rd	%pc, %g7;				\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 nop;
+
+#define ACCESS_EXCEPTION_TRAPTL1(routine)		\
+	rdpr	%pstate, %g1;				\
+	wrpr	%g1, PSTATE_MG|PSTATE_AG, %pstate;	\
+	ba,pt	%xcc, etraptl1;				\
+	 rd	%pc, %g7;				\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 nop;
 
 #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
 #define	LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
@@ -54,11 +112,36 @@
 #define SETCC_TRAP TRAP(setcc)
 #define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
 
-#define TRAP_IRQ(routine, level) TRAP_ARG(routine, level)
+#define TRAP_IRQ(routine, level)			\
+	rdpr	%pil, %g4;				\
+	wrpr	%g0, 15, %pil;				\
+	ba,pt	%xcc, etrap_irq;			\
+	 rd	%pc, %g7;				\
+	mov	level, %o0;				\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1;	\
+	ba,a,pt	%xcc, rtrap;
+
+/* On UP this is ok, and worth the effort, for SMP we need
+ * a different mechanism and thus cannot do it all in trap table. -DaveM
+ */
+#if 0 /* ndef __SMP__ */
+#define TRAP_IVEC				\
+	ldxa	[%g2] ASI_UDB_INTR_R, %g3;	\
+	and	%g3, 0x7ff, %g3;		\
+	sllx	%g3, 3, %g3;			\
+	ldx	[%g1 + %g3], %g5;		\
+	wr	%g5, 0x0, %set_softint;		\
+	stxa	%g0, [%g0] ASI_INTR_RECEIVE;	\
+	membar	#Sync;				\
+	retry;
+#else
+#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
+#endif
 
 #define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
 
-#define BTRAPTL1(lvl) TRAP_ARG(bad_trap_tl1, lvl)
+#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl)
 
 #define FLUSH_WINDOW_TRAP					\
 	flushw;							\
@@ -87,8 +170,8 @@
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 64bit spill */
-#define SPILL_1_NORMAL					\
-	wr	%g0, ASI_AIUP, %asi;			\
+#define SPILL_1_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
 	stxa	%l0, [%sp + STACK_BIAS + 0x00] %asi;	\
 	stxa	%l1, [%sp + STACK_BIAS + 0x08] %asi;	\
 	stxa	%l2, [%sp + STACK_BIAS + 0x10] %asi;	\
@@ -109,8 +192,8 @@
 	nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 32bit spill */
-#define SPILL_2_NORMAL					\
-	wr	%g0, ASI_AIUP, %asi;			\
+#define SPILL_2_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
 	srl	%sp, 0, %sp;				\
 	stda	%l0, [%sp + 0x00] %asi;			\
 	stda	%l2, [%sp + 0x10] %asi;			\
@@ -120,10 +203,12 @@
 	stda	%i2, [%sp + 0x50] %asi;			\
 	stda	%i4, [%sp + 0x60] %asi;			\
 	stda	%i6, [%sp + 0x70] %asi;			\
-	saved; retry; nop; nop; nop; nop; nop;		\
+	saved; retry; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
+#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
+#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
 #define SPILL_3_NORMAL SPILL_0_NORMAL
 #define SPILL_4_NORMAL SPILL_0_NORMAL
 #define SPILL_5_NORMAL SPILL_0_NORMAL
@@ -131,8 +216,8 @@
 #define SPILL_7_NORMAL SPILL_0_NORMAL
 
 #define SPILL_0_OTHER SPILL_0_NORMAL
-#define SPILL_1_OTHER SPILL_1_NORMAL
-#define SPILL_2_OTHER SPILL_2_NORMAL
+#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS)
+#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS)
 #define SPILL_3_OTHER SPILL_3_NORMAL
 #define SPILL_4_OTHER SPILL_4_NORMAL
 #define SPILL_5_OTHER SPILL_5_NORMAL
@@ -157,12 +242,12 @@
 	ldx	[%sp + STACK_BIAS + 0x68], %i5;		\
 	ldx	[%sp + STACK_BIAS + 0x70], %i6;		\
 	ldx	[%sp + STACK_BIAS + 0x78], %i7;		\
-	saved; retry; nop; nop; nop; nop; nop; nop;	\
+	restored; retry; nop; nop; nop; nop; nop; nop;	\
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 64bit fill */
-#define FILL_1_NORMAL					\
-	wr	%g0, ASI_AIUP, %asi;			\
+#define FILL_1_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
 	ldxa	[%sp + STACK_BIAS + 0x00] %asi, %l0;	\
 	ldxa	[%sp + STACK_BIAS + 0x08] %asi, %l1;	\
 	ldxa	[%sp + STACK_BIAS + 0x10] %asi, %l2;	\
@@ -179,12 +264,12 @@
 	ldxa	[%sp + STACK_BIAS + 0x68] %asi, %i5;	\
 	ldxa	[%sp + STACK_BIAS + 0x70] %asi, %i6;	\
 	ldxa	[%sp + STACK_BIAS + 0x78] %asi, %i7;	\
-	saved; retry; nop; nop; nop; nop; nop; nop;	\
+	restored; retry; nop; nop; nop; nop; nop; nop;	\
 	nop; nop; nop; nop; nop; nop; nop;
 
 /* Normal 32bit fill */
-#define FILL_2_NORMAL					\
-	wr	%g0, ASI_AIUP, %asi;			\
+#define FILL_2_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
 	srl	%sp, 0, %sp;				\
 	ldda	[%sp + 0x00] %asi, %l0;			\
 	ldda	[%sp + 0x10] %asi, %l2;			\
@@ -194,10 +279,12 @@
 	ldda	[%sp + 0x50] %asi, %i2;			\
 	ldda	[%sp + 0x60] %asi, %i4;			\
 	ldda	[%sp + 0x70] %asi, %i6;			\
-	saved; retry; nop; nop; nop; nop; nop;		\
+	restored; retry; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;
 
+#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
+#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
 #define FILL_3_NORMAL FILL_0_NORMAL
 #define FILL_4_NORMAL FILL_0_NORMAL
 #define FILL_5_NORMAL FILL_0_NORMAL
@@ -205,8 +292,8 @@
 #define FILL_7_NORMAL FILL_0_NORMAL
 
 #define FILL_0_OTHER FILL_0_NORMAL
-#define FILL_1_OTHER FILL_1_NORMAL
-#define FILL_2_OTHER FILL_2_NORMAL
+#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS)
+#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS)
 #define FILL_3_OTHER FILL_3_NORMAL
 #define FILL_4_OTHER FILL_4_NORMAL
 #define FILL_5_OTHER FILL_5_NORMAL
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/idprom.h linux/include/asm-sparc64/idprom.h
--- v2.1.33/linux/include/asm-sparc64/idprom.h	Fri Dec 13 01:37:47 1996
+++ linux/include/asm-sparc64/idprom.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: idprom.h,v 1.1 1996/11/20 15:33:43 davem Exp $
+/* $Id: idprom.h,v 1.2 1997/04/04 00:50:16 davem Exp $
  * idprom.h: Macros and defines for idprom routines
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,8 @@
 #ifndef _SPARC64_IDPROM_H
 #define _SPARC64_IDPROM_H
 
+#include <linux/types.h>
+
 /* Offset into the EEPROM where the id PROM is located on the 4c */
 #define IDPROM_OFFSET  0x7d8
 
@@ -16,13 +18,13 @@
 
 struct idprom
 {
-	unsigned char	id_format;	/* Format identifier (always 0x01) */
-	unsigned char	id_machtype;	/* Machine type */
-	unsigned char	id_ethaddr[6];	/* Hardware ethernet address */
-	int		id_date;	/* Date of manufacture */
-	unsigned int	id_sernum:24;	/* Unique serial number */
-	unsigned char	id_cksum;	/* Checksum - xor of the data bytes */
-	unsigned char	reserved[16];
+	u8		id_format;	/* Format identifier (always 0x01) */
+	u8		id_machtype;	/* Machine type */
+	u8		id_ethaddr[6];	/* Hardware ethernet address */
+	s32		id_date;	/* Date of manufacture */
+	u32		id_sernum:24;	/* Unique serial number */
+	u8		id_cksum;	/* Checksum - xor of the data bytes */
+	u8		reserved[16];
 };
 
 extern struct idprom *idprom;
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- v2.1.33/linux/include/asm-sparc64/io.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/io.h	Fri Apr 11 10:47:39 1997
@@ -1,8 +1,9 @@
-/* $Id: io.h,v 1.5 1997/03/18 18:04:00 jj Exp $ */
+/* $Id: io.h,v 1.10 1997/04/10 05:13:29 davem Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
 #include <linux/kernel.h>
+#include <linux/types.h>
 
 #include <asm/page.h>      /* IO address mapping routines need this */
 #include <asm/system.h>
@@ -83,24 +84,24 @@
 #define inb_p inb
 #define outb_p outb
 
-extern void sparc_ultra_mapioaddr   (unsigned long physaddr, unsigned long virt_addr, int rdonly);
+extern void sparc_ultra_mapioaddr   (unsigned long physaddr, unsigned long virt_addr,
+				     int bus, int rdonly);
 extern void sparc_ultra_unmapioaddr (unsigned long virt_addr);
 
-extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr, int rdonly)
+extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr,
+				  int bus, int rdonly)
 {
-	sparc_ultra_mapioaddr (physaddr, virt_addr, rdonly);
-	return;
+	sparc_ultra_mapioaddr (physaddr, virt_addr, bus, rdonly);
 }
 
 extern __inline__ void unmapioaddr(unsigned long virt_addr)
 {
 	sparc_ultra_unmapioaddr (virt_addr);
-	return;
 }
 
-extern void *sparc_alloc_io (void *, void *, int, char *, unsigned, int);
-extern void sparc_free_io (void *, int);
-extern void *sparc_dvma_malloc (int, char *);
+extern void *sparc_alloc_io (u32 pa, void *va, int sz, char *name, u32 io, int rdonly);
+extern void sparc_free_io (void *va, int sz);
+extern void *sparc_dvma_malloc (int sz, char *name, __u32 *dvma_addr);
 
 #define virt_to_phys(x) __pa((unsigned long)(x))
 #define phys_to_virt(x) __va((unsigned long)(x))
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/ioctls.h linux/include/asm-sparc64/ioctls.h
--- v2.1.33/linux/include/asm-sparc64/ioctls.h	Fri Dec 13 01:37:47 1996
+++ linux/include/asm-sparc64/ioctls.h	Fri Apr 11 10:47:39 1997
@@ -1,8 +1,13 @@
-/* $Id: ioctls.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */
+/* $Id: ioctls.h,v 1.2 1997/04/04 00:50:18 davem Exp $ */
 #ifndef _ASM_SPARC64_IOCTLS_H
 #define _ASM_SPARC64_IOCTLS_H
 
 #include <asm/ioctl.h>
+
+/* XXX 32-bit binary compatability issues, I am sure that
+ * XXX only IOCTL's which reference structures will be of
+ * XXX concern and these are easily fabricated using wrappers.
+ */
 
 /* Big T */
 #define TCGETA		_IOR('T', 1, struct termio)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/iommu.h linux/include/asm-sparc64/iommu.h
--- v2.1.33/linux/include/asm-sparc64/iommu.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/iommu.h	Fri Apr 11 10:47:39 1997
@@ -6,6 +6,7 @@
 #define _SPARC64_IOMMU_H
 
 #include <asm/page.h>
+#include <asm/sysio.h>
 
 /* The iommu handles all virtual to physical address translations
  * that occur between the SYSIO and physical memory.  Access by
@@ -17,21 +18,6 @@
  */
 
 /* The IOMMU register set. */
-struct iommu_regs {
-	volatile unsigned long		csr;
-	volatile unsigned long		tsb_base;
-	volatile unsigned long		flush;
-	unsigned char _unused0[PAGE_SIZE - 0x18];
-
-	volatile unsigned long		va_diag;
-	volatile unsigned long		tag_compare;
-	unsigned char _unused1[0x100 - 0x10];
-
-	volatile unsigned long		lru_diag[0x80  / 8];
-	volatile unsigned long		tag_diag[0x80  / 8];
-	volatile unsigned long		ram_diag[0x100 / 8];
-};
-
 #define IOMMU_CTRL_IMPL     0xf000000000000000 /* Implementation                */
 #define IOMMU_CTRL_VERS     0x0f00000000000000 /* Version                       */
 #define IOMMU_CTRL_TSBSZ    0x0000000000070000 /* TSB Size                      */
@@ -57,17 +43,12 @@
 #define IOPTE_WRITE         0x0000000000000002 /* Writeable                        */
 
 struct iommu_struct {
-	struct iommu_regs *regs;
+	struct sysio_regs *sysio_regs;
 	iopte_t *page_table;
 
 	/* For convenience */
 	unsigned long start; /* First managed virtual address */
 	unsigned long end;   /* Last managed virtual address */
 };
-
-extern __inline__ void iommu_invalidate_page(struct iommu_regs *regs, unsigned long page)
-{
-	regs->flush = (page & (PAGE_MASK << 3));
-}
 
 #endif /* !(_SPARC_IOMMU_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/ipc.h linux/include/asm-sparc64/ipc.h
--- v2.1.33/linux/include/asm-sparc64/ipc.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/ipc.h	Fri Apr 11 10:47:39 1997
@@ -6,6 +6,7 @@
  *
  * See arch/sparc64/kernel/sys_sparc.c for ugly details..
  */
+/* XXX 32-bit binary compatability... */
 struct ipc_kludge {
 	struct msgbuf *msgp;
 	long msgtyp;
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h
--- v2.1.33/linux/include/asm-sparc64/irq.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/irq.h	Fri Apr 11 10:47:39 1997
@@ -1,11 +1,9 @@
-/* $Id: irq.h,v 1.1 1996/12/26 17:28:13 davem Exp $
+/* $Id: irq.h,v 1.4 1997/04/04 00:50:20 davem Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
-/* XXX Write the sun5 specific code... XXX */
-
 #ifndef _SPARC64_IRQ_H
 #define _SPARC64_IRQ_H
 
@@ -15,27 +13,41 @@
 
 #define NR_IRQS    15
 
-/* Dave Redman (djhr@tadpole.co.uk)
- * changed these to function pointers.. it saves cycles and will allow
- * the irq dependencies to be split into different files at a later date
- * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
- */
-extern void (*disable_irq)(unsigned int);
-extern void (*enable_irq)(unsigned int);
-extern void (*clear_clock_irq)( void );
-extern void (*clear_profile_irq)( void );
-extern void (*load_profile_irq)( unsigned int timeout );
-extern void (*init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *));
-extern void claim_ticker14(void (*irq_handler)(int, void *, struct pt_regs *),
-			   int irq,
-			   unsigned int timeout);
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *));
 
 #ifdef __SMP__
-extern void (*set_cpu_int)(int, int);
-extern void (*clear_cpu_int)(int, int);
-extern void (*set_irq_udt)(int);
+extern void set_cpu_int(int, int);
+extern void clear_cpu_int(int, int);
+extern void set_irq_udt(int);
 #endif
 
-extern int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, __const__ char *devname);
+extern int request_fast_irq(unsigned int irq,
+			    void (*handler)(int, void *, struct pt_regs *),
+			    unsigned long flags, __const__ char *devname);
+
+extern __inline__ void set_softint(unsigned long bits)
+{
+	__asm__ __volatile__("wr	%0, 0x0, %%set_softint"
+			     : /* No outputs */
+			     : "r" (bits));
+}
+
+extern __inline__ void clear_softint(unsigned long bits)
+{
+	__asm__ __volatile__("wr	%0, 0x0, %%clear_softint"
+			     : /* No outputs */
+			     : "r" (bits));
+}
+
+extern __inline__ unsigned long get_softint(void)
+{
+	unsigned long retval;
+
+	__asm__ __volatile__("rd	%%softint, %0"
+			     : "=r" (retval));
+	return retval;
+}
 
 #endif
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/kdebug.h linux/include/asm-sparc64/kdebug.h
--- v2.1.33/linux/include/asm-sparc64/kdebug.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/kdebug.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: kdebug.h,v 1.1 1997/03/14 21:05:34 jj Exp $
+/* $Id: kdebug.h,v 1.2 1997/04/04 00:50:21 davem Exp $
  * kdebug.h:  Defines and definitions for debugging the Linux kernel
  *            under various kernel debuggers.
  *
@@ -8,6 +8,8 @@
 #define _SPARC64_KDEBUG_H
 
 #include <asm/openprom.h>
+
+/* XXX This needs to all be fixed for Ultra/V9 -DaveM */
 
 /* The debugger lives in 1MB of virtual address space right underneath
  * the boot prom.
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/lsu.h linux/include/asm-sparc64/lsu.h
--- v2.1.33/linux/include/asm-sparc64/lsu.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/lsu.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id */
+/* $Id: lsu.h,v 1.2 1997/04/04 00:50:22 davem Exp $ */
 #ifndef _SPARC64_LSU_H
 #define _SPARC64_LSU_H
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/machines.h linux/include/asm-sparc64/machines.h
--- v2.1.33/linux/include/asm-sparc64/machines.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/machines.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: machines.h,v 1.1 1997/03/14 21:05:37 jj Exp $
+/* $Id: machines.h,v 1.2 1997/04/04 00:50:23 davem Exp $
  * machines.h:  Defines for taking apart the machine type value in the
  *              idprom and determining the kind of machine we are on.
  *
@@ -6,6 +6,8 @@
  */
 #ifndef _SPARC64_MACHINES_H
 #define _SPARC64_MACHINES_H
+
+/* XXX This should disappear. -DaveM */
 
 struct Sun_Machine_Models {
 	char *name;
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.1.33/linux/include/asm-sparc64/mmu_context.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/mmu_context.h	Fri Apr 11 10:47:39 1997
@@ -1,34 +1,74 @@
-/* $Id: mmu_context.h,v 1.4 1996/12/28 18:39:51 davem Exp $ */
+/* $Id: mmu_context.h,v 1.7 1997/04/04 00:50:23 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
+/* Derived heavily from Linus's Alpha/AXP ASN code... */
+
 #include <asm/system.h>
 #include <asm/spitfire.h>
 
-#define NO_CONTEXT     -1
+#define NO_CONTEXT     0
 
 #ifndef __ASSEMBLY__
 
 /* Initialize the context related info for a new mm_struct
  * instance.
  */
-#define init_new_context(mm) ((mm)->context = NO_CONTEXT)
+#define init_new_context(mm)	((mm)->context = NO_CONTEXT)
+
+#define destroy_context(mm)	do { } while(0)
+
+extern unsigned long tlb_context_cache;
+
+#define MAX_CTX			PAGE_SIZE
 
-extern void spitfire_get_new_context(struct mm_struct *mm);
+#define CTX_VERSION_SHIFT	PAGE_SHIFT
+#define CTX_VERSION_MASK	((~0UL) << CTX_VERSION_SHIFT)
+#define CTX_FIRST_VERSION	((1UL << CTX_VERSION_SHIFT) + 1UL)
+
+extern __inline__ void get_new_mmu_context(struct mm_struct *mm,
+					   unsigned long ctx)
+{
+	if((ctx & ~CTX_VERSION_MASK) > MAX_CTX) {
+		unsigned long flags;
+		int entry;
+
+		save_and_cli(flags);
+		__asm__ __volatile__("stxa	%%g0, [%0] %1\n\t"
+				     "stxa	%%g0, [%0] %2"
+				     : /* No outputs */
+				     : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU),
+				       "i" (ASI_DMMU));
+		for(entry = 0; entry < 62; entry++) {
+			spitfire_put_dtlb_data(entry, 0x0UL);
+			spitfire_put_itlb_data(entry, 0x0UL);
+		}
+		membar("#Sync");
+		flushi(PAGE_OFFSET);
+		restore_flags(flags);
+
+		ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
+		if(!ctx)
+			ctx = CTX_FIRST_VERSION;
+	}
+	tlb_context_cache = ctx + 1;
+	mm->context = ctx;
+}
 
 extern __inline__ void get_mmu_context(struct task_struct *tsk)
 {
 	struct mm_struct *mm = tsk->mm;
 
-	if(tsk->mm->context == NO_CONTEXT)
-		spitfire_get_new_context(mm);
-
-	/* Get current set of user windows out of the cpu. */
-	flushw_user();
-
-	/* Jump into new ASN. */
-	spitfire_set_primary_context(mm->context);
-	spitfire_set_secondary_context(mm->context);
+	if(mm						&&
+	   !(tsk->tss.flags & SPARC_FLAG_KTHREAD)	&&
+	   !(tsk->flags & PF_EXITING)) {
+		unsigned long ctx = tlb_context_cache;
+
+		flushw_user();
+		if((mm->context ^ ctx) & CTX_VERSION_MASK)
+			get_new_mmu_context(mm, ctx);
+		spitfire_set_secondary_context(mm->context);
+	}
 }
 
 #endif /* !(__ASSEMBLY__) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/mostek.h linux/include/asm-sparc64/mostek.h
--- v2.1.33/linux/include/asm-sparc64/mostek.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/mostek.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: mostek.h,v 1.1 1996/12/26 13:25:22 davem Exp $
+/* $Id: mostek.h,v 1.2 1997/03/25 03:58:30 davem Exp $
  * mostek.h:  Describes the various Mostek time of day clock registers.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -114,7 +114,13 @@
 };
 extern struct mostek48t08 *mstk48t08_regs;
 
-enum sparc_clock_type {	MSTK48T02, MSTK48T08, MSTK_INVALID };
-extern enum sparc_clock_type sp_clock_typ;
+/* SUN5 systems usually have 48t59 model clock chipsets.  But we keep the older
+ * clock chip definitions around just in case.
+ */
+struct mostek48t59 {
+	char offset[6*1024];
+	struct mostek48t02 regs;
+};
+extern struct mostek48t59 *mstk48t59_regs;
 
 #endif /* !(_SPARC64_MOSTEK_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.1.33/linux/include/asm-sparc64/namei.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/namei.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.1 1996/12/26 13:25:22 davem Exp $
+/* $Id: namei.h,v 1.2 1997/03/19 17:28:27 jj Exp $
  * linux/include/asm-sparc64/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -11,46 +11,44 @@
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
-#define gnemul_namei(pathname, base, follow_links, res_inode) ({			\
- if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {	\
-	struct inode *emul_ino;								\
-	int namelen;									\
-	const char *name;								\
-											\
-	while (*pathname == '/')							\
-		pathname++;								\
-	current->fs->root->i_count++;							\
-	if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL,\
-		&namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
-			*res_inode = NULL;						\
-			if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 &&\
-					*res_inode) 					\
-				return 0;						\
-	}										\
-	base = current->fs->root;							\
-	base->i_count++;								\
-  }											\
+#define translate_namei(pathname, base, follow_links, res_inode) ({					\
+	if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {			\
+		struct inode *emul_ino;									\
+		int namelen;										\
+		const char *name;									\
+													\
+		while (*pathname == '/')								\
+			pathname++;									\
+		current->fs->root->i_count++;								\
+		if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, 	\
+				&namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
+			*res_inode = NULL;								\
+			if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) 	\
+				return 0;								\
+		}											\
+		base = current->fs->root;								\
+		base->i_count++;									\
+	}												\
 })
 
-#define gnemul_open_namei(pathname, flag, mode, res_inode, base) ({			\
-  if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {	\
-	struct inode *emul_ino;								\
-	int namelen;									\
-	const char *name;								\
-											\
-	while (*pathname == '/')							\
-		pathname++;								\
-	current->fs->root->i_count++;							\
-	if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL,\
-		  &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
-		*res_inode = NULL;							\
-		if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && 	\
-				*res_inode)						\
-			return 0;							\
-	}										\
-	base = current->fs->root;							\
-	base->i_count++;								\
-  }											\
+#define translate_open_namei(pathname, flag, mode, res_inode, base) ({					\
+	if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {			\
+		struct inode *emul_ino;									\
+		int namelen;										\
+		const char *name;									\
+													\
+		while (*pathname == '/')								\
+			pathname++;									\
+		current->fs->root->i_count++;								\
+		if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, 	\
+				&namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
+			*res_inode = NULL;								\
+			if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode)	\
+				return 0;								\
+		}											\
+		base = current->fs->root;								\
+		base->i_count++;									\
+	}												\
 })
 
 #endif /* __SPARC64_NAMEI_H */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/openprom.h linux/include/asm-sparc64/openprom.h
--- v2.1.33/linux/include/asm-sparc64/openprom.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/openprom.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.3 1997/03/18 18:03:20 jj Exp $ */
+/* $Id: openprom.h,v 1.4 1997/03/24 06:42:08 davem Exp $ */
 #ifndef __SPARC64_OPENPROM_H
 #define __SPARC64_OPENPROM_H
 
@@ -186,9 +186,9 @@
 #define PROMINTR_MAX    15
 
 struct linux_prom_registers {
-	unsigned which_io;         /* hi part of physical address */
-	unsigned phys_addr;   /* The physical address of this register */
-	int reg_size;         /* How many bytes does this register take up? */
+	unsigned which_io;	/* hi part of physical address			*/
+	unsigned phys_addr;	/* The physical address of this register	*/
+	int reg_size;		/* How many bytes does this register take up?	*/
 };
 
 struct linux_prom64_registers {
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h
--- v2.1.33/linux/include/asm-sparc64/oplib.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/oplib.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.6 1997/03/18 18:01:30 jj Exp $
+/* $Id: oplib.h,v 1.7 1997/04/03 09:29:25 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -271,6 +271,9 @@
 			
 extern int prom_pathtoinode(char *path);
 extern int prom_inst2pkg(int);
+
+/* Client interface level routines. */
+extern void prom_set_trap_table(unsigned long tba);
 
 /* Dorking with Bus ranges... */
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.1.33/linux/include/asm-sparc64/page.h	Mon Mar 17 14:54:33 1997
+++ linux/include/asm-sparc64/page.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.5 1997/02/25 20:00:36 jj Exp $ */
+/* $Id: page.h,v 1.8 1997/03/26 12:24:21 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -7,7 +7,13 @@
 
 #ifdef __KERNEL__
 
+#ifndef __ASSEMBLY__
+/* I have my suspicions... -DaveM */
+#define PAGE_SIZE    (1UL << PAGE_SHIFT)
+#else
 #define PAGE_SIZE    (1 << PAGE_SHIFT)
+#endif
+
 #define PAGE_MASK    (~(PAGE_SIZE-1))
 
 #ifndef __ASSEMBLY__
@@ -73,12 +79,21 @@
 
 #endif /* !(__ASSEMBLY__) */
 
+#ifndef __ASSEMBLY__
+#define TASK_UNMAPPED_BASE	0x0000000070000000UL
+#else
 #define TASK_UNMAPPED_BASE	0x0000000070000000
+#endif
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
+#ifndef __ASSEMBLY__
+#define PAGE_OFFSET		0xFFFFF80000000000UL
+#else
 #define PAGE_OFFSET		0xFFFFF80000000000
+#endif
+
 #define __pa(x)			((unsigned long)(x) - PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long) (x) + PAGE_OFFSET))
 #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.33/linux/include/asm-sparc64/pgtable.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/pgtable.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.13 1997/03/13 16:25:05 jj Exp $
+/* $Id: pgtable.h,v 1.27 1997/04/10 23:32:46 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
 #include <asm/system.h>
 
 #ifndef __ASSEMBLY__
+#include <asm/sbus.h>
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
@@ -42,10 +43,15 @@
 #define PTRS_PER_PMD	(1UL << (PAGE_SHIFT-3))
 #define PTRS_PER_PGD	(1UL << (PAGE_SHIFT-3))
 
+#define PTE_TABLE_SIZE	0x2000	/* 1024 entries 8 bytes each */
+#define PMD_TABLE_SIZE	0x2000	/* 1024 entries 8 bytes each */
+#define PGD_TABLE_SIZE	0x2000	/* 1024 entries 8 bytes each */
+
 /* the no. of pointers that fit on a page */
 #define PTRS_PER_PAGE	(1UL << (PAGE_SHIFT-3))
 
-#define VMALLOC_START		0xFFFFFE0000000000UL
+/* NOTE: TLB miss handlers depend heavily upon where this is. */
+#define VMALLOC_START		0xFFFFFc0000000000UL
 #define VMALLOC_VMADDR(x)	((unsigned long)(x))
 
 #endif /* !(__ASSEMBLY__) */
@@ -77,26 +83,36 @@
 #define _PAGE_ACCESSED	0x0000000000000400	/* Accessed Page (ie. referenced)     */
 #define _PAGE_READ	0x0000000000000200	/* Readable SW Bit                    */
 #define _PAGE_WRITE	0x0000000000000100	/* Writable SW Bit                    */
+#define _PAGE_PRIV	0x0000000000000080	/* Software privilege bit	      */
 
 #define _PAGE_CACHE	(_PAGE_CP | _PAGE_CV)
 
 #define __DIRTY_BITS	(_PAGE_MODIFIED | _PAGE_WRITE | _PAGE_W)
 #define __ACCESS_BITS	(_PAGE_ACCESSED | _PAGE_READ | _PAGE_R)
+#define __PRIV_BITS	(_PAGE_P | _PAGE_PRIV)
+
+#define PAGE_NONE	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
+				  __PRIV_BITS | __ACCESS_BITS)
+
+#define PAGE_SHARED	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
+				  __ACCESS_BITS | _PAGE_W | _PAGE_WRITE)
+
+#define PAGE_COPY	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
+				  __ACCESS_BITS)
+
+#define PAGE_READONLY	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
+				  __ACCESS_BITS)
+
+#define PAGE_KERNEL	__pgprot (_PAGE_PRESENT | _PAGE_VALID | _PAGE_CACHE | \
+				  __PRIV_BITS | __ACCESS_BITS | __DIRTY_BITS)
 
-/* David: Please FIXME these. I just define them somehow to get it compile. jj */
-#define PAGE_NONE	__pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_P | _PAGE_G | __ACCESS_BITS)
-#define PAGE_SHARED	__pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_G | __ACCESS_BITS | _PAGE_W | _PAGE_WRITE)
-#define PAGE_COPY	__pgprot (_PAGE_VALID | _PAGE_CACHE | __ACCESS_BITS)
-#define PAGE_READONLY	__pgprot (_PAGE_VALID | _PAGE_CACHE | __ACCESS_BITS)
-#define PAGE_KERNEL	__pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_P | __ACCESS_BITS | __DIRTY_BITS)
 #define PAGE_INVALID	__pgprot (0)
 
 #define _PFN_MASK	_PAGE_PADDR
 
-#define _PAGE_CHG_MASK	(_PFN_MASK | _PAGE_MODIFIED | _PAGE_ACCESSED)
+#define _PAGE_CHG_MASK	(_PFN_MASK | _PAGE_MODIFIED | _PAGE_ACCESSED | _PAGE_PRESENT)
 
-/* FIXME: Define this correctly to io page protection. Has to include side effects. */
-#define pg_iobits (_PAGE_VALID | _PAGE_P | __ACCESS_BITS | _PAGE_E)
+#define pg_iobits (_PAGE_VALID | __PRIV_BITS | __ACCESS_BITS | _PAGE_E)
 
 #define __P000	PAGE_NONE
 #define __P001	PAGE_READONLY
@@ -119,13 +135,28 @@
 #ifndef __ASSEMBLY__
 
 extern pte_t __bad_page(void);
-extern pmd_t *__bad_pagetable(void);
-extern unsigned long __zero_page(void);
+extern pmd_t *__bad_pmd(void);
+extern pte_t *__bad_pte(void);
 
-#define BAD_PAGETABLE	__bad_pagetable()
+#define BAD_PMD		__bad_pmd()
+#define BAD_PTE		__bad_pte()
 #define BAD_PAGE	__bad_page()
 
-#define ZERO_PAGE	PAGE_OFFSET
+/* First phsical page can be anywhere, the following is needed so that
+ * va-->pa and vice versa conversions work properly without performance
+ * hit for all __pa()/__va() operations.
+ */
+extern unsigned long phys_base;
+
+#define ZERO_PAGE	(PAGE_OFFSET + phys_base)
+
+/* This is for making TLB miss faster to process. */
+extern unsigned long null_pmd_table;
+extern unsigned long null_pte_table;
+
+/* Allocate a block of RAM which is aligned to its size.
+   This procedure can be used until the call to mem_init(). */
+extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
 
 /* Cache and TLB flush operations. */
 
@@ -164,7 +195,8 @@
 	bge,pt		%%icc, 1b
 	 add		%2, %1, %0
 "	: "=&r" (page), "=&r" (temp)
-	: "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40));
+	: "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40)
+	: "cc");
 }
 
 extern __inline__ void flush_cache_all(void)
@@ -173,7 +205,6 @@
 
 	flushw_all();
 	for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
-		spitfire_put_dcache_tag(addr, 0x0UL);
 		spitfire_put_icache_tag(addr, 0x0UL);
 		membar("#Sync");
 	}
@@ -189,14 +220,13 @@
 
 		flushw_user();
 		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
-			spitfire_put_dcache_tag(addr, 0x0UL);
 			spitfire_put_icache_tag(addr, 0x0UL);
 			membar("#Sync");
 		}
-	}
 
-	/* Kill the pipeline. */
-	flushi(PAGE_OFFSET);
+		/* Kill the pipeline. */
+		flushi(PAGE_OFFSET);
+	}
 }
 
 extern __inline__ void flush_cache_range(struct mm_struct *mm, unsigned long start,
@@ -220,14 +250,17 @@
 {
 	struct mm_struct *mm = vma->vm_mm;
 
-	if(mm->context != NO_CONTEXT && (vma->vm_flags & VM_EXEC)) {
-		int ctx;
+	if(mm->context != NO_CONTEXT) {
+		unsigned long addr;
 
-		ctx = spitfire_get_primary_context();
 		flushw_user();
-		spitfire_set_primary_context(mm->context);
-		spitfire_flush_icache_page(page & PAGE_MASK);
-		spitfire_set_primary_context(ctx);
+		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+			spitfire_put_icache_tag(addr, 0x0UL);
+			membar("#Sync");
+		}
+
+		/* Kill the pipeline. */
+		flushi(PAGE_OFFSET);
 	}
 }
 
@@ -236,27 +269,36 @@
 
 extern __inline__ void flush_tlb_all(void)
 {
+	unsigned long flags;
 	int entry;
 
 	/* Invalidate all non-locked TTE's in both the dtlb and itlb. */
-	for(entry = 0; entry < 64; entry++) {
-		unsigned long dtag, itag;
-
-		dtag = spitfire_get_dtlb_data(entry);
-		itag = spitfire_get_itlb_data(entry);
-		if(!(dtag & _PAGE_L))
-			spitfire_put_dtlb_data(entry, 0x0UL);
-		if(!(itag & _PAGE_L))
-			spitfire_put_itlb_data(entry, 0x0UL);
+	save_and_cli(flags);
+	__asm__ __volatile__("stxa	%%g0, [%0] %1\n\t"
+			     "stxa	%%g0, [%0] %2"
+			     : /* No outputs */
+			     : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU), "i" (ASI_DMMU));
+	for(entry = 0; entry < 62; entry++) {
+		spitfire_put_dtlb_data(entry, 0x0UL);
+		spitfire_put_itlb_data(entry, 0x0UL);
 	}
+	membar("#Sync");
+	flushi(PAGE_OFFSET);
+	restore_flags(flags);
 }
 
 extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
 {
 	if(mm->context != NO_CONTEXT) {
+		unsigned long orig_ctx = spitfire_get_secondary_context();
+		unsigned long flags;
+
+		save_and_cli(flags);
 		spitfire_set_secondary_context(mm->context);
 		spitfire_flush_dtlb_secondary_context();
 		spitfire_flush_itlb_secondary_context();
+		spitfire_set_secondary_context(orig_ctx);
+		restore_flags(flags);
 	}
 }
 
@@ -264,13 +306,19 @@
 				       unsigned long end)
 {
 	if(mm->context != NO_CONTEXT) {
+		unsigned long old_ctx = spitfire_get_secondary_context();
+		unsigned long flags;
+
 		start &= PAGE_MASK;
+		save_and_cli(flags);
 		spitfire_set_secondary_context(mm->context);
 		while(start < end) {
 			spitfire_flush_dtlb_secondary_page(start);
 			spitfire_flush_itlb_secondary_page(start);
 			start += PAGE_SIZE;
 		}
+		spitfire_set_secondary_context(old_ctx);
+		restore_flags(flags);
 	}
 }
 
@@ -279,16 +327,22 @@
 	struct mm_struct *mm = vma->vm_mm;
 
 	if(mm->context != NO_CONTEXT) {
+		unsigned long old_ctx = spitfire_get_secondary_context();
+		unsigned long flags;
+
 		page &= PAGE_MASK;
+		save_and_cli(flags);
 		spitfire_set_secondary_context(mm->context);
 		if(vma->vm_flags & VM_EXEC)
 			spitfire_flush_itlb_secondary_page(page);
 		spitfire_flush_dtlb_secondary_page(page);
+		spitfire_set_secondary_context(old_ctx);
+		restore_flags(flags);
 	}
 }
 
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ return __pte((page - PAGE_OFFSET) | pgprot_val(pgprot)); }
+{ return __pte(__pa(page) | pgprot_val(pgprot)); }
 
 extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 { return __pte(physpage | pgprot_val(pgprot)); }
@@ -297,33 +351,33 @@
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
 extern inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
-{ pmd_val(*pmdp) = ((unsigned long) ptep) - PAGE_OFFSET; }
+{ pmd_val(*pmdp) = __pa((unsigned long) ptep); }
 
 extern inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp)
-{ pgd_val(*pgdp) = ((unsigned long) pmdp) - PAGE_OFFSET; }
+{ pgd_val(*pgdp) = __pa((unsigned long) pmdp); }
 
 extern inline unsigned long pte_page(pte_t pte)
-{ return PAGE_OFFSET + (pte_val(pte) & _PFN_MASK); }
+{ return (unsigned long) __va((pte_val(pte) & _PFN_MASK)); }
 
 extern inline unsigned long pmd_page(pmd_t pmd)
-{ return (pmd_val(pmd) + PAGE_OFFSET); }
+{ return (unsigned long) __va(pmd_val(pmd)); }
 
 extern inline unsigned long pgd_page(pgd_t pgd)
-{ return (pgd_val(pgd) + PAGE_OFFSET); }
+{ return (unsigned long) __va(pgd_val(pgd)); }
 
 extern inline int pte_none(pte_t pte) 		{ return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
 extern inline void pte_clear(pte_t *pte)	{ pte_val(*pte) = 0; }
 
-extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+extern inline int pmd_none(pmd_t pmd)		{ return pmd_val(pmd)==null_pte_table; }
 extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK); }
-extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd); }
-extern inline void pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
+extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd)!=null_pte_table; }
+extern inline void pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = null_pte_table; }
 
-extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
+extern inline int pgd_none(pgd_t pgd)		{ return pgd_val(pgd)==null_pmd_table; }
 extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~PAGE_MASK); }
-extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd); }
-extern inline void pgd_clear(pgd_t *pgdp)	{ pgd_val(*pgdp) = 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd)!=null_pmd_table; }
+extern inline void pgd_clear(pgd_t *pgdp)	{ pgd_val(*pgdp) = null_pmd_table; }
 
 /* The following only work if pte_present() is true.
  * Undefined behaviour if not..
@@ -358,7 +412,7 @@
 	if(pte_val(pte) & _PAGE_WRITE)
 		return __pte(pte_val(pte) | (_PAGE_MODIFIED | _PAGE_W));
 	else
-		return __pte(pte_val(pte) | _PAGE_MODIFIED);
+		return __pte(pte_val(pte) | (_PAGE_MODIFIED));
 }
 
 extern inline pte_t pte_mkyoung(pte_t pte)
@@ -366,14 +420,14 @@
 	if(pte_val(pte) & _PAGE_READ)
 		return __pte(pte_val(pte) | (_PAGE_ACCESSED | _PAGE_R));
 	else
-		return __pte(pte_val(pte) | _PAGE_ACCESSED);
+		return __pte(pte_val(pte) | (_PAGE_ACCESSED));
 }
 
 extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
 {
 	register unsigned long paddr asm("o5");
 
-	paddr = ((unsigned long) pgdir) - PAGE_OFFSET;
+	paddr = __pa(pgdir);
 
 	if(tsk->mm == current->mm) {
 		__asm__ __volatile__ ("
@@ -381,7 +435,8 @@
 			wrpr		%%o4, %1, %%pstate
 			mov		%0, %%g7
 			wrpr		%%o4, 0x0, %%pstate
-		" : : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
+		" : /* No outputs */
+		  : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
 		  : "o4");
 	}
 }
@@ -401,6 +456,13 @@
 extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
 { return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1)); }
 
+extern __inline__ void __init_pmd(pmd_t *pmdp)
+{
+	extern void __bfill64(void *, unsigned long);
+	
+	__bfill64((void *)pmdp, null_pte_table);
+}
+
 /* Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on supervisor
  * bits if any.
@@ -418,14 +480,14 @@
 				pmd_set(pmd, page);
 				return page + address;
 			}
-			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			pmd_set(pmd, BAD_PTE);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
 	if (pmd_bad(*pmd)) {
 		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		pmd_set(pmd, BAD_PTE);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -441,17 +503,18 @@
 		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
 		if (pgd_none(*pgd)) {
 			if (page) {
+				__init_pmd(page);
 				pgd_set(pgd, page);
 				return page + address;
 			}
-			pgd_set(pgd, BAD_PAGETABLE);
+			pgd_set(pgd, BAD_PMD);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
 	if (pgd_bad(*pgd)) {
 		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, BAD_PAGETABLE);
+		pgd_set(pgd, BAD_PMD);
 		return NULL;
 	}
 	return (pmd_t *) pgd_page(*pgd) + address;
@@ -470,14 +533,14 @@
 				pmd_set(pmd, page);
 				return page + address;
 			}
-			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			pmd_set(pmd, BAD_PTE);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
 	if (pmd_bad(*pmd)) {
 		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		pmd_set(pmd, BAD_PTE);
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
@@ -493,17 +556,18 @@
 		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
 		if (pgd_none(*pgd)) {
 			if (page) {
+				__init_pmd(page);
 				pgd_set(pgd, page);
 				return page + address;
 			}
-			pgd_set(pgd, BAD_PAGETABLE);
+			pgd_set(pgd, BAD_PMD);
 			return NULL;
 		}
 		free_page((unsigned long) page);
 	}
 	if (pgd_bad(*pgd)) {
 		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, BAD_PAGETABLE);
+		pgd_set(pgd, BAD_PMD);
 		return NULL;
 	}
 	return (pmd_t *) pgd_page(*pgd) + address;
@@ -513,10 +577,34 @@
 { free_page((unsigned long)pgd); }
 
 extern inline pgd_t * pgd_alloc(void)
-{ return (pgd_t *) get_free_page(GFP_KERNEL); }
+{
+	extern void __bfill64(void *, unsigned long);
+	pgd_t *pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
+	
+	if (pgd)
+		__bfill64((void *)pgd, null_pmd_table);
+	return pgd;
+}
 
 extern pgd_t swapper_pg_dir[1024];
 
+/* Routines for getting a dvma scsi buffer. */
+struct mmu_sglist {
+	char *addr;
+	char *__dont_touch;
+	unsigned int len;
+	__u32 dvma_addr;
+};
+
+extern __u32 mmu_get_scsi_one(char *, unsigned long, struct linux_sbus *sbus);
+extern void  mmu_get_scsi_sgl(struct mmu_sglist *, int, struct linux_sbus *sbus);
+
+/* These do nothing with the way I have things setup. */
+#define mmu_release_scsi_one(vaddr, len, sbus)	do { } while(0)
+#define mmu_release_scsi_sgl(sg, sz, sbus)	do { } while(0)
+#define mmu_lockarea(vaddr, len)		(vaddr)
+#define mmu_unlockarea(vaddr, len)		do { } while(0)
+
 extern inline void update_mmu_cache(struct vm_area_struct * vma,
 	unsigned long address, pte_t pte)
 {
@@ -576,44 +664,14 @@
 
 /* Make a non-present pseudo-TTE. */
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
-{ pte_t pte; pte_val(pte) = (type) | (offset << 8); return pte; }
+{ pte_t pte; pte_val(pte) = (type<<PAGE_SHIFT)|(offset<<(PAGE_SHIFT+8)); return pte; }
 
 extern inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space)
-/* FIXME. How is space added to the address??? */
 { pte_t pte; pte_val(pte) = (page) | pgprot_val(prot); return pte; }
 
-
-#define SWP_TYPE(entry)		(((entry) & 0xff))
-#define SWP_OFFSET(entry)	((entry) >> 8)
+#define SWP_TYPE(entry)		(((entry>>PAGE_SHIFT) & 0xff))
+#define SWP_OFFSET(entry)	((entry) >> (PAGE_SHIFT+8))
 #define SWP_ENTRY(type,offset)	pte_val(mk_swap_pte((type),(offset)))
-
-struct ctx_list {
-	struct ctx_list *next;
-	struct ctx_list *prev;
-	unsigned int ctx_number;
-	struct mm_struct *ctx_mm;
-};
-
-extern struct ctx_list *ctx_list_pool;  /* Dynamically allocated */
-extern struct ctx_list ctx_free;        /* Head of free list */
-extern struct ctx_list ctx_used;        /* Head of used contexts list */
-
-#define NO_CONTEXT     -1
-
-extern __inline__ void remove_from_ctx_list(struct ctx_list *entry)
-{
-	entry->next->prev = entry->prev;
-	entry->prev->next = entry->next;
-}
-
-extern __inline__ void add_to_ctx_list(struct ctx_list *head, struct ctx_list *entry)
-{
-	entry->next = head;
-	(entry->prev = head->prev)->next = entry;
-	head->prev = entry;
-}
-#define add_to_free_ctxlist(entry) add_to_ctx_list(&ctx_free, entry)
-#define add_to_used_ctxlist(entry) add_to_ctx_list(&ctx_used, entry)
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/posix_types.h linux/include/asm-sparc64/posix_types.h
--- v2.1.33/linux/include/asm-sparc64/posix_types.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/posix_types.h	Fri Apr 11 10:47:39 1997
@@ -9,25 +9,25 @@
 
 typedef unsigned long long     __kernel_size_t;
 
-typedef int                    __kernel_ssize_t;
-typedef unsigned long long int __kernel_ptrdiff_t;
+typedef long long              __kernel_ssize_t;
+typedef long                   __kernel_ptrdiff_t;
 typedef long                   __kernel_time_t;
 typedef long                   __kernel_clock_t;
 typedef int                    __kernel_pid_t;
-typedef unsigned short         __kernel_ipc_pid_t;
-typedef unsigned short         __kernel_uid_t;
-typedef unsigned short         __kernel_gid_t;
-typedef unsigned short         __kernel_dev_t;
-typedef unsigned long          __kernel_ino_t;
-typedef unsigned short         __kernel_mode_t;
+typedef int                    __kernel_ipc_pid_t;
+typedef unsigned int           __kernel_uid_t;
+typedef unsigned int           __kernel_gid_t;
+typedef unsigned int           __kernel_dev_t;
+typedef unsigned int           __kernel_ino_t;
+typedef unsigned int           __kernel_mode_t;
 typedef unsigned short         __kernel_umode_t;
-typedef short                  __kernel_nlink_t;
-typedef long                   __kernel_daddr_t;
+typedef unsigned int           __kernel_nlink_t;
+typedef int                    __kernel_daddr_t;
 typedef long                   __kernel_off_t;
 typedef char *                 __kernel_caddr_t;
 
 #ifdef __GNUC__
-typedef long long	__kernel_loff_t;
+typedef long long              __kernel_loff_t;
 #endif
 
 typedef struct {
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.1.33/linux/include/asm-sparc64/processor.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/processor.h	Mon Apr 14 09:31:09 1997
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.10 1997/03/14 21:05:39 jj Exp $
+/* $Id: processor.h,v 1.20 1997/04/11 22:34:54 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -10,7 +10,6 @@
 #include <asm/a.out.h>
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
-#include <asm/head.h>
 #include <asm/signal.h>
 #include <asm/segment.h>
 
@@ -24,19 +23,11 @@
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
-/* Whee, this is STACK_TOP + PAGE_SIZE and the lowest kernel address too... 
- * That one page is used to protect kernel from intruders, so that
- * we can make our access_ok test faster
- */
-#define TASK_SIZE	(0xFFFFF80000000000UL)
+/* User lives in his very own context, and cannot reference us. */
+#define TASK_SIZE	((1UL << (PAGE_SHIFT - 3)) * PGDIR_SIZE)
 
 #ifndef __ASSEMBLY__
 
-struct fpq {
-	unsigned long *insn_addr;
-	unsigned long insn;
-};
-
 #define NSWINS		8
 
 /* The Sparc processor specific thread struct. */
@@ -48,12 +39,9 @@
 	   is multiplied by 512 to get the amount of wasted kernel memory. */
 	unsigned int    float_regs[64] __attribute__ ((aligned (64)));
 	unsigned long   fsr;
-	unsigned long   fpqdepth;
-	struct fpq	fpqueue[16];
 	
 	/* Context switch saved kernel state. */
-	unsigned long user_globals[8];		/* performance hack */
-	unsigned long ksp, kpc;
+	unsigned long ksp, kpc, wstate, cwp;
 
 	/* Storage for windows when user stack is bogus. */
 	struct reg_window reg_window[NSWINS] __attribute__ ((aligned (16)));
@@ -82,7 +70,7 @@
 #define SPARC_FLAG_NEWSIGNALS   0x4    /* task wants new-style signals */
 #define SPARC_FLAG_32BIT        0x8    /* task is older 32-bit binary */
 
-#define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffffe00000, \
+#define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \
 		    PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC }
 
 #define INIT_TSS  {							\
@@ -90,12 +78,10 @@
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	\
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	\
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },	\
-/* FPU status, FPU qdepth, FPU queue */ 				\
-   0,          0,          { { 0, 0, }, }, 				\
-/* user_globals */ 							\
-   { 0, 0, 0, 0, 0, 0, 0, 0 }, 						\
-/* ksp, kpc */ 								\
-   0,   0, 								\
+/* FPU status */ 							\
+   0, 									\
+/* ksp, kpc, wstate, cwp */ 						\
+   0,   0,   0,	     0,							\
 /* reg_window */							\
 { { { 0, }, { 0, } }, }, 						\
 /* rwbuf_stkptrs */							\
@@ -123,79 +109,85 @@
 }
 
 /* Do necessary setup to start up a newly executed thread. */
-extern __inline__ void start_thread(struct pt_regs *regs, unsigned long pc,
-				    unsigned long sp)
-{
-	regs->tstate = (regs->tstate & (TSTATE_CWP)) | TSTATE_IE;
-	regs->tpc = ((pc & (~3)) - 4);
-	regs->tnpc = regs->tpc + 4;
-	regs->y = 0;
-	__asm__ __volatile__("
-		stx		%%g0, [%0 + %2 + 0x00]
-		stx		%%g0, [%0 + %2 + 0x08]
-		stx		%%g0, [%0 + %2 + 0x10]
-		stx		%%g0, [%0 + %2 + 0x18]
-		stx		%%g0, [%0 + %2 + 0x20]
-		stx		%%g0, [%0 + %2 + 0x28]
-		stx		%%g0, [%0 + %2 + 0x30]
-		stx		%%g0, [%0 + %2 + 0x38]
-		stx		%%g0, [%0 + %2 + 0x40]
-		stx		%%g0, [%0 + %2 + 0x48]
-		stx		%%g0, [%0 + %2 + 0x50]
-		stx		%%g0, [%0 + %2 + 0x58]
-		stx		%%g0, [%0 + %2 + 0x60]
-		stx		%%g0, [%0 + %2 + 0x68]
-		stx		%1,   [%0 + %2 + 0x70]
-		stx		%%g0, [%0 + %2 + 0x78]
-		" : : "r" (regs), "r" (sp - REGWIN_SZ),
-		      "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])));
-}
-
-extern __inline__ void start_thread32(struct pt_regs *regs, unsigned long pc,
-				      unsigned long sp)
-{
-	register unsigned int zero asm("g1");
-
-	pc &= 0x00000000ffffffffUL;
-	sp &= 0x00000000ffffffffUL;
-
-	regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_IE | TSTATE_AM);
-	regs->tpc = ((pc & (~3)) - 4);
-	regs->tnpc = regs->tpc + 4;
-	regs->y = 0;
-	zero = 0;
-	__asm__ __volatile__("
-		stx		%%g0, [%0 + %2 + 0x00]
-		stx		%%g0, [%0 + %2 + 0x08]
-		stx		%%g0, [%0 + %2 + 0x10]
-		stx		%%g0, [%0 + %2 + 0x18]
-		stx		%%g0, [%0 + %2 + 0x20]
-		stx		%%g0, [%0 + %2 + 0x28]
-		stx		%%g0, [%0 + %2 + 0x30]
-		stx		%%g0, [%0 + %2 + 0x38]
-		stx		%%g0, [%0 + %2 + 0x40]
-		stx		%%g0, [%0 + %2 + 0x48]
-		stx		%%g0, [%0 + %2 + 0x50]
-		stx		%%g0, [%0 + %2 + 0x58]
-		stx		%%g0, [%0 + %2 + 0x60]
-		stx		%%g0, [%0 + %2 + 0x68]
-		stx		%1,   [%0 + %2 + 0x70]
-		stx		%%g0, [%0 + %2 + 0x78]
-		" : : "r" (regs), "r" (sp - REGWIN32_SZ),
-		      "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])),
-		      "r" (zero));
-}
+#define start_thread(regs, pc, sp) \
+do { \
+	regs->tstate = (regs->tstate & (TSTATE_CWP)) | TSTATE_IE; \
+	regs->tpc = ((pc & (~3)) - 4); \
+	regs->tnpc = regs->tpc + 4; \
+	regs->y = 0; \
+	__asm__ __volatile__( \
+	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x08]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x10]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x18]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x20]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x28]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x30]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x38]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x40]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x48]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x50]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x58]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x60]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x68]\n\t" \
+	"stx		%1,   [%0 + %2 + 0x70]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
+	: \
+	: "r" (regs), "r" (sp - REGWIN_SZ), \
+	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
+} while(0)
+
+#define start_thread32(regs, pc, sp) \
+do { \
+	register unsigned int zero asm("g1"); \
+\
+	pc &= 0x00000000ffffffffUL; \
+	sp &= 0x00000000ffffffffUL; \
+\
+	regs->tstate = (regs->tstate & (TSTATE_CWP)) | (TSTATE_IE | TSTATE_AM); \
+	regs->tpc = ((pc & (~3)) - 4); \
+	regs->tnpc = regs->tpc + 4; \
+	regs->y = 0; \
+	current->tss.flags |= SPARC_FLAG_32BIT; \
+	zero = 0; \
+	__asm__ __volatile__( \
+	"stx		%%g0, [%0 + %2 + 0x00]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x08]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x10]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x18]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x20]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x28]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x30]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x38]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x40]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x48]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x50]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x58]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x60]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x68]\n\t" \
+	"stx		%1,   [%0 + %2 + 0x70]\n\t" \
+	"stx		%%g0, [%0 + %2 + 0x78]\n\t" \
+	: \
+	: "r" (regs), "r" (sp - REGWIN32_SZ), \
+	  "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0])), \
+	  "r" (zero)); \
+} while(0)
 
 /* Free all resources held by a thread. */
 #define release_thread(tsk)		do { } while(0)
 
 #ifdef __KERNEL__
 /* Allocation and freeing of basic task resources. */
+
+/* XXX FIXME For task_struct must use SLAB or something other than
+ * XXX kmalloc() as FPU registers in TSS require that entire structure
+ * XXX be 64-byte aligned as well.
+ */
 #define alloc_kernel_stack(tsk)		__get_free_page(GFP_KERNEL)
 #define free_kernel_stack(stack)	free_page(stack)
 #define alloc_task_struct()		kmalloc(sizeof(struct task_struct), GFP_KERNEL)
 #define free_task_struct(tsk)		kfree(tsk)
-#endif
+#endif /* __KERNEL__ */
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/psrcompat.h linux/include/asm-sparc64/psrcompat.h
--- v2.1.33/linux/include/asm-sparc64/psrcompat.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/psrcompat.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: psrcompat.h,v 1.1 1996/12/26 10:02:30 davem Exp $ */
+/* $Id: psrcompat.h,v 1.2 1997/04/07 18:57:17 jj Exp $ */
 #ifndef _SPARC64_PSRCOMPAT_H
 #define _SPARC64_PSRCOMPAT_H
 
@@ -36,7 +36,7 @@
 	psr |= ((tstate & TSTATE_ICC) >> 12);
 
 	/* This is completely arbitrary. */
-	__asm__ __volatile__("rdpr	%vers, %0" : "=r" (vers));
+	__asm__ __volatile__("rdpr	%%ver, %0" : "=r" (vers));
 	psr |= ((vers << 8) >> 32) & PSR_IMPL;
 	psr |= ((vers << 24) >> 36) & PSR_VERS;
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/pstate.h linux/include/asm-sparc64/pstate.h
--- v2.1.33/linux/include/asm-sparc64/pstate.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/pstate.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: pstate.h,v 1.2 1996/12/26 09:56:16 davem Exp $ */
+/* $Id: pstate.h,v 1.3 1997/03/25 03:58:31 davem Exp $ */
 #ifndef _SPARC64_PSTATE_H
 #define _SPARC64_PSTATE_H
 
@@ -21,10 +21,10 @@
 #define PSTATE_IE	0x0000000000000002	/* Interrupt Enable.		*/
 #define PSTATE_AG	0x0000000000000001	/* Alternate Globals.		*/
 
-/* The V9 TSTATE Register (with SpitFire extensions).
+/* The V9 TSTATE Register (with SpitFire and Linux extensions).
  *
  * ---------------------------------------------------------------
- * |  Resv  |  CCR  |  ASI  |  Resv  |  PSTATE  |  Resv  |  CWP  |
+ * |  Resv  |  CCR  |  ASI  |  %pil  |  PSTATE  |  Resv  |  CWP  |
  * ---------------------------------------------------------------
  *  63    40 39   32 31   24 23    20 19       8 7      5 4     0
  */
@@ -40,6 +40,7 @@
 #define TSTATE_IOVFL	0x0000000200000000	/* %icc Overflow.		*/
 #define TSTATE_ICARRY	0x0000000100000000	/* %icc Carry.			*/
 #define TSTATE_ASI	0x00000000ff000000	/* Address Space Identifier.	*/
+#define TSTATE_PIL	0x0000000000f00000	/* %pil (Linux traps set this)  */
 #define TSTATE_PSTATE	0x00000000000fff00	/* PSTATE.			*/
 #define TSTATE_IG	0x0000000000080000	/* Interrupt Globals.		*/
 #define TSTATE_MG	0x0000000000040000	/* MMU Globals.			*/
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/resource.h linux/include/asm-sparc64/resource.h
--- v2.1.33/linux/include/asm-sparc64/resource.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/resource.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: resource.h,v 1.1 1996/12/26 14:22:34 davem Exp $
+/* $Id: resource.h,v 1.2 1997/04/04 00:50:27 davem Exp $
  * resource.h: Resource definitions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -25,7 +25,7 @@
 #define RLIM_NLIMITS	10
 
 #ifdef __KERNEL__
-
+/* XXX 32-bit binary compatability... */
 #define INIT_RLIMITS							\
 {									\
     {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/sbus.h linux/include/asm-sparc64/sbus.h
--- v2.1.33/linux/include/asm-sparc64/sbus.h	Mon Mar 17 14:54:34 1997
+++ linux/include/asm-sparc64/sbus.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.2 1997/02/25 20:00:35 jj Exp $
+/* $Id: sbus.h,v 1.3 1997/03/21 17:57:24 jj Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -19,8 +19,8 @@
  */
 
 /* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR        0xf8000000
-#define SBUS_OFF_MASK          0x01ffffff
+#define SUN_SBUS_BVADDR        0x00000000
+#define SBUS_OFF_MASK          0x0fffffff
 
 /* These routines are used to calculate device address from slot
  * numbers + offsets, and vice versa.
@@ -28,12 +28,12 @@
 
 extern __inline__ unsigned long sbus_devaddr(int slotnum, unsigned long offset)
 {
-  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
+  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset));
 }
 
 extern __inline__ int sbus_dev_slot(unsigned long dev_addr)
 {
-  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
+  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28);
 }
 
 extern __inline__ unsigned long sbus_dev_offset(unsigned long dev_addr)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/scatterlist.h linux/include/asm-sparc64/scatterlist.h
--- v2.1.33/linux/include/asm-sparc64/scatterlist.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/scatterlist.h	Fri Apr 11 10:47:39 1997
@@ -1,4 +1,4 @@
-/* $Id: scatterlist.h,v 1.1 1996/12/26 14:22:32 davem Exp $ */
+/* $Id: scatterlist.h,v 1.4 1997/04/10 05:13:32 davem Exp $ */
 #ifndef _SPARC64_SCATTERLIST_H
 #define _SPARC64_SCATTERLIST_H
 
@@ -10,9 +10,9 @@
 			 * dma indirect buffer.  NULL otherwise */
     unsigned int length;
 
-    char * dvma_address; /* A place to hang host-specific addresses at. */
+    __u32 dvma_address; /* A place to hang host-specific addresses at. */
 };
 
-#define ISA_DMA_THRESHOLD ((0x100000000) + PAGE_OFFSET)
+#define ISA_DMA_THRESHOLD ((0xf0000000) + PAGE_OFFSET)
 
 #endif /* !(_SPARC64_SCATTERLIST_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- v2.1.33/linux/include/asm-sparc64/semaphore.h	Mon Mar 17 14:54:34 1997
+++ linux/include/asm-sparc64/semaphore.h	Mon Apr 14 09:31:09 1997
@@ -11,19 +11,27 @@
 	struct wait_queue * wait;
 };
 
-#define MUTEX ((struct semaphore) { 1, 0, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+#define MUTEX ((struct semaphore) { { 1 }, { 0 }, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL })
 
 extern void __down(struct semaphore * sem);
+extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
+#define sema_init(sem, val)	atomic_set(&((sem)->count), val)
+
 extern __inline__ void down(struct semaphore * sem)
 {
-	for (;;) {
-		if (atomic_dec_return(&sem->count) >= 0)
-			break;
+	if (atomic_dec_return(&sem->count) < 0)
 		__down(sem);
-	}
+}
+
+extern __inline__ int down_interruptible(struct semaphore *sem)
+{
+	int ret = 0;
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_interruptible(sem);
+	return ret;
 }
 
 extern __inline__ void up(struct semaphore * sem)
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/sigcontext.h linux/include/asm-sparc64/sigcontext.h
--- v2.1.33/linux/include/asm-sparc64/sigcontext.h	Mon Mar 17 14:54:34 1997
+++ linux/include/asm-sparc64/sigcontext.h	Fri Apr 11 10:47:39 1997
@@ -1,8 +1,13 @@
-/* $Id: sigcontext.h,v 1.3 1997/03/03 16:51:55 jj Exp $ */
+/* $Id: sigcontext.h,v 1.4 1997/04/04 00:50:28 davem Exp $ */
 #ifndef __SPARC64_SIGCONTEXT_H
 #define __SPARC64_SIGCONTEXT_H
 
 #include <asm/ptrace.h>
+
+/* XXX This gets exported to userland as well as kernel, it is probably
+ * XXX riddled with many hard to find 32-bit binary compatability issues.
+ * XXX Signals and this file need to be investigated heavily. -DaveM
+ */
 
 #define SUNOS_MAXWIN   31
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.1.33/linux/include/asm-sparc64/smp.h	Mon Mar 17 14:54:34 1997
+++ linux/include/asm-sparc64/smp.h	Fri Apr 11 10:47:39 1997
@@ -19,6 +19,7 @@
 };
 
 extern int linux_num_cpus;	/* number of CPUs probed  */
+extern struct prom_cpuinfo linux_cpus[NCPUS];
 
 #endif /* !(__ASSEMBLY__) */
 
@@ -26,8 +27,6 @@
 
 #ifndef __ASSEMBLY__
 
-extern struct prom_cpuinfo linux_cpus[NCPUS];
-
 /* Per processor Sparc parameters we need. */
 
 struct cpuinfo_sparc {
@@ -71,8 +70,6 @@
 extern void smp_store_cpu_info(int id);
 extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
 			   unsigned long arg3, unsigned long arg4, unsigned long arg5);
-extern void smp_capture(void);
-extern void smp_release(void);
 
 extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
 extern __inline__ void xc1(smpfunc_t func, unsigned long arg1)
@@ -126,7 +123,8 @@
 2:
 	membar		#StoreStore | #StoreLoad
 " 	: "=&r" (temp0), "=&r" (temp1), "=r" (ctr)
-	: "ir" (i), "r" (ctr));
+	: "ir" (i), "r" (ctr)
+	: "cc");
 }
 
 extern __inline__ __volatile__ void dec_smp_counter(volatile int *ctr)
@@ -144,7 +142,8 @@
 2:
 	membar		#StoreStore | #StoreLoad
 " 	: "=&r" (temp0), "=&r" (temp1), "=r" (ctr)
-	: "ir" (i), "r" (ctr));
+	: "ir" (i), "r" (ctr)
+	: "cc");
 }
 
 extern __inline__ __volatile__ int read_smp_counter(volatile int *ctr)
@@ -155,7 +154,6 @@
 #endif /* !(__ASSEMBLY__) */
 
 /* Sparc specific messages. */
-#define MSG_CAPTURE            0x0004       /* Park a processor. */
 #define MSG_CROSS_CALL         0x0005       /* run func on cpus */
 
 /* Empirical PROM processor mailbox constants.  If the per-cpu mailbox
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/smp_lock.h linux/include/asm-sparc64/smp_lock.h
--- v2.1.33/linux/include/asm-sparc64/smp_lock.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/smp_lock.h	Fri Apr 11 10:47:40 1997
@@ -11,53 +11,14 @@
 #include <asm/pgtable.h>
 
 #ifndef __SMP__
-#define lock_kernel()           do { } while(0)
-#define unlock_kernel()         do { } while(0)
-#else
-
-extern __inline__ __volatile__ unsigned char ldstub(volatile unsigned char *lock)
-{
-	volatile unsigned char retval;
-
-	__asm__ __volatile__("ldstub [%1], %0" : "=&r" (retval) : "r" (lock));
-	return retval;
-}
-
-/*
- *	Locking the kernel 
- */
 
-/* Knock knock... */
-extern __inline__ void lock_kernel(void)
-{
-	int proc = smp_processor_id();
-
-	while(ldstub(&kernel_flag)) {
-		if(proc == active_kernel_processor)
-			break;
-		do {
-#ifdef __SMP_PROF__		
-			smp_spins[smp_processor_id()]++;
-#endif			
-			barrier();
-		} while(kernel_flag); /* Don't lock the bus more than we have to. */
-	}
-	active_kernel_processor = proc;
-	kernel_counter++;
-}
-
-/* I want out... */
-extern __inline__ void unlock_kernel(void)
-{
-	if(kernel_counter == 0)
-		panic("Bogus kernel counter.\n");
-
-	if(!--kernel_counter) {
-		active_kernel_processor = NO_PROC_ID;
-		kernel_flag = KLOCK_CLEAR;
-	}
-}
+#define lock_kernel()				do { } while(0)
+#define unlock_kernel()				do { } while(0)
+#define release_kernel_lock(task, cpu, depth)	((depth) = 1)
+#define reaquire_kernel_lock(task, cpu, depth)	do { } while(0)
 
+#else
+#error SMP on sparc64 not supported yet
 #endif /* (__SMP__) */
 
 #endif /* !(__SPARC64_SMPLOCK_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h
--- v2.1.33/linux/include/asm-sparc64/softirq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/softirq.h	Mon Apr 14 09:31:09 1997
@@ -0,0 +1,58 @@
+/* softirq.h: 64-bit Sparc soft IRQ support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_SOFTIRQ_H
+#define __SPARC64_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+/* The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+extern atomic_t __sparc64_bh_counter;
+
+#define get_active_bhs()	(bh_mask & bh_active)
+
+#ifdef __SMP__
+#error SMP not supported on sparc64 yet
+#else
+
+#define softirq_trylock()	(atomic_read(&__sparc64_bh_counter) ? \
+				0 : \
+				((atomic_set(&__sparc64_bh_counter,1)),1))
+#define softirq_endlock()	(atomic_set(&__sparc64_bh_counter, 0))
+#define clear_active_bhs(x)	(bh_active &= ~(x))
+
+#define init_bh(nr, routine)	\
+do {	int ent = nr;		\
+	bh_base[ent] = routine;	\
+	bh_mask_count[ent] = 0;	\
+	bh_mask |= 1 << ent;	\
+} while(0)
+
+#define mark_bh(nr)		(bh_active |= (1 << (nr)))
+
+#define disable_bh(nr)		\
+do {	int ent = nr;		\
+	bh_mask &= ~(1 << ent);	\
+	bh_mask_count[ent]++;	\
+} while(0)
+
+#define enable_bh(nr)			\
+do {	int ent = nr;			\
+	if (!--bh_mask_count[ent])	\
+		bh_mask |= 1 << ent;	\
+} while(0)
+
+#define start_bh_atomic() \
+	do { atomic_inc(&__sparc64_bh_counter); synchronize_irq(); } while(0)
+
+#define end_bh_atomic()	  do { atomic_dec(&__sparc64_bh_counter); } while(0)
+
+#endif /* !(__SMP__) */
+
+#endif /* !(__SPARC64_SOFTIRQ_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.1.33/linux/include/asm-sparc64/spinlock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/spinlock.h	Fri Apr 11 10:47:40 1997
@@ -0,0 +1,32 @@
+/* spinlock.h: 64-bit Sparc spinlock support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_SPINLOCK_H
+#define __SPARC64_SPINLOCK_H
+
+#ifndef __ASSEMBLY__
+
+#ifndef __SMP__
+
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { }
+
+#define spin_lock_init(lock)	do { } while(0)
+#define spin_lock(lock)		do { } while(0)
+#define spin_trylock(lock)	do { } while(0)
+#define spin_unlock(lock)	do { } while(0)
+#define spin_lock_irq(lock)	cli()
+#define spin_unlock_irq(lock)	sti()
+
+#define spin_lock_irqsave(lock, flags)		save_and_cli(flags)
+#define spin_unlock_irqrestore(lock, flags)	restore_flags(flags)
+
+#else /* !(__SMP__) */
+#error SMP not supported on sparc64
+#endif /* __SMP__ */
+
+#endif /* !(__ASSEMBLY__) */
+
+#endif /* !(__SPARC64_SPINLOCK_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h
--- v2.1.33/linux/include/asm-sparc64/spitfire.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/spitfire.h	Fri Apr 11 10:47:40 1997
@@ -1,4 +1,4 @@
-/* $Id: spitfire.h,v 1.2 1996/12/28 18:39:55 davem Exp $
+/* $Id: spitfire.h,v 1.7 1997/04/04 00:50:29 davem Exp $
  * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -29,6 +29,48 @@
 
 #ifndef __ASSEMBLY__
 
+extern __inline__ unsigned long spitfire_get_isfsr(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (ret)
+			     : "r" (TLB_SFSR), "i" (ASI_IMMU));
+	return ret;
+}
+
+extern __inline__ unsigned long spitfire_get_dsfsr(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (ret)
+			     : "r" (TLB_SFSR), "i" (ASI_DMMU));
+	return ret;
+}
+
+extern __inline__ unsigned long spitfire_get_sfar(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (ret)
+			     : "r" (DMMU_SFAR), "i" (ASI_DMMU));
+	return ret;
+}
+
+extern __inline__ void spitfire_put_isfsr(unsigned long sfsr)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2" :
+			     : "r" (sfsr), "r" (TLB_SFSR), "i" (ASI_IMMU));
+}
+
+extern __inline__ void spitfire_put_dsfsr(unsigned long sfsr)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2" :
+			     : "r" (sfsr), "r" (TLB_SFSR), "i" (ASI_DMMU));
+}
+
 extern __inline__ unsigned long spitfire_get_primary_context(void)
 {
 	unsigned long ctx;
@@ -36,12 +78,16 @@
 	__asm__ __volatile__("ldxa	[%1] %2, %0"
 			     : "=r" (ctx)
 			     : "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+	return ctx;
 }
 
-extern __inline__ unsigned long spitfire_set_primary_context(unsigned long ctx)
+extern __inline__ void spitfire_set_primary_context(unsigned long ctx)
 {
 	__asm__ __volatile__("stxa	%0, [%1] %2"
-			     : : "r" (ctx), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+			     : /* No outputs */
+			     : "r" (ctx & 0x1fff),
+			       "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+	membar("#Sync");
 }
 
 extern __inline__ unsigned long spitfire_get_secondary_context(void)
@@ -51,12 +97,16 @@
 	__asm__ __volatile__("ldxa	[%1] %2, %0"
 			     : "=r" (ctx)
 			     : "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU));
+	return ctx;
 }
 
-extern __inline__ unsigned long spitfire_set_secondary_context(unsigned long ctx)
+extern __inline__ void spitfire_set_secondary_context(unsigned long ctx)
 {
 	__asm__ __volatile__("stxa	%0, [%1] %2"
-			     : : "r" (ctx), "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU));
+			     : /* No outputs */
+			     : "r" (ctx & 0x1fff),
+			       "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU));
+	membar("#Sync");
 }
 
 /* The data cache is write through, so this just invalidates the
@@ -92,11 +142,22 @@
 	return data;
 }
 
-extern __inline__ unsigned long spitfire_put_dtlb_data(int entry, unsigned long data)
+extern __inline__ unsigned long spitfire_get_dtlb_tag(int entry)
+{
+	unsigned long tag;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (tag)
+			     : "r" (entry << 3), "i" (ASI_DTLB_TAG_READ));
+	return tag;
+}
+
+extern __inline__ void spitfire_put_dtlb_data(int entry, unsigned long data)
 {
 	__asm__ __volatile__("stxa	%0, [%1] %2"
-			     : : "r" (data), "r" (entry << 3),
-			         "i" (ASI_DTLB_DATA_ACCESS));
+			     : /* No outputs */
+			     : "r" (data), "r" (entry << 3),
+			       "i" (ASI_DTLB_DATA_ACCESS));
 }
 
 extern __inline__ unsigned long spitfire_get_itlb_data(int entry)
@@ -109,11 +170,22 @@
 	return data;
 }
 
-extern __inline__ unsigned long spitfire_put_itlb_data(int entry, unsigned long data)
+extern __inline__ unsigned long spitfire_get_itlb_tag(int entry)
+{
+	unsigned long tag;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (tag)
+			     : "r" (entry << 3), "i" (ASI_ITLB_TAG_READ));
+	return tag;
+}
+
+extern __inline__ void spitfire_put_itlb_data(int entry, unsigned long data)
 {
 	__asm__ __volatile__("stxa	%0, [%1] %2"
-			     : : "r" (data), "r" (entry << 3),
-			         "i" (ASI_ITLB_DATA_ACCESS));
+			     : /* No outputs */
+			     : "r" (data), "r" (entry << 3),
+			       "i" (ASI_ITLB_DATA_ACCESS));
 }
 
 /* Spitfire hardware assisted TLB flushes. */
@@ -122,74 +194,86 @@
 extern __inline__ void spitfire_flush_dtlb_primary_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (0x40), "i" (ASI_DMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (0x40), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_primary_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (0x40), "i" (ASI_IMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (0x40), "i" (ASI_IMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_dtlb_secondary_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (0x41), "i" (ASI_DMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (0x41), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_secondary_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (0x41), "i" (ASI_IMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (0x41), "i" (ASI_IMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_dtlb_nucleus_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (0x42), "i" (ASI_DMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (0x42), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_nucleus_context(void)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (0x42), "i" (ASI_IMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (0x42), "i" (ASI_IMMU_DEMAP));
 }
 
 /* Page level flushes. */
 extern __inline__ void spitfire_flush_dtlb_primary_page(unsigned long page)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (page), "i" (ASI_DMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (page), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_primary_page(unsigned long page)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (page), "i" (ASI_IMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (page), "i" (ASI_IMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_dtlb_secondary_page(unsigned long page)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (page | 0x10), "i" (ASI_DMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (page | 0x10), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_secondary_page(unsigned long page)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (page | 0x10), "i" (ASI_IMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (page | 0x10), "i" (ASI_IMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_dtlb_nucleus_page(unsigned long page)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (page | 0x20), "i" (ASI_DMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (page | 0x20), "i" (ASI_DMMU_DEMAP));
 }
 
 extern __inline__ void spitfire_flush_itlb_nucleus_page(unsigned long page)
 {
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
-			     : : "r" (page | 0x20), "i" (ASI_IMMU_DEMAP));
+			     : /* No outputs */
+			     : "r" (page | 0x20), "i" (ASI_IMMU_DEMAP));
 }
 
 #endif /* !(__ASSEMBLY__) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h
--- v2.1.33/linux/include/asm-sparc64/string.h	Mon Mar 17 14:54:34 1997
+++ linux/include/asm-sparc64/string.h	Fri Apr 11 10:47:40 1997
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.3 1997/03/03 17:11:15 jj Exp $
+/* $Id: string.h,v 1.4 1997/04/01 09:34:41 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -37,16 +37,18 @@
 {
 	extern void __copy_1page(void *, const void *);
 
-	if(n <= 32) {
-		__builtin_memcpy(to, from, n);
-	} else {
-		switch(n) {
-		case 8192:
-			__copy_1page(to, from);
-			break;
-		default:
-			__memcpy(to, from, n);
-			break;
+	if(n) {
+		if(n <= 32) {
+			__builtin_memcpy(to, from, n);
+		} else {
+			switch(n) {
+			case 8192:
+				__copy_1page(to, from);
+				break;
+			default:
+				__memcpy(to, from, n);
+				break;
+			}
 		}
 	}
 	return to;
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/sysio.h linux/include/asm-sparc64/sysio.h
--- v2.1.33/linux/include/asm-sparc64/sysio.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/sysio.h	Fri Apr 11 10:47:40 1997
@@ -0,0 +1,337 @@
+/* $Id: sysio.h,v 1.2 1997/04/03 12:26:45 davem Exp $
+ * sysio.h: UltraSparc sun5 specific SBUS definitions.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_SYSIO_H
+#define __SPARC64_SYSIO_H
+
+#include <linux/types.h>
+
+/* SUN5 SYSIO Register Set, one per controller probed. */
+struct sysio_regs {
+/*0x0000*/	u64	upa_id;		/* SYSIO UPA Port ID Register		*/
+/*0x0008*/	u64	upa_cfg;	/* SYSIO UPA Config Register		*/
+/*0x0010*/	u64	control;	/* SYSIO Control Register		*/
+/*0x0018*/	u64	_unused1;
+/*0x0020*/	u64	ecc_control;	/* ECC Control Register			*/
+/*0x0028*/	u64	_unused2;
+
+		/* Uncorrectable Error Fault Registers */
+/*0x0030*/	u64	ue_afsr;	/* UE Async Fault Status		*/
+/*0x0038*/	u64	ue_afar;	/* UE Async Fault Address		*/
+
+		/* Correctable Error Fault Registers */
+/*0x0040*/	u64	ce_afsr;	/* CE Async Fault Status		*/
+/*0x0048*/	u64	ce_afar;	/* CE Async Fault Address		*/
+
+		u64	__pad0[0x16];
+
+		/* Performance Monitoring Registers */
+/*0x0100*/	u64	pmon_control;
+/*0x0108*/	u64	pmon_counter;
+
+		u64	__pad1[0x3de];
+
+		/* SBUS Module Registers */
+/*0x2000*/	u64	sbus_control;	/* SBUS Control Register		*/
+/*0x2008*/	u64	_unused3;
+/*0x2010*/	u64	sbus_afsr;	/* SBUS Async Fault Status		*/
+/*0x2018*/	u64	sbus_afar;	/* SBUS Async Fault Address		*/
+
+		/* SBUS Slot Configuration Registers.
+		 * On Fusion/Electron/Pulsar desktops/servers slots 4-->6
+		 * are for on-board devices, in particular for Electron/Pulsar
+		 * they are:
+		 *
+		 *	slot 4) Audio
+		 *	slot 5) MACIO
+		 *	slot 6) SLAVIO
+		 *
+		 * On Sunfire/Wildfire enterprise boxen these upper slots
+		 * are unused.
+		 */
+/*0x2020*/	u64	sbus_s0cfg;	/* SBUS Slot 0 Config			*/
+/*0x2028*/	u64	sbus_s1cfg;	/* SBUS Slot 1 Config			*/
+/*0x2030*/	u64	sbus_s2cfg;	/* SBUS Slot 2 Config			*/
+/*0x2038*/	u64	sbus_s3cfg;	/* SBUS Slot 3 Config			*/
+/*0x2040*/	u64	sbus_s4cfg;	/* SBUS Slot 4 Config			*/
+/*0x2048*/	u64	sbus_s5cfg;	/* SBUS Slot 5 Config			*/
+/*0x2050*/	u64	sbus_s6cfg;	/* SBUS Slot 6 Config			*/
+
+		u64	__pad2[0x75];
+
+		/* SBUS IOMMU lives here */
+/*0x2400*/	u64	iommu_control;	/* IOMMU Control			*/
+/*0x2408*/	u64	iommu_tsbbase;	/* IOMMU TSB Base			*/
+/*0x2410*/	u64	iommu_flush;	/* IOMMU Flush Register			*/
+
+		u64	__pad3[0x7d];
+
+		/* SBUS/IOMMU Streaming Buffer Registers */
+/*0x2800*/	u64	sbuf_control;	/* StrBuffer Control			*/
+/*0x2808*/	u64	sbuf_pflush;	/* StrBuffer Page Flush			*/
+/*0x2810*/	u64	sbus_fsync;	/* StrBuffer Flush Synchronization Reg	*/
+
+		u64	__pad4[0x7d];
+
+		/* Interrupt mapping/control registers */
+/*0x2c00*/	u32	imap_slot0, _uim0;	/* SBUS Slot 0 Int Mapping	*/
+/*0x2c08*/	u32	imap_slot1, _uim1;	/* SBUS Slot 1 Int Mapping	*/
+/*0x2c10*/	u32	imap_slot2, _uim2;	/* SBUS Slot 2 Int Mapping	*/
+/*0x2c18*/	u32	imap_slot3, _uim3;	/* SBUS Slot 3 Int Mapping	*/
+
+		/* Interrupt Retry Timer. */
+/*0x2c20*/	u32	irq_retry,  _irpad;
+
+		u64	__pad5[0x7b];
+
+		/* The following are only used on Fusion/Electron/Pulsar
+		 * desktop systems, they mean nothing on Sunfire/Wildfire
+		 */
+/*0x3000*/	u32	imap_scsi,  _uis;	/* SCSI Int Mapping		*/
+/*0x3008*/	u32	imap_eth,   _uie;	/* Ethernet Int Mapping		*/
+/*0x3010*/	u32	imap_bpp,   _uip;	/* Parallel Port Int Mapping	*/
+/*0x3018*/	u32	imap_audio, _uia;	/* Audio Int Mapping		*/
+/*0x3020*/	u32	imap_pfail, _uipf;	/* Power Fail Int Mapping	*/
+/*0x3028*/	u32	imap_kms,   _uik;	/* Kbd/Mouse/Serial Int Mapping	*/
+/*0x3030*/	u32	imap_flpy,  _uif;	/* Floppy Int Mapping		*/
+/*0x3038*/	u32	imap_shw,   _uishw;	/* Spare HW Int Mapping		*/
+/*0x3040*/	u32	imap_kbd,   _uikbd;	/* Kbd Only Int Mapping		*/
+/*0x3048*/	u32	imap_ms,    _uims;	/* Mouse Only Int Mapping	*/
+/*0x3050*/	u32	imap_ser,   _uiser;	/* Serial Only Int Mapping	*/
+/*0x3058*/	u64	_imap_unused;
+/*0x3060*/	u32	imap_tim0,  _uit0;	/* Timer 0 Int Mapping		*/
+/*0x3068*/	u32	imap_tim1,  _uit1;	/* Timer 1 Int Mapping		*/
+/*0x3070*/	u32	imap_ue,    _uiue;	/* UE Int Mapping		*/
+/*0x3078*/	u32	imap_ce,    _uice;	/* CE Int Mapping		*/
+/*0x3080*/	u32	imap_sberr, _uisbe;	/* SBUS Err Int Mapping		*/
+/*0x3088*/	u32	imap_pmgmt, _uipm;	/* Power Mgmt Int Mapping	*/
+/*0x3090*/	u32	imap_gfx,   _uigfx;	/* OB Graphics Int Mapping	*/
+/*0x3098*/	u32	imap_eupa,  _uieupa;	/* UPA Expansion Int Mapping	*/
+
+		u64	__pad6[0x6c];
+
+		/* Interrupt Clear Registers */
+/*0x3400*/	u64	iclr_unused0;
+/*0x3408*/	u32	iclr_slot0, _ucs0;
+		u64	__pad7[0x7];
+/*0x3448*/	u32	iclr_slot1, _ucs1;
+		u64	__pad8[0x7];
+/*0x3488*/	u32	iclr_slot2, _ucs2;
+		u64	__pad9[0x7];
+/*0x34c8*/	u32	iclr_slot3, _ucs3;
+		u64	__pad10[0x66];
+/*0x3800*/	u32	iclr_scsi,  _ucscsi;
+/*0x3808*/	u32	iclr_eth,   _uceth;
+/*0x3810*/	u32	iclr_bpp,   _ucbpp;
+/*0x3818*/	u32	iclr_audio, _ucaudio;
+/*0x3820*/	u32	iclr_pfail, _ucpfail;
+/*0x3828*/	u32	iclr_kms,   _uckms;
+/*0x3830*/	u32	iclr_flpt,  _ucflpy;
+/*0x3838*/	u32	iclr_shw,   _ucshw;
+/*0x3840*/	u32	iclr_kbd,   _uckbd;
+/*0x3848*/	u32	iclr_ms,    _ucms;
+/*0x3850*/	u32	iclr_ser,   _ucser;
+/*0x3858*/	u64	iclr_unused1;
+/*0x3860*/	u32	iclr_tim0,  _uctim0;
+/*0x3868*/	u32	iclr_tim1,  _uctim1;
+/*0x3870*/	u32	iclr_ue,    _ucue;
+/*0x3878*/	u32	iclr_ce,    _ucce;
+/*0x3880*/	u32	iclr_serr,  _ucserr;
+/*0x3888*/	u32	iclr_pmgmt, _ucpmgmt;
+
+		u64	__pad11[0x6e];
+
+		/* Counters/Timers */
+/*0x3c00*/	u32	tim0_cnt, _tim0_u0;
+/*0x3c08*/	u32	tim0_lim, _tim0_u1;
+/*0x3c10*/	u32	tim1_cnt, _tim1_u0;
+/*0x3c18*/	u32	tim1_lim, _tim1_u1;
+
+		u64	__pad12[0x7c];
+
+		/* DMA Scoreboard Diagnostic Registers */
+/*0x4000*/	u64	dscore_reg0;	/* DMA Scoreboard Diag Reg 0		*/
+/*0x4008*/	u64	dscore_reg1;	/* DMA Scoreboard Diag Reg 1		*/
+
+		u64	__pad13[0x7e];
+
+		/* SBUS IOMMU Diagnostic Registers */
+/*0x4400*/	u64	sbus_vdiag;	/* SBUS VADDR Diagnostic Register	*/
+/*0x4408*/	u64	sbus_tcompare;	/* SBUS IOMMU TLB Tag Compare		*/
+
+		u64	__pad14[0x1e];
+
+		/* More IOMMU diagnostic things */
+/*0x4500*/	u64	iommu_lru[16];	/* IOMMU LRU Queue Diagnostic Access	*/
+/*0x4580*/	u64	iommu_tag[16];	/* IOMMU TLB Tag Diagnostic Access	*/
+/*0x4600*/	u64	iommu_data[32];	/* IOMMU TLB Data RAM Diagnostic Access	*/
+
+		/* Interrupt State Diagnostics */
+/*0x4800*/	u64	sbus_istate;
+/*0x4808*/	u64	obio_istate;
+
+		u64	__pad15[0xfe];
+
+		/* Streaming Buffer Diagnostic Area */
+/*0x5000*/	u64	sbuf_data[128];	/* StrBuffer Data Ram Diagnostic	*/
+/*0x5400*/	u64	sbuf_errs[128];	/* StrBuffer Error Status Diagnostics	*/
+/*0x5800*/	u64	sbuf_ptag[16];	/* StrBuffer Page Tag Diagnostics	*/
+/*0x5880*/	u64	_unusedXXX[16];
+/*0x5900*/	u64	sbuf_ltag[16];	/* StrBuffer Line Tag Diagnostics	*/
+};
+
+/* SYSIO UPA Port ID */
+#define SYSIO_UPPID_FESC	0xff00000000000000 /* FCode escape, 0xfc           */
+#define SYSIO_UPPID_RESV1	0x00fffff800000000 /* Reserved                     */
+#define SYSIO_UPPID_ENV		0x0000000400000000 /* Cannot generate ECC          */
+#define SYSIO_UPPID_ORD		0x0000000200000000 /* One Outstanding Read         */
+#define SYSIO_UPPID_RESV2	0x0000000180000000 /* Reserved                     */
+#define SYSIO_UPPID_PDQ		0x000000007e000000 /* Data Queue size              */
+#define SYSIO_UPPID_PRQ		0x0000000001e00000 /* Request Queue size           */
+#define SYSIO_UPPID_UCAP	0x00000000001f0000 /* UPA Capabilities             */
+#define SYSIO_UPPID_JEDEC	0x000000000000ffff /* JEDEC ID for SYSIO           */
+
+/* SYSIO UPA Configuration Register */
+#define SYSIO_UPCFG_RESV	0xffffffffffffff00 /* Reserved                     */
+#define SYSIO_UPCFG_SCIQ1	0x00000000000000f0 /* Unused, always zero          */
+#define SYSIO_UPCFG_SCIQ2	0x000000000000000f /* Requests Queue size (0x2)    */
+
+/* SYSIO Control Register */
+#define SYSIO_CONTROL_IMPL	0xf000000000000000 /* Implementation of this SYSIO */
+#define SYSIO_CONTROL_VER	0x0f00000000000000 /* Version of this SYSIO        */
+#define SYSIO_CONTROL_MID	0x00f8000000000000 /* UPA Module ID of SYSIO       */
+#define SYSIO_CONTROL_IGN	0x0007c00000000000 /* Interrupt Group Number       */
+#define SYSIO_CONTROL_RESV      0x00003ffffffffff0 /* Reserved                     */
+#define SYSIO_CONTROL_APCKEN	0x0000000000000008 /* Address Parity Check Enable  */
+#define SYSIO_CONTROL_APERR	0x0000000000000004 /* Incoming System Addr Parerr  */
+#define SYSIO_CONTROL_IAP	0x0000000000000002 /* Invert UPA Parity            */
+#define SYSIO_CONTROL_MODE	0x0000000000000001 /* SYSIO clock mode             */
+
+/* SYSIO ECC Control Register */
+#define SYSIO_ECNTRL_ECCEN	0x8000000000000000 /* Enable ECC Checking          */
+#define SYSIO_ECNTRL_UEEN	0x4000000000000000 /* Enable UE Interrupts         */
+#define SYSIO_ECNTRL_CEEN	0x2000000000000000 /* Enable CE Interrupts         */
+
+/* Uncorrectable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define SYSIO_UEAFSR_PPIO	0x8000000000000000 /* Primary PIO is cause         */
+#define SYSIO_UEAFSR_PDRD	0x4000000000000000 /* Primary DVMA read is cause   */
+#define SYSIO_UEAFSR_PDWR	0x2000000000000000 /* Primary DVMA write is cause  */
+#define SYSIO_UEAFSR_SPIO	0x1000000000000000 /* Secondary PIO is cause       */
+#define SYSIO_UEAFSR_SDRD	0x0800000000000000 /* Secondary DVMA read is cause */
+#define SYSIO_UEAFSR_SDWR	0x0400000000000000 /* Secondary DVMA write is cause*/
+#define SYSIO_UEAFSR_RESV1	0x03ff000000000000 /* Reserved                     */
+#define SYSIO_UEAFSR_DOFF	0x0000e00000000000 /* Doubleword Offset            */
+#define SYSIO_UEAFSR_SIZE	0x00001c0000000000 /* Bad transfer size is 2**SIZE */
+#define SYSIO_UEAFSR_MID	0x000003e000000000 /* UPA MID causing the fault    */
+#define SYSIO_UEAFSR_RESV2	0x0000001fffffffff /* Reserved                     */
+
+/* Correctable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define SYSIO_CEAFSR_PPIO	0x8000000000000000 /* Primary PIO is cause         */
+#define SYSIO_CEAFSR_PDRD	0x4000000000000000 /* Primary DVMA read is cause   */
+#define SYSIO_CEAFSR_PDWR	0x2000000000000000 /* Primary DVMA write is cause  */
+#define SYSIO_CEAFSR_SPIO	0x1000000000000000 /* Secondary PIO is cause       */
+#define SYSIO_CEAFSR_SDRD	0x0800000000000000 /* Secondary DVMA read is cause */
+#define SYSIO_CEAFSR_SDWR	0x0400000000000000 /* Secondary DVMA write is cause*/
+#define SYSIO_CEAFSR_RESV1	0x0300000000000000 /* Reserved                     */
+#define SYSIO_CEAFSR_ESYND	0x00ff000000000000 /* Syndrome Bits                */
+#define SYSIO_CEAFSR_DOFF	0x0000e00000000000 /* Double Offset                */
+#define SYSIO_CEAFSR_SIZE	0x00001c0000000000 /* Bad transfer size is 2**SIZE */
+#define SYSIO_CEAFSR_MID	0x000003e000000000 /* UPA MID causing the fault    */
+#define SYSIO_CEAFSR_RESV2	0x0000001fffffffff /* Reserved                     */
+
+/* DMA Scoreboard Diagnostic Register(s) */
+#define SYSIO_DSCORE_VALID	0x0040000000000000 /* Entry is valid               */
+#define SYSIO_DSCORE_C		0x0020000000000000 /* Transaction cacheable        */
+#define SYSIO_DSCORE_READ	0x0010000000000000 /* Transaction was a read       */
+#define SYSIO_DSCORE_TAG	0x000f000000000000 /* Transaction ID               */
+#define SYSIO_DSCORE_ADDR	0x0000ffffffffff80 /* Transaction PADDR            */
+#define SYSIO_DSCORE_SIZE	0x0000000000000030 /* Transaction size             */
+#define SYSIO_DSCORE_SRC	0x000000000000000f /* Transaction source           */
+
+/* SYSIO SBUS Control Register */
+#define SYSIO_SBCNTRL_IMPL	0xf000000000000000 /* Implementation               */
+#define SYSIO_SBCNTRL_REV	0x0f00000000000000 /* Revision                     */
+#define SYSIO_SBCNTRL_RESV1	0x00c0000000000000 /* Reserved                     */
+#define SYSIO_SBCNTRL_DPERR	0x003f000000000000 /* DMA Write Parity Error       */
+#define SYSIO_SBCNTRL_RESV2	0x0000800000000000 /* Reserved                     */
+#define SYSIO_SBCNTRL_PPERR	0x00007f0000000000 /* PIO Load Parity Error        */
+#define SYSIO_SBCNTRL_RESV	0x000000fffffffc00 /* Reserved                     */
+#define SYSIO_SBCNTRL_WEN	0x0000000000000200 /* Power Mgmt Wake Enable       */
+#define SYSIO_SBCNTRL_EEN	0x0000000000000100 /* SBUS Error Interrupt Enable  */
+#define SYSIO_SBCNTRL_RESV3	0x00000000000000c0 /* Reserved                     */
+#define SYSIO_SBCNTRL_AEN	0x000000000000003f /* SBUS DVMA Arbitration Enable */
+
+/* SYSIO SBUS AFSR, AFAR holds low 40 bits of physical address causing the fault. */
+#define SYSIO_SBAFSR_PLE	0x8000000000000000 /* Primary Late PIO Error       */
+#define SYSIO_SBAFSR_PTO	0x4000000000000000 /* Primary SBUS Timeout         */
+#define SYSIO_SBAFSR_PBERR	0x2000000000000000 /* Primary SBUS Error ACK       */
+#define SYSIO_SBAFSR_SLE	0x1000000000000000 /* Secondary Late PIO Error     */
+#define SYSIO_SBAFSR_STO	0x0800000000000000 /* Secondary SBUS Timeout       */
+#define SYSIO_SBAFSR_SBERR	0x0400000000000000 /* Secondary SBUS Error ACK     */
+#define SYSIO_SBAFSR_RESV1	0x03ff000000000000 /* Reserved                     */
+#define SYSIO_SBAFSR_RD		0x0000800000000000 /* Primary was late PIO read    */
+#define SYSIO_SBAFSR_RESV2	0x0000600000000000 /* Reserved                     */
+#define SYSIO_SBAFSR_SIZE	0x00001c0000000000 /* Size of transfer             */
+#define SYSIO_SBAFSR_MID	0x000003e000000000 /* MID causing the error        */
+#define SYSIO_SBAFSR_RESV3	0x0000001fffffffff /* Reserved                     */
+
+/* SYSIO SBUS Slot Configuration Register */
+#define SYSIO_SBSCFG_RESV1	0xfffffffff8000000 /* Reserved                     */
+#define SYSIO_SBSCFG_SADDR	0x0000000007ff0000 /* Segment Address (PA[40:30])  */
+#define SYSIO_SBSCFG_CP		0x0000000000008000 /* Bypasses are cacheable       */
+#define SYSIO_SBSCFG_ETM	0x0000000000004000 /* Ext Transfer Mode supported  */
+#define SYSIO_SBSCFG_PE		0x0000000000002000 /* SBUS Parity Checking Enable  */
+#define SYSIO_SBSCFG_RESV2	0x0000000000001fe0 /* Reserved                     */
+#define SYSIO_SBSCFG_BA64	0x0000000000000010 /* 64-byte bursts supported     */
+#define SYSIO_SBSCFG_BA32	0x0000000000000008 /* 32-byte bursts supported     */
+#define SYSIO_SBSCFG_BA16	0x0000000000000004 /* 16-byte bursts supported     */
+#define SYSIO_SBSCFG_BA8	0x0000000000000002 /* 8-byte bursts supported      */
+#define SYSIO_SBSCFG_BY		0x0000000000000001 /* IOMMU Bypass Enable          */
+
+/* IOMMU things defined fully in asm-sparc64/iommu.h */
+
+/* Streaming Buffer Control Register */
+#define SYSIO_SBUFCTRL_IMPL	0xf000000000000000 /* Implementation               */
+#define SYSIO_SBUFCTRL_REV	0x0f00000000000000 /* Revision                     */
+#define SYSIO_SBUFCTRL_DE	0x0000000000000002 /* Diag Mode Enable             */
+#define SYSIO_SBUFCTRL_SB_EN	0x0000000000000001 /* Streaming Buffer Enable      */
+
+/* Streaming Buffer Page Invalidate/Flush Register */
+#define SYSIO_SBUFFLUSH_ADDR	0x00000000ffffe000 /* DVMA Page to be flushed      */
+#define SYSIO_SBUFFLUSH_RESV    0x0000000000001fff /* Ignored bits                 */
+
+/* Streaming Buffer Flush Synchronization Register */
+#define SYSIO_SBUFSYNC_ADDR	0x000001fffffffffc /* Physical address to update   */
+#define SYSIO_SBUFSYNC_RESV	0x0000000000000003 /* Ignored bits                 */
+
+/* SYSIO Interrupt mapping register(s). */
+#define SYSIO_IMAP_VALID	0x80000000	/* This enables delivery.	   */
+#define SYSIO_IMAP_TID		0x7c000000	/* Target ID (MID to send it to)   */
+#define SYSIO_IMAP_RESV		0x03fff800	/* Reserved.			   */
+#define SYSIO_IMAP_IGN		0x000007c0	/* Interrupt Group Number.	   */
+#define SYSIO_IMAP_INO		0x0000003f	/* Interrupt Number Offset.	   */
+#define SYSIO_IMAP_INR		0x000007ff	/* Interrupt # (Gfx/UPA_slave only)*/
+
+/* SYSIO Interrupt clear pseudo register(s). */
+#define SYSIO_ICLR_IDLE		0x00000000	/* Transition to idle state.	   */
+#define SYSIO_ICLR_TRANSMIT	0x00000001	/* Transition to transmit state.   */
+#define SYSIO_ICLR_RESV		0x00000002	/* Reserved.			   */
+#define SYSIO_ICLR_PENDING	0x00000003	/* Transition to pending state.	   */
+
+/* SYSIO Interrupt Retry Timer register. */
+#define SYSIO_IRETRY_LIMIT	0x000000ff	/* The retry interval.		   */
+
+/* SYSIO Interrupt State registers. XXX fields to be documented later */
+
+/* SYSIO Counter register. XXX fields to be documented later */
+
+/* SYSIO Limit register. XXX fields to be documented later */
+
+/* SYSIO Performance Monitor Control register. XXX fields to be documented later */
+
+/* SYSIO Performance Monitor Counter register. XXX fields to be documented later */
+
+#endif /* !(__SPARC64_SYSIO_H) */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.1.33/linux/include/asm-sparc64/system.h	Thu Mar 27 14:40:09 1997
+++ linux/include/asm-sparc64/system.h	Fri Apr 11 10:47:40 1997
@@ -1,15 +1,13 @@
-/* $Id: system.h,v 1.7 1997/03/18 18:02:41 jj Exp $ */
+/* $Id: system.h,v 1.15 1997/04/10 23:32:49 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
+#include <asm/asm_offsets.h>
 
 #define NCPUS	4	/* No SMP yet */
 
-#define EMPTY_PGT       (&empty_bad_page)
-#define EMPTY_PGE       (&empty_bad_page_table)
-
 #ifndef __ASSEMBLY__
 /*
  * Sparc (general) CPU types
@@ -29,17 +27,18 @@
                   
 
 extern unsigned long empty_bad_page;
-extern unsigned long empty_bad_page_table;
+extern unsigned long empty_bad_pmd_table;
+extern unsigned long empty_bad_pte_table;
 extern unsigned long empty_zero_page;
 #endif
 
 #define setipl(__new_ipl) \
 	__asm__ __volatile__("wrpr	%0, %%pil"  : : "r" (__new_ipl) : "memory")
 
-#define cli() \
+#define __cli() \
 	__asm__ __volatile__("wrpr	15, %%pil" : : : "memory")
 
-#define sti() \
+#define __sti() \
 	__asm__ __volatile__("wrpr	0, %%pil" : : : "memory")
 
 #define getipl() \
@@ -64,9 +63,19 @@
 	retval; \
 })
 
-#define save_flags(flags)	((flags) = getipl())
-#define save_and_cli(flags)	((flags) = read_pil_and_cli())
-#define restore_flags(flags)	setipl((flags))
+#define __save_flags(flags)	((flags) = getipl())
+#define __save_and_cli(flags)	((flags) = read_pil_and_cli())
+#define __restore_flags(flags)	setipl((flags))
+
+#ifndef __SMP__
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#else
+#error SMP not supported on sparc64
+#endif
 
 #define mb()  		__asm__ __volatile__ ("stbar" : : : "memory")
 
@@ -93,15 +102,81 @@
 		bne,pn		%%xcc, 1b
 		 restore	%%g0, %%g0, %%g0
 	" : : "i" (-REGWIN_SZ)
-	  : "g1", "g2");
+	  : "g1", "g2", "cc");
 }
 
+#define flush_user_windows flushw_user
+
+#ifdef __SMP__
+#error SMP not supported on sparc64
+#else
+#if 0
+#define SWITCH_DO_LAZY_FPU(next)			\
+	if(last_task_used_math != (next))		\
+		(next)->tss.kregs->tstate&=~TSTATE_PEF
+#else
+/* XXX FIX ME BIG TIME XXX -DaveM */
+#define SWITCH_DO_LAZY_FPU(next)	do { } while(0)
+#endif
+#endif
+
+	/* See what happens when you design the chip correctly?
+	 * NOTE NOTE NOTE this is extremely non-trivial what I
+	 * am doing here.  GCC needs only two registers to stuff
+	 * things into ('next' and &current_set[cpu])  So I "claim"
+	 * that I do not clobber them, when in fact I do.  Please,
+	 * when modifying this code inspect output of sched.s very
+	 * carefully to make sure things still work.  -DaveM
+	 */
+#define switch_to(prev, next)								\
+do {											\
+	__label__ switch_continue;							\
+	register unsigned long task_pc asm("o7");					\
+	SWITCH_DO_LAZY_FPU(next);							\
+	task_pc = ((unsigned long) &&switch_continue) - 0x8;				\
+	__asm__ __volatile__(								\
+	"flushw\n\t"									\
+	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"						\
+	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"						\
+	"stx	%%o6, [%%g6 + %3]\n\t"							\
+	"rdpr	%%wstate, %%o5\n\t"							\
+	"stx	%%o7, [%%g6 + %4]\n\t"							\
+	"mov	%6, %%o4\n\t"								\
+	"stx	%%o5, [%%g6 + %2]\n\t"							\
+	"st	%%o4, [%%g6 + %7]\n\t"							\
+	"rdpr	%%cwp, %%o5\n\t"							\
+	"stx	%%o5, [%%g6 + %8]\n\t"							\
+	"mov	%1, %%g6\n\t"								\
+	"stx	%%g6, [%0]\n\t"								\
+	"ldx	[%%g6 + %8], %%g1\n\t"							\
+	"wrpr	%%g1, %%cwp\n\t"							\
+	"ldx	[%%g6 + %2], %%o5\n\t"							\
+	"ldx	[%%g6 + %3], %%o6\n\t"							\
+	"ldx	[%%g6 + %4], %%o7\n\t"							\
+	"wrpr	%%o5, 0x0, %%wstate\n\t"						\
+	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"						\
+	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
+	" ldx	[%%sp + 2047 + 0x78], %%i7\n\t"						\
+	: /* No outputs */								\
+	: "r" (&(current_set[smp_processor_id()])), "r" (next),				\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),		\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)),		\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)),		\
+	  "r" (task_pc), "i" (255),							\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->processor)),		\
+	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp))		\
+	: "cc", "g1", "g2", "g3", "g5", "g7",						\
+	  "l2", "l3", "l4", "l5", "l6", "l7",						\
+	  "i0", "i1", "i2", "i3", "i4", "i5",						\
+	  "o0", "o1", "o2", "o3", "o4", "o5");						\
+switch_continue: } while(0)
+
 /* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
 extern __inline__ unsigned long xchg_u32(__volatile__ unsigned int *m, unsigned int val)
 {
-	__asm__ __volatile__("swap	[%1], %0"
+	__asm__ __volatile__("swap	[%2], %0"
 			     : "=&r" (val)
-			     : "r" (m), "0" (val));
+			     : "0" (val), "r" (m));
 	return val;
 }
 
@@ -111,14 +186,15 @@
 {
 	unsigned long temp;
 	__asm__ __volatile__("
-	ldx		[%2], %1
+	ldx		[%3], %1
 1:
-	casx		[%2], %1, %0
+	casx		[%3], %1, %0
 	cmp		%1, %0
 	bne,a,pn	%%xcc, 1b
-	 ldx		[%2], %1
+	 ldx		[%3], %1
 "	: "=&r" (val), "=&r" (temp)
-	: "r" (m), "0" (val));
+	: "0" (val), "r" (m)
+	: "cc");
 	return val;
 }
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/termbits.h linux/include/asm-sparc64/termbits.h
--- v2.1.33/linux/include/asm-sparc64/termbits.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/termbits.h	Fri Apr 11 10:47:40 1997
@@ -117,43 +117,40 @@
 #define WRAP    0x00020000  /* SUNOS specific */
 
 /* c_cflag bit meaning */
-#define CBAUD	0x0000000f
-#define  B0	0x00000000   /* hang up */
-#define  B50	0x00000001
-#define  B75	0x00000002
-#define  B110	0x00000003
-#define  B134	0x00000004
-#define  B150	0x00000005
-#define  B200	0x00000006
-#define  B300	0x00000007
-#define  B600	0x00000008
-#define  B1200	0x00000009
-#define  B1800	0x0000000a
-#define  B2400	0x0000000b
-#define  B4800	0x0000000c
-#define  B9600	0x0000000d
-#define  B19200	0x0000000e
-#define  B38400	0x0000000f
-#define EXTA    B19200
-#define EXTB    B38400
-#define  CSIZE  0x00000030
-#define   CS5	0x00000000
-#define   CS6	0x00000010
-#define   CS7	0x00000020
-#define   CS8	0x00000030
-#define CSTOPB	0x00000040
-#define CREAD	0x00000080
-#define PARENB	0x00000100
-#define PARODD	0x00000200
-#define HUPCL	0x00000400
-#define CLOCAL	0x00000800
-/* We'll never see these speeds with the Zilogs' but for completeness... */
-#define CBAUDEX 0x00010000
-#define  B57600  0x00010001
-#define  B115200 0x00010002
-#define  B230400 0x00010003
-#define  B460800 0x00010004
-#define CIBAUD	  0x000f0000  /* input baud rate (not used) */
+#define CBAUD	  0x0000100f
+#define  B0	  0x00000000   /* hang up */
+#define  B50	  0x00000001
+#define  B75	  0x00000002
+#define  B110	  0x00000003
+#define  B134	  0x00000004
+#define  B150	  0x00000005
+#define  B200	  0x00000006
+#define  B300	  0x00000007
+#define  B600	  0x00000008
+#define  B1200	  0x00000009
+#define  B1800	  0x0000000a
+#define  B2400	  0x0000000b
+#define  B4800	  0x0000000c
+#define  B9600	  0x0000000d
+#define  B19200	  0x0000000e
+#define  B38400	  0x0000000f
+#define EXTA      B19200
+#define EXTB      B38400
+#define  CSIZE    0x00000030
+#define   CS5	  0x00000000
+#define   CS6	  0x00000010
+#define   CS7	  0x00000020
+#define   CS8	  0x00000030
+#define CSTOPB	  0x00000040
+#define CREAD	  0x00000080
+#define PARENB	  0x00000100
+#define PARODD	  0x00000200
+#define HUPCL	  0x00000400
+#define CLOCAL	  0x00000800
+#define CBAUDEX   0x00001000
+#define  B57600   0x00001001
+#define CIBAUD	  0x100f0000  /* input baud rate (not used) */
+#define CMSPAR    0x40000000  /* mark or space (stick) parity */
 #define CRTSCTS	  0x80000000  /* flow control */
 
 /* c_lflag bits */
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.1.33/linux/include/asm-sparc64/uaccess.h	Thu Mar 27 14:40:10 1997
+++ linux/include/asm-sparc64/uaccess.h	Fri Apr 11 10:47:40 1997
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.8 1997/03/14 21:05:33 jj Exp $ */
+/* $Id: uaccess.h,v 1.12 1997/04/10 23:32:50 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -10,6 +10,9 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <asm/a.out.h>
+#include <asm/asi.h>
+#include <asm/system.h>
+#include <asm/spitfire.h>
 #endif
 
 #ifndef __ASSEMBLY__
@@ -27,21 +30,27 @@
 
 #define get_fs() (current->tss.current_ds)
 #define get_ds() (KERNEL_DS)
-#define set_fs(val) ((current->tss.current_ds) = (val))
+extern __inline__ void set_fs(int val)
+{
+	if (val != current->tss.current_ds) {
+		if (val == KERNEL_DS) {
+			flushw_user ();
+			spitfire_set_secondary_context (0);
+		} else {
+			spitfire_set_secondary_context (current->mm->context);
+		}
+		current->tss.current_ds = val;
+	}
+}
 
-/* We have there a nice not-mapped page at page_offset - PAGE_SIZE, so that this test
- * can be fairly lightweight.
- * No one can read/write anything from userland in the kernel space by setting
- * large size and address near to page_offset - a fault will break his intentions.
- */
-#define __user_ok(addr,size) ((addr) < PAGE_OFFSET)
+#define __user_ok(addr,size) 1
 #define __kernel_ok (get_fs() == KERNEL_DS)
-#define __access_ok(addr,size) (__user_ok(((unsigned long)(addr)) & get_fs(),(size)))
-#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
+#define __access_ok(addr,size) 1
+#define access_ok(type,addr,size) 1
 
 extern inline int verify_area(int type, const void * addr, unsigned long size)
 {
-	return access_ok(type,addr,size)?0:-EFAULT;
+	return 0;
 }
 
 /*
@@ -87,55 +96,28 @@
  */
 #define put_user(x,ptr) ({ \
 unsigned long __pu_addr = (unsigned long)(ptr); \
-__put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
+__put_user_nocheck((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
 
 #define put_user_ret(x,ptr,retval) ({ \
 unsigned long __pu_addr = (unsigned long)(ptr); \
-__put_user_check_ret((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr)),retval); })
+__put_user_nocheck_ret((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr)),retval); })
 
 #define get_user(x,ptr) ({ \
 unsigned long __gu_addr = (unsigned long)(ptr); \
-__get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
+__get_user_nocheck((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
 
 #define get_user_ret(x,ptr,retval) ({ \
 unsigned long __gu_addr = (unsigned long)(ptr); \
-__get_user_check_ret((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr)),retval); })
+__get_user_nocheck_ret((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr)),retval); })
 
-/*
- * The "__xxx" versions do not do address space checking, useful when
- * doing multiple accesses to the same area (the user has to do the
- * checks by hand with "access_ok()")
- */
-#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
-#define __put_user_ret(x,ptr,retval) __put_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),retval)
-#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
-#define __get_user_ret(x,ptr,retval) __get_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)),retval)
+#define __put_user(x,ptr) put_user(x,ptr)
+#define __put_user_ret(x,ptr,retval) put_user_ret(x,ptr,retval)
+#define __get_user(x,ptr) get_user(x,ptr)
+#define __get_user_ret(x,ptr,retval) get_user_ret(x,ptr,retval)
 
 struct __large_struct { unsigned long buf[100]; };
 #define __m(x) ((struct __large_struct *)(x))
 
-#define __put_user_check(data,addr,size) ({ \
-register int __pu_ret; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __put_user_asm(data,b,addr,__pu_ret); break; \
-case 2: __put_user_asm(data,h,addr,__pu_ret); break; \
-case 4: __put_user_asm(data,w,addr,__pu_ret); break; \
-case 8: __put_user_asm(data,x,addr,__pu_ret); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} } else { __pu_ret = -EFAULT; } __pu_ret; })
-
-#define __put_user_check_ret(data,addr,size,retval) ({ \
-register int __foo __asm__ ("l1"); \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __put_user_asm_ret(data,b,addr,retval,__foo); break; \
-case 2: __put_user_asm_ret(data,h,addr,retval,__foo); break; \
-case 4: __put_user_asm_ret(data,w,addr,retval,__foo); break; \
-case 8: __put_user_asm_ret(data,x,addr,retval,__foo); break; \
-default: if (__put_user_bad()) return retval; break; \
-} } else return retval; })
-
 #define __put_user_nocheck(data,addr,size) ({ \
 register int __pu_ret; \
 switch (size) { \
@@ -159,7 +141,7 @@
 #define __put_user_asm(x,size,addr,ret)					\
 __asm__ __volatile__(							\
 	"/* Put user asm, inline. */\n"					\
-"1:\t"	"st"#size " %1, [%2]\n\t"					\
+"1:\t"	"st"#size "a %1, [%2] %4\n\t"					\
 	"clr	%0\n"							\
 "2:\n\n\t"								\
 	".section .fixup,#alloc,#execinstr\n\t"				\
@@ -172,23 +154,23 @@
 	".align	4\n\t"							\
 	".word	1b, 3b\n\t"						\
 	".previous\n\n\t"						\
-       : "=&r" (ret) : "r" (x), "r" (__m(addr)),			\
-	 "i" (-EFAULT))
+       : "=r" (ret) : "r" (x), "r" (__m(addr)),				\
+	 "i" (-EFAULT), "i" (ASI_S))
 
 #define __put_user_asm_ret(x,size,addr,ret,foo)				\
 if (__builtin_constant_p(ret) && ret == -EFAULT)			\
 __asm__ __volatile__(							\
 	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size " %1, [%2]\n\n\t"					\
+"1:\t"	"st"#size "a %1, [%2] %3\n\n\t"					\
 	".section __ex_table,#alloc\n\t"				\
 	".align	4\n\t"							\
 	".word	1b, __ret_efault\n\n\t"					\
 	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "r" (__m(addr)));			\
+       : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ASI_S));		\
 else									\
 __asm__ __volatile(							\
 	"/* Put user asm ret, inline. */\n"				\
-"1:\t"	"st"#size " %1, [%2]\n\n\t"					\
+"1:\t"	"st"#size "a %1, [%2] %4\n\n\t"					\
 	".section .fixup,#alloc,#execinstr\n\t"				\
 	".align	4\n"							\
 "3:\n\t"								\
@@ -199,33 +181,11 @@
 	".align	4\n\t"							\
 	".word	1b, 3b\n\n\t"						\
 	".previous\n\n\t"						\
-       : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ret))
+       : "=r" (foo) : "r" (x), "r" (__m(addr)),				\
+         "i" (ret), "i" (ASI_S))
 
 extern int __put_user_bad(void);
 
-#define __get_user_check(data,addr,size,type) ({ \
-register int __gu_ret; \
-register unsigned long __gu_val; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __get_user_asm(__gu_val,ub,addr,__gu_ret); break; \
-case 2: __get_user_asm(__gu_val,uh,addr,__gu_ret); break; \
-case 4: __get_user_asm(__gu_val,uw,addr,__gu_ret); break; \
-case 8: __get_user_asm(__gu_val,x,addr,__gu_ret); break; \
-default: __gu_val = 0; __gu_ret = __get_user_bad(); break; \
-} } else { __gu_val = 0; __gu_ret = -EFAULT; } data = (type) __gu_val; __gu_ret; })
-
-#define __get_user_check_ret(data,addr,size,type,retval) ({ \
-register unsigned long __gu_val __asm__ ("l1"); \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __get_user_asm_ret(__gu_val,ub,addr,retval); break; \
-case 2: __get_user_asm_ret(__gu_val,uh,addr,retval); break; \
-case 4: __get_user_asm_ret(__gu_val,uw,addr,retval); break; \
-case 8: __get_user_asm_ret(__gu_val,x,addr,retval); break; \
-default: if (__get_user_bad()) return retval; \
-} data = (type) __gu_val; } else return retval; })
-
 #define __get_user_nocheck(data,addr,size,type) ({ \
 register int __gu_ret; \
 register unsigned long __gu_val; \
@@ -250,7 +210,7 @@
 #define __get_user_asm(x,size,addr,ret)					\
 __asm__ __volatile__(							\
 	"/* Get user asm, inline. */\n"					\
-"1:\t"	"ld"#size " [%2], %1\n\t"					\
+"1:\t"	"ld"#size "a [%2] %4, %1\n\t"					\
 	"clr	%0\n"							\
 "2:\n\n\t"								\
 	".section .fixup,#alloc,#execinstr\n\t"				\
@@ -264,80 +224,63 @@
 	".align	4\n\t"							\
 	".word	1b, 3b\n\n\t"						\
 	".previous\n\t"							\
-       : "=&r" (ret), "=&r" (x) : "r" (__m(addr)),			\
-	 "i" (-EFAULT))
+       : "=r" (ret), "=r" (x) : "r" (__m(addr)),			\
+	 "i" (-EFAULT), "i" (ASI_S))
 
 #define __get_user_asm_ret(x,size,addr,retval)				\
 if (__builtin_constant_p(retval) && retval == -EFAULT)			\
 __asm__ __volatile__(							\
 	"/* Get user asm ret, inline. */\n"				\
-"1:\t"	"ld"#size " [%1], %0\n\n\t"					\
+"1:\t"	"ld"#size "a [%1] %2, %0\n\n\t"					\
 	".section __ex_table,#alloc\n\t"				\
 	".align	4\n\t"							\
 	".word	1b,__ret_efault\n\n\t"					\
 	".previous\n\t"							\
-       : "=&r" (x) : "r" (__m(addr)));					\
+       : "=r" (x) : "r" (__m(addr)), "i" (ASI_S));			\
 else									\
 __asm__ __volatile__(							\
 	"/* Get user asm ret, inline. */\n"				\
-"1:\t"	"ld"#size " [%1], %0\n\n\t"					\
+"1:\t"	"ld"#size "a [%1] %2, %0\n\n\t"					\
 	".section .fixup,#alloc,#execinstr\n\t"				\
 	".align	4\n"							\
 "3:\n\t"								\
 	"ret\n\t"							\
-	" restore %%g0, %2, %%o0\n\n\t"					\
+	" restore %%g0, %3, %%o0\n\n\t"					\
 	".previous\n\t"							\
 	".section __ex_table,#alloc\n\t"				\
 	".align	4\n\t"							\
 	".word	1b, 3b\n\n\t"						\
 	".previous\n\t"							\
-       : "=&r" (x) : "r" (__m(addr)), "i" (retval))
+       : "=r" (x) : "r" (__m(addr)), "i" (retval), "i" (ASI_S))
 
 extern int __get_user_bad(void);
 
-extern __kernel_size_t __copy_user(void *to, void *from, __kernel_size_t size);
+extern __kernel_size_t __copy_to_user(void *to, void *from, __kernel_size_t size);
+extern __kernel_size_t __copy_from_user(void *to, void *from, __kernel_size_t size);
 
-#define copy_to_user(to,from,n) ({ \
-void *__copy_to = (void *) (to); \
-__kernel_size_t __copy_size = (__kernel_size_t) (n); \
-__kernel_size_t __copy_res; \
-if(__copy_size && __access_ok(__copy_to, __copy_size)) { \
-__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
-} else __copy_res = __copy_size; \
-__copy_res; })
+#define copy_to_user(to,from,n) \
+	__copy_to_user((void *)(to), \
+	(void *) (from), (__kernel_size_t)(n))
 
 #define copy_to_user_ret(to,from,n,retval) ({ \
 if (copy_to_user(to,from,n)) \
 	return retval; \
 })
 
-#define __copy_to_user(to,from,n)		\
-	__copy_user((void *)(to),	\
-		    (void *)(from), n)
-
 #define __copy_to_user_ret(to,from,n,retval) ({ \
 if (__copy_to_user(to,from,n)) \
 	return retval; \
 })
 
-#define copy_from_user(to,from,n) ({ \
-void *__copy_from = (void *) (from); \
-__kernel_size_t __copy_size = (__kernel_size_t) (n); \
-__kernel_size_t __copy_res; \
-if(__copy_size && __access_ok(__copy_from, __copy_size)) { \
-__copy_res = __copy_user((void *) (to), __copy_from, __copy_size); \
-} else __copy_res = __copy_size; \
-__copy_res; })
+#define copy_from_user(to,from,n)		\
+	__copy_from_user((void *)(to),	\
+		    (void *)(from), (__kernel_size_t)(n))
 
 #define copy_from_user_ret(to,from,n,retval) ({ \
 if (copy_from_user(to,from,n)) \
 	return retval; \
 })
 
-#define __copy_from_user(to,from,n)		\
-	__copy_user((void *)(to),	\
-		    (void *)(from), n)
-
 #define __copy_from_user_ret(to,from,n,retval) ({ \
 if (__copy_from_user(to,from,n)) \
 	return retval; \
@@ -352,23 +295,18 @@
 	.word 1f,3
 	.previous
 1:
+	wr %%g0, %3, %%asi
 	mov %2, %%o1
-	call __bzero
+	call __bzero_noasi
 	 mov %1, %%o0
 	mov %%o0, %0
-	" : "=r" (ret) : "r" (addr), "r" (size) :
-	"o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
+	" : "=r" (ret) : "r" (addr), "r" (size), "i" (ASI_S) :
+	"cc", "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
   return ret;
 }
 
-#define clear_user(addr,n) ({ \
-void *__clear_addr = (void *) (addr); \
-__kernel_size_t __clear_size = (__kernel_size_t) (n); \
-__kernel_size_t __clear_res; \
-if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
-__clear_res = __clear_user(__clear_addr, __clear_size); \
-} else __clear_res = __clear_size; \
-__clear_res; })
+#define clear_user(addr,n) \
+	__clear_user((void *)(addr), (__kernel_size_t)(n))
 
 #define clear_user_ret(addr,size,retval) ({ \
 if (clear_user(addr,size)) \
@@ -377,23 +315,12 @@
 
 extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
 
-#define strncpy_from_user(dest,src,count) ({ \
-unsigned long __sfu_src = (unsigned long) (src); \
-int __sfu_count = (int) (count); \
-long __sfu_res = -EFAULT; \
-if(__access_ok(__sfu_src, __sfu_count)) { \
-__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
-} __sfu_res; })
+#define strncpy_from_user(dest,src,count) \
+	__strncpy_from_user((unsigned long)(dest), (unsigned long)(src), (int)(count))
 
 extern int __strlen_user(const char *);
 
-extern __inline__ int strlen_user(const char *str)
-{
-	if(!access_ok(VERIFY_READ, str, 0))
-		return 0;
-	else
-		return __strlen_user(str);
-}
+#define strlen_user __strlen_user
 
 #endif  /* __ASSEMBLY__ */
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h
--- v2.1.33/linux/include/asm-sparc64/unistd.h	Thu Mar 27 14:40:10 1997
+++ linux/include/asm-sparc64/unistd.h	Fri Apr 11 10:47:40 1997
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.2 1997/03/18 18:00:26 jj Exp $ */
+/* $Id: unistd.h,v 1.3 1997/04/10 23:32:51 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -283,7 +283,7 @@
 		      "movcc %%xcc, %%o0, %0\n\t" \
 		      : "=r" (__res)\
 		      : "0" (__NR_##name) \
-		      : "g1", "o0"); \
+		      : "g1", "o0", "cc"); \
 if (__res >= 0) \
     return (type) __res; \
 errno = -__res; \
@@ -301,7 +301,7 @@
 		      "movcc %%xcc, %%o0, %0\n\t" \
 		      : "=r" (__res), "=r" ((long)(arg1)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)) \
-		      : "g1", "o0"); \
+		      : "g1", "o0", "cc"); \
 if (__res >= 0) \
 	return (type) __res; \
 errno = -__res; \
@@ -320,7 +320,7 @@
 		      "movcc %%xcc, %%o0, %0\n\t" \
 		      : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
-		      : "g1", "o0", "o1"); \
+		      : "g1", "o0", "o1", "cc"); \
 if (__res >= 0) \
 	return (type) __res; \
 errno = -__res; \
@@ -342,7 +342,7 @@
 		        "=r" ((long)(arg3)) \
 		      : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
 		        "3" ((long)(arg3)) \
-		      : "g1", "o0", "o1", "o2"); \
+		      : "g1", "o0", "o1", "o2", "cc"); \
 if (__res>=0) \
 	return (type) __res; \
 errno = -__res; \
@@ -365,7 +365,7 @@
 		        "=r" ((long)(arg3)), "=r" ((long)(arg4)) \
 		      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
 		        "3" ((long)(arg3)),"4" ((long)(arg4)) \
-		      : "g1", "o0", "o1", "o2", "o3"); \
+		      : "g1", "o0", "o1", "o2", "o3", "cc"); \
 if (__res>=0) \
 	return (type) __res; \
 errno = -__res; \
@@ -391,7 +391,7 @@
 		      : "r" ((long)(arg1)),"r" ((long)(arg2)), \
 		        "r" ((long)(arg3)),"r" ((long)(arg4)),"r" ((long)(arg5)), \
 		        "i" (__NR_##name)  \
-		      : "g1", "o0", "o1", "o2", "o3", "o4"); \
+		      : "g1", "o0", "o1", "o2", "o3", "o4", "cc"); \
 if (__res>=0) \
 	return (type) __res; \
 errno = -__res; \
@@ -461,7 +461,7 @@
 			   "=r" (retval) :
 			   "i" (__NR_clone), "r" (flags | CLONE_VM),
 			   "i" (__NR_exit),  "r" (fn), "r" (arg) :
-			   "g1", "g2", "g3", "o0", "o1", "memory");
+			   "g1", "g2", "g3", "o0", "o1", "memory", "cc");
 	return retval;
 }
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/upa.h linux/include/asm-sparc64/upa.h
--- v2.1.33/linux/include/asm-sparc64/upa.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/upa.h	Fri Apr 11 10:47:40 1997
@@ -1,4 +1,4 @@
-/* $Id */
+/* $Id: upa.h,v 1.2 1997/04/04 00:50:30 davem Exp $ */
 #ifndef _SPARC64_UPA_H
 #define _SPARC64_UPA_H
 
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/vaddrs.h linux/include/asm-sparc64/vaddrs.h
--- v2.1.33/linux/include/asm-sparc64/vaddrs.h	Thu Mar 27 14:40:10 1997
+++ linux/include/asm-sparc64/vaddrs.h	Fri Apr 11 10:47:40 1997
@@ -1,8 +1,6 @@
-/* $Id: vaddrs.h,v 1.1 1997/03/18 18:03:43 jj Exp $ */
+/* $Id: vaddrs.h,v 1.6 1997/04/04 00:50:31 davem Exp $ */
 #ifndef _SPARC64_VADDRS_H
 #define _SPARC64_VADDRS_H
-
-#include <asm/head.h>
 
 /* asm-sparc64/vaddrs.h:  Here will be define the virtual addresses at
  *                      which important I/O addresses will be mapped.
diff -u --recursive --new-file v2.1.33/linux/include/asm-sparc64/winmacro.h linux/include/asm-sparc64/winmacro.h
--- v2.1.33/linux/include/asm-sparc64/winmacro.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/winmacro.h	Wed Dec 31 16:00:00 1969
@@ -1,66 +0,0 @@
-/* $Id: winmacro.h,v 1.1 1996/12/26 13:25:20 davem Exp $
- * winmacro.h: Window loading-unloading macros for Sparc/V9.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC64_WINMACRO_H
-#define _SPARC64_WINMACRO_H
-
-#define STORE_V9_WINDOW_GENERIC_ASI(store_insn, base, offset, the_asi)	\
-	store_insn	%l0, [base + offset + RW_V9_L0] the_asi;	\
-	store_insn	%l1, [base + offset + RW_V9_L1] the_asi;	\
-	store_insn	%l2, [base + offset + RW_V9_L2] the_asi;	\
-	store_insn	%l3, [base + offset + RW_V9_L3] the_asi;	\
-	store_insn	%l4, [base + offset + RW_V9_L4] the_asi;	\
-	store_insn	%l5, [base + offset + RW_V9_L5] the_asi;	\
-	store_insn	%l6, [base + offset + RW_V9_L6] the_asi;	\
-	store_insn	%l7, [base + offset + RW_V9_L7] the_asi;	\
-	store_insn	%i0, [base + offset + RW_V9_I0] the_asi;	\
-	store_insn	%i1, [base + offset + RW_V9_I1] the_asi;	\
-	store_insn	%i2, [base + offset + RW_V9_I2] the_asi;	\
-	store_insn	%i3, [base + offset + RW_V9_I3] the_asi;	\
-	store_insn	%i4, [base + offset + RW_V9_I4] the_asi;	\
-	store_insn	%i5, [base + offset + RW_V9_I5] the_asi;	\
-	store_insn	%i6, [base + offset + RW_V9_I6] the_asi;	\
-	store_insn	%i7, [base + offset + RW_V9_I7] the_asi;
-
-#define STORE_V9_WINDOW_KERNEL(base)		\
-	stx	%l0, [base + RW_V9_L0];		\
-	stx	%l1, [base + RW_V9_L1];		\
-	stx	%l2, [base + RW_V9_L2];		\
-	stx	%l3, [base + RW_V9_L3];		\
-	stx	%l4, [base + RW_V9_L4];		\
-	stx	%l5, [base + RW_V9_L5];		\
-	stx	%l6, [base + RW_V9_L6];		\
-	stx	%l7, [base + RW_V9_L7];		\
-	stx	%i0, [base + RW_V9_I0];		\
-	stx	%i1, [base + RW_V9_I1];		\
-	stx	%i2, [base + RW_V9_I2];		\
-	stx	%i3, [base + RW_V9_I3];		\
-	stx	%i4, [base + RW_V9_I4];		\
-	stx	%i5, [base + RW_V9_I5];		\
-	stx	%i6, [base + RW_V9_I6];		\
-	stx	%i7, [base + RW_V9_I7];
-
-#define LOAD_V9_WINDOW_KERNEL(base)		\
-	ldx	[base + RW_V9_L0], %l0;		\
-	ldx	[base + RW_V9_L1], %l1;		\
-	ldx	[base + RW_V9_L2], %l2;		\
-	ldx	[base + RW_V9_L3], %l3;		\
-	ldx	[base + RW_V9_L4], %l4;		\
-	ldx	[base + RW_V9_L5], %l5;		\
-	ldx	[base + RW_V9_L6], %l6;		\
-	ldx	[base + RW_V9_L7], %l7;		\
-	ldx	[base + RW_V9_I0], %i0;		\
-	ldx	[base + RW_V9_I1], %i1;		\
-	ldx	[base + RW_V9_I2], %i2;		\
-	ldx	[base + RW_V9_I3], %i3;		\
-	ldx	[base + RW_V9_I4], %i4;		\
-	ldx	[base + RW_V9_I5], %i5;		\
-	ldx	[base + RW_V9_I6], %i6;		\
-	ldx	[base + RW_V9_I7], %i7;
-
-#define STORE_V9_WINDOW_ASI_REG(base)		\
-
-#endif /* !(_SPARC64_WINMACRO_H) */
diff -u --recursive --new-file v2.1.33/linux/include/linux/atalk.h linux/include/linux/atalk.h
--- v2.1.33/linux/include/linux/atalk.h	Sun Jan 19 05:47:26 1997
+++ linux/include/linux/atalk.h	Mon Apr 14 11:43:06 1997
@@ -72,11 +72,15 @@
 
 #ifdef __KERNEL__
 
+#include <asm/byteorder.h>
+
 struct ddpehdr
 {
-	/* FIXME for bigendians */
-	/*__u16	deh_pad:2,deh_hops:4,deh_len:10;*/
-	__u16	deh_len:10,deh_hops:4,deh_pad:2;
+#ifdef __LITTLE_ENDIAN_BITFIELD
+	__u16	deh_len:10, deh_hops:4, deh_pad:2;
+#else
+	__u16	deh_pad:2, deh_hops:4, deh_len:10;
+#endif
 	__u16	deh_sum;
 	__u16	deh_dnet;
 	__u16	deh_snet;
@@ -93,8 +97,11 @@
  
 struct ddpshdr
 {
-	/* FIXME for bigendians */
+#ifdef __LITTLE_ENDIAN_BITFIELD
 	__u16	dsh_len:10, dsh_pad:6;
+#else
+	__u16	dsh_pad:6, dsh_len:10;
+#endif
 	__u8	dsh_dport;
 	__u8	dsh_sport;
 	/* And netatalk apps expect to stick the type in themselves */
diff -u --recursive --new-file v2.1.33/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.1.33/linux/include/linux/binfmts.h	Sun Jan 26 02:07:48 1997
+++ linux/include/linux/binfmts.h	Fri Apr 11 10:47:40 1997
@@ -48,9 +48,11 @@
 extern int open_inode(struct inode * inode, int mode);
 
 extern int init_elf_binfmt(void);
+extern int init_elf32_binfmt(void);
 extern int init_aout_binfmt(void);
 extern int init_script_binfmt(void);
 extern int init_java_binfmt(void);
+extern int init_em86_binfmt(void);
 
 extern int prepare_binprm(struct linux_binprm *);
 extern void remove_arg_zero(struct linux_binprm *);
diff -u --recursive --new-file v2.1.33/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.1.33/linux/include/linux/cdrom.h	Sun Dec 29 01:18:04 1996
+++ linux/include/linux/cdrom.h	Mon Apr 14 09:26:00 1997
@@ -368,7 +368,8 @@
 	u_char	number_blocks_lo;
 	u_char	_r3;
 	u_char	block_length_hi; /* block length for blocks in this desc */
-	u_short	block_length;
+	u_char	block_length_med;
+	u_char	block_length_lo;
 };
 
 /*
diff -u --recursive --new-file v2.1.33/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v2.1.33/linux/include/linux/interrupt.h	Mon Apr  7 11:35:31 1997
+++ linux/include/linux/interrupt.h	Mon Apr 14 11:42:12 1997
@@ -3,10 +3,8 @@
 #define _LINUX_INTERRUPT_H
 
 #include <linux/kernel.h>
-
 #include <asm/bitops.h>
 #include <asm/atomic.h>
-#include <asm/hardirq.h>
 
 struct irqaction {
 	void (*handler)(int, void *, struct pt_regs *);
@@ -17,7 +15,6 @@
 	struct irqaction *next;
 };
 
-extern atomic_t intr_count;
 extern volatile unsigned char bh_running;
 
 extern int bh_mask_count[32];
@@ -45,58 +42,8 @@
 	CM206_BH
 };
 
-extern inline void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	bh_mask_count[nr] = 0;
-	bh_mask |= 1 << nr;
-}
-
-extern inline void mark_bh(int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
-/*
- * These use a mask count to correctly handle
- * nested disable/enable calls
- */
-extern inline void disable_bh(int nr)
-{
-	bh_mask &= ~(1 << nr);
-	bh_mask_count[nr]++;
-}
-
-extern inline void enable_bh(int nr)
-{
-	if (!--bh_mask_count[nr])
-		bh_mask |= 1 << nr;
-}
-
-/*
- * start_bh_atomic/end_bh_atomic also nest
- * naturally by using a counter
- */
-extern inline void start_bh_atomic(void)
-{
-#ifdef __SMP__
-	atomic_inc(&intr_count);
-	synchronize_irq();
-#else
-	intr_count++;
-	barrier();
-#endif
-}
-
-extern inline void end_bh_atomic(void)
-{
-#ifdef __SMP__
-	atomic_dec(&intr_count);
-#else
-	barrier();
-	intr_count--;
-#endif
-}
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
 
 /*
  * Autoprobing for irqs:
diff -u --recursive --new-file v2.1.33/linux/include/linux/ioport.h linux/include/linux/ioport.h
--- v2.1.33/linux/include/linux/ioport.h	Thu Mar 27 14:40:10 1997
+++ linux/include/linux/ioport.h	Fri Apr 11 10:47:40 1997
@@ -23,9 +23,9 @@
 extern int get_ioport_list(char *);
 
 #ifdef __sparc__
-extern unsigned int occupy_region(unsigned long base, unsigned long end,
-				  unsigned long num, unsigned int align,
-				  const char *name);
+extern unsigned long occupy_region(unsigned long base, unsigned long end,
+				   unsigned long num, unsigned int align,
+				   const char *name);
 #endif
 
 #define HAVE_AUTOIRQ
diff -u --recursive --new-file v2.1.33/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.1.33/linux/include/linux/netdevice.h	Fri Apr  4 08:52:25 1997
+++ linux/include/linux/netdevice.h	Mon Apr 14 11:43:06 1997
@@ -28,6 +28,8 @@
 #include <linux/if.h>
 #include <linux/if_ether.h>
 
+#include <asm/atomic.h>
+
 /*
  *	For future expansion when we will have different priorities. 
  */
@@ -86,7 +88,7 @@
 struct hh_cache
 {
 	struct hh_cache *hh_next;	/* Next entry			     */
-	int		hh_refcnt;	/* number of users                   */
+	atomic_t	hh_refcnt;	/* number of users                   */
 	unsigned short  hh_type;	/* protocol identifier, f.e ETH_P_IP */
 	char		hh_uptodate;	/* hh_data is valid                  */
 	/* cached hardware header; allow for machine alignment needs.        */
@@ -354,7 +356,7 @@
  
 extern __inline__ void dev_lock_wait(void)
 {
-	while(dev_lockct)
+	while(atomic_read(&dev_lockct))
 		schedule();
 }
 
diff -u --recursive --new-file v2.1.33/linux/include/linux/nfs.h linux/include/linux/nfs.h
--- v2.1.33/linux/include/linux/nfs.h	Mon Apr  7 11:35:31 1997
+++ linux/include/linux/nfs.h	Mon Apr 14 09:31:10 1997
@@ -84,6 +84,15 @@
 #define NFSPROC_READDIR		16
 #define NFSPROC_STATFS		17
 
+/* Mount support for NFSroot */
+#ifdef __KERNEL__
+#define NFS_MNT_PROGRAM		100005
+#define NFS_MNT_VERSION		1
+#define NFS_MNT_PORT		627
+#define NFS_MNTPROC_MNT		1
+#define NFS_MNTPROC_UMNT	3
+#endif
+
 #if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
 
 extern struct rpc_program	nfs_program;
@@ -123,9 +132,9 @@
 struct nfs_entry {
 	__u32			fileid;
 	char *			name;
-	unsigned int		length;
+	unsigned int		length:31,
+				eof:1;
 	__u32			cookie;
-	__u32			eof;
 };
 
 struct nfs_fsinfo {
diff -u --recursive --new-file v2.1.33/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.1.33/linux/include/linux/nfs_fs.h	Mon Apr  7 11:35:31 1997
+++ linux/include/linux/nfs_fs.h	Mon Apr 14 11:42:11 1997
@@ -190,6 +190,12 @@
 extern int  nfs_readpage_sync(struct inode *, struct page *);
 
 /*
+ * linux/fs/mount_clnt.c
+ * (Used only by nfsroot module)
+ */
+extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+
+/*
  * inline functions
  */
 static inline int
@@ -232,6 +238,7 @@
 #define NFSDBG_PROC		0x0010
 #define NFSDBG_XDR		0x0020
 #define NFSDBG_FILE		0x0040
+#define NFSDBG_ROOT		0x0080
 #define NFSDBG_ALL		0xFFFF
 
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.1.33/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.33/linux/include/linux/skbuff.h	Fri Apr  4 08:52:26 1997
+++ linux/include/linux/skbuff.h	Mon Apr 14 11:42:12 1997
@@ -196,12 +196,12 @@
 
 extern __inline__ int skb_cloned(struct sk_buff *skb)
 {
-	return (skb->data_skb->count != 1);
+	return (atomic_read(&skb->data_skb->count) != 1);
 }
 
 extern __inline__ int skb_shared(struct sk_buff *skb)
 {
-	return (skb->users != 1);
+	return (atomic_read(&skb->users) != 1);
 }
 
 /*
diff -u --recursive --new-file v2.1.33/linux/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h
--- v2.1.33/linux/include/linux/sunrpc/clnt.h	Mon Apr  7 11:35:32 1997
+++ linux/include/linux/sunrpc/clnt.h	Mon Apr 14 11:44:27 1997
@@ -126,5 +126,12 @@
 	xprt_set_timeout(&clnt->cl_timeout, retr, incr);
 }
 
+/*
+ * Helper function for NFSroot support
+ */
+#ifdef CONFIG_ROOT_NFS
+int		rpc_getport_external(struct sockaddr_in *, __u32, __u32, int);
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
diff -u --recursive --new-file v2.1.33/linux/include/net/af_unix.h linux/include/net/af_unix.h
--- v2.1.33/linux/include/net/af_unix.h	Thu Dec 12 06:54:21 1996
+++ linux/include/net/af_unix.h	Mon Apr 14 09:31:10 1997
@@ -16,7 +16,7 @@
 
 struct unix_address
 {
-	int		refcnt;
+	atomic_t	refcnt;
 	int		len;
 	unsigned	hash;
 	struct sockaddr_un name[0];
diff -u --recursive --new-file v2.1.33/linux/include/net/dst.h linux/include/net/dst.h
--- v2.1.33/linux/include/net/dst.h	Thu Mar 27 14:40:11 1997
+++ linux/include/net/dst.h	Mon Apr 14 11:45:18 1997
@@ -116,7 +116,7 @@
 static __inline__
 void dst_free(struct dst_entry * dst)
 {
-	if (!dst->use) {
+	if (!atomic_read(&dst->use)) {
 		dst_destroy(dst);
 		return;
 	}
diff -u --recursive --new-file v2.1.33/linux/include/net/ipv6.h linux/include/net/ipv6.h
--- v2.1.33/linux/include/net/ipv6.h	Thu Mar 27 14:40:11 1997
+++ linux/include/net/ipv6.h	Mon Apr 14 11:45:34 1997
@@ -4,7 +4,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: ipv6.h,v 1.5 1997/03/18 18:24:10 davem Exp $
+ *	$Id: ipv6.h,v 1.6 1997/04/01 02:22:58 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -16,6 +16,7 @@
 #define _NET_IPV6_H
 
 #include <linux/ipv6.h>
+#include <asm/hardirq.h>
 #include <net/ndisc.h>
 #include <net/flow.h>
 
@@ -199,7 +200,7 @@
 extern __inline__ int gfp_any(void)
 {
 	int pri = GFP_KERNEL;
-	if (intr_count)
+	if (in_interrupt())
 		pri = GFP_ATOMIC;
 	return pri;
 }
diff -u --recursive --new-file v2.1.33/linux/include/net/neighbour.h linux/include/net/neighbour.h
--- v2.1.33/linux/include/net/neighbour.h	Thu Mar 27 14:40:11 1997
+++ linux/include/net/neighbour.h	Mon Apr 14 11:45:18 1997
@@ -116,7 +116,7 @@
 				    struct neighbour *neigh)
 {
 	start_bh_atomic();
-	if (tbl->tbl_lock == 1)
+	if (atomic_read(&tbl->tbl_lock) == 1)
 	{
 		neigh_table_ins(tbl, neigh);
 	}
diff -u --recursive --new-file v2.1.33/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.33/linux/include/net/sock.h	Fri Apr  4 08:52:26 1997
+++ linux/include/net/sock.h	Mon Apr 14 11:43:08 1997
@@ -794,7 +794,7 @@
 
 extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-	if (sk->rmem_alloc + skb->truesize >= sk->rcvbuf)
+	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= sk->rcvbuf)
 		return -ENOMEM;
 	skb_set_owner_r(skb, sk);
 	skb_queue_tail(&sk->receive_queue,skb);
@@ -805,7 +805,7 @@
 
 extern __inline__ int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-	if (sk->rmem_alloc + skb->truesize >= sk->rcvbuf)
+	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= sk->rcvbuf)
 		return -ENOMEM;
 	skb_set_owner_r(skb, sk);
 	__skb_queue_tail(&sk->receive_queue,skb);
@@ -816,7 +816,7 @@
 
 extern __inline__ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 {
-	if (sk->rmem_alloc + skb->truesize >= sk->rcvbuf)
+	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= sk->rcvbuf)
 		return -ENOMEM;
 	skb_set_owner_r(skb, sk);
 	__skb_queue_tail(&sk->error_queue,skb);
diff -u --recursive --new-file v2.1.33/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.33/linux/include/net/tcp.h	Thu Mar 27 14:40:12 1997
+++ linux/include/net/tcp.h	Mon Apr 14 11:45:23 1997
@@ -20,6 +20,7 @@
 
 #include <linux/config.h>
 #include <linux/tcp.h>
+#include <linux/slab.h>
 #include <net/checksum.h>
 
 /* This is for all connections with a full identity, no wildcards. */
@@ -188,21 +189,7 @@
 	void (*destructor)	(struct open_request *req);
 };
 
-struct open_request {
-	struct open_request	*dl_next;
-	struct open_request	*dl_prev;
-	__u32			rcv_isn;
-	__u32			snt_isn;
-	__u16			mss;
-	__u16			rmt_port;
-	unsigned long		expires;
-	int			retrans;
-	struct or_calltable	*class;
-	struct sock		*sk;
-};
-
 struct tcp_v4_open_req {
-	struct open_request	req;
 	__u32			loc_addr;
 	__u32			rmt_addr;
 	struct ip_options	*opt;
@@ -210,7 +197,6 @@
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 struct tcp_v6_open_req {
-	struct open_request	req;
 	struct in6_addr		loc_addr;
 	struct in6_addr		rmt_addr;
 	struct ipv6_options	*opt;
@@ -218,6 +204,31 @@
 };
 #endif
 
+struct open_request {
+	struct open_request	*dl_next;
+	struct open_request	*dl_prev;
+	__u32			rcv_isn;
+	__u32			snt_isn;
+	__u16			rmt_port;
+	__u16			mss;
+	unsigned long		expires;
+	int			retrans;
+	struct or_calltable	*class;
+	struct sock		*sk;
+	union {
+		struct tcp_v4_open_req v4_req;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+		struct tcp_v6_open_req v6_req;
+#endif
+	} af;
+};
+
+/* SLAB cache for open requests. */
+extern kmem_cache_t *tcp_openreq_cachep;
+
+#define tcp_openreq_alloc()	kmem_cache_alloc(tcp_openreq_cachep, SLAB_ATOMIC)
+#define tcp_openreq_free(req)	kmem_cache_free(tcp_openreq_cachep, req)
+
 /*
  *	Pointers to address related TCP functions
  *	(i.e. things that depend on the address family)
@@ -560,7 +571,7 @@
 {
 	struct tcp_sl_timer *slt = &tcp_slt_array[timer];
 	
-	if (slt->count == 0)
+	if (atomic_read(&slt->count) == 0)
 	{
 		__tcp_inc_slow_timer(slt);
 	}
diff -u --recursive --new-file v2.1.33/linux/ipc/msg.c linux/ipc/msg.c
--- v2.1.33/linux/ipc/msg.c	Sun Jan 26 02:07:48 1997
+++ linux/ipc/msg.c	Fri Apr 11 22:11:21 1997
@@ -137,7 +137,7 @@
 				return -EAGAIN;
 			if (current->signal & ~current->blocked)
 				return -EINTR;
-			if (intr_count) {
+			if (in_interrupt()) {
 				/* Very unlikely, but better safe than sorry */
 				printk(KERN_WARNING "Ouch, kerneld:msgsnd buffers full!\n");
 				return -EINTR;
@@ -774,7 +774,7 @@
 		return -ENODEV;
 
 	/* Do not wait for an answer at interrupt-time! */
-	if (intr_count)
+	if (in_interrupt())
 		ret_size &= ~KERNELD_WAIT;
 #ifdef NEW_KERNELD_PROTOCOL
 	else
diff -u --recursive --new-file v2.1.33/linux/ipc/shm.c linux/ipc/shm.c
--- v2.1.33/linux/ipc/shm.c	Sun Jan 26 02:07:48 1997
+++ linux/ipc/shm.c	Mon Apr 14 09:31:10 1997
@@ -721,7 +721,7 @@
 
 done:	/* pte_val(pte) == shp->shm_pages[idx] */
 	current->min_flt++;
-	mem_map[MAP_NR(pte_page(pte))].count++;
+	atomic_inc(&mem_map[MAP_NR(pte_page(pte))].count);
 	return pte_modify(pte, shmd->vm_page_prot);
 }
 
@@ -821,7 +821,7 @@
 		flush_cache_page(shmd, tmp);
 		set_pte(page_table,
 		  __pte(shmd->vm_pte + SWP_ENTRY(0, idx << SHM_IDX_SHIFT)));
-		mem_map[MAP_NR(pte_page(pte))].count--;
+		atomic_dec(&mem_map[MAP_NR(pte_page(pte))].count);
 		if (shmd->vm_mm->rss > 0)
 			shmd->vm_mm->rss--;
 		flush_tlb_page(shmd, tmp);
@@ -831,7 +831,7 @@
 		break;
 	}
 
-	if (mem_map[MAP_NR(pte_page(page))].count != 1)
+	if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) != 1)
 		goto check_table;
 	shp->shm_pages[idx] = swap_nr;
 	write_swap_page (swap_nr, (char *) pte_page(page));
diff -u --recursive --new-file v2.1.33/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.33/linux/kernel/ksyms.c	Mon Apr  7 11:35:32 1997
+++ linux/kernel/ksyms.c	Mon Apr 14 09:31:10 1997
@@ -183,14 +183,6 @@
 EXPORT_SYMBOL(tty_unregister_driver);
 EXPORT_SYMBOL(tty_std_termios);
 
-#if defined(CONFIG_BLK_DEV_IDECD) || \
-    defined(CONFIG_BLK_DEV_SR) || \
-    defined(CONFIG_CM206)
-EXPORT_SYMBOL(register_cdrom);
-EXPORT_SYMBOL(unregister_cdrom);
-EXPORT_SYMBOL(cdrom_fops);
-#endif
-
 /* block device driver support */
 EXPORT_SYMBOL(block_read);
 EXPORT_SYMBOL(block_write);
@@ -266,7 +258,9 @@
 EXPORT_SYMBOL(tq_scheduler);
 EXPORT_SYMBOL(timer_active);
 EXPORT_SYMBOL(timer_table);
-EXPORT_SYMBOL(intr_count);
+#ifdef __SMP__
+EXPORT_SYMBOL(waitqueue_lock);
+#endif
 
 /* autoirq from  drivers/net/auto_irq.c */
 EXPORT_SYMBOL(autoirq_setup);
diff -u --recursive --new-file v2.1.33/linux/kernel/resource.c linux/kernel/resource.c
--- v2.1.33/linux/kernel/resource.c	Sun Apr 13 10:18:22 1997
+++ linux/kernel/resource.c	Fri Apr 11 10:47:40 1997
@@ -123,8 +123,8 @@
 /*
  * This is for architectures with MMU-managed ports (sparc).
  */
-unsigned int occupy_region(unsigned long base, unsigned long end,
-			unsigned long num, unsigned int align, const char *name)
+unsigned long occupy_region(unsigned long base, unsigned long end,
+			    unsigned long num, unsigned int align, const char *name)
 {
 	unsigned long from = 0, till;
 	unsigned long flags;
@@ -148,14 +148,14 @@
 
 	save_flags(flags);
 	cli();
-	/* printk("occupy: search in %08x[%x] ", base, end - base); */
+	/* printk("occupy: search in %08lx[%08lx] ", base, end - base); */
 	s = NULL;
 	for (p = &iolist; p != NULL; p = p1) {
 		p1 = p->next;
 		/* Find window in list */
-		from = (p->from+p->num + align-1) & ~(align-1);
-		till = (p1 == NULL)? (unsigned) (0 - align): p1->from;
-		/* printk(" %08x:%08x", from, till); */
+		from = (p->from+p->num + align-1) & ~((unsigned long)align-1);
+		till = (p1 == NULL)? (unsigned long) (0 - (unsigned long)align): p1->from;
+		/* printk(" %08lx:%08lx", from, till); */
 		/* Clip window with base and end */
 		if (from < base) from = base;
 		if (till > end) till = end;
diff -u --recursive --new-file v2.1.33/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.33/linux/kernel/sched.c	Sun Apr 13 10:18:22 1997
+++ linux/kernel/sched.c	Mon Apr 14 10:14:08 1997
@@ -16,6 +16,7 @@
  * current-task
  */
 
+#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -49,7 +50,7 @@
 int securelevel = 0;			/* system security level */
 
 long tick = (1000000 + HZ/2) / HZ;	/* timer interrupt period */
-volatile struct timeval xtime;		/* The current time */
+volatile struct timeval xtime __attribute__ ((aligned (8)));	/* The current time */
 int tickadj = 500/HZ;			/* microsecs */
 
 DECLARE_TASK_QUEUE(tq_timer);
@@ -362,6 +363,9 @@
 		 * the scheduler lock
 		 */
 		spin_unlock_irq(&runqueue_lock);
+#ifdef __SMP__
+		prev->processor = NO_PROC_ID;
+#endif
 	
 /*
  * Note! there may appear new tasks on the run-queue during this, as
@@ -510,27 +514,9 @@
  * needs to do something only if count was negative before
  * the increment operation.
  *
- * This routine must execute atomically.
- */
-static inline int waking_non_zero(struct semaphore *sem)
-{
-	int ret;
-	long flags;
-
-	save_flags(flags);
-	cli();
-
-	ret = 0;
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	}
-
-	restore_flags(flags);
-	return ret;
-}
-
-/*
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
  * When __up() is called, the count was negative before
  * incrementing it, and we need to wake up somebody.
  *
@@ -548,7 +534,7 @@
  */
 void __up(struct semaphore *sem)
 {
-	atomic_inc(&sem->waking);
+	wake_one_more(sem);
 	wake_up(&sem->wait);
 }
 
@@ -1131,7 +1117,7 @@
 	}
 }
 
-static __inline__ void update_one_process(struct task_struct *p,
+void update_one_process(struct task_struct *p,
 	unsigned long ticks, unsigned long user, unsigned long system)
 {
 	do_process_times(p, user, system);
@@ -1141,6 +1127,9 @@
 
 static void update_process_times(unsigned long ticks, unsigned long system)
 {
+/*
+ * SMP does this on a per-CPU basis elsewhere
+ */
 #ifndef  __SMP__
 	struct task_struct * p = current;
 	unsigned long user = ticks - system;
@@ -1157,63 +1146,6 @@
 		kstat.cpu_system += system;
 	}
 	update_one_process(p, ticks, user, system);
-#else
-	int cpu,j;
-	cpu = smp_processor_id();
-	for (j=0;j<smp_num_cpus;j++)
-	{
-		int i = cpu_logical_map[j];
-		struct task_struct *p;
-		
-#ifdef __SMP_PROF__
-		if (test_bit(i,&smp_idle_map)) 
-			smp_idle_count[i]++;
-#endif
-		p = current_set[i];
-		/*
-		 * Do we have a real process?
-		 */
-		if (p->pid) {
-			/* assume user-mode process */
-			unsigned long utime = ticks;
-			unsigned long stime = 0;
-			if (cpu == i) {
-				utime = ticks-system;
-				stime = system;
-			} else if (smp_proc_in_lock[j]) {
-				utime = 0;
-				stime = ticks;
-			}
-
-			update_one_process(p, ticks, utime, stime);
-
-			if (p->priority < DEF_PRIORITY)
-				kstat.cpu_nice += utime;
-			else
-				kstat.cpu_user += utime;
-			kstat.cpu_system += stime;
-
-			p->counter -= ticks;
-			if (p->counter >= 0)
-				continue;
-			p->counter = 0;
-		} else {
-			/*
-			 * Idle processor found, do we have anything
-			 * we could run?
-			 */
-			if (!(read_smp_counter(&smp_process_available)))
-				continue;
-		}
-		/* Ok, we should reschedule, do the magic */
-		cli();
-		if (i==cpu) {
-			need_resched = 1;
-		} else {
-			smp_message_pass(i, MSG_RESCHEDULE, 0L, 0);
-		}
-		sti();
-	}
 #endif
 }
 
@@ -1252,37 +1184,13 @@
 	run_timer_list();
 }
 
-/*
- * It is up to the platform where it does the profiling: in the
- * global timer interrupt, or in a special interrupt handler.
- *
- * by default it's done in the global timer interrupt.
- */
-
-static void default_do_profile (struct pt_regs * regs)
-{
-	if (prof_buffer && current->pid) {
-		extern int _stext;
-		unsigned long ip = instruction_pointer(regs);
-		ip -= (unsigned long) &_stext;
-		ip >>= prof_shift;
-		if (ip < prof_len)
-			prof_buffer[ip]++;
-	}
-}
-
-void (*do_profile)(struct pt_regs *) = default_do_profile;
-
 void do_timer(struct pt_regs * regs)
 {
 	(*(unsigned long *)&jiffies)++;
 	lost_ticks++;
 	mark_bh(TIMER_BH);
-	if (!user_mode(regs)) {
+	if (!user_mode(regs))
 		lost_ticks_system++;
-		if (do_profile)
-			do_profile(regs);
-	}
 	if (tq_timer)
 		mark_bh(TQUEUE_BH);
 }
@@ -1667,7 +1575,7 @@
 
 
 	if (t.tv_sec == 0 && t.tv_nsec <= 2000000L &&
-	    current->policy != SCHED_OTHER) 
+	    current->policy != SCHED_OTHER)
 	{
 		/*
 		 * Short delay requests up to 2 ms will be handled with
diff -u --recursive --new-file v2.1.33/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.1.33/linux/kernel/softirq.c	Thu Mar 27 14:40:12 1997
+++ linux/kernel/softirq.c	Mon Apr 14 09:31:10 1997
@@ -23,16 +23,13 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/atomic.h>
-#include <asm/hardirq.h>
-#include <asm/softirq.h>
 
-atomic_t intr_count = 0;
+/* intr_count died a painless death... -DaveM */
 
 int bh_mask_count[32];
 unsigned long bh_active = 0;
 unsigned long bh_mask = 0;
 void (*bh_base[32])(void);
-
 
 /*
  * This needs to make sure that only one bottom half handler
diff -u --recursive --new-file v2.1.33/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.33/linux/mm/filemap.c	Fri Apr  4 08:52:26 1997
+++ linux/mm/filemap.c	Mon Apr 14 09:31:10 1997
@@ -168,7 +168,7 @@
 		   buffer cache; we'd have to modify the following
 		   test to allow for that case. */
 
-		switch (page->count) {
+		switch (atomic_read(&page->count)) {
 			case 1:
 				/* If it has been referenced recently, don't free it */
 				if (clear_bit(PG_referenced, &page->flags))
@@ -214,7 +214,7 @@
 unsigned long page_unuse(unsigned long page)
 {
 	struct page * p = mem_map + MAP_NR(page);
-	int count = p->count;
+	int count = atomic_read(&p->count);
 
 	if (count != 2)
 		return count;
@@ -260,7 +260,7 @@
 	struct inode * inode, unsigned long offset,
 	struct page **hash)
 {
-	page->count++;
+	atomic_inc(&page->count);
 	page->flags &= ~((1 << PG_uptodate) | (1 << PG_error));
 	page->offset = offset;
 	add_page_to_inode_queue(inode, page);
@@ -1000,7 +1000,7 @@
 {
 	unsigned long page = SWP_OFFSET(entry);
 
-	mem_map[page].count++;
+	atomic_inc(&mem_map[page].count);
 	page = (page << PAGE_SHIFT) + PAGE_OFFSET;
 	return mk_pte(page,vma->vm_page_prot);
 }
@@ -1023,7 +1023,7 @@
 		set_pte(ptep, pte_mkclean(pte));
 		flush_tlb_page(vma, address);
 		page = pte_page(pte);
-		mem_map[MAP_NR(page)].count++;
+		atomic_inc(&mem_map[MAP_NR(page)].count);
 	} else {
 		if (pte_none(pte))
 			return 0;
diff -u --recursive --new-file v2.1.33/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- v2.1.33/linux/mm/kmalloc.c	Thu Mar 27 14:40:12 1997
+++ linux/mm/kmalloc.c	Fri Apr 11 22:10:49 1997
@@ -266,8 +266,8 @@
 	priority &= GFP_LEVEL_MASK;
 
 /* Sanity check... */
-#if 0	/* no longer valid */
-	if (intr_count && priority != GFP_ATOMIC) {
+
+	if (in_interrupt() && priority != GFP_ATOMIC) {
 		static int count = 0;
 		if (++count < 5) {
 			printk("kmalloc called nonatomically from interrupt %p\n",
@@ -275,7 +275,7 @@
 			priority = GFP_ATOMIC;
 		}
 	}
-#endif
+
 	save_flags(flags);
 	cli();
 	page = *pg;
diff -u --recursive --new-file v2.1.33/linux/mm/memory.c linux/mm/memory.c
--- v2.1.33/linux/mm/memory.c	Wed Jan  1 06:20:45 1997
+++ linux/mm/memory.c	Mon Apr 14 09:31:10 1997
@@ -199,7 +199,7 @@
 		pte = pte_mkdirty(pte);
 	set_pte(new_pte, pte_mkold(pte));
 	set_pte(old_pte, pte);
-	mem_map[page_nr].count++;
+	atomic_inc(&mem_map[page_nr].count);
 }
 
 static inline int copy_pte_range(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long address, unsigned long size, int cow)
@@ -546,7 +546,7 @@
 
 	if (MAP_NR(page) >= max_mapnr)
 		printk("put_dirty_page: trying to put page %08lx at %08lx\n",page,address);
-	if (mem_map[MAP_NR(page)].count != 1)
+	if (atomic_read(&mem_map[MAP_NR(page)].count) != 1)
 		printk("mem_map disagrees with %08lx at %08lx\n",page,address);
 	pgd = pgd_offset(tsk->mm,address);
 	pmd = pmd_alloc(pgd, address);
@@ -621,7 +621,7 @@
 	/*
 	 * Do we need to copy?
 	 */
-	if (mem_map[MAP_NR(old_page)].count != 1) {
+	if (atomic_read(&mem_map[MAP_NR(old_page)].count) != 1) {
 		if (new_page) {
 			if (PageReserved(mem_map + MAP_NR(old_page)))
 				++vma->vm_mm->rss;
@@ -766,7 +766,8 @@
 		free_page(pte_page(page));
 		return;
 	}
-	if (mem_map[MAP_NR(pte_page(page))].count > 1 && !(vma->vm_flags & VM_SHARED))
+	if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1 &&
+	    !(vma->vm_flags & VM_SHARED))
 		page = pte_wrprotect(page);
 	++vma->vm_mm->rss;
 	++tsk->maj_flt;
@@ -833,7 +834,8 @@
 	entry = mk_pte(page, vma->vm_page_prot);
 	if (write_access) {
 		entry = pte_mkwrite(pte_mkdirty(entry));
-	} else if (mem_map[MAP_NR(page)].count > 1 && !(vma->vm_flags & VM_SHARED))
+	} else if (atomic_read(&mem_map[MAP_NR(page)].count) > 1 &&
+		   !(vma->vm_flags & VM_SHARED))
 		entry = pte_wrprotect(entry);
 	put_page(page_table, entry);
 	/* no need to invalidate: a not-present page shouldn't be cached */
diff -u --recursive --new-file v2.1.33/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.1.33/linux/mm/page_alloc.c	Thu Mar 27 14:40:12 1997
+++ linux/mm/page_alloc.c	Mon Apr 14 09:31:10 1997
@@ -190,7 +190,7 @@
 		index += size; \
 		map += size; \
 	} \
-	map->count = 1; \
+	atomic_set(&map->count, 1); \
 	map->age = PAGE_INITIAL_AGE; \
 } while (0)
 
@@ -201,8 +201,8 @@
 
 	if (order >= NR_MEM_LISTS)
 		return 0;
-#if 0
-	if (intr_count && priority != GFP_ATOMIC) {
+
+	if (in_interrupt() && priority != GFP_ATOMIC) {
 		static int count = 0;
 		if (++count < 5) {
 			printk("gfp called nonatomically from interrupt %p\n",
@@ -210,7 +210,7 @@
 			priority = GFP_ATOMIC;
 		}
 	}
-#endif
+
 	reserved_pages = 5;
 	if (priority != GFP_NFS)
 		reserved_pages = min_free_pages;
@@ -288,6 +288,7 @@
 	memset(mem_map, 0, start_mem - (unsigned long) mem_map);
 	do {
 		--p;
+		atomic_set(&p->count, 0);
 		p->flags = (1 << PG_DMA) | (1 << PG_reserved);
 		p->map_nr = p - mem_map;
 	} while (p > mem_map);
diff -u --recursive --new-file v2.1.33/linux/mm/slab.c linux/mm/slab.c
--- v2.1.33/linux/mm/slab.c	Thu Mar 27 14:40:12 1997
+++ linux/mm/slab.c	Fri Apr 11 22:11:10 1997
@@ -478,7 +478,7 @@
 		printk(KERN_ERR "%sNULL ptr\n", func_nm);
 		return NULL;
 	}
-	if (0 && intr_count) {
+	if (in_interrupt()) {
 		printk(KERN_ERR "%sCalled during int - %s\n", func_nm, name);
 		return NULL;
 	}
@@ -743,7 +743,7 @@
 		goto err_end;
 	}
 
-	if (0 && intr_count) {
+	if (in_interrupt()) {
 		printk(KERN_ERR "kmem_dest: Called during int - %s\n", cachep->c_name);
 err_end:
 		return 1;
@@ -809,7 +809,7 @@
 		goto end;
 	}
 
-	if (0 && intr_count) {
+	if (in_interrupt()) {
 		printk(KERN_ERR "kmem_shrink: Called during int - %s\n", cachep->c_name);
 		goto end;
 	}
@@ -951,7 +951,7 @@
 	 * in kmem_cache_alloc().  If a caller is slightly mis-behaving,
 	 * will eventually be caught here (where it matters)
 	 */
-	if (0 && intr_count && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) {
+	if (in_interrupt() && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) {
 		static int count = 0;
 		if (count < 8) {
 			printk(KERN_ERR "kmem_grow: Called nonatomically from "
diff -u --recursive --new-file v2.1.33/linux/mm/swap.c linux/mm/swap.c
--- v2.1.33/linux/mm/swap.c	Mon Oct 28 04:21:41 1996
+++ linux/mm/swap.c	Mon Apr 14 09:31:10 1997
@@ -44,7 +44,7 @@
 
 /* We track the number of pages currently being asynchronously swapped
    out, so that we don't try to swap TOO many pages out at once */
-atomic_t nr_async_pages = 0;
+atomic_t nr_async_pages = ATOMIC_INIT;
 
 /*
  * Constants for the page aging mechanism: the maximum age (actually,
diff -u --recursive --new-file v2.1.33/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.33/linux/mm/vmscan.c	Sun Apr 13 10:18:22 1997
+++ linux/mm/vmscan.c	Mon Apr 14 09:31:10 1997
@@ -7,7 +7,7 @@
  *  kswapd added: 7.1.96  sct
  *  Removed kswapd_ctl limits, and swap out as many pages as needed
  *  to bring the system back to free_pages_high: 2.4.97, Rik van Riel.
- *  Version: $Id: vmscan.c,v 1.21 1997/01/06 06:54:03 davem Exp $
+ *  Version: $Id: vmscan.c,v 1.23 1997/04/12 04:31:05 davem Exp $
  */
 
 #include <linux/mm.h>
@@ -103,7 +103,7 @@
 			if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
 				kill_proc(pid, SIGBUS, 1);
 		} else {
-			if (page_map->count != 1)
+			if (atomic_read(&page_map->count) != 1)
 				return 0;
 			if (!(entry = get_swap_page()))
 				return 0;
@@ -118,7 +118,7 @@
 		return 1;	/* we slept: the process may not exist any more */
 	}
         if ((entry = find_in_swap_cache(MAP_NR(page))))  {
-		if (page_map->count != 1) {
+		if (atomic_read(&page_map->count) != 1) {
 			set_pte(page_table, pte_mkdirty(pte));
 			printk("Aiee.. duplicated cached swap-cache entry\n");
 			return 0;
@@ -369,7 +369,7 @@
 int kswapd(void *unused)
 {
 	int i;
-	char *revision="$Revision: 1.21 $", *s, *e;
+	char *revision="$Revision: 1.23 $", *s, *e;
 	
 	current->session = 1;
 	current->pgrp = 1;
@@ -412,9 +412,9 @@
 		 */
 		while(nr_free_pages < min_free_pages)
 			try_to_free_page(GFP_KERNEL, 0, 1);
-		while((nr_free_pages + nr_async_pages) < free_pages_low)
+		while((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_low)
 			try_to_free_page(GFP_KERNEL, 0, 1);
-		while((nr_free_pages + nr_async_pages) < free_pages_high)
+		while((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_high)
 			try_to_free_page(GFP_KERNEL, 0, 0);
 	}
 }
@@ -428,13 +428,13 @@
 	int	want_wakeup = 0;
 	static int	last_wakeup_low = 0;
 
-	if ((nr_free_pages + nr_async_pages) < free_pages_low) {
+	if ((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_low) {
 		if (last_wakeup_low)
 			want_wakeup = jiffies >= next_swap_jiffies;
 		else
 			last_wakeup_low = want_wakeup = 1;
 	}
-	else if (((nr_free_pages + nr_async_pages) < free_pages_high) && 
+	else if (((nr_free_pages + atomic_read(&nr_async_pages)) < free_pages_high) && 
 	         jiffies >= next_swap_jiffies) {
 		last_wakeup_low = 0;
 		want_wakeup = 1;
diff -u --recursive --new-file v2.1.33/linux/net/802/sysctl_net_802.c linux/net/802/sysctl_net_802.c
--- v2.1.33/linux/net/802/sysctl_net_802.c	Fri Feb  7 05:54:55 1997
+++ linux/net/802/sysctl_net_802.c	Sun Apr 13 09:23:31 1997
@@ -12,6 +12,7 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/config.h>
 
 ctl_table e802_table[] = {
 	{0}
diff -u --recursive --new-file v2.1.33/linux/net/802/tr.c linux/net/802/tr.c
--- v2.1.33/linux/net/802/tr.c	Fri Feb  7 05:54:55 1997
+++ linux/net/802/tr.c	Sun Apr 13 09:23:31 1997
@@ -14,6 +14,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.1.33/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.33/linux/net/appletalk/ddp.c	Fri Apr  4 08:52:26 1997
+++ linux/net/appletalk/ddp.c	Mon Apr 14 09:31:10 1997
@@ -198,7 +198,9 @@
 			ntohs(s->protinfo.af_at.dest_net),
 			s->protinfo.af_at.dest_node,
 			s->protinfo.af_at.dest_port);
-		len += sprintf (buffer+len,"%08X:%08X ", s->wmem_alloc, s->rmem_alloc);
+		len += sprintf (buffer+len,"%08X:%08X ",
+				atomic_read(&s->wmem_alloc),
+				atomic_read(&s->rmem_alloc));
 		len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid);
 
 		/* Are we still dumping unwanted data then discard the record */
@@ -1891,7 +1893,7 @@
 		 *	Protocol layer
 		 */
 		case TIOCOUTQ:
-			amount=sk->sndbuf-sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if(amount<0)
 				amount=0;
 			break;
diff -u --recursive --new-file v2.1.33/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.33/linux/net/ax25/af_ax25.c	Mon Apr  7 11:35:32 1997
+++ linux/net/ax25/af_ax25.c	Mon Apr 14 09:31:10 1997
@@ -360,7 +360,9 @@
 	struct sk_buff *copy;
 
 	while (sk != NULL) {
-		if (sk->type == SOCK_RAW && sk->protocol == proto && sk->rmem_alloc <= sk->rcvbuf) {
+		if (sk->type == SOCK_RAW &&
+		    sk->protocol == proto &&
+		    atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) {
 			if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
 				return;
 
@@ -417,7 +419,9 @@
 	}
 
 	if (ax25->sk != NULL) {
-		if (ax25->sk->wmem_alloc != 0 || ax25->sk->rmem_alloc != 0) {	/* Defer: outstanding buffers */
+		if (atomic_read(&ax25->sk->wmem_alloc) != 0 ||
+		    atomic_read(&ax25->sk->rmem_alloc) != 0) {
+			/* Defer: outstanding buffers */
 			init_timer(&ax25->timer);
 			ax25->timer.expires  = jiffies + 10 * HZ;
 			ax25->timer.function = ax25_destroy_timer;
@@ -1532,7 +1536,7 @@
 		case TIOCOUTQ:
 			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
 				return err;
-			amount = sk->sndbuf - sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if (amount < 0)
 				amount = 0;
 			put_user(amount, (int *)arg);
@@ -1607,8 +1611,8 @@
 			ax25_info.idletimer = sk->protinfo.ax25->idletimer;
 			ax25_info.n2count   = sk->protinfo.ax25->n2count;
 			ax25_info.state     = sk->protinfo.ax25->state;
-			ax25_info.rcv_q     = sk->rmem_alloc;
-			ax25_info.snd_q     = sk->wmem_alloc;
+			ax25_info.rcv_q     = atomic_read(&sk->rmem_alloc);
+			ax25_info.snd_q     = atomic_read(&sk->wmem_alloc);
 			copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info));
 			return 0;
 
@@ -1682,8 +1686,8 @@
 
 		if (ax25->sk != NULL) {
 			len += sprintf(buffer + len, " %5d %5d\n",
-				ax25->sk->wmem_alloc,
-				ax25->sk->rmem_alloc);
+				atomic_read(&ax25->sk->wmem_alloc),
+				atomic_read(&ax25->sk->rmem_alloc));
 		} else {
 			len += sprintf(buffer + len, "\n");
 		}
diff -u --recursive --new-file v2.1.33/linux/net/ax25/ax25_ds_timer.c linux/net/ax25/ax25_ds_timer.c
--- v2.1.33/linux/net/ax25/ax25_ds_timer.c	Thu Mar 27 14:40:13 1997
+++ linux/net/ax25/ax25_ds_timer.c	Mon Apr 14 09:31:10 1997
@@ -146,7 +146,7 @@
 			 * Check the state of the receive buffer.
 			 */
 			if (ax25->sk != NULL) {
-				if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+				if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
 					ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
 					break;
 				}
diff -u --recursive --new-file v2.1.33/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- v2.1.33/linux/net/ax25/ax25_in.c	Thu Mar 27 14:40:14 1997
+++ linux/net/ax25/ax25_in.c	Mon Apr 14 09:31:10 1997
@@ -325,7 +325,7 @@
 			case AX25_P_TEXT:
 				/* Now find a suitable dgram socket */
 				if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
-					if (sk->rmem_alloc >= sk->rcvbuf) {
+					if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
 						kfree_skb(skb, FREE_READ);
 					} else {
 						/*
diff -u --recursive --new-file v2.1.33/linux/net/ax25/ax25_std_timer.c linux/net/ax25/ax25_std_timer.c
--- v2.1.33/linux/net/ax25/ax25_std_timer.c	Thu Feb 27 10:57:32 1997
+++ linux/net/ax25/ax25_std_timer.c	Mon Apr 14 09:31:10 1997
@@ -66,7 +66,8 @@
 			 * Check the state of the receive buffer.
 			 */
 			if (ax25->sk != NULL) {
-				if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+				if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
+				    (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
 					ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
 					ax25->condition &= ~AX25_COND_ACK_PENDING;
 					ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
diff -u --recursive --new-file v2.1.33/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c
--- v2.1.33/linux/net/ax25/sysctl_net_ax25.c	Thu Mar 27 14:40:14 1997
+++ linux/net/ax25/sysctl_net_ax25.c	Sun Apr 13 09:23:31 1997
@@ -7,6 +7,7 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/config.h>
 #include <net/ax25.h>
 
 static int min_ipdefmode[] = {0},	max_ipdefmode[] = {1};
diff -u --recursive --new-file v2.1.33/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.1.33/linux/net/core/datagram.c	Sat Jan 25 13:46:14 1997
+++ linux/net/core/datagram.c	Mon Apr 14 09:31:10 1997
@@ -123,7 +123,7 @@
 			goto no_packet;
 
 		wait_for_packet(sk);
-	  }
+	}
 
 	/* Again only user level code calls this function, so nothing interrupt level
 	   will suddenly eat the receive_queue */
@@ -228,7 +228,7 @@
 			if (sock_wspace(sk) >= MIN_WRITE_SPACE)
 				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 		} else {
-			if (sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
+			if (sk->sndbuf - atomic_read(&sk->wmem_alloc) >= MIN_WRITE_SPACE)
 				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 		}
 	}
diff -u --recursive --new-file v2.1.33/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.33/linux/net/core/dev.c	Sun Apr 13 10:18:22 1997
+++ linux/net/core/dev.c	Mon Apr 14 09:31:10 1997
@@ -122,7 +122,7 @@
  *	Device list lock
  */
  
-atomic_t dev_lockct=0;
+atomic_t dev_lockct = ATOMIC_INIT;
  
 /*
  *	Our notifier list
diff -u --recursive --new-file v2.1.33/linux/net/core/dst.c linux/net/core/dst.c
--- v2.1.33/linux/net/core/dst.c	Thu Mar 27 14:40:14 1997
+++ linux/net/core/dst.c	Mon Apr 14 09:31:10 1997
@@ -20,7 +20,7 @@
 #include <net/dst.h>
 
 struct dst_entry * dst_garbage_list;
-atomic_t	dst_total;
+atomic_t	dst_total = ATOMIC_INIT;
 
 static unsigned long dst_gc_timer_expires;
 static unsigned long dst_gc_timer_inc = DST_GC_MAX;
@@ -41,7 +41,7 @@
 	del_timer(&dst_gc_timer);
 	dstp = &dst_garbage_list;
 	while ((dst = *dstp) != NULL) {
-		if (dst->use) {
+		if (atomic_read(&dst->use)) {
 			dstp = &dst->next;
 			delayed++;
 			continue;
@@ -58,7 +58,9 @@
 	dst_gc_timer_inc += DST_GC_INC;
 	dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
 #if RT_CACHE_DEBUG >= 2
-	printk("dst_total: %d/%d/%d %ld\n", dst_total, delayed, hh_count, dst_gc_timer_expires);
+	printk("dst_total: %d/%d/%d %ld\n",
+	       atomic_read(&dst_total), delayed,
+	       atomic_read(&hh_count), dst_gc_timer_expires);
 #endif
 	add_timer(&dst_gc_timer);
 }
@@ -83,7 +85,7 @@
 		return NULL;
 	memset(dst, 0, size);
 	dst->ops = ops;
-	dst->refcnt = 1;
+	atomic_set(&dst->refcnt, 1);
 	dst->lastuse = jiffies;
 	dst->input = dst_discard;
 	dst->output = dst_blackhole;
diff -u --recursive --new-file v2.1.33/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.1.33/linux/net/core/skbuff.c	Thu Mar 27 14:40:15 1997
+++ linux/net/core/skbuff.c	Mon Apr 14 09:31:10 1997
@@ -60,9 +60,9 @@
  *	Resource tracking variables
  */
 
-atomic_t net_skbcount = 0;
-atomic_t net_allocs = 0;
-atomic_t net_fails  = 0;
+static atomic_t net_skbcount = ATOMIC_INIT;
+static atomic_t net_allocs = ATOMIC_INIT;
+static atomic_t net_fails  = ATOMIC_INIT;
 
 extern atomic_t ip_frag_mem;
 
@@ -75,11 +75,15 @@
 
 void show_net_buffers(void)
 {
-	printk(KERN_INFO "Networking buffers in use          : %u\n",net_skbcount);
-	printk(KERN_INFO "Total network buffer allocations   : %u\n",net_allocs);
-	printk(KERN_INFO "Total failed network buffer allocs : %u\n",net_fails);
+	printk(KERN_INFO "Networking buffers in use          : %u\n",
+	       atomic_read(&net_skbcount));
+	printk(KERN_INFO "Total network buffer allocations   : %u\n",
+	       atomic_read(&net_allocs));
+	printk(KERN_INFO "Total failed network buffer allocs : %u\n",
+	       atomic_read(&net_fails));
 #ifdef CONFIG_INET
-	printk(KERN_INFO "IP fragment buffer size            : %u\n",ip_frag_mem);
+	printk(KERN_INFO "IP fragment buffer size            : %u\n",
+	       atomic_read(&ip_frag_mem));
 #endif	
 }
 
@@ -606,7 +610,7 @@
 	int len;
 	unsigned char *bptr;
 
-	if (0 && intr_count && priority!=GFP_ATOMIC) 
+	if (in_interrupt() && priority!=GFP_ATOMIC) 
 	{
 		static int count = 0;
 		if (++count < 5) {
@@ -633,7 +637,7 @@
 	bptr=(unsigned char *)kmalloc(size,priority);
 	if (bptr == NULL)
 	{
-		net_fails++;
+		atomic_inc(&net_fails);
 		return NULL;
 	}
 #ifdef PARANOID_BUGHUNT_MODE
@@ -647,12 +651,12 @@
 	 *	by doing the following. Which is to deliberately put the
 	 *	skb at the _end_ not the start of the memory block.
 	 */
-	net_allocs++;
+	atomic_inc(&net_allocs);
 	
 	skb=(struct sk_buff *)(bptr+size)-1;
 
-	skb->count = 1;		/* only one reference to this */
-	skb->data_skb = skb;	/* and we're our own data skb */
+	atomic_set(&skb->count, 1);		/* only one reference to this */
+	skb->data_skb = skb;			/* and we're our own data skb */
 
 	skb->pkt_type = PACKET_HOST;	/* Default type */
 	skb->pkt_bridged = 0;		/* Not bridged */
@@ -667,11 +671,11 @@
 	skb->destructor = NULL;
 	memset(skb->cb, 0, sizeof(skb->cb));
 	skb->priority = SOPRI_NORMAL;
-	net_skbcount++;
+	atomic_inc(&net_skbcount);
 #if CONFIG_SKB_CHECK
 	skb->magic_debug_cookie = SK_GOOD_SKB;
 #endif
-	skb->users = 1;
+	atomic_set(&skb->users, 1);
 	/* Load the data pointers */
 	skb->head=bptr;
 	skb->data=bptr;
@@ -741,7 +745,7 @@
 			return NULL;
 	}
 	memcpy(n, skb, sizeof(*n));
-	n->count = 1;
+	atomic_set(&n->count, 1);
 	skb = skb->data_skb;
 	atomic_inc(&skb->count);
 	atomic_inc(&net_allocs);
@@ -752,7 +756,7 @@
 	n->list = NULL;
 	n->sk = NULL;
 	n->tries = 0;
-	n->users = 1;
+	atomic_set(&n->users, 1);
 	n->inclone = inbuff;
 	n->destructor = NULL;
 	return n;
@@ -807,7 +811,7 @@
 	n->used=skb->used;
 	n->arp=skb->arp;
 	n->tries=0;
-	n->users=1;
+	atomic_set(&n->users, 1);
 	n->pkt_type=skb->pkt_type;
 	n->stamp=skb->stamp;
 	n->destructor = NULL;
@@ -862,7 +866,7 @@
 	n->used=skb->used;
 	n->arp=skb->arp;
 	n->tries=0;
-	n->users=1;
+	atomic_set(&n->users, 1);
 	n->pkt_type=skb->pkt_type;
 	n->stamp=skb->stamp;
 	n->destructor = NULL;
diff -u --recursive --new-file v2.1.33/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.33/linux/net/core/sock.c	Fri Apr  4 08:52:28 1997
+++ linux/net/core/sock.c	Mon Apr 14 09:31:10 1997
@@ -512,7 +512,7 @@
 
 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
 {
-	if (force || sk->wmem_alloc < sk->sndbuf) {
+	if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
 		struct sk_buff * skb = alloc_skb(size, priority);
 		if (skb) {
 			atomic_add(skb->truesize, &sk->wmem_alloc);
@@ -526,7 +526,7 @@
 
 struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
 {
-	if (force || sk->rmem_alloc < sk->rcvbuf) {
+	if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) {
 		struct sk_buff *skb = alloc_skb(size, priority);
 		if (skb) {
 			atomic_add(skb->truesize, &sk->rmem_alloc);
@@ -545,9 +545,9 @@
 
 	if (sk != NULL) 
 	{
-		if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW) 
+		if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf-2*MIN_WINDOW) 
 			return(0);
-		amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
+		amt = min((sk->rcvbuf-atomic_read(&sk->rmem_alloc))/2-MIN_WINDOW, MAX_WINDOW);
 		if (amt < 0) 
 			return(0);
 		return(amt);
@@ -562,9 +562,9 @@
 	{
 		if (sk->shutdown & SEND_SHUTDOWN)
 			return(0);
-		if (sk->wmem_alloc >= sk->sndbuf)
+		if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf)
 			return(0);
-		return sk->sndbuf - sk->wmem_alloc;
+		return sk->sndbuf - atomic_read(&sk->wmem_alloc);
 	}
 	return(0);
 }
@@ -627,7 +627,7 @@
 				*errcode=-EPIPE;
 				return NULL;
 			}
-			tmp = sk->wmem_alloc;
+			tmp = atomic_read(&sk->wmem_alloc);
 			cli();
 			if(sk->shutdown&SEND_SHUTDOWN)
 			{
@@ -637,7 +637,7 @@
 			}
 			
 #if 1
-			if( tmp <= sk->wmem_alloc)
+			if( tmp <= atomic_read(&sk->wmem_alloc))
 #else
 			/* ANK: Line above seems either incorrect
 			 *	or useless. sk->wmem_alloc has a tiny chance to change
@@ -647,7 +647,7 @@
 			 *	In any case I'd delete this check at all, or
 			 *	change it to:
 			 */
-			if (sk->wmem_alloc + size >= sk->sndbuf) 
+			if (atomic_read(&sk->wmem_alloc) + size >= sk->sndbuf) 
 #endif
 			{
 				sk->socket->flags &= ~SO_NOSPACE;
@@ -765,7 +765,9 @@
 		kfree_skb(skb,FREE_READ);
 	}
 
-	if(sk->wmem_alloc == 0 && sk->rmem_alloc == 0 && sk->dead)
+	if(atomic_read(&sk->wmem_alloc) == 0 &&
+	   atomic_read(&sk->rmem_alloc) == 0 &&
+	   sk->dead)
 	{
 		sk_free(sk);
 	}
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.33/linux/net/ipv4/af_inet.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/af_inet.c	Mon Apr 14 09:31:10 1997
@@ -184,7 +184,7 @@
 	 */
 		  
 	printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n",
-	       sk->rmem_alloc, sk->wmem_alloc);
+	       atomic_read(&sk->rmem_alloc), atomic_read(&sk->wmem_alloc));
 
 	sk->destroy = 1;
 	sk->ack_backlog = 0;
@@ -216,7 +216,7 @@
 	 * structure, otherwise we need to keep it around until
 	 * everything is gone.
 	 */
-	if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
+	if (atomic_read(&sk->rmem_alloc) == 0 && atomic_read(&sk->wmem_alloc) == 0)
 		kill_sk_now(sk);
 	else
 		kill_sk_later(sk);
@@ -1057,6 +1057,7 @@
 };
 #endif		/* CONFIG_PROC_FS */
 
+extern void tcp_init(void);
 
 /*
  *	Called by socket.c on kernel startup.  
@@ -1107,6 +1108,9 @@
   	 */
 
 	ip_init();
+
+	/* Setup TCP slab cache for open requests. */
+	tcp_init();
 
 	/*
 	 *	Set the ICMP layer up
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.33/linux/net/ipv4/arp.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/arp.c	Mon Apr 14 09:31:10 1997
@@ -230,9 +230,9 @@
 
 int sysctl_arp_dead_res_time = ARP_DEAD_RES_TIME;
 
-
+/* This should be completely nuked... -DaveM */
 #if RT_CACHE_DEBUG >= 1
-#define ASSERT_BH() if (!intr_count) printk(KERN_CRIT __FUNCTION__ " called from SPL=0\n");
+#define ASSERT_BH() if (!in_interrupt()) printk(KERN_CRIT __FUNCTION__ " called from SPL=0\n");
 #else
 #define ASSERT_BH()
 #endif
@@ -251,8 +251,8 @@
 };
 
 
-static atomic_t arp_size = 0;
-static atomic_t arp_unres_size = 0;
+static atomic_t arp_size = ATOMIC_INIT;
+static atomic_t arp_unres_size = ATOMIC_INIT;
 
 #ifdef CONFIG_ARPD
 static int arpd_not_running;
@@ -424,7 +424,7 @@
 	arpreq->stamp = arpd_stamp;
 	arpreq->updated = updated;
 	if (ha)
-		memcpy(arpreq->u.neigh.ha, ha, sizeof(arpreq->u.neigh.ha));
+		memcpy(arpreq->ha, ha, sizeof(arpreq->ha));
 
 	retval = netlink_post(NETLINK_ARPD, skb);
 	if (retval)
@@ -503,7 +503,7 @@
 	else
 	{
 		start_bh_atomic();
-		arp_update(retreq->ip, retreq->u.neigh.ha, dev, retreq->updated, 0);
+		arp_update(retreq->ip, retreq->ha, dev, retreq->updated, 0);
 		end_bh_atomic();
 	}
 
@@ -541,7 +541,7 @@
 	unsigned long now = jiffies;
 	int result = 0;
 
-	static last_index;
+	static int last_index;
 
 	if (last_index >= ARP_TABLE_SIZE)
 		last_index = 0;
@@ -554,7 +554,7 @@
 		{
 			if (!(entry->flags & ATF_PERM))
 			{
-				if (!entry->u.neigh.refcnt &&
+				if (!atomic_read(&entry->u.neigh.refcnt) &&
 				    now - entry->u.neigh.lastused > sysctl_arp_timeout)
 				{
 #if RT_CACHE_DEBUG >= 2
@@ -562,11 +562,11 @@
 #endif
 					arp_free(pentry);
 					result++;
-					if (arp_size < ARP_MAXSIZE)
+					if (atomic_read(&arp_size) < ARP_MAXSIZE)
 						goto done;
 					continue;
 				}
-				if (!entry->u.neigh.refcnt &&
+				if (!atomic_read(&entry->u.neigh.refcnt) &&
 				    entry->u.neigh.lastused < oldest_used)
 				{
 					oldest_entry = pentry;
@@ -602,7 +602,7 @@
 			    (entry->retries < sysctl_arp_max_tries ||
 			     entry->timer.expires - now <
 			     sysctl_arp_res_time - sysctl_arp_res_time/32)) {
-				if (!entry->u.neigh.refcnt) {
+				if (!atomic_read(&entry->u.neigh.refcnt)) {
 #if RT_CACHE_DEBUG >= 2
 					printk("arp_unres_expire: %08x discarded\n", entry->ip);
 #endif
@@ -653,7 +653,7 @@
 				continue;
 			}
 
-			if (!entry->u.neigh.refcnt &&
+			if (!atomic_read(&entry->u.neigh.refcnt) &&
 			    now - entry->u.neigh.lastused > sysctl_arp_timeout)
 			{
 #if RT_CACHE_DEBUG >= 2
@@ -735,7 +735,7 @@
 
 	arp_purge_send_q(entry);
 
-	if (entry->u.neigh.refcnt)
+	if (atomic_read(&entry->u.neigh.refcnt))
 	{
 		/*
 		 *	The host is dead, but someone refers to it.
@@ -797,19 +797,20 @@
 {
 	struct arp_table * entry;
 
-	if (how && arp_size >= ARP_MAXSIZE)
+	if (how && atomic_read(&arp_size) >= ARP_MAXSIZE)
 		arp_force_expire();
-	if (how > 1 && arp_unres_size >= ARP_MAX_UNRES) {
+	if (how > 1 && atomic_read(&arp_unres_size) >= ARP_MAX_UNRES) {
 		arp_unres_expire();
-		if (arp_unres_size >= ARP_MAX_UNRES) {
-			printk(KERN_DEBUG "arp_unres_size=%d\n", arp_unres_size);
+		if (atomic_read(&arp_unres_size) >= ARP_MAX_UNRES) {
+			printk(KERN_DEBUG "arp_unres_size=%d\n",
+			       atomic_read(&arp_unres_size));
 			return NULL;
 		}
 	}
 
 	entry = (struct arp_table *)neigh_alloc(sizeof(struct arp_table),
 						&arp_neigh_ops);
-	entry->u.neigh.refcnt = 1;
+	atomic_set(&entry->u.neigh.refcnt, 1);
 
 	if (entry != NULL)
 	{
@@ -1780,7 +1781,7 @@
 		    && (entry->u.neigh.dev == dev || (!(r->arp_flags&ATF_PUBL) && !dev))
 		    && (!(r->arp_flags&ATF_MAGIC) || r->arp_flags == entry->flags))
 		{
-			if (!entry->u.neigh.refcnt)
+			if (!atomic_read(&entry->u.neigh.refcnt))
 			{
 				arp_free(entryp);
 				retval = 0;
@@ -1935,8 +1936,8 @@
 				 entry->mask==DEF_ARP_NETMASK ?
 				 "*" : in_ntoa(entry->mask),
 				 entry->u.neigh.dev ? entry->u.neigh.dev->name : "*", 
-				 entry->u.neigh.refcnt,
-				 entry->u.neigh.hh ? entry->u.neigh.hh->hh_refcnt : -1,
+				 atomic_read(&entry->u.neigh.refcnt),
+				 entry->u.neigh.hh ? atomic_read(&entry->u.neigh.hh->hh_refcnt) : -1,
 				 entry->u.neigh.hh ? entry->u.neigh.hh->hh_uptodate : 0);
 #endif
 	
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/fib.c linux/net/ipv4/fib.c
--- v2.1.33/linux/net/ipv4/fib.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/fib.c	Mon Apr 14 09:31:10 1997
@@ -117,11 +117,11 @@
  */
 
 static struct wait_queue *fib_wait;
-atomic_t fib_users;
+static atomic_t fib_users = ATOMIC_INIT;
 
 static void fib_lock(void)
 {
-	while (fib_users)
+	while (atomic_read(&fib_users))
 		sleep_on(&fib_wait);
 	atomic_inc(&fib_users);
 	dev_lock_list();
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.1.33/linux/net/ipv4/ip_fragment.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ip_fragment.c	Mon Apr 14 09:31:10 1997
@@ -46,7 +46,7 @@
 
 static struct ipq *ipqueue = NULL;		/* IP fragment queue	*/
 
-atomic_t ip_frag_mem = 0;			/* Memory used for fragments */
+atomic_t ip_frag_mem = ATOMIC_INIT;		/* Memory used for fragments */
 
 char *in_ntoa(unsigned long in);
 
@@ -105,7 +105,7 @@
 	 
 	save_flags(flags);
 	cli();
-	ip_frag_mem+=skb->truesize;
+	atomic_add(skb->truesize, &ip_frag_mem);
 	restore_flags(flags);
 
 	return(fp);
@@ -226,7 +226,7 @@
  
 static void ip_evictor(void)
 {
-	while(ip_frag_mem>IPFRAG_LOW_THRESH)
+	while(atomic_read(&ip_frag_mem)>IPFRAG_LOW_THRESH)
 	{
 		if(!ipqueue)
 			panic("ip_evictor: memcount");
@@ -422,7 +422,7 @@
 	 *	Start by cleaning up the memory
 	 */
 
-	if(ip_frag_mem>IPFRAG_HIGH_THRESH)
+	if(atomic_read(&ip_frag_mem)>IPFRAG_HIGH_THRESH)
 		ip_evictor();
 	/* 
 	 *	Find the entry of this IP datagram in the "incomplete datagrams" queue. 
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c
--- v2.1.33/linux/net/ipv4/ip_masq_raudio.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ip_masq_raudio.c	Fri Apr 11 10:47:40 1997
@@ -2,7 +2,7 @@
  *		IP_MASQ_RAUDIO  - Real Audio masquerading module
  *
  *
- * Version:	@(#)$Id: ip_masq_raudio.c,v 1.3 1996/05/20 13:24:26 nigel Exp $
+ * Version:	@(#)$Id: ip_masq_raudio.c,v 1.5 1997/04/03 08:52:02 davem Exp $
  *
  * Author:	Nigel Metheringham
  *		[strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.1.33/linux/net/ipv4/ipmr.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/ipmr.c	Fri Apr 11 10:47:40 1997
@@ -314,6 +314,8 @@
 		kfree_skb(skb, FREE_READ);
 		return ret;
 	}
+
+	return ret;
 }
 
 /*
@@ -357,7 +359,7 @@
 			/* If the report failed throw the cache entry 
 			   out - Brad Parker */
 			if(ipmr_cache_report(skb, vifi, 0)<0)
-				impr_cache_delete(cache);
+				ipmr_cache_delete(cache);
 		}
 	}
 	/*
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.1.33/linux/net/ipv4/proc.c	Sun Apr 13 10:18:22 1997
+++ linux/net/ipv4/proc.c	Mon Apr 14 09:31:10 1997
@@ -92,18 +92,27 @@
 		destp = sp->dummy_th.dest;
 		srcp  = sp->dummy_th.source;
 
+		/* FIXME: The fact that retransmit_timer occurs as a field
+		 * in two different parts of the socket structure is,
+	 	 * to say the least, confusing. This code now uses the
+		 * right retransmit_timer variable, but I'm not sure
+		 * the rest of the timer stuff is still correct.
+		 * In particular I'm not sure what the timeout value
+		 * is suppose to reflect (as opposed to tm->when). -- erics
+		 */
+
 		/* Since we are Little Endian we need to swap the bytes :-( */
 		destp = ntohs(destp);
 		srcp  = ntohs(srcp);
-		timer_active1 = del_timer(&sp->retransmit_timer);
+		timer_active1 = del_timer(&tp->retransmit_timer);
 		timer_active2 = del_timer(&sp->timer);
-		if (!timer_active1) sp->retransmit_timer.expires=0;
+		if (!timer_active1) tp->retransmit_timer.expires=0;
 		if (!timer_active2) sp->timer.expires=0;
 		timer_active=0;
 		timer_expires=(unsigned)-1;
-		if (timer_active1 && sp->retransmit_timer.expires < timer_expires) {
+		if (timer_active1 && tp->retransmit_timer.expires < timer_expires) {
 			timer_active=timer_active1;
-			timer_expires=sp->retransmit_timer.expires;
+			timer_expires=tp->retransmit_timer.expires;
 		}
 		if (timer_active2 && sp->timer.expires < timer_expires) {
 			timer_active=timer_active2;
@@ -112,14 +121,15 @@
 		sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
 			" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
 			i, src, srcp, dest, destp, sp->state, 
-			format==0?sp->write_seq-tp->snd_una:sp->wmem_alloc, 
-			format==0?tp->rcv_nxt-sp->copied_seq:sp->rmem_alloc,
-			timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
+			format==0?sp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc), 
+			format==0?tp->rcv_nxt-sp->copied_seq:atomic_read(&sp->rmem_alloc),
+			timer_active, timer_expires-jiffies,
+			(unsigned) atomic_read(&sp->retransmits),
 			sp->socket ? sp->socket->inode->i_uid:0,
 			timer_active?sp->timeout:0,
 			sp->socket ? sp->socket->inode->i_ino:0);
 
-		if (timer_active1) add_timer(&sp->retransmit_timer);
+		if (timer_active1) add_timer(&tp->retransmit_timer);
 		if (timer_active2) add_timer(&sp->timer);
 		len += sprintf(buffer+len, "%-127s\n", tmpbuf);
 		if(len >= length)
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.33/linux/net/ipv4/route.c	Thu Mar 27 14:40:15 1997
+++ linux/net/ipv4/route.c	Mon Apr 14 09:31:10 1997
@@ -111,7 +111,7 @@
  * Route cache.
  */
 
-static atomic_t		 rt_cache_size;
+static atomic_t		 rt_cache_size = ATOMIC_INIT;
 static struct rtable 	*rt_hash_table[RT_HASH_DIVISOR];
 
 static struct rtable * rt_intern_hash(unsigned hash, struct rtable * rth, u16 protocol);
@@ -160,12 +160,12 @@
 				r->u.dst.dev ? r->u.dst.dev->name : "*",
 				(unsigned long)r->rt_dst,
 				(unsigned long)r->rt_gateway,
-				r->rt_flags, r->u.dst.refcnt,
-				r->u.dst.use, 0,
+				r->rt_flags, atomic_read(&r->u.dst.refcnt),
+				atomic_read(&r->u.dst.use), 0,
 				(unsigned long)r->rt_src, (int)r->u.dst.pmtu,
 				r->u.dst.window,
 				(int)r->u.dst.rtt, r->key.tos,
-				r->u.dst.hh ? r->u.dst.hh->hh_refcnt : -1,
+				r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1,
 				r->u.dst.hh ? r->u.dst.hh->hh_uptodate : 0,
 				r->rt_spec_dst,
 				i);
@@ -213,7 +213,8 @@
 			 * Cleanup aged off entries.
 			 */
 
-			if (!rth->u.dst.use && now - rth->u.dst.lastuse > RT_CACHE_TIMEOUT) {
+			if (!atomic_read(&rth->u.dst.use) &&
+			    (now - rth->u.dst.lastuse > RT_CACHE_TIMEOUT)) {
 				*rthp = rth_next;
 				atomic_dec(&rt_cache_size);
 #if RT_CACHE_DEBUG >= 2
@@ -235,7 +236,7 @@
 
 			if ( rth_next->u.dst.lastuse - rth->u.dst.lastuse > RT_CACHE_BUBBLE_THRESHOLD ||
 			    (rth->u.dst.lastuse - rth_next->u.dst.lastuse < 0 &&
-			     rth->u.dst.use < rth_next->u.dst.use)) {
+			     atomic_read(&rth->u.dst.use) < atomic_read(&rth_next->u.dst.use))) {
 #if RT_CACHE_DEBUG >= 2
 				printk("rt_check_expire bubbled %02x@%08x<->%08x\n", rover, rth->rt_dst, rth_next->rt_dst);
 #endif
@@ -338,7 +339,8 @@
 		if (!rt_hash_table[i])
 			continue;
 		for (rthp=&rt_hash_table[i]; (rth=*rthp); rthp=&rth->u.rt_next)	{
-			if (rth->u.dst.use || now - rth->u.dst.lastuse > expire)
+			if (atomic_read(&rth->u.dst.use) ||
+			    (now - rth->u.dst.lastuse > expire))
 				continue;
 			atomic_dec(&rt_cache_size);
 			*rthp = rth->u.rt_next;
@@ -349,7 +351,7 @@
 	}
 
 	last_gc = now;
-	if (rt_cache_size < RT_CACHE_MAX_SIZE)
+	if (atomic_read(&rt_cache_size) < RT_CACHE_MAX_SIZE)
 		expire = RT_CACHE_TIMEOUT>>1;
 	else
 		expire >>= 1;
@@ -380,7 +382,7 @@
 #endif
 			memset(hh, 0, sizeof(struct hh_cache));
 			hh->hh_type = ETH_P_IP;
-			hh->hh_refcnt = 0;
+			atomic_set(&hh->hh_refcnt, 0);
 			hh->hh_next = NULL;
 			if (rt->u.dst.dev->hard_header_cache(&rt->u.dst, neigh, hh)) {
 				kfree(hh);
@@ -435,7 +437,7 @@
 		rthp = &rth->u.rt_next;
 	}
 
-	if (rt_cache_size >= RT_CACHE_MAX_SIZE)
+	if (atomic_read(&rt_cache_size) >= RT_CACHE_MAX_SIZE)
 		rt_garbage_collect();
 
 	rt->u.rt_next = rt_hash_table[hash];
@@ -519,14 +521,14 @@
 			/*
 			 * Copy all the information.
 			 */
-			rt->u.dst.refcnt = 1;
+			atomic_set(&rt->u.dst.refcnt, 1);
 			rt->u.dst.dev = dev;
 			rt->u.dst.input = rth->u.dst.input;
 			rt->u.dst.output = rth->u.dst.output;
 			rt->u.dst.pmtu = dev->mtu;
 			rt->u.dst.rtt = TCP_TIMEOUT_INIT;
 			rt->u.dst.window = 0;
-			rt->u.dst.use = 1;
+			atomic_set(&rt->u.dst.use, 1);
 			rt->u.dst.lastuse = jiffies;
 
 			rt->rt_flags = rth->rt_flags|RTF_DYNAMIC|RTF_MODIFIED;
@@ -946,7 +948,7 @@
 
 	rth->u.dst.output= ip_rt_bug;
 
-	rth->u.dst.use	= 1;
+	atomic_set(&rth->u.dst.use, 1);
 	rth->key.dst	= dst_key;
 	rth->rt_dst	= dst_key;
 	rth->rt_dst_map	= daddr;
@@ -1259,7 +1261,7 @@
 	if (!rth)
 		return -ENOBUFS;
 
-	rth->u.dst.use	= 1;
+	atomic_set(&rth->u.dst.use, 1);
 	rth->key.dst	= dst_key;
 	rth->key.tos	= tos;
 	rth->key.src	= src_key;
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.1.33/linux/net/ipv4/sysctl_net_ipv4.c	Mon Apr  7 11:35:32 1997
+++ linux/net/ipv4/sysctl_net_ipv4.c	Sun Apr 13 09:23:31 1997
@@ -7,6 +7,7 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/config.h>
 #include <net/snmp.h>
 #include <net/ip.h>
 #include <net/route.h>
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.33/linux/net/ipv4/tcp.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/tcp.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.50 1997/03/16 03:25:59 davem Exp $
+ * Version:	$Id: tcp.c,v 1.55 1997/04/13 10:31:45 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -198,6 +198,8 @@
  *	Willy Konynenberg	:	Transparent proxying support.
  *		Keith Owens	:	Do proper meging with partial SKB's in
  *					tcp_do_sendmsg to avoid burstiness.
+ *		Eric Schenk	:	Fix fast close down bug with
+ *					shutdown() followed by close().
  *					
  * To Fix:
  *		Fast path the code. Two things here - fix the window calculation
@@ -431,7 +433,7 @@
 unsigned long seq_offset;
 struct tcp_mib	tcp_statistics;
 
-
+kmem_cache_t *tcp_openreq_cachep;
 
 /*
  *	Find someone to 'accept'. Must be called with
@@ -440,25 +442,16 @@
 
 static struct open_request *tcp_find_established(struct tcp_opt *tp)
 {
-	struct open_request *req;
-
-	req = tp->syn_wait_queue;
+	struct open_request *req = tp->syn_wait_queue;
 
 	if (!req)
 		return NULL;
-	
 	do {
 		if (req->sk && 
 		    (req->sk->state == TCP_ESTABLISHED ||
 		     req->sk->state >= TCP_FIN_WAIT1))
-		{
 			return req;
-		}
-
-		req = req->dl_next;
-
-	} while (req != tp->syn_wait_queue);
-	
+	} while ((req = req->dl_next) != tp->syn_wait_queue);
 	return NULL;
 }
 
@@ -471,13 +464,10 @@
 static void tcp_close_pending (struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct open_request *req;
-
-	req = tp->syn_wait_queue;
+	struct open_request *req = tp->syn_wait_queue;
 
 	if (!req)
 		return;
-	
 	do {
 		struct open_request *iter;
 		
@@ -490,12 +480,10 @@
 		(*iter->class->destructor)(iter);
 		tcp_dec_slow_timer(TCP_SLT_SYNACK);
 		sk->ack_backlog--;
-		kfree(iter);
-
+		tcp_openreq_free(iter);
 	} while (req != tp->syn_wait_queue);
 
 	tp->syn_wait_queue = NULL;
-	return;
 }
 
 /*
@@ -729,7 +717,7 @@
 
 static inline int tcp_memory_free(struct sock *sk)
 {
-	return sk->wmem_alloc < sk->sndbuf;
+	return atomic_read(&sk->wmem_alloc) < sk->sndbuf;
 }
 
 /*
@@ -961,7 +949,7 @@
 			tmp = MAX_HEADER + sk->prot->max_header + 
 				sizeof(struct sk_buff) + 15;
 			if (copy < min(sk->mss, sk->max_window >> 1) && 
-			    !(flags & MSG_OOB) && sk->packets_out)
+			    !(flags & MSG_OOB) && atomic_read(&sk->packets_out))
 			{
 				tmp += min(sk->mss, sk->max_window);
 			}
@@ -1177,7 +1165,7 @@
 	 */
 
 	while ((skb=skb_peek(&sk->receive_queue)) != NULL) {
-		if (!skb->used || skb->users>1)
+		if (!skb->used || atomic_read(&skb->users)>1)
 			break;
 		tcp_eat_skb(sk, skb);
 	}
@@ -1439,7 +1427,7 @@
 		if (flags & MSG_PEEK)
 			continue;
 		skb->used = 1;
-		if (skb->users == 1)
+		if (atomic_read(&skb->users) == 1)
 			tcp_eat_skb(sk, skb);
 		continue;
 
@@ -1505,6 +1493,7 @@
 		case TCP_CLOSE:
 		case TCP_LISTEN:
 			break;
+		case TCP_LAST_ACK:	/* Could have shutdown() then close() */
 		case TCP_CLOSE_WAIT:	/* They have FIN'd us. We send our FIN and
 					   wait only for the ACK */
 			ns=TCP_LAST_ACK;
@@ -1681,8 +1670,8 @@
 			tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
 	}
 
-	release_sock(sk);
 	sk->dead = 1;
+	release_sock(sk);
 
 	if(sk->state == TCP_CLOSE)
 		sk->prot->unhash(sk);
@@ -1728,11 +1717,9 @@
 	struct sock *newsk = NULL;
 	int error;
 
-  /*
-   * We need to make sure that this socket is listening,
-   * and that it has something pending.
-   */
-
+	/* We need to make sure that this socket is listening,
+	 * and that it has something pending.
+	 */
 	error = EINVAL;
 	if (sk->state != TCP_LISTEN)
 		goto no_listen;
@@ -1744,7 +1731,7 @@
 got_new_connect:
 		tcp_synq_unlink(tp, req);
 		newsk = req->sk;
-		kfree(req);
+		tcp_openreq_free(req);
 		sk->ack_backlog--;
 		error = 0;
 out:
@@ -1852,4 +1839,14 @@
 	{
 		tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
 	}
+}
+
+void tcp_init(void)
+{
+	tcp_openreq_cachep = kmem_cache_create("tcp_open_request",
+					       sizeof(struct open_request),
+					       sizeof(long)*8, SLAB_HWCACHE_ALIGN,
+					       NULL, NULL);
+	if(!tcp_openreq_cachep)
+		panic("tcp_init: Cannot alloc open_request cache.");
 }
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.33/linux/net/ipv4/tcp_input.c	Thu Mar 27 14:40:15 1997
+++ linux/net/ipv4/tcp_input.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.39 1997/03/17 04:49:35 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.42 1997/04/12 04:32:24 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -37,6 +37,8 @@
  *		Eric Schenk	:	Delayed ACK bug fixes.
  *		Eric Schenk	:	Floyd style fast retrans war avoidance.
  *		David S. Miller	:	Don't allow zero congestion window.
+ *		Eric Schenk	:	Fix retransmitter so that it sends
+ *					next packet on ack of previous packet.
  */
 
 #include <linux/config.h>
@@ -149,11 +151,19 @@
 	 */
 			 
 	tp->rto = (tp->srtt >> 3) + tp->mdev;
+	tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1));
+
 
 	if (tp->rto > 120*HZ)
 		tp->rto = 120*HZ;
 
-	/* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */
+	/* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks 
+	 * FIXME: It's not entirely clear this lower bound is the best
+	 * way to avoid the problem. Is it possible to drop the lower
+	 * bound and still avoid trouble with BSD stacks? Perhaps
+	 * some modification to the RTO calculation that takes delayed
+	 * ack bais into account? This needs serious thought. -- erics
+	 */
 	if (tp->rto < HZ/5)
 		tp->rto = HZ/5;
 
@@ -302,6 +312,15 @@
 {
 	struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
 
+	/* FIXME: if we are already retransmitting should this code
+	 * be skipped? [Floyd high_seq check sort of does this]
+	 * The case I'm worried about is falling into a fast
+	 * retransmit on a link with a congestion window of 1 or 2.
+	 * There was some evidence in 2.0.x that this was problem
+	 * on really slow links (1200 or 2400 baud). I need to
+	 * try this situation again and see what happens.
+	 */
+
 	/*
 	 * An ACK is a duplicate if:
 	 * (1) it has the same sequence number as the largest number we've 
@@ -313,7 +332,7 @@
 	 *     The packet acked data after high_seq;
 	 */
 
-	if (ack == tp->snd_una && sk->packets_out && (not_dup == 0))
+	if (ack == tp->snd_una && atomic_read(&sk->packets_out) && (not_dup == 0))
 	{
 		/*
 		 * 1. When the third duplicate ack is received, set ssthresh 
@@ -327,9 +346,14 @@
 
 			if (sk->dup_acks == 3)
 			{
-				sk->ssthresh = max(sk->cong_window >> 1, 2);
-				sk->cong_window = sk->ssthresh + 3;
+				sk->ssthresh = max(tp->snd_cwnd >> 1, 2);
+				tp->snd_cwnd = sk->ssthresh + 3;
 				tcp_do_retransmit(sk, 0);
+				/* careful not to timeout just after fast
+				 * retransmit!
+				 */
+				tcp_reset_xmit_timer(sk, TIME_RETRANS,
+						     tp->rto);
 			}
 		}
 
@@ -344,7 +368,7 @@
 		if (sk->dup_acks >= 3)
 		{
 			sk->dup_acks++;
-			sk->cong_window++;
+			tp->snd_cwnd++;
 		}
 	}
 	else
@@ -357,8 +381,8 @@
 		if (sk->dup_acks >= 3)
 		{
 			tp->retrans_head = NULL;
-			sk->cong_window = max(sk->ssthresh, 1);
-			sk->retransmits = 0;
+			tp->snd_cwnd = max(sk->ssthresh, 1);
+			atomic_set(&sk->retransmits, 0);
 		}
 		sk->dup_acks = 0;
 		tp->high_seq = 0;
@@ -425,7 +449,7 @@
 	 *      Slow Start
 	 */
 	
-	if (sk->cong_window < sk->ssthresh &&
+	if (tp->snd_cwnd < sk->ssthresh &&
 	    (seq == tp->snd_nxt ||
 	     (expected - actual <= TCP_VEGAS_GAMMA * inv_basebd)))
 	{
@@ -436,7 +460,7 @@
 			
 		if (sk->cong_count++)
 		{
-			sk->cong_window++;
+			tp->snd_cwnd++;
 			sk->cong_count = 0;
 		}
 	}
@@ -450,9 +474,9 @@
 		{
 			/* Increase Linearly */
 				
-			if (sk->cong_count++ >= sk->cong_window)
+			if (sk->cong_count++ >= tp->snd_cwnd)
 			{
-				sk->cong_window++;
+				tp->snd_cwnd++;
 				sk->cong_count = 0;
 			}
 		}
@@ -461,21 +485,22 @@
 		{
 			/* Decrease Linearly */
 
-			if (sk->cong_count++ >= sk->cong_window)
+			if (sk->cong_count++ >= tp->snd_cwnd)
 			{
-				sk->cong_window--;
+				tp->snd_cwnd--;
 				sk->cong_count = 0;
 			}
 
 			/* Never less than 2 segments */
-			if (sk->cong_window < 2)
-				sk->cong_window = 2;
+			if (tp->snd_cwnd < 2)
+				tp->snd_cwnd = 2;
 		}
 	}
 }
 
 static void tcp_cong_avoid_vanj(struct sock *sk, u32 seq, u32 ack, u32 seq_rtt)
 {
+	struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
 	
         /* 
          * This is Jacobson's slow start and congestion avoidance. 
@@ -483,27 +508,38 @@
          * integral mss's, we can't do cwnd += 1 / cwnd.  
          * Instead, maintain a counter and increment it once every 
          * cwnd times.  
+	 * FIXME: Check to be sure the mathematics works out right
+	 * on this trick when we have to reduce the congestion window.
+	 * The cong_count has to be reset properly when reduction events
+	 * happen.
+	 * FIXME: What happens when the congestion window gets larger
+	 * than the maximum receiver window by some large factor
+	 * Suppose the pipeline never looses packets for a long
+	 * period of time, then traffic increases causing packet loss.
+	 * The congestion window should be reduced, but what it should
+	 * be reduced to is not clear, since 1/2 the old window may
+	 * still be larger than the maximum sending rate we ever achieved.
          */
 
-        if (sk->cong_window <= sk->ssthresh)  
+        if (tp->snd_cwnd <= sk->ssthresh)  
 	{
                 /* 
                  *	In "safe" area, increase
                  */
 
-                sk->cong_window++;
+                tp->snd_cwnd++;
 	}
         else 
 	{
                 /*
                  *	In dangerous area, increase slowly.  
                  *      In theory this is
-                 *  	sk->cong_window += 1 / sk->cong_window
+                 *  	tp->snd_cwnd += 1 / tp->snd_cwnd
                  */
 
-                if (sk->cong_count >= sk->cong_window) {
+                if (sk->cong_count >= tp->snd_cwnd) {
 			
-                        sk->cong_window++;
+                        tp->snd_cwnd++;
                         sk->cong_count = 0;
                 }
                 else 
@@ -551,6 +587,10 @@
 
 		acked = FLAG_DATA_ACKED;
 		
+		/* FIXME: packet counting may break if we have to
+		 * do packet "repackaging" for stacks that don't
+		 * like overlapping packets.
+		 */
 		atomic_dec(&sk->packets_out);
 
 		*seq = skb->seq;
@@ -702,10 +742,10 @@
 	 *	if we where retransmiting don't count rtt estimate
 	 */
 
-	if (sk->retransmits)
+	if (atomic_read(&sk->retransmits))
 	{
-		if (sk->packets_out == 0)
-			sk->retransmits = 0;
+		if (atomic_read(&sk->packets_out) == 0)
+			atomic_set(&sk->retransmits, 0);
 	}
 	else
 	{
@@ -729,17 +769,30 @@
 		}
 	}
 
-	if (sk->packets_out)
+	if (atomic_read(&sk->packets_out))
 	{
 		if (flag & FLAG_DATA_ACKED)
 		{
 			long when;
 
 			skb = skb_peek(&sk->write_queue);
-
 			when = tp->rto - (jiffies - skb->when);
 
-			if (when <= 0)
+			/*
+			 * FIXME: This assumes that when we are retransmitting
+			 * we should only ever respond with one packet.
+			 * This means congestion windows should not grow
+			 * during recovery. In 2.0.X we allow the congestion
+			 * window to grow. It is not clear to me which
+			 * decision is correct. The RFCs should be double
+			 * checked as should the behavior of other stacks.
+			 * Also note that if we do want to allow the
+			 * congestion window to grow during retransmits
+			 * we have to fix the call to congestion window
+			 * updates so that it works during retransmission.
+			 */
+
+			if (atomic_read(&sk->retransmits))
 			{
 				tp->retrans_head = NULL;
 				/* 
@@ -758,6 +811,10 @@
 		tcp_clear_xmit_timer(sk, TIME_RETRANS);
 
 
+	/* FIXME: danger, if we just did a timeout and got the third
+	 * ack on this packet, then this is going to send it again!
+	 * [No. Floyd retransmit war check keeps this from happening. -- erics]
+	 */
 	tcp_fast_retrans(sk, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE)));
 
 	/*
@@ -1095,21 +1152,27 @@
 	if ((skb = tp->send_head))
 	{
 		if (!after(skb->end_seq, tp->snd_una + tp->snd_wnd) &&
-		    sk->packets_out < sk->cong_window )
+		    atomic_read(&sk->packets_out) < tp->snd_cwnd )
 		{
 			/*
 			 *	Add more data to the send queue.
 			 */
+			/* FIXME: the congestion window is checked
+			 * again in tcp_write_xmit anyway?!
+			 */
 
 			tcp_write_xmit(sk);
 			if(!sk->dead)
 				sk->write_space(sk);
 		}
-		else if (sk->packets_out == 0 && !tp->pending)
+		else if (atomic_read(&sk->packets_out) == 0 && !tp->pending)
  		{
  			/*
  			 *	Data to queue but no room.
  			 */
+			/* FIXME: Is it right to do a zero window probe into
+			 * a congestion window limited window???
+			 */
  			tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
  		}
 	}
@@ -1384,7 +1447,7 @@
 	 *	If our receive queue has grown past its limits,
 	 *	try to prune away duplicates etc..
 	 */
-	if (sk->rmem_alloc > sk->rcvbuf)
+	if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf)
 		prune_queue(sk);
 
 	/*
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.33/linux/net/ipv4/tcp_ipv4.c	Sun Apr 13 10:18:23 1997
+++ linux/net/ipv4/tcp_ipv4.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.23 1997/03/17 04:49:38 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.30 1997/04/13 10:31:44 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -581,11 +581,11 @@
 	tcp_init_xmit_timers(sk);
 
 	/* Now works the right way instead of a hacked initial setting */
-	sk->retransmits = 0;
+	atomic_set(&sk->retransmits, 0);
 
 	skb_queue_tail(&sk->write_queue, buff);
 
-	sk->packets_out++;
+	atomic_inc(&sk->packets_out);
 	buff->when = jiffies;
 
 	skb1 = skb_clone(buff, GFP_KERNEL);
@@ -663,8 +663,8 @@
 	{
 		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
-		sk->ssthresh = max(sk->cong_window >> 1, 2);
-		sk->cong_window = sk->ssthresh + 3;
+		sk->ssthresh = max(tp->snd_cwnd >> 1, 2);
+		tp->snd_cwnd = sk->ssthresh + 3;
 		tp->high_seq = tp->snd_nxt;
 
 		return;
@@ -800,56 +800,41 @@
 
 static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
 {
-	struct tcp_v4_open_req *af_req = (struct tcp_v4_open_req *) req;
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	struct sk_buff * skb;
 	struct tcphdr *th;
 	unsigned char *ptr;
 	int mss;
-	int tmp;
 
 	skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
-
 	if (skb == NULL)
-	{
 		return;
-	}
 
-	tmp = ip_build_pkt(skb, sk, af_req->loc_addr, af_req->rmt_addr,
-			   af_req->opt);
-
-	if (tmp < 0)
-	{
+	if(ip_build_pkt(skb, sk, req->af.v4_req.loc_addr,
+			req->af.v4_req.rmt_addr, req->af.v4_req.opt) < 0) {
 		kfree_skb(skb, FREE_WRITE);
 		return;
 	}
 
-	mss = skb->dst->pmtu;
-
-	mss -= sizeof(struct iphdr) + sizeof(struct tcphdr);
-
+	mss = (skb->dst->pmtu - sizeof(struct iphdr) + sizeof(struct tcphdr));
 	if (sk->user_mss)
 		mss = min(mss, sk->user_mss);
+	skb->h.th = th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
 
-	th =(struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
-	skb->h.th = th;
+	/* Yuck, make this header setup more efficient... -DaveM */
 	memset(th, 0, sizeof(struct tcphdr));
-
 	th->syn = 1;
 	th->ack = 1;
-
 	th->source = sk->dummy_th.source;
 	th->dest = req->rmt_port;
-
 	skb->seq = req->snt_isn;
 	skb->end_seq = skb->seq + 1;
-
 	th->seq = ntohl(skb->seq);
 	th->ack_seq = htonl(req->rcv_isn + 1);
 	th->doff = sizeof(*th)/4 + 1;
-
 	th->window = ntohs(tp->rcv_wnd);
 
+	/* FIXME: csum_partial() of a four byte quantity is itself! -DaveM */
 	ptr = skb_put(skb, TCPOLEN_MSS);
 	ptr[0] = TCPOPT_MSS;
 	ptr[1] = TCPOLEN_MSS;
@@ -858,8 +843,7 @@
 	skb->csum = csum_partial(ptr, TCPOLEN_MSS, 0);
 
 	th->check = tcp_v4_check(th, sizeof(*th) + TCPOLEN_MSS,
-				 af_req->loc_addr,
-				 af_req->rmt_addr,
+				 req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr,
 				 csum_partial((char *)th, sizeof(*th), skb->csum));
 
 	ip_queue_xmit(skb);
@@ -868,13 +852,9 @@
 
 static void tcp_v4_or_free(struct open_request *req)
 {
-	struct tcp_v4_open_req *af_req = (struct tcp_v4_open_req *) req;
-
-	if (af_req->req.sk)
-		return;
-
-	if (af_req->opt)
-		kfree_s(af_req->opt, sizeof(struct options) + af_req->opt->optlen);
+	if(!req->sk && req->af.v4_req.opt)
+		kfree_s(req->af.v4_req.opt,
+			sizeof(struct options) + req->af.v4_req.opt->optlen);
 }
 
 static struct or_calltable or_ipv4 = {
@@ -890,11 +870,11 @@
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 isn)
 {
 	struct ip_options *opt = (struct ip_options *) ptr;
-	struct tcp_v4_open_req *af_req;
 	struct open_request *req;
 	struct tcphdr *th = skb->h.th;
 	__u32 saddr = skb->nh.iph->saddr;
 	__u32 daddr = skb->nh.iph->daddr;
+	__u16 req_mss;
 
 	/* If the socket is dead, don't accept the connection.	*/
 	if (sk->dead)
@@ -916,55 +896,40 @@
 		goto exit;
 	}
 
-	af_req = kmalloc(sizeof(struct tcp_v4_open_req), GFP_ATOMIC);
-
-	if (af_req == NULL)
-	{
+	req = tcp_openreq_alloc();
+	if (req == NULL) {
 		tcp_statistics.TcpAttemptFails++;
 		goto exit;
 	}
 
 	sk->ack_backlog++;
-	req = (struct open_request *) af_req;
-
-	memset(af_req, 0, sizeof(struct tcp_v4_open_req));
 
 	req->rcv_isn = skb->seq;
 	req->snt_isn = isn;
-
-	/* mss */
-	req->mss = tcp_parse_options(th);
-
-	if (!req->mss)
-	{
-		req->mss = 536;
-	}
-
+	req_mss = tcp_parse_options(th);
+	if (!req_mss)
+		req_mss = 536;
+	req->mss = req_mss;
 	req->rmt_port = th->source;
+	req->af.v4_req.loc_addr = daddr;
+	req->af.v4_req.rmt_addr = saddr;
 
-	af_req->loc_addr = daddr;
-	af_req->rmt_addr = saddr;
-
-	/*
-	 *	options
-	 */
-
-	if (opt && opt->optlen)
-	{
-		af_req->opt = (struct ip_options*) kmalloc(sizeof(struct ip_options) +
-							   opt->optlen, GFP_ATOMIC);
-		if (af_req->opt)
-		{
-			if (ip_options_echo(af_req->opt, skb))
-			{
-				kfree_s(af_req->opt, sizeof(struct options) +
-					opt->optlen);
-				af_req->opt = NULL;
+	/* IPv4 options */
+	req->af.v4_req.opt = NULL;
+	if (opt && opt->optlen) {
+		int opt_size = sizeof(struct ip_options) + opt->optlen;
+
+		req->af.v4_req.opt = kmalloc(opt_size, GFP_ATOMIC);
+		if (req->af.v4_req.opt) {
+			if (ip_options_echo(req->af.v4_req.opt, skb)) {
+				kfree_s(req->af.v4_req.opt, opt_size);
+				req->af.v4_req.opt = NULL;
 			}
 		}
 	}
-
 	req->class = &or_ipv4;
+	req->retrans = 0;
+	req->sk = NULL;
 
 	tcp_v4_send_synack(sk, req);
 
@@ -973,7 +938,8 @@
 	tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);
 
 	sk->data_ready(sk, 0);
-  exit:
+
+exit:
 	kfree_skb(skb, FREE_READ);
 	return 0;
 }
@@ -981,7 +947,6 @@
 struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 				   struct open_request *req)
 {
-	struct tcp_v4_open_req *af_req = (struct tcp_v4_open_req *) req;
 	struct tcp_opt *newtp;
 	struct sock *newsk;
 	struct rtable *rt;
@@ -989,9 +954,7 @@
 
 	newsk = sk_alloc(GFP_ATOMIC);
 	if (newsk == NULL)
-	{
 		return NULL;
-	}
 
 	memcpy(newsk, sk, sizeof(*newsk));
 
@@ -1022,15 +985,17 @@
 	newsk->prot->init(newsk);
 
 	newsk->cong_count = 0;
+#if 0 /* Don't mess up the initialization we did in the init routine! */
 	newsk->ssthresh = 0;
+#endif
 	newtp->backoff = 0;
 	newsk->intr = 0;
 	newsk->proc = 0;
 	newsk->done = 0;
 	newsk->partial = NULL;
 	newsk->pair = NULL;
-	newsk->wmem_alloc = 0;
-	newsk->rmem_alloc = 0;
+	atomic_set(&newsk->wmem_alloc, 0);
+	atomic_set(&newsk->rmem_alloc, 0);
 	newsk->localroute = sk->localroute;
 
 	newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
@@ -1055,8 +1020,8 @@
 	newtp->snd_nxt = newsk->write_seq;
 
 	newsk->urg_data = 0;
-	newsk->packets_out = 0;
-	newsk->retransmits = 0;
+	atomic_set(&newsk->packets_out, 0);
+	atomic_set(&newsk->retransmits, 0);
 	newsk->linger=0;
 	newsk->destroy = 0;
 	init_timer(&newsk->timer);
@@ -1075,15 +1040,14 @@
 
 	newsk->socket = NULL;
 
-	newsk->daddr = af_req->rmt_addr;
-	newsk->saddr = af_req->loc_addr;
-	newsk->rcv_saddr = af_req->loc_addr;
+	newsk->daddr = req->af.v4_req.rmt_addr;
+	newsk->saddr = req->af.v4_req.loc_addr;
+	newsk->rcv_saddr = req->af.v4_req.loc_addr;
 
 	/*
 	 *	options / mss / route_cache
 	 */
-	newsk->opt = af_req->opt;
-
+	newsk->opt = req->af.v4_req.opt;
 	if (ip_route_output(&rt,
 			    newsk->opt && newsk->opt->srr ? newsk->opt->faddr : newsk->daddr,
 			    newsk->saddr, newsk->ip_tos, NULL)) {
@@ -1099,16 +1063,11 @@
 	newsk->mtu = snd_mss;
 	/* sanity check */
 	if (newsk->mtu < 64)
-	{
 		newsk->mtu = 64;
-	}
 
 	snd_mss -= sizeof(struct iphdr) + sizeof(struct tcphdr);
-
 	if (sk->user_mss)
-	{
 		snd_mss = min(snd_mss, sk->user_mss);
-	}
 
 	newsk->mss = min(req->mss, snd_mss);
 
@@ -1120,77 +1079,50 @@
 struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct open_request *req;
+	struct open_request *req = tp->syn_wait_queue;
 
-	/*
-	 *	assumption: the socket is not in use.
+	/*	assumption: the socket is not in use.
 	 *	as we checked the user count on tcp_rcv and we're
 	 *	running from a soft interrupt.
 	 */
-
-	req = tp->syn_wait_queue;
-
 	if (!req)
-	{
 		return sk;
-	}
 
 	do {
-		struct tcp_v4_open_req *af_req;
-
-		af_req = (struct tcp_v4_open_req *) req;
-
-		if (af_req->rmt_addr == skb->nh.iph->saddr &&
-		    af_req->loc_addr == skb->nh.iph->daddr &&
-		    req->rmt_port == skb->h.th->source)
-		{
+		if (req->af.v4_req.rmt_addr == skb->nh.iph->saddr &&
+		    req->af.v4_req.loc_addr == skb->nh.iph->daddr &&
+		    req->rmt_port == skb->h.th->source) {
 			u32 flg;
 
-			if (req->sk)
-			{
-				/*
-				 *	socket already created but not
+			if (req->sk) {
+				/*	socket already created but not
 				 *	yet accepted()...
 				 */
-
 				sk = req->sk;
 				break;
 			}
 
-			/* match */
-
-			/*
-			 *	Check for syn retransmission
-			 */
+			/* Check for syn retransmission */
 			flg = *(((u32 *)skb->h.th) + 3);
 			flg &= __constant_htonl(0x002f0000);
-
 			if ((flg == __constant_htonl(0x00020000)) &&
-			    (!after(skb->seq, req->rcv_isn)))
-			{
-				/*
-				 *	retransmited syn
+			    (!after(skb->seq, req->rcv_isn))) {
+				/*	retransmited syn
 				 *	FIXME: must send an ack
 				 */
 				return NULL;
 			}
 
 			sk = tp->af_specific->syn_recv_sock(sk, skb, req);
-
 			tcp_dec_slow_timer(TCP_SLT_SYNACK);
-
 			if (sk == NULL)
-			{
 				return NULL;
-			}
 
 			req->expires = 0UL;
 			req->sk = sk;
 			break;
 		}
-
-		req = req->dl_next;
-	} while (req != tp->syn_wait_queue);
+	} while ((req = req->dl_next) != tp->syn_wait_queue);
 
 	skb_orphan(skb);
 	skb_set_owner_r(skb, sk);
@@ -1422,8 +1354,8 @@
 	 * See draft-stevens-tcpca-spec-01 for discussion of the
 	 * initialization of these values.
 	 */
-	sk->cong_window = 1;
-	sk->ssthresh = 0x7fffffff;
+	tp->snd_cwnd = 1;
+	sk->ssthresh = 0x7fffffff;	/* Infinity */
 
 	sk->priority = 1;
 	sk->state = TCP_CLOSE;
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.1.33/linux/net/ipv4/tcp_output.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/tcp_output.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.31 1997/03/16 07:03:07 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.34 1997/04/12 04:32:33 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -79,14 +79,14 @@
 		
 	len = skb->end_seq - skb->seq;
 
-	if (!sk->nonagle && len < (sk->mss >> 1) && sk->packets_out)
+	if (!sk->nonagle && len < (sk->mss >> 1) && atomic_read(&sk->packets_out))
 	{
 		nagle_check = 0;
 	}
 
-	return (nagle_check && sk->packets_out < sk->cong_window &&
+	return (nagle_check && atomic_read(&sk->packets_out) < tp->snd_cwnd &&
 		!after(skb->end_seq, tp->snd_una + tp->snd_wnd) &&
-		sk->retransmits == 0);
+		atomic_read(&sk->retransmits) == 0);
 }
 
 /*
@@ -189,7 +189,7 @@
 	if (tp->send_head == NULL)
 		tp->send_head = skb;
 
-	if (sk->packets_out == 0 && !tp->pending)
+	if (atomic_read(&sk->packets_out) == 0 && !tp->pending)
 	{
 		tp->pending = TIME_PROBE0;
 		tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
@@ -309,7 +309,7 @@
 	 *	cannot currently occur.
 	 */
 
-	sk->retransmits = 0;
+	atomic_set(&sk->retransmits, 0);
 
 	printk(KERN_DEBUG "tcp_write_xmit: bug skb in write queue\n");
 
@@ -720,7 +720,7 @@
 		 */
 		 
 		ct++;
-		sk->prot->retransmits ++;
+		sk->prot->retransmits++; /* ???: atomic_t necessary here? -DaveM */
 		tcp_statistics.TcpRetransSegs++;
 
 		tp->high_seq = tp->snd_nxt;
@@ -736,7 +736,7 @@
 		 *	This should cut it off before we send too many packets.
 		 */
 
-		if (ct >= sk->cong_window)
+		if (ct >= tp->snd_cwnd)
 			break;
 
 		/*
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.1.33/linux/net/ipv4/tcp_timer.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/tcp_timer.c	Mon Apr 14 09:31:10 1997
@@ -34,8 +34,8 @@
 
 
 struct tcp_sl_timer tcp_slt_array[TCP_SLT_MAX] = {
-	{0, TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},		/* SYNACK	*/
-	{0, TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive}		/* KEEPALIVE	*/
+	{ATOMIC_INIT, TCP_SYNACK_PERIOD, 0, tcp_syn_recv_timer},/* SYNACK	*/
+	{ATOMIC_INIT, TCP_KEEPALIVE_PERIOD, 0, tcp_keepalive}	/* KEEPALIVE	*/
 };
 
 /*
@@ -165,8 +165,11 @@
 	/*
 	 *	Look for a 'soft' timeout.
 	 */
-	if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
-		|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) 
+	if ((sk->state == TCP_ESTABLISHED &&
+	     atomic_read(&sk->retransmits) &&
+	     !(atomic_read(&sk->retransmits) & 7)) ||
+	    (sk->state != TCP_ESTABLISHED &&
+	     atomic_read(&sk->retransmits) > TCP_RETR1)) 
 	{
 		/*
 		 *	Attempt to recover if arp has changed (unlikely!) or
@@ -179,7 +182,7 @@
 	 *	Have we tried to SYN too many times (repent repent 8))
 	 */
 	 
-	if(sk->retransmits > TCP_SYN_RETRIES && sk->state==TCP_SYN_SENT)
+	if(atomic_read(&sk->retransmits) > TCP_SYN_RETRIES && sk->state==TCP_SYN_SENT)
 	{
 		if(sk->err_soft)
 			sk->err=sk->err_soft;
@@ -199,7 +202,7 @@
 	/*
 	 *	Has it gone just too far ?
 	 */
-	if (sk->retransmits > TCP_RETR2) 
+	if (atomic_read(&sk->retransmits) > TCP_RETR2) 
 	{
 		if(sk->err_soft)
 			sk->err = sk->err_soft;
@@ -415,16 +418,16 @@
 
 	tp->retrans_head = NULL;
 
-	if (sk->retransmits == 0)
+	if (atomic_read(&sk->retransmits) == 0)
 	{
 		/*
 		 * remember window where we lost
 		 * "one half of the current window but at least 2 segments"
 		 */
 
-		sk->ssthresh = max(sk->cong_window >> 1, 2);
+		sk->ssthresh = max(tp->snd_cwnd >> 1, 2);
 		sk->cong_count = 0;
-		sk->cong_window = 1;
+		tp->snd_cwnd = 1;
 	}
 
 	atomic_inc(&sk->retransmits);
@@ -476,9 +479,7 @@
 			
 			/* TCP_LISTEN is implied. */
 			if (!sk->sock_readers && tp->syn_wait_queue) {
-				struct open_request *req;
-
-				req = tp->syn_wait_queue;
+				struct open_request *req = tp->syn_wait_queue;
 				do {
 					struct open_request *conn;
 				  
@@ -500,7 +501,7 @@
 						(*conn->class->destructor)(conn);
 						tcp_dec_slow_timer(TCP_SLT_SYNACK);
 						sk->ack_backlog--;
-						kfree(conn);
+						tcp_openreq_free(conn);
 
 						if (!tp->syn_wait_queue)
 							break;
@@ -536,7 +537,7 @@
 
 	for (i=0; i < TCP_SLT_MAX; i++, slt++)
 	{
-		if (slt->count)
+		if (atomic_read(&slt->count))
 		{
 			long trigger;
 
diff -u --recursive --new-file v2.1.33/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.33/linux/net/ipv4/udp.c	Sun Apr 13 10:18:23 1997
+++ linux/net/ipv4/udp.c	Mon Apr 14 09:31:10 1997
@@ -768,7 +768,6 @@
 				amount = skb->len-sizeof(struct udphdr);
 			}
 			return put_user(amount, (int *)arg);
-			return(0);
 		}
 
 		default:
@@ -923,8 +922,9 @@
 	sk->state = TCP_CLOSE;
 	if(uh_cache_sk == sk)
 		uh_cache_sk = NULL;
-	release_sock(sk);
 	sk->dead = 1;
+	release_sock(sk);
+	udp_v4_unhash(sk);
 	destroy_sock(sk);
 }
 
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.33/linux/net/ipv6/addrconf.c	Thu Mar 27 14:40:16 1997
+++ linux/net/ipv6/addrconf.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: addrconf.c,v 1.15 1997/03/18 18:24:23 davem Exp $
+ *	$Id: addrconf.c,v 1.16 1997/04/12 04:32:44 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -20,6 +20,7 @@
  *	<chexum@bankinf.banki.hu>
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -68,7 +69,7 @@
  */
 struct inet6_dev		*inet6_dev_lst[IN6_ADDR_HSIZE];
 
-atomic_t			addr_list_lock = 0;
+static atomic_t			addr_list_lock = ATOMIC_INIT;
 
 void addrconf_verify(unsigned long);
 
@@ -241,7 +242,7 @@
 	struct inet6_ifaddr *iter, **back;
 	int hash;
 
-	if (addr_list_lock) {
+	if (atomic_read(&addr_list_lock)) {
 		ifp->flags |= ADDR_INVALID;
 		return;
 	}
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c
--- v2.1.33/linux/net/ipv6/datagram.c	Thu Mar 27 14:40:16 1997
+++ linux/net/ipv6/datagram.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: datagram.c,v 1.8 1997/03/18 18:24:28 davem Exp $
+ *	$Id: datagram.c,v 1.10 1997/04/14 05:39:42 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c
--- v2.1.33/linux/net/ipv6/ip6_fib.c	Thu Mar 27 14:40:16 1997
+++ linux/net/ipv6/ip6_fib.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_fib.c,v 1.6 1997/03/18 18:24:33 davem Exp $
+ *	$Id: ip6_fib.c,v 1.7 1997/04/12 04:32:46 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -795,7 +795,7 @@
 	back = &fn->leaf;
 
 	for (rt = fn->leaf; rt;) {
-		if ((rt->rt6i_flags & RTF_CACHE) && rt->rt6i_use == 0) {
+		if ((rt->rt6i_flags & RTF_CACHE) && atomic_read(&rt->rt6i_use) == 0) {
 			if (now - rt->rt6i_tstamp > timeout) {
 				struct rt6_info *old;
 
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c
--- v2.1.33/linux/net/ipv6/ipv6_sockglue.c	Mon Apr  7 11:35:33 1997
+++ linux/net/ipv6/ipv6_sockglue.c	Sun Apr 13 09:23:31 1997
@@ -7,7 +7,7 @@
  *
  *	Based on linux/net/ipv4/ip_sockglue.c
  *
- *	$Id: ipv6_sockglue.c,v 1.8 1997/03/18 18:24:38 davem Exp $
+ *	$Id: ipv6_sockglue.c,v 1.9 1997/04/07 06:55:51 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -21,6 +21,7 @@
  *	o	Return an optlen of the truncated length if need be
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c
--- v2.1.33/linux/net/ipv6/mcast.c	Thu Mar 27 14:40:16 1997
+++ linux/net/ipv6/mcast.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: mcast.c,v 1.7 1997/03/18 18:24:39 davem Exp $
+ *	$Id: mcast.c,v 1.8 1997/04/12 04:32:48 davem Exp $
  *
  *	Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c 
  *
@@ -208,7 +208,7 @@
 
 	memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
 	mc->dev = dev;
-	mc->mca_users = 1;
+	atomic_set(&mc->mca_users, 1);
 
 	mc->next = inet6_mcast_lst[hash];
 	inet6_mcast_lst[hash] = mc;
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.1.33/linux/net/ipv6/ndisc.c	Thu Mar 27 14:40:17 1997
+++ linux/net/ipv6/ndisc.c	Mon Apr 14 09:31:10 1997
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Mike Shaver		<shaver@ingenia.com>
  *
- *	$Id: ndisc.c,v 1.13 1997/03/18 18:24:41 davem Exp $
+ *	$Id: ndisc.c,v 1.14 1997/04/12 04:32:51 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -157,7 +157,7 @@
 	neigh_table_lock(&nd_tbl);
 
 	start_bh_atomic();
-	if (nd_tbl.tbl_lock == 1) {
+	if (atomic_read(&nd_tbl.tbl_lock) == 1) {
 		ntbl_walk_table(&nd_tbl, ndisc_gc_func, 0, 0, NULL);
 		ndisc_gc_timer.expires = now + nd_gc_interval;
 	} else {
@@ -178,7 +178,7 @@
 	struct nd_neigh *ndn = (struct nd_neigh *) neigh;
         unsigned long now = jiffies;
 
-	if (ndn->ndn_refcnt == 0) {
+	if (atomic_read(&ndn->ndn_refcnt) == 0) {
 		switch (ndn->ndn_nud_state) {
 		
 		case NUD_REACHABLE:
@@ -262,7 +262,7 @@
 {
 	struct nd_neigh *ndn = (struct nd_neigh *) neigh;
 
-	if (ndn->ndn_refcnt == 0) {
+	if (atomic_read(&ndn->ndn_refcnt) == 0) {
 		if (ndn->ndn_nud_state & NUD_IN_TIMER)
 			ndisc_del_timer(ndn);
 		
@@ -295,7 +295,7 @@
 #endif
 
 		start_bh_atomic();
-		if (nd_tbl.tbl_lock == 1) {
+		if (atomic_read(&nd_tbl.tbl_lock) == 1) {
 #if ND_DEBUG >= 2
 			printk(KERN_DEBUG "ndisc_alloc: forcing gc\n");
 #endif
@@ -1608,7 +1608,7 @@
 				       now - ndn->ndn_tstamp,
 				       nd_reachable_time,
 				       nd_gc_staletime,
-				       ndn->ndn_refcnt,
+				       atomic_read(&ndn->ndn_refcnt),
 				       ndn->ndn_flags,
 				       ndn->ndn_dev ? ndn->ndn_dev->name : "NULLDEV");
 
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/proc.c linux/net/ipv6/proc.c
--- v2.1.33/linux/net/ipv6/proc.c	Thu Mar 27 14:40:17 1997
+++ linux/net/ipv6/proc.c	Mon Apr 14 09:31:10 1997
@@ -7,7 +7,7 @@
  *		PROC file system.  This is very similar to the IPv4 version,
  *		except it reports the sockets in the INET6 address family.
  *
- * Version:	$Id: proc.c,v 1.1 1997/03/16 08:47:18 davem Exp $
+ * Version:	$Id: proc.c,v 1.2 1997/04/12 04:32:55 davem Exp $
  *
  * Authors:	David S. Miller (davem@caip.rutgers.edu)
  *
@@ -83,9 +83,10 @@
 			dest->s6_addr32[0], dest->s6_addr32[1],
 			dest->s6_addr32[2], dest->s6_addr32[3], destp,
 			sp->state,
-			format==0?sp->write_seq-tp->snd_una:sp->wmem_alloc,
-			format==0?tp->rcv_nxt-sp->copied_seq:sp->rmem_alloc,
-			timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
+			format==0?sp->write_seq-tp->snd_una:atomic_read(&sp->wmem_alloc),
+			format==0?tp->rcv_nxt-sp->copied_seq:atomic_read(&sp->rmem_alloc),
+			timer_active, timer_expires-jiffies,
+			(unsigned) atomic_read(&sp->retransmits),
 			sp->socket ? sp->socket->inode->i_uid:0,
 			timer_active?sp->timeout:0,
 			sp->socket ? sp->socket->inode->i_ino:0);
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.1.33/linux/net/ipv6/raw.c	Thu Mar 27 14:40:17 1997
+++ linux/net/ipv6/raw.c	Fri Apr 11 10:47:41 1997
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.11 1997/03/18 18:24:46 davem Exp $
+ *	$Id: raw.c,v 1.12 1997/04/01 02:23:34 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.1.33/linux/net/ipv6/route.c	Thu Mar 27 14:40:17 1997
+++ linux/net/ipv6/route.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.9 1997/03/19 14:56:25 davem Exp $
+ *	$Id: route.c,v 1.10 1997/04/12 04:32:57 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -62,7 +62,7 @@
 };
 
 struct rt6_info ip6_null_entry = {
-	{{NULL, 0, 0, NULL,
+	{{NULL, ATOMIC_INIT, ATOMIC_INIT, NULL,
 	  0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL,
 	  ip6_pkt_discard, ip6_pkt_discard, &ip6_dst_ops}},
 	NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL,
@@ -93,7 +93,7 @@
 #define ip6_rt_policy (0)
 #endif
 
-static atomic_t	rt6_tbl_lock	= 0;
+static atomic_t	rt6_tbl_lock	= ATOMIC_INIT;
 static int	rt6_bh_mask	= 0;
 
 #define RT_BH_REQUEST		1
@@ -514,7 +514,7 @@
 void rt6_ins(struct rt6_info *rt)
 {
 	start_bh_atomic();
-	if (rt6_tbl_lock == 1)
+	if (atomic_read(&rt6_tbl_lock) == 1)
 		fib6_add(&ip6_routing_table, rt);
 	else
 		rtreq_add(rt, RT_OPER_ADD);
@@ -721,7 +721,7 @@
 
 	rt6_dflt_pointer = NULL;
 
-	if (rt6_tbl_lock == 1)
+	if (atomic_read(&rt6_tbl_lock) == 1)
 		fib6_del(rt);
 	else
 		rtreq_add(rt, RT_OPER_DEL);
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/sysctl_net_ipv6.c linux/net/ipv6/sysctl_net_ipv6.c
--- v2.1.33/linux/net/ipv6/sysctl_net_ipv6.c	Mon Apr  7 11:35:33 1997
+++ linux/net/ipv6/sysctl_net_ipv6.c	Sun Apr 13 09:23:31 1997
@@ -4,6 +4,7 @@
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/config.h>
 #include <linux/in6.h>
 #include <linux/ipv6.h>
 #include <net/ndisc.h>
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.33/linux/net/ipv6/tcp_ipv6.c	Sun Apr 13 10:18:23 1997
+++ linux/net/ipv6/tcp_ipv6.c	Mon Apr 14 09:31:10 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.15 1997/03/18 18:24:56 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.20 1997/04/13 10:31:48 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -445,10 +445,10 @@
 
 	tcp_init_xmit_timers(sk);
 
-	sk->retransmits = 0;
+	atomic_set(&sk->retransmits, 0);
 
 	skb_queue_tail(&sk->write_queue, buff);
-	sk->packets_out++;
+	atomic_inc(&sk->packets_out);
 	buff->when = jiffies;
 	skb1 = skb_clone(buff, GFP_KERNEL);
 	skb_set_owner_w(skb1, sk);
@@ -570,7 +570,6 @@
 
 static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
 {
-	struct tcp_v6_open_req *af_req = (struct tcp_v6_open_req *) req;
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 	struct sk_buff * skb;
 	struct tcphdr *th;
@@ -579,19 +578,17 @@
 	struct flowi fl;
 
 	skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
-	
 	if (skb == NULL)
 		return;
 
 	fl.proto = IPPROTO_TCP;
-	fl.nl_u.ip6_u.daddr = &af_req->rmt_addr;
-	fl.nl_u.ip6_u.saddr = &af_req->loc_addr;
-	fl.dev = af_req->dev;
+	fl.nl_u.ip6_u.daddr = &req->af.v6_req.rmt_addr;
+	fl.nl_u.ip6_u.saddr = &req->af.v6_req.loc_addr;
+	fl.dev = req->af.v6_req.dev;
 	fl.uli_u.ports.dport = req->rmt_port;
 	fl.uli_u.ports.sport = sk->dummy_th.source;
 
 	dst = ip6_route_output(sk, &fl);
-
 	if (dst->error) {
 		kfree_skb(skb, FREE_WRITE);
 		dst_release(dst);
@@ -602,25 +599,23 @@
 	skb_reserve(skb, (skb->dev->hard_header_len + 15) & ~15);
 	skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb,sizeof(struct ipv6hdr));
 
-	th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
-	skb->h.th = th;
+	skb->h.th = th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
+
+	/* Yuck, make this header setup more efficient... -DaveM */
 	memset(th, 0, sizeof(struct tcphdr));
-	
 	th->syn = 1;
 	th->ack = 1;
-
 	th->source = sk->dummy_th.source;
 	th->dest = req->rmt_port;
-	       
 	skb->seq = req->snt_isn;
 	skb->end_seq = skb->seq + 1;
-
 	th->seq = ntohl(skb->seq);
 	th->ack_seq = htonl(req->rcv_isn + 1);
 	th->doff = sizeof(*th)/4 + 1;
 	
 	th->window = ntohs(tp->rcv_wnd);
 
+	/* FIXME: csum_partial() of a four byte quantity is itself! -DaveM */
 	ptr = skb_put(skb, TCPOLEN_MSS);
 	ptr[0] = TCPOPT_MSS;
 	ptr[1] = TCPOLEN_MSS;
@@ -629,12 +624,11 @@
 	skb->csum = csum_partial(ptr, TCPOLEN_MSS, 0);
 
 	th->check = tcp_v6_check(th, sizeof(*th) + TCPOLEN_MSS,
-				 &af_req->loc_addr, &af_req->rmt_addr,
-				 csum_partial((char *)th, sizeof(*th),
-					      skb->csum));
+				 &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
+				 csum_partial((char *)th, sizeof(*th), skb->csum));
 
 	ip6_dst_store(sk, dst);
-	ip6_xmit(sk, skb, &fl, af_req->opt);
+	ip6_xmit(sk, skb, &fl, req->af.v6_req.opt);
 	dst_release(dst);
 
 	tcp_statistics.TcpOutSegs++;
@@ -652,8 +646,8 @@
 static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
 			       __u32 isn)
 {
-	struct tcp_v6_open_req *af_req;
 	struct open_request *req;
+	__u16 req_mss;
 	
 	/* If the socket is dead, don't accept the connection.	*/
 	if (sk->dead) {
@@ -675,38 +669,30 @@
 		goto exit;
 	}
 
-	af_req = kmalloc(sizeof(struct tcp_v6_open_req), GFP_ATOMIC);
-
-	if (af_req == NULL) {
+	req = tcp_openreq_alloc();
+	if (req == NULL) {
 		tcp_statistics.TcpAttemptFails++;
 		goto exit;		
 	}
 
 	sk->ack_backlog++;
-	req = (struct open_request *) af_req;
-
-	memset(af_req, 0, sizeof(struct tcp_v6_open_req));
 
 	req->rcv_isn = skb->seq;
 	req->snt_isn = isn;
 
-	/* mss */
-	req->mss = tcp_parse_options(skb->h.th);
-
-	if (!req->mss)
-		req->mss = 536;
-
+	req_mss = tcp_parse_options(skb->h.th);
+	if (!req_mss)
+		req_mss = 536;
+	req->mss = req_mss;
 	req->rmt_port = skb->h.th->source;
-
-	ipv6_addr_copy(&af_req->rmt_addr, &skb->nh.ipv6h->saddr);
-	ipv6_addr_copy(&af_req->loc_addr, &skb->nh.ipv6h->daddr);
-
-	/* FIXME: options */
-
-	/* keep incoming device so that link locals have meaning */
-	af_req->dev = skb->dev;
+	ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr);
+	ipv6_addr_copy(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr);
+	req->af.v6_req.opt = NULL;	/* FIXME: options */
+	req->af.v6_req.dev = skb->dev;  /* So that link locals have meaning */
 
 	req->class = &or_ipv6;
+	req->retrans = 0;
+	req->sk = NULL;
 
 	tcp_v6_send_synack(sk, req);
 
@@ -735,7 +721,6 @@
 static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 					  struct open_request *req)
 {
-	struct tcp_v6_open_req *af_req = (struct tcp_v6_open_req *) req;
 	struct ipv6_pinfo *np;
 	struct dst_entry *dst;
 	struct flowi fl;
@@ -810,8 +795,8 @@
 	newsk->done = 0;
 	newsk->partial = NULL;
 	newsk->pair = NULL;
-	newsk->wmem_alloc = 0;
-	newsk->rmem_alloc = 0;
+	atomic_set(&newsk->wmem_alloc, 0);
+	atomic_set(&newsk->rmem_alloc, 0);
 	newsk->localroute = sk->localroute;
 
 	newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
@@ -836,8 +821,8 @@
 	newtp->snd_nxt = newsk->write_seq;
 
 	newsk->urg_data = 0;
-	newsk->packets_out = 0;
-	newsk->retransmits = 0;
+	atomic_set(&newsk->packets_out, 0);
+	atomic_set(&newsk->retransmits, 0);
 	newsk->linger=0;
 	newsk->destroy = 0;
 	init_timer(&newsk->timer);
@@ -856,10 +841,10 @@
 
 	newsk->socket = NULL;
 
-	ipv6_addr_copy(&np->daddr, &af_req->rmt_addr);
-	ipv6_addr_copy(&np->saddr, &af_req->loc_addr);
-	ipv6_addr_copy(&np->rcv_saddr, &af_req->loc_addr);
-	np->oif = af_req->dev;
+	ipv6_addr_copy(&np->daddr, &req->af.v6_req.rmt_addr);
+	ipv6_addr_copy(&np->saddr, &req->af.v6_req.loc_addr);
+	ipv6_addr_copy(&np->rcv_saddr, &req->af.v6_req.loc_addr);
+	np->oif = req->af.v6_req.dev;
 
 	/*
 	 *	options / mss / route cache
@@ -877,7 +862,7 @@
 	ip6_dst_store(newsk, dst);
 
 	if (dst->error)
-		newsk->mtu = af_req->dev->mtu;
+		newsk->mtu = req->af.v6_req.dev->mtu;
 	else
 		newsk->mtu = dst->pmtu;
 
@@ -963,26 +948,18 @@
 struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct open_request *req;
+	struct open_request *req = tp->syn_wait_queue;
 
-	/*
-	 *	assumption: the socket is not in use.
+	/*	assumption: the socket is not in use.
 	 *	as we checked the user count on tcp_rcv and we're
 	 *	running from a soft interrupt.
 	 */
-
-	req = tp->syn_wait_queue;
-
 	if (!req)
 		return sk;
 
 	do {
-		struct tcp_v6_open_req *af_req;
-
-		af_req = (struct tcp_v6_open_req *) req;
-
-		if (!ipv6_addr_cmp(&af_req->rmt_addr, &skb->nh.ipv6h->saddr) &&
-		    !ipv6_addr_cmp(&af_req->loc_addr, &skb->nh.ipv6h->daddr) &&
+		if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr) &&
+		    !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr) &&
 		    req->rmt_port == skb->h.th->source) {
 			u32 flg;
 
@@ -992,18 +969,13 @@
 				break;
 			}
 
-			/* match */
-
-			/*
-			 *	Check for syn retransmission
-			 */
+			/* Check for syn retransmission */
 			flg = *(((u32 *)skb->h.th) + 3);
 			flg &= __constant_htonl(0x002f0000);
 
 			if ((flg == __constant_htonl(0x00020000)) &&
 			    (!after(skb->seq, req->rcv_isn))) {
-				/*
-				 *	retransmited syn
+				/*	retransmited syn
 				 *	FIXME: must send an ack
 				 */
 				return NULL;
@@ -1022,10 +994,7 @@
 			req->sk = sk;
 			break;
 		}
-
-		req = req->dl_next;
-	} while (req != tp->syn_wait_queue);
-
+	} while ((req = req->dl_next) != tp->syn_wait_queue);
 	return sk;
 }
 
@@ -1316,7 +1285,7 @@
 	tp->rcv_wnd = 8192;
 
 	/* start with only sending one packet at a time. */
-	sk->cong_window = 1;
+	tp->snd_cwnd = 1;
 	sk->ssthresh = 0x7fffffff;
 
 	sk->priority = 1;
diff -u --recursive --new-file v2.1.33/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.33/linux/net/ipv6/udp.c	Sun Apr 13 10:18:23 1997
+++ linux/net/ipv6/udp.c	Mon Apr 14 09:31:10 1997
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.12 1997/03/18 18:24:59 davem Exp $
+ *	$Id: udp.c,v 1.16 1997/04/11 22:22:57 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -290,7 +290,7 @@
 		dst_release(np->dst);
 
 	ipv6_sock_mc_close(sk);
-
+	udp_v6_unhash(sk);
 	release_sock(sk);
 	destroy_sock(sk);
 }
@@ -382,7 +382,7 @@
 	sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source);
    
 	if (sk == NULL) {
-		printk(KERN_DEBUG "icmp for unkown sock\n");
+		printk(KERN_DEBUG "icmp for unknown sock\n");
 		return;
 	}
 
diff -u --recursive --new-file v2.1.33/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.33/linux/net/ipx/af_ipx.c	Thu Mar 27 14:40:17 1997
+++ linux/net/ipx/af_ipx.c	Mon Apr 14 09:31:10 1997
@@ -1636,7 +1636,8 @@
 					htons(s->protinfo.af_ipx.dest_addr.sock));
 			}
 			len += sprintf (buffer+len,"%08X  %08X  ",
-				s->wmem_alloc, s->rmem_alloc);
+				atomic_read(&s->wmem_alloc),
+					atomic_read(&s->rmem_alloc));
 			len += sprintf (buffer+len,"%02X     %03d\n",
 				s->state, SOCK_INODE(s->socket)->i_uid);
 
@@ -2254,7 +2255,7 @@
 	switch(cmd)
 	{
 		case TIOCOUTQ:
-			amount=sk->sndbuf-sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if(amount<0)
 				amount=0;
 			return put_user(amount, (int *)arg);
diff -u --recursive --new-file v2.1.33/linux/net/netbeui/af_netbeui.c linux/net/netbeui/af_netbeui.c
--- v2.1.33/linux/net/netbeui/af_netbeui.c	Thu Feb 27 10:57:32 1997
+++ linux/net/netbeui/af_netbeui.c	Mon Apr 14 09:31:10 1997
@@ -513,7 +513,7 @@
 		 *	Protocol layer
 		 */
 		case TIOCOUTQ:
-			amount=sk->sndbuf-sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if(amount<0)
 				amount=0;
 			break;
diff -u --recursive --new-file v2.1.33/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.33/linux/net/netrom/af_netrom.c	Mon Apr  7 11:35:33 1997
+++ linux/net/netrom/af_netrom.c	Mon Apr 14 09:31:10 1997
@@ -308,7 +308,8 @@
 		kfree_skb(skb, FREE_READ);
 	}
 
-	if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) {	/* Defer: outstanding buffers */
+	if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) {
+		/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = nr_destroy_timer;
@@ -1183,7 +1184,7 @@
 		case TIOCOUTQ:
 			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int))) != 0)
 				return err;
-			amount = sk->sndbuf - sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if (amount < 0)
 				amount = 0;
 			put_user(amount, (int *)arg);
@@ -1277,7 +1278,7 @@
 			s->protinfo.nr->n2count,
 			s->protinfo.nr->n2,
 			s->protinfo.nr->window,
-			s->wmem_alloc, s->rmem_alloc);
+			atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
 
 		pos = begin + len;
 
diff -u --recursive --new-file v2.1.33/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c
--- v2.1.33/linux/net/netrom/nr_timer.c	Thu Mar 27 14:40:17 1997
+++ linux/net/netrom/nr_timer.c	Mon Apr 14 09:31:10 1997
@@ -85,7 +85,8 @@
 			/*
 			 * Check for the state of the receive buffer.
 			 */
-			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)) {
+			if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
+			    (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)) {
 				sk->protinfo.nr->condition &= ~NR_COND_OWN_RX_BUSY;
 				sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 				sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
diff -u --recursive --new-file v2.1.33/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.33/linux/net/netsyms.c	Mon Apr  7 11:35:33 1997
+++ linux/net/netsyms.c	Mon Apr 14 09:31:10 1997
@@ -237,6 +237,7 @@
 EXPORT_SYMBOL(net_delete_timer);
 EXPORT_SYMBOL(udp_prot);
 EXPORT_SYMBOL(tcp_prot);
+EXPORT_SYMBOL(tcp_openreq_cachep);
 EXPORT_SYMBOL(ipv4_specific);
 #endif
 
@@ -260,6 +261,7 @@
 EXPORT_SYMBOL(register_trdev);
 EXPORT_SYMBOL(unregister_trdev);
 EXPORT_SYMBOL(init_trdev);
+EXPORT_SYMBOL(tr_freedev);
 #endif
                   
 #ifdef CONFIG_NET_ALIAS
diff -u --recursive --new-file v2.1.33/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.33/linux/net/rose/af_rose.c	Mon Apr  7 11:35:33 1997
+++ linux/net/rose/af_rose.c	Mon Apr 14 09:31:10 1997
@@ -357,7 +357,8 @@
 		kfree_skb(skb, FREE_READ);
 	}
 
-	if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) {	/* Defer: outstanding buffers */
+	if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) {
+		/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = rose_destroy_timer;
@@ -1184,7 +1185,7 @@
 		case TIOCOUTQ:
 			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0)
 				return err;
-			amount = sk->sndbuf - sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if (amount < 0)
 				amount = 0;
 			put_user(amount, (unsigned int *)arg);
@@ -1290,7 +1291,7 @@
 			s->protinfo.rose->t2    / ROSE_SLOWHZ,
 			s->protinfo.rose->t3    / ROSE_SLOWHZ,
 			s->protinfo.rose->hb    / ROSE_SLOWHZ,
-			s->wmem_alloc, s->rmem_alloc);
+			atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
 
 		pos = begin + len;
 
diff -u --recursive --new-file v2.1.33/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c
--- v2.1.33/linux/net/rose/rose_timer.c	Thu Mar 27 14:40:18 1997
+++ linux/net/rose/rose_timer.c	Mon Apr 14 09:31:10 1997
@@ -85,7 +85,8 @@
 			/*
 			 * Check for the state of the receive buffer.
 			 */
-			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) {
+			if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
+			    (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) {
 				sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
 				sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
 				sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
diff -u --recursive --new-file v2.1.33/linux/net/sunrpc/pmap_clnt.c linux/net/sunrpc/pmap_clnt.c
--- v2.1.33/linux/net/sunrpc/pmap_clnt.c	Mon Apr  7 11:35:33 1997
+++ linux/net/sunrpc/pmap_clnt.c	Mon Apr 14 09:31:10 1997
@@ -32,7 +32,8 @@
 extern struct rpc_program	pmap_program;
 
 /*
- * Obtain the port for a given RPC service on a given host
+ * Obtain the port for a given RPC service on a given host. This one can
+ * be called for an ongoing RPC request.
  */
 void
 rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
@@ -75,6 +76,34 @@
 	task->tk_status = -EIO;
 	task->tk_action = NULL;
 }
+
+#ifdef CONFIG_ROOT_NFS
+int
+rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
+{
+	struct rpc_portmap map = { prog, vers, prot, 0 };
+	struct rpc_clnt	*pmap_clnt;
+	char		hostname[32];
+	int		status;
+
+	dprintk("RPC:      rpc_getport_external(%s, %d, %d, %d)\n",
+			in_ntoa(sin->sin_addr.s_addr), prog, vers, prot);
+
+	strcpy(hostname, in_ntoa(sin->sin_addr.s_addr));
+	if (!(pmap_clnt = pmap_create(hostname, sin, prot)))
+		return -EACCES;
+
+	/* Setup the call info struct */
+	status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0);
+
+	if (status >= 0) {
+		if (map.pm_port != 0)
+			return map.pm_port;
+		status = -EACCES;
+	}
+	return status;
+}
+#endif
 
 static void
 pmap_getport_done(struct rpc_task *task)
diff -u --recursive --new-file v2.1.33/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.1.33/linux/net/sunrpc/svcsock.c	Mon Apr  7 11:35:33 1997
+++ linux/net/sunrpc/svcsock.c	Mon Apr 14 09:31:10 1997
@@ -962,6 +962,6 @@
 		kfree(svsk);
 	} else {
 		printk(KERN_NOTICE "svc: server socket destroy delayed\n");
-		svsk->sk_server = NULL;
+		/* svsk->sk_server = NULL; */
 	}
 }
diff -u --recursive --new-file v2.1.33/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.33/linux/net/unix/af_unix.c	Thu Mar 27 14:40:18 1997
+++ linux/net/unix/af_unix.c	Mon Apr 14 09:31:10 1997
@@ -228,7 +228,7 @@
 static void unix_destroy_timer(unsigned long data)
 {
 	unix_socket *sk=(unix_socket *)data;
-	if(!unix_locked(sk) && sk->wmem_alloc==0)
+	if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0)
 	{
 		unix_release_addr(sk->protinfo.af_unix.addr);
 		sk_free(sk);
@@ -281,7 +281,7 @@
 		sk->protinfo.af_unix.inode=NULL;
 	}
 	
-	if(!unix_unlock(sk) && sk->wmem_alloc==0)
+	if(!unix_unlock(sk) && atomic_read(&sk->wmem_alloc) == 0)
 	{
 		unix_release_addr(sk->protinfo.af_unix.addr);
 		sk_free(sk);
@@ -348,7 +348,7 @@
 	
 	sk->protinfo.af_unix.family=AF_UNIX;
 	sk->protinfo.af_unix.inode=NULL;
-	sk->sock_readers=1;				/* Us */
+	sk->sock_readers=1;			/* Us */
 	sk->protinfo.af_unix.readsem=MUTEX;	/* single task reading lock */
 	sk->mtu=4096;
 	sk->protinfo.af_unix.list=&unix_sockets_unbound;
@@ -418,7 +418,7 @@
 	}
 	memset(addr, 0, sizeof(*addr) + sizeof(short) + 16);
 	addr->name->sun_family = AF_UNIX;
-	addr->refcnt = 1;
+	atomic_set(&addr->refcnt, 1);
 
 retry:
 	addr->len = sprintf(addr->name->sun_path+1, "%08x", ordernum) + 1 + sizeof(short);
@@ -504,7 +504,7 @@
 	if (!addr)
 		return -ENOBUFS;
 
-	/* We sleeped; recheck ... */
+	/* We slept; recheck ... */
 
 	if (sk->protinfo.af_unix.addr || sk->protinfo.af_unix.inode)
 	{
@@ -515,7 +515,7 @@
 	memcpy(addr->name, sunaddr, addr_len);
 	addr->len = addr_len;
 	addr->hash = hash;
-	addr->refcnt = 1;
+	atomic_set(&addr->refcnt, 1);
 
 	if (!sunaddr->sun_path[0])
 	{
@@ -1105,26 +1105,16 @@
 	struct sock *sk = sock->sk;
 	int noblock = flags & MSG_DONTWAIT;
 	struct sk_buff *skb;
+	int err;
 
 	if (flags&MSG_OOB)
 		return -EOPNOTSUPP;
 
 	msg->msg_namelen = 0;
 
-retry:
-	skb=skb_dequeue(&sk->receive_queue);
-
-	if (skb==NULL)
-	{
-		if (sk->shutdown & RCV_SHUTDOWN)
-			return 0;
-		if (noblock)
-			return -EAGAIN;
-		unix_data_wait(sk);
-		if (current->signal & ~current->blocked)
-			return -ERESTARTSYS;
-		goto retry;
-	}
+	skb=skb_recv_datagram(sk, flags, noblock, &err);
+	if(skb==NULL)
+		return err;
 
 	if (msg->msg_name)
 	{
@@ -1143,10 +1133,8 @@
 	else if (size < skb->len)
 		msg->msg_flags |= MSG_TRUNC;
 
-	if (memcpy_toiovec(msg->msg_iov, skb->data, size)) {
-		skb_queue_head(&sk->receive_queue, skb);
+	if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size))
 		return -EFAULT;
-	}
 
 	scm->creds = *UNIXCREDS(skb);
 
@@ -1154,9 +1142,9 @@
 	{
 		if (UNIXCB(skb).fp)
 			unix_detach_fds(scm, skb);
-		kfree_skb(skb, FREE_WRITE);
-		return size;
-	} else 
+	}
+	else 
+	{
 		/* It is questionable: on PEEK we could:
 		   - do not return fds - good, but too simple 8)
 		   - return fds, and do not return them on read (old strategy,
@@ -1171,8 +1159,8 @@
 		*/
 		if (UNIXCB(skb).fp)
 			scm->fp = scm_fp_dup(UNIXCB(skb).fp);
-
-	skb_queue_head(&sk->receive_queue, skb);
+	}
+	skb_free_datagram(sk,skb);
 	return size;
 }
 
@@ -1342,7 +1330,7 @@
 	{
 	
 		case TIOCOUTQ:
-			amount=sk->sndbuf-sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if(amount<0)
 				amount=0;
 			return put_user(amount, (int *)arg);
@@ -1475,7 +1463,7 @@
 	struct sk_buff *dummy_skb;
 	struct proc_dir_entry *ent;
 	
-	printk(KERN_INFO "NET3: Unix domain sockets 0.15 for Linux NET3.038.\n");
+	printk(KERN_INFO "NET3: Unix domain sockets 0.16 for Linux NET3.038.\n");
 	if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb))
 	{
 		printk(KERN_CRIT "unix_proto_init: panic\n");
diff -u --recursive --new-file v2.1.33/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.33/linux/net/x25/af_x25.c	Mon Apr  7 11:35:33 1997
+++ linux/net/x25/af_x25.c	Mon Apr 14 09:31:10 1997
@@ -328,7 +328,8 @@
 		kfree_skb(skb, FREE_READ);
 	}
 
-	if (sk->wmem_alloc != 0 || sk->rmem_alloc != 0) {	/* Defer: outstanding buffers */
+	if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) {
+		/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = x25_destroy_timer;
@@ -1057,7 +1058,7 @@
 		case TIOCOUTQ:
 			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
 				return err;
-			amount = sk->sndbuf - sk->wmem_alloc;
+			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
 			if (amount < 0)
 				amount = 0;
 			put_user(amount, (unsigned long *)arg);
@@ -1198,7 +1199,7 @@
 			s->protinfo.x25->t21   / X25_SLOWHZ,
 			s->protinfo.x25->t22   / X25_SLOWHZ,
 			s->protinfo.x25->t23   / X25_SLOWHZ,
-			s->wmem_alloc, s->rmem_alloc);
+			atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc));
 
 		pos = begin + len;
 
diff -u --recursive --new-file v2.1.33/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c
--- v2.1.33/linux/net/x25/x25_timer.c	Thu Mar 27 14:40:18 1997
+++ linux/net/x25/x25_timer.c	Mon Apr 14 09:31:10 1997
@@ -84,7 +84,8 @@
 			/*
 			 * Check for the state of the receive buffer.
 			 */
-			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)) {
+			if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
+			    (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)) {
 				sk->protinfo.x25->condition &= ~X25_COND_OWN_RX_BUSY;
 				sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
 				sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
diff -u --recursive --new-file v2.1.33/linux/scripts/Configure linux/scripts/Configure
--- v2.1.33/linux/scripts/Configure	Sun Apr 13 10:18:23 1997
+++ linux/scripts/Configure	Fri Apr 11 10:50:49 1997
@@ -47,8 +47,9 @@
 # 090397 Axel Boldt (boldt@math.ucsb.edu) - avoid ? and + in regular 
 # expressions for GNU expr since version 1.15 and up use \? and \+.
 #
-# 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for "limint", 
-# allow dep_tristate to take a list of dependencies rather than just one.
+# 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for min/max 
+# arguments to "int", allow dep_tristate to take a list of dependencies
+# rather than just one.
 
 #
 # Make sure we're really running bash.
@@ -311,7 +312,7 @@
 	if [ $# -gt 3 ]; then
 	  min=$4
 	else
-	  min=1
+	  min=-10000000    # !!
 	fi
 	if [ $# -gt 4 ]; then
 	  max=$5
