Import 2.1.92pre22.1.92pre2
authorLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:03 +0000 (23 15:15 -0500)
committerLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:03 +0000 (23 15:15 -0500)
121 files changed:
arch/alpha/Makefile
arch/alpha/boot/bootp.c
arch/alpha/config.in
arch/alpha/defconfig
arch/alpha/kernel/Makefile
arch/alpha/kernel/apecs.c
arch/alpha/kernel/bios32.c
arch/alpha/kernel/cia.c
arch/alpha/kernel/entry.S
arch/alpha/kernel/head.S
arch/alpha/kernel/irq.c
arch/alpha/kernel/lca.c
arch/alpha/kernel/mcpcia.c[new file with mode: 0644]
arch/alpha/kernel/process.c
arch/alpha/kernel/pyxis.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/smp.c[new file with mode: 0644]
arch/alpha/kernel/t2.c
arch/alpha/kernel/time.c
arch/alpha/kernel/tsunami.c[new file with mode: 0644]
arch/alpha/mm/fault.c
arch/alpha/mm/init.c
arch/arm/config.in
arch/arm/defconfig
arch/i386/boot/compressed/head.S
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/entry.S
arch/i386/kernel/head.S
arch/i386/kernel/irq.h
arch/i386/kernel/process.c
arch/i386/kernel/signal.c
arch/i386/kernel/traps.c
arch/i386/kernel/vm86.c
arch/m68k/config.in
arch/ppc/config.in
arch/sparc/config.in
arch/sparc64/config.in
arch/sparc64/defconfig
drivers/block/ide-cd.c
drivers/block/ide-cd.h
drivers/block/ide-disk.c
drivers/block/ide-floppy.c
drivers/block/ide-pci.c
drivers/block/ide-probe.c
drivers/block/ide-proc.c
drivers/block/ide-tape.c
drivers/block/ide.c
drivers/block/ide.h
drivers/block/ll_rw_blk.c
drivers/block/md.c
drivers/cdrom/Makefile
drivers/cdrom/cdrom.c
drivers/char/apm_bios.c
drivers/char/console.c
drivers/char/pc_keyb.c
drivers/net/de4x5.c
drivers/pci/oldproc.c
drivers/pci/pci.c
drivers/scsi/BusLogic.c
drivers/scsi/BusLogic.h
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/NCR53c406a.c
drivers/scsi/README.BusLogic
drivers/scsi/hosts.h
drivers/scsi/ncr53c8xx.c
drivers/scsi/qlogicisp.c
drivers/scsi/wd7000.c
fs/ncpfs/ncplib_kernel.c
fs/ncpfs/ncpsign_kernel.c
fs/ntfs/types.h
include/asm-alpha/apecs.h
include/asm-alpha/bitops.h
include/asm-alpha/cia.h
include/asm-alpha/hardirq.h
include/asm-alpha/hwrpb.h
include/asm-alpha/io.h
include/asm-alpha/irq.h
include/asm-alpha/lca.h
include/asm-alpha/mcpcia.h[new file with mode: 0644]
include/asm-alpha/mmu_context.h
include/asm-alpha/pgtable.h
include/asm-alpha/pyxis.h
include/asm-alpha/smp.h
include/asm-alpha/smp_lock.h
include/asm-alpha/softirq.h
include/asm-alpha/spinlock.h
include/asm-alpha/system.h
include/asm-alpha/t2.h
include/asm-alpha/tsunami.h[new file with mode: 0644]
include/asm-i386/ide.h
include/asm-i386/processor.h
include/linux/blk.h
include/linux/lists.h
include/linux/major.h
include/linux/pci.h
include/linux/skbuff.h
include/linux/ufs_fs.h
include/net/sock.h
include/net/tcp.h
ipc/shm.c
kernel/exit.c
kernel/fork.c
kernel/ksyms.c
kernel/sysctl.c
mm/page_alloc.c
net/core/skbuff.c
net/ipv4/af_inet.c
net/ipv4/devinet.c
net/ipv4/ip_masq_mod.c
net/ipv4/ip_output.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv6/af_inet6.c
net/ipv6/tcp_ipv6.c
net/netsyms.c
net/socket.c

index 9cd1ab3..40d153e 100644 (file)
 
 NM := nm -B
 
+#LINKFLAGS = -static -T arch/alpha/vmlinux.lds
+#CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
+
+ifdef CONFIG_CROSSCOMPILE
+# enable this for linking under OSF/1:
+LINKFLAGS = -non_shared -T 0xfffffc0000310000 -N
+else
+ elf=$(shell if $(LD) --help | grep elf64alpha >/dev/null; then echo yes; fi)
+ ifeq ($(elf),yes)
+#   LINKFLAGS = -static -Ttext 0xfffffc0000310000 -N
 LINKFLAGS = -static -T arch/alpha/vmlinux.lds
-CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
+ else
+   LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N
+ endif
+# GNU gcc/cc1/as can use pipes instead of temporary files
+CFLAGS := $(CFLAGS) -pipe
+endif
+
+CFLAGS := $(CFLAGS) -mno-fp-regs -ffixed-8 -Wno-uninitialized
+
+# determine if we can use the BWX instructions with GAS
+$(shell rm -f ./GAS_VER)
+$(shell $(AS) --version >& ./GAS_VER)
+OLD_GAS := $(shell if cat ./GAS_VER | grep 'version 2.7' > /dev/null; then echo yes; else echo no; fi)
+$(shell rm -f ./GAS_VER)
+
+ifneq ($(OLD_GAS),yes)
+ CFLAGS := $(CFLAGS) -Wa,-m21164a -DBWX_USABLE
+
+# if PYXIS, then enable use of BWIO space
+ ifeq ($(CONFIG_ALPHA_PYXIS),y)
+  CFLAGS := $(CFLAGS) -DBWIO_ENABLED
+ endif
+endif
 
 HEAD := arch/alpha/kernel/head.o
 
@@ -23,7+55,7 @@ ifeq ($(CONFIG_MATHEMU),y)
   CORE_FILES := $(CORE_FILES) arch/alpha/math-emu/math-emu.o
 endif
 
-LIBS := arch/alpha/lib/lib.a $(LIBS) arch/alpha/lib/lib.a
+LIBS := $(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
index 6582979..24f1079 100644 (file)
 #include <linux/string.h>
 #include <linux/version.h>
 #include <linux/mm.h>
+#include <linux/config.h>
 
 #include <asm/system.h>
 #include <asm/console.h>
 #include <asm/hwrpb.h>
 #include <asm/pgtable.h>
+#include <asm/io.h>
 
 #include <stdarg.h>
 
@@ -156,7+158,8 @@ void pal_init(void)
        printk("Ok (rev %lx)\n", rev);
        /* remove the old virtual page-table mapping */
        L1[1] = 0;
-       flush_tlb_all();
+
+       tbia(); /* do it directly in case we are SMP */
 }
 
 static inline long load(unsigned long dst,
@@ -189,30+192,59 @@ extern char _end;
 
 void start_kernel(void)
 {
-       long i;
-       int nbytes;
-       char envval[256];
+       static long i;
+       static int nbytes;
+       /*
+        * note that this crufty stuff with static and envval and envbuf
+        * is because:
+        *
+        * 1. frequently, the stack is is short, and we don't want to overrun;
+        * 2. frequently the stack is where we are going to copy the kernel to;
+        * 3. a certain SRM console required the GET_ENV output to stack.
+        */
+       static char envval[256];
+       char envbuf[256];
 
        printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n");
        if (hwrpb.pagesize != 8192) {
-               printk("Expected 8kB pages, got %ldkB\n", hwrpb.pagesize >> 10);
+               printk("Expected 8kB pages, got %ldkB\n",
+                      hwrpb.pagesize >> 10);
                return;
        }
        pal_init();
 
        nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
-                         envval, sizeof(envval));
-       if (nbytes < 0) {
+                         envbuf, sizeof(envbuf));
+       if (nbytes < 0 || nbytes >= sizeof(envbuf)) {
                nbytes = 0;
        }
-       envval[nbytes] = '\0';
-       strcpy((char*)ZERO_PAGE, envval);
-
-       printk("Loading the kernel ...\n");
+       envbuf[nbytes] = '\0';
+       memcpy(envval, envbuf, nbytes+1);
+       printk("Loading the kernel...'%s'\n", envval);
 
        /* NOTE: *no* callbacks or printouts from here on out!!! */
 
+#if 1
+       /*
+        * this is a hack, as some consoles seem to get virtual 20000000
+        * (ie where the SRM console puts the kernel bootp image) memory
+        * overlapping physical 310000 memory, which causes real problems
+        * when attempting to copy the former to the latter... :-(
+        *
+        * so, we first move the kernel virtual-to-physical way above where
+        * we physically want the kernel to end up, then copy it from there
+        * to its final resting place... ;-}
+        *
+        * sigh...
+        */
+
+        i = load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
+        i = load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
+#else
        i = load(START_ADDR, KERNEL_ORIGIN, KERNEL_SIZE);
+#endif
+
+       strcpy((char*)ZERO_PAGE, envval);
 
        runkernel();
 
index 1fefe0c..25aedbf 100644 (file)
@@ -6,11+6,13 @@ mainmenu_name "Kernel configuration of Linux for Alpha machines"
 
 # clear all implied options (don't want default values for those):
 unset CONFIG_CROSSCOMPILE CONFIG_NATIVE
-unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5
+unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6
 unset CONFIG_PCI CONFIG_ALPHA_EISA
 unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
 unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS
+unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
 unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
+unset CONFIG_ALPHA_SRM CONFIG_ALPHA_SRM_SETUP
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
@@ -48,13+50,16 @@ choice 'Alpha system type' \
         PC164          CONFIG_ALPHA_PC164              \
         LX164          CONFIG_ALPHA_LX164              \
         SX164          CONFIG_ALPHA_SX164              \
+        DP264          CONFIG_ALPHA_DP264              \
         Jensen         CONFIG_ALPHA_JENSEN             \
         Noname         CONFIG_ALPHA_NONAME             \
+        Takara         CONFIG_ALPHA_TAKARA             \
         Mikasa         CONFIG_ALPHA_MIKASA             \
         Noritake       CONFIG_ALPHA_NORITAKE           \
         Alcor          CONFIG_ALPHA_ALCOR              \
         Miata          CONFIG_ALPHA_MIATA              \
         Sable          CONFIG_ALPHA_SABLE              \
+        Rawhide        CONFIG_ALPHA_RAWHIDE            \
         AlphaBook1     CONFIG_ALPHA_BOOK1              \
         Ruffian        CONFIG_ALPHA_RUFFIAN            \
         Platform2000   CONFIG_ALPHA_P2K" Cabriolet
@@ -78,7+83,8 @@ then
        define_bool CONFIG_ALPHA_APECS y
 fi
 if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
-       -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" ]
+       -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" \
+       -o "$CONFIG_ALPHA_TAKARA" = "y" ]
 then
        define_bool CONFIG_PCI y
        define_bool CONFIG_ALPHA_EV5 y
@@ -86,9+92,7 @@ then
 fi
 if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ]
 then
-       choice 'CPU daughtercard' \
-               "Pinnacle       CONFIG_ALPHA_PINNACLE \
-               Primo           CONFIG_ALPHA_PRIMO" Primo
+       bool 'EV5 CPU daughtercard (model 5/xxx)?' CONFIG_ALPHA_PRIMO
        if [ "$CONFIG_ALPHA_PRIMO" = "y" ]
        then
                define_bool CONFIG_ALPHA_EV5 y
@@ -102,7+106,13 @@ fi
 if [ "$CONFIG_ALPHA_SABLE" = "y" ]
 then
        define_bool CONFIG_PCI y
+       bool 'EV5 CPU(s) (model 5/xxx)?' CONFIG_ALPHA_GAMMA
+       if [ "$CONFIG_ALPHA_GAMMA" = "y" ]
+       then
+               define_bool CONFIG_ALPHA_EV5 y
+       else
        define_bool CONFIG_ALPHA_EV4 y
+       fi
        define_bool CONFIG_ALPHA_T2 y
 fi
 if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \
@@ -112,6+122,18 @@ then
        define_bool CONFIG_ALPHA_EV5 y
        define_bool CONFIG_ALPHA_PYXIS y
 fi
+if [ "$CONFIG_ALPHA_DP264" = "y" ]
+then
+       define_bool CONFIG_PCI y
+       define_bool CONFIG_ALPHA_EV6 y
+       define_bool CONFIG_ALPHA_TSUNAMI y
+fi
+if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ]
+then
+       define_bool CONFIG_PCI y
+       define_bool CONFIG_ALPHA_EV5 y
+       define_bool CONFIG_ALPHA_MCPCIA y
+fi
 if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
 then
        define_bool CONFIG_ALPHA_EV4 y
@@ -127,12+149,19 @@ if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
        -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \
        -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \
        -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
-       -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ]
+       -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \
+       -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" ]
 then
-       bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
+  bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    if [ "$CONFIG_ALPHA_SRM" = "y" ]; then
+      bool '  Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP
+    fi
+  fi
 fi
 if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
-       -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ]
+       -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
+       -o "$CONFIG_ALPHA_RAWHIDE" = "y" ]
 then
        define_bool CONFIG_ALPHA_EISA y
 fi
@@ -141,8+170,13 @@ then
        define_bool CONFIG_ALPHA_AVANTI y
 fi
 
+#bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO
+
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'TGA Console Support' CONFIG_TGA_CONSOLE
+#  if [ "$CONFIG_TGA_CONSOLE" = "y" ]; then
+#    bool 'VGA Console Support' CONFIG_VGA_CONSOLE
+#  fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
   fi
@@ -216,17+250,6 @@ if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
 fi
 endmenu
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_CDU31A" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" -o "$CONFIG_SBPCD" = "m" -o "$CONFIG_MCD" = "m" -o "$CONFIG_CM206" = "m" -o "$CONFIG_CDU31A" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 source fs/nls/Config.in
index 1bdecf4..7d78e4b 100644 (file)
@@ -27,14+27,20 @@ CONFIG_NATIVE=y
 # CONFIG_ALPHA_EB64P is not set
 # CONFIG_ALPHA_EB164 is not set
 # CONFIG_ALPHA_PC164 is not set
+# CONFIG_ALPHA_LX164 is not set
+# CONFIG_ALPHA_SX164 is not set
+# CONFIG_ALPHA_DP264 is not set
 # CONFIG_ALPHA_JENSEN is not set
 # CONFIG_ALPHA_NONAME is not set
+# CONFIG_ALPHA_TAKARA is not set
 # CONFIG_ALPHA_MIKASA is not set
 # CONFIG_ALPHA_NORITAKE is not set
 CONFIG_ALPHA_ALCOR=y
 # CONFIG_ALPHA_MIATA is not set
 # CONFIG_ALPHA_SABLE is not set
+# CONFIG_ALPHA_RAWHIDE is not set
 # CONFIG_ALPHA_BOOK1 is not set
+# CONFIG_ALPHA_RUFFIAN is not set
 # CONFIG_ALPHA_P2K is not set
 CONFIG_PCI=y
 CONFIG_ALPHA_EV5=y
@@ -214,7+220,6 @@ CONFIG_DE4X5=y
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
-CONFIG_CDROM=y
 
 #
 # Filesystems
index ba0aee5..8d09ea8 100644 (file)
@@ -8,9+8,9 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 .S.s:
-       $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
+       $(CPP) -D__ASSEMBLY__ $(AFLAGS) -traditional    $< -o $*.s
 .S.o:
-       $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+       $(CC)  -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
 all: kernel.o head.o
 
@@ -35,19+35,29 @@ endif
 ifdef CONFIG_ALPHA_T2
 O_OBJS   += t2.o
 endif
+ifdef CONFIG_ALPHA_TSUNAMI
+O_OBJS   += tsunami.o
+endif
+ifdef CONFIG_ALPHA_MCPCIA
+O_OBJS   += mcpcia.o
+endif
+
 ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),nn)
 O_OBJS   += smc37c93x.o
 endif
-ifdef CONFIG_ALPHA_SX164
+ifneq ($(CONFIG_ALPHA_SX164)$(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),nnn)
 O_OBJS   += smc37c669.o
 endif
 
+ifdef SMP
+O_OBJS   += smp.o
+endif
 
 all: kernel.o head.o
 
 head.o: head.s
 
 head.s: head.S $(TOPDIR)/include/asm-alpha/system.h
-       $(CPP) -traditional -o $*.s $<
+       $(CPP) -traditional $(AFLAGS) -o $*.s $<
 
 include $(TOPDIR)/Rules.make
index d5e7fa2..f2e8d9a 100644 (file)
 #include <asm/hwrpb.h>
 #include <asm/ptrace.h>
 
-/* NOTE: Herein are back-to-back mb insns.  They are magic. 
-   A plausible explanation is that the i/o controler does not properly
-   handle the system transaction.  Another involves timing.  Ho hum.  */
+/*
+ * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
+ * One plausible explanation is that the i/o controller does not properly
+ * handle the system transaction.  Another involves timing.  Ho hum.
+ */
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern int alpha_sys_type;
 
 /*
  * BIOS32-style PCI interface:
@@ -36,13+37,16 @@ extern int alpha_sys_type;
 # define DBG(args)
 #endif
 
-#define vulp   volatile unsigned long *
 #define vuip   volatile unsigned int  *
 
 static volatile unsigned int apecs_mcheck_expected = 0;
 static volatile unsigned int apecs_mcheck_taken = 0;
-static unsigned long apecs_jd, apecs_jd1, apecs_jd2;
+static unsigned int apecs_jd, apecs_jd1, apecs_jd2;
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int APECS_DMA_WIN_BASE = APECS_DMA_WIN_BASE_DEFAULT;
+unsigned int APECS_DMA_WIN_SIZE = APECS_DMA_WIN_SIZE_DEFAULT;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -194,7+198,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
                }
 
                /* reset error status: */
-               *(vulp)APECS_IOC_DCSR = stat0;
+               *(vuip)APECS_IOC_DCSR = stat0;
                mb();
                wrmces(0x7);                    /* reset machine check */
                value = 0xffffffff;
@@ -269,7+273,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char typ
                }
 
                /* reset error status: */
-               *(vulp)APECS_IOC_DCSR = stat0;
+               *(vuip)APECS_IOC_DCSR = stat0;
                mb();
                wrmces(0x7);                    /* reset machine check */
        }
@@ -424,6+428,38 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)APECS_IOC_TB2R = 0;
 
 #else  /* CONFIG_ALPHA_XL */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 1 for enabled and mapped to 0 */
+       if ((*(vuip)APECS_IOC_PB1R & (1U<<19)) && (*(vuip)APECS_IOC_TB1R == 0))
+       {
+         APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB1R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM1R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE += 0x00100000U;
+#if 0
+         printk("apecs_init: using Window 1 settings\n");
+         printk("apecs_init: PB1R 0x%x PM1R 0x%x TB1R 0x%x\n",
+                *(vuip)APECS_IOC_PB1R,
+                *(vuip)APECS_IOC_PM1R,
+                *(vuip)APECS_IOC_TB1R);
+#endif
+       }
+       else    /* check window 2 for enabled and mapped to 0 */
+       if ((*(vuip)APECS_IOC_PB2R & (1U<<19)) && (*(vuip)APECS_IOC_TB2R == 0))
+       {
+         APECS_DMA_WIN_BASE = *(vuip)APECS_IOC_PB2R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE = *(vuip)APECS_IOC_PM2R & 0xfff00000U;
+         APECS_DMA_WIN_SIZE += 0x00100000U;
+#if 0
+         printk("apecs_init: using Window 2 settings\n");
+         printk("apecs_init: PB2R 0x%x PM2R 0x%x TB2R 0x%x\n",
+                *(vuip)APECS_IOC_PB2R,
+                *(vuip)APECS_IOC_PM2R,
+                *(vuip)APECS_IOC_TB2R);
+#endif
+       }
+       else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+       {
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, window 2 is disabled.  In the future, we may
@@ -435,9+471,11 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)APECS_IOC_PB1R  = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U);
        *(vuip)APECS_IOC_PM1R  = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U;
        *(vuip)APECS_IOC_TB1R  = 0;
+       }
 #endif /* CONFIG_ALPHA_XL */
 
 #ifdef CONFIG_ALPHA_CABRIOLET
+#ifdef NO_LONGER_NEEDED_I_HOPE
        /*
         * JAE: HACK!!! for now, hardwire if configured...
         * davidm: Older miniloader versions don't set the clock frequency
@@ -461,6+499,7 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
              sum += *l;
            hwrpb->chksum = sum;
        }
+#endif /* NO_LONGER_NEEDED_I_HOPE */
 #endif /* CONFIG_ALPHA_CABRIOLET */
 
        /*
@@ -483,15+522,15 @@ unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
 
 int apecs_pci_clr_err(void)
 {
-       apecs_jd = *(vulp)APECS_IOC_DCSR;
+       apecs_jd = *(vuip)APECS_IOC_DCSR;
        if (apecs_jd & 0xffe0L) {
-               apecs_jd1 = *(vulp)APECS_IOC_SEAR;
-               *(vulp)APECS_IOC_DCSR = apecs_jd | 0xffe1L;
-               apecs_jd = *(vulp)APECS_IOC_DCSR;
+               apecs_jd1 = *(vuip)APECS_IOC_SEAR;
+               *(vuip)APECS_IOC_DCSR = apecs_jd | 0xffe1L;
+               apecs_jd = *(vuip)APECS_IOC_DCSR;
                mb();
        }
-       *(vulp)APECS_IOC_TBIA = APECS_IOC_TBIA;
-       apecs_jd2 = *(vulp)APECS_IOC_TBIA;
+       *(vuip)APECS_IOC_TBIA = (unsigned int)APECS_IOC_TBIA;
+       apecs_jd2 = *(vuip)APECS_IOC_TBIA;
        mb();
        return 0;
 }
index af89718..89e57e4 100644 (file)
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/tasks.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
@@ -63,6+64,8 @@ asmlinkage int sys_pciconfig_write()
 #include <asm/hwrpb.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/segment.h>
+#include <asm/system.h>
 
 
 #define KB             1024
@@ -70,7+73,9 @@ asmlinkage int sys_pciconfig_write()
 #define GB             (1024*MB)
 
 #define MAJOR_REV      0
-#define MINOR_REV      3
+
+/* minor revision 4, add multi-PCI handling */
+#define MINOR_REV      4
 
 /*
  * Align VAL to ALIGN, which must be a power of two.
@@ -78,7+83,20 @@ asmlinkage int sys_pciconfig_write()
 #define ALIGN(val,align)       (((val) + ((align) - 1)) & ~((align) - 1))
 
 
+#if defined(CONFIG_ALPHA_MCPCIA) || defined(CONFIG_ALPHA_TSUNAMI)
+/* multiple PCI bus machines */
+/* make handle from bus number */
+extern struct linux_hose_info *bus2hose[256];
+#define HANDLE(b) (((unsigned long)(bus2hose[(b)]->pci_hose_index)&3)<<32)
+#define DEV_IS_ON_PRIMARY(dev) \
+       (bus2hose[(dev)->bus->number]->pci_first_busno == (dev)->bus->number)
+#else /* MCPCIA || TSUNAMI */
+#define HANDLE(b) (0)
+#define DEV_IS_ON_PRIMARY(dev) ((dev)->bus->number == 0)
+#endif /* MCPCIA || TSUNAMI */
 /*
+ * PCI_MODIFY
+ *
  * Temporary internal macro.  If this 0, then do not write to any of
  * the PCI registers, merely read them (i.e., use configuration as
  * determined by SRM).  The SRM seem do be doing a less than perfect
@@ -95,7+113,18 @@ asmlinkage int sys_pciconfig_write()
  * the graphics card---there have been some rumor that the #9 BIOS
  * incorrectly resets that address to 0...).
  */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+#define PCI_MODIFY             0
+static struct pci_dev *irq_dev_to_reset[16];
+static unsigned char irq_to_reset[16];
+static int irq_reset_count = 0;
+static struct pci_dev *io_dev_to_reset[16];
+static unsigned char io_reg_to_reset[16];
+static unsigned int io_to_reset[16];
+static int io_reset_count = 0;
+#else /* SRM_SETUP */
 #define PCI_MODIFY             1
+#endif /* SRM_SETUP */
 
 extern struct hwrpb_struct *hwrpb;
 
@@ -103,9+132,7 @@ extern struct hwrpb_struct *hwrpb;
 #if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)
 extern int SMC93x_Init(void);
 #endif
-#ifdef CONFIG_ALPHA_SX164
 extern int SMC669_Init(void);
-#endif
 #ifdef CONFIG_ALPHA_MIATA
 static int es1888_init(void);
 #endif
@@ -115,7+142,7 @@ static int es1888_init(void);
 /*
  * NOTE: we can't just blindly use 64K for machines with EISA busses; they
  * may also have PCI-PCI bridges present, and then we'd configure the bridge
- * incorrectly
+ * incorrectly.
  *
  * Also, we start at 0x8000 or 0x9000, in hopes to get all devices'
  * IO space areas allocated *before* 0xC000; this is because certain
@@ -123,12+150,17 @@ static int es1888_init(void);
  * accesses to probe the bus. If a device's registers appear at 0xC000,
  * it may see an INx/OUTx at that address during BIOS emulation of the
  * VGA BIOS, and some cards, notably Adaptec 2940UW, take mortal offense.
+ *
+ * Note that we may need this stuff for SRM_SETUP also, since certain
+ * SRM consoles screw up and allocate I/O space addresses > 64K behind
+ * PCI-to_PCI bridges, which can't pass I/O addresses larger than 64K, AFAIK.
  */
 #if defined(CONFIG_ALPHA_EISA)
-static unsigned int    io_base  = 0x9000;      /* start above 8th slot */
+#define DEFAULT_IO_BASE 0x9000 /* start above 8th slot */
 #else
-static unsigned int    io_base  = 0x8000;
+#define DEFAULT_IO_BASE 0x8000 /* start at 8th slot */
 #endif
+static unsigned int    io_base;
 
 #if defined(CONFIG_ALPHA_XL)
 /*
@@ -142,7+174,7 @@ static unsigned int    io_base  = 0x8000;
  * We accept the risk that a broken Myrinet card will be put into a true XL
  * and thus can more easily run into the problem described below.
  */
-static unsigned int mem_base = 16*MB + 2*MB; /* 16M to 64M-1 is avail */
+#define DEFAULT_MEM_BASE (16*MB + 2*MB) /* 16M to 64M-1 is avail */
 
 #elif defined(CONFIG_ALPHA_LCA) || defined(CONFIG_ALPHA_APECS)
 /*
@@ -154,7+186,7 @@ static unsigned int mem_base = 16*MB + 2*MB; /* 16M to 64M-1 is avail */
  * However, APECS and LCA have only 34 bits for physical addresses, thus
  * limiting PCI bus memory addresses for SPARSE access to be less than 128Mb.
  */
-static unsigned int mem_base = 64*MB + 2*MB;
+#define DEFAULT_MEM_BASE (64*MB + 2*MB)
 
 #else
 /*
@@ -166,9+198,10 @@ static unsigned int mem_base = 64*MB + 2*MB;
  * Because CIA and PYXIS and T2 have more bits for physical addresses,
  * they support an expanded range of SPARSE memory addresses.
  */
-static unsigned int    mem_base = 128*MB + 16*MB;
+#define DEFAULT_MEM_BASE (128*MB + 16*MB)
 
 #endif
+static unsigned int mem_base; 
 
 /*
  * Disable PCI device DEV so that it does not respond to I/O or memory
@@ -179,7+212,6 @@ static void disable_dev(struct pci_dev *dev)
        struct pci_bus *bus;
        unsigned short cmd;
 
-#ifdef CONFIG_ALPHA_EISA
        /*
         * HACK: the PCI-to-EISA bridge does not seem to identify
         *       itself as a bridge... :-(
@@ -189,15+221,17 @@ static void disable_dev(struct pci_dev *dev)
                DBG_DEVS(("disable_dev: ignoring PCEB...\n"));
                return;
        }
-#endif
-#ifdef CONFIG_ALPHA_SX164
+
+       /*
+        * we don't have code that will init the CYPRESS bridge correctly
+        * so we do the next best thing, and depend on the previous
+        * console code to do the right thing, and ignore it here... :-\
+        */
        if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
-           /* FIXME: We want a symbolic device name here.  */
-           dev->device == 0xc693) {
+           dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
                DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n"));
                return;
        }
-#endif
 
        bus = dev->bus;
        pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
@@ -211,16+245,16 @@ static void disable_dev(struct pci_dev *dev)
 /*
  * Layout memory and I/O for a device:
  */
-#define MAX(val1, val2) ((val1) > (val2) ? val1 : val2)
+#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2))
 
 static void layout_dev(struct pci_dev *dev)
 {
        struct pci_bus *bus;
        unsigned short cmd;
-       unsigned int base, mask, size, reg;
+       unsigned int base, mask, size, off;
        unsigned int alignto;
+       unsigned long handle;
 
-#ifdef CONFIG_ALPHA_EISA
        /*
         * HACK: the PCI-to-EISA bridge does not seem to identify
         *       itself as a bridge... :-(
@@ -230,32+264,39 @@ static void layout_dev(struct pci_dev *dev)
                DBG_DEVS(("layout_dev: ignoring PCEB...\n"));
                return;
        }
-#endif
-#ifdef CONFIG_ALPHA_SX164
+
+       /*
+        * we don't have code that will init the CYPRESS bridge correctly
+        * so we do the next best thing, and depend on the previous
+        * console code to do the right thing, and ignore it here... :-\
+        */
        if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
-           dev->device == 0xc693) {
+           dev->device == PCI_DEVICE_ID_CONTAQ_82C693) {
                DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n"));
                return;
        }
-#endif
 
        bus = dev->bus;
        pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
 
-       for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+       for (off = PCI_BASE_ADDRESS_0; off <= PCI_BASE_ADDRESS_5; off += 4) {
                /*
                 * Figure out how much space and of what type this
                 * device wants.
                 */
-               pcibios_write_config_dword(bus->number, dev->devfn, reg,
+               pcibios_write_config_dword(bus->number, dev->devfn, off,
                                           0xffffffff);
-               pcibios_read_config_dword(bus->number, dev->devfn, reg, &base);
+               pcibios_read_config_dword(bus->number, dev->devfn, off, &base);
                if (!base) {
                        /* this base-address register is unused */
-                       dev->base_address[(reg - PCI_BASE_ADDRESS_0)>>2] = 0;
+                       dev->base_address[PCI_BASE_INDEX(off)] = 0;
                        continue;
                }
 
+               DBG_DEVS(("layout_dev: slot %d fn %d off 0x%x base 0x%x\n",
+                         PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+                         off, base));
+
                /*
                 * We've read the base address register back after
                 * writing all ones and so now we must decode it.
@@ -281,11+322,13 @@ static void layout_dev(struct pci_dev *dev)
                        base = ALIGN(io_base, alignto);
                        io_base = base + size;
                        pcibios_write_config_dword(bus->number, dev->devfn, 
-                                                  reg, base | 0x1);
-                       dev->base_address[(reg - PCI_BASE_ADDRESS_0)>>2]
-                               = base | 0x1;
-                       DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%x (0x%x)\n",
-                                 dev->device, base, size));
+                                                  off, base | 0x1);
+
+                       handle = HANDLE(bus->number) | base | 1;
+                       dev->base_address[PCI_BASE_INDEX(off)] = handle;
+
+                       DBG_DEVS(("layout_dev: dev 0x%x IO @ 0x%lx (0x%x)\n",
+                                 dev->device, handle, size));
                } else {
                        unsigned int type;
                        /*
@@ -306,7+349,7 @@ static void layout_dev(struct pci_dev *dev)
                                       "slot %d, function %d: \n",
                                       PCI_SLOT(dev->devfn),
                                       PCI_FUNC(dev->devfn));
-                               reg += 4;       /* skip extra 4 bytes */
+                               off += 4;       /* skip extra 4 bytes */
                                continue;
 
                        case PCI_BASE_ADDRESS_MEM_TYPE_1M:
@@ -365,10+408,11 @@ static void layout_dev(struct pci_dev *dev)
                        }
                        mem_base = base + size;
                        pcibios_write_config_dword(bus->number, dev->devfn,
-                                                  reg, base);
-                       dev->base_address[(reg-PCI_BASE_ADDRESS_0)>>2] = base;
-                       DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%x (0x%x)\n",
-                                 dev->device, base, size));
+                                                  off, base);
+                       handle = HANDLE(bus->number) | base;
+                       dev->base_address[PCI_BASE_INDEX(off)] = handle;
+                       DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n",
+                                 dev->device, handle, size));
                }
        }
 
@@ -397,16+441,17 @@ static void layout_dev(struct pci_dev *dev)
 }
 
 
-static void layout_bus(struct pci_bus *bus)
+static int layout_bus(struct pci_bus *bus)
 {
        unsigned int l, tio, bio, tmem, bmem;
        struct pci_bus *child;
        struct pci_dev *dev;
+       int found_vga = 0;
 
        DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
 
        if (!bus->devices && !bus->children)
-               return;
+               return 0;
 
        /*
         * Align the current bases on appropriate boundaries (4K for
@@ -424,6+469,8 @@ static void layout_bus(struct pci_bus *bus)
         * devices.  They'll be re-enabled only once all address
         * decoders are programmed consistently.
         */
+       DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number));
+
        for (dev = bus->devices; dev; dev = dev->sibling) {
                if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
                    (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
@@ -441,6+488,8 @@ static void layout_bus(struct pci_bus *bus)
                    (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
                        layout_dev(dev);
                }
+               if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+                       found_vga = 1;
        }
        /*
         * Recursively allocate space for all of the sub-buses:
@@ -448,7+497,7 @@ static void layout_bus(struct pci_bus *bus)
        DBG_DEVS(("layout_bus: starting bus %d children\n", bus->number));
 
        for (child = bus->children; child; child = child->next) {
-               layout_bus(child);
+               found_vga += layout_bus(child);
        }
        /*
         * Align the current bases on 4K and 1MB boundaries:
@@ -458,6+507,8 @@ static void layout_bus(struct pci_bus *bus)
 
        if (bus->self) {
                struct pci_dev *bridge = bus->self;
+
+               DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number));
                /*
                 * Set up the top and bottom of the PCI I/O segment
                 * for this bus.
@@ -481,10+532,13 @@ static void layout_bus(struct pci_bus *bus)
                pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
                                           0x24, 0x0000ffff);
                /*
-                * Tell bridge that there is an ISA bus in the system:
+                * Tell bridge that there is an ISA bus in the system,
+                * and (possibly) a VGA as well.
                 */
+               l = 0x00040000; /* ISA present */
+               if (found_vga) l |= 0x00080000; /* VGA present */
                pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
-                                          0x3c, 0x00040000);
+                                          0x3c, l);
                /*
                 * Clear status bits, enable I/O (for downstream I/O),
                 * turn on master enable (for upstream I/O), turn on
@@ -494,6+548,8 @@ static void layout_bus(struct pci_bus *bus)
                pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
                                           0x4, 0xffff0007);
        }
+       DBG_DEVS(("layout_bus: bus %d finished\n", bus->number));
+       return found_vga;
 }
 
 #endif /* !PCI_MODIFY */
@@ -633,6+689,76 @@ bridge_swizzle(unsigned char pin, unsigned int slot)
        return (((pin-1) + slot) % 4) + 1;
 }
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* look for mis-configured devices' I/O space addresses behind bridges */
+static void check_behind_io(struct pci_dev *dev)
+{
+       struct pci_bus *bus = dev->bus;
+       unsigned int reg, orig_base, new_base, found_one = 0;
+
+       for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+               /* read the current setting, check for I/O space and >= 64K */
+               pcibios_read_config_dword(bus->number, dev->devfn, reg, &orig_base);
+               if (!orig_base || !(orig_base & PCI_BASE_ADDRESS_SPACE_IO))
+                       continue; /* unused or non-IO */
+               if (orig_base < 64*1024) {
+#if 1
+printk("check_behind_io: ALREADY OK! bus %d slot %d base 0x%x\n",
+       bus->number, PCI_SLOT(dev->devfn), orig_base);
+#endif
+                       if (orig_base & ~1)
+                         continue; /* OK! */
+                       orig_base = 0x12001; /* HACK! FIXME!! */
+               }
+
+               /* HACK ALERT! for now, just subtract 32K from the
+                  original address, which should give us addresses
+                  in the range 0x8000 and up */
+               new_base = orig_base - 0x8000;
+#if 1
+printk("check_behind_io: ALERT! bus %d slot %d old 0x%x new 0x%x\n",
+       bus->number, PCI_SLOT(dev->devfn), orig_base, new_base);
+#endif
+               pcibios_write_config_dword(bus->number, dev->devfn,
+                                          reg, new_base);
+
+               io_dev_to_reset[io_reset_count] = dev;
+               io_reg_to_reset[io_reset_count] = reg;
+               io_to_reset[io_reset_count] = orig_base;
+               io_reset_count++;
+               found_one++;
+       } /* end for-loop */
+
+       /* if any were modified, gotta hack the bridge IO limits too... */
+       if (found_one) {
+           if (bus->self) {
+               struct pci_dev *bridge = bus->self;
+               unsigned int l;
+               /*
+                * Set up the top and bottom of the PCI I/O segment
+                * for this bus.
+                */
+               pcibios_read_config_dword(bridge->bus->number,
+                                         bridge->devfn, 0x1c, &l);
+#if 1
+printk("check_behind_io: ALERT! bus %d slot %d oldLIM 0x%x\n",
+       bus->number, PCI_SLOT(bridge->devfn), l);
+#endif
+               l = (l & 0xffff0000U) | 0xf080U; /* give it ALL */
+               pcibios_write_config_dword(bridge->bus->number,
+                                          bridge->devfn, 0x1c, l);
+               pcibios_write_config_dword(bridge->bus->number,
+                                          bridge->devfn,
+                                          0x3c, 0x00040000);
+               pcibios_write_config_dword(bridge->bus->number,
+                                          bridge->devfn,
+                                          0x4, 0xffff0007);
+           } else
+               printk("check_behind_io: WARNING! bus->self NULL\n");
+       }
+}
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+
 /*
  * Most evaluation boards share most of the fixup code, which is isolated
  * here.  This function is declared "inline" as only one platform will ever
@@ -644,7+770,7 @@ common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
             char irq_tab[max_idsel - min_idsel + 1][irqs_per_slot],
             long ide_base)
 {
-       struct pci_dev *dev;
+       struct pci_dev *dev, *curr;
        unsigned char pin;
        unsigned char slot;
 
@@ -652,12+778,18 @@ common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
         * Go through all devices, fixing up irqs as we see fit:
         */
        for (dev = pci_devices; dev; dev = dev->next) {
-               if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE
-                    /* PCEB (PCI to EISA bridge) does not identify
-                       itself as a bridge... :-P */
-                    && !(dev->vendor == PCI_VENDOR_ID_INTEL &&
-                         dev->device == PCI_DEVICE_ID_INTEL_82375))
-                    || dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) {
+               if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE ||
+                   dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA) {
+                       /*
+                        * HACK: the PCI-to-EISA bridge appears not to identify
+                        *       itself as a bridge... :-(
+                        */
+                       if (dev->vendor == PCI_VENDOR_ID_INTEL &&
+                           dev->device == PCI_DEVICE_ID_INTEL_82375) {
+                               DBG_DEVS(("common_fixup: ignoring PCEB...\n"));
+                               continue;
+                       }
+
                        /*
                         * This device is not on the primary bus, we need
                         * to figure out which interrupt pin it will come
@@ -668,45+800,100 @@ common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
                         * the inline static routine above).
                         */
                        dev->irq = 0;
-                       if (dev->bus->number != 0) {
-                               struct pci_dev *curr = dev;
+                       if (!DEV_IS_ON_PRIMARY(dev)) {
                                /* read the pin and do the PCI-PCI bridge
                                   interrupt pin swizzle */
                                pcibios_read_config_byte(dev->bus->number,
                                                         dev->devfn,
                                                         PCI_INTERRUPT_PIN,
                                                         &pin);
-                               /* cope with 0 */
-                               if (pin == 0)
+                               /* cope with 0 and illegal */
+                               if (pin == 0 || pin > 4)
                                        pin = 1;
                                /* follow the chain of bridges, swizzling
                                   as we go */
+                               curr = dev;
 #if defined(CONFIG_ALPHA_MIATA)
+                               /* check first for the built-in bridge */
+                               if ((PCI_SLOT(dev->bus->self->devfn) == 8) ||
+                                   (PCI_SLOT(dev->bus->self->devfn) == 20)) {
                                slot = PCI_SLOT(dev->devfn) + 5;
                                DBG_DEVS(("MIATA: bus 1 slot %d pin %d"
                                          " irq %d min_idsel %d\n",
                                          PCI_SLOT(dev->devfn), pin,
                                          irq_tab[slot - min_idsel][pin],
                                          min_idsel));
+                               }
+                               else /* must be a card-based bridge */
+                               {
+                               do {
+                                 if ((PCI_SLOT(curr->bus->self->devfn) == 8) ||
+                                     (PCI_SLOT(curr->bus->self->devfn) == 20))
+                                   {
+                                     slot = PCI_SLOT(curr->devfn) + 5;
+                                     break;
+                                   }
+                                       /* swizzle */
+                                   pin = bridge_swizzle(
+                                                 pin, PCI_SLOT(curr->devfn)) ;
+                                   /* move up the chain of bridges */
+                                   curr = curr->bus->self ;
+                                   /* slot of the next bridge. */
+                                   slot = PCI_SLOT(curr->devfn);
+                                 } while (curr->bus->self) ;
+                               }
 #elif defined(CONFIG_ALPHA_NORITAKE)
-                               /* WAG Alert! */
-                               slot = PCI_SLOT(dev->devfn) + 14;
+                               /* check first for the built-in bridge */
+                               if (PCI_SLOT(dev->bus->self->devfn) == 8) {
+                                 slot = PCI_SLOT(dev->devfn) + 15; /* WAG! */
                                DBG_DEVS(("NORITAKE: bus 1 slot %d pin %d"
-                                         " irq %d min_idsel %d\n",
+                                           "irq %d min_idsel %ld\n",
                                          PCI_SLOT(dev->devfn), pin,
                                          irq_tab[slot - min_idsel][pin],
                                          min_idsel));
-#else
+                               }
+                               else /* must be a card-based bridge */
+                               {
                                do {
+                                   if (PCI_SLOT(curr->bus->self->devfn) == 8) {
+                                     slot = PCI_SLOT(curr->devfn) + 15;
+                                     break;
+                                   }
                                        /* swizzle */
-                                       pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn));
+                                   pin = bridge_swizzle(
+                                               pin, PCI_SLOT(curr->devfn)) ;
+                                   /* move up the chain of bridges */
+                                   curr = curr->bus->self ;
+                                   /* slot of the next bridge. */
+                                   slot = PCI_SLOT(curr->devfn);
+                                 } while (curr->bus->self) ;
+                               }
+#else /* everyone but MIATA and NORITAKE */
+                               DBG_DEVS(("common_fixup: bus %d slot %d pin %d "
+                                         "irq %d min_idsel %ld\n",
+                                         curr->bus->number,
+                                         PCI_SLOT(dev->devfn), pin,
+                                         irq_tab[slot - min_idsel][pin],
+                                         min_idsel));
+                               do {
+                                 /* swizzle */
+                                 pin =
+                                   bridge_swizzle(pin, PCI_SLOT(curr->devfn));
                                        /* move up the chain of bridges */
                                        curr = curr->bus->self;
                                } while (curr->bus->self);
                                /* The slot is the slot of the last bridge. */
                                slot = PCI_SLOT(curr->devfn);
-#endif /* MIATA */
-                       } else {
+#endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+                               /*
+                                * must make sure that SRM didn't screw up
+                                * and allocate an address > 64K for I/O
+                                * space behind a PCI-PCI bridge
+                               */
+                               check_behind_io(dev);
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+                       } else { /* just a device on a primary bus */
                                /* work out the slot */
                                slot = PCI_SLOT(dev->devfn);
                                /* read the pin */
@@ -714,16+901,48 @@ common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
                                                         dev->devfn,
                                                         PCI_INTERRUPT_PIN,
                                                         &pin);
+                               DBG_DEVS(("common_fixup: bus %d slot %d"
+                                         " pin %d irq %d min_idsel %ld\n",
+                                         dev->bus->number, slot, pin,
+                                         irq_tab[slot - min_idsel][pin],
+                                         min_idsel));
+                               /* cope with 0 and illegal */
+                               if (pin == 0 || pin > 4)
+                                       pin = 1;
                        }
                        if (irq_tab[slot - min_idsel][pin] != -1)
                                dev->irq = irq_tab[slot - min_idsel][pin];
-#if PCI_MODIFY
-                       /* tell the device: */
-                       pcibios_write_config_byte(dev->bus->number,
+#ifdef CONFIG_ALPHA_RAWHIDE
+                       dev->irq +=
+                           24 * bus2hose[dev->bus->number]->pci_hose_index;
+#endif /* RAWHIDE */
+#ifdef CONFIG_ALPHA_SRM
+                       {
+                         unsigned char irq_orig;
+                         /* read the original SRM-set IRQ and tell */
+                         pcibios_read_config_byte(dev->bus->number,
                                                  dev->devfn,
                                                  PCI_INTERRUPT_LINE,
-                                                 dev->irq);
-#endif
+                                                   &irq_orig);
+                         if (irq_orig != dev->irq) {
+                           DBG_DEVS(("common_fixup: bus %d slot 0x%x "
+                                     "SRM IRQ 0x%x changed to 0x%x\n",
+                                     dev->bus->number,PCI_SLOT(dev->devfn),
+                                     irq_orig, dev->irq));
+#ifdef CONFIG_ALPHA_SRM_SETUP
+                           irq_dev_to_reset[irq_reset_count] = dev;
+                           irq_to_reset[irq_reset_count] = irq_orig;
+                           irq_reset_count++;
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+                         }
+                       }
+#endif /* SRM */
+
+                       /* always tell the device, so the driver knows what is
+                        * the real IRQ to use; the device does not use it.
+                        */
+                       pcibios_write_config_byte(dev->bus->number, dev->devfn,
+                                                 PCI_INTERRUPT_LINE, dev->irq);
 
                        DBG_DEVS(("common_fixup: bus %d slot 0x%x"
                                  " VID 0x%x DID 0x%x\n"
@@ -737,11+956,24 @@ common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
                         * if it's a VGA, enable its BIOS ROM at C0000
                         */
                        if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
-                               pcibios_write_config_dword(dev->bus->number,
+                         /* but if its a Cirrus 543x/544x DISABLE it, */
+                         /* since enabling ROM disables the memory... */
+                         if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) &&
+                             (dev->device >= 0x00a0) &&
+                             (dev->device <= 0x00ac)) {
+                                 pcibios_write_config_dword(
+                                       dev->bus->number,
+                                       dev->devfn,
+                                       PCI_ROM_ADDRESS,
+                                       0x00000000);
+                         } else {
+                                 pcibios_write_config_dword(
+                                       dev->bus->number,
                                                           dev->devfn,
                                                           PCI_ROM_ADDRESS,
                                                           0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
                        }
+                       }
                        /*
                         * if it's a SCSI, disable its BIOS ROM
                         */
@@ -752,46+984,6 @@ common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
                                                           0x0000000);
                        }
                }
-#ifdef CONFIG_ALPHA_SX164
-               /* If it the CYPRESS PCI-ISA bridge, disable IDE
-                  interrupt routing through PCI (ie do through PIC).  */
-               else if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
-                        dev->device == 0xc693 &&
-                        PCI_FUNC(dev->devfn) == 0) {
-                       pcibios_write_config_word(dev->bus->number,
-                                                 dev->devfn, 0x04, 0x0007);
-
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x40, 0x80);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x41, 0x80);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x42, 0x80);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x43, 0x80);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x44, 0x27);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x45, 0xe0);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x48, 0xf0);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x49, 0x40);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x4a, 0x00);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x4b, 0x80);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x4c, 0x80);
-                       pcibios_write_config_byte(dev->bus->number,
-                                                 dev->devfn, 0x4d, 0x70);
-
-                       outb(0, DMA1_RESET_REG);
-                       outb(0, DMA2_RESET_REG);
-                       outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
-                       outb(0, DMA2_MASK_REG);
-               }
-#endif /* SX164 */
        }
        if (ide_base) {
                enable_ide(ide_base);
@@ -814,6+1006,7 @@ common_fixup(long min_idsel, long max_idsel, long irqs_per_slot,
 static inline void eb66p_fixup(void)
 {
        static char irq_tab[5][5] __initlocaldata = {
+               /*INT  INTA  INTB  INTC   INTD */
                {16+0, 16+0, 16+5,  16+9, 16+13},  /* IdSel 6,  slot 0, J25 */
                {16+1, 16+1, 16+6, 16+10, 16+14},  /* IdSel 7,  slot 1, J26 */
                {  -1,   -1,   -1,    -1,    -1},  /* IdSel 8,  SIO         */
@@ -825,8+1018,8 @@ static inline void eb66p_fixup(void)
 
 
 /*
- * The PC164/LX164 has 19 PCI interrupts, four from each of the four PCI
- * slots, the SIO, PCI/IDE, and USB.
+ * The PC164 and LX164 have 19 PCI interrupts, four from each of the four
+ * PCI slots, the SIO, PCI/IDE, and USB.
  * 
  * Each of the interrupts can be individually masked. This is
  * accomplished by setting the appropriate bit in the mask register.
@@ -901,6+1094,7 @@ static inline void alphapc164_fixup(void)
 static inline void cabriolet_fixup(void)
 {
        static char irq_tab[5][5] __initlocaldata = {
+               /*INT   INTA  INTB  INTC   INTD */
                { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5,  slot 2, J21 */
                { 16+0, 16+0, 16+5,  16+9, 16+13}, /* IdSel 6,  slot 0, J19 */
                { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7,  slot 1, J20 */
@@ -957,6+1151,7 @@ static inline void cabriolet_fixup(void)
 static inline void eb66_and_eb64p_fixup(void)
 {
        static char irq_tab[5][5] __initlocaldata = {
+               /*INT  INTA  INTB  INTC   INTD */
                {16+7, 16+7, 16+7, 16+7,  16+7},  /* IdSel 5,  slot ?, ?? */
                {16+0, 16+0, 16+2, 16+4,  16+9},  /* IdSel 6,  slot ?, ?? */
                {16+1, 16+1, 16+3, 16+8, 16+10},  /* IdSel 7,  slot ?, ?? */
@@ -968,7+1163,7 @@ static inline void eb66_and_eb64p_fixup(void)
 
 
 /*
- * Fixup configuration for MIKASA (NORITAKE is different)
+ * Fixup configuration for MIKASA (AlphaServer 1000)
  *
  * Summary @ 0x536:
  * Bit      Meaning
@@ -1020,7+1215,10 @@ static inline void mikasa_fixup(void)
 }
 
 /*
- * Fixup configuration for NORITAKE (MIKASA is different)
+ * Fixup configuration for NORITAKE (AlphaServer 1000A)
+ *
+ * This is also used for CORELLE (AlphaServer 800)
+ * and ALCOR Primo (AlphaStation 600A).
  *
  * Summary @ 0x542, summary register #1:
  * Bit      Meaning
@@ -1076,8+1274,11 @@ static inline void mikasa_fixup(void)
  */
 static inline void noritake_fixup(void)
 {
-       static char irq_tab[13][5] __initlocaldata = {
+       static char irq_tab[15][5] __initlocaldata = {
                /*INT    INTA   INTB   INTC   INTD */
+         /* note: IDSELs 16, 17, and 25 are CORELLE only */
+          { 16+1,  16+1,  16+1,  16+1,  16+1},  /* IdSel 16,  QLOGIC */
+         {   -1,    -1,    -1,    -1,    -1},  /* IdSel 17,  S3 Trio64 */
                {   -1,    -1,    -1,    -1,    -1},  /* IdSel 18,  PCEB */
                {   -1,    -1,    -1,    -1,    -1},  /* IdSel 19,  PPB  */
                {   -1,    -1,    -1,    -1,    -1},  /* IdSel 20,  ???? */
@@ -1085,18+1286,20 @@ static inline void noritake_fixup(void)
                { 16+2,  16+2,  16+3,  32+2,  32+3},  /* IdSel 22,  slot 0 */
                { 16+4,  16+4,  16+5,  32+4,  32+5},  /* IdSel 23,  slot 1 */
                { 16+6,  16+6,  16+7,  32+6,  32+7},  /* IdSel 24,  slot 2 */
-               /* The following are actually on bus 1, across the bridge */
+         { 16+8,  16+8,  16+9,  32+8,  32+9},  /* IdSel 25,  slot 3 */
+         /* the following 5 are actually on PCI bus 1, which is */
+         /* across the built-in bridge of the NORITAKE only */
                { 16+1,  16+1,  16+1,  16+1,  16+1},  /* IdSel 16,  QLOGIC */
                { 16+8,  16+8,  16+9,  32+8,  32+9},  /* IdSel 17,  slot 3 */
                {16+10, 16+10, 16+11, 32+10, 32+11},  /* IdSel 18,  slot 4 */
                {16+12, 16+12, 16+13, 32+12, 32+13},  /* IdSel 19,  slot 5 */
                {16+14, 16+14, 16+15, 32+14, 32+15},  /* IdSel 20,  slot 6 */
        };
-       common_fixup(7, 18, 5, irq_tab, 0);
+       common_fixup(5, 19, 5, irq_tab, 0);
 }
 
 /*
- * Fixup configuration for ALCOR
+ * Fixup configuration for ALCOR and XLT (XL-300/366/433)
  *
  * Summary @ GRU_INT_REQ:
  * Bit      Meaning
@@ -1126,6+1329,7 @@ static inline void noritake_fixup(void)
  * The device to slot mapping looks like:
  *
  * Slot     Device
+ *  6       built-in TULIP (XLT only)
  *  7       PCI on board slot 0
  *  8       PCI on board slot 3
  *  9       PCI on board slot 4
@@ -1140,8+1344,10 @@ static inline void noritake_fixup(void)
  */
 static inline void alcor_fixup(void)
 {
-       static char irq_tab[6][5] __initlocaldata = {
+       static char irq_tab[7][5] __initlocaldata = {
                /*INT    INTA   INTB   INTC   INTD */
+         /* note: IDSEL 17 is XLT only */
+         {16+13, 16+13, 16+13, 16+13, 16+13},  /* IdSel 17,  TULIP  */
                { 16+8,  16+8,  16+9, 16+10, 16+11},    /* IdSel 18,  slot 0 */
                {16+16, 16+16, 16+17, 16+18, 16+19},    /* IdSel 19,  slot 3 */
                {16+12, 16+12, 16+13, 16+14, 16+15},    /* IdSel 20,  slot 4 */
@@ -1149,62+1355,6 @@ static inline void alcor_fixup(void)
                { 16+0,  16+0,  16+1,  16+2,  16+3},    /* IdSel 22,  slot 2 */
                { 16+4,  16+4,  16+5,  16+6,  16+7},    /* IdSel 23,  slot 1 */
        };
-       common_fixup(7, 12, 5, irq_tab, 0);
-}
-
-/*
- * Fixup configuration for ALPHA XLT (EV5/EV56)
- *
- * Summary @ GRU_INT_REQ:
- * Bit      Meaning
- * 0        Interrupt Line A from slot 2
- * 1        Interrupt Line B from slot 2
- * 2        Interrupt Line C from slot 2
- * 3        Interrupt Line D from slot 2
- * 4        Interrupt Line A from slot 1
- * 5        Interrupt line B from slot 1
- * 6        Interrupt Line C from slot 1
- * 7        Interrupt Line D from slot 1
- * 8        Interrupt Line A from slot 0
- * 9        Interrupt Line B from slot 0
- *10        Interrupt Line C from slot 0
- *11        Interrupt Line D from slot 0
- *12        NCR810 SCSI in slot 9
- *13        DC-21040 (TULIP) in slot 6
- *14-19     Reserved
- *20-23     Jumpers (interrupt)
- *24-27     Module revision
- *28-30     Reserved
- *31        EISA interrupt
- *
- * The device to slot mapping looks like:
- *
- * Slot     Device
- *  6       TULIP
- *  7       PCI on board slot 0
- *  8       none
- *  9       SCSI
- * 10       PCI-ISA bridge
- * 11       PCI on board slot 2
- * 12       PCI on board slot 1
- *   
- *
- * This two layered interrupt approach means that we allocate IRQ 16 and 
- * above for PCI interrupts.  The IRQ relates to which bit the interrupt
- * comes in on.  This makes interrupt processing much easier.
- */
-static inline void xlt_fixup(void)
-{
-       static char irq_tab[7][5] __initlocaldata = {
-               /*INT    INTA   INTB   INTC   INTD */
-               {16+13, 16+13, 16+13, 16+13, 16+13},    /* IdSel 17,  TULIP  */
-               { 16+8,  16+8,  16+9, 16+10, 16+11},    /* IdSel 18,  slot 0 */
-               {   -1,    -1,    -1,    -1,    -1},    /* IdSel 19,  none   */
-               {16+12, 16+12, 16+12, 16+12, 16+12},    /* IdSel 20,  SCSI   */
-               {   -1,    -1,    -1,    -1,    -1},    /* IdSel 21,  SIO    */
-               { 16+0,  16+0,  16+1,  16+2,  16+3},    /* IdSel 22,  slot 2 */
-               { 16+4,  16+4,  16+5,  16+6,  16+7},    /* IdSel 23,  slot 1 */
-       };
        common_fixup(6, 12, 5, irq_tab, 0);
 }
 
@@ -1262,8+1412,6 @@ static inline void xlt_fixup(void)
  * with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables
  * in irq.c
  */
-
-#ifdef CONFIG_ALPHA_SABLE
 static inline void sable_fixup(void)
 {
         static char irq_tab[9][5] __initlocaldata = {
@@ -1280,7+1428,6 @@ static inline void sable_fixup(void)
         };
         common_fixup(0, 8, 5, irq_tab, 0);
 }
-#endif
 
 /*
  * Fixup configuration for MIATA (EV56+PYXIS)
@@ -1362,7+1509,8 @@ static inline void miata_fixup(void)
                {   -1,    -1,    -1,    -1,    -1},  /* IdSel 21,  none    */
                {16+12, 16+12, 16+13, 16+14, 16+15},  /* IdSel 22,  slot 4 */
                {16+16, 16+16, 16+17, 16+18, 16+19},  /* IdSel 23,  slot 5 */
-               /* The following are actually on bus 1, across the bridge */
+               /* The following are actually on bus 1, which is */
+               /* across the builtin PCI-PCI bridge */
                {16+20, 16+20, 16+21, 16+22, 16+23},  /* IdSel 24,  slot 1 */
                {16+24, 16+24, 16+25, 16+26, 16+27},  /* IdSel 25,  slot 2 */
                {16+28, 16+28, 16+29, 16+30, 16+31},  /* IdSel 26,  slot 3 */
@@ -1373,6+1521,7 @@ static inline void miata_fixup(void)
                {   -1,    -1,    -1,    -1,    -1},  /* IdSel 31,  PCI-PCI */
         };
        common_fixup(3, 20, 5, irq_tab, 0);
+       SMC669_Init(); /* it might be a GL (fails harmlessly if not) */
        es1888_init();
 }
 #endif
@@ -1399,7+1548,6 @@ static inline void miata_fixup(void)
  *14        Interrupt Line B from slot 1
  *15        Interrupt line B from slot 0
  *16        Interrupt Line C from slot 3
-
  *17        Interrupt Line C from slot 2
  *18        Interrupt Line C from slot 1
  *19        Interrupt Line C from slot 0
@@ -1417,7+1565,6 @@ static inline void miata_fixup(void)
  * 
  */
 
-#ifdef CONFIG_ALPHA_SX164
 static inline void sx164_fixup(void)
 {
        static char irq_tab[5][5] __initlocaldata = {
@@ -1428,12+1575,154 @@ static inline void sx164_fixup(void)
                {    -1,    -1,    -1,    -1,    -1}, /* IdSel 8 SIO        */
                { 16+ 8, 16+ 8, 16+12, 16+16, 16+20}  /* IdSel 9 slot 3 J15 */
        };
-
        common_fixup(5, 9, 5, irq_tab, 0);
+       SMC669_Init();
+}
+
+/*
+ * Fixup configuration for DP264 (EV6+TSUNAMI)
+ *
+ * Summary @ TSUNAMI_CSR_DIM0:
+ * Bit      Meaning
+ * 0-17     Unused
+ *18        Interrupt SCSI B (Adaptec 7895 builtin)
+ *19        Interrupt SCSI A (Adaptec 7895 builtin)
+ *20        Interrupt Line D from slot 2 PCI0
+ *21        Interrupt Line C from slot 2 PCI0
+ *22        Interrupt Line B from slot 2 PCI0
+ *23        Interrupt Line A from slot 2 PCI0
+ *24        Interrupt Line D from slot 1 PCI0
+ *25        Interrupt Line C from slot 1 PCI0
+ *26        Interrupt Line B from slot 1 PCI0
+ *27        Interrupt Line A from slot 1 PCI0
+ *28        Interrupt Line D from slot 0 PCI0
+ *29        Interrupt Line C from slot 0 PCI0
+ *30        Interrupt Line B from slot 0 PCI0
+ *31        Interrupt Line A from slot 0 PCI0
+ *
+ *32        Interrupt Line D from slot 3 PCI1
+ *33        Interrupt Line C from slot 3 PCI1
+ *34        Interrupt Line B from slot 3 PCI1
+ *35        Interrupt Line A from slot 3 PCI1
+ *36        Interrupt Line D from slot 2 PCI1
+ *37        Interrupt Line C from slot 2 PCI1
+ *38        Interrupt Line B from slot 2 PCI1
+ *39        Interrupt Line A from slot 2 PCI1
+ *40        Interrupt Line D from slot 1 PCI1
+ *41        Interrupt Line C from slot 1 PCI1
+ *42        Interrupt Line B from slot 1 PCI1
+ *43        Interrupt Line A from slot 1 PCI1
+ *44        Interrupt Line D from slot 0 PCI1
+ *45        Interrupt Line C from slot 0 PCI1
+ *46        Interrupt Line B from slot 0 PCI1
+ *47        Interrupt Line A from slot 0 PCI1
+ *48-52     Unused
+ *53        PCI0 NMI (from Cypress)
+ *54        PCI0 SMI INT (from Cypress)
+ *55        PCI0 ISA Interrupt (from Cypress)
+ *56-60     Unused
+ *61        PCI1 Bus Error
+ *62        PCI0 Bus Error
+ *63        Reserved
+ *
+ * IdSel       
+ *   5  Cypress Bridge I/O
+ *   6  SCSI Adaptec builtin
+ *   7  64 bit PCI option slot 0
+ *   8  64 bit PCI option slot 1
+ *   9  64 bit PCI option slot 2
+ * 
+ */
 
+static inline void dp264_fixup(void)
+{
+       static char irq_tab[5][5] __initlocaldata = {
+          /*INT    INTA   INTB   INTC   INTD */
+         {    -1,    -1,    -1,    -1,    -1}, /* IdSel 5 ISA Bridge */
+         { 16+ 2, 16+ 2, 16+ 2, 16+ 2, 16+ 2}, /* IdSel 6 SCSI builtin */
+         { 16+15, 16+15, 16+14, 16+13, 16+12}, /* IdSel 7 slot 0 */
+         { 16+11, 16+11, 16+10, 16+ 9, 16+ 8}, /* IdSel 8 slot 1 */
+         { 16+ 7, 16+ 7, 16+ 6, 16+ 5, 16+ 4}  /* IdSel 9 slot 2 */
+       };
+       common_fixup(5, 9, 5, irq_tab, 0);
        SMC669_Init();
 }
-#endif
+
+/*
+ * Fixup configuration for RAWHIDE
+ *
+ * Summary @ MCPCIA_PCI0_INT_REQ:
+ * Bit      Meaning
+ *0         Interrupt Line A from slot 2 PCI0
+ *1         Interrupt Line B from slot 2 PCI0
+ *2         Interrupt Line C from slot 2 PCI0
+ *3         Interrupt Line D from slot 2 PCI0
+ *4         Interrupt Line A from slot 3 PCI0
+ *5         Interrupt Line B from slot 3 PCI0
+ *6         Interrupt Line C from slot 3 PCI0
+ *7         Interrupt Line D from slot 3 PCI0
+ *8         Interrupt Line A from slot 4 PCI0
+ *9         Interrupt Line B from slot 4 PCI0
+ *10        Interrupt Line C from slot 4 PCI0
+ *11        Interrupt Line D from slot 4 PCI0
+ *12        Interrupt Line A from slot 5 PCI0
+ *13        Interrupt Line B from slot 5 PCI0
+ *14        Interrupt Line C from slot 5 PCI0
+ *15        Interrupt Line D from slot 5 PCI0
+ *16        EISA interrupt (PCI 0) or SCSI interrupt (PCI 1)
+ *17-23     NA
+ *
+ * IdSel       
+ *   1  EISA bridge (PCI bus 0 only)
+ *   2          PCI option slot 2
+ *   3  PCI option slot 3
+ *   4   PCI option slot 4
+ *   5   PCI option slot 5
+ * 
+ */
+
+static inline void rawhide_fixup(void)
+{
+       static char irq_tab[5][5] __initlocaldata = {
+          /*INT    INTA   INTB   INTC   INTD */
+         { 16+16, 16+16, 16+16, 16+16, 16+16}, /* IdSel 1 SCSI PCI 1 only */
+         { 16+ 0, 16+ 0, 16+ 1, 16+ 2, 16+ 3}, /* IdSel 2 slot 2 */
+         { 16+ 4, 16+ 4, 16+ 5, 16+ 6, 16+ 7}, /* IdSel 3 slot 3 */
+         { 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 4 slot 4 */
+         { 16+12, 16+12, 16+13, 16+14, 16+15}  /* IdSel 5 slot 5 */
+       };
+       common_fixup(1, 5, 5, irq_tab, 0);
+}
+
+/*
+ * The Takara has PCI devices 1, 2, and 3 configured to slots 20,
+ * 19, and 18 respectively, in the default configuration. They can
+ * also be jumpered to slots 8, 7, and 6 respectively, which is fun
+ * because the SIO ISA bridge can also be slot 7. However, the SIO
+ * doesn't explicitly generate PCI-type interrupts, so we can
+ * assign it whatever the hell IRQ we like and it doesn't matter.
+ */
+static inline void takara_fixup(void)
+{
+       static char irq_tab[15][5] __initlocaldata = {
+           { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
+           { 16+2, 16+2, 16+2, 16+2, 16+2},   /* slot  7 == device 2 */
+           { 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot  8 == device 1 */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot  9 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 10 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 11 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 12 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 13 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 14 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 15 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 16 == nothing */
+           {   -1,   -1,   -1,   -1,   -1},   /* slot 17 == nothing */
+           { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot 18 == device 3 */
+           { 16+2, 16+2, 16+2, 16+2, 16+2},   /* slot 19 == device 2 */
+           { 16+1, 16+1, 16+1, 16+1, 16+1},   /* slot 20 == device 1 */
+       };
+       common_fixup(6, 20, 5, irq_tab, 0x26e);
+}
 
 /*
  * Fixup configuration for all boards that route the PCI interrupts
@@ -1462,6+1751,7 @@ static inline void sio_fixup(void)
         * driven at all).
         */
        static const char pirq_tab[][5] __initlocaldata = {
+             /*INT   A   B   C   D */
 #ifdef CONFIG_ALPHA_P2K
                { 0,  0, -1, -1, -1}, /* idsel  6 (53c810) */
                {-1, -1, -1, -1, -1}, /* idsel  7 (SIO: PCI/ISA bridge) */
@@ -1497,7+1787,7 @@ static inline void sio_fixup(void)
 
 #if defined(CONFIG_ALPHA_BOOK1)
         /* for the AlphaBook1, NCR810 SCSI is 14, PCMCIA controller is 15 */
-        const unsigned int route_tab = 0x0e0f0a0a;
+        const unsigned int new_route_tab = 0x0e0f0a0a;
 
 #elif defined(CONFIG_ALPHA_NONAME)
        /*
@@ -1510,16+1800,24 @@ static inline void sio_fixup(void)
         *  they are co-indicated when the platform type "Noname" is
         *  selected... :-(
         */
-       const unsigned int route_tab = 0x0b0a0f09;
+       const unsigned int new_route_tab = 0x0b0a0f09;
 #else
-       const unsigned int route_tab = 0x0b0a090f;
+       const unsigned int new_route_tab = 0x0b0a090f;
 #endif
-
-       unsigned int level_bits;
+        unsigned int route_tab, old_route_tab;
+       unsigned int level_bits, old_level_bits;
        unsigned char pin, slot;
        int pirq;
 
+        pcibios_read_config_dword(0, PCI_DEVFN(7, 0), 0x60, &old_route_tab);
+       DBG_DEVS(("sio_fixup: old pirq route table: 0x%08x\n",
+                  old_route_tab));
+#if PCI_MODIFY
+       route_tab = new_route_tab;
        pcibios_write_config_dword(0, PCI_DEVFN(7, 0), 0x60, route_tab);
+#else
+       route_tab = old_route_tab;
+#endif
 
        /*
         * Go through all devices, fixing up irqs as we see fit:
@@ -1576,20+1874,33 @@ static inline void sio_fixup(void)
                 * if it's a VGA, enable its BIOS ROM at C0000
                 */
                if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
-                       pcibios_write_config_dword(dev->bus->number,
+                       /* but if its a Cirrus 543x/544x DISABLE it, */
+                       /* since enabling ROM disables the memory... */
+                       if ((dev->vendor == PCI_VENDOR_ID_CIRRUS) &&
+                           (dev->device >= 0x00a0) &&
+                           (dev->device <= 0x00ac)) {
+                               pcibios_write_config_dword(
+                                       dev->bus->number,
+                                       dev->devfn,
+                                       PCI_ROM_ADDRESS,
+                                       0x00000000);
+                       } else {
+                               pcibios_write_config_dword(
+                                       dev->bus->number,
                                                   dev->devfn,
                                                   PCI_ROM_ADDRESS,
                                                   0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
                }
+               }
                if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
                        continue; /* for now, displays get no IRQ */
                }
 
                if (pirq < 0) {
-                       printk("bios32.sio_fixup: "
+                       DBG_DEVS(("bios32.sio_fixup: "
                               "weird, device %04x:%04x coming in on"
                               " slot %d has no irq line!!\n",
-                              dev->vendor, dev->device, slot);
+                              dev->vendor, dev->device, slot));
                        continue;
                }
 
@@ -1653,7+1964,12 @@ static inline void sio_fixup(void)
         *
         * Note: we at least preserve any level-set bits on AlphaBook1
         */
-       level_bits |= ((inb(0x4d0) | (inb(0x4d1) << 8)) & 0x71ff);
+       old_level_bits = inb(0x4d0) | (inb(0x4d1) << 8);
+       DBG_DEVS(("sio_fixup: old irq level bits: 0x%04x\n",
+                  old_level_bits));
+       level_bits |= (old_level_bits & 0x71ff);
+       DBG_DEVS(("sio_fixup: new irq level bits: 0x%04x\n",
+                  level_bits));
        outb((level_bits >> 0) & 0xff, 0x4d0);
        outb((level_bits >> 8) & 0xff, 0x4d1);
 
@@ -1688,11+2004,35 @@ extern void tga_console_init(void);
 unsigned long __init
 pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
 {
+         struct pci_bus *cur;
+
+#ifdef CONFIG_ALPHA_MCPCIA
+       /* must do massive setup for multiple PCI busses here... */
+       DBG_DEVS(("pcibios_fixup: calling mcpcia_fixup()...\n"));
+       mem_start = mcpcia_fixup(mem_start, mem_end);
+#endif /* MCPCIA */
+
+#ifdef CONFIG_ALPHA_TSUNAMI
+       /* must do massive setup for multiple PCI busses here... */
+       /*      mem_start = tsunami_fixup(mem_start, mem_end); */
+#endif /* TSUNAMI */
+
 #if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN)
        /*
         * Scan the tree, allocating PCI memory and I/O space.
         */
-       layout_bus(&pci_root);
+       /*
+        * Sigh; check_region() will need changing to accept a HANDLE,
+        * if we allocate I/O space addresses on a per-bus basis.
+        * For now, make the I/O bases unique across all busses, so
+        * that check_region() will not get confused... ;-}
+        */
+       io_base = DEFAULT_IO_BASE;
+       for (cur = &pci_root; cur; cur = cur->next) {
+               mem_base = DEFAULT_MEM_BASE;
+               DBG_DEVS(("pcibios_fixup: calling layout_bus()\n"));
+               layout_bus(cur);
+       }
 #endif
        
        /*
@@ -1713,10+2053,8 @@ pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
        eb66_and_eb64p_fixup();
 #elif defined(CONFIG_ALPHA_MIKASA)
        mikasa_fixup();
-#elif defined(CONFIG_ALPHA_ALCOR)
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
        alcor_fixup();
-#elif defined(CONFIG_ALPHA_XLT)
-       xlt_fixup();
 #elif defined(CONFIG_ALPHA_SABLE)
        sable_fixup();
 #elif defined(CONFIG_ALPHA_MIATA)
@@ -1725,6+2063,12 @@ pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
        noritake_fixup();
 #elif defined(CONFIG_ALPHA_SX164)
        sx164_fixup();
+#elif defined(CONFIG_ALPHA_DP264)
+       dp264_fixup();
+#elif defined(CONFIG_ALPHA_RAWHIDE)
+       rawhide_fixup();
+#elif defined(CONFIG_ALPHA_TAKARA)
+       takara_fixup();
 #elif defined(CONFIG_ALPHA_RUFFIAN)
        /* no fixup needed */
 #else
@@ -1831,6+2175,33 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
        return err;
 }
 
+#if (defined(CONFIG_ALPHA_PC164) || \
+     defined(CONFIG_ALPHA_LX164) || \
+     defined(CONFIG_ALPHA_SX164) || \
+     defined(CONFIG_ALPHA_EB164) || \
+     defined(CONFIG_ALPHA_EB66P) || \
+     defined(CONFIG_ALPHA_CABRIOLET)) && defined(CONFIG_ALPHA_SRM)
+
+/*
+  on the above machines, under SRM console, we must use the CSERVE PALcode
+  routine to manage the interrupt mask for us, otherwise, the kernel/HW get
+  out of sync with what the PALcode thinks it needs to deliver/ignore
+ */
+void
+cserve_update_hw(unsigned long irq, unsigned long mask)
+{
+    extern void cserve_ena(unsigned long);
+    extern void cserve_dis(unsigned long);
+
+    if (mask & (1UL << irq))
+       /* disable */
+       cserve_dis(irq - 16);
+    else
+      /* enable */
+       cserve_ena(irq - 16);
+    return;
+}
+#endif /* (PC164 || LX164 || SX164 || EB164 || CABRIO) && SRM */
 
 #ifdef CONFIG_ALPHA_MIATA
 /*
@@ -1877,4+2248,44 @@ es1888_init(void)
 }
 #endif /* CONFIG_ALPHA_MIATA */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+void reset_for_srm(void)
+{
+       extern void scrreset(void);
+       struct pci_dev *dev;
+       int i;
+
+       /* reset any IRQs that we changed */
+       for (i = 0; i < irq_reset_count; i++) {
+           dev = irq_dev_to_reset[i];
+
+           pcibios_write_config_byte(dev->bus->number, dev->devfn,
+                                     PCI_INTERRUPT_LINE, irq_to_reset[i]);
+#if 1
+           printk("reset_for_srm: bus %d slot 0x%x "
+                  "SRM IRQ 0x%x changed back from 0x%x\n",
+                  dev->bus->number, PCI_SLOT(dev->devfn),
+                  irq_to_reset[i], dev->irq);
+#endif
+       }
+
+       /* reset any IO addresses that we changed */
+       for (i = 0; i < io_reset_count; i++) {
+           dev = io_dev_to_reset[i];
+
+           pcibios_write_config_byte(dev->bus->number, dev->devfn,
+                                     io_reg_to_reset[i], io_to_reset[i]);
+#if 1
+           printk("reset_for_srm: bus %d slot 0x%x "
+                  "SRM IO restored to 0x%x\n",
+                  dev->bus->number, PCI_SLOT(dev->devfn),
+                  io_to_reset[i]);
+#endif
+}
+
+       /* reset the visible screen to the top of display memory */
+       scrreset();
+}
+#endif /* CONFIG_ALPHA_SRM_SETUP */
+
 #endif /* CONFIG_PCI */
index 4bebe27..c895361 100644 (file)
@@ -6,6+6,7 @@
  *
  */
 #include <linux/kernel.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <asm/ptrace.h>
 #include <asm/mmu_context.h>
 
-/* NOTE: Herein are back-to-back mb insns.  They are magic.
-   A plausible explanation is that the i/o controler does not properly
-   handle the system transaction.  Another involves timing.  Ho hum.  */
+/*
+ * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
+ * One plausible explanation is that the i/o controller does not properly
+ * handle the system transaction.  Another involves timing.  Ho hum.
+ */
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern int alpha_sys_type;
 
 /*
  * Machine check reasons.  Defined according to PALcode sources
@@ -56,13+58,17 @@ extern int alpha_sys_type;
 # define DBGC(args)
 #endif
 
-#define vulp   volatile unsigned long *
 #define vuip   volatile unsigned int  *
 
 static volatile unsigned int CIA_mcheck_expected = 0;
 static volatile unsigned int CIA_mcheck_taken = 0;
 static unsigned int CIA_jd;
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int CIA_DMA_WIN_BASE = CIA_DMA_WIN_BASE_DEFAULT;
+unsigned int CIA_DMA_WIN_SIZE = CIA_DMA_WIN_SIZE_DEFAULT;
+unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -271,7+277,7 @@ static void conf_write(unsigned long addr, unsigned int value,
                }
 
                /* reset error status: */
-               *(vulp)CIA_IOC_CIA_ERR = stat0;
+               *(vuip)CIA_IOC_CIA_ERR = stat0;
                mb();
                wrmces(0x7);                    /* reset machine check */
                value = 0xffffffff;
@@ -442,6+448,18 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
                printk("CIA_init: CIA_STAT was 0x%x\n", temp);
                temp = *(vuip)CIA_IOC_MCR; mb();
                printk("CIA_init: CIA_MCR was 0x%x\n", temp);
+               temp = *(vuip)CIA_IOC_CIA_CTRL; mb();
+               printk("CIA_init: CIA_CTRL was 0x%x\n", temp);
+               temp = *(vuip)CIA_IOC_ERR_MASK; mb();
+               printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp);
+               temp = *((vuip)CIA_IOC_PCI_W0_BASE); mb();
+               printk("CIA_init: W0_BASE was 0x%x\n", temp);
+               temp = *((vuip)CIA_IOC_PCI_W1_BASE); mb();
+               printk("CIA_init: W1_BASE was 0x%x\n", temp);
+               temp = *((vuip)CIA_IOC_PCI_W2_BASE); mb();
+               printk("CIA_init: W2_BASE was 0x%x\n", temp);
+               temp = *((vuip)CIA_IOC_PCI_W3_BASE); mb();
+               printk("CIA_init: W3_BASE was 0x%x\n", temp);
        }
 #endif /* DEBUG_DUMP_REGS */
 
@@ -458,6+476,70 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)CIA_IOC_CIA_CTRL = cia_tmp;
        mb();
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W0_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T0_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W0_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W0_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 0 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W0_BASE,
+                *(vuip)CIA_IOC_PCI_W0_MASK,
+                *(vuip)CIA_IOC_PCI_T0_BASE);
+#endif
+       }
+       else  /* check window 1 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W1_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T1_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W1_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W1_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 1 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W1_BASE,
+                *(vuip)CIA_IOC_PCI_W1_MASK,
+                *(vuip)CIA_IOC_PCI_T1_BASE);
+#endif
+       }
+       else  /* check window 2 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W2_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T2_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W2_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W2_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 2 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W2_BASE,
+                *(vuip)CIA_IOC_PCI_W2_MASK,
+                *(vuip)CIA_IOC_PCI_T2_BASE);
+#endif
+       }
+       else  /* check window 3 for enabled and mapped to 0 */
+       if (((*(vuip)CIA_IOC_PCI_W3_BASE & 3) == 1) &&
+           (*(vuip)CIA_IOC_PCI_T3_BASE == 0))
+       {
+         CIA_DMA_WIN_BASE = *(vuip)CIA_IOC_PCI_W3_BASE & 0xfff00000U;
+         CIA_DMA_WIN_SIZE = *(vuip)CIA_IOC_PCI_W3_MASK & 0xfff00000U;
+         CIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("cia_init: using Window 3 settings\n");
+         printk("cia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)CIA_IOC_PCI_W3_BASE,
+                *(vuip)CIA_IOC_PCI_W3_MASK,
+                *(vuip)CIA_IOC_PCI_T3_BASE);
+#endif
+       }
+       else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+       {
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, windows 1,2 and 3 are disabled.  In the future, we may
@@ -472,6+554,7 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)CIA_IOC_PCI_W1_BASE = 0x0;
        *(vuip)CIA_IOC_PCI_W2_BASE = 0x0;
        *(vuip)CIA_IOC_PCI_W3_BASE = 0x0;
+       }
 
        /*
         * check ASN in HWRPB for validity, report if bad
@@ -483,28+566,54 @@ unsigned long cia_init(unsigned long mem_start, unsigned long mem_end)
        }
 
         /*
-         * Finally, clear the CIA_CFG register, which gets used
+         * Next, clear the CIA_CFG register, which gets used
          *  for PCI Config Space accesses. That is the way
          *  we want to use it, and we do not want to depend on
          *  what ARC or SRM might have left behind...
          */
         {
-#if 0
-               unsigned int cia_cfg = *(vuip)CIA_IOC_CFG; mb();
-               if (cia_cfg) printk("CIA_init: CFG was 0x%x\n", cia_cfg);
-#endif
-               *(vuip)CIA_IOC_CFG = 0; mb();
+          unsigned int cia_cfg = *((vuip)CIA_IOC_CFG); mb();
+          if (cia_cfg) {
+             printk("CIA_init: CFG was 0x%x\n", cia_cfg);
+             *((vuip)CIA_IOC_CFG) = 0; mb();
+         }
         }
  
-#if 0
        {
-               unsigned int temp;
-               temp = *(vuip)CIA_IOC_CIA_CTRL; mb();
-               printk("CIA_init: CIA_CTRL was 0x%x\n", temp);
-               temp = *(vuip)CIA_IOC_ERR_MASK; mb();
-               printk("CIA_init: CIA_ERR_MASK was 0x%x\n", temp);
-       }
+          unsigned int cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM);
+          unsigned int cia_hae_io = *((vuip)CIA_IOC_HAE_IO);
+#if 0
+         printk("CIA_init: HAE_MEM was 0x%x\n", cia_hae_mem);
+         printk("CIA_init: HAE_IO was 0x%x\n", cia_hae_io);
 #endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+         /*
+           sigh... For the SRM setup, unless we know apriori what the HAE
+           contents will be, we need to setup the arbitrary region bases
+           so we can test against the range of addresses and tailor the
+           region chosen for the SPARSE memory access.
+
+           see include/asm-alpha/cia.h for the SPARSE mem read/write
+         */
+         cia_sm_base_r1 = (cia_hae_mem      ) & 0xe0000000UL; /* region 1 */
+         cia_sm_base_r2 = (cia_hae_mem << 16) & 0xf8000000UL; /* region 2 */
+         cia_sm_base_r3 = (cia_hae_mem << 24) & 0xfc000000UL; /* region 3 */
+
+         /*
+           Set the HAE cache, so that setup_arch() code
+           will use the SRM setting always. Our readb/writeb
+           code in cia.h expects never to have to change
+           the contents of the HAE.
+          */
+         hae.cache = cia_hae_mem;
+#else /* SRM_SETUP */
+         *((vuip)CIA_IOC_HAE_MEM) = 0; mb();
+         cia_hae_mem = *((vuip)CIA_IOC_HAE_MEM);
+         *((vuip)CIA_IOC_HAE_IO) = 0; mb();
+         cia_hae_io = *((vuip)CIA_IOC_HAE_IO);
+#endif /* SRM_SETUP */
+        }
        return mem_start;
 }
 
@@ -512,7+621,7 @@ int cia_pci_clr_err(void)
 {
        CIA_jd = *(vuip)CIA_IOC_CIA_ERR;
        DBGM(("CIA_pci_clr_err: CIA ERR after read 0x%x\n", CIA_jd));
-       *(vulp)CIA_IOC_CIA_ERR = 0x0180;
+       *(vuip)CIA_IOC_CIA_ERR = 0x0180;
        mb();
        return 0;
 }
index b139d51..0bbc719 100644 (file)
@@ -4,6+4,7 @@
  * kernel entry-points
  */
 
+#include <linux/config.h>
 #include <asm/system.h>
 
 #define halt   .long PAL_halt
  * JRP - Save regs 16-18 in a special area of the stack, so that
  * the palcode-provided values are available to the signal handler.
  */
+#if defined(CONFIG_ALPHA_TSUNAMI)
+/* TSUNAMI has no HAE register to save/restore */
 #define SAVE_ALL                       \
        subq    $30,184,$30;            \
        stq     $0,0($30);              \
        stq     $2,16($30);             \
        stq     $3,24($30);             \
        stq     $4,32($30);             \
+       stq     $5,40($30);             \
+       stq     $6,48($30);             \
+       stq     $7,56($30);             \
+       stq     $8,64($30);             \
+       stq     $19,72($30);            \
+       stq     $20,80($30);            \
+       stq     $21,88($30);            \
+       stq     $22,96($30);            \
+       stq     $23,104($30);           \
+       stq     $24,112($30);           \
+       stq     $25,120($30);           \
+       stq     $26,128($30);           \
+       stq     $27,136($30);           \
+       stq     $28,144($30);           \
+       stq     $16,160($30);           \
+       stq     $17,168($30);           \
+       stq     $18,176($30)
+
+#define RESTORE_ALL                    \
+       ldq     $0,0($30);              \
+       ldq     $1,8($30);              \
+       ldq     $2,16($30);             \
+       ldq     $3,24($30);             \
+       ldq     $4,32($30);             \
+       ldq     $5,40($30);             \
+       ldq     $6,48($30);             \
+       ldq     $7,56($30);             \
+       ldq     $8,64($30);             \
+       ldq     $19,72($30);            \
+       ldq     $20,80($30);            \
+       ldq     $21,88($30);            \
+       ldq     $22,96($30);            \
+       ldq     $23,104($30);           \
+       ldq     $24,112($30);           \
+       ldq     $25,120($30);           \
+       ldq     $26,128($30);           \
+       ldq     $27,136($30);           \
+       ldq     $28,144($30);           \
+       addq    $30,184,$30
+
+#else /* TSUNAMI */
+#define SAVE_ALL                       \
+       subq    $30,184,$30;            \
+       stq     $0,0($30);              \
+       stq     $1,8($30);              \
+       stq     $2,16($30);             \
+       stq     $3,24($30);             \
+       stq     $4,32($30);             \
+       stq     $28,144($30);           \
        lda     $2,hae;                 \
        stq     $5,40($30);             \
        stq     $6,48($30);             \
        stq     $25,120($30);           \
        stq     $26,128($30);           \
        stq     $27,136($30);           \
-       stq     $28,144($30);           \
        stq     $2,152($30);            \
        stq     $16,160($30);           \
        stq     $17,168($30);           \
        ldq     $28,144($30);           \
        addq    $30,184,$30
 
+#endif /* TSUNAMI */
+
 .text
 .set noat
 #if defined(__linux__) && !defined(__ELF__)
@@ -508,6+561,8 @@ sys_clone:
 alpha_switch_to:
        bsr $1,do_switch_stack
        call_pal PAL_swpctx
+       lda $16,-2($31)
+       call_pal PAL_tbi
        bsr $1,undo_switch_stack
        ret $31,($26),1
 .end alpha_switch_to
@@ -681,6+736,19 @@ signal_return:
        br      $31,restore_all
 .end entSys
 
+#ifdef __SMP__
+        .globl  ret_from_smpfork
+.align 3
+.ent ret_from_smpfork
+ret_from_smpfork:
+       .set at
+       stq     $31,scheduler_lock      
+       mb      /* ?????????????????? */
+       br      ret_from_sys_call
+       .set noat
+.end ret_from_smpfork
+#endif /* __SMP__ */
+
 .align 3
 .ent reschedule
 reschedule:
index 4a3ec9e..f7baa07 100644 (file)
@@ -8,6+8,7 @@
  */
 
 #define __ASSEMBLY__
+#include <linux/config.h>
 #include <asm/system.h>
 
 #define halt call_pal PAL_halt
@@ -32,6+33,27 @@ __start:
        halt
        .end __start
 
+#ifdef __SMP__
+       .align 3
+       .globl  __start_cpu
+       .ent    __start_cpu
+       /* on entry here from SRM console, the HWPCB of this processor */
+       /* has been loaded, and $27 contains the task pointer */
+__start_cpu:
+       /* first order of business, load the GP */
+       br      $26,1f
+1:     ldgp    $29,0($26)
+       /* We need to get current loaded up with our first task...  */
+       lda     $8,0($27)
+       /* set FEN */
+       lda     $16,1($31)
+       call_pal PAL_wrfen
+       /* ... and then we can start the processor.  */
+       jsr     $26,start_secondary
+       halt
+       .end __start_cpu
+#endif /* __SMP__ */
+
        .align 3
        .globl  wrent
        .ent    wrent
index 41d5d5f..bcac2da 100644 (file)
 #define vulp   volatile unsigned long *
 #define vuip   volatile unsigned int *
 
+extern void timer_interrupt(struct pt_regs * regs);
+extern void cserve_update_hw(unsigned long, unsigned long);
+extern void handle_ipi(struct pt_regs *);
+
 #define RTC_IRQ    8
 #ifdef CONFIG_RTC
 #define TIMER_IRQ  0        /* timer is the pit */
 #if defined(CONFIG_ALPHA_P2K)
   /* always mask out unused timer irq 0 and RTC irq 8 */
 # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0x101UL)
-#elif defined(CONFIG_ALPHA_ALCOR)
+#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
   /* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */
 # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL)
 #elif defined(CONFIG_ALPHA_RUFFIAN)
   /* must leave timer irq 0 in the mask */
 # define PROBE_MASK ((1UL << NR_IRQS) - 1)
+#elif NR_IRQS == 64
+  /* always mask out unused timer irq 0: */
+# define PROBE_MASK (~1UL)
 #else
   /* always mask out unused timer irq 0: */
 # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL)
@@ -119,7+126,7 @@ sable_update_hw(unsigned long irq, unsigned long mask)
 {
        /* The "irq" argument is really the mask bit number */
        switch (irq) {
-       default: /* 16 ... 23 */
+       case 16 ... 23:
                outb(mask >> 16, 0x53d);
                break;
        case 8 ... 15:
@@ -135,7+142,7 @@ static inline void
 noritake_update_hw(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
-       default: /* 32 ... 47 */
+       case 32 ... 47:
                outw(~(mask >> 32), 0x54c);
                break;
        case 16 ... 31:
@@ -155,7+162,7 @@ static inline void
 miata_update_hw(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
-       default: /* 16 ... 47 */
+       case 16 ... 47:
                /* Make CERTAIN none of the bogus ints get enabled... */
                *(vulp)PYXIS_INT_MASK =
                        ~((long)mask >> 16) & ~0x4000000000000e3bUL;
@@ -178,7+185,7 @@ static inline void
 alcor_and_xlt_update_hw(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
-       default: /* 16 ... 47 */
+       case 16 ... 47:
                /* On Alcor, at least, lines 20..30 are not connected and can
                   generate spurrious interrupts if we turn them on while IRQ
                   probing.  So explicitly mask them out. */
@@ -202,7+209,7 @@ static inline void
 mikasa_update_hw(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
-       default: /* 16 ... 31 */
+       case 16 ... 31:
                outw(~(mask >> 16), 0x536); /* note invert */
                break;
        case  8 ... 15: /* ISA PIC2 */
@@ -214,7+221,7 @@ mikasa_update_hw(unsigned long irq, unsigned long mask)
        }
 }
 
-#ifdef CONFIG_ALPHA_RUFFIAN
+#if defined(CONFIG_ALPHA_RUFFIAN)
 static inline void
 ruffian_update_hw(unsigned long irq, unsigned long mask)
 {
@@ -223,8+230,7 @@ ruffian_update_hw(unsigned long irq, unsigned long mask)
                /* Note inverted sense of mask bits: */
                /* Make CERTAIN none of the bogus ints get enabled... */
                *(vulp)PYXIS_INT_MASK =
-                       ~((long)mask >> 16) & 0x00000000ffffffbfUL;
-               mb();
+                     ~((long)mask >> 16) & 0x00000000ffffffbfUL; mb();
                /* ... and read it back to make sure it got written.  */
                *(vulp)PYXIS_INT_MASK;
                break;
@@ -236,20+242,23 @@ ruffian_update_hw(unsigned long irq, unsigned long mask)
                break;
        }
 }
-#endif
+#endif /* RUFFIAN */
 
-#ifdef CONFIG_ALPHA_SX164
+#if defined(CONFIG_ALPHA_SX164)
 static inline void
 sx164_update_hw(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
        case 16 ... 39:
-               /* Make CERTAIN none of the bogus ints get enabled */
+#if defined(CONFIG_ALPHA_SRM)
+               cserve_update_hw(irq, mask);
+#else
+               /* make CERTAIN none of the bogus ints get enabled */
                *(vulp)PYXIS_INT_MASK =
-                       ~((long)mask >> 16) & ~0x000000000000003bUL;
-               mb();
+                   ~((long)mask >> 16) & ~0x000000000000003bUL; mb();
                /* ... and read it back to make sure it got written.  */
                *(vulp)PYXIS_INT_MASK;
+#endif /* SRM */
                break;
        case  8 ... 15: /* ISA PIC2 */
                outb(mask >> 8, 0xA1);
@@ -258,20+267,23 @@ sx164_update_hw(unsigned long irq, unsigned long mask)
                outb(mask, 0x21);
                break;
        }
-}
-#endif
 
-/* Unlabeled mechanisms based on the number of irqs.  Someone should
-   probably document and name these.  */
+}
+#endif /* SX164 */
 
+#if defined(CONFIG_ALPHA_DP264)
 static inline void
-update_hw_33(unsigned long irq, unsigned long mask)
+dp264_update_hw(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
-       default: /* 16 ... 32 */
-               outl(mask >> 16, 0x804);
+       case 16 ... 63:
+               /* make CERTAIN none of the bogus ints get enabled */
+               /* HACK ALERT! only CPU#0 is used currently */
+               *(vulp)TSUNAMI_CSR_DIM0 =
+                   ~(mask) & ~0x0000000000000000UL; mb();
+               /* ... and read it back to make sure it got written.  */
+               *(vulp)TSUNAMI_CSR_DIM0;
                break;
-
        case  8 ... 15: /* ISA PIC2 */
                outb(mask >> 8, 0xA1);
                break;
@@ -280,16+292,24 @@ update_hw_33(unsigned long irq, unsigned long mask)
                break;
        }
 }
+#endif /* DP264 */
 
+#if defined(CONFIG_ALPHA_RAWHIDE)
 static inline void
-update_hw_32(unsigned long irq, unsigned long mask)
+rawhide_update_hw(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
-       default: /* 24 ... 31 */
-               outb(mask >> 24, 0x27);
+       case 16 ... 39: /* PCI bus 0 with EISA bridge */
+               *(vuip)MCPCIA_INT_MASK0(0) =
+                   (~((mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb();
+               /* ... and read it back to make sure it got written.  */
+               *(vuip)MCPCIA_INT_MASK0(0);
                break;
-       case 16 ... 23:
-               outb(mask >> 16, 0x26);
+       case 40 ... 63: /* PCI bus 1 with builtin NCR810 SCSI */
+               *(vuip)MCPCIA_INT_MASK0(1) =
+                   (~((mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb();
+               /* ... and read it back to make sure it got written.  */
+               *(vuip)MCPCIA_INT_MASK0(1);
                break;
        case  8 ... 15: /* ISA PIC2 */
                outb(mask >> 8, 0xA1);
@@ -299,12+319,29 @@ update_hw_32(unsigned long irq, unsigned long mask)
                break;
        }
 }
+#endif /* RAWHIDE */
 
+/*
+ * HW update code for the following platforms:
+ *
+ *     CABRIOLET (AlphaPC64)
+ *     EB66P
+ *     EB164
+ *     PC164
+ *     LX164
+ */
 static inline void
-update_hw_16(unsigned long irq, unsigned long mask)
+update_hw_35(unsigned long irq, unsigned long mask)
 {
        switch (irq) {
-       default: /* 8 ... 15, ISA PIC2 */
+       case 16 ... 34:
+#if defined(CONFIG_ALPHA_SRM)
+               cserve_update_hw(irq, mask);
+#else /* SRM */
+               outl(irq_mask >> 16, 0x804);
+#endif /* SRM */
+               break;
+       case  8 ... 15: /* ISA PIC2 */
                outb(mask >> 8, 0xA1);
                break;
        case  0 ... 7: /* ISA PIC1 */
@@ -313,42+350,38 @@ update_hw_16(unsigned long irq, unsigned long mask)
        }
 }
 
-#if (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \
-       && defined(CONFIG_ALPHA_SRM)
-/*
- * On the pc164, we cannot take over the IRQs from the SRM, 
- * so we call down to do our dirty work.  Too bad the SRM
- * isn't consistent across platforms otherwise we could do
- * this always.
- */
-
-extern void cserve_ena(unsigned long);
-extern void cserve_dis(unsigned long);
-
-static inline void mask_irq(unsigned long irq)
+static inline void
+update_hw_32(unsigned long irq, unsigned long mask)
 {
-       irq_mask |= (1UL << irq);
-       cserve_dis(irq - 16);
+       switch (irq) {
+       case 24 ... 31:
+               outb(mask >> 24, 0x27);
+               break;
+       case 16 ... 23:
+               outb(mask >> 16, 0x26);
+               break;
+       case  8 ... 15: /* ISA PIC2 */
+               outb(mask >> 8, 0xA1);
+               break;
+       case  0 ... 7:  /* ISA PIC1 */
+               outb(mask, 0x21);
+               break;
 }
-
-static inline void unmask_irq(unsigned long irq)
-{
-       irq_mask &= ~(1UL << irq);
-       cserve_ena(irq - 16);
 }
 
-/* Since we are calling down to PALcode, no need to diddle IPL.  */
-void disable_irq(unsigned int irq_nr)
+static inline void
+update_hw_16(unsigned long irq, unsigned long mask)
 {
-       mask_irq(IRQ_TO_MASK(irq_nr));
+       switch (irq) {
+       case 8 ... 15: /* ISA PIC2 */
+               outb(mask >> 8, 0xA1);
+               break;
+       case  0 ... 7: /* ISA PIC1 */
+               outb(mask, 0x21);
+               break;
 }
-
-void enable_irq(unsigned int irq_nr)
-{
-       unmask_irq(IRQ_TO_MASK(irq_nr));
 }
 
-#else
 /*
  * We manipulate the hardware ourselves.
  */
@@ -369,9+402,18 @@ static void update_hw(unsigned long irq, unsigned long mask)
        sx164_update_hw(irq, mask);
 #elif defined(CONFIG_ALPHA_RUFFIAN)
        ruffian_update_hw(irq, mask);
-#elif NR_IRQS == 33
-       update_hw_33(irq, mask);
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_DP264)
+       dp264_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_RAWHIDE)
+       rawhide_update_hw(irq, mask);
+#elif defined(CONFIG_ALPHA_CABRIOLET) || \
+      defined(CONFIG_ALPHA_EB66P)     || \
+      defined(CONFIG_ALPHA_EB164)     || \
+      defined(CONFIG_ALPHA_PC164)     || \
+      defined(CONFIG_ALPHA_LX164)
+       update_hw_35(irq, mask);
+#elif defined(CONFIG_ALPHA_EB66) || \
+      defined(CONFIG_ALPHA_EB64P)
        update_hw_32(irq, mask);
 #elif NR_IRQS == 16
        update_hw_16(irq, mask);
@@ -396,8+438,7 @@ void disable_irq(unsigned int irq_nr)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        mask_irq(IRQ_TO_MASK(irq_nr));
        restore_flags(flags);
 }
@@ -406,12+447,10 @@ void enable_irq(unsigned int irq_nr)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        unmask_irq(IRQ_TO_MASK(irq_nr));
        restore_flags(flags);
 }
-#endif /* (PC164 || LX164) && SRM */
 
 /*
  * Initial irq handlers.
@@ -423,13+462,14 @@ int get_irq_list(char *buf)
 {
        int i, len = 0;
        struct irqaction * action;
+       int cpu = smp_processor_id();
 
        for (i = 0; i < NR_IRQS; i++) {
                action = irq_action[i];
                if (!action) 
                        continue;
                len += sprintf(buf+len, "%2d: %10u %c %s",
-                              i, kstat.irqs[0][i],
+                              i, kstat.irqs[cpu][i],
                               (action->flags & SA_INTERRUPT) ? '+' : ' ',
                               action->name);
                for (action=action->next; action; action = action->next) {
@@ -463,16+503,18 @@ static inline void ack_irq(int irq)
 #elif defined(CONFIG_ALPHA_RUFFIAN)
        if (irq < 16) {
                /* Ack PYXIS ISA interrupt.  */
-               *(vulp)PYXIS_INT_REQ = 1 << 7;
-               mb();
+               *(vulp)PYXIS_INT_REQ = 1L << 7; mb();
+               /* ... and read it back to make sure it got written.  */
+               *(vulp)PYXIS_INT_REQ;
                if (irq > 7) {
                        outb(0x20, 0xa0);
                }
                outb(0x20, 0x20);
        } else {
-               /* Ack PYXIS interrupt.  */
+               /* Ack PYXIS PCI interrupt.  */
                *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16));
-               mb();
+               /* ... and read it back to make sure it got written.  */
+               *(vulp)PYXIS_INT_REQ;
        }
 #else
        if (irq < 16) {
@@ -488,7+530,7 @@ static inline void ack_irq(int irq)
                /* on ALCOR/XLT, need to dismiss interrupt via GRU */
                *(vuip)GRU_INT_CLEAR = 0x80000000; mb();
                *(vuip)GRU_INT_CLEAR = 0x00000000; mb();
-#endif
+#endif /* ALCOR || XLT */
        }
 #endif
 }
@@ -556,8+598,7 @@ int request_irq(unsigned int irq,
        action->next = NULL;
        action->dev_id = dev_id;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
        *p = action;
 
        if (!shared)
@@ -585,8+626,7 @@ void free_irq(unsigned int irq, void *dev_id)
                        continue;
 
                /* Found it - now free it */
-               save_flags(flags);
-               cli();
+               save_and_cli(flags);
                *p = action->next;
                if (!irq[irq_action])
                        mask_irq(IRQ_TO_MASK(irq));
@@ -607,7+647,277 @@ unsigned int local_irq_count[NR_CPUS];
 unsigned int local_bh_count[NR_CPUS];
 
 #ifdef __SMP__
-#error "Me no hablo Alpha SMP"
+/* 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;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+/* This protects BH software state (masks, things like that). */
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+atomic_t global_bh_count = ATOMIC_INIT(0);
+
+static unsigned long previous_irqholder = NO_PROC_ID;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#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, atomic_read(&global_irq_count)); 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];
+
+       /* Are we the only one in an interrupt context? */
+       while (local_count != atomic_read(&global_irq_count)) {
+               /*
+                * No such luck. Now we need to release the lock,
+                * _and_ release our interrupt context, because
+                * otherwise we'd have dead-locks and live-locks
+                * and other fun things.
+                */
+               atomic_sub(local_count, &global_irq_count);
+               spin_unlock(&global_irq_lock);
+
+               /*
+                * Wait for everybody else to go away and release
+                * their things before trying to get the lock again.
+                */
+               for (;;) {
+                       STUCK;
+                       if (atomic_read(&global_irq_count))
+                               continue;
+                       if (global_irq_lock.lock)
+                               continue;
+                       if (spin_trylock(&global_irq_lock))
+                               break;
+               }
+               atomic_add(local_count, &global_irq_count);
+       }
+}
+
+#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)) {
+               /* do we already hold the lock? */
+               if ((unsigned char) cpu == global_irq_holder) {
+#if 0
+                       printk("get_irqlock: already held at %08lx\n",
+                              previous_irqholder);
+#endif
+                       return;
+               }
+               /* Uhhuh.. Somebody else got it. Wait.. */
+               do {
+                       do {
+                               STUCK;
+                               barrier();
+                       } while (global_irq_lock.lock);
+               } while (!spin_trylock(&global_irq_lock));
+       }
+       /*
+        * Ok, we got the lock bit.
+        * But that's actually just the easy part.. Now
+        * we need to make sure that nobody else is running
+        * in an interrupt context. 
+        */
+       wait_on_irq(cpu, where);
+
+       /*
+        * Finally.
+        */
+       global_irq_holder = cpu;
+       previous_irqholder = where;
+}
+
+void __global_cli(void)
+{
+       int cpu = smp_processor_id();
+       unsigned long where;
+
+        __asm__("mov $26, %0" : "=r" (where));
+       __cli();
+
+       if (!local_irq_count[cpu])
+         get_irqlock(smp_processor_id(), where);
+}
+
+void __global_sti(void)
+{
+        int cpu = smp_processor_id();
+
+        if (!local_irq_count[cpu])
+         release_irqlock(smp_processor_id());
+
+       __sti();
+}
+
+#if 0
+unsigned long __global_save_flags(void)
+{
+       return global_irq_holder == (unsigned char) smp_processor_id();
+}
+#endif
+
+void __global_restore_flags(unsigned long flags)
+{
+       if (flags & 1) {
+               __global_cli();
+       } else {
+               /* release_irqlock() */
+               if (global_irq_holder == smp_processor_id()) {
+                       global_irq_holder = NO_PROC_ID;
+                       spin_unlock(&global_irq_lock);
+               }
+               if (!(flags & 2))
+                       __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;}
+
+#undef VERBOSE_IRQLOCK_DEBUGGING
+
+void irq_enter(int cpu, int irq)
+{
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+       extern void smp_show_backtrace_all_cpus(void);
+#endif
+       int stuck = INIT_STUCK;
+
+       hardirq_enter(cpu);
+       barrier();
+       while (global_irq_lock.lock) {
+               if ((unsigned char) cpu == global_irq_holder) {
+                       int globl_locked = global_irq_lock.lock;
+                       int globl_icount = atomic_read(&global_irq_count);
+                       int local_count = local_irq_count[cpu];
+
+                       /* It is very important that we load the state variables
+                        * before we do the first call to printk() as printk()
+                        * could end up changing them...
+                        */
+
+#if 0
+                       printk("CPU[%d]: BAD! Local IRQ's enabled,"
+                              " global disabled interrupt\n", cpu);
+#endif
+                       printk("CPU[%d]: where [%08lx] glocked[%d] gicnt[%d]"
+                              " licnt[%d]\n",
+                              cpu, previous_irqholder, globl_locked,
+                              globl_icount, local_count);
+#ifdef VERBOSE_IRQLOCK_DEBUGGING
+                       printk("Performing backtrace on all cpus,"
+                              " write this down!\n");
+                       smp_show_backtrace_all_cpus();
+#endif
+                       break;
+               }
+               STUCK;
+               barrier();
+       }
+}
+
+void irq_exit(int cpu, int irq)
+{
+       hardirq_exit(cpu);
+       release_irqlock(cpu);
+}
+
+static void show(char * str)
+{
+#if 0
+       int i;
+        unsigned long *stack;
+#endif
+        int cpu = smp_processor_id();
+
+        printk("\n%s, CPU %d:\n", str, cpu);
+        printk("irq:  %d [%d %d]\n",
+              atomic_read(&global_irq_count), local_irq_count[0],
+              local_irq_count[1]);
+        printk("bh:   %d [%d %d]\n",
+              atomic_read(&global_bh_count), local_bh_count[0],
+              local_bh_count[1]);
+#if 0
+        stack = (unsigned long *) &str;
+        for (i = 40; i ; i--) {
+               unsigned long x = *++stack;
+                if (x > (unsigned long) &init_task_union &&
+                   x < (unsigned long) &vsprintf) {
+                       printk("<[%08lx]> ", x);
+                }
+        }
+#endif
+}
+        
+#define MAXCOUNT 100000000
+
+static inline void wait_on_bh(void)
+{
+       int count = MAXCOUNT;
+        do {
+               if (!--count) {
+                       show("wait_on_bh");
+                        count = ~0;
+                }
+                /* nothing .. wait for the other bh's to go away */
+        } while (atomic_read(&global_bh_count) != 0);
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler.
+ */
+void synchronize_bh(void)
+{
+       if (atomic_read(&global_bh_count)) {
+               int cpu = smp_processor_id();
+                if (!local_irq_count[cpu] && !local_bh_count[cpu]) {
+                       wait_on_bh();
+               }
+        }
+}
+
+/* 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;
+
+               /* An infamously unpopular approach. */
+               save_and_cli(flags);
+               restore_flags(flags);
+       }
+}
+
 #else
 #define irq_enter(cpu, irq)    (++local_irq_count[cpu])
 #define irq_exit(cpu, irq)     (--local_irq_count[cpu])
@@ -647,7+957,7 @@ static inline void handle_irq(int irq, struct pt_regs * regs)
        int cpu = smp_processor_id();
 
        irq_enter(cpu, irq);
-       kstat.irqs[0][irq] += 1;
+       kstat.irqs[cpu][irq] += 1;
        if (!action) {
                unexpected_irq(irq, regs);
        } else {
@@ -670,8+980,9 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
        }
 
        irq_enter(cpu, irq);
-       kstat.irqs[0][irq] += 1;
+       kstat.irqs[cpu][irq] += 1;
        action = irq_action[irq];
+
        /*
         * For normal interrupts, we mask it out, and then ACK it.
         * This way another (more timing-critical) interrupt can
@@ -691,6+1002,10 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
                        action = action->next;
                } while (action);
                unmask_irq(ack);
+       } else {
+#if 1
+               printk("device_interrupt: unexpected interrupt %d\n", irq);
+#endif
        }
        irq_exit(cpu, irq);
 }
@@ -711,6+1026,8 @@ static inline void isa_device_interrupt(unsigned long vector,
 #      define IACK_SC  CIA_IACK_SC
 #elif defined(CONFIG_ALPHA_PYXIS)
 #      define IACK_SC  PYXIS_IACK_SC
+#elif defined(CONFIG_ALPHA_TSUNAMI)
+#      define IACK_SC  TSUNAMI_PCI0_IACK_SC
 #else
        /*
         * This is bogus but necessary to get it to compile
@@ -729,7+1046,7 @@ static inline void isa_device_interrupt(unsigned long vector,
         * interrupt that is pending.  The PALcode sets up the
         * interrupts vectors such that irq level L generates vector L.
         */
-       j = *(volatile int *) IACK_SC;
+       j = *(vuip) IACK_SC;
        j &= 0xff;
        if (j == 7) {
                if (!(inb(0x20) & 0x80)) {
@@ -775,10+1092,9 @@ alcor_and_xlt_device_interrupt(unsigned long vector, struct pt_regs *regs)
        unsigned int i;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
 
-       /* read the interrupt summary register of the GRU */
+       /* Read the interrupt summary register of the GRU */
        pld = (*(vuip)GRU_INT_REQ) & GRU_INT_REQ_BITS;
 
 #if 0
@@ -810,10+1126,9 @@ cabriolet_and_eb66p_device_interrupt(unsigned long vector,
        unsigned int i;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
 
-       /* read the interrupt summary registers */
+       /* Read the interrupt summary registers */
        pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
 
 #if 0
@@ -843,10+1158,9 @@ mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
        unsigned int i;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
 
-       /* read the interrupt summary registers */
+       /* Read the interrupt summary registers */
        pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) |
                (((unsigned long) inb(0xa0))  <<  8) |
                ((unsigned long) inb(0x20));
@@ -878,10+1192,9 @@ eb66_and_eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
        unsigned int i;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
 
-       /* read the interrupt summary registers */
+       /* Read the interrupt summary registers */
        pld = inb(0x26) | (inb(0x27) << 8);
        /*
         * Now, for every possible bit set, work through
@@ -909,30+1222,34 @@ miata_device_interrupt(unsigned long vector, struct pt_regs *regs)
        unsigned int i;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
 
-       /* read the interrupt summary register of PYXIS */
-       pld = (*(vulp)PYXIS_INT_REQ);
+       /* Read the interrupt summary register of PYXIS */
+       pld = *(vulp)PYXIS_INT_REQ;
 
 #if 0
        printk("[0x%08lx/0x%08lx/0x%04x]", pld,
               *(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8));
 #endif
 
-       /* For now, AND off any bits we are not interested in.  */
-#if defined(CONFIG_ALPHA_MIATA)
-       /* HALT (2), timer (6), ISA Bridge (7), 21142/3 (8),
-          then all the PCI slots/INTXs (12-31).  */
+#ifdef CONFIG_ALPHA_MIATA
+       /*
+        * For now, AND off any bits we are not interested in:
+        *   HALT (2), timer (6), ISA Bridge (7), 21142/3 (8)
+        * then all the PCI slots/INTXs (12-31).
+        */
        /* Maybe HALT should only be used for SRM console boots? */
        pld &= 0x00000000fffff1c4UL;
 #endif
-#if defined(CONFIG_ALPHA_SX164)
-       /* HALT (2), timer (6), ISA Bridge (7),
-          then all the PCI slots/INTXs (8-23).  */
-       /* HALT should only be used for SRM console boots.  */
+#ifdef CONFIG_ALPHA_SX164
+       /*
+        * For now, AND off any bits we are not interested in:
+        *  HALT (2), timer (6), ISA Bridge (7)
+        * then all the PCI slots/INTXs (8-23)
+        */
+       /* Maybe HALT should only be used for SRM console boots? */
        pld &= 0x0000000000ffffc0UL;
-#endif
+#endif /* SX164 */
 
        /*
         * Now for every possible bit set, work through them and call
@@ -962,10+1279,9 @@ noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
        unsigned int i;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
 
-       /* read the interrupt summary registers of NORITAKE */
+       /* Read the interrupt summary registers of NORITAKE */
        pld = ((unsigned long) inw(0x54c) << 32) |
                ((unsigned long) inw(0x54a) << 16) |
                ((unsigned long) inb(0xa0)  <<  8) |
@@ -991,16+1307,76 @@ noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
        restore_flags(flags);
 }
 
+#if defined(CONFIG_ALPHA_DP264)
+/* we have to conditionally compile this because of TSUNAMI_xxx symbols */
+static inline void dp264_device_interrupt(unsigned long vector,
+                                                  struct pt_regs * regs)
+{
+        unsigned long pld, tmp;
+        unsigned int i;
+        unsigned long flags;
+
+       __save_and_cli(flags);
+
+        /* Read the interrupt summary register of TSUNAMI */
+        pld = (*(vulp)TSUNAMI_CSR_DIR0);
+
+#if 0
+        printk("[0x%08lx/0x%08lx/0x%04x]", pld,
+              *(vulp)TSUNAMI_CSR_DIM0,
+              inb(0x20) | (inb(0xA0) << 8));
+#endif
+
+        /*
+         * Now for every possible bit set, work through them and call
+         * the appropriate interrupt handler.
+         */
+        while (pld) {
+                i = ffz(~pld);
+                pld &= pld - 1; /* clear least bit set */
+                if (i == 55) {
+                        isa_device_interrupt(vector, regs);
+               } else { /* if not timer int */
+                        device_interrupt(16 + i, 16 + i, regs);
+                }
+#if 0
+               *(vulp)TSUNAMI_CSR_DIR0 = 1UL << i; mb();
+               tmp = *(vulp)TSUNAMI_CSR_DIR0;
+#endif
+        }
+       __restore_flags(flags);
+}
+#endif /* DP264 */
+
+#if defined(CONFIG_ALPHA_RAWHIDE)
+/* we have to conditionally compile this because of MCPCIA_xxx symbols */
+static inline void rawhide_device_interrupt(unsigned long vector,
+                                                  struct pt_regs * regs)
+{
+#if 0
+        unsigned long pld;
+        unsigned int i;
+        unsigned long flags;
+
+       __save_and_cli(flags);
+
+       /* PLACEHOLDER, perhaps never used if we always do SRM */
+
+       __restore_flags(flags);
+#endif
+}
+#endif /* RAWHIDE */
+
 #if defined(CONFIG_ALPHA_RUFFIAN)
 static inline void
 ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs)
+
 {
        unsigned long pld;
        unsigned int i;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+        save_and_cli(flags);
 
        /* Read the interrupt summary register of PYXIS */
        pld = *(vulp)PYXIS_INT_REQ;
@@ -1010,16+1386,16 @@ ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs)
         * then all the PCI slots/INTXs (12-31) 
         * flash(5) :DWH:
         */
-       pld &= 0x00000000ffffff9fUL;
+        pld &= 0x00000000ffffff9fUL;/* was ffff7f */
 
        /*
         * Now for every possible bit set, work through them and call
         * the appropriate interrupt handler.
         */
+
        while (pld) {
                i = ffz(~pld);
                pld &= pld - 1; /* clear least bit set */
-
                if (i == 7) {
                        /* Copy this bit from isa_device_interrupt cause
                           we need to hook into int 0 for the timer.  I
@@ -1041,19+1417,57 @@ ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs)
                        } else {
                                device_interrupt(j, j, regs);
                        }
-               } else {
+                } else { /* if not timer int */
                        device_interrupt(16 + i, 16 + i, regs);
                }
 
-               *(vulp)PYXIS_INT_REQ = 1UL << i;
-               mb();
-               *(vulp)PYXIS_INT_REQ;
+                *(vulp)PYXIS_INT_REQ = 1UL << i; mb();
+                *(vulp)PYXIS_INT_REQ; /* read to force the write */
        }
-
        restore_flags(flags);
 }
 #endif /* RUFFIAN */
 
+static inline void takara_device_interrupt(unsigned long vector,
+                                          struct pt_regs * regs)
+{
+       unsigned long flags;
+       unsigned intstatus;
+
+       save_and_cli(flags);
+
+       /*
+        * The PALcode will have passed us vectors 0x800 or 0x810,
+        * which are fairly arbitrary values and serve only to tell
+        * us whether an interrupt has come in on IRQ0 or IRQ1. If
+        * it's IRQ1 it's a PCI interrupt; if it's IRQ0, it's
+        * probably ISA, but PCI interrupts can come through IRQ0
+        * as well if the interrupt controller isn't in accelerated
+        * mode.
+        *
+        * OTOH, the accelerator thing doesn't seem to be working
+        * overly well, so what we'll do instead is try directly
+        * examining the Master Interrupt Register to see if it's a
+        * PCI interrupt, and if _not_ then we'll pass it on to the
+        * ISA handler.
+        */
+
+       intstatus = inw(0x500) & 15;
+       if (intstatus) {
+               /*
+                * This is a PCI interrupt. Check each bit and
+                * despatch an interrupt if it's set.
+                */
+               if (intstatus & 8) device_interrupt(16+3, 16+3, regs);
+               if (intstatus & 4) device_interrupt(16+2, 16+2, regs);
+               if (intstatus & 2) device_interrupt(16+1, 16+1, regs);
+               if (intstatus & 1) device_interrupt(16+0, 16+0, regs);
+       } else
+               isa_device_interrupt (vector, regs);
+
+       restore_flags(flags);
+}
+
 #endif /* CONFIG_PCI */
 
 /*
@@ -1085,9+1499,11 @@ srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
        int irq, ack;
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       __save_and_cli(flags);
 
+#ifdef __SMP__
+if (smp_processor_id()) printk("srm_device_interrupt on other CPU\n");
+#endif
 
        ack = irq = (vector - 0x800) >> 4;
 
@@ -1131,9+1547,9 @@ srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 
 #ifdef CONFIG_ALPHA_NORITAKE
        /*
-        * I really hate to do this, but the NORITAKE SRM console reports
-        *  PCI vectors *lower* than I expected from the bit numbering in
-        *  the documentation.
+        * I really hate to do this, too, but the NORITAKE SRM console also
+        *  reports PCI vectors *lower* than I expected from the bit numbers
+        *  in the documentation.
         * But I really don't want to change the fixup code for allocation
         *  of IRQs, nor the irq_mask maintenance stuff, both of which look
         *  nice and clean now.
@@ -1153,9+1569,41 @@ srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 #endif
 #endif /* CONFIG_ALPHA_SABLE */
 
+#ifdef CONFIG_ALPHA_DP264
+        /*
+         * the DP264 SRM console reports PCI interrupts with a vector
+        * 0x100 *higher* than one might expect, as PCI IRQ 0 (ie bit 0)
+        * shows up as IRQ 16, etc, etc. We adjust it down by 16 to have
+        * it line up with the actual bit numbers from the DIM registers,
+        * which is how we manage the interrupts/mask. Sigh...
+         */
+        if (irq >= 32)
+                ack = irq = irq - 16;
+#endif /* DP264 */
+
+#ifdef CONFIG_ALPHA_RAWHIDE
+        /*
+         * the RAWHIDE SRM console reports PCI interrupts with a vector
+        * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0)
+        * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have
+        * it line up with the actual bit numbers from the REQ registers,
+        * which is how we manage the interrupts/mask. Sigh...
+        *
+        * also, PCI #1 interrupts are offset some more... :-(
+         */
+       if (irq == 52)
+         ack = irq = 56; /* SCSI on PCI 1 is special */
+       else {
+         if (irq >= 24) /* adjust all PCI interrupts down 8 */
+           ack = irq = irq - 8;
+         if (irq >= 48) /* adjust PCI bus 1 interrupts down another 8 */
+           ack = irq = irq - 8;
+       }
+#endif /* RAWHIDE */
+
        device_interrupt(irq, ack, regs);
 
-       restore_flags(flags);
+       __restore_flags(flags);
 }
 
 /*
@@ -1218,6+1666,10 @@ extern void pyxis_machine_check(unsigned long vector, unsigned long la,
                                struct pt_regs * regs);
 extern void t2_machine_check(unsigned long vector, unsigned long la,
                             struct pt_regs * regs);
+extern void tsunami_machine_check(unsigned long vector, unsigned long la,
+                                 struct pt_regs * regs);
+extern void mcpcia_machine_check(unsigned long vector, unsigned long la,
+                                struct pt_regs * regs);
 
 static void 
 machine_check(unsigned long vector, unsigned long la, struct pt_regs *regs)
@@ -1232,6+1684,10 @@ machine_check(unsigned long vector, unsigned long la, struct pt_regs *regs)
        pyxis_machine_check(vector, la, regs);
 #elif defined(CONFIG_ALPHA_T2)
        t2_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_TSUNAMI)
+       tsunami_machine_check(vector, la, regs);
+#elif defined(CONFIG_ALPHA_MCPCIA)
+       mcpcia_machine_check(vector, la, regs);
 #else
        printk("Machine check\n");
 #endif
@@ -1244,7+1700,14 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
 {
        switch (type) {
        case 0:
+#ifdef __SMP__
+/*             irq_enter(smp_processor_id(), 0); ??????? */
+               handle_ipi(&regs);
+/*             irq_exit(smp_processor_id(), 0);  ??????? */
+               return;
+#else /* __SMP__ */
                printk("Interprocessor interrupt? You must be kidding\n");
+#endif /* __SMP__ */
                break;
        case 1:
                handle_irq(RTC_IRQ, &regs);
@@ -1253,23+1716,38 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
                machine_check(vector, la_ptr, &regs);
                return;
        case 3:
-#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
-    defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM)
+#if defined(CONFIG_ALPHA_JENSEN) || \
+    defined(CONFIG_ALPHA_NONAME) || \
+    defined(CONFIG_ALPHA_P2K)    || \
+    defined(CONFIG_ALPHA_SRM)
                srm_device_interrupt(vector, &regs);
-#elif defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164)
+#elif defined(CONFIG_ALPHA_MIATA) || \
+    defined(CONFIG_ALPHA_SX164)
                miata_device_interrupt(vector, &regs);
 #elif defined(CONFIG_ALPHA_NORITAKE)
                noritake_device_interrupt(vector, &regs);
-#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
+#elif defined(CONFIG_ALPHA_ALCOR) || \
+      defined(CONFIG_ALPHA_XLT)
                alcor_and_xlt_device_interrupt(vector, &regs);
-#elif defined(CONFIG_ALPHA_RUFFIAN)
-               ruffian_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_CABRIOLET) || \
+      defined(CONFIG_ALPHA_EB66P)     || \
+      defined(CONFIG_ALPHA_EB164)     || \
+      defined(CONFIG_ALPHA_PC164)     || \
+      defined(CONFIG_ALPHA_LX164)
+               cabriolet_and_eb66p_device_interrupt(vector, &regs);
 #elif defined(CONFIG_ALPHA_MIKASA)
                mikasa_device_interrupt(vector, &regs);
-#elif NR_IRQS == 33
-               cabriolet_and_eb66p_device_interrupt(vector, &regs);
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_EB66) || \
+      defined(CONFIG_ALPHA_EB64P)
                eb66_and_eb64p_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_RUFFIAN)
+               ruffian_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_DP264)
+               dp264_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_RAWHIDE)
+               rawhide_device_interrupt(vector, &regs);
+#elif defined(CONFIG_ALPHA_TAKARA)
+               takara_device_interrupt(vector, &regs);
 #elif NR_IRQS == 16
                isa_device_interrupt(vector, &regs);
 #endif
@@ -1293,22+1771,21 @@ static inline void sable_init_IRQ(void)
        outb(0x44, 0x535);              /* enable cascades in master */
 }
 
-#ifdef CONFIG_ALPHA_SX164
+#if defined(CONFIG_ALPHA_SX164)
 static inline void sx164_init_IRQ(void)
 {
+#if !defined(CONFIG_ALPHA_SRM)
        /* note invert on MASK bits */
        *(vulp)PYXIS_INT_MASK  = ~((long)irq_mask >> 16); mb();
-#if 0
-       *(vulp)PYXIS_INT_HILO  = 0x000000B2UL; mb(); /* ISA/NMI HI */
-       *(vulp)PYXIS_RT_COUNT  = 0UL; mb(); /* clear count */
-#endif
+        *(vulp)PYXIS_INT_MASK;
+#endif /* !SRM */
        enable_irq(16 + 6);     /* enable timer */
        enable_irq(16 + 7);     /* enable ISA PIC cascade */
        enable_irq(2);          /* enable cascade */
 }
 #endif /* SX164 */
 
-#ifdef CONFIG_ALPHA_RUFFIAN
+#if defined(CONFIG_ALPHA_RUFFIAN)
 static inline void ruffian_init_IRQ(void)
 {
        /* invert 6&7 for i82371 */
@@ -1343,19+1820,19 @@ static inline void ruffian_init_IRQ(void)
 }
 #endif /* RUFFIAN */
 
-
 #ifdef CONFIG_ALPHA_MIATA
 static inline void miata_init_IRQ(void)
 {
        /* note invert on MASK bits */
        *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); /* invert */
+#if 0
+       /* these break on MiataGL so we'll try not to do it at all */
        *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb();     /* ISA/NMI HI */
        *(vulp)PYXIS_RT_COUNT = 0UL; mb();              /* clear count */
-       *(vulp)PYXIS_INT_REQ  = 0x4000000000000000UL; mb(); /* clear upper timer */
-#if 0
-       *(vulp)PYXIS_INT_ROUTE = 0UL; mb();             /* all are level */
-       *(vulp)PYXIS_INT_CNFG  = 0UL; mb();             /* all clear */
 #endif
+       /* clear upper timer */
+       *(vulp)PYXIS_INT_REQ  = 0x4000000000000000UL; mb();
+
        enable_irq(16 + 2);     /* enable HALT switch - SRM only? */
        enable_irq(16 + 6);     /* enable timer */
        enable_irq(16 + 7);     /* enable ISA PIC cascade */
@@ -1381,7+1858,7 @@ static inline void alcor_and_xlt_init_IRQ(void)
        enable_irq(16 + 31);            /* enable (E)ISA PIC cascade */
        enable_irq(2);                  /* enable cascade */
 }
-#endif
+#endif /* ALCOR || XLT */
 
 static inline void mikasa_init_IRQ(void)
 {
@@ -1389,9+1866,56 @@ static inline void mikasa_init_IRQ(void)
        enable_irq(2);                  /* enable cascade */
 }
 
-static inline void init_IRQ_33(void)
+#if defined(CONFIG_ALPHA_DP264)
+static inline void dp264_init_IRQ(void)
+{
+       /* note invert on MASK bits */
+        *(vulp)TSUNAMI_CSR_DIM0 =
+             ~(irq_mask) & ~0x0000000000000000UL; mb();
+        *(vulp)TSUNAMI_CSR_DIM0;
+        enable_irq(55);     /* enable CYPRESS interrupt controller (ISA) */
+       enable_irq(2);
+}
+#endif /* DP264 */
+
+#if defined(CONFIG_ALPHA_RAWHIDE)
+static inline void rawhide_init_IRQ(void)
 {
+       /* HACK ALERT! only PCI busses 0 and 1 are used currently,
+          and routing is only to CPU #1*/
+
+       *(vuip)MCPCIA_INT_MASK0(0) =
+           (~((irq_mask) >> 16) & 0x00ffffffU) | 0x00ff0000U; mb();
+       /* ... and read it back to make sure it got written.  */
+       *(vuip)MCPCIA_INT_MASK0(0);
+
+       *(vuip)MCPCIA_INT_MASK0(1) =
+           (~((irq_mask) >> 40) & 0x00ffffffU) | 0x00fe0000U; mb();
+       /* ... and read it back to make sure it got written.  */
+       *(vuip)MCPCIA_INT_MASK0(1);
+       enable_irq(2);
+}
+#endif /* RAWHIDE */
+
+static inline void takara_init_IRQ(void)
+{
+       unsigned int ctlreg = inl(0x500);
+
+       ctlreg &= ~0x8000;     /* return to non-accelerated mode */
+       outw(ctlreg >> 16, 0x502);
+       outw(ctlreg & 0xFFFF, 0x500);
+       ctlreg = 0x05107c00;   /* enable the PCI interrupt register */
+       printk("Setting to 0x%08x\n", ctlreg);
+       outw(ctlreg >> 16, 0x502);
+       outw(ctlreg & 0xFFFF, 0x500);
+       enable_irq(2);
+}
+
+static inline void init_IRQ_35(void)
+{
+#if !defined(CONFIG_ALPHA_SRM)
        outl(irq_mask >> 16, 0x804);
+#endif /* !SRM */
        enable_irq(16 + 4);             /* enable SIO cascade */
        enable_irq(2);                  /* enable cascade */
 }
@@ -1413,13+1937,20 @@ void __init
 init_IRQ(void)
 {
        wrent(entInt, 0);
-       dma_outb(0, DMA1_RESET_REG);
-       dma_outb(0, DMA2_RESET_REG);
-#ifndef CONFIG_ALPHA_SX164
-       dma_outb(0, DMA1_CLR_MASK_REG);
-       /* We need to figure out why this fails on the SX164.  */
-       dma_outb(0, DMA2_CLR_MASK_REG);
-#endif
+
+/* FIXME FIXME FIXME FIXME FIXME */
+#if !defined(CONFIG_ALPHA_DP264)
+       /* we need to figure out why these fail on the DP264 */
+       outb(0, DMA1_RESET_REG);
+       outb(0, DMA2_RESET_REG);
+#endif /* !DP264 */
+/* FIXME FIXME FIXME FIXME FIXME */
+#if !defined(CONFIG_ALPHA_SX164) && !defined(CONFIG_ALPHA_DP264)
+       outb(0, DMA1_CLR_MASK_REG);
+       /* we need to figure out why this fails on the SX164 */
+       outb(0, DMA2_CLR_MASK_REG);
+#endif /* !SX164 && !DP264 */
+/* end FIXMEs */
 
 #if defined(CONFIG_ALPHA_SABLE)
        sable_init_IRQ();
@@ -1431,17+1962,21 @@ init_IRQ(void)
        noritake_init_IRQ();
 #elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT)
        alcor_and_xlt_init_IRQ();
-#elif (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \
-       && defined(CONFIG_ALPHA_SRM)
-       /* Disable all the PCI interrupts?  Otherwise, everthing was
-          done by SRM already.  */
 #elif defined(CONFIG_ALPHA_MIKASA)
        mikasa_init_IRQ();
+#elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \
+      defined(CONFIG_ALPHA_PC164)     || defined(CONFIG_ALPHA_LX164) || \
+      defined(CONFIG_ALPHA_EB164)
+       init_IRQ_35();
 #elif defined(CONFIG_ALPHA_RUFFIAN)
        ruffian_init_IRQ();
-#elif NR_IRQS == 33
-       init_IRQ_33();
-#elif NR_IRQS == 32
+#elif defined(CONFIG_ALPHA_DP264)
+        dp264_init_IRQ();
+#elif defined(CONFIG_ALPHA_RAWHIDE)
+        rawhide_init_IRQ();
+#elif defined(CONFIG_ALPHA_TAKARA)
+        takara_init_IRQ();
+#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
        init_IRQ_32();
 #elif NR_IRQS == 16
        init_IRQ_16();
index 2a39a1c..4307a19 100644 (file)
@@ -6,6+6,7 @@
  * bios code.
  */
 #include <linux/kernel.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #define MCHK_K_SIO_IOCHK       0x206   /* all platforms so far */
 #define MCHK_K_DCSR            0x208   /* all but Noname */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int LCA_DMA_WIN_BASE = LCA_DMA_WIN_BASE_DEFAULT;
+unsigned int LCA_DMA_WIN_SIZE = LCA_DMA_WIN_SIZE_DEFAULT;
+#endif /* SRM_SETUP */
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address and setup the LCA_IOC_CONF register
@@ -100,11+106,11 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
                        return -1;
                }
 
-               *((vulp) LCA_IOC_CONF) = 0;
+               *(vulp)LCA_IOC_CONF = 0;
                addr = (1 << (11 + device)) | (func << 8) | where;
        } else {
                /* type 1 configuration cycle: */
-               *((vulp) LCA_IOC_CONF) = 1;
+               *(vulp)LCA_IOC_CONF = 1;
                addr = (bus << 16) | (device_fn << 8) | where;
        }
        *pci_addr = addr;
@@ -130,7+136,7 @@ static unsigned int conf_read(unsigned long addr)
        value = *(vuip)addr;
        draina();
 
-       stat0 = *((unsigned long*)LCA_IOC_STAT0);
+       stat0 = *(vulp)LCA_IOC_STAT0;
        if (stat0 & LCA_IOC_STAT0_ERR) {
                code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT)
                        & LCA_IOC_STAT0_CODE_MASK);
@@ -167,7+173,7 @@ static void conf_write(unsigned long addr, unsigned int value)
        *(vuip)addr = value;
        draina();
 
-       stat0 = *((unsigned long*)LCA_IOC_STAT0);
+       stat0 = *(vulp)LCA_IOC_STAT0;
        if (stat0 & LCA_IOC_STAT0_ERR) {
                code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT)
                        & LCA_IOC_STAT0_CODE_MASK);
@@ -287,6+293,40 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
 
 unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
 {
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if ((*(vulp)LCA_IOC_W_BASE0 & (1UL<<33)) &&
+           (*(vulp)LCA_IOC_T_BASE0 == 0))
+       {
+         LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE0 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK0 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE += 1;
+#if 1
+         printk("lca_init: using Window 0 settings\n");
+         printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)LCA_IOC_W_BASE0,
+                *(vulp)LCA_IOC_W_MASK0,
+                *(vulp)LCA_IOC_T_BASE0);
+#endif
+       }
+       else    /* check window 2 for enabled and mapped to 0 */
+       if ((*(vulp)LCA_IOC_W_BASE1 & (1UL<<33)) &&
+           (*(vulp)LCA_IOC_T_BASE1 == 0))
+       {
+         LCA_DMA_WIN_BASE = *(vulp)LCA_IOC_W_BASE1 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE = *(vulp)LCA_IOC_W_MASK1 & 0xffffffffUL;
+         LCA_DMA_WIN_SIZE += 1;
+#if 1
+         printk("lca_init: using Window 1 settings\n");
+         printk("lca_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)LCA_IOC_W_BASE1,
+                *(vulp)LCA_IOC_W_MASK1,
+                *(vulp)LCA_IOC_T_BASE1);
+#endif
+       }
+       else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+       {
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, window 1 is disabled.  In the future, we may
@@ -294,9+334,11 @@ unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
         * goes at 1 GB and is 1 GB large.
         */
        *(vulp)LCA_IOC_W_BASE1 = 0UL<<33;
+
        *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE;
        *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1;
        *(vulp)LCA_IOC_T_BASE0 = 0;
+       }
 
        /*
         * Disable PCI parity for now.  The NCR53c810 chip has
diff --git a/arch/alpha/kernel/mcpcia.c b/arch/alpha/kernel/mcpcia.c
new file mode 100644 (file)
index 0000000..3c3736b
--- /dev/null
@@ -0,0 +1,981 @@
+/*
+ * Code common to all MCbus-PCI adaptor chipsets
+ *
+ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+#include <asm/delay.h>
+
+/*
+ * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
+ * One plausible explanation is that the i/o controller does not properly
+ * handle the system transaction.  Another involves timing.  Ho hum.
+ */
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef CONFIG_ALPHA_MCPCIA
+
+#undef DEBUG_CFG
+
+#ifdef DEBUG_CFG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+#undef DEBUG_PCI
+
+#ifdef DEBUG_PCI
+# define DBG_PCI(args) printk args
+#else
+# define DBG_PCI(args)
+#endif
+
+#define DEBUG_MCHECK
+
+#ifdef DEBUG_MCHECK
+# define DBG_MCK(args) printk args
+# define DEBUG_MCHECK_DUMP
+#else
+# define DBG_MCK(args)
+#endif
+
+#define vuip   volatile unsigned int  *
+#define vulp   volatile unsigned long  *
+
+static volatile unsigned int MCPCIA_mcheck_expected[NR_CPUS];
+static volatile unsigned int MCPCIA_mcheck_taken[NR_CPUS];
+static unsigned int MCPCIA_jd[NR_CPUS];
+
+#define MCPCIA_MAX_HOSES 2
+static int mcpcia_num_hoses = 0;
+
+static int pci_probe_enabled = 0; /* disable to start */
+
+static struct linux_hose_info *mcpcia_root = NULL, *mcpcia_last_hose;
+
+struct linux_hose_info *bus2hose[256];
+
+static inline unsigned long long_align(unsigned long addr)
+{
+       return ((addr + (sizeof(unsigned long) - 1)) &
+               ~(sizeof(unsigned long) - 1));
+}
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int MCPCIA_DMA_WIN_BASE = MCPCIA_DMA_WIN_BASE_DEFAULT;
+unsigned int MCPCIA_DMA_WIN_SIZE = MCPCIA_DMA_WIN_SIZE_DEFAULT;
+unsigned long mcpcia_sm_base_r1, mcpcia_sm_base_r2, mcpcia_sm_base_r3;
+#endif /* SRM_SETUP */
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the MCPCIA_HAXR2 register
+ * accordingly.  It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     31:11   Device select bit.
+ *     10:8    Function number
+ *      7:2    Register number
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     31:24   reserved
+ *     23:16   bus number (8 bits = 128 possible buses)
+ *     15:11   Device number (5 bits)
+ *     10:8    function number
+ *      7:2    register number
+ *  
+ * Notes:
+ *     The function number selects which function of a multi-function device 
+ *     (e.g., scsi and ethernet).
+ * 
+ *     The register selects a DWORD (32 bit) register offset.  Hence it
+ *     doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ *     bits.
+ */
+
+static unsigned int
+conf_read(unsigned long addr, unsigned char type1,
+         struct linux_hose_info *hose)
+{
+       unsigned long flags;
+       unsigned long hoseno = hose->pci_hose_index;
+       unsigned int stat0, value, temp, cpu;
+
+       cpu = smp_processor_id();
+
+       save_and_cli(flags);
+
+       DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n",
+            addr, type1, hoseno));
+
+       /* reset status register to avoid losing errors: */
+       stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno);
+       *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb();
+       temp = *(vuip)MCPCIA_CAP_ERR(hoseno);
+       DBG_CFG(("conf_read: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0));
+
+       mb();
+       draina();
+       MCPCIA_mcheck_expected[cpu] = 1;
+       MCPCIA_mcheck_taken[cpu] = 0;
+       mb();
+       /* access configuration space: */
+       value = *((vuip)addr);
+       mb();
+       mb();  /* magic */
+       if (MCPCIA_mcheck_taken[cpu]) {
+               MCPCIA_mcheck_taken[cpu] = 0;
+               value = 0xffffffffU;
+               mb();
+       }
+       MCPCIA_mcheck_expected[cpu] = 0;
+       mb();
+
+       DBG_CFG(("conf_read(): finished\n"));
+
+       restore_flags(flags);
+       return value;
+}
+
+
+static void
+conf_write(unsigned long addr, unsigned int value, unsigned char type1,
+          struct linux_hose_info *hose)
+{
+       unsigned long flags;
+       unsigned long hoseno = hose->pci_hose_index;
+       unsigned int stat0, temp, cpu;
+
+       cpu = smp_processor_id();
+
+       save_and_cli(flags);    /* avoid getting hit by machine check */
+
+       /* reset status register to avoid losing errors: */
+       stat0 = *(vuip)MCPCIA_CAP_ERR(hoseno);
+       *(vuip)MCPCIA_CAP_ERR(hoseno) = stat0; mb();
+       temp = *(vuip)MCPCIA_CAP_ERR(hoseno);
+       DBG_CFG(("conf_write: MCPCIA CAP_ERR(%d) was 0x%x\n", hoseno, stat0));
+
+       draina();
+       MCPCIA_mcheck_expected[cpu] = 1;
+       mb();
+       /* access configuration space: */
+       *((vuip)addr) = value;
+       mb();
+       mb();  /* magic */
+       temp = *(vuip)MCPCIA_CAP_ERR(hoseno); /* read to force the write */
+       MCPCIA_mcheck_expected[cpu] = 0;
+       mb();
+
+       DBG_CFG(("conf_write(): finished\n"));
+       restore_flags(flags);
+}
+
+static int mk_conf_addr(struct linux_hose_info *hose,
+                       unsigned char bus, unsigned char device_fn,
+                       unsigned char where, unsigned long *pci_addr,
+                       unsigned char *type1)
+{
+       unsigned long addr;
+
+       if (!pci_probe_enabled) /* if doing standard pci_init(), ignore */
+           return -1;
+
+       DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
+            " pci_addr=0x%p, type1=0x%p)\n",
+            bus, device_fn, where, pci_addr, type1));
+
+       /* type 1 configuration cycle for *ALL* busses */
+       *type1 = 1;
+
+       if (hose->pci_first_busno == bus)
+           bus = 0;
+       addr = (bus << 16) | (device_fn << 8) | (where);
+       addr <<= 5; /* swizzle for SPARSE */
+       addr |= hose->pci_config_space;
+
+       *pci_addr = addr;
+       DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+       return 0;
+}
+
+
+int hose_read_config_byte (struct linux_hose_info *hose,
+                          unsigned char bus, unsigned char device_fn,
+                          unsigned char where, unsigned char *value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       *value = 0xff;
+
+       if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= 0x00; /* or in length */
+
+       *value = conf_read(addr, type1, hose) >> ((where & 3) * 8);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int hose_read_config_word (struct linux_hose_info *hose,
+                          unsigned char bus, unsigned char device_fn,
+                          unsigned char where, unsigned short *value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       *value = 0xffff;
+
+       if (where & 0x1) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= 0x08; /* or in length */
+
+       *value = conf_read(addr, type1, hose) >> ((where & 3) * 8);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int hose_read_config_dword (struct linux_hose_info *hose,
+                           unsigned char bus, unsigned char device_fn,
+                           unsigned char where, unsigned int *value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       *value = 0xffffffff;
+
+       if (where & 0x3) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+       addr |= 0x18; /* or in length */
+
+       *value = conf_read(addr, type1, hose);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int hose_write_config_byte (struct linux_hose_info *hose,
+                           unsigned char bus, unsigned char device_fn,
+                           unsigned char where, unsigned char value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= 0x00; /* or in length */
+
+       conf_write(addr, value << ((where & 3) * 8), type1, hose);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int hose_write_config_word (struct linux_hose_info *hose,
+                           unsigned char bus, unsigned char device_fn,
+                           unsigned char where, unsigned short value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= 0x08; /* or in length */
+
+       conf_write(addr, value << ((where & 3) * 8), type1, hose);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int hose_write_config_dword (struct linux_hose_info *hose,
+                            unsigned char bus, unsigned char device_fn,
+                            unsigned char where, unsigned int value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(hose, bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       addr |= 0x18; /* or in length */
+
+       conf_write(addr, value << ((where & 3) * 8), type1, hose);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char devfn,
+                             unsigned char where, unsigned char *value)
+{
+       return hose_read_config_byte(bus2hose[bus], bus, devfn, where, value);
+}
+
+int pcibios_read_config_word (unsigned char bus, unsigned char devfn,
+                             unsigned char where, unsigned short *value)
+{
+       return hose_read_config_word(bus2hose[bus], bus, devfn, where, value);
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char devfn,
+                              unsigned char where, unsigned int *value)
+{
+       return hose_read_config_dword(bus2hose[bus], bus, devfn, where, value);
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
+                              unsigned char where, unsigned char value)
+{
+       return hose_write_config_byte(bus2hose[bus], bus, devfn, where, value);
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
+                              unsigned char where, unsigned short value)
+{
+       return hose_write_config_word(bus2hose[bus], bus, devfn, where, value);
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
+                               unsigned char where, unsigned int value)
+{
+       return hose_write_config_dword(bus2hose[bus], bus, devfn, where, value);
+}
+
+unsigned long mcpcia_init(unsigned long mem_start, unsigned long mem_end)
+{
+    struct linux_hose_info *hose;
+    unsigned int mcpcia_err;
+    unsigned int pci_rev;
+    int h;
+
+    mem_start = long_align(mem_start);
+
+    for (h = 0; h < NR_CPUS; h++) {
+       MCPCIA_mcheck_expected[h] = 0;
+       MCPCIA_mcheck_taken[h] = 0;
+    }
+
+    /* first, find how many hoses we have */
+    for (h = 0; h < MCPCIA_MAX_HOSES; h++) {
+       pci_rev = *(vuip)MCPCIA_REV(h);
+#if 0
+       printk("mcpcia_init: got 0x%x for PCI_REV for hose %d\n",
+              pci_rev, h);
+#endif
+       if ((pci_rev >> 16) == PCI_CLASS_BRIDGE_HOST) {
+           mcpcia_num_hoses++;
+
+           hose = (struct linux_hose_info *)mem_start;
+           mem_start = long_align(mem_start + sizeof(*hose));
+
+           memset(hose, 0, sizeof(*hose));
+
+           if (mcpcia_root)
+               mcpcia_last_hose->next = hose;
+           else
+               mcpcia_root = hose;
+           mcpcia_last_hose = hose;
+
+           hose->pci_io_space = MCPCIA_IO(h);
+           hose->pci_mem_space = MCPCIA_DENSE(h);
+           hose->pci_config_space = MCPCIA_CONF(h);
+           hose->pci_sparse_space = MCPCIA_SPARSE(h);
+           hose->pci_hose_index = h;
+           hose->pci_first_busno = 255;
+           hose->pci_last_busno = 0;
+       }
+    }
+
+#if 1
+    printk("mcpcia_init: found %d hoses\n", mcpcia_num_hoses);
+#endif
+
+    /* now do init for each hose */
+    for (hose = mcpcia_root; hose; hose = hose->next) {
+      h = hose->pci_hose_index;
+#if 0
+#define PRINTK printk
+PRINTK("mcpcia_init: -------- hose %d --------\n",h);
+PRINTK("mcpcia_init: MCPCIA_REV 0x%x\n", *(vuip)MCPCIA_REV(h));
+PRINTK("mcpcia_init: MCPCIA_WHOAMI 0x%x\n", *(vuip)MCPCIA_WHOAMI(h));
+PRINTK("mcpcia_init: MCPCIA_HAE_MEM 0x%x\n", *(vuip)MCPCIA_HAE_MEM(h));
+PRINTK("mcpcia_init: MCPCIA_HAE_IO 0x%x\n", *(vuip)MCPCIA_HAE_IO(h));
+PRINTK("mcpcia_init: MCPCIA_HAE_DENSE 0x%x\n", *(vuip)MCPCIA_HAE_DENSE(h));
+PRINTK("mcpcia_init: MCPCIA_INT_CTL 0x%x\n", *(vuip)MCPCIA_INT_CTL(h));
+PRINTK("mcpcia_init: MCPCIA_INT_REQ 0x%x\n", *(vuip)MCPCIA_INT_REQ(h));
+PRINTK("mcpcia_init: MCPCIA_INT_TARG 0x%x\n", *(vuip)MCPCIA_INT_TARG(h));
+PRINTK("mcpcia_init: MCPCIA_INT_ADR 0x%x\n", *(vuip)MCPCIA_INT_ADR(h));
+PRINTK("mcpcia_init: MCPCIA_INT_ADR_EXT 0x%x\n", *(vuip)MCPCIA_INT_ADR_EXT(h));
+PRINTK("mcpcia_init: MCPCIA_INT_MASK0 0x%x\n", *(vuip)MCPCIA_INT_MASK0(h));
+PRINTK("mcpcia_init: MCPCIA_INT_MASK1 0x%x\n", *(vuip)MCPCIA_INT_MASK1(h));
+PRINTK("mcpcia_init: MCPCIA_HBASE 0x%x\n", *(vuip)MCPCIA_HBASE(h));
+#endif
+
+        /* 
+        * Set up error reporting. Make sure CPU_PE is OFF in the mask.
+        */
+#if 0
+       mcpcia_err = *(vuip)MCPCIA_ERR_MASK(h);
+       mcpcia_err &= ~4;   
+       *(vuip)MCPCIA_ERR_MASK(h) = mcpcia_err;
+       mb();
+       mcpcia_err = *(vuip)MCPCIA_ERR_MASK;
+#endif
+
+       mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h);
+       mcpcia_err |= 0x0006;   /* master/target abort */
+       *(vuip)MCPCIA_CAP_ERR(h) = mcpcia_err;
+       mb() ;
+       mcpcia_err = *(vuip)MCPCIA_CAP_ERR(h);
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if (((*(vuip)MCPCIA_W0_BASE(h) & 3) == 1) &&
+           (*(vuip)MCPCIA_T0_BASE(h) == 0) &&
+           ((*(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U) > 0x0ff00000U))
+       {
+         MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W0_BASE(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W0_MASK(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("mcpcia_init: using Window 0 settings\n");
+         printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)MCPCIA_W0_BASE(h),
+                *(vuip)MCPCIA_W0_MASK(h),
+                *(vuip)MCPCIA_T0_BASE(h));
+#endif
+       }
+       else  /* check window 1 for enabled and mapped to 0 */
+       if (((*(vuip)MCPCIA_W1_BASE(h) & 3) == 1) &&
+           (*(vuip)MCPCIA_T1_BASE(h) == 0) &&
+           ((*(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U) > 0x0ff00000U))
+{
+         MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W1_BASE(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W1_MASK(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("mcpcia_init: using Window 1 settings\n");
+         printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)MCPCIA_W1_BASE(h),
+                *(vuip)MCPCIA_W1_MASK(h),
+                *(vuip)MCPCIA_T1_BASE(h));
+#endif
+       }
+       else  /* check window 2 for enabled and mapped to 0 */
+       if (((*(vuip)MCPCIA_W2_BASE(h) & 3) == 1) &&
+           (*(vuip)MCPCIA_T2_BASE(h) == 0) &&
+           ((*(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U) > 0x0ff00000U))
+       {
+         MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W2_BASE(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W2_MASK(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("mcpcia_init: using Window 2 settings\n");
+         printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)MCPCIA_W2_BASE(h),
+                *(vuip)MCPCIA_W2_MASK(h),
+                *(vuip)MCPCIA_T2_BASE(h));
+#endif
+       }
+       else  /* check window 3 for enabled and mapped to 0 */
+       if (((*(vuip)MCPCIA_W3_BASE(h) & 3) == 1) &&
+           (*(vuip)MCPCIA_T3_BASE(h) == 0) &&
+           ((*(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U) > 0x0ff00000U))
+       {
+         MCPCIA_DMA_WIN_BASE = *(vuip)MCPCIA_W3_BASE(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE = *(vuip)MCPCIA_W3_MASK(h) & 0xfff00000U;
+         MCPCIA_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("mcpcia_init: using Window 3 settings\n");
+         printk("mcpcia_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)MCPCIA_W3_BASE(h),
+                *(vuip)MCPCIA_W3_MASK(h),
+                *(vuip)MCPCIA_T3_BASE(h));
+#endif
+       }
+       else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+       {
+       /*
+        * Set up the PCI->physical memory translation windows.
+        * For now, windows 1,2 and 3 are disabled.  In the future, we may
+        * want to use them to do scatter/gather DMA.  Window 0
+        * goes at 1 GB and is 1 GB large.
+        */
+
+       *(vuip)MCPCIA_W0_BASE(h) = 1U | (MCPCIA_DMA_WIN_BASE & 0xfff00000U);
+       *(vuip)MCPCIA_W0_MASK(h) = (MCPCIA_DMA_WIN_SIZE - 1) & 0xfff00000U;
+       *(vuip)MCPCIA_T0_BASE(h) = 0;
+
+       *(vuip)MCPCIA_W1_BASE(h) = 0x0 ;
+       *(vuip)MCPCIA_W2_BASE(h) = 0x0 ;
+       *(vuip)MCPCIA_W3_BASE(h) = 0x0 ;
+
+       *(vuip)MCPCIA_HBASE(h) = 0x0 ;
+       mb();
+       }
+
+       /*
+        * check ASN in HWRPB for validity, report if bad
+        */
+       if (hwrpb->max_asn != MAX_ASN) {
+               printk("mcpcia_init: max ASN from HWRPB is bad (0x%lx)\n",
+                       hwrpb->max_asn);
+               hwrpb->max_asn = MAX_ASN;
+       }
+
+#if 0
+        {
+          unsigned int mcpcia_int_ctl = *((vuip)MCPCIA_INT_CTL(h));
+         printk("mcpcia_init: INT_CTL was 0x%x\n", mcpcia_int_ctl);
+          *(vuip)MCPCIA_INT_CTL(h) = 1U; mb();
+         mcpcia_int_ctl = *(vuip)MCPCIA_INT_CTL(h);
+        }
+#endif
+
+        {
+          unsigned int mcpcia_hae_mem = *(vuip)MCPCIA_HAE_MEM(h);
+          unsigned int mcpcia_hae_io = *(vuip)MCPCIA_HAE_IO(h);
+#if 0
+         printk("mcpcia_init: HAE_MEM was 0x%x\n", mcpcia_hae_mem);
+         printk("mcpcia_init: HAE_IO was 0x%x\n", mcpcia_hae_io);
+#endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+         /*
+           sigh... For the SRM setup, unless we know apriori what the HAE
+           contents will be, we need to setup the arbitrary region bases
+           so we can test against the range of addresses and tailor the
+           region chosen for the SPARSE memory access.
+
+           see include/asm-alpha/mcpcia.h for the SPARSE mem read/write
+         */
+         mcpcia_sm_base_r1 = (mcpcia_hae_mem      ) & 0xe0000000UL;/* reg 1 */
+         mcpcia_sm_base_r2 = (mcpcia_hae_mem << 16) & 0xf8000000UL;/* reg 2 */
+         mcpcia_sm_base_r3 = (mcpcia_hae_mem << 24) & 0xfc000000UL;/* reg 3 */
+         /*
+           Set the HAE cache, so that setup_arch() code
+           will use the SRM setting always. Our readb/writeb
+           code in mcpcia.h expects never to have to change
+           the contents of the HAE.
+          */
+         hae.cache = mcpcia_hae_mem;
+#else /* SRM_SETUP */
+          *(vuip)MCPCIA_HAE_MEM(h) = 0U; mb();
+         mcpcia_hae_mem = *(vuip)MCPCIA_HAE_MEM(h);
+          *(vuip)MCPCIA_HAE_IO(h) = 0; mb();
+         mcpcia_hae_io = *(vuip)MCPCIA_HAE_IO(h);
+#endif /* SRM_SETUP */
+        }
+    } /* end for-loop on hoses */
+    return mem_start;
+}
+
+int mcpcia_pci_clr_err(int h)
+{
+       unsigned int cpu = smp_processor_id();
+
+       MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h);
+#if 0
+       DBG_MCK(("MCPCIA_pci_clr_err: MCPCIA CAP_ERR(%d) after read 0x%x\n",
+            h, MCPCIA_jd[cpu]));
+#endif
+       *(vuip)MCPCIA_CAP_ERR(h) = 0xffffffff; mb(); /* clear them all */
+       MCPCIA_jd[cpu] = *(vuip)MCPCIA_CAP_ERR(h);
+       return 0;
+}
+
+static void
+mcpcia_print_uncorrectable(struct el_MCPCIA_uncorrected_frame_mcheck *logout)
+{
+  struct el_common_EV5_uncorrectable_mcheck *frame;
+  int i;
+
+  frame = &logout->procdata;
+
+  /* Print PAL fields */
+  for (i = 0; i < 24; i += 2) {
+    printk("\tpal temp[%d-%d]\t\t= %16lx %16lx\n\r",
+          i, i+1, frame->paltemp[i], frame->paltemp[i+1]);
+  }
+  for (i = 0; i < 8; i += 2) {
+    printk("\tshadow[%d-%d]\t\t= %16lx %16lx\n\r",
+          i, i+1, frame->shadow[i], 
+          frame->shadow[i+1]);
+  }
+  printk("\tAddr of excepting instruction\t= %16lx\n\r",
+        frame->exc_addr);
+  printk("\tSummary of arithmetic traps\t= %16lx\n\r",
+        frame->exc_sum);
+  printk("\tException mask\t\t\t= %16lx\n\r",
+        frame->exc_mask);
+  printk("\tBase address for PALcode\t= %16lx\n\r",
+        frame->pal_base);
+  printk("\tInterrupt Status Reg\t\t= %16lx\n\r",
+        frame->isr);
+  printk("\tCURRENT SETUP OF EV5 IBOX\t= %16lx\n\r",
+        frame->icsr);
+  printk("\tI-CACHE Reg %s parity error\t= %16lx\n\r",
+        (frame->ic_perr_stat & 0x800L) ? 
+        "Data" : "Tag", 
+        frame->ic_perr_stat); 
+  printk("\tD-CACHE error Reg\t\t= %16lx\n\r",
+        frame->dc_perr_stat);
+  if (frame->dc_perr_stat & 0x2) {
+    switch (frame->dc_perr_stat & 0x03c) {
+    case 8:
+      printk("\t\tData error in bank 1\n\r");
+      break;
+    case 4:
+      printk("\t\tData error in bank 0\n\r");
+      break;
+    case 20:
+      printk("\t\tTag error in bank 1\n\r");
+      break;
+    case 10:
+      printk("\t\tTag error in bank 0\n\r");
+      break;
+    }
+  }
+  printk("\tEffective VA\t\t\t= %16lx\n\r",
+        frame->va);
+  printk("\tReason for D-stream\t\t= %16lx\n\r",
+        frame->mm_stat);
+  printk("\tEV5 SCache address\t\t= %16lx\n\r",
+        frame->sc_addr);
+  printk("\tEV5 SCache TAG/Data parity\t= %16lx\n\r",
+        frame->sc_stat);
+  printk("\tEV5 BC_TAG_ADDR\t\t\t= %16lx\n\r",
+        frame->bc_tag_addr);
+  printk("\tEV5 EI_ADDR: Phys addr of Xfer\t= %16lx\n\r",
+        frame->ei_addr);
+  printk("\tFill Syndrome\t\t\t= %16lx\n\r",
+        frame->fill_syndrome);
+  printk("\tEI_STAT reg\t\t\t= %16lx\n\r",
+        frame->ei_stat);
+  printk("\tLD_LOCK\t\t\t\t= %16lx\n\r",
+        frame->ld_lock);
+}
+
+void mcpcia_machine_check(unsigned long type, unsigned long la_ptr,
+                        struct pt_regs * regs)
+{
+#if 0
+        printk("mcpcia machine check ignored\n") ;
+#else
+       struct el_common *mchk_header;
+       struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
+       unsigned int cpu = smp_processor_id();
+       int h = 0;
+
+       mchk_header = (struct el_common *)la_ptr;
+       mchk_logout = (struct el_MCPCIA_uncorrected_frame_mcheck *)la_ptr;
+
+#if 0
+       DBG_MCK(("mcpcia_machine_check: type=0x%lx la_ptr=0x%lx\n",
+            type, la_ptr));
+       DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+            regs->pc, mchk_header->size, mchk_header->proc_offset,
+            mchk_header->sys_offset));
+#endif
+       /*
+        * Check if machine check is due to a badaddr() and if so,
+        * ignore the machine check.
+        */
+       mb();
+       mb();  /* magic */
+       if (MCPCIA_mcheck_expected[cpu]) {
+#if 0
+               DBG_MCK(("MCPCIA machine check expected\n"));
+#endif
+               MCPCIA_mcheck_expected[cpu] = 0;
+               MCPCIA_mcheck_taken[cpu] = 1;
+               mb();
+               mb();  /* magic */
+               draina();
+               mcpcia_pci_clr_err(h);
+               wrmces(0x7);
+               mb();
+       }
+#if 1
+       else {
+               printk("MCPCIA machine check NOT expected on CPU %d\n", cpu);
+               DBG_MCK(("mcpcia_machine_check: type=0x%lx pc=0x%lx"
+                        " code=0x%lx\n",
+                        type, regs->pc, mchk_header->code));
+
+               MCPCIA_mcheck_expected[cpu] = 0;
+               MCPCIA_mcheck_taken[cpu] = 1;
+               mb();
+               mb();  /* magic */
+               draina();
+               mcpcia_pci_clr_err(h);
+               wrmces(0x7);
+               mb();
+#ifdef DEBUG_MCHECK_DUMP
+               if (type == 0x620)
+                 printk("MCPCIA machine check: system CORRECTABLE!\n");
+               else if (type == 0x630)
+                 printk("MCPCIA machine check: processor CORRECTABLE!\n");
+               else
+                 mcpcia_print_uncorrectable(mchk_logout);
+#endif /* DEBUG_MCHECK_DUMP */
+       }
+#endif
+#endif
+}
+
+/*==========================================================================*/
+
+#define PRIMARY(b) ((b)&0xff)
+#define SECONDARY(b) (((b)>>8)&0xff)
+#define SUBORDINATE(b) (((b)>>16)&0xff)
+
+static int
+hose_scan_bridges(struct linux_hose_info *hose, unsigned char bus)
+{
+       unsigned int devfn, l, class;
+       unsigned char hdr_type = 0;
+       unsigned int found = 0;
+
+       for (devfn = 0; devfn < 0xff; ++devfn) {
+               if (PCI_FUNC(devfn) == 0) {
+                       hose_read_config_byte(hose, bus, devfn,
+                                             PCI_HEADER_TYPE, &hdr_type);
+               } else if (!(hdr_type & 0x80)) {
+                       /* not a multi-function device */
+                       continue;
+               }
+
+               /* Check if there is anything here. */
+               hose_read_config_dword(hose, bus, devfn, PCI_VENDOR_ID, &l);
+               if (l == 0xffffffff || l == 0x00000000) {
+                       hdr_type = 0;
+                       continue;
+               }
+
+               /* See if this is a bridge device. */
+               hose_read_config_dword(hose, bus, devfn,
+                                      PCI_CLASS_REVISION, &class);
+
+               if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+                       unsigned int busses;
+
+                       found++;
+
+                       hose_read_config_dword(hose, bus, devfn,
+                                              PCI_PRIMARY_BUS, &busses);
+
+DBG_PCI(("hose_scan_bridges: hose %d bus %d slot %d busses 0x%x\n",
+       hose->pci_hose_index, bus, PCI_SLOT(devfn), busses));
+                       /*
+                        * do something with first_busno and last_busno
+                        */
+                       if (hose->pci_first_busno > PRIMARY(busses)) {
+                               hose->pci_first_busno = PRIMARY(busses);
+DBG_PCI(("hose_scan_bridges: hose %d bus %d slot %d change first to %d\n",
+       hose->pci_hose_index, bus, PCI_SLOT(devfn), PRIMARY(busses)));
+                       }
+                       if (hose->pci_last_busno < SUBORDINATE(busses)) {
+                               hose->pci_last_busno = SUBORDINATE(busses);
+DBG_PCI(("hose_scan_bridges: hose %d bus %d slot %d change last to %d\n",
+       hose->pci_hose_index, bus, PCI_SLOT(devfn), SUBORDINATE(busses)));
+                       }
+                       /*
+                        * Now scan everything underneath the bridge.
+                        */
+                       hose_scan_bridges(hose, SECONDARY(busses));
+               }
+       }
+       return found;
+}
+
+static void
+hose_reconfigure_bridges(struct linux_hose_info *hose, unsigned char bus)
+{
+       unsigned int devfn, l, class;
+       unsigned char hdr_type = 0;
+
+       for (devfn = 0; devfn < 0xff; ++devfn) {
+               if (PCI_FUNC(devfn) == 0) {
+                       hose_read_config_byte(hose, bus, devfn,
+                                             PCI_HEADER_TYPE, &hdr_type);
+               } else if (!(hdr_type & 0x80)) {
+                       /* not a multi-function device */
+                       continue;
+               }
+
+               /* Check if there is anything here. */
+               hose_read_config_dword(hose, bus, devfn, PCI_VENDOR_ID, &l);
+               if (l == 0xffffffff || l == 0x00000000) {
+                       hdr_type = 0;
+                       continue;
+               }
+
+               /* See if this is a bridge device. */
+               hose_read_config_dword(hose, bus, devfn,
+                                      PCI_CLASS_REVISION, &class);
+
+               if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+                       unsigned int busses;
+
+                       hose_read_config_dword(hose, bus, devfn,
+                                              PCI_PRIMARY_BUS, &busses);
+
+                       /*
+                        * First reconfigure everything underneath the bridge.
+                        */
+                       hose_reconfigure_bridges(hose, (busses >> 8) & 0xff);
+
+                       /*
+                        * Unconfigure this bridges bus numbers,
+                        * pci_scan_bus() will fix this up properly.
+                        */
+                       busses &= 0xff000000;
+                       hose_write_config_dword(hose, bus, devfn,
+                                               PCI_PRIMARY_BUS, busses);
+               }
+       }
+}
+
+static void mcpcia_fixup_busno(struct linux_hose_info *hose, unsigned char bus)
+{
+       unsigned int nbus;
+
+       /*
+        * First, scan for all bridge devices underneath this hose,
+        * to determine the first and last busnos.
+        */
+       if (!hose_scan_bridges(hose, 0)) {
+               /* none found, exit */
+               hose->pci_first_busno = bus;
+               hose->pci_last_busno = bus;
+       } else {
+               /*
+                * Reconfigure all bridge devices underneath this hose.
+                */
+               hose_reconfigure_bridges(hose, hose->pci_first_busno);
+       }
+
+       /*
+        * Now reconfigure the hose to it's new bus number and set up
+        * our bus2hose mapping for this hose.
+        */
+       nbus = hose->pci_last_busno - hose->pci_first_busno;
+
+       hose->pci_first_busno = bus;
+
+DBG_PCI(("mcpcia_fixup_busno: hose %d startbus %d nbus %d\n",
+       hose->pci_hose_index, bus, nbus));
+
+       do {
+               bus2hose[bus++] = hose;
+       } while (nbus-- > 0);
+}
+
+static void mcpcia_probe(struct linux_hose_info *hose,
+                        unsigned long *mem_start)
+{
+       static struct pci_bus *pchain = NULL;
+       struct pci_bus *pbus = &hose->pci_bus;
+       static unsigned char busno = 0;
+
+       /* Hoses include child PCI bridges in bus-range property,
+        * but we don't scan each of those ourselves, Linux generic PCI
+        * probing code will find child bridges and link them into this
+        * hose's root PCI device hierarchy.
+        */
+
+       pbus->number = pbus->secondary = busno;
+       pbus->sysdata = hose;
+
+       mcpcia_fixup_busno(hose, busno);
+
+       pbus->subordinate = pci_scan_bus(pbus, mem_start); /* the original! */
+
+       /*
+        * Set the maximum subordinate bus of this hose.
+        */
+       hose->pci_last_busno = pbus->subordinate;
+#if 0
+       hose_write_config_byte(hose, busno, 0, 0x41, hose->pci_last_busno);
+#endif
+       busno = pbus->subordinate + 1;
+
+       /*
+        * Fixup the chain of primary PCI busses.
+        */
+       if (pchain) {
+               pchain->next = &hose->pci_bus;
+               pchain = pchain->next;
+       } else {
+               pchain = &pci_root;
+               memcpy(pchain, &hose->pci_bus, sizeof(pci_root));
+       }
+}
+
+unsigned long mcpcia_fixup(unsigned long memory_start,
+                          unsigned long memory_end)
+{
+       struct linux_hose_info *hose;
+
+       /* turn on Config space access finally! */
+       pci_probe_enabled = 1;
+
+       /* for each hose, probe and setup the devices on the hose */
+       for (hose = mcpcia_root; hose; hose = hose->next) {
+               mcpcia_probe(hose, &memory_start);
+       }
+
+       return memory_start;
+}
+#endif /* CONFIG_ALPHA_MCPCIA */
index f8146c5..401a7af 100644 (file)
@@ -66,10+66,49 @@ asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
        unsigned long a3, unsigned long a4, unsigned long a5,
        struct pt_regs regs)
 {
+#if !defined(CONFIG_ALPHA_TSUNAMI)
        (&regs)->hae = hae;
+#endif
        return 0;
 }
 
+#ifdef __SMP__
+/* This is being executed in task 0 'user space'. */
+#define resched_needed() 1
+int cpu_idle(void *unused)
+{
+       extern volatile int smp_commenced;
+
+       current->priority = -100;
+       while (1) {
+               /*
+                * 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;
+               if (!smp_commenced || resched_needed()) {
+                       schedule();
+               }
+       }
+}
+
+asmlinkage int sys_idle(void)
+{
+        if(current->pid != 0)
+                return -EPERM;
+
+        cpu_idle(NULL);
+        return 0;
+}
+
+#else /* __SMP__ */
+
 asmlinkage int sys_idle(void)
 {
        int ret = -EPERM;
@@ -88,6+127,12 @@ out:
        unlock_kernel();
        return ret;
 }
+#endif /* __SMP__ */
+
+#if defined(CONFIG_ALPHA_SRM_SETUP)
+extern void reset_for_srm(void);       
+extern unsigned long srm_hae;
+#endif
 
 static void finish_shutdown(void)
 {
@@ -96,8+141,8 @@ static void finish_shutdown(void)
        unsigned long flags;
 
        /* i'm not sure if i really need to disable interrupts here */
-       save_flags(flags);
-       cli();
+       save_and_cli(flags);
+
        /* reset periodic interrupt frequency */
         CMOS_WRITE(0x26, RTC_FREQ_SELECT);
 
@@ -131,6+176,10 @@ void machine_restart(char * __unused)
 /*     flags |=  0x0000000000030000UL; *//* this is "warm bootstrap" */
        cpup->flags = flags;                                           
        mb();                                           
+#if defined(CONFIG_ALPHA_SRM_SETUP)
+       reset_for_srm();
+       set_hae(srm_hae);
+#endif
 #endif /* SRM */                                        
 
        finish_shutdown();
@@ -150,6+199,10 @@ void machine_halt(void)
        flags |=  0x0000000000040000UL; /* this is "remain halted" */
        cpup->flags = flags;                                           
        mb();                                           
+#if defined(CONFIG_ALPHA_SRM_SETUP)
+       reset_for_srm();
+       set_hae(srm_hae);
+#endif
 
        finish_shutdown();
 #endif /* SRM */                                        
@@ -228,6+281,7 @@ int alpha_clone(unsigned long clone_flags, unsigned long usp,
 }
 
 extern void ret_from_sys_call(void);
+extern void ret_from_smpfork(void);
 /*
  * Copy an alpha thread..
  *
@@ -258,7+312,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        stack = ((struct switch_stack *) regs) - 1;
        childstack = ((struct switch_stack *) childregs) - 1;
        *childstack = *stack;
+#ifdef __SMP__
+       childstack->r26 = (unsigned long) ret_from_smpfork;
+#else
        childstack->r26 = (unsigned long) ret_from_sys_call;
+#endif
        p->tss.usp = usp;
        p->tss.ksp = (unsigned long) childstack;
        p->tss.pal_flags = 1;   /* set FEN, clear everything else */
index b4c5d18..c776414 100644 (file)
 #include <asm/ptrace.h>
 #include <asm/mmu_context.h>
 
-/* NOTE: Herein are back-to-back mb insns.  They are magic.
-   A plausible explanation is that the i/o controler does not properly
+/* NOTE: Herein are back-to-back mb instructions.  They are magic.
+   One plausible explanation is that the I/O controller does not properly
    handle the system transaction.  Another involves timing.  Ho hum.  */
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern int alpha_sys_type;
 
 /*
  * BIOS32-style PCI interface:
@@ -38,6+37,7 @@ extern int alpha_sys_type;
 #define DEBUG_MCHECK
 #ifdef DEBUG_MCHECK
 # define DBG_MCK(args) printk args
+#define DEBUG_MCHECK_DUMP
 #else
 # define DBG_MCK(args)
 #endif
@@ -49,6+49,11 @@ static volatile unsigned int PYXIS_mcheck_expected = 0;
 static volatile unsigned int PYXIS_mcheck_taken = 0;
 static unsigned int PYXIS_jd;
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int PYXIS_DMA_WIN_BASE = PYXIS_DMA_WIN_BASE_DEFAULT;
+unsigned int PYXIS_DMA_WIN_SIZE = PYXIS_DMA_WIN_SIZE_DEFAULT;
+unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -129,24+134,23 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
 static unsigned int conf_read(unsigned long addr, unsigned char type1)
 {
        unsigned long flags;
-       unsigned int stat0, value;
+       unsigned int stat0, value, temp;
        unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
 
-       save_flags(flags);      /* avoid getting hit by machine check */
-       cli();
+       save_and_cli(flags);    /* avoid getting hit by machine check */
 
        DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 
        /* reset status register to avoid losing errors: */
        stat0 = *(vuip)PYXIS_ERR;
-       *(vuip)PYXIS_ERR = stat0;
-       mb();
+       *(vuip)PYXIS_ERR = stat0; mb();
+       temp = *(vuip)PYXIS_ERR;  /* re-read to force write */
        DBG(("conf_read: PYXIS ERR was 0x%x\n", stat0));
        /* if Type1 access, must set PYXIS CFG */
        if (type1) {
                pyxis_cfg = *(vuip)PYXIS_CFG;
-               *(vuip)PYXIS_CFG = pyxis_cfg | 1;
-               mb();
+               *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb();
+               temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
                DBG(("conf_read: TYPE1 access\n"));
        }
 
@@ -166,36+170,11 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
        }
        PYXIS_mcheck_expected = 0;
        mb();
-       /*
-        * david.rusling@reo.mts.dec.com.  This code is needed for the
-        * EB64+ as it does not generate a machine check (why I don't
-        * know).  When we build kernels for one particular platform
-        * then we can make this conditional on the type.
-        */
-#if 0
-       draina();
-
-       /* now look for any errors */
-       stat0 = *(vuip)PYXIS_IOC_PYXIS_ERR;
-       DBG(("conf_read: PYXIS ERR after read 0x%x\n", stat0));
-       if (stat0 & 0x8280U) { /* is any error bit set? */
-               /* if not NDEV, print status */
-               if (!(stat0 & 0x0080)) {
-                       printk("PYXIS.c:conf_read: got stat0=%x\n", stat0);
-               }
-
-               /* reset error status: */
-               *(vulp)PYXIS_IOC_PYXIS_ERR = stat0;
-               mb();
-               wrmces(0x7);                    /* reset machine check */
-               value = 0xffffffff;
-       }
-#endif
 
        /* if Type1 access, must reset IOC CFG so normal IO space ops work */
        if (type1) {
-               *(vuip)PYXIS_CFG = pyxis_cfg & ~1;
-               mb();
+               *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb();
+               temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
        }
 
        DBG(("conf_read(): finished\n"));
@@ -209,22+188,21 @@ static void conf_write(unsigned long addr, unsigned int value,
                       unsigned char type1)
 {
        unsigned long flags;
-       unsigned int stat0;
+       unsigned int stat0, temp;
        unsigned int pyxis_cfg = 0; /* to keep gcc quiet */
 
-       save_flags(flags);      /* avoid getting hit by machine check */
-       cli();
+       save_and_cli(flags);    /* avoid getting hit by machine check */
 
        /* reset status register to avoid losing errors: */
        stat0 = *(vuip)PYXIS_ERR;
-       *(vuip)PYXIS_ERR = stat0;
-       mb();
+       *(vuip)PYXIS_ERR = stat0; mb();
+       temp = *(vuip)PYXIS_ERR;  /* re-read to force write */
        DBG(("conf_write: PYXIS ERR was 0x%x\n", stat0));
        /* if Type1 access, must set PYXIS CFG */
        if (type1) {
                pyxis_cfg = *(vuip)PYXIS_CFG;
-               *(vuip)PYXIS_CFG = pyxis_cfg | 1;
-               mb();
+               *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb();
+               temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
                DBG(("conf_read: TYPE1 access\n"));
        }
 
@@ -235,13+213,14 @@ static void conf_write(unsigned long addr, unsigned int value,
        *(vuip)addr = value;
        mb();
        mb();  /* magic */
+       temp = *(vuip)PYXIS_ERR; /* do a PYXIS read to force the write */
        PYXIS_mcheck_expected = 0;
        mb();
 
        /* if Type1 access, must reset IOC CFG so normal IO space ops work */
        if (type1) {
-               *(vuip)PYXIS_CFG = pyxis_cfg & ~1;
-               mb();
+               *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb();
+               temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
        }
 
        DBG(("conf_write(): finished\n"));
@@ -367,19+346,105 @@ unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end)
 {
        unsigned int pyxis_err ;
 
+#if 0
+printk("pyxis_init: PYXIS_ERR_MASK 0x%x\n", *(vuip)PYXIS_ERR_MASK);
+printk("pyxis_init: PYXIS_ERR 0x%x\n", *(vuip)PYXIS_ERR);
+
+printk("pyxis_init: PYXIS_INT_REQ 0x%lx\n", *(vulp)PYXIS_INT_REQ);
+printk("pyxis_init: PYXIS_INT_MASK 0x%lx\n", *(vulp)PYXIS_INT_MASK);
+printk("pyxis_init: PYXIS_INT_ROUTE 0x%lx\n", *(vulp)PYXIS_INT_ROUTE);
+printk("pyxis_init: PYXIS_INT_HILO 0x%lx\n", *(vulp)PYXIS_INT_HILO);
+printk("pyxis_init: PYXIS_INT_CNFG 0x%x\n", *(vuip)PYXIS_INT_CNFG);
+printk("pyxis_init: PYXIS_RT_COUNT 0x%lx\n", *(vulp)PYXIS_RT_COUNT);
+#endif
+
        /* 
-        * Set up error reporting.
+        * Set up error reporting. Make sure CPU_PE is OFF in the mask.
         */
+       pyxis_err = *(vuip)PYXIS_ERR_MASK;
+       pyxis_err &= ~4;   
+       *(vuip)PYXIS_ERR_MASK = pyxis_err; mb();
+       pyxis_err = *(vuip)PYXIS_ERR_MASK;  /* re-read to force write */
+
        pyxis_err = *(vuip)PYXIS_ERR ;
        pyxis_err |= 0x180;   /* master/target abort */
-       *(vuip)PYXIS_ERR = pyxis_err ;
-       mb() ;
-       pyxis_err = *(vuip)PYXIS_ERR ;
-
-#ifdef CONFIG_ALPHA_RUFFIAN
-       printk("pyxis_init: Skipping window register rewrites --"
+       *(vuip)PYXIS_ERR = pyxis_err; mb();
+       pyxis_err = *(vuip)PYXIS_ERR;  /* re-read to force write */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W0_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T0_BASE == 0) &&
+           ((*(vuip)PYXIS_W0_MASK & 0xfff00000U) > 0x0ff00000U))
+       {
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W0_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W0_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 0 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W0_BASE,
+                *(vuip)PYXIS_W0_MASK,
+                *(vuip)PYXIS_T0_BASE);
+#endif
+       }
+       else  /* check window 1 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W1_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T1_BASE == 0) &&
+           ((*(vuip)PYXIS_W1_MASK & 0xfff00000U) > 0x0ff00000U))
+{
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W1_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W1_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 1 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W1_BASE,
+                *(vuip)PYXIS_W1_MASK,
+                *(vuip)PYXIS_T1_BASE);
+#endif
+       }
+       else  /* check window 2 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W2_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T2_BASE == 0) &&
+           ((*(vuip)PYXIS_W2_MASK & 0xfff00000U) > 0x0ff00000U))
+       {
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W2_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W2_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 2 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W2_BASE,
+                *(vuip)PYXIS_W2_MASK,
+                *(vuip)PYXIS_T2_BASE);
+#endif
+       }
+       else  /* check window 3 for enabled and mapped to 0 */
+       if (((*(vuip)PYXIS_W3_BASE & 3) == 1) &&
+           (*(vuip)PYXIS_T3_BASE == 0) &&
+           ((*(vuip)PYXIS_W3_MASK & 0xfff00000U) > 0x0ff00000U))
+       {
+         PYXIS_DMA_WIN_BASE = *(vuip)PYXIS_W3_BASE & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE = *(vuip)PYXIS_W3_MASK & 0xfff00000U;
+         PYXIS_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("pyxis_init: using Window 3 settings\n");
+         printk("pyxis_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vuip)PYXIS_W3_BASE,
+                *(vuip)PYXIS_W3_MASK,
+                *(vuip)PYXIS_T3_BASE);
+#endif
+       }
+       else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+       {
+#if defined(CONFIG_ALPHA_RUFFIAN)
+#if 1
+       printk("pyxis_init: skipping window register rewrites... "
               " trust DeskStation firmware!\n");
-#else
+#endif
+#else /* RUFFIAN */
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, windows 1,2 and 3 are disabled.  In the future, we may
@@ -395,7+460,8 @@ unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end)
        *(vuip)PYXIS_W2_BASE = 0x0 ;
        *(vuip)PYXIS_W3_BASE = 0x0 ;
        mb();
-#endif
+#endif /* RUFFIAN */
+       }
 
        /*
         * check ASN in HWRPB for validity, report if bad
@@ -407,18+473,21 @@ unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end)
        }
 
        /*
-        * Finally, clear the PYXIS_CFG register, which gets used
+         * Next, clear the PYXIS_CFG register, which gets used
         *  for PCI Config Space accesses. That is the way
         *  we want to use it, and we do not want to depend on
         *  what ARC or SRM might have left behind...
         */
        {
-               unsigned int pyxis_cfg;
+          unsigned int pyxis_cfg, temp;
                pyxis_cfg = *(vuip)PYXIS_CFG; mb();
-#if 0
+         if (pyxis_cfg != 0) {
+#if 1
                printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg);
 #endif
                *(vuip)PYXIS_CFG = 0; mb();
+           temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
+         }
        }
  
        {
@@ -428,10+497,48 @@ unsigned long pyxis_init(unsigned long mem_start, unsigned long mem_end)
                printk("PYXIS_init: HAE_MEM was 0x%x\n", pyxis_hae_mem);
                printk("PYXIS_init: HAE_IO was 0x%x\n", pyxis_hae_io);
 #endif
-               *(vuip)PYXIS_HAE_MEM = 0; mb();
-               pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM;
+#ifdef CONFIG_ALPHA_SRM_SETUP
+         /*
+          * sigh... For the SRM setup, unless we know apriori what the HAE
+          * contents will be, we need to setup the arbitrary region bases
+          * so we can test against the range of addresses and tailor the
+          * region chosen for the SPARSE memory access.
+          * 
+          * see include/asm-alpha/pyxis.h for the SPARSE mem read/write
+         */
+         pyxis_sm_base_r1 = (pyxis_hae_mem      ) & 0xe0000000UL;/* region 1 */
+         pyxis_sm_base_r2 = (pyxis_hae_mem << 16) & 0xf8000000UL;/* region 2 */
+         pyxis_sm_base_r3 = (pyxis_hae_mem << 24) & 0xfc000000UL;/* region 3 */
+
+         /*
+           Set the HAE cache, so that setup_arch() code
+           will use the SRM setting always. Our readb/writeb
+           code in pyxis.h expects never to have to change
+           the contents of the HAE.
+          */
+         hae.cache = pyxis_hae_mem;
+#else /* SRM_SETUP */
+          *(vuip)PYXIS_HAE_MEM = 0U; mb();
+         pyxis_hae_mem = *(vuip)PYXIS_HAE_MEM;  /* re-read to force write */
                *(vuip)PYXIS_HAE_IO = 0; mb();
-               pyxis_hae_io = *(vuip)PYXIS_HAE_IO;
+         pyxis_hae_io = *(vuip)PYXIS_HAE_IO;  /* re-read to force write */
+#endif /* SRM_SETUP */
+        }
+
+       /*
+        * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for
+        * enabling byte/word PCI bus space(s) access.
+        */
+       {
+         unsigned int ctrl1;
+         ctrl1 = *(vuip) PYXIS_CTRL1;
+         if (!(ctrl1 & 1)) {
+#if 1
+           printk("PYXIS_init: enabling byte/word PCI space\n");
+#endif
+           *(vuip) PYXIS_CTRL1 = ctrl1 | 1; mb();
+           ctrl1 = *(vuip)PYXIS_CTRL1;  /* re-read to force write */
+         }
        }
 
        return mem_start;
@@ -441,9+548,8 @@ int pyxis_pci_clr_err(void)
 {
        PYXIS_jd = *(vuip)PYXIS_ERR;
        DBG(("PYXIS_pci_clr_err: PYXIS ERR after read 0x%x\n", PYXIS_jd));
-       *(vuip)PYXIS_ERR = 0x0180;
-       mb();
-       PYXIS_jd = *(vuip)PYXIS_ERR;
+       *(vuip)PYXIS_ERR = 0x0180; mb();
+       PYXIS_jd = *(vuip)PYXIS_ERR;  /* re-read to force write */
        return 0;
 }
 
@@ -486,7+592,7 @@ void pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
         */
        mb();
        mb();  /* magic */
-       if (PYXIS_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+       if (PYXIS_mcheck_expected) {
                DBG(("PYXIS machine check expected\n"));
                PYXIS_mcheck_expected = 0;
                PYXIS_mcheck_taken = 1;
@@ -502,7+608,8 @@ void pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
                printk("PYXIS machine check NOT expected\n") ;
                DBG_MCK(("pyxis_machine_check: vector=0x%lx la_ptr=0x%lx\n",
                         vector, la_ptr));
-               DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+               DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x"
+                        " sysoffset 0x%x\n",
                         regs->pc, mchk_header->size, mchk_header->proc_offset,
                         mchk_header->sys_offset));
                PYXIS_mcheck_expected = 0;
index 9ce9c1f..c69b11e 100644 (file)
 #include <linux/delay.h>
 #include <linux/config.h>      /* CONFIG_ALPHA_LCA etc */
 #include <linux/ioport.h>
+#include <linux/mc146818rtc.h>
 
 #ifdef CONFIG_RTC
 #include <linux/timex.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 
+extern void setup_smp(void);
+extern char *smp_info(void);
+
+#if 1
+# define DBG_SRM(args)         printk args
+#else
+# define DBG_SRM(args)
+#endif
+
 struct hae hae = {
        0,
        (unsigned long*) HAE_ADDRESS
 };
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned long srm_hae;
+#endif
+
 struct hwrpb_struct *hwrpb;
 
 unsigned char aux_device_present = 0xaa;
@@ -106,12+120,13 @@ static void init_pit (void)
     outb(LATCH & 0xff, 0x40); /* LSB */
     outb(LATCH >> 8, 0x40); /* MSB */
     request_region(0x40, 0x20, "timer"); /* reserve pit */
-#else
-#ifndef CONFIG_ALPHA_RUFFIAN
+#else /* RTC */
+#if !defined(CONFIG_ALPHA_RUFFIAN)
+    /* Ruffian depends on the system timer established in MILO!! */
     outb(0x36, 0x43);  /* counter 0: system timer */
     outb(0x00, 0x40);
     outb(0x00, 0x40);
-#endif
+#endif /* RUFFIAN */
     request_region(0x70, 0x10, "timer"); /* reserve rtc */
 #endif /* RTC */
 
@@ -148,9+163,21 @@ void setup_arch(char **cmdline_p,
 
        init_pit();
 
+       if ((CMOS_READ(RTC_FREQ_SELECT) & 0x3f) != 0x26) {
+         printk("setup_arch: setting RTC_FREQ to 1024/sec\n");
+         CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+       }
+
        hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
 
+#if !defined(CONFIG_ALPHA_TSUNAMI)
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       srm_hae = *hae.reg; /* save SRM setting for restoration */
+       DBG_SRM(("setup_arch: old HAE base: 0x%016lx\n", srm_hae));
+#endif /* SRM_SETUP */
        set_hae(hae.cache);     /* sync HAE register w/hae_cache */
+#endif /* !TSUNAMI */
+
        wrmces(0x7);            /* reset enable correctable error reports */
 
        ROOT_DEV = to_kdev_t(0x0802);           /* sda2 */
@@ -185,12+212,54 @@ void setup_arch(char **cmdline_p,
        *memory_start_p = pyxis_init(*memory_start_p, *memory_end_p);
 #elif defined(CONFIG_ALPHA_T2)
        *memory_start_p = t2_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_TSUNAMI)
+       *memory_start_p = tsunami_init(*memory_start_p, *memory_end_p);
+#elif defined(CONFIG_ALPHA_MCPCIA)
+       *memory_start_p = mcpcia_init(*memory_start_p, *memory_end_p);
+#endif
+
+#ifdef __SMP__
+       setup_smp();
 #endif
 }
 
 
 #define N(a) (sizeof(a)/sizeof(a[0]))
 
+/* A change was made to the HWRPB via an ECO and the following code tracks
+ * a part of the ECO.  The HWRPB version must be 5 or higher or the ECO
+ * was not implemented in the console firmware.  If its at rev 5 or greater
+ * we can get the platform ascii string name from the HWRPB.  Thats what this
+ * function does.  It checks the rev level and if the string is in the HWRPB
+ * it returns the addtess of the string ... a pointer to the platform name.
+ *
+ * Returns:
+ *      - Pointer to a ascii string if its in the HWRPB
+ *      - Pointer to a blank string if the data is not in the HWRPB.
+ */
+static char *
+platform_string(void)
+{
+       struct dsr_struct *dsr;
+       static char unk_system_string[] = "N/A";
+
+        /* Go to the console for the string pointer.
+         * If the rpb_vers is not 5 or greater the rpb
+        * is old and does not have this data in it.
+        */
+        if (hwrpb->revision < 5)
+               return (unk_system_string);
+       else {
+               /* The Dynamic System Recognition struct
+                * has the system platform name starting
+                * after the character count of the string.
+                */
+               dsr =  ((struct dsr_struct *)
+                         ((char *)hwrpb + hwrpb->dsr_offset));
+               return ((char *)dsr + (dsr->sysname_off +
+                                                sizeof(long)));
+        }
+}
 
 static void
 get_sysnames(long type, long variation,
@@ -222,6+291,10 @@ get_sysnames(long type, long variation,
        static char * eb66_names[] = {"EB66", "EB66+"};
        static int eb66_indices[] = {0,0,1};
 
+       static char * rawhide_names[] = {"Dodge", "Wrangler", "Durango",
+                                        "Tincup", "DaVinci"};
+       static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
+
        long member;
 
        /* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */
@@ -249,7+322,9 @@ get_sysnames(long type, long variation,
 
        member = (variation >> 10) & 0x3f; /* member ID is a bit-field */
 
-       switch (type) {
+       switch (type) { /* select by family */
+       default: /* default to variation "0" for now */
+               break;
        case ST_DEC_EB164:
                if (member < N(eb164_indices))
                        *variation_name = eb164_names[eb164_indices[member]];
@@ -266,7+341,11 @@ get_sysnames(long type, long variation,
                if (member < N(eb66_indices))
                        *variation_name = eb66_names[eb66_indices[member]];
                break;
-       }
+       case ST_DEC_RAWHIDE:
+               if (member < N(rawhide_indices))
+                 *variation_name = rawhide_names[rawhide_indices[member]];
+               break;
+       } /* end family switch */
 }
 
 /*
@@ -315,7+394,12 @@ int get_cpuinfo(char *buffer)
                       "max. addr. space #\t: %ld\n"
                       "BogoMIPS\t\t: %lu.%02lu\n"
                       "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
-                      "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n",
+                      "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n"
+                      "platform string\t: %s\n"
+#ifdef __SMP__
+                      "%s"
+#endif
+                      ,
 
                       cpu_name, cpu->variation, cpu->revision,
                       (char*)cpu->serial_no,
@@ -329,5+413,10 @@ int get_cpuinfo(char *buffer)
                       hwrpb->max_asn,
                       loops_per_sec / 500000, (loops_per_sec / 5000) % 100,
                       unaligned[0].count, unaligned[0].pc, unaligned[0].va,
-                      unaligned[1].count, unaligned[1].pc, unaligned[1].va);
+                      unaligned[1].count, unaligned[1].pc, unaligned[1].va,
+                      platform_string()
+#ifdef __SMP__
+                      , smp_info()
+#endif
+                      );
 }
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
new file mode 100644 (file)
index 0000000..8654474
--- /dev/null
@@ -0,0 +1,1096 @@
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/tasks.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
+#define __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
+
+struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
+
+struct cpuinfo_alpha cpu_data[NR_CPUS];
+
+/* Processor holding kernel spinlock */
+klock_info_t klock_info = { KLOCK_CLEAR, 0 };
+
+spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+
+unsigned int boot_cpu_id = 0;
+static int smp_activated = 0;
+
+int smp_found_config = 0; /* Have we found an SMP box */
+static int max_cpus = -1;
+
+unsigned int cpu_present_map = 0;
+
+int smp_num_cpus = 1;
+int smp_num_probed = 0; /* Internal processor count */
+
+int smp_threads_ready = 0;
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
+volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
+
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
+
+volatile int ipi_bits[NR_CPUS];
+
+unsigned long boot_cpu_palrev;
+
+volatile int smp_commenced = 0;
+volatile int smp_processors_ready = 0;
+
+volatile int cpu_number_map[NR_CPUS];
+volatile int cpu_logical_map[NR_CPUS];
+
+extern int cpu_idle(void *unused);
+extern void calibrate_delay(void);
+extern struct hwrpb_struct *hwrpb;
+extern struct thread_struct * original_pcb_ptr;
+extern void __start_cpu(unsigned long);
+
+static void smp_setup_percpu_timer(void);
+static void secondary_cpu_start(int, struct task_struct *);
+static void send_cpu_msg(char *, int);
+
+/* process bootcommand SMP options, like "nosmp" and "maxcpus=" */
+__initfunc(void smp_setup(char *str, int *ints))
+{
+       if (ints && ints[0] > 0)
+               max_cpus = ints[1];
+        else
+               max_cpus = 0;
+}
+
+void smp_store_cpu_info(int id)
+{
+       /* This is it on Alpha, so far. */
+        cpu_data[id].loops_per_sec = loops_per_sec;
+}
+
+void smp_commence(void)
+{
+       /* Lets the callin's below out of their loop. */
+       mb();
+       smp_commenced = 1;
+}
+
+void smp_callin(void)
+{
+        int cpuid = hard_smp_processor_id();
+
+#if 0
+       printk("CALLIN %d state 0x%lx\n", cpuid, current->state);
+#endif
+#ifdef HUH
+        local_flush_cache_all();
+        local_flush_tlb_all();
+#endif
+#if 0
+        set_irq_udt(mid_xlate[boot_cpu_id]);
+#endif
+
+        /* Get our local ticker going. */
+        smp_setup_percpu_timer();
+
+#if 0
+        calibrate_delay();
+#endif
+        smp_store_cpu_info(cpuid);
+#ifdef HUH
+        local_flush_cache_all();
+        local_flush_tlb_all();
+#endif
+
+        /* Allow master to continue. */
+        set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]);
+#ifdef HUH
+        local_flush_cache_all();
+        local_flush_tlb_all();
+#endif
+
+#ifdef NOT_YET
+        while(!task[cpuid] || current_set[cpuid] != task[cpuid])
+                barrier();
+#endif /* NOT_YET */
+
+#if 0
+        /* Fix idle thread fields. */
+        __asm__ __volatile__("ld [%0], %%g6\n\t"
+                             : : "r" (&current_set[cpuid])
+                             : "memory" /* paranoid */);
+        current->mm->mmap->vm_page_prot = PAGE_SHARED;
+        current->mm->mmap->vm_start = PAGE_OFFSET;
+        current->mm->mmap->vm_end = init_task.mm->mmap->vm_end;
+#endif
+        
+#ifdef HUH
+        local_flush_cache_all();
+        local_flush_tlb_all();
+#endif
+#if 0
+        __sti();
+#endif
+}
+
+asmlinkage int start_secondary(void *unused)
+{
+       extern asmlinkage void entInt(void);
+       extern void paging_init_secondary(void);
+
+       wrmces(7);
+       paging_init_secondary();
+       trap_init();
+       wrent(entInt, 0);
+
+        smp_callin();
+        while (!smp_commenced)
+               barrier();
+#if 1
+printk("start_secondary: commencing CPU %d current %p\n",
+       hard_smp_processor_id(), current);
+#endif
+        return cpu_idle(NULL);
+}
+
+/*
+ *      Cycle through the processors sending START msgs to boot each.
+ */
+void smp_boot_cpus(void)
+{
+        int cpucount = 0;
+        int i, first, prev;
+
+        printk("smp_boot_cpus: Entering SMP Mode...\n");
+
+#if 0
+        __sti();
+#endif
+
+        for(i=0; i < NR_CPUS; i++) {
+               cpu_number_map[i] = -1;
+               cpu_logical_map[i] = -1;
+                prof_counter[i] = 1;
+                prof_multiplier[i] = 1;
+               ipi_bits[i] = 0;
+       }
+
+       cpu_number_map[boot_cpu_id] = 0;
+       cpu_logical_map[0] = boot_cpu_id;
+       current->processor = boot_cpu_id; /* ??? */
+        klock_info.akp = boot_cpu_id;
+
+        smp_store_cpu_info(boot_cpu_id);
+#ifdef NOT_YET
+        printk("CPU%d: ", boot_cpu_id);
+        print_cpu_info(&cpu_data[boot_cpu_id]);
+        set_irq_udt(mid_xlate[boot_cpu_id]);
+#endif /* NOT_YET */
+        smp_setup_percpu_timer();
+#ifdef HUH
+        local_flush_cache_all();
+#endif
+        if (smp_num_probed == 1)
+               return;  /* Not an MP box. */
+
+#if NOT_YET
+        /*
+         * If SMP should be disabled, then really disable it!
+         */
+        if (!max_cpus)
+       {
+               smp_found_config = 0;
+                printk(KERN_INFO "SMP mode deactivated.\n");
+        }
+#endif /* NOT_YET */
+
+        for (i = 0; i < NR_CPUS; i++) {
+
+               if (i == boot_cpu_id)
+                       continue;
+
+                if (cpu_present_map & (1 << i)) {
+                        struct task_struct *idle;
+                        int timeout;
+
+                        /* Cook up an idler for this guy. */
+                        kernel_thread(start_secondary, NULL, CLONE_PID);
+                        idle = task[++cpucount];
+                       if (!idle)
+                               panic("No idle process for CPU %d", i);
+                        idle->processor = i;
+
+#if 0
+printk("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n",
+       i, idle->state, idle->flags);
+#endif
+
+                        /* whirrr, whirrr, whirrrrrrrrr... */
+#ifdef HUH
+                        local_flush_cache_all();
+#endif
+                        secondary_cpu_start(i, idle);
+
+                        /* wheee... it's going... wait for 5 secs...*/
+                        for (timeout = 0; timeout < 50000; timeout++) {
+                               if (cpu_callin_map[i])
+                                       break;
+                                udelay(100);
+                        }
+                        if (cpu_callin_map[i]) {
+                               /* Another "Red Snapper". */
+                               cpu_number_map[i] = cpucount;
+                                cpu_logical_map[cpucount] = i;
+                        } else {
+                               cpucount--;
+                                printk("smp_boot_cpus: Processor %d"
+                                      " is stuck 0x%lx.\n", i, idle->flags);
+                        }
+                }
+                if (!(cpu_callin_map[i])) {
+                       cpu_present_map &= ~(1 << i);
+                        cpu_number_map[i] = -1;
+                }
+        }
+#ifdef HUH
+        local_flush_cache_all();
+#endif
+        if (cpucount == 0) {
+               printk("smp_boot_cpus: ERROR - only one Processor found.\n");
+                cpu_present_map = (1 << smp_processor_id());
+        } else {
+               unsigned long bogosum = 0;
+                for (i = 0; i < NR_CPUS; i++) {
+                       if (cpu_present_map & (1 << i))
+                               bogosum += cpu_data[i].loops_per_sec;
+                }
+                printk("smp_boot_cpus: Total of %d Processors activated"
+                      " (%lu.%02lu BogoMIPS).\n",
+                       cpucount + 1,
+                       (bogosum + 2500)/500000,
+                       ((bogosum + 2500)/5000)%100);
+                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;
+                        prev = i;
+                }
+        }
+        cpu_data[prev].next = first;
+
+        /* Ok, they are spinning and ready to go. */
+        smp_processors_ready = 1;
+}
+
+__initfunc(void ioapic_pirq_setup(char *str, int *ints))
+{
+  /* this is prolly INTEL-specific */
+}
+
+static void smp_setup_percpu_timer(void)
+{
+        int cpu = smp_processor_id();
+
+        prof_counter[cpu] = prof_multiplier[cpu] = 1;
+#ifdef NOT_YET
+        load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+        if (cpu == boot_cpu_id)
+               enable_pil_irq(14);
+#endif
+}
+
+extern void update_one_process(struct task_struct *p, unsigned long ticks,
+                               unsigned long user, unsigned long system,
+                              int cpu);
+
+void smp_percpu_timer_interrupt(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+#ifdef NOT_YET
+        clear_profile_irq(mid_xlate[cpu]);
+#ifdef CONFIG_PROFILE
+        if(!user_mode(regs))
+               sparc_do_profile(regs->pc);
+#endif
+#endif
+
+        if (!--prof_counter[cpu]) {
+               int user = user_mode(regs);
+                if (current->pid) {
+                       update_one_process(current, 1, user, !user, cpu);
+
+                        if (--current->counter < 0) {
+                               current->counter = 0;
+                                need_resched = 1;
+                        }
+
+                        spin_lock(&ticker_lock);
+                        if (user) {
+                               if (current->priority < DEF_PRIORITY) {
+                                       kstat.cpu_nice++;
+                                       kstat.per_cpu_nice[cpu]++;
+                               } else {
+                                       kstat.cpu_user++;
+                                       kstat.per_cpu_user[cpu]++;
+                               }
+                        } else {
+                               kstat.cpu_system++;
+                               kstat.per_cpu_system[cpu]++;
+                        }
+                        spin_unlock(&ticker_lock);
+                }
+                prof_counter[cpu] = prof_multiplier[cpu];
+        }
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+#ifdef NOT_YET
+        int i;
+        unsigned long flags;
+
+        /* Prevent level14 ticker IRQ flooding. */
+        if((!multiplier) || (lvl14_resolution / multiplier) < 500)
+                return -EINVAL;
+
+        save_and_cli(flags);
+        for(i = 0; i < NR_CPUS; i++) {
+                if(cpu_present_map & (1 << i)) {
+                        load_profile_irq(mid_xlate[i], lvl14_resolution / multip
+lier);
+                        prof_multiplier[i] = multiplier;
+                }
+        }
+        restore_flags(flags);
+
+        return 0;
+
+#endif
+  return -EINVAL;
+}
+
+/* Only broken Intel needs this, thus it should not even be referenced
+ * globally...
+ */
+__initfunc(void initialize_secondary(void))
+{
+       printk("initialize_secondary: entry\n");
+}
+
+static void
+secondary_cpu_start(int cpuid, struct task_struct *idle)
+{
+       struct percpu_struct *cpu;
+        int timeout;
+         
+       cpu = (struct percpu_struct *)
+               ((char*)hwrpb
+                       + hwrpb->processor_offset
+                       + cpuid * hwrpb->processor_size);
+
+       /* set context to idle thread this CPU will use when running */
+       /* assumption is that the idle thread is all set to go... ??? */
+       memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct));
+       cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */
+#if 0
+printk("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n",
+       cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb);
+printk("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n",
+       cpuid, idle->state, idle->tss.pal_flags);
+#endif
+
+       /* setup HWRPB fields that SRM uses to activate secondary CPU */
+        hwrpb->CPU_restart = __start_cpu;
+        hwrpb->CPU_restart_data = (unsigned long) idle;
+
+        /* recalculate and update the HWRPB checksum */
+        {
+          unsigned long sum, *lp1, *lp2;
+          sum = 0;
+          lp1 = (unsigned long *)hwrpb;
+          lp2 = &hwrpb->chksum;
+          while (lp1 < lp2)
+            sum += *lp1++;
+          *lp2 = sum;
+        }
+
+       /*
+        * Send a "start" command to the specified processor.
+        */
+
+       /* SRM III 3.4.1.3 */
+       cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */
+       cpu->flags &= ~1;/* turn off Bootstrap In Progress */
+       mb();
+
+       send_cpu_msg("START\r\n", cpuid);
+
+       /* now, we wait... */
+       for (timeout = 10000; !(cpu->flags & 1); timeout--) {
+               if (timeout <= 0) {
+                       printk("Processor %d failed to start\n", cpuid);
+                                /* needed for pset_info to work */
+#if 0
+                       ipc_processor_enable(cpu_to_processor(cpunum));
+#endif
+                       return;
+               }
+               udelay(1000);
+       }
+#if 0
+       printk("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid);
+#endif
+}
+
+static void
+send_cpu_msg(char *str, int cpuid)
+{
+       struct percpu_struct *cpu;
+        register char *cp1, *cp2;
+        unsigned long cpumask;
+        int timeout;
+
+         
+       cpu = (struct percpu_struct *)
+               ((char*)hwrpb
+                       + hwrpb->processor_offset
+                       + cpuid * hwrpb->processor_size);
+
+        cpumask = (1L << cpuid);
+        for (timeout = 10000; (hwrpb->txrdy & cpumask); timeout--) {
+                if (timeout <= 0) {
+                        printk("Processor %x not ready\n", cpuid);
+                        return;
+                }
+                udelay(1000);
+        }
+
+        cp1 = (char *) &cpu->ipc_buffer[1];
+        cp2 = str;
+        while (*cp2) *cp1++ = *cp2++;
+        *(unsigned int *)&cpu->ipc_buffer[0] = cp2 - str; /* hack */
+
+        /* atomic test and set */
+        set_bit(cpuid, &hwrpb->rxrdy);
+
+        for (timeout = 10000; (hwrpb->txrdy & cpumask); timeout--) {
+                if (timeout <= 0) {
+                        printk("Processor %x not ready\n", cpuid);
+                        return;
+                }
+                udelay(1000);
+        }
+}
+
+/*
+ * setup_smp()
+ *
+ * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined
+ */
+__initfunc(void setup_smp(void))
+{
+       struct percpu_struct *cpubase, *cpu;
+       int i;
+         
+       boot_cpu_id = hard_smp_processor_id();
+       if (boot_cpu_id != 0) {
+               printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id);
+       }
+
+       if (hwrpb->nr_processors > 1) {
+#if 0
+printk("setup_smp: nr_processors 0x%lx\n",
+       hwrpb->nr_processors);
+#endif
+               cpubase = (struct percpu_struct *)
+                       ((char*)hwrpb + hwrpb->processor_offset);
+               boot_cpu_palrev = cpubase->pal_revision;
+
+               for (i = 0; i < hwrpb->nr_processors; i++ ) {
+                       cpu = (struct percpu_struct *)
+                               ((char *)cpubase + i*hwrpb->processor_size);
+                       if ((cpu->flags & 0x1cc) == 0x1cc) {
+                               smp_num_probed++;
+                               /* assume here that "whami" == index */
+                               cpu_present_map |= (1 << i);
+                               if (i != boot_cpu_id)
+                                 cpu->pal_revision = boot_cpu_palrev;
+                       }
+#if 0
+printk("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n",
+       i, cpu->flags, cpu->type);
+ printk("setup_smp: CPU %d: PAL rev 0x%lx\n",
+       i, cpu->pal_revision);
+#endif
+               }
+       } else {
+               smp_num_probed = 1;
+               cpu_present_map = (1 << boot_cpu_id);
+       }
+       printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x,"
+              " boot_cpu_id %d\n",
+              smp_num_probed, cpu_present_map, boot_cpu_id);
+}
+
+static void
+secondary_console_message(void)
+{
+        int mycpu, i, cnt;
+       unsigned long txrdy = hwrpb->txrdy;
+       char *cp1, *cp2, buf[80];
+        struct percpu_struct *cpu;
+
+        mycpu = hard_smp_processor_id();
+
+#if 0
+printk("secondary_console_message: TXRDY 0x%lx.\n", txrdy);
+#endif
+        for (i = 0; i < NR_CPUS; i++) {
+          if (txrdy & (1L << i)) {
+#if 0
+printk("secondary_console_message: TXRDY contains CPU %d.\n", i);
+#endif
+            cpu = (struct percpu_struct *)
+              ((char*)hwrpb
+               + hwrpb->processor_offset
+               + i * hwrpb->processor_size);
+#if 1
+            printk("secondary_console_message: on %d from %d"
+                   " HALT_REASON 0x%lx FLAGS 0x%lx\n",
+                   mycpu, i, cpu->halt_reason, cpu->flags);
+#endif
+            cnt = cpu->ipc_buffer[0] >> 32;
+            if (cnt <= 0 || cnt >= 80)
+              strcpy(buf,"<<< BOGUS MSG >>>");
+            else {
+              cp1 = (char *) &cpu->ipc_buffer[11];
+              cp2 = buf;
+              while (cnt--) {
+                if (*cp1 == '\r' || *cp1 == '\n') {
+                  *cp2++ = ' '; cp1++;
+                } else
+                  *cp2++ = *cp1++;
+              }
+              *cp2 = 0;
+            }
+#if 1
+            printk("secondary_console_message: on %d message is '%s'\n",
+                   mycpu, buf);
+#endif
+          }
+               }
+        hwrpb->txrdy = 0;
+        return;
+}
+
+static int
+halt_on_panic(unsigned int this_cpu)
+{
+       halt();
+       return 0;
+}
+
+static int
+local_flush_tlb_all(unsigned int this_cpu)
+{
+       tbia();
+       clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
+       mb();
+       return 0;
+}
+
+static int
+local_flush_tlb_mm(unsigned int this_cpu)
+{
+       struct mm_struct * mm = ipi_msg_flush_tb.p.flush_mm;
+       if (mm != current->mm)
+               flush_tlb_other(mm);
+       else
+               flush_tlb_current(mm);
+       clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
+       mb();
+       return 0;
+}
+
+static int
+local_flush_tlb_page(unsigned int this_cpu)
+{
+       struct vm_area_struct * vma = ipi_msg_flush_tb.p.flush_vma;
+       struct mm_struct * mm = vma->vm_mm;
+
+       if (mm != current->mm)
+               flush_tlb_other(mm);
+       else
+               flush_tlb_current_page(mm, vma, ipi_msg_flush_tb.flush_addr);
+       clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask);
+       mb();
+       return 0;
+}
+
+static int
+wrapper_local_flush_tlb_page(unsigned int this_cpu)
+{
+#if 0
+       int cpu = smp_processor_id();
+
+       if (cpu) {
+         printk("wrapper: ipi_msg_flush_tb.flush_addr 0x%lx [%d]\n",
+                ipi_msg_flush_tb.flush_addr, atomic_read(&global_irq_count));
+       }
+#endif
+       local_flush_tlb_page(this_cpu);
+       return 0;
+}
+
+static int
+unknown_ipi(unsigned int this_cpu)
+{
+       printk("unknown_ipi() on cpu %d:  ", this_cpu);
+       return 1;
+}
+
+enum ipi_message_type {
+  CPU_STOP,
+  TLB_ALL,
+  TLB_MM,
+  TLB_PAGE,
+  TLB_RANGE
+};
+
+static int (* ipi_func[32])(unsigned int) = {
+  halt_on_panic,
+  local_flush_tlb_all,
+  local_flush_tlb_mm,
+  wrapper_local_flush_tlb_page,
+  local_flush_tlb_mm,          /* a.k.a. local_flush_tlb_range */
+  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
+  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
+  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
+  unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi, unknown_ipi,
+  unknown_ipi, unknown_ipi, unknown_ipi
+};
+
+void
+handle_ipi(struct pt_regs *regs)
+{
+       int this_cpu = smp_processor_id();
+       volatile int * pending_ipis = &ipi_bits[this_cpu];
+       int ops;
+
+       mb();
+#if 0
+       printk("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n",
+              this_cpu, *pending_ipis, regs->pc);
+#endif
+       while ((ops = *pending_ipis)) {
+               int first;
+               for (first = 0; (ops & 1) == 0; ++first, ops >>= 1)
+                       ; /* look for the first thing to do */
+               clear_bit(first, pending_ipis);
+               mb();
+               if ((*ipi_func[first])(this_cpu))
+                 printk("%d\n", first);
+               mb();
+       }
+       if (hwrpb->txrdy)
+         secondary_console_message();
+}
+
+void
+send_ipi_message(long to_whom, enum ipi_message_type operation)
+{
+       int i;
+       unsigned int j;
+
+       for (i = 0, j = 1; i < NR_CPUS; ++i, j += j) {
+               if ((to_whom & j) == 0)
+                       continue;
+               set_bit(operation, &ipi_bits[i]);
+               mb();
+               wripir(i);
+       }
+}
+
+static char smp_buf[256];
+
+char *smp_info(void)
+{
+        sprintf(smp_buf, "CPUs probed %d active %d map 0x%x AKP %d\n",
+               smp_num_probed, smp_num_cpus, cpu_present_map,
+               klock_info.akp);
+
+        return smp_buf;
+}
+
+/* wrapper for call from panic() */
+void
+smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+       int me = smp_processor_id();
+
+       if (msg != MSG_STOP_CPU)
+               goto barf;
+
+       send_ipi_message(CPU_STOP, cpu_present_map ^ (1 << me));
+       return;
+barf:
+       printk("Yeeee, trying to send SMP msg(%d) on cpu %d\n", msg, me);
+       panic("Bogon SMP message pass.");
+}
+
+void
+flush_tlb_all(void)
+{
+       unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
+       int timeout = 10000;
+
+#if 1
+       if (!kernel_lock_held()) {
+         printk("flush_tlb_all: kernel_flag %d (cpu %d akp %d)!\n",
+                klock_info.kernel_flag, smp_processor_id(), klock_info.akp);
+       }
+#endif
+       ipi_msg_flush_tb.flush_tb_mask = to_whom;
+       send_ipi_message(to_whom, TLB_ALL);
+       tbia();
+
+       while (ipi_msg_flush_tb.flush_tb_mask) {
+         if (--timeout < 0) {
+           printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n",
+                  smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask);
+           ipi_msg_flush_tb.flush_tb_mask = 0;
+           break;
+         }
+         udelay(100);
+               ; /* Wait for all clear from other CPUs. */
+       }
+}
+
+void
+flush_tlb_mm(struct mm_struct *mm)
+{
+       unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id());
+       int timeout = 10000;
+
+#if 1
+       if (!kernel_lock_held()) {
+         printk("flush_tlb_mm: kernel_flag %d (cpu %d akp %d)!\n",
+                klock_info.kernel_flag, smp_processor_id(), klock_info.akp);
+       }
+#endif
+       ipi_msg_flush_tb.p.flush_mm = mm;
+       ipi_msg_flush_tb.flush_tb_mask = to_whom;
+       send_ipi_message(to_whom, TLB_MM);
+
+       if (mm != current->mm)
+               flush_tlb_other(mm);
+       else
+               flush_tlb_current(mm);
+
+       while (ipi_msg_flush_tb.flush_tb_mask) {
+         if (--timeout < 0) {
+           printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n",
+                  smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask);
+           ipi_msg_flush_tb.flush_tb_mask = 0;
+           break;
+         }
+         udelay(100);
+               ; /* Wait for all clear from other CPUs. */
+       }
+}
+
+void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+       int cpu = smp_processor_id();
+       unsigned int to_whom = cpu_present_map ^ (1 << cpu);
+       struct mm_struct * mm = vma->vm_mm;
+       int timeout = 10000;
+
+#if 1
+       if (!kernel_lock_held()) {
+         printk("flush_tlb_page: kernel_flag %d (cpu %d akp %d)!\n",
+                klock_info.kernel_flag, cpu, klock_info.akp);
+       }
+#endif
+       ipi_msg_flush_tb.p.flush_vma = vma;
+       ipi_msg_flush_tb.flush_addr = addr;
+       ipi_msg_flush_tb.flush_tb_mask = to_whom;
+       send_ipi_message(to_whom, TLB_PAGE);
+
+       if (mm != current->mm)
+               flush_tlb_other(mm);
+       else
+               flush_tlb_current_page(mm, vma, addr);
+
+       while (ipi_msg_flush_tb.flush_tb_mask) {
+         if (--timeout < 0) {
+           printk("flush_tlb_page: STUCK on CPU %d [0x%x,0x%lx,%d,%d]\n",
+                  cpu, ipi_msg_flush_tb.flush_tb_mask, addr,
+                  klock_info.akp, global_irq_holder);
+           ipi_msg_flush_tb.flush_tb_mask = 0;
+           break;
+         }
+         udelay(100);
+               ; /* Wait for all clear from other CPUs. */
+       }
+}
+
+void
+flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+#if 0
+       flush_tlb_mm(mm);
+#else
+       unsigned int to_whom;
+       int timeout;
+        unsigned long where;
+
+        __asm__("mov $26, %0" : "=r" (where));
+
+       timeout = 10000;
+       to_whom = cpu_present_map ^ (1 << smp_processor_id());
+
+#if 1
+       if (!kernel_lock_held()) {
+         printk("flush_tlb_range: kernel_flag %d (cpu %d akp %d) @ 0x%lx\n",
+                klock_info.kernel_flag, smp_processor_id(), klock_info.akp,
+                where);
+       }
+#endif
+       ipi_msg_flush_tb.p.flush_mm = mm;
+       ipi_msg_flush_tb.flush_tb_mask = to_whom;
+       send_ipi_message(to_whom, TLB_MM);
+
+       if (mm != current->mm)
+               flush_tlb_other(mm);
+       else
+               flush_tlb_current(mm);
+
+       while (ipi_msg_flush_tb.flush_tb_mask) {
+         if (--timeout < 0) {
+           printk("flush_tlb_range: STUCK on CPU %d mask 0x%x\n",
+                  smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask);
+           ipi_msg_flush_tb.flush_tb_mask = 0;
+           break;
+         }
+         udelay(100);
+               ; /* Wait for all clear from other CPUs. */
+       }
+#endif
+}
+
+#ifdef DEBUG_KERNEL_LOCK
+void ___lock_kernel(klock_info_t *klip, int cpu, long ipl)
+{
+       long regx;
+       int stuck_lock;
+       unsigned long inline_pc;
+
+        __asm__("mov $26, %0" : "=r" (inline_pc));
+
+ try_again:
+
+       stuck_lock = 1<<26;
+
+       __asm__ __volatile__(
+       "1:     ldl_l   %1,%0;"
+       "       blbs    %1,6f;"
+       "       or      %1,1,%1;"
+       "       stl_c   %1,%0;"
+       "       beq     %1,6f;"
+       "4:     mb\n"
+       ".section .text2,\"ax\"\n"
+       "6:     mov     %5,$16;"
+       "       call_pal %4;"
+       "7:     ldl     %1,%0;"
+       "       blt     %2,4b   # debug\n"
+       "       subl    %2,1,%2 # debug\n"
+       "       blbs    %1,7b;"
+       "       bis     $31,7,$16;"
+       "       call_pal %4;"
+       "       br      1b\n"
+       ".previous"
+       : "=m,=m" (__dummy_lock(klip)), "=&r,=&r" (regx),
+         "=&r,=&r" (stuck_lock)
+       : "0,0" (__dummy_lock(klip)), "i,i" (PAL_swpipl),
+         "i,r" (ipl), "2,2" (stuck_lock)
+       : "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory");
+
+       if (stuck_lock < 0) {
+               printk("___kernel_lock stuck at %lx(%d) held %lx(%d)\n",
+                      inline_pc, cpu, klip->pc, klip->cpu);
+               goto try_again;
+       } else {
+               klip->pc = inline_pc;
+               klip->cpu = cpu;
+       }
+}
+#endif
+
+#ifdef DEBUG_SPINLOCK
+void spin_lock(spinlock_t * lock)
+{
+       long tmp;
+       long stuck;
+       unsigned long inline_pc;
+
+        __asm__("mov $26, %0" : "=r" (inline_pc));
+
+ try_again:
+
+       stuck = 0x10000000; /* was 4G, now 256M */
+
+       /* Use sub-sections to put the actual loop at the end
+          of this object file's text section so as to perfect
+          branch prediction.  */
+       __asm__ __volatile__(
+       "1:     ldq_l   %0,%1\n"
+       "       subq    %2,1,%2\n"
+       "       blbs    %0,2f\n"
+       "       or      %0,1,%0\n"
+       "       stq_c   %0,%1\n"
+       "       beq     %0,3f\n"
+       "4:     mb\n"
+       ".section .text2,\"ax\"\n"
+       "2:     ldq     %0,%1\n"
+       "       subq    %2,1,%2\n"
+       "3:     blt     %2,4b\n"
+       "       blbs    %0,2b\n"
+       "       br      1b\n"
+       ".previous"
+       : "=r" (tmp),
+         "=m" (__dummy_lock(lock)),
+         "=r" (stuck)
+       : "2" (stuck));
+
+       if (stuck < 0) {
+               printk("spinlock stuck at %lx (cur=%lx, own=%lx)\n",
+                      inline_pc,
+#if 0
+                      lock->previous, lock->task
+#else
+                      (unsigned long) current, lock->task
+#endif
+                      );
+               goto try_again;
+       } else {
+               lock->previous = (unsigned long) inline_pc;
+               lock->task = (unsigned long) current;
+       }
+}
+#endif /* DEBUG_SPINLOCK */
+
+#ifdef DEBUG_RWLOCK
+void write_lock(rwlock_t * lock)
+{
+       long regx, regy;
+       int stuck_lock, stuck_reader;
+       unsigned long inline_pc;
+
+        __asm__("mov $26, %0" : "=r" (inline_pc));
+
+ try_again:
+
+       stuck_lock = 1<<26;
+       stuck_reader = 1<<26;
+
+       __asm__ __volatile__(
+       "1:     ldl_l   %1,%0;"
+       "       blbs    %1,6f;"
+       "       or      %1,1,%2;"
+       "       stl_c   %2,%0;"
+       "       beq     %2,6f;"
+       "       blt     %1,8f;"
+       "4:     mb\n"
+       ".section .text2,\"ax\"\n"
+       "6:     ldl     %1,%0;"
+       "       blt     %3,4b   # debug\n"
+       "       subl    %3,1,%3 # debug\n"
+       "       blbs    %1,6b;"
+       "       br      1b;"
+       "8:     ldl     %1,%0;"
+       "       blt     %4,4b   # debug\n"
+       "       subl    %4,1,%4 # debug\n"
+       "       blt     %1,8b;"
+       "9:     br      4b\n"
+       ".previous"
+       : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
+       , "=&r" (stuck_lock), "=&r" (stuck_reader)
+       : "0" (__dummy_lock(lock))
+       , "3" (stuck_lock), "4" (stuck_reader)
+       );
+
+       if (stuck_lock < 0) {
+               printk("write_lock stuck at %lx\n", inline_pc);
+               goto try_again;
+       }
+       if (stuck_reader < 0) {
+               printk("write_lock stuck on readers at %lx\n", inline_pc);
+               goto try_again;
+       }
+}
+
+void _read_lock(rwlock_t * lock)
+{
+       long regx;
+       int stuck_lock;
+       unsigned long inline_pc;
+
+        __asm__("mov $26, %0" : "=r" (inline_pc));
+
+ try_again:
+
+       stuck_lock = 1<<26;
+
+       __asm__ __volatile__(
+       "1:     ldl_l   %1,%0;"
+       "       blbs    %1,6f;"
+       "       subl    %1,2,%1;"
+       "       stl_c   %1,%0;"
+       "       beq     %1,6f;"
+       "4:     mb\n"
+       ".section .text2,\"ax\"\n"
+       "6:     ldl     %1,%0;"
+       "       blt     %2,4b   # debug\n"
+       "       subl    %2,1,%2 # debug\n"
+       "       blbs    %1,6b;"
+       "       br      1b\n"
+       ".previous"
+       : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock)
+       : "0" (__dummy_lock(lock)), "2" (stuck_lock)
+       );
+
+       if (stuck_lock < 0) {
+               printk("_read_lock stuck at %lx\n", inline_pc);
+               goto try_again;
+       }
+}
+#endif /* DEBUG_RWLOCK */
index 398aaeb..ffa1665 100644 (file)
@@ -8,6+8,7 @@
  *
  */
 #include <linux/kernel.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <asm/ptrace.h>
 #include <asm/mmu_context.h>
 
-/* NOTE: Herein are back-to-back mb insns.  They are magic.
-   A plausable explanation is that the i/o controler does not properly
-   handle the system transaction.  Another involves timing.  Ho hum.  */
+/*
+ * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
+ * One plausible explanation is that the i/o controller does not properly
+ * handle the system transaction.  Another involves timing.  Ho hum.
+ */
 
 extern struct hwrpb_struct *hwrpb;
 extern asmlinkage void wrmces(unsigned long mces);
-extern asmlinkage unsigned long whami(void);
-extern int alpha_sys_type;
-
-#define CPUID whami()
-
 
 /*
  * Machine check reasons.  Defined according to PALcode sources
@@ -62,10+60,14 @@ extern int alpha_sys_type;
 #define vulp   volatile unsigned long *
 #define vuip   volatile unsigned int  *
 
-static volatile unsigned int T2_mcheck_expected = 0;
-static volatile unsigned int T2_mcheck_taken = 0;
-static unsigned long T2_jd;
+static volatile unsigned int T2_mcheck_expected[NR_CPUS];
+static volatile unsigned int T2_mcheck_taken[NR_CPUS];
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int T2_DMA_WIN_BASE = T2_DMA_WIN_BASE_DEFAULT;
+unsigned int T2_DMA_WIN_SIZE = T2_DMA_WIN_SIZE_DEFAULT;
+unsigned long t2_sm_base;
+#endif /* SRM_SETUP */
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -145,8+147,10 @@ static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
 static unsigned int conf_read(unsigned long addr, unsigned char type1)
 {
        unsigned long flags;
-       unsigned int stat0, value;
-       unsigned int t2_cfg = 0; /* to keep gcc quiet */
+       unsigned int stat0, value, cpu;
+       unsigned long t2_cfg = 0; /* to keep gcc quiet */
+
+       cpu = smp_processor_id();
 
        save_flags(flags);      /* avoid getting hit by machine check */
        cli();
@@ -155,43+159,41 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1)
 
 #if 0
        /* reset status register to avoid losing errors: */
-       stat0 = *(vuip)T2_IOCSR;
-       *(vuip)T2_IOCSR = stat0;
+       stat0 = *(vulp)T2_IOCSR;
+       *(vulp)T2_IOCSR = stat0;
        mb();
        DBG(("conf_read: T2 IOCSR was 0x%x\n", stat0));
+#endif
        /* if Type1 access, must set T2 CFG */
        if (type1) {
-               t2_cfg = *(vuip)T2_IOC_CFG;
+               t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
+               *(vulp)T2_HAE_3 = 0x40000000UL | t2_cfg;
                mb();
-               *(vuip)T2_IOC_CFG = t2_cfg | 1;
                DBG(("conf_read: TYPE1 access\n"));
        }
        mb();
        draina();
-#endif
 
-       T2_mcheck_expected = 1;
-       T2_mcheck_taken = 0;
+       T2_mcheck_expected[cpu] = 1;
+       T2_mcheck_taken[cpu] = 0;
        mb();
        /* access configuration space: */
        value = *(vuip)addr;
        mb();
        mb();  /* magic */
-       if (T2_mcheck_taken) {
-               T2_mcheck_taken = 0;
+       if (T2_mcheck_taken[cpu]) {
+               T2_mcheck_taken[cpu] = 0;
                value = 0xffffffffU;
                mb();
        }
-       T2_mcheck_expected = 0;
+       T2_mcheck_expected[cpu] = 0;
        mb();
 
-#if 0
-       /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+       /* if Type1 access, must reset T2 CFG so normal IO space ops work */
        if (type1) {
-               *(vuip)T2_IOC_CFG = t2_cfg & ~1;
+               *(vulp)T2_HAE_3 = t2_cfg;
                mb();
        }
-#endif
        DBG(("conf_read(): finished\n"));
 
        restore_flags(flags);
@@ -203,44+205,45 @@ static void conf_write(unsigned long addr, unsigned int value,
                       unsigned char type1)
 {
        unsigned long flags;
-       unsigned int stat0;
-       unsigned int t2_cfg = 0; /* to keep gcc quiet */
+       unsigned int stat0, cpu;
+       unsigned long t2_cfg = 0; /* to keep gcc quiet */
+
+       cpu = smp_processor_id();
 
        save_flags(flags);      /* avoid getting hit by machine check */
        cli();
 
 #if 0
        /* reset status register to avoid losing errors: */
-       stat0 = *(vuip)T2_IOCSR;
-       *(vuip)T2_IOCSR = stat0;
+       stat0 = *(vulp)T2_IOCSR;
+       *(vulp)T2_IOCSR = stat0;
        mb();
        DBG(("conf_write: T2 ERR was 0x%x\n", stat0));
+#endif
        /* if Type1 access, must set T2 CFG */
        if (type1) {
-               t2_cfg = *(vuip)T2_IOC_CFG;
+               t2_cfg = *(vulp)T2_HAE_3 & ~0xc0000000UL;
+               *(vulp)T2_HAE_3 = t2_cfg | 0x40000000UL;
                mb();
-               *(vuip)T2_IOC_CFG = t2_cfg | 1;
                DBG(("conf_write: TYPE1 access\n"));
        }
+       mb();
        draina();
-#endif
 
-       T2_mcheck_expected = 1;
+       T2_mcheck_expected[cpu] = 1;
        mb();
        /* access configuration space: */
        *(vuip)addr = value;
        mb();
        mb();  /* magic */
-       T2_mcheck_expected = 0;
+       T2_mcheck_expected[cpu] = 0;
        mb();
 
-#if 0
-       /* if Type1 access, must reset IOC CFG so normal IO space ops work */
+       /* if Type1 access, must reset T2 CFG so normal IO space ops work */
        if (type1) {
-               *(vuip)T2_IOC_CFG = t2_cfg & ~1;
+               *(vulp)T2_HAE_3 = t2_cfg;
                mb();
        }
-#endif
        DBG(("conf_write(): finished\n"));
        restore_flags(flags);
 }
@@ -362,17+365,21 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
 
 unsigned long t2_init(unsigned long mem_start, unsigned long mem_end)
 {
-       unsigned int t2_err;
-       struct percpu_struct *cpu;
-       int i;
+       unsigned long t2_err;
+       unsigned int i;
+
+       for (i = 0; i < NR_CPUS; i++) {
+               T2_mcheck_expected[i] = 0;
+               T2_mcheck_taken[i] = 0;
+       }
 
 #if 0
        /* 
         * Set up error reporting.
         */
-       t2_err = *(vuip)T2_IOCSR ;
+       t2_err = *(vulp)T2_IOCSR ;
        t2_err |= (0x1 << 7) ;   /* master abort */
-       *(vuip)T2_IOC_T2_ERR = t2_err ;
+       *(vulp)T2_IOCSR = t2_err ;
        mb() ;
 #endif
 
@@ -388,6+395,42 @@ unsigned long t2_init(unsigned long mem_start, unsigned long mem_end)
               *(vulp)T2_TBASE2);
 #endif
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 1 for enabled and mapped to 0 */
+       if (((*(vulp)T2_WBASE1 & (3UL<<18)) == (2UL<<18)) &&
+            (*(vulp)T2_TBASE1 == 0))
+       {
+         T2_DMA_WIN_BASE = *(vulp)T2_WBASE1 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE = *(vulp)T2_WMASK1 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE += 0x00100000UL;
+/* DISABLE window 2!! ?? */
+#if 1
+         printk("t2_init: using Window 1 settings\n");
+         printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)T2_WBASE1,
+                *(vulp)T2_WMASK1,
+                *(vulp)T2_TBASE1);
+#endif
+       }
+       else    /* check window 2 for enabled and mapped to 0 */
+       if (((*(vulp)T2_WBASE2 & (3UL<<18)) == (2UL<<18)) &&
+            (*(vulp)T2_TBASE2 == 0))
+       {
+         T2_DMA_WIN_BASE = *(vulp)T2_WBASE2 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE = *(vulp)T2_WMASK2 & 0xfff00000UL;
+         T2_DMA_WIN_SIZE += 0x00100000UL;
+/* DISABLE window 1!! ?? */
+#if 1
+         printk("t2_init: using Window 2 settings\n");
+         printk("t2_init: BASE 0x%lx MASK 0x%lx TRANS 0x%lx\n",
+                *(vulp)T2_WBASE2,
+                *(vulp)T2_WMASK2,
+                *(vulp)T2_TBASE2);
+#endif
+       }
+       else /* we must use our defaults... */
+#endif /* SRM_SETUP */
+       {
        /*
         * Set up the PCI->physical memory translation windows.
         * For now, window 2 is  disabled.  In the future, we may
@@ -396,13+439,13 @@ unsigned long t2_init(unsigned long mem_start, unsigned long mem_end)
         */
 
        /* WARNING!! must correspond to the DMA_WIN params!!! */
-       *(vuip)T2_WBASE1 = 0x400807ffU;
-       *(vuip)T2_WMASK1 = 0x3ff00000U;
-       *(vuip)T2_TBASE1 = 0;
-
-       *(vuip)T2_WBASE2 = 0x0;
+       *(vulp)T2_WBASE1 = 0x400807ffU;
+       *(vulp)T2_WMASK1 = 0x3ff00000U;
+       *(vulp)T2_TBASE1 = 0;
 
-       *(vuip)T2_HBASE = 0x0;
+       *(vulp)T2_WBASE2 = 0x0;
+       *(vulp)T2_HBASE = 0x0;
+       }
 
        /*
         * check ASN in HWRPB for validity, report if bad
@@ -420,41+463,43 @@ unsigned long t2_init(unsigned long mem_start, unsigned long mem_end)
         *  what ARC or SRM might have left behind...
         */
        {
-#if 0
-               printk("T2_init: HAE1 was 0x%lx\n", *(vulp)T2_HAE_1);
-               printk("T2_init: HAE2 was 0x%lx\n", *(vulp)T2_HAE_2);
-               printk("T2_init: HAE3 was 0x%lx\n", *(vulp)T2_HAE_3);
-               printk("T2_init: HAE4 was 0x%lx\n", *(vulp)T2_HAE_4);
+         unsigned long t2_hae_1 = *(vulp)T2_HAE_1;
+         unsigned long t2_hae_2 = *(vulp)T2_HAE_2;
+         unsigned long t2_hae_3 = *(vulp)T2_HAE_3;
+         unsigned long t2_hae_4 = *(vulp)T2_HAE_4;
+#if 1
+          printk("T2_init: HAE1 was 0x%lx\n", t2_hae_1);
+          printk("T2_init: HAE2 was 0x%lx\n", t2_hae_2);
+          printk("T2_init: HAE3 was 0x%lx\n", t2_hae_3);
+          printk("T2_init: HAE4 was 0x%lx\n", t2_hae_4);
 #endif
+#ifdef CONFIG_ALPHA_SRM_SETUP
+         /*
+          * sigh... For the SRM setup, unless we know apriori what the HAE
+          * contents will be, we need to setup the arbitrary region bases
+          * so we can test against the range of addresses and tailor the
+          *        region chosen for the SPARSE memory access.
+          *
+          * see include/asm-alpha/t2.h for the SPARSE mem read/write
+         */
+         t2_sm_base = (t2_hae_1 << 27) & 0xf8000000UL;
+         /*
+           Set the HAE cache, so that setup_arch() code
+           will use the SRM setting always. Our readb/writeb
+           code in .h expects never to have to change
+           the contents of the HAE.
+          */
+         hae.cache = t2_hae_1;
+#else /* SRM_SETUP */
+         *(vulp)T2_HAE_1 = 0; mb();
+         *(vulp)T2_HAE_2 = 0; mb();
+         *(vulp)T2_HAE_3 = 0; mb();
 #if 0
-               *(vuip)T2_HAE_1 = 0; mb();
-               *(vuip)T2_HAE_2 = 0; mb();
-               *(vuip)T2_HAE_3 = 0; mb();
-               *(vuip)T2_HAE_4 = 0; mb();
+         *(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */
 #endif
+#endif /* SRM_SETUP */
        }
  
-#if 1
-       if (hwrpb->nr_processors > 1) {
-               printk("T2_init: nr_processors 0x%lx\n",
-                      hwrpb->nr_processors);
-               printk("T2_init: processor_size 0x%lx\n",
-                      hwrpb->processor_size);
-               printk("T2_init: processor_offset 0x%lx\n",
-                      hwrpb->processor_offset);
-
-               cpu = (struct percpu_struct *)
-                       ((char*)hwrpb + hwrpb->processor_offset);
-
-               for (i = 0; i < hwrpb->nr_processors; i++ ) {
-                       printk("T2_init: CPU 0x%x: flags 0x%lx type 0x%lx\n",
-                              i, cpu->flags, cpu->type);
-                       cpu = (struct percpu_struct *)
-                               ((char *)cpu + hwrpb->processor_size);
-               }
-       }
-#endif
-
        return mem_start;
 }
 
@@ -469,17+514,19 @@ static struct sable_cpu_csr *sable_cpu_regs[4] = {
 
 int t2_clear_errors(void)
 {
+       unsigned int cpu = smp_processor_id();
+
        DBGMC(("???????? t2_clear_errors\n"));
 
-       sable_cpu_regs[CPUID]->sic &= ~SIC_SEIC;
+       sable_cpu_regs[cpu]->sic &= ~SIC_SEIC;
 
        /* 
         * clear cpu errors
         */
-       sable_cpu_regs[CPUID]->bcce |= sable_cpu_regs[CPUID]->bcce;
-       sable_cpu_regs[CPUID]->cbe  |= sable_cpu_regs[CPUID]->cbe;
-       sable_cpu_regs[CPUID]->bcue |= sable_cpu_regs[CPUID]->bcue;
-       sable_cpu_regs[CPUID]->dter |= sable_cpu_regs[CPUID]->dter;
+       sable_cpu_regs[cpu]->bcce |= sable_cpu_regs[cpu]->bcce;
+       sable_cpu_regs[cpu]->cbe  |= sable_cpu_regs[cpu]->cbe;
+       sable_cpu_regs[cpu]->bcue |= sable_cpu_regs[cpu]->bcue;
+       sable_cpu_regs[cpu]->dter |= sable_cpu_regs[cpu]->dter;
 
        *(vulp)T2_CERR1 |= *(vulp)T2_CERR1;
        *(vulp)T2_PERR1 |= *(vulp)T2_PERR1;
@@ -499,6+546,7 @@ void t2_machine_check(unsigned long vector, unsigned long la_ptr,
        const char * reason;
        char buf[128];
        long i;
+       unsigned int cpu = smp_processor_id();
 
        DBGMC(("t2_machine_check: vector=0x%lx la_ptr=0x%lx\n",
               vector, la_ptr));
@@ -516,7+564,7 @@ void t2_machine_check(unsigned long vector, unsigned long la_ptr,
        DBGMC(("         pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
               regs->pc, mchk_header->elfl_size, mchk_header->elfl_procoffset,
               mchk_header->elfl_sysoffset));
-       DBGMC(("t2_machine_check: expected %d\n", T2_mcheck_expected));
+       DBGMC(("t2_machine_check: expected %d\n", T2_mcheck_expected[cpu]));
 
 #ifdef DEBUG_DUMP
        {
@@ -537,11+585,11 @@ void t2_machine_check(unsigned long vector, unsigned long la_ptr,
         */
        mb();
        mb();  /* magic */
-       if (T2_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) {
+       if (T2_mcheck_expected[cpu]) {
                DBGMC(("T2 machine check expected\n"));
-               T2_mcheck_taken = 1;
+               T2_mcheck_taken[cpu] = 1;
                t2_clear_errors();
-               T2_mcheck_expected = 0;
+               T2_mcheck_expected[cpu] = 0;
                mb();
                mb();  /* magic */
                wrmces(rdmces()|1);/* ??? */
index 9d8b56d..0456eb1 100644 (file)
@@ -82,6+82,16 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
        __u32 now;
        long nticks;
 
+#ifdef __SMP__
+       extern void smp_percpu_timer_interrupt(struct pt_regs *);
+       extern unsigned int boot_cpu_id;
+       /* when SMP, do this for *all* CPUs, 
+          but only do the rest for the boot CPU */
+       smp_percpu_timer_interrupt(regs);
+       if (smp_processor_id() != boot_cpu_id)
+         return;
+#endif
+
        /*
         * Estimate how many ticks have passed since the last update.
         * Round the result, .5 to even.  When we loose ticks due to
diff --git a/arch/alpha/kernel/tsunami.c b/arch/alpha/kernel/tsunami.c
new file mode 100644 (file)
index 0000000..5c4d34e
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Code common to all TSUNAMI chips.
+ *
+ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/ptrace.h>
+#include <asm/mmu_context.h>
+
+/*
+ * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
+ * One plausible explanation is that the i/o controller does not properly
+ * handle the system transaction.  Another involves timing.  Ho hum.
+ */
+
+extern struct hwrpb_struct *hwrpb;
+extern asmlinkage void wrmces(unsigned long mces);
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef CONFIG_ALPHA_TSUNAMI
+
+#ifdef DEBUG 
+# define DBG(args)     printk args
+#else
+# define DBG(args)
+#endif
+
+#define DEBUG_MCHECK
+#ifdef DEBUG_MCHECK
+# define DBG_MCK(args) printk args
+#define DEBUG_MCHECK_DUMP
+#else
+# define DBG_MCK(args)
+#endif
+
+#define vuip   volatile unsigned int  *
+#define vulp   volatile unsigned long  *
+
+static volatile unsigned int TSUNAMI_mcheck_expected[NR_CPUS];
+static volatile unsigned int TSUNAMI_mcheck_taken[NR_CPUS];
+static unsigned int TSUNAMI_jd[NR_CPUS];
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+unsigned int TSUNAMI_DMA_WIN_BASE = TSUNAMI_DMA_WIN_BASE_DEFAULT;
+unsigned int TSUNAMI_DMA_WIN_SIZE = TSUNAMI_DMA_WIN_SIZE_DEFAULT;
+#endif /* SRM_SETUP */
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address
+ * accordingly.  It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Note that all config space accesses use Type 1 address format.
+ *
+ * Note also that type 1 is determined by non-zero bus number.
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     31:24   reserved
+ *     23:16   bus number (8 bits = 128 possible buses)
+ *     15:11   Device number (5 bits)
+ *     10:8    function number
+ *      7:2    register number
+ *  
+ * Notes:
+ *     The function number selects which function of a multi-function device 
+ *     (e.g., scsi and ethernet).
+ * 
+ *     The register selects a DWORD (32 bit) register offset.  Hence it
+ *     doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ *     bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+                       unsigned char where, unsigned long *pci_addr,
+                       unsigned char *type1)
+{
+       unsigned long addr;
+
+       DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
+            bus, device_fn, where, pci_addr, type1));
+
+       if (bus == 0) {
+               *type1 = 0;
+       } else {
+               /* type 1 configuration cycle: */
+               *type1 = 1;
+       }
+       addr = (bus << 16) | (device_fn << 8) | (where);
+       *pci_addr = addr;
+       DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+       return 0;
+}
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned char *value)
+{
+       unsigned long addr;
+       unsigned char type1;
+       unsigned char result;
+
+       *value = 0xff;
+
+       if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+TSUNAMI_PCI0_CONF)));
+
+       *value = result;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+                             unsigned char where, unsigned short *value)
+{
+       unsigned long addr;
+       unsigned char type1;
+       unsigned short result;
+
+       *value = 0xffff;
+
+       if (where & 0x1) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+TSUNAMI_PCI0_CONF)));
+
+       *value = result;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned int *value)
+{
+       unsigned long addr;
+       unsigned char type1;
+       unsigned int result;
+
+       *value = 0xffffffff;
+       if (where & 0x3) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &addr, &type1)) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+TSUNAMI_PCI0_CONF)));
+
+       *value = result;
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned char value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+TSUNAMI_PCI0_CONF)),
+                    "r" (value));
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned short value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       if (where & 0x1) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+TSUNAMI_PCI0_CONF)),
+                    "r" (value));
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+                               unsigned char where, unsigned int value)
+{
+       unsigned long addr;
+       unsigned char type1;
+
+       if (where & 0x3) {
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       }
+
+       if (mk_conf_addr(bus, device_fn, where, &addr, &type1) < 0) {
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+TSUNAMI_PCI0_CONF)),
+                    "r" (value));
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long tsunami_init(unsigned long mem_start, unsigned long mem_end)
+{
+        unsigned long tsunami_err;
+       unsigned int i;
+
+#if 0
+printk("tsunami_init: CChip registers:\n");
+printk("tsunami_init: CSR_CSC 0x%lx\n", *(vulp)TSUNAMI_CSR_CSC);
+printk("tsunami_init: CSR_MTR 0x%lx\n", *(vulp)TSUNAMI_CSR_MTR);
+printk("tsunami_init: CSR_MISC 0x%lx\n", *(vulp)TSUNAMI_CSR_MISC);
+printk("tsunami_init: CSR_DIM0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM0);
+printk("tsunami_init: CSR_DIM1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIM1);
+printk("tsunami_init: CSR_DIR0 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR0);
+printk("tsunami_init: CSR_DIR1 0x%lx\n", *(vulp)TSUNAMI_CSR_DIR1);
+printk("tsunami_init: CSR_DRIR 0x%lx\n", *(vulp)TSUNAMI_CSR_DRIR);
+
+printk("tsunami_init: DChip registers:\n");
+printk("tsunami_init: CSR_DSC 0x%lx\n", *(vulp)TSUNAMI_CSR_DSC);
+printk("tsunami_init: CSR_STR 0x%lx\n", *(vulp)TSUNAMI_CSR_STR);
+printk("tsunami_init: CSR_DREV 0x%lx\n", *(vulp)TSUNAMI_CSR_DREV);
+
+printk("tsunami_init: PChip registers:\n");
+printk("tsunami_init: PCHIP0_WSBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA0);
+printk("tsunami_init: PCHIP0_WSBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA1);
+printk("tsunami_init: PCHIP0_WSBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA2);
+printk("tsunami_init: PCHIP0_WSBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSBA3);
+printk("tsunami_init: PCHIP0_WSM0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM0);
+printk("tsunami_init: PCHIP0_WSM1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM1);
+printk("tsunami_init: PCHIP0_WSM2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM2);
+printk("tsunami_init: PCHIP0_WSM3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_WSM3);
+printk("tsunami_init: PCHIP0_TBA0 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA0);
+printk("tsunami_init: PCHIP0_TBA1 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA1);
+printk("tsunami_init: PCHIP0_TBA2 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA2);
+printk("tsunami_init: PCHIP0_TBA3 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_TBA3);
+
+printk("tsunami_init: PCHIP0_PCTL 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PCTL);
+printk("tsunami_init: PCHIP0_PLAT 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PLAT);
+printk("tsunami_init: PCHIP0_PERROR 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERROR);
+printk("tsunami_init: PCHIP0_PERRMASK 0x%lx\n", *(vulp)TSUNAMI_PCHIP0_PERRMASK);
+
+#endif
+
+       for (i = 0; i < NR_CPUS; i++) {
+               TSUNAMI_mcheck_expected[i] = 0;
+               TSUNAMI_mcheck_taken[i] = 0;
+       }
+#ifdef NOT_YET
+        /* 
+        * Set up error reporting. Make sure CPU_PE is OFF in the mask.
+        */
+       tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK;
+       tsunami_err &= ~20;   
+       *(vulp)TSUNAMI_PCHIP0_PERRMASK = tsunami_err;
+       mb();
+       tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERRMASK;
+
+       tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ;
+       tsunami_err |= 0x40;   /* master/target abort */
+       *(vulp)TSUNAMI_PCHIP0_PERROR = tsunami_err ;
+       mb() ;
+       tsunami_err = *(vulp)TSUNAMI_PCHIP0_PERROR ;
+#endif /* NOT_YET */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+       /* check window 0 for enabled and mapped to 0 */
+       if (((*(vulp)TSUNAMI_PCHIP0_WSBA0 & 3) == 1) &&
+           (*(vulp)TSUNAMI_PCHIP0_TBA0 == 0) &&
+           ((*(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U) > 0x0ff00000U))
+       {
+         TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA0 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM0 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("tsunami_init: using Window 0 settings\n");
+         printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vulp)TSUNAMI_PCHIP0_WSBA0,
+                *(vulp)TSUNAMI_PCHIP0_WSM0,
+                *(vulp)TSUNAMI_PCHIP0_TBA0);
+#endif
+       }
+       else  /* check window 1 for enabled and mapped to 0 */
+       if (((*(vulp)TSUNAMI_PCHIP0_WSBA1 & 3) == 1) &&
+           (*(vulp)TSUNAMI_PCHIP0_TBA1 == 0) &&
+           ((*(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U) > 0x0ff00000U))
+{
+         TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA1 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM1 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("tsunami_init: using Window 1 settings\n");
+         printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vulp)TSUNAMI_PCHIP0_WSBA1,
+                *(vulp)TSUNAMI_PCHIP0_WSM1,
+                *(vulp)TSUNAMI_PCHIP0_TBA1);
+#endif
+       }
+       else  /* check window 2 for enabled and mapped to 0 */
+       if (((*(vulp)TSUNAMI_PCHIP0_WSBA2 & 3) == 1) &&
+           (*(vulp)TSUNAMI_PCHIP0_TSB2 == 0) &&
+           ((*(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U) > 0x0ff00000U))
+       {
+         TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA2 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM2 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("tsunami_init: using Window 2 settings\n");
+         printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vulp)TSUNAMI_PCHIP0_WSBA2,
+                *(vulp)TSUNAMI_PCHIP0_WSM2,
+                *(vulp)TSUNAMI_PCHIP0_TSB2);
+#endif
+       }
+       else  /* check window 3 for enabled and mapped to 0 */
+       if (((*(vulp)TSUNAMI_PCHIP0_WSBA3 & 3) == 1) &&
+           (*(vulp)TSUNAMI_PCHIP0_TBA3 == 0) &&
+           ((*(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U) > 0x0ff00000U))
+       {
+         TSUNAMI_DMA_WIN_BASE = *(vulp)TSUNAMI_PCHIP0_WSBA3 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE = *(vulp)TSUNAMI_PCHIP0_WSM3 & 0xfff00000U;
+         TSUNAMI_DMA_WIN_SIZE += 0x00100000U;
+#if 1
+         printk("tsunami_init: using Window 3 settings\n");
+         printk("tsunami_init: BASE 0x%x MASK 0x%x TRANS 0x%x\n",
+                *(vulp)TSUNAMI_PCHIP0_WSBA3,
+                *(vulp)TSUNAMI_PCHIP0_WSM3,
+                *(vulp)TSUNAMI_PCHIP0_TBA3);
+#endif
+       }
+       else  /* we must use our defaults which were pre-initialized... */
+#endif /* SRM_SETUP */
+       {
+       /*
+        * Set up the PCI->physical memory translation windows.
+        * For now, windows 1,2 and 3 are disabled.  In the future, we may
+        * want to use them to do scatter/gather DMA.  Window 0
+        * goes at 1 GB and is 1 GB large.
+        */
+
+        *(vulp)TSUNAMI_PCHIP0_WSBA0 = 1L | (TSUNAMI_DMA_WIN_BASE & 0xfff00000U);
+        *(vulp)TSUNAMI_PCHIP0_WSM0 = (TSUNAMI_DMA_WIN_SIZE - 1) & 0xfff00000UL;
+        *(vulp)TSUNAMI_PCHIP0_TBA0 = 0UL;
+
+        *(vulp)TSUNAMI_PCHIP0_WSBA1 = 0UL;
+        *(vulp)TSUNAMI_PCHIP0_WSBA2 = 0UL;
+        *(vulp)TSUNAMI_PCHIP0_WSBA3 = 0UL;
+       mb();
+       }
+
+       /*
+        * check ASN in HWRPB for validity, report if bad
+        */
+       if (hwrpb->max_asn != MAX_ASN) {
+               printk("TSUNAMI_init: max ASN from HWRPB is bad (0x%lx)\n",
+                       hwrpb->max_asn);
+               hwrpb->max_asn = MAX_ASN;
+       }
+
+       return mem_start;
+}
+
+int tsunami_pci_clr_err(void)
+{
+       unsigned int cpu = smp_processor_id();
+
+       TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR);
+       DBG(("TSUNAMI_pci_clr_err: PERROR after read 0x%x\n", TSUNAMI_jd[cpu]));
+       *((vulp)TSUNAMI_PCHIP0_PERROR) = 0x040; mb();
+       TSUNAMI_jd[cpu] = *((vulp)TSUNAMI_PCHIP0_PERROR);
+       return 0;
+}
+
+void tsunami_machine_check(unsigned long vector, unsigned long la_ptr,
+                        struct pt_regs * regs)
+{
+#if 1
+        printk("TSUNAMI machine check ignored\n") ;
+#else
+       struct el_common *mchk_header;
+       struct el_TSUNAMI_sysdata_mcheck *mchk_sysdata;
+       unsigned int cpu = smp_processor_id();
+
+       mchk_header = (struct el_common *)la_ptr;
+
+       mchk_sysdata = 
+         (struct el_TSUNAMI_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
+
+#if 0
+       DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+            vector, la_ptr));
+       DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+            regs->pc, mchk_header->size, mchk_header->proc_offset,
+            mchk_header->sys_offset));
+       DBG_MCK(("tsunami_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
+            TSUNAMI_mcheck_expected[cpu], mchk_sysdata->epic_dcsr,
+            mchk_sysdata->epic_pear));
+#endif
+#ifdef DEBUG_MCHECK_DUMP
+       {
+           unsigned long *ptr;
+           int i;
+
+           ptr = (unsigned long *)la_ptr;
+           for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+               printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+           }
+       }
+#endif /* DEBUG_MCHECK_DUMP */
+       /*
+        * Check if machine check is due to a badaddr() and if so,
+        * ignore the machine check.
+        */
+       mb();
+       mb();  /* magic */
+       if (TSUNAMI_mcheck_expected[cpu]) {
+               DBG(("TSUNAMI machine check expected\n"));
+               TSUNAMI_mcheck_expected[cpu] = 0;
+               TSUNAMI_mcheck_taken[cpu] = 1;
+               mb();
+               mb();  /* magic */
+               draina();
+               tsunami_pci_clr_err();
+               wrmces(0x7);
+               mb();
+       }
+#if 1
+       else {
+               printk("TSUNAMI machine check NOT expected\n") ;
+       DBG_MCK(("tsunami_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+            vector, la_ptr));
+       DBG_MCK(("\t\t pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+            regs->pc, mchk_header->size, mchk_header->proc_offset,
+            mchk_header->sys_offset));
+               TSUNAMI_mcheck_expected[cpu] = 0;
+               TSUNAMI_mcheck_taken[cpu] = 1;
+               mb();
+               mb();  /* magic */
+               draina();
+               tsunami_pci_clr_err();
+               wrmces(0x7);
+               mb();
+       }
+#endif
+#endif
+}
+
+#endif /* CONFIG_ALPHA_TSUNAMI */
index e44639f..603b331 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 
+#ifdef __SMP__
+unsigned long last_asn[NR_CPUS] = { /* gag */
+  ASN_FIRST_VERSION +  (0 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (1 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (2 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (3 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (4 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (5 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (6 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (7 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (8 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION +  (9 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (10 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (11 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (12 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (13 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (14 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (15 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (16 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (17 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (18 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (19 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (20 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (21 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (22 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (23 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (24 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (25 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (26 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (27 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (28 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (29 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (30 << WIDTH_HARDWARE_ASN),
+  ASN_FIRST_VERSION + (31 << WIDTH_HARDWARE_ASN)
+};
+#else
 unsigned long asn_cache = ASN_FIRST_VERSION;
+#endif /* __SMP__ */
 
 #ifndef BROKEN_ASN
 /*
@@ -30,7+69,8 @@ unsigned long asn_cache = ASN_FIRST_VERSION;
  */
 void get_new_asn_and_reload(struct task_struct *tsk, struct mm_struct *mm)
 {
-       get_new_mmu_context(tsk, mm, asn_cache);
+       mm->context = 0;
+       get_new_mmu_context(tsk, mm);
        reload_context(tsk);
 }
 #endif
@@ -84,6+124,7 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr,
                }
        }
 
+       lock_kernel();
        down(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (!vma)
@@ -112,7+153,7 @@ good_area:
        }
        handle_mm_fault(current, vma, address, cause > 0);
        up(&mm->mmap_sem);
-       return;
+       goto out;
 
 /*
  * Something tried to access memory that isn't in our memory map..
@@ -123,16+164,17 @@ bad_area:
 
        if (user_mode(regs)) {
                force_sig(SIGSEGV, current);
-               return;
+               goto out;
        }
 
        /* Are we prepared to handle this fault as an exception?  */
        if ((fixup = search_exception_table(regs->pc)) != 0) {
                unsigned long newpc;
                newpc = fixup_exception(dpf_reg, fixup, regs->pc);
-               printk("%s: Exception at [<%lx>] (%lx)\n", current->comm, regs->pc, newpc);
+               printk("%s: Exception at [<%lx>] (%lx)\n",
+                      current->comm, regs->pc, newpc);
                regs->pc = newpc;
-               return;
+               goto out;
        }
 
 /*
@@ -143,4+185,7 @@ bad_area:
               "virtual address %016lx\n", address);
        die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
        do_exit(SIGKILL);
+ out:
+       unlock_kernel();
 }
+
index 67faa97..7562f67 100644 (file)
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
+struct thread_struct * original_pcb_ptr;
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -81,15+83,22 @@ void show_mem(void)
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
-static void load_PCB(struct thread_struct * pcb)
+static struct thread_struct * load_PCB(struct thread_struct * pcb)
 {
+       struct thread_struct *old_pcb;
+
        __asm__ __volatile__(
-               "stq $30,0(%0)\n\t"
-               "bis %0,%0,$16\n\t"
-               "call_pal %1"
-               : /* no outputs */
+               "stq $30,0(%1)\n\t"
+               "bis %1,%1,$16\n\t"
+#ifdef CONFIG_ALPHA_DP264
+               "zap $16,0xe0,$16\n\t"
+#endif /* DP264 */
+               "call_pal %2\n\t"
+               "bis $0,$0,%0"
+               : "=r" (old_pcb)
                : "r" (pcb), "i" (PAL_swpctx)
                : "$0", "$1", "$16", "$22", "$23", "$24", "$25");
+       return old_pcb;
 }
 
 /*
@@ -107,7+116,8 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        start_mem = free_area_init(start_mem, end_mem);
 
        /* find free clusters, update mem_map[] accordingly */
-       memdesc = (struct memdesc_struct *) (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
+       memdesc = (struct memdesc_struct *)
+               (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
        cluster = memdesc->cluster;
        for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
                unsigned long pfn, nr;
@@ -129,16+139,47 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
        memset(swapper_pg_dir, 0, PAGE_SIZE);
        newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
-       pgd_val(swapper_pg_dir[1023]) = (newptbr << 32) | pgprot_val(PAGE_KERNEL);
+       pgd_val(swapper_pg_dir[1023]) =
+               (newptbr << 32) | pgprot_val(PAGE_KERNEL);
        init_task.tss.ptbr = newptbr;
        init_task.tss.pal_flags = 1;    /* set FEN, clear everything else */
        init_task.tss.flags = 0;
-       load_PCB(&init_task.tss);
+       original_pcb_ptr =
+         phys_to_virt((unsigned long)load_PCB(&init_task.tss));
+#if 0
+printk("OKSP 0x%lx OPTBR 0x%lx\n",
+       original_pcb_ptr->ksp, original_pcb_ptr->ptbr);
+#endif
 
-       flush_tlb_all();
+       tbia();
        return start_mem;
 }
 
+#ifdef __SMP__
+/*
+ * paging_init_secondary(), called ONLY by secondary CPUs,
+ * sets up current->tss contents appropriately and does a load_PCB.
+ * note that current should be pointing at the idle thread task struct
+ * for this CPU.
+ */
+void paging_init_secondary(void)
+{
+       current->tss.ptbr = init_task.tss.ptbr;
+       current->tss.pal_flags = 1;
+       current->tss.flags = 0;
+
+#if 0
+printk("paging_init_secondary: KSP 0x%lx PTBR 0x%lx\n",
+       current->tss.ksp, current->tss.ptbr);
+#endif
+
+       load_PCB(&current->tss);
+       tbia();
+
+       return;
+}
+#endif /* __SMP__ */
+
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
        unsigned long tmp;
index b95c2f1..a02f294 100644 (file)
@@ -105,17+105,6 @@ fi
 # fi
 # endmenu
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 source fs/nls/Config.in
index 4835855..3953955 100644 (file)
@@ -169,7+169,6 @@ CONFIG_PPP=m
 CONFIG_ETHER1=m
 CONFIG_ETHER3=m
 CONFIG_ETHERH=m
-CONFIG_CDROM=y
 
 #
 # Filesystems
index fb1bd55..0aa8ddc 100644 (file)
@@ -37,10+37,10 @@ startup_32:
        cld
        cli
        movl $(__KERNEL_DS),%eax
-       mov %ax,%ds
-       mov %ax,%es
-       mov %ax,%fs
-       mov %ax,%gs
+       movl %ax,%ds
+       movl %ax,%es
+       movl %ax,%fs
+       movl %ax,%gs
 #ifdef __SMP__
        orw %bx,%bx                     # What state are we in BX=1 for SMP
                                        # 0 for boot
index 058f908..ee53040 100644 (file)
@@ -114,17+114,6 @@ if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
 fi
 endmenu
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_MCDX" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_CDU31A" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" -o "$CONFIG_SBPCD" = "m" -o "$CONFIG_MCD" = "m" -o "$CONFIG_MCDX" = "m" -o "$CONFIG_CM206" = "m" -o "$CONFIG_CDU31A" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 source fs/nls/Config.in
index f3792ce..eff1006 100644 (file)
@@ -214,7+214,6 @@ CONFIG_EEXPRESS_PRO100=y
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
-CONFIG_CDROM=y
 
 #
 # Filesystems
index 14b82b4..edec2e2 100644 (file)
@@ -81,8+81,8 @@ ENOSYS = 38
 
 #define SAVE_ALL \
        cld; \
-       push %es; \
-       push %ds; \
+       pushl %es; \
+       pushl %ds; \
        pushl %eax; \
        pushl %ebp; \
        pushl %edi; \
@@ -91,8+91,8 @@ ENOSYS = 38
        pushl %ecx; \
        pushl %ebx; \
        movl $(__KERNEL_DS),%edx; \
-       mov %dx,%ds; \
-       mov %dx,%es;
+       movl %dx,%ds; \
+       movl %dx,%es;
 
 #define RESTORE_ALL \
        popl %ebx; \
@@ -102,8+102,8 @@ ENOSYS = 38
        popl %edi; \
        popl %ebp; \
        popl %eax; \
-       pop %ds; \
-       pop %es; \
+       popl %ds; \
+       popl %es; \
        addl $4,%esp; \
        iret
 
@@ -231,7+231,7 @@ ENTRY(divide_error)
        pushl $ SYMBOL_NAME(do_divide_error)
        ALIGN
 error_code:
-       push %ds
+       pushl %ds
        pushl %eax
        xorl %eax,%eax
        pushl %ebp
@@ -241,17+241,27 @@ error_code:
        decl %eax                       # eax = -1
        pushl %ecx
        pushl %ebx
+#if 1
        xorl %ecx,%ecx                  # zero ecx
        cld
        mov %es,%cx                     # get the lower order bits of es
+#else
+       cld
+# Some older processors leave the top 16 bits of the 32 bit destination
+# register undefined, rather than zeroed in the following instruction.
+# This won't matter when restoring or loading a segment register from the
+# stack.  It may be a problem if any code reads the full 32 bit value.
+# dosemu? kernel?  Would somebody like to verify that this way is really OK?
+       movl %es,%cx
+#endif
        xchgl %eax, ORIG_EAX(%esp)      # orig_eax (get the error code. )
        movl %esp,%edx
        xchgl %ecx, ES(%esp)            # get the address and save es.
        pushl %eax                      # push the error code
        pushl %edx
        movl $(__KERNEL_DS),%edx
-       mov %dx,%ds
-       mov %dx,%es
+       movl %dx,%ds
+       movl %dx,%es
        GET_CURRENT(%ebx)
        call *%ecx
        addl $8,%esp
index 0489218..3d80cde 100644 (file)
@@ -45,10+45,10 @@ startup_32:
  */
        cld
        movl $(__KERNEL_DS),%eax
-       mov %ax,%ds
-       mov %ax,%es
-       mov %ax,%fs
-       mov %ax,%gs
+       movl %ax,%ds
+       movl %ax,%es
+       movl %ax,%fs
+       movl %ax,%gs
 #ifdef __SMP__
        orw %bx,%bx
        jz 1f
@@ -321,10+321,10 @@ is386:    pushl %ecx              # restore original EFLAGS
        lidt idt_descr
        ljmp $(__KERNEL_CS),$1f
 1:     movl $(__KERNEL_DS),%eax        # reload all the segment registers
-       mov %ax,%ds             # after changing gdt.
-       mov %ax,%es
-       mov %ax,%fs
-       mov %ax,%gs
+       movl %ax,%ds            # after changing gdt.
+       movl %ax,%es
+       movl %ax,%fs
+       movl %ax,%gs
 #ifdef __SMP__
        movl $(__KERNEL_DS), %eax
        mov  %ax,%ss            # Reload the stack pointer (segment only)
@@ -404,16+404,16 @@ ignore_int:
        pushl %eax
        pushl %ecx
        pushl %edx
-       push %es
-       push %ds
+       pushl %es
+       pushl %ds
        movl $(__KERNEL_DS),%eax
-       mov %ax,%ds
-       mov %ax,%es
+       movl %ax,%ds
+       movl %ax,%es
        pushl $int_msg
        call SYMBOL_NAME(printk)
        popl %eax
-       pop %ds
-       pop %es
+       popl %ds
+       popl %es
        popl %edx
        popl %ecx
        popl %eax
index 9824026..2658bda 100644 (file)
@@ -83,8+83,8 @@ static inline void irq_exit(int cpu, unsigned int irq)
 
 #define SAVE_ALL \
        "cld\n\t" \
-       "push %es\n\t" \
-       "push %ds\n\t" \
+       "pushl %es\n\t" \
+       "pushl %ds\n\t" \
        "pushl %eax\n\t" \
        "pushl %ebp\n\t" \
        "pushl %edi\n\t" \
@@ -93,8+93,8 @@ static inline void irq_exit(int cpu, unsigned int irq)
        "pushl %ecx\n\t" \
        "pushl %ebx\n\t" \
        "movl $" STR(__KERNEL_DS) ",%edx\n\t" \
-       "mov %dx,%ds\n\t" \
-       "mov %dx,%es\n\t"
+       "movl %dx,%ds\n\t" \
+       "movl %dx,%es\n\t"
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
index 6ba4e0f..741453c 100644 (file)
@@ -375,12+375,12 @@ void machine_restart(char * __unused)
           registers don't have to be reloaded after switching to real mode:
           the values are consistent for real mode operation already. */
 
-       __asm__ __volatile__ ("movw $0x0010,%%ax\n"
-                               "\tmovw %%ax,%%ds\n"
-                               "\tmovw %%ax,%%es\n"
-                               "\tmovw %%ax,%%fs\n"
-                               "\tmovw %%ax,%%gs\n"
-                               "\tmovw %%ax,%%ss" : : : "eax");
+       __asm__ __volatile__ ("movl $0x0010,%%eax\n"
+                               "\tmovl %%ax,%%ds\n"
+                               "\tmovl %%ax,%%es\n"
+                               "\tmovl %%ax,%%fs\n"
+                               "\tmovl %%ax,%%gs\n"
+                               "\tmovl %%ax,%%ss" : : : "eax");
 
        /* Jump to the 16-bit code that we copied earlier.  It disables paging
           and the cache, switches to real mode, and jumps to the BIOS reset
@@ -428,7+428,7 @@ void exit_thread(void)
        if (last_task_used_math == current)
                last_task_used_math = NULL;
        /* forget local segments */
-       __asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
+       __asm__ __volatile__("movl %w0,%%fs ; movl %w0,%%gs ; lldt %w0"
                : /* no outputs */
                : "r" (0));
        current->tss.ldt = 0;
@@ -583,8+583,8 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
        dump->regs.eax = regs->eax;
        dump->regs.ds = regs->xds;
        dump->regs.es = regs->xes;
-       __asm__("mov %%fs,%0":"=r" (dump->regs.fs));
-       __asm__("mov %%gs,%0":"=r" (dump->regs.gs));
+       __asm__("movl %%fs,%0":"=r" (dump->regs.fs));
+       __asm__("movl %%gs,%0":"=r" (dump->regs.gs));
        dump->regs.orig_eax = regs->orig_eax;
        dump->regs.eip = regs->eip;
        dump->regs.cs = regs->xcs;
index 12a777b..c17c135 100644 (file)
@@ -199,7+199,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
              && (tmp & 0x4) != 0x4     /* not a LDT selector */        \
              && (tmp & 3) != 3)        /* not a RPL3 GDT selector */   \
                  goto badframe;                                        \
-         __asm__ __volatile__("mov %w0,%%" #seg : : "r"(tmp)); }
+         __asm__ __volatile__("movl %w0,%%" #seg : : "r"(tmp)); }
 
        GET_SEG(gs);
        GET_SEG(fs);
@@ -337,9+337,9 @@ setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate,
        unsigned int tmp;
 
        tmp = 0;
-       __asm__("mov %%gs,%w0" : "=r"(tmp): "0"(tmp));
+       __asm__("movl %%gs,%w0" : "=r"(tmp): "0"(tmp));
        __put_user(tmp, (unsigned int *)&sc->gs);
-       __asm__("mov %%fs,%w0" : "=r"(tmp): "0"(tmp));
+       __asm__("movl %%fs,%w0" : "=r"(tmp): "0"(tmp));
        __put_user(tmp, (unsigned int *)&sc->fs);
 
        __put_user(regs->xes, (unsigned int *)&sc->es);
@@ -427,7+427,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        regs->eip = (unsigned long) ka->sa.sa_handler;
        {
                unsigned long seg = __USER_DS;
-               __asm__("mov %w0,%%fs ; mov %w0,%%gs": "=r"(seg) : "0"(seg));
+               __asm__("movl %w0,%%fs ; movl %w0,%%gs": "=r"(seg) : "0"(seg));
                set_fs(USER_DS);
                regs->xds = seg;
                regs->xes = seg;
@@ -492,7+492,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->eip = (unsigned long) ka->sa.sa_handler;
        {
                unsigned long seg = __USER_DS;
-               __asm__("mov %w0,%%fs ; mov %w0,%%gs": "=r"(seg) : "0"(seg));
+               __asm__("movl %w0,%%fs ; movl %w0,%%gs": "=r"(seg) : "0"(seg));
                set_fs(USER_DS);
                regs->xds = seg;
                regs->xes = seg;
index fdcf951..754e937 100644 (file)
@@ -68,19+68,19 @@ out: \
 
 #define get_seg_byte(seg,addr) ({ \
 register unsigned char __res; \
-__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \
+__asm__("pushl %%fs;movl %%ax,%%fs;movb %%fs:%2,%%al;popl %%fs" \
        :"=a" (__res):"0" (seg),"m" (*(addr))); \
 __res;})
 
 #define get_seg_long(seg,addr) ({ \
 register unsigned long __res; \
-__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \
+__asm__("pushl %%fs;movl %%ax,%%fs;movl %%fs:%2,%%eax;popl %%fs" \
        :"=a" (__res):"0" (seg),"m" (*(addr))); \
 __res;})
 
 #define _fs() ({ \
 register unsigned short __res; \
-__asm__("mov %%fs,%%ax":"=a" (__res):); \
+__asm__("movl %%fs,%%ax":"=a" (__res):); \
 __res;})
 
 void page_exception(void);
index 5ae87b0..db7da10 100644 (file)
@@ -255,7+255,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
                mark_screen_rdonly(tsk);
        unlock_kernel();
        __asm__ __volatile__(
-               "xorl %%eax,%%eax; mov %%ax,%%fs; mov %%ax,%%gs\n\t"
+               "xorl %%eax,%%eax; movl %%ax,%%fs; movl %%ax,%%gs\n\t"
                "movl %0,%%esp\n\t"
                "jmp ret_from_sys_call"
                : /* no outputs */
index e6c984b..8ad01e6 100644 (file)
@@ -269,17+269,6 @@ endmenu
 
 fi
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 if [ "$CONFIG_VME" = "n" ]; then
index 72bab89..c6ab44e 100644 (file)
@@ -149,17+149,6 @@ if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
 fi
 endmenu
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_CDU31A" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_SR" = "m" -o "$CONFIG_SBPCD" = "m" -o "$CONFIG_MCD" = "m" -o "$CONFIG_CM206" = "m" -o "$CONFIG_CDU31A" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 source fs/nls/Config.in
index 4a087fc..6e3d501 100644 (file)
@@ -159,17+159,6 @@ if [ "$CONFIG_NET" = "y" ]; then
        endmenu
 fi
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_SR" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_SR" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 source fs/nls/Config.in
index 4461cde..4af9da2 100644 (file)
@@ -218,17+218,6 @@ if [ "$CONFIG_NET" = "y" ]; then
        endmenu
 fi
 
-# Conditionally compile in the Uniform CD-ROM driver
-if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" ]; then
-  define_bool CONFIG_CDROM y
-else
-  if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" ]; then
-    define_bool CONFIG_CDROM m
-  else
-    define_bool CONFIG_CDROM n
-  fi
-fi
-
 source fs/Config.in
 
 source fs/nls/Config.in
index f3c2e2c..740fd68 100644 (file)
@@ -205,7+205,6 @@ CONFIG_HAPPYMEAL=y
 CONFIG_SUNQE=m
 CONFIG_MYRI_SBUS=m
 CONFIG_DE4X5=y
-CONFIG_CDROM=y
 
 #
 # Filesystems
index 27b7d4c..98b94ca 100644 (file)
  *                         inform me of where "Illegal mode for this track"
  *                         was never returned due to a comparison on data
  *                         types of limited range.
+ * 4.12  Mar 29, 1998  -- Fixed bug in CDROM_SELECT_SPEED so write speed is 
+ *                         now set ionly for CD-R and CD-RW drives.  I had 
+ *                         removed this support because it produced errors.
+ *                         It produced errors _only_ for non-writers. duh.
  *
  *************************************************************************/
 
-#define IDECD_VERSION "4.11"
+#define IDECD_VERSION "4.12"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -276,32+280,34 @@ void cdrom_analyze_sense_data (ide_drive_t *drive,
                char buf[80];
 
                printk ("ATAPI device %s:\n", drive->name);
-
-               printk ("  Error code: 0x%02x\n", reqbuf->error_code);
+               if (reqbuf->error_code==0x70)
+                       printk("  Error: ");
+               else if (reqbuf->error_code==0x71)
+                       printk("  Deferred Error: ");
+               else
+                       printk("  Unknown Error Type: ");
 
                if ( reqbuf->sense_key < ARY_LEN (sense_key_texts))
                        s = sense_key_texts[reqbuf->sense_key];
                else
-                       s = "(bad sense key)";
+                       s = "bad sense key!";
 
-               printk ("  Sense key: 0x%02x - %s\n", reqbuf->sense_key, s);
+               printk ("%s -- (Sense key=0x%02x)\n", s, reqbuf->sense_key);
 
                if (reqbuf->asc == 0x40) {
                        sprintf (buf, "Diagnostic failure on component 0x%02x",
                                 reqbuf->ascq);
                        s = buf;
                } else {
-                       int lo, hi;
+                       int lo=0, mid, hi=ARY_LEN (sense_data_texts);
                        unsigned short key = (reqbuf->asc << 8);
                        if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) )
                                key |= reqbuf->ascq;
 
-                       lo = 0;
-                       hi = ARY_LEN (sense_data_texts);
                        s = NULL;
 
                        while (hi > lo) {
-                               int mid = (lo + hi) / 2;
+                               mid = (lo + hi) / 2;
                                if (sense_data_texts[mid].asc_ascq == key) {
                                        s = sense_data_texts[mid].text;
                                        break;
@@ -320,14+326,30 @@ void cdrom_analyze_sense_data (ide_drive_t *drive,
                                s = "(reserved error code)";
                }
 
-               printk ("  Additional sense data: 0x%02x, 0x%02x  - %s\n",
-                       reqbuf->asc, reqbuf->ascq, s);
+               printk ("  %s -- (asc=0x%02x, ascq=0x%02x)\n",
+                       s, reqbuf->asc, reqbuf->ascq);
 
                if (failed_command != NULL) {
-                       printk ("  Failed packet command: ");
+
+                       int lo=0, mid, hi= ARY_LEN (packet_command_texts);
+                       s = NULL;
+
+                       while (hi > lo) {
+                               mid = (lo + hi) / 2;
+                               if (packet_command_texts[mid].packet_command == failed_command->c[0]) {
+                                       s = packet_command_texts[mid].text;
+                                       break;
+                               }
+                               else if (packet_command_texts[mid].packet_command > failed_command->c[0])
+                                       hi = mid;
+                               else
+                                       lo = mid+1;
+                       }
+
+                       printk ("  The failed \"%s\" packet command was: \n\t\"", s);
                        for (i=0; i<sizeof (failed_command->c); i++)
                                printk ("%02x ", failed_command->c[i]);
-                       printk ("\n");
+                       printk ("\"\n");
                }
 
                if (reqbuf->sense_key == ILLEGAL_REQUEST &&
@@ -358,7+380,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive,
                                                reqbuf->asc == 0x3a)))
                return;
 
-       printk ("%s: code: 0x%02x  key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
+       printk ("%s: error code: 0x%02x  sense_key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",
                drive->name,
                reqbuf->error_code, reqbuf->sense_key,
                reqbuf->asc, reqbuf->ascq);
@@ -1486,6+1508,9 @@ cdrom_eject (ide_drive_t *drive, int ejectflag,
 {
        struct packet_command pc;
 
+       if (CDROM_CONFIG_FLAGS (drive)->no_eject==1 && ejectflag==0)
+               return -EDRIVE_CANT_DO_THIS;
+
        memset (&pc, 0, sizeof (pc));
        pc.sense_data = reqbuf;
 
@@ -1747,16+1772,7 @@ cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen,
 }
 
 
-/* Note that this takes speed in kbytes/second, so don't try requesting
-   silly speeds like 2 here. Common speeds include:
-     176 kbytes/second  --  1x
-     353 kbytes/second  --  2x
-     387 kbytes/second  --  2.2x
-     528 kbytes/second  --  3x
-     706 kbytes/second  --  4x
-     1400 kbytes/second --  8x
-     2800 kbytes/second --  16x
-   ATAPI drives are free to select the speed you request or any slower
+/* ATAPI cdrom drives are free to select the speed you request or any slower
    rate :-( Requesting too fast a speed will _not_ produce an error. */
 static int
 cdrom_select_speed (ide_drive_t *drive, int speed,
@@ -1766,7+1782,7 @@ cdrom_select_speed (ide_drive_t *drive, int speed,
        memset (&pc, 0, sizeof (pc));
        pc.sense_data = reqbuf;
 
-       if (speed < 1)
+       if (speed == 0)
            speed = 0xffff; /* set to max */
        else
            speed *= 177;   /* Nx to kbytes/s */
@@ -1776,10+1792,13 @@ cdrom_select_speed (ide_drive_t *drive, int speed,
        pc.c[2] = (speed >> 8) & 0xff;  
        /* Read Drive speed in kbytes/second LSB */
        pc.c[3] = speed & 0xff;
-       /* Write Drive speed in kbytes/second MSB */
-       //pc.c[4] = (speed >> 8) & 0xff;        
-       /* Write Drive speed in kbytes/second LSB */
-       //pc.c[5] = speed & 0xff;
+       if ( CDROM_CONFIG_FLAGS(drive)->cd_r ||
+                   CDROM_CONFIG_FLAGS(drive)->cd_rw ) {
+               /* Write Drive speed in kbytes/second MSB */
+               pc.c[4] = (speed >> 8) & 0xff;
+               /* Write Drive speed in kbytes/second LSB */
+               pc.c[5] = speed & 0xff;
+       }
 
        return cdrom_queue_packet_command (drive, &pc);
 }
@@ -2485,7+2504,7 @@ int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
        if (stat<0)
                return stat;
 
-       /* Now that that is done, update the speed fields */
+       /* Now with that done, update the speed fields */
         do {    /* we seem to get stat=0x01,err=0x00 the first time (??) */
                 if (attempts-- <= 0)
                         return 0;
@@ -2802,6+2821,8 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
 
        if (buf.cap.lock == 0)
                CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+       if (buf.cap.eject)
+               CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
        if (buf.cap.cd_r_write)
                CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
        if (buf.cap.cd_rw_write)
@@ -2903,6+2924,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
        CDROM_CONFIG_FLAGS (drive)->is_changer = 0;
        CDROM_CONFIG_FLAGS (drive)->cd_r = 0;
        CDROM_CONFIG_FLAGS (drive)->cd_rw = 0;
+       CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
        CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
 
 #if ! STANDARD_ATAPI
index 140c4cc..1c73b2d 100644 (file)
    (Some other cdrom-specific codes are in cdrom.h.) */
 #define TEST_UNIT_READY         0x00
 #define REQUEST_SENSE           0x03
+#define INQUIRY                 0x12
 #define START_STOP              0x1b
 #define ALLOW_MEDIUM_REMOVAL    0x1e
-#define READ_CAPACITY          0x25
+#define READ_CAPACITY           0x25
 #define READ_10                 0x28
 #define SEEK                   0x2b
-#define MODE_SENSE_10           0x5a
+#define READ_HEADER             0x44
+#define STOP_PLAY_SCAN         0x4e
 #define MODE_SELECT_10          0x55
-#define READ_CD                 0xbe
-#define SET_CD_SPEED            0xbb
+#define MODE_SENSE_10           0x5a
 #define LOAD_UNLOAD             0xa6
+#define READ_12                 0xa8
+#define READ_CD_MSF             0xb9
+#define SCAN                   0xba
+#define SET_CD_SPEED            0xbb
+#define PLAY_CD                 0xbc
 #define MECHANISM_STATUS        0xbd
+#define READ_CD                 0xbe
 
 
 /* Page codes for mode sense/set */
 #define PAGE_ALL                0x3f
 
 
-/* ATAPI sense keys (mostly copied from scsi.h). */
+/* ATAPI sense keys (from table 140 of ATAPI 2.6) */
 
 #define NO_SENSE                0x00
 #define RECOVERED_ERROR         0x01
@@ -109,6+116,7 @@ struct ide_cd_config_flags {
        __u8 drq_interrupt    : 1; /* Device sends an interrupt when ready
                                      for a packet command. */
        __u8 no_doorlock      : 1; /* Drive cannot lock the door. */
+       __u8 no_eject         : 1; /* Drive cannot eject the disc. */
        __u8 nec260           : 1; /* Drive is a pre-1.2 NEC 260 drive. */
        __u8 playmsf_as_bcd   : 1; /* PLAYMSF command takes BCD args. */
        __u8 tocaddr_as_bcd   : 1; /* TOC addresses are in BCD. */
@@ -427,6+435,39 @@ char *sense_key_texts[16] = {
 };
 
 
+/* From Table 37 of the ATAPI 2.6 draft standard. */
+struct {
+       unsigned short packet_command;
+       char *text;
+} packet_command_texts[] = {
+       { TEST_UNIT_READY, "Test Unit Ready" },
+       { REQUEST_SENSE, "Request Sense" },
+       { INQUIRY, "Inquiry" },
+       { START_STOP, "Start Stop Unit" },
+       { ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
+       { READ_CAPACITY, "Read CD-ROM Capacity" },
+       { READ_10, "Read(10)" },
+       { SEEK, "Seek" },
+       { SCMD_READ_TOC, "Read TOC" },
+       { SCMD_READ_SUBCHANNEL, "Read Sub-Channel" },
+       { READ_HEADER, "Read Header" },
+       { STOP_PLAY_SCAN, "Stop Play/Scan" },
+       { SCMD_PLAYAUDIO10, "Play Audio" },
+       { SCMD_PLAYAUDIO_MSF, "Play Audio MSF" },
+       { SCMD_PAUSE_RESUME, "Pause/Resume" },
+       { MODE_SELECT_10, "Mode Select" },
+       { MODE_SENSE_10, "Mode Sense" },
+       { LOAD_UNLOAD, "Load/Unload CD" },
+       { READ_12, "Read(12)" },
+       { READ_CD_MSF, "Read CD MSF" },
+       { SCAN, "Scan" },
+       { SET_CD_SPEED, "Set CD Speed" },
+       { PLAY_CD, "Play CD" },
+       { MECHANISM_STATUS, "Mechanism Status" },
+       { READ_CD, "Read CD" },
+};
+
+
 /* From Table 125 of the ATAPI 1.2 spec.,
    with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */
 
index 8c72c79..066896b 100644 (file)
@@ -496,25+496,13 @@ static void idedisk_pre_reset (ide_drive_t *drive)
                drive->special.b.set_multmode = 1;
 }
 
-static int proc_idedisk_read_cache
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-       ide_drive_t     *drive = (ide_drive_t *) data;
-       char            *out = page;
-       int             len;
-
-       if (drive->id)
-               len = sprintf(out,"%i\n", drive->id->buf_size / 2);
-       else
-               len = sprintf(out,"(none)\n");
-       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
 static int smart_enable(ide_drive_t *drive)
 {
        return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL);
 }
 
+#ifdef CONFIG_PROC_FS
+
 static int get_smart_values(ide_drive_t *drive, byte *buf)
 {
        (void) smart_enable(drive);
@@ -527,6+515,20 @@ static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
        return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf);
 }
 
+static int proc_idedisk_read_cache
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       char            *out = page;
+       int             len;
+
+       if (drive->id)
+               len = sprintf(out,"%i\n", drive->id->buf_size / 2);
+       else
+               len = sprintf(out,"(none)\n");
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
 static int proc_idedisk_read_smart_thresholds
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -566,13+568,19 @@ static int proc_idedisk_read_smart_values
 }
 
 static ide_proc_entry_t idedisk_proc[] = {
-       { "cache", proc_idedisk_read_cache, NULL },
-       { "geometry", proc_ide_read_geometry, NULL },
-       { "smart_values", proc_idedisk_read_smart_values, NULL },
-       { "smart_thresholds", proc_idedisk_read_smart_thresholds, NULL },
-       { NULL, NULL, NULL }
+       { "cache",              S_IFREG|S_IRUGO,        proc_idedisk_read_cache,                NULL },
+       { "geometry",           S_IFREG|S_IRUGO,        proc_ide_read_geometry,                 NULL },
+       { "smart_values",       S_IFREG|S_IRUSR,        proc_idedisk_read_smart_values,         NULL },
+       { "smart_thresholds",   S_IFREG|S_IRUSR,        proc_idedisk_read_smart_thresholds,     NULL },
+       { NULL, 0, NULL, NULL }
 };
 
+#else
+
+#define        idedisk_proc    NULL
+
+#endif /* CONFIG_PROC_FS */
+
 static int set_multcount(ide_drive_t *drive, int arg)
 {
        struct request rq;
index d79f79a..a4aa0b4 100644 (file)
@@ -1379,11+1379,19 @@ static int idefloppy_cleanup (ide_drive_t *drive)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
+
 static ide_proc_entry_t idefloppy_proc[] = {
-       { "geometry", proc_ide_read_geometry, NULL },
-       { NULL, NULL, NULL }
+       { "geometry",   S_IFREG|S_IRUGO,        proc_ide_read_geometry, NULL },
+       { NULL, 0, NULL, NULL }
 };
 
+#else
+
+#define        idefloppy_proc  NULL
+
+#endif /* CONFIG_PROC_FS */
+
 /*
  *     IDE subdriver functions, registered with ide.c
  */
index 9e8fd51..6353c80 100644 (file)
@@ -174,9+174,13 @@ __initfunc(static ide_hwif_t *ide_match_hwif (unsigned int io_base, const char *
         * just in case there's another interface yet-to-be-scanned
         * which uses ports 1f0/170 (the ide0/ide1 defaults).
         */
-       for (h = 0; h < MAX_HWIFS; ++h) {
-               int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */
-               hwif = &ide_hwifs[hwifs[h]];
+       for (h = 2; h < MAX_HWIFS; ++h) {
+               hwif = ide_hwifs + h;
+               if (hwif->chipset == ide_unknown)
+                       return hwif;    /* pick an unused entry */
+       }
+       for (h = 0; h < 2; ++h) {
+               hwif = ide_hwifs + h;
                if (hwif->chipset == ide_unknown)
                        return hwif;    /* pick an unused entry */
        }
@@ -366,8+370,10 @@ static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)
                 * workaround Intel Advanced/ZP with bios <= 1.04;
                 * these appear in some Dell Dimension XPS's 
                 */
-               if (!hedt && IDE_PCI_DEVID_EQ(devid, DEVID_PIIXa))
+               if (!hedt && IDE_PCI_DEVID_EQ(devid, DEVID_PIIXa)) {
+                       printk("ide: implementing workaround for PIIX detection\n");
                        hedt = 0x80;
+               }
 
                for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
                if (d->init_hwif == IDE_IGNORE)
@@ -382,7+388,7 @@ static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)
                                printk("%s: IDE controller on PCI bus %d function %d\n", d->name, bus, fn);
                        ide_setup_pci_device(bus, fn, ccode, d);
                }
-       } while (hedt == 0x80 && (++fn & 7));
+       } while ((hedt & 0x80) && (++fn & 7));
 }
 
 /*
index 57b4a1f..b2ea1bf 100644 (file)
@@ -662,6+662,12 @@ static int hwif_init (ide_hwif_t *hwif)
 #if MAX_HWIFS > 3
        case IDE3_MAJOR: rfn = &do_ide3_request; break;
 #endif
+#if MAX_HWIFS > 4
+       case IDE4_MAJOR: rfn = &do_ide4_request; break;
+#endif
+#if MAX_HWIFS > 5
+       case IDE5_MAJOR: rfn = &do_ide5_request; break;
+#endif
        default:
                printk("%s: request_fn NOT DEFINED\n", hwif->name);
                return (hwif->present = 0);
index e9dad1c..1b4871d 100644 (file)
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifdef CONFIG_PCI
-
 static int ide_getxdigit(char c)
 {
        int digit;
@@ -125,7+123,7 @@ static int proc_ide_write_config
        }
        /*
         * Do one full pass to verify all parameters,
-        * then do another to actually write the pci regs.
+        * then do another to actually write the regs.
         */
        save_flags(flags);
        do {
@@ -136,11+134,11 @@ static int proc_ide_write_config
                        ide_hwgroup_t *mategroup = NULL;
                        if (hwif->mate && hwif->mate->hwgroup)
                                mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
-                       cli();  /* ensure all PCI writes are done together */
+                       cli();  /* ensure all writes are done together */
                        while (mygroup->active || (mategroup && mategroup->active)) {
                                restore_flags(flags);
                                if (0 < (signed long)(jiffies - timeout)) {
-                                       printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
+                                       printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
                                        return -EBUSY;
                                }
                                cli();
@@ -157,7+155,12 @@ static int proc_ide_write_config
                                case 'R':       is_pci = 0;
                                                break;
                                case 'P':       is_pci = 1;
-                                               break;
+#ifdef CONFIG_BLK_DEV_IDEPCI
+                                               if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+                                                       break;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+                                               msg = "not a PCI device";
+                                               goto parse_error;
                                default:        msg = "expected 'R' or 'P'";
                                                goto parse_error;
                        }
@@ -195,15+198,18 @@ static int proc_ide_write_config
                                --n;
                                ++p;
                        }
+#ifdef CONFIG_BLK_DEV_IDEPCI
                        if (is_pci && (reg & ((digits >> 1) - 1))) {
                                msg = "misaligned access";
                                goto parse_error;
                        }
+#endif /* CONFIG_BLK_DEV_IDEPCI */
                        if (for_real) {
 #if 0
                                printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits);
 #endif
                                if (is_pci) {
+#ifdef CONFIG_BLK_DEV_IDEPCI
                                        int rc = 0;
                                        switch (digits) {
                                                case 2: msg = "byte";
@@ -223,6+229,7 @@ static int proc_ide_write_config
                                                printk("proc_ide_write_config: %s\n", pcibios_strerror(rc));
                                                return -EIO;
                                        }
+#endif /* CONFIG_BLK_DEV_IDEPCI */
                                } else {        /* not pci */
                                        switch (digits) {
                                                case 2: outb(val, reg);
@@ -251,7+258,8 @@ static int proc_ide_read_config
        char            *out = page;
        int             len, reg = 0;
 
-       out += sprintf(out, "pci bus %d function %d vendor %04x device %04x channel %d\n",
+#ifdef CONFIG_BLK_DEV_IDEPCI
+       out += sprintf(out, "pci bus %d device %d vid %04x did %04x channel %d\n",
                hwif->pci_bus, hwif->pci_fn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
        do {
                byte val;
@@ -265,20+273,13 @@ static int proc_ide_read_config
                } else
                        out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
        } while (reg < 0x100);
+#else  /* CONFIG_BLK_DEV_IDEPCI */
+       out += sprintf(out, "(none)\n");
+#endif /* CONFIG_BLK_DEV_IDEPCI */
        len = out - page;
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_imodel
-       (char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-       ide_hwif_t      *hwif = (ide_hwif_t *) data;
-       int             len;
-
-       len = sprintf(page,"%04x: %04x\n", hwif->pci_devid.vid, hwif->pci_devid.did);
-       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-#endif /* CONFIG_PCI */
 
 static int ide_getdigit(char c)
 {
@@ -308,7+309,7 @@ static int proc_ide_read_drivers
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_type
+static int proc_ide_read_imodel
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
        ide_hwif_t      *hwif = (ide_hwif_t *) data;
@@ -341,7+342,10 @@ static int proc_ide_read_mate
        ide_hwif_t      *hwif = (ide_hwif_t *) data;
        int             len;
 
-       len = sprintf(page, "%s\n", hwif->mate->name);
+       if (hwif && hwif->mate && hwif->mate->present)
+               len = sprintf(page, "%s\n", hwif->mate->name);
+       else
+               len = sprintf(page, "(none)\n");
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -426,7+430,6 @@ static int proc_ide_write_settings
 
        if (!suser())
                return -EACCES;
-
        /*
         * Skip over leading whitespace
         */
@@ -447,11+450,11 @@ static int proc_ide_write_settings
                        ide_hwgroup_t *mategroup = NULL;
                        if (hwif->mate && hwif->mate->hwgroup)
                                mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
-                       cli();  /* ensure all PCI writes are done together */
+                       cli();  /* ensure all writes are done together */
                        while (mygroup->active || (mategroup && mategroup->active)) {
                                restore_flags(flags);
                                if (0 < (signed long)(jiffies - timeout)) {
-                                       printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
+                                       printk("/proc/ide/%s/settings: channel(s) busy, cannot write\n", drive->name);
                                        return -EBUSY;
                                }
                                cli();
@@ -517,9+520,9 @@ int proc_ide_read_capacity
        int             len;
 
        if (!driver)
-           len = sprintf(page, "(none)\n");
+               len = sprintf(page, "(none)\n");
         else
-           len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+               len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -598,40+601,37 @@ static int proc_ide_read_media
 }
 
 static ide_proc_entry_t generic_drive_entries[] = {
-       { "driver", proc_ide_read_driver, proc_ide_write_driver },
-       { "identify", proc_ide_read_identify, NULL },
-       { "media", proc_ide_read_media, NULL },
-       { "model", proc_ide_read_dmodel, NULL },
-       { "settings", proc_ide_read_settings, proc_ide_write_settings },
-       { NULL, NULL, NULL }
+       { "driver",     S_IFREG|S_IRUGO,        proc_ide_read_driver,   proc_ide_write_driver },
+       { "identify",   S_IFREG|S_IRUSR,        proc_ide_read_identify, NULL },
+       { "media",      S_IFREG|S_IRUGO,        proc_ide_read_media,    NULL },
+       { "model",      S_IFREG|S_IRUGO,        proc_ide_read_dmodel,   NULL },
+       { "settings",   S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings, proc_ide_write_settings },
+       { NULL, 0, NULL, NULL }
 };
 
-void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
 {
        struct proc_dir_entry *ent;
 
-       if (!drive->proc || !p)
+       if (!dir || !p)
                return;
        while (p->name != NULL) {
-               mode_t mode = S_IFREG|S_IRUSR;
-               if (!strcmp(p->name,"settings"))
-                       mode |= S_IWUSR;
-               ent = create_proc_entry(p->name, mode, drive->proc);
+               ent = create_proc_entry(p->name, p->mode, dir);
                if (!ent) return;
                ent->nlink = 1;
-               ent->data = drive;
+               ent->data = data;
                ent->read_proc = p->read_proc;
                ent->write_proc = p->write_proc;
                p++;
        }
 }
 
-void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 {
-       if (!drive->proc || !p)
+       if (!dir || !p)
                return;
        while (p->name != NULL) {
-               remove_proc_entry(p->name, drive->proc);
+               remove_proc_entry(p->name, dir);
                p++;
        }
 }
@@ -654,7+654,7 @@ static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *par
                        continue;
                drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
                if (drive->proc)
-                       ide_add_proc_entries(drive, generic_drive_entries);
+                       ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
 
                ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, root);
                if (!ent) return;
@@ -664,10+664,18 @@ static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *par
        }
 }
 
+static ide_proc_entry_t hwif_entries[] = {
+       { "channel",    S_IFREG|S_IRUGO,        proc_ide_read_channel,  NULL },
+       { "config",     S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,   proc_ide_write_config },
+       { "mate",       S_IFREG|S_IRUGO,        proc_ide_read_mate,     NULL },
+       { "model",      S_IFREG|S_IRUGO,        proc_ide_read_imodel,   NULL },
+       { NULL, 0, NULL, NULL }
+};
+
 static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
 {
        int     h;
-       struct proc_dir_entry *hwif_ent, *ent;
+       struct proc_dir_entry *hwif_ent;
 
        for (h = 0; h < MAX_HWIFS; h++) {
                ide_hwif_t *hwif = &ide_hwifs[h];
@@ -676,43+684,12 @@ static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
                        continue;
                hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
                if (!hwif_ent) return;
-#ifdef CONFIG_PCI
-               if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) {
-                       ent = create_proc_entry("config", S_IFREG|S_IRUSR|S_IWUSR, hwif_ent);
-                       if (!ent) return;
-                       ent->nlink = 1;
-                       ent->data = hwif;
-                       ent->read_proc  = proc_ide_read_config;
-                       ent->write_proc = proc_ide_write_config;;
-
-                       ent = create_proc_entry("model", 0, hwif_ent);
-                       if (!ent) return;
-                       ent->data = hwif;
-                       ent->read_proc  = proc_ide_read_imodel;
-               }
-#endif /* CONFIG_PCI */
-               ent = create_proc_entry("channel", 0, hwif_ent);
-               if (!ent) return;
-               ent->data = hwif;
-               ent->read_proc  = proc_ide_read_channel;
-
-               if (hwif->mate && hwif->mate->present) {
-                       ent = create_proc_entry("mate", 0, hwif_ent);
-                       if (!ent) return;
-                       ent->data = hwif;
-                       ent->read_proc  = proc_ide_read_mate;
-               }
-
-               ent = create_proc_entry("type", 0, hwif_ent);
-               if (!ent) return;
-               ent->data = hwif;
-               ent->read_proc  = proc_ide_read_type;
-
+               ide_add_proc_entries(hwif_ent, hwif_entries, hwif);
                create_proc_ide_drives(hwif, hwif_ent, parent);
        }
 }
 
-void proc_ide_init(void)
+void proc_ide_create(void)
 {
        struct proc_dir_entry *root, *ent;
        root = create_proc_entry("ide", S_IFDIR, 0);
@@ -723,3+700,13 @@ void proc_ide_init(void)
        if (!ent) return;
        ent->read_proc  = proc_ide_read_drivers;
 }
+
+void proc_ide_destroy(void)
+{
+       /*
+        * Mmmm.. does this free up all resources,
+        * or do we need to do a more proper cleanup here ??
+        */
+       remove_proc_entry("ide/drivers", 0);
+       remove_proc_entry("ide", 0);
+}
index f3f4ef8..c4f5c6e 100644 (file)
@@ -3640,6+3640,8 @@ static int idetape_cleanup (ide_drive_t *drive)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
+
 static int proc_idetape_read_name
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -3653,10+3655,16 @@ static int proc_idetape_read_name
 }
 
 static ide_proc_entry_t idetape_proc[] = {
-       { "name", proc_idetape_read_name, NULL },
-       { NULL, NULL, NULL }
+       { "name",       S_IFREG|S_IRUGO,        proc_idetape_read_name, NULL },
+       { NULL, 0, NULL, NULL }
 };
 
+#else
+
+#define        idetape_proc    NULL
+
+#endif
+
 /*
  *     IDE subdriver functions, registered with ide.c
  */
index e105785..2bf40ce 100644 (file)
@@ -1,5+1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 6.12  January  2, 1998
+ *  linux/drivers/block/ide.c  Version 6.13  March 29, 1998
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
  *            and Gadi Oxman <gadio@netvision.net.il>
  *
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
  * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
  * Secondary:  ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
  * Tertiary:   ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
  * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
- *
- * It is easy to extend ide.c to handle more than four interfaces:
- *
- *     Change the MAX_HWIFS constant in ide.h.
- *
- *     Define some new major numbers (in major.h), and insert them into
- *     the ide_hwif_to_major table in ide.c.
- *
- *     Fill in the extra values for the new interfaces into the two tables
- *     inside ide.c:  default_io_base[]  and  default_irqs[].
- *
- *     Create the new request handlers by cloning "do_ide3_request()"
- *     for each new interface, and add them to the switch statement
- *     in the ide_init() function in ide.c.
- *
- *     Recompile, create the new /dev/ entries, and it will probably work.
+ * ...
  *
  *  From hd.c:
  *  |
  *                     mask all hwgroup interrupts on each irq entry
  * Version 6.12                integrate ioctl and proc interfaces
  *                     fix parsing of "idex=" command line parameter
+ * Version 6.13                add support for ide4/ide5 courtesy rjones@orchestream.com
  *
  *  Some additional driver compile-time options are in ide.h
  *
 #include <linux/kmod.h>
 #endif /* CONFIG_KMOD */
 
-static const byte      ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
+static const byte      ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR };
 
 static int     idebus_parameter; /* holds the "idebus=" parameter */
 static int     system_bus_speed; /* holds what we think is VESA/PCI bus speed */
@@ -1183,6+1169,20 @@ void do_ide3_request (void)      /* invoked with __cli() */
 }
 #endif /* MAX_HWIFS > 3 */
 
+#if MAX_HWIFS > 4
+void do_ide4_request (void)    /* invoked with cli() */
+{
+       do_hwgroup_request (ide_hwifs[4].hwgroup);
+}
+#endif /* MAX_HWIFS > 4 */
+
+#if MAX_HWIFS > 5
+void do_ide5_request (void)    /* invoked with cli() */
+{
+       do_hwgroup_request (ide_hwifs[5].hwgroup);
+}
+#endif /* MAX_HWIFS > 5 */
+
 void ide_timer_expiry (unsigned long data)
 {
        ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
@@ -2575,7+2575,7 @@ __initfunc(void ide_init_builtin_drivers (void))
 #endif /* CONFIG_BLK_DEV_IDE */
 
 #ifdef CONFIG_PROC_FS
-       proc_ide_init();
+       proc_ide_create();
 #endif
 
        /*
@@ -2691,10+2691,12 @@ search:
        return NULL;
 }
 
+#ifdef CONFIG_PROC_FS
 static ide_proc_entry_t generic_subdriver_entries[] = {
-       { "capacity", proc_ide_read_capacity, NULL },
-       { NULL, NULL, NULL }
+       { "capacity",   S_IFREG|S_IRUGO,        proc_ide_read_capacity, NULL },
+       { NULL, 0, NULL, NULL }
 };
+#endif
 
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
 {
@@ -2717,8+2719,10 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
                drive->nice1 = 1;
        }
        drive->revalidate = 1;
-       ide_add_proc_entries(drive, generic_subdriver_entries);
-       ide_add_proc_entries(drive, driver->proc);
+#ifdef CONFIG_PROC_FS
+       ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+       ide_add_proc_entries(drive->proc, driver->proc, drive);
+#endif
        return 0;
 }
 
@@ -2732,8+2736,10 @@ int ide_unregister_subdriver (ide_drive_t *drive)
                __restore_flags(flags);
                return 1;
        }
-       ide_remove_proc_entries(drive, DRIVER(drive)->proc);
-       ide_remove_proc_entries(drive, generic_subdriver_entries);
+#ifdef CONFIG_PROC_FS
+       ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
+       ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
+#endif
        auto_remove_settings(drive);
        drive->driver = NULL;
        __restore_flags(flags);
@@ -2803,6+2809,12 @@ EXPORT_SYMBOL(do_ide2_request);
 #if MAX_HWIFS > 3
 EXPORT_SYMBOL(do_ide3_request);
 #endif /* MAX_HWIFS > 3 */
+#if MAX_HWIFS > 4
+EXPORT_SYMBOL(do_ide4_request);
+#endif /* MAX_HWIFS > 4 */
+#if MAX_HWIFS > 5
+EXPORT_SYMBOL(do_ide5_request);
+#endif /* MAX_HWIFS > 5 */
 
 /*
  * Driver module
@@ -2828,11+2840,13 @@ EXPORT_SYMBOL(ide_revalidate_disk);
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_wait_cmd);
 EXPORT_SYMBOL(ide_stall_queue);
+#ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(ide_add_proc_entries);
 EXPORT_SYMBOL(ide_remove_proc_entries);
+EXPORT_SYMBOL(proc_ide_read_geometry);
+#endif
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
-EXPORT_SYMBOL(proc_ide_read_geometry);
 
 EXPORT_SYMBOL(ide_register);
 EXPORT_SYMBOL(ide_unregister);
@@ -2881,5+2895,8 @@ void cleanup_module (void)
 
        for (index = 0; index < MAX_HWIFS; ++index)
                ide_unregister(index);
+#ifdef CONFIG_PROC_FS
+       proc_ide_destroy();
+#endif
 }
 #endif /* MODULE */
index 2daae4f..96fdf94 100644 (file)
@@ -405,14+405,17 @@ void ide_add_generic_settings(ide_drive_t *drive);
  * /proc/ide interface
  */
 typedef struct {
-       const char *name;
-       read_proc_t *read_proc;
-       write_proc_t *write_proc;
+       const char      *name;
+       mode_t          mode;
+       read_proc_t     *read_proc;
+       write_proc_t    *write_proc;
 } ide_proc_entry_t;
 
-void proc_ide_init(void);
-void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
-void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+#ifdef CONFIG_PROC_FS
+void proc_ide_create(void);
+void proc_ide_destroy(void);
+void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
+void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
 read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
@@ -431,6+434,7 @@ read_proc_t proc_ide_read_geometry;
        *start = page + off;            \
        return len;                     \
 }
+#endif
 
 /*
  * Subdrivers support.
@@ -673,6+677,12 @@ void do_ide2_request (void);
 #if MAX_HWIFS > 3
 void do_ide3_request (void);
 #endif
+#if MAX_HWIFS > 4
+void do_ide4_request (void);
+#endif
+#if MAX_HWIFS > 5
+void do_ide5_request (void);
+#endif
 void ide_init_subdrivers (void);
 
 #ifndef _IDE_C
index cf16e58..b9b90c8 100644 (file)
@@ -428,6+428,8 @@ void make_request(int major,int rw, struct buffer_head * bh)
             case FLOPPY_MAJOR:
             case IDE2_MAJOR:
             case IDE3_MAJOR:
+            case IDE4_MAJOR:
+            case IDE5_MAJOR:
             case ACSI_MAJOR:
                /*
                 * The scsi disk and cdrom drivers completely remove the request
@@ -716,9+718,6 @@ __initfunc(int blk_dev_init(void))
 #ifdef CONFIG_BLK_DEV_LOOP
        loop_init();
 #endif
-#ifdef CONFIG_CDROM            /* this must precede all CD-ROM drivers */
-       cdrom_init();
-#endif CONFIG_CDROM
 #ifdef CONFIG_ISP16_CDI
        isp16_init();
 #endif CONFIG_ISP16_CDI
index 4d0ccf4..674c378 100644 (file)
@@ -851,11+851,13 @@ EXPORT_SYMBOL(md_map);
 EXPORT_SYMBOL(md_wakeup_thread);
 EXPORT_SYMBOL(md_do_sync);
 
+#ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_md = {
        PROC_MD, 6, "mdstat",
        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_array_inode_operations,
 };
+#endif
 
 static void md_geninit (struct gendisk *gdisk)
 {
@@ -873,7+875,9 @@ static void md_geninit (struct gendisk *gdisk)
   blksize_size[MD_MAJOR] = md_blocksizes;
   max_readahead[MD_MAJOR] = md_maxreadahead;
 
+#ifdef CONFIG_PROC_FS
   proc_register(&proc_root, &proc_md);
+#endif
 }
 
 int md_error (kdev_t mddev, kdev_t rdev)
dissimilarity index 95%
index 5681e2f..00cb2cd 100644 (file)
-#
-# Makefile for the kernel cdrom device drivers.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now inherited from the
-# parent makefile.
-#
-
-#
-# Note : at this point, these files are compiled on all systems. 
-# In the future, some of these should be built conditionally.
-#
-
-
-L_TARGET := cdrom.a
-L_OBJS   :=
-M_OBJS   :=
-MOD_LIST_NAME := CDROM_MODULES
-
-ifeq ($(CONFIG_AZTCD),y)
-L_OBJS += aztcd.o
-else
-  ifeq ($(CONFIG_AZTCD),m)
-  M_OBJS += aztcd.o
-  endif
-endif #CONFIG_AZTCD
-
-ifeq ($(CONFIG_CDU31A),y)
-L_OBJS += cdu31a.o
-else
-  ifeq ($(CONFIG_CDU31A),m)
-  M_OBJS += cdu31a.o
-  endif
-endif #CONFIG_CDU31A
-
-ifeq ($(CONFIG_MCD),y)
-L_OBJS += mcd.o
-else
-  ifeq ($(CONFIG_MCD),m)
-  M_OBJS += mcd.o
-  endif
-endif #CONFIG_MCD
-
-ifeq ($(CONFIG_MCDX),y)
-L_OBJS += mcdx.o
-else
-  ifeq ($(CONFIG_MCDX),m)
-  M_OBJS += mcdx.o
-  endif
-endif #CONFIG_MCDX
-
-ifeq ($(CONFIG_SBPCD),y)
-L_OBJS += sbpcd.o
-else
-  ifeq ($(CONFIG_SBPCD),m)
-  M_OBJS += sbpcd.o
-  endif
-endif #CONFIG_SBPCD
-
-ifeq ($(CONFIG_SBPCD2),y)
-L_OBJS += sbpcd2.o
-endif #CONFIG_SBPCD2
-
-ifeq ($(CONFIG_SBPCD3),y)
-L_OBJS += sbpcd3.o
-endif #CONFIG_SBPCD3
-
-ifeq ($(CONFIG_SBPCD4),y)
-L_OBJS += sbpcd4.o
-endif #CONFIG_SBPCD4
-
-ifeq ($(CONFIG_CDU535),y)
-L_OBJS += sonycd535.o
-else
-  ifeq ($(CONFIG_CDU535),m)
-  M_OBJS += sonycd535.o
-  endif
-endif #CONFIG_CDU535
-
-ifeq ($(CONFIG_GSCD),y)
-L_OBJS += gscd.o
-else
-  ifeq ($(CONFIG_GSCD),m)
-  M_OBJS += gscd.o
-  endif
-endif #CONFIG_GSCD
-
-ifeq ($(CONFIG_CM206),y)
-L_OBJS += cm206.o
-else
-  ifeq ($(CONFIG_CM206),m)
-  M_OBJS += cm206.o
-  endif
-endif #CONFIG_CM206
-
-ifeq ($(CONFIG_OPTCD),y)
-L_OBJS += optcd.o
-else
-  ifeq ($(CONFIG_OPTCD),m)
-  M_OBJS += optcd.o
-  endif
-endif #CONFIG_OPTCD
-
-ifeq ($(CONFIG_SJCD),y)
-L_OBJS += sjcd.o
-else
-  ifeq ($(CONFIG_SJCD),m)
-  M_OBJS += sjcd.o
-  endif
-endif #CONFIG_SJCD
-
-ifeq ($(CONFIG_ISP16_CDI),y)
-L_OBJS += isp16.o
-else
-  ifeq ($(CONFIG_ISP16_CDI),m)
-  M_OBJS += isp16.o
-  endif
-endif #CONFIG_ISP16_CDI
-
-ifeq ($(CONFIG_CDROM),y)
-LX_OBJS += cdrom.o
-else
-  ifeq ($(CONFIG_CDROM),m)
-  MX_OBJS += cdrom.o
-  endif
-endif #CONFIG_CDROM for the Uniform CD-ROM driver
-
-include $(TOPDIR)/Rules.make
+# Makefile for the kernel cdrom device drivers.
+#
+# 30 Jan 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
+# Rewritten to use lists instead of if-statements.
+
+
+
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs    := cdrom.o
+
+
+
+# Object file lists.
+
+obj-y          :=
+obj-m          :=
+obj-n          :=
+obj-           :=
+
+
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_BLK_DEV_IDECD)    +=              cdrom.o
+obj-$(CONFIG_BLK_DEV_SR)       +=              cdrom.o
+
+obj-$(CONFIG_AZTCD)            += aztcd.o
+obj-$(CONFIG_CDU31A)           += cdu31a.o     cdrom.o
+obj-$(CONFIG_CM206)            += cm206.o      cdrom.o
+obj-$(CONFIG_GSCD)             += gscd.o
+obj-$(CONFIG_ISP16_CDI)                += isp16.o
+obj-$(CONFIG_MCD)              += mcd.o        cdrom.o
+obj-$(CONFIG_MCDX)             += mcdx.o       cdrom.o
+obj-$(CONFIG_OPTCD)            += optcd.o
+obj-$(CONFIG_SBPCD)            += sbpcd.o      cdrom.o
+obj-$(CONFIG_SBPCD2)           += sbpcd2.o     cdrom.o
+obj-$(CONFIG_SBPCD3)           += sbpcd3.o     cdrom.o
+obj-$(CONFIG_SBPCD4)           += sbpcd4.o     cdrom.o
+obj-$(CONFIG_SJCD)             += sjcd.o
+obj-$(CONFIG_CDU535)           += sonycd535.o
+
+
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m          := $(filter-out $(obj-y), $(obj-m))
+
+
+
+# Translate to Rules.make lists.
+
+L_TARGET       := cdrom.a
+MOD_LIST_NAME  := CDROM_MODULES
+
+L_OBJS         := $(sort $(filter-out $(export-objs), $(obj-y)))
+LX_OBJS                := $(sort $(filter     $(export-objs), $(obj-y)))
+M_OBJS         := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS                := $(sort $(filter     $(export-objs), $(obj-m)))
+
+
+
+# Hand off to Rules.make.
+
+include $(TOPDIR)/Rules.make
index 48a3ae4..30c8e96 100644 (file)
 #define REVISION "Revision: 2.12"
 #define VERSION "Id: cdrom.c 2.12 1998/01/24 22:15:45 erik Exp"
 
+/* I use an error-log mask to give fine grain control over the type of
+   messages dumped to the system logs.  The available masks include: */
+#define CD_NOTHING      0x0
+#define CD_WARNING     0x1
+#define CD_REG_UNREG   0x2
+#define CD_DO_IOCTL    0x4
+#define CD_OPEN                0x8
+#define CD_CLOSE       0x10
+#define CD_COUNT_TRACKS 0x20
+
+/* Define this to remove _all_ the debugging messages */
+/* #define ERRLOGMASK CD_NOTHING */
+#define ERRLOGMASK (CD_WARNING)
+/* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */
+/* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */
+
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
 
-/* I use an error-log mask to give fine grain control over the type of
-   error messages dumped to the system logs.  The available masks include: */
-#define CD_WARNING     0x1
-#define CD_REG_UNREG   0x2
-#define CD_DO_IOCTL    0x4
-#define CD_OPEN                0x8
-#define CD_CLOSE       0x10
-#define CD_COUNT_TRACKS 0x20
-
-/* When VERBOSE_STATUS_INFO is not defined, the debugging printks don't 
-   get compiled in at all */
-#define VERBOSE_STATUS_INFO
-
-#define ERRLOGMASK (CD_WARNING) 
-/* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */
-/* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE) */
-
-#ifdef VERBOSE_STATUS_INFO
+#if (ERRLOGMASK!=CD_NOTHING)
 #define cdinfo(type, fmt, args...) \
        if (ERRLOGMASK & type) printk(KERN_INFO "cdrom: " fmt, ## args)
 #else
@@ -168,11+167,6 @@ struct file_operations cdrom_fops =
        NULL                            /* revalidate */
 };
 
-void cdrom_init(void) {
-       if (!topCdromPtr)
-           printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n");
-}
-
 /* This macro makes sure we don't have to check on cdrom_device_ops
  * existence in the run-time routines below. Change_capability is a
  * hack to have the capability flags defined const, while we can still
@@ -205,6+199,15 @@ int register_cdrom(struct cdrom_device_info *cdi)
                                        /* default compatibility mode */
        cdi->mc_flags = 0;
        cdo->n_minors = 0;
+
+       {
+           static char banner_printed = 0;
+           if ( !banner_printed ) {
+               printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n");
+               banner_printed = 1;
+           }
+       }
+
        cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
        cdi->next = topCdromPtr;        
        topCdromPtr = cdi;
@@ -293,13+296,14 @@ int open_for_data(struct cdrom_device_info * cdi)
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
                cdinfo(CD_OPEN, "drive_status=%d\n", ret); 
                if (ret == CDS_TRAY_OPEN) {
-                       cdinfo(CD_WARNING, "tray is open...\n"); 
+                       cdinfo(CD_OPEN, "the tray is open...\n"); 
                        /* can/may i close it? */
                        if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
                            cdi->options & CDO_AUTO_CLOSE) {
+                               cdinfo(CD_OPEN, "trying to close the tray.\n"); 
                                ret=cdo->tray_move(cdi,0);
                                if (ret) {
-                                       cdinfo(CD_WARNING, "bummer. tried to close tray but failed.\n"); 
+                                       cdinfo(CD_OPEN, "bummer. tried to close the tray but failed.\n"); 
                                        /* Ignore the error from the low
                                        level driver.  We don't care why it
                                        couldn't close the tray.  We only care 
@@ -309,36+313,37 @@ int open_for_data(struct cdrom_device_info * cdi)
                                        goto clean_up_and_return;
                                }
                        } else {
-                               cdinfo(CD_WARNING, "this driver can't close the tray.\n"); 
+                               cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n"); 
                                ret=-ENOMEDIUM;
                                goto clean_up_and_return;
                        }
                        /* Ok, the door should be closed now.. Check again */
                        ret = cdo->drive_status(cdi, CDSL_CURRENT);
-                       cdinfo(CD_OPEN, "tried again. drive_status=%d\n", ret); 
                        if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
+                               cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 
                                ret=-ENOMEDIUM;
                                goto clean_up_and_return;
                        }
+                       cdinfo(CD_OPEN, "the tray is now closed.\n"); 
                }
                if (ret!=CDS_DISC_OK)
                        goto clean_up_and_return;
        }
        cdrom_count_tracks(cdi, &tracks);
        if (tracks.error == CDS_NO_DISC) {
-               cdinfo(CD_OPEN, "bummer. no disc...\n");
+               cdinfo(CD_OPEN, "bummer. no disc.\n");
                ret=-ENOMEDIUM;
                goto clean_up_and_return;
        }
        /* CD-Players which don't use O_NONBLOCK, workman
         * for example, need bit CDO_CHECK_TYPE cleared! */
        if (cdi->options & CDO_CHECK_TYPE && tracks.data==0) {
-               cdinfo(CD_OPEN, "bummer. wrong media type...\n"); 
+               cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
                ret=-EMEDIUMTYPE;
                goto clean_up_and_return;
        }
 
-       cdinfo(CD_OPEN, "all seems well, opening the device...\n"); 
+       cdinfo(CD_OPEN, "all seems well, opening the device.\n"); 
 
        /* all seems well, we can open the device */
        ret = cdo->open(cdi, 0); /* open for data */
@@ -347,7+352,7 @@ int open_for_data(struct cdrom_device_info * cdi)
           opening the device, but we don't want the device locked if 
           this somehow fails... */
        if (ret) {
-               cdinfo(CD_OPEN, "open device failed...\n"); 
+               cdinfo(CD_OPEN, "open device failed.\n"); 
                goto clean_up_and_return;
        }
        if (cdo->capability & ~cdi->mask & CDC_LOCK && 
@@ -364,11+369,11 @@ int open_for_data(struct cdrom_device_info * cdi)
        This ensures that the drive gets unlocked after a mount fails.  This 
        is a goto to avoid adding bloating the driver with redundant code. */ 
 clean_up_and_return:
-       cdinfo(CD_WARNING, "failed to open the device.\n"); 
+       cdinfo(CD_WARNING, "open failed.\n"); 
        if (cdo->capability & ~cdi->mask & CDC_LOCK && 
                cdi->options & CDO_LOCK) {
                        cdo->lock_door(cdi, 0);
-                       cdinfo(CD_WARNING, "door unlocked.\n");
+                       cdinfo(CD_OPEN, "door unlocked.\n");
        }
        return ret;
 }
@@ -389,13+394,14 @@ int check_for_audio_disc(struct cdrom_device_info * cdi,
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
                cdinfo(CD_OPEN, "drive_status=%d\n", ret); 
                if (ret == CDS_TRAY_OPEN) {
-                       cdinfo(CD_WARNING, "tray is open...\n"); 
+                       cdinfo(CD_OPEN, "the tray is open...\n"); 
                        /* can/may i close it? */
                        if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
                            cdi->options & CDO_AUTO_CLOSE) {
+                               cdinfo(CD_OPEN, "trying to close the tray.\n"); 
                                ret=cdo->tray_move(cdi,0);
                                if (ret) {
-                                       cdinfo(CD_WARNING, "bummer. tried to close tray but failed.\n"); 
+                                       cdinfo(CD_OPEN, "bummer. tried to close tray but failed.\n"); 
                                        /* Ignore the error from the low
                                        level driver.  We don't care why it
                                        couldn't close the tray.  We only care 
@@ -404,16+410,20 @@ int check_for_audio_disc(struct cdrom_device_info * cdi,
                                        return -ENOMEDIUM;
                                }
                        } else {
-                               cdinfo(CD_WARNING, "this driver can't close the tray.\n"); 
+                               cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n"); 
                                return -ENOMEDIUM;
                        }
                        /* Ok, the door should be closed now.. Check again */
                        ret = cdo->drive_status(cdi, CDSL_CURRENT);
-                       cdinfo(CD_OPEN, "tried again. drive_status=%d\n", ret); 
-                       if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN))
+                       if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
+                               cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 
                                return -ENOMEDIUM;
-                       if (ret!=CDS_DISC_OK)
+                       }       
+                       if (ret!=CDS_DISC_OK) {
+                               cdinfo(CD_OPEN, "bummer. disc isn't ready.\n"); 
                                return -EIO;
+                       }       
+                       cdinfo(CD_OPEN, "the tray is now closed.\n"); 
                }       
        }
        cdrom_count_tracks(cdi, &tracks);
@@ -1031,7+1041,6 @@ static void cdrom_sysctl_unregister(void)
 
 int init_module(void)
 {
-       cdrom_init();
 #ifdef CONFIG_SYSCTL
        cdrom_sysctl_register();
 #endif /* CONFIG_SYSCTL */ 
index 94f13f8..29aeaa4 100644 (file)
@@ -231,10+231,10 @@ extern unsigned long get_cmos_time(void);
                "pushl %%fs\n\t" \
                "pushl %%gs\n\t" \
                "xorl %%edx, %%edx\n\t" \
-               "mov %%dx, %%ds\n\t" \
-               "mov %%dx, %%es\n\t" \
-               "mov %%dx, %%fs\n\t" \
-               "mov %%dx, %%gs\n\t"
+               "movl %%dx, %%ds\n\t" \
+               "movl %%dx, %%es\n\t" \
+               "movl %%dx, %%fs\n\t" \
+               "movl %%dx, %%gs\n\t"
 #      define APM_DO_RESTORE_SEGS      \
                "popl %%gs\n\t" \
                "popl %%fs\n\t" \
index 927cc12..73634b1 100644 (file)
@@ -204,6+204,121 @@ int last_console = 0;
 int want_console = -1;
 int kmsg_redirect = 0;
 
+#define CONFIG_SERIAL_ECHO
+#ifdef CONFIG_SERIAL_ECHO
+
+#include <linux/serial_reg.h>
+
+extern int serial_echo_init (int base);
+extern int serial_echo_print (const char *s);
+
+/*
+ * this defines the address for the port to which printk echoing is done
+ *  when CONFIG_SERIAL_ECHO is defined
+ */
+#define SERIAL_ECHO_PORT       0x3f8   /* COM1 */
+
+static int serial_echo_port = 0;
+
+#define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port)
+#define serial_echo_inb(a)    inb((a)+serial_echo_port)
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/* Wait for transmitter & holding register to empty */
+#define WAIT_FOR_XMITR \
+ do { \
+       lsr = serial_echo_inb(UART_LSR); \
+ } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+
+/* These two functions abstract the actual communications with the
+ * debug port. This is so we can change the underlying communications
+ * mechanism without modifying the rest of the code.
+ */
+int
+serial_echo_print(const char *s)
+{
+       int     lsr, ier;
+       int     i;
+
+       if (!serial_echo_port) return (0);
+
+       /*
+        * First save the IER then disable the interrupts
+        */
+       ier = serial_echo_inb(UART_IER);
+       serial_echo_outb(0x00, UART_IER);
+
+       /*
+        * Now, do each character
+        */
+       for (i = 0; *s; i++, s++) {
+               WAIT_FOR_XMITR;
+
+               /* Send the character out. */
+               serial_echo_outb(*s, UART_TX);
+
+               /* if a LF, also do CR... */
+               if (*s == 10) {
+                       WAIT_FOR_XMITR;
+                       serial_echo_outb(13, UART_TX);
+               }
+       }
+
+       /*
+        * Finally, Wait for transmitter & holding register to empty
+        *  and restore the IER
+        */
+       do {
+               lsr = serial_echo_inb(UART_LSR);
+       } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+       serial_echo_outb(ier, UART_IER);
+
+       return (0);
+}
+
+
+int
+serial_echo_init(int base)
+{
+       int comstat, hi, lo;
+       
+       if (base != 0x2f8 && base != 0x3f8) {
+               serial_echo_port = 0;
+               return (0);
+       } else
+         serial_echo_port = base;
+
+       /*
+        * read the Divisor Latch
+        */
+       comstat = serial_echo_inb(UART_LCR);
+       serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR);
+       hi = serial_echo_inb(UART_DLM);
+       lo = serial_echo_inb(UART_DLL);
+       serial_echo_outb(comstat, UART_LCR);
+
+       /*
+        * now do hardwired init
+        */
+       serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */
+       serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */
+       serial_echo_outb(0x00, UART_DLM); /* 9600 baud */
+       serial_echo_outb(0x0c, UART_DLL);
+       serial_echo_outb(0x03, UART_LCR); /* Done with divisor */
+
+       /* Prior to disabling interrupts, read the LSR and RBR
+        * registers
+        */
+       comstat = serial_echo_inb(UART_LSR); /* COM? LSR */
+       comstat = serial_echo_inb(UART_RX);     /* COM? RBR */
+       serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */
+
+       return(0);
+}
+
+#endif /* CONFIG_SERIAL_ECHO */
+
 int vc_cons_allocated(unsigned int i)
 {
        return (i < MAX_NR_CONSOLES && vc_cons[i].d);
@@ -579,6+694,37 @@ scrdown(int currcons, unsigned int t, unsigned int b, unsigned int nr)
        has_scrolled = 1;
 }
 
+/*
+ * Routine to reset the visible "screen" to the top of video memory.
+ * This is necessary when exiting from the kernel back to a console
+ * which expects only the top of video memory to be used for the visible
+ * screen (with scrolling down by moving the memory contents).
+ * The normal action of the LINUX console is to scroll using all of the
+ * video memory and diddling the hardware top-of-video register as needed.
+ */
+void
+scrreset(void)
+{
+       int currcons = fg_console;
+       unsigned short * d = (unsigned short *) video_mem_start;
+       unsigned short * s = (unsigned short *) origin;
+       unsigned int count;
+
+       count = (video_num_lines-1)*video_num_columns;
+       memcpyw(d, s, 2*count);
+       memsetw(d + count, video_erase_char,
+               2*video_num_columns);
+       scr_end -= origin-video_mem_start;
+       pos -= origin-video_mem_start;
+       origin = video_mem_start;
+
+       has_scrolled = 1;
+       has_wrapped = 1;
+
+       set_origin(currcons);
+       set_cursor(currcons);
+}
+
 static void lf(int currcons)
 {
        /* don't scroll if above bottom of scrolling region, or
@@ -1866,6+2012,10 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
                return;
        }
 
+#ifdef CONFIG_SERIAL_ECHO
+        serial_echo_print(b);
+#endif /* CONFIG_SERIAL_ECHO */
+
        while (count-- > 0) {
                c = *(b++);
                if (c == 10 || c == 13 || need_wrap) {
@@ -2117,6+2267,10 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
                /* This may be suboptimal but is a safe bet - go with it */
                video_scan_lines = video_font_height * video_num_lines;
 
+#ifdef CONFIG_SERIAL_ECHO
+               serial_echo_init(SERIAL_ECHO_PORT);
+#endif /* CONFIG_SERIAL_ECHO */
+
                printk("Console: %ld point font, %ld scans\n",
                       video_font_height, video_scan_lines);
        }
index 67a3d04..477151c 100644 (file)
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/system.h>
 
 /* Some configuration switches are present in the include file... */
@@ -55,18+56,17 @@ unsigned char pckbd_sysrq_xlate[128] =
 
 __initfunc(static int kbd_wait_for_input(void))
 {
-       int     n;
        int     status, data;
        unsigned long start = jiffies;
 
        do {
                 status = inb(KBD_STATUS_REG);
+
                 /*
                  * Wait for input data to become available.  This bit will
                  * then be cleared by the following read of the DATA
                  * register.
                  */
-
                 if (!(status & KBD_STAT_OBF))
                        continue;
 
@@ -98,6+98,8 @@ __initfunc(static void kbd_write(int address, int data))
 
 __initfunc(static char *initialize_kbd2(void))
 {
+       int status;
+
        /* Flush any pending input. */
 
        while (kbd_wait_for_input() != -1)
@@ -132,22+134,37 @@ __initfunc(static char *initialize_kbd2(void))
         * then the assumption is that no keyboard is
         * plugged into the machine.
         * This defaults the keyboard to scan-code set 2.
+        *
+        * Set up to try again if the keyboard asks for RESEND.
         */
 
+        do {
        kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
-       if (kbd_wait_for_input() != KBD_REPLY_ACK)
+                status = kbd_wait_for_input();
+                if (status == KBD_REPLY_ACK)
+                       break;
+                else if (status != KBD_REPLY_RESEND)
                return "Keyboard reset failed, no ACK";
+        } while (1);
+
        if (kbd_wait_for_input() != KBD_REPLY_POR)
                return "Keyboard reset failed, no POR";
 
        /*
         * Set keyboard controller mode. During this, the keyboard should be
         * in the disabled state.
+        *
+        * Set up to try again if the keyboard asks for RESEND.
         */
 
+       do {
        kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
-       if (kbd_wait_for_input() != KBD_REPLY_ACK)
+               status = kbd_wait_for_input();
+               if (status == KBD_REPLY_ACK)
+                       break;
+               else if (status != KBD_REPLY_RESEND)
                return "Disable keyboard: no ACK";
+       } while (1);
 
        kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
        kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT
index 6bd5be8..55424dc 100644 (file)
@@ -1094,14+1094,14 @@ de4x5_hw_init(struct device *dev, u_long iobase))
     
     dev->base_addr = iobase;
     if (lp->bus == EISA) {
-       printk("%s: %s at 0x%04lx (EISA slot %ld)", 
+       printk("%s: %s at 0x%04lx (EISA slot %ld),\n", 
               dev->name, name, iobase, ((iobase>>12)&0x0f));
     } else {                                 /* PCI port address */
-       printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name,
+       printk("%s: %s at 0x%04lx (PCI bus %d, device %d),\n", dev->name, name,
               iobase, lp->bus_num, lp->device);
     }
     
-    printk(", h/w address ");
+    printk("      h/w address ");
     status = get_hw_addr(dev);
     for (i = 0; i < ETH_ALEN - 1; i++) {     /* get the ethernet addr. */
        printk("%2.2x:", dev->dev_addr[i]);
@@ -2092,9+2092,7 @@ pci_probe(struct device *dev, u_long ioaddr))
         index++) {
        dev_num = PCI_SLOT(dev_fn);
        if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue;
-       for (pdev = pci_devices; pdev; pdev = pdev->next) {
-           if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
-       }
+       pdev = pci_find_dev(pb, dev_fn);
 
        vendor = pdev->vendor;
        device = pdev->device << 8;
@@ -2193,9+2191,7 @@ srom_search(int index))
 
        if (lp->bus_num != pb) return;
        dev_num = PCI_SLOT(dev_fn);
-       for (pdev = pci_devices; pdev; pdev = pdev->next) {
-           if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break;
-       }
+       pdev = pci_find_dev(pb, dev_fn);
 
        vendor = pdev->vendor;
        device = pdev->device << 8;
@@ -5737,10+5733,7 @@ count_adapters(void)
     for (i=0; 
         (pcibios_find_class(class, i, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
         i++) {
-       for (pdev = pci_devices; pdev; pdev = pdev->next) {
-           if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break;
-       }
-
+       pdev = pci_find_dev(pb, dev_fn);
        vendor = pdev->vendor;
        device = pdev->device << 8;
        if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
index 816ff89..c9fb9b2 100644 (file)
@@ -213,6+213,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( CYRIX,          CYRIX_5530_VIDEO,"5530 Kahlua Video"),
        DEVICE( LEADTEK,        LEADTEK_805,    "S3 805"),
        DEVICE( CONTAQ,         CONTAQ_82C599,  "82C599"),
+       DEVICE( CONTAQ,         CONTAQ_82C693,  "82C693"),
        DEVICE( OLICOM,         OLICOM_OC3136,  "OC-3136/3137"),
        DEVICE( OLICOM,         OLICOM_OC2315,  "OC-2315"),
        DEVICE( OLICOM,         OLICOM_OC2325,  "OC-2325"),
index 74596e8..199bb91 100644 (file)
@@ -273,3+273,13 @@ __initfunc(unsigned long pci_init (unsigned long mem_start, unsigned long mem_en
 
        return mem_start;
 }
+
+struct pci_dev *pci_find_dev(unsigned char bus, unsigned char devfn)
+{
+       struct pci_dev *pdev;
+       for (pdev = pci_devices; pdev; pdev = pdev->next) {
+               if ((pdev->bus->number==bus) && (pdev->devfn==devfn)) break;
+
+       }
+       return pdev;
+}
index b81756c..a658b11 100644 (file)
 */
 
 
-#define BusLogic_DriverVersion         "2.0.11"
-#define BusLogic_DriverDate            "31 January 1998"
+#define BusLogic_DriverVersion         "2.0.12"
+#define BusLogic_DriverDate            "29 March 1998"
 
 
 #include <linux/version.h>
@@ -1020,6+1020,38 @@ static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
           : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
        BusLogic_AppendProbeAddressISA(0x134);
     }
+  /*
+    Iterate over the older non-compliant MultiMaster PCI Host Adapters,
+    noting the PCI bus location and assigned IRQ Channel.
+  */
+  Index = 0;
+  while (pcibios_find_device(PCI_VENDOR_ID_BUSLOGIC,
+                            PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
+                            Index++, &Bus, &DeviceFunction) == 0)
+    if (pcibios_read_config_dword(Bus, DeviceFunction,
+                                 PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
+       pcibios_read_config_byte(Bus, DeviceFunction,
+                                PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
+      {
+       unsigned char Device = DeviceFunction >> 3;
+       IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+       if (IO_Address == 0 || IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
+         continue;
+       for (i = 0; i < BusLogic_ProbeInfoCount; i++)
+         {
+           BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[i];
+           if (ProbeInfo->IO_Address == IO_Address &&
+               ProbeInfo->HostAdapterType == BusLogic_MultiMaster)
+             {
+               ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+               ProbeInfo->PCI_Address = 0;
+               ProbeInfo->Bus = Bus;
+               ProbeInfo->Device = Device;
+               ProbeInfo->IRQ_Channel = IRQ_Channel;
+               break;
+             }
+         }
+      }
   return PCIMultiMasterCount;
 }
 
@@ -1976,6+2008,12 @@ Common:
   if (HostAdapter->BounceBuffersRequired)
     HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB;
   else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
+  if (HostAdapter->DriverOptions != NULL)
+    HostAdapter->CommonQueueDepth =
+      HostAdapter->DriverOptions->CommonQueueDepth;
+  if (HostAdapter->CommonQueueDepth > 0 &&
+      HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth)
+    HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth;
   /*
     Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
     Therefore, mask the Tagged Queuing Permitted Default bits with the
@@ -2682,17+2720,26 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
     if (HostAdapter->TargetFlags[TargetID].TargetExists)
       {
-       int QueueDepth = HostAdapter->UntaggedQueueDepth;
+       int QueueDepth = HostAdapter->QueueDepth[TargetID];
        if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported &&
            (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
          {
-           QueueDepth = HostAdapter->QueueDepth[TargetID];
            TaggedDeviceCount++;
            if (QueueDepth == 0) AutomaticTaggedDeviceCount++;
          }
-       else UntaggedDeviceCount++;
-       HostAdapter->QueueDepth[TargetID] = QueueDepth;
+       else
+         {
+           UntaggedDeviceCount++;
+           if (QueueDepth == 0 ||
+               QueueDepth > HostAdapter->UntaggedQueueDepth)
+             {
+               QueueDepth = HostAdapter->UntaggedQueueDepth;
+               HostAdapter->QueueDepth[TargetID] = QueueDepth;
+             }
+         }
        AllocatedQueueDepth += QueueDepth;
+       if (QueueDepth == 1)
+         HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
       }
   HostAdapter->TargetDeviceCount = TaggedDeviceCount + UntaggedDeviceCount;
   if (AutomaticTaggedDeviceCount > 0)
@@ -4567,14+4614,18 @@ static boolean BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
   QueueDepth:<integer>
 
     The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
-    Target Devices that support Tagged Queuing.  If no Queue Depth option is
-    provided, the Queue Depth will be determined automatically based on the
-    Host Adapter's Total Queue Depth and the number, type, speed, and
+    Target Devices that support Tagged Queuing, as well as the maximum Queue
+    Depth for devices that do not support Tagged Queuing.  If no Queue Depth
+    option is provided, the Queue Depth will be determined automatically based
+    on the Host Adapter's Total Queue Depth and the number, type, speed, and
     capabilities of the detected Target Devices.  For Host Adapters that
     require ISA Bounce Buffers, the Queue Depth is automatically set by default
-    to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
-    Bounce Buffer memory.  Target Devices that do not support Tagged Queuing
-    always use a Queue Depth of BusLogic_UntaggedQueueDepth.
+    to BusLogic_TaggedQueueDepthBB or BusLogic_UntaggedQueueDepthBB to avoid
+    excessive preallocation of DMA Bounce Buffer memory.  Target Devices that
+    do not support Tagged Queuing always have their Queue Depth set to
+    BusLogic_UntaggedQueueDepth or BusLogic_UntaggedQueueDepthBB, unless a
+    lower Queue Depth option is provided.  A Queue Depth of 1 automatically
+    disables Tagged Queuing.
 
   QueueDepth:[<integer>,<integer>...]
 
@@ -4826,6+4877,7 @@ static void BusLogic_ParseDriverOptions(char *OptionsString)
                                 NULL, QueueDepth);
                  return;
                }
+             DriverOptions->CommonQueueDepth = QueueDepth;
              for (TargetID = 0;
                   TargetID < BusLogic_MaxTargetDevices;
                   TargetID++)
index ef7a8dc..0e07abe 100644 (file)
@@ -1252,6+1252,7 @@ typedef struct BusLogic_DriverOptions
   unsigned short TaggedQueuingPermittedMask;
   unsigned short BusSettleTime;
   BusLogic_LocalOptions_T LocalOptions;
+  unsigned char CommonQueueDepth;
   unsigned char QueueDepth[BusLogic_MaxTargetDevices];
   BusLogic_ErrorRecoveryStrategy_T
     ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
@@ -1412,6+1413,7 @@ typedef struct BusLogic_HostAdapter
   unsigned short DriverQueueDepth;
   unsigned short HostAdapterQueueDepth;
   unsigned short UntaggedQueueDepth;
+  unsigned short CommonQueueDepth;
   unsigned short BusSettleTime;
   unsigned short SynchronousPermitted;
   unsigned short FastPermitted;
index ba17531..557fbe9 100644 (file)
@@ -491,11+491,11 @@ static __inline__ void run_main(void) {
  */
 #ifndef USLEEP_SLEEP
 /* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP 2
+#define USLEEP_SLEEP (20*HZ/1000)
 #endif
 /* 300 RPM (floppy speed) */
 #ifndef USLEEP_POLL
-#define USLEEP_POLL 20
+#define USLEEP_POLL (200*HZ/1000)
 #endif
 
 static struct Scsi_Host * expires_first = NULL;
@@ -644,7+644,7 @@ __initfunc(static int NCR5380_probe_irq (struct Scsi_Host *instance, int possibl
            == 0)) 
            trying_irqs |= mask;
 
-    timeout = jiffies + 25;
+    timeout = jiffies + (250*HZ/1000);
     probe_irq = IRQ_NONE;
 
 /*
@@ -820,7+820,7 @@ int NCR5380_proc_info (
 SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
 #endif
 
-   SPRINTF("\nBase Addr: 0x%05X    ", (int)instance->base);
+   SPRINTF("\nBase Addr: 0x%05lX    ", (long)instance->base);
    SPRINTF("io_port: %04x      ", (int)instance->io_port);
    if (instance->irq == IRQ_NONE)
       SPRINTF("IRQ: None.\n");
@@ -1003,7+1003,7 @@ __initfunc(static void NCR5380_init (struct Scsi_Host *instance, int flags)) {
        case 5:
            printk("scsi%d: SCSI bus busy, waiting up to five seconds\n",
                instance->host_no);
-           timeout = jiffies + 500;
+           timeout = jiffies + 5*HZ;
            while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY));
            break;
        case 2:
@@ -1619,7+1619,7 @@ static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
      * selection.
      */
 
-    timeout = jiffies + 25
+    timeout = jiffies + (250*HZ/1000)
 
     /* 
      * XXX very interesting - we're seeing a bounce where the BSY we 
index 50708cf..08e2897 100644 (file)
@@ -314,29+314,33 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
 static int NCR5380_transfer_pio (struct Scsi_Host *instance,
        unsigned char *phase, int *count, unsigned char **data);
 
-#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
-static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
+#if (defined(REAL_DMA) || defined(REAL_DMA_POLL))
+
+#if defined(i386) || defined(__alpha__)
+
+static __inline__ int NCR5380_pc_dma_setup (struct Scsi_Host *instance,
        unsigned char *ptr, unsigned int count, unsigned char mode) {
     unsigned limit;
+    unsigned long bus_addr = virt_to_bus(ptr);
 
     if (instance->dma_channel <=3) {
        if (count > 65536)
            count = 65536;
-       limit = 65536 - (((unsigned) ptr) & 0xFFFF);
+       limit = 65536 - (bus_addr & 0xFFFF);
     } else {
        if (count > 65536 * 2) 
            count = 65536 * 2;
-       limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF);
+       limit = 65536* 2 - (bus_addr & 0x1FFFF);
     }
 
     if (count > limit) count = limit;
 
-    if ((count & 1) || (((unsigned) ptr) & 1))
+    if ((count & 1) || (bus_addr & 1))
        panic ("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
     cli();
     disable_dma(instance->dma_channel);
     clear_dma_ff(instance->dma_channel);
-    set_dma_addr(instance->dma_channel, (unsigned int) ptr);
+    set_dma_addr(instance->dma_channel, bus_addr);
     set_dma_count(instance->dma_channel, count);
     set_dma_mode(instance->dma_channel, mode);
     enable_dma(instance->dma_channel);
@@ -344,17+348,17 @@ static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
     return count;
 }
 
-static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_write_setup (struct Scsi_Host *instance,
     unsigned char *src, unsigned int count) {
-    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE);
+    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_WRITE);
 }
 
-static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance,
+static __inline__ int NCR5380_pc_dma_read_setup (struct Scsi_Host *instance,
     unsigned char *src, unsigned int count) {
-    return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ);
+    return NCR5380_pc_dma_setup (instance, src, count, DMA_MODE_READ);
 }
 
-static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
+static __inline__ int NCR5380_pc_dma_residual (struct Scsi_Host *instance) {
     register int tmp;
     cli();
     clear_dma_ff(instance->dma_channel);
@@ -362,7+366,8 @@ static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) {
     sti();
     return tmp;
 }
-#endif /* defined(REAL_DMA) && defined(i386)  */
+#endif /* defined(i386) || defined(__alpha__) */
+#endif /* defined(REAL_DMA)  */
 #endif __KERNEL_
 #endif /* ndef ASM */
 #endif /* NCR5380_H */
index d2529b1..8e94585 100644 (file)
@@ -226,7+226,8 @@ static void *addresses[] = {
 #endif USE_BIOS
                       
 /* possible i/o port addresses */
-static unsigned short ports[] = { 0x230, 0x330 };
+static unsigned short ports[] =
+  { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 };
 #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
 
 /* possible interrupt channels */
index 60fa401..05ac741 100644 (file)
           BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
 
-                        Version 2.0.11 for Linux 2.0
+                        Version 2.0.12 for Linux 2.0
 
                              PRODUCTION RELEASE
 
-                               31 January 1998
+                                29 March 1998
 
                               Leonard N. Zubkoff
                               Dandelion Digital
@@ -429,14+429,18 @@ following options are available:
 QueueDepth:<integer>
 
   The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
-  Target Devices that support Tagged Queuing.  If no Queue Depth option is
-  provided, the Queue Depth will be determined automatically based on the
-  Host Adapter's Total Queue Depth and the number, type, speed, and
+  Target Devices that support Tagged Queuing, as well as the maximum Queue
+  Depth for devices that do not support Tagged Queuing.  If no Queue Depth
+  option is provided, the Queue Depth will be determined automatically based
+  on the Host Adapter's Total Queue Depth and the number, type, speed, and
   capabilities of the detected Target Devices.  For Host Adapters that
   require ISA Bounce Buffers, the Queue Depth is automatically set by default
-  to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
-  Bounce Buffer memory.  Target Devices that do not support Tagged Queuing
-  always use a Queue Depth of BusLogic_UntaggedQueueDepth.
+  to BusLogic_TaggedQueueDepthBB or BusLogic_UntaggedQueueDepthBB to avoid
+  excessive preallocation of DMA Bounce Buffer memory.  Target Devices that
+  do not support Tagged Queuing always have their Queue Depth set to
+  BusLogic_UntaggedQueueDepth or BusLogic_UntaggedQueueDepthBB, unless a
+  lower Queue Depth option is provided.  A Queue Depth of 1 automatically
+  disables Tagged Queuing.
 
 QueueDepth:[<integer>,<integer>...]
 
@@ -587,7+591,7 @@ To install the new BusLogic SCSI driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf BusLogic-2.0.11.tar.gz
+  tar -xvzf BusLogic-2.0.12.tar.gz
   mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
   patch -p < BusLogic.patch
   cd linux
index f41438e..d5f4c9c 100644 (file)
@@ -332,7+332,7 @@ struct Scsi_Host
 
     /* These parameters should be set by the detect routine */
     unsigned char *base;
-    unsigned int  io_port;
+    unsigned long io_port;
     unsigned char n_io_port;
     unsigned char irq;
     unsigned char dma_channel;
@@ -374,7+374,7 @@ struct Scsi_Host
     /*
      * We should ensure that this is aligned, both for better performance
      * and also because some compilers (m68k) don't automatically force
-     * alignment to a 4-byte boundary.
+     * alignment to a long boundary.
      */
     unsigned long hostdata[0]  /* Used for storage of host specific stuff */
         __attribute__ ((aligned (sizeof(unsigned long))));
index 04972ab..fa27ee2 100644 (file)
@@ -666,12+666,12 @@ static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21
 typedef struct {
        int     bus;
        u_char  device_fn;
-       u_int   base;
-       u_int   base_2;
-       u_int   io_port;
+       u_long  base;
+       u_long  base_2;
+       u_long  io_port;
        int     irq;
 /* port and reg fields to use INB, OUTB macros */
-       u_int   port;
+       u_long  port;
        volatile struct ncr_reg *reg;
 } ncr_slot;
 
@@ -1834,7+1834,7 @@ struct ncb {
        /*
        **      address of the ncr control registers in io space
        */
-       u_int           port;
+       u_long          port;
 
        /*
        **      irq level
@@ -4388,7+4388,7 @@ static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
        u_long flags = 0;
        ncr_nvram *nvram = device->nvram;
 
-printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%x, io_port=0x%x, irq=%d\n",
+printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
        device->chip.name, unit, device->chip.revision_id, device->slot.base,
        device->slot.io_port, device->slot.irq);
 
@@ -9296,7+9296,10 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
        ushort vendor_id, device_id, command;
        uchar cache_line_size, latency_timer;
        uchar irq, revision;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,90)
+       ulong base, base_2, io_port;
+       struct pci_dev *pdev;
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
        uint base, base_2, io_port; 
 #else
        ulong base, base_2; 
@@ -9309,7+9312,7 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
        ncr_chip *chip;
 
        printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
-               bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
+               bus, PCI_SLOT(device_fn), PCI_FUNC(device_fn));
        /*
         * Read info from the PCI config space.
         * pcibios_read_config_xxx() functions are assumed to be used for 
@@ -9323,6+9326,13 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
                                        PCI_DEVICE_ID, &device_id);
        (void) pcibios_read_config_word(bus, device_fn,
                                        PCI_COMMAND, &command);
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,90)
+       pdev = pci_find_dev(bus, device_fn);
+       io_port = pdev->base_address[0];
+       base    = pdev->base_address[1];
+       base_2  = pdev->base_address[2];
+       irq     = pdev->irq;
+#else
        (void) pcibios_read_config_dword(bus, device_fn,
                                        PCI_BASE_ADDRESS_0, &io_port);  
        (void) pcibios_read_config_dword(bus, device_fn,
@@ -9330,9+9340,10 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
        (void) pcibios_read_config_dword(bus, device_fn,
                                        PCI_BASE_ADDRESS_2, &base_2);
        (void) pcibios_read_config_byte(bus, device_fn,
-                                       PCI_CLASS_REVISION,&revision);  
-       (void) pcibios_read_config_byte(bus, device_fn,
                                        PCI_INTERRUPT_LINE, &irq);
+#endif
+       (void) pcibios_read_config_byte(bus, device_fn,
+                                       PCI_CLASS_REVISION, &revision); 
        (void) pcibios_read_config_byte(bus, device_fn,
                                        PCI_CACHE_LINE_SIZE, &cache_line_size);
        (void) pcibios_read_config_byte(bus, device_fn,
@@ -9448,7+9459,7 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
        /*
         * Try to fix up PCI config according to wished features.
         */
-#if defined(__i386__) && !defined(MODULE)
+#if defined(__i386) && !defined(MODULE)
        if ((driver_setup.pci_fix_up & 1) &&
            (chip->features & FE_CLSE) && cache_line_size == 0) {
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
index 861e126..2e9d3a9 100644 (file)
 
 #define DEFAULT_LOOP_COUNT     1000000
 
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
 /* End Configuration section *************************************************/
 
 #include <linux/module.h>
@@ -606,7+608,7 @@ int isp1020_detect(Scsi_Host_Template *tmpt)
                }
 
                if (check_region(host->io_port, 0xff)) {
-                       printk("qlogicisp : i/o region 0x%04x-0x%04x already "
+                       printk("qlogicisp : i/o region 0x%lx-0x%lx already "
                               "in use\n",
                               host->io_port, host->io_port + 0xff);
                        free_irq(host->irq, NULL);
@@ -658,7+660,7 @@ const char *isp1020_info(struct Scsi_Host *host)
 
        hostdata = (struct isp1020_hostdata *) host->hostdata;
        sprintf(buf,
-               "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x",
+               "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%lx",
                hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, host->irq,
                host->io_port);
 
@@ -1166,10+1168,13 @@ static int isp1020_reset_hardware(struct Scsi_Host *host)
 
 static int isp1020_init(struct Scsi_Host *sh)
 {
-       u_int io_base;
+       u_long io_base = 0;
        struct isp1020_hostdata *hostdata;
        u_char bus, device_fn, revision, irq;
        u_short vendor_id, device_id, command;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,90)
+       struct pci_dev *pdev;
+#endif
 
        ENTER("isp1020_init");
 
@@ -1182,17+1187,25 @@ static int isp1020_init(struct Scsi_Host *sh)
                                        PCI_DEVICE_ID, &device_id)
             || pcibios_read_config_word(bus, device_fn,
                                        PCI_COMMAND, &command)
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,90)
             || pcibios_read_config_dword(bus, device_fn,
                                         PCI_BASE_ADDRESS_0, &io_base)
            || pcibios_read_config_byte(bus, device_fn,
-                                       PCI_CLASS_REVISION, &revision)
+                                       PCI_INTERRUPT_LINE, &irq)
+#endif
             || pcibios_read_config_byte(bus, device_fn,
-                                       PCI_INTERRUPT_LINE, &irq))
+                                       PCI_CLASS_REVISION, &revision))
        {
                printk("qlogicisp : error reading PCI configuration\n");
                return 1;
        }
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,90)
+       pdev = pci_find_dev(bus, device_fn);
+       io_base = pdev->base_address[0];
+       irq     = pdev->irq;
+#endif
+
        if (vendor_id != PCI_VENDOR_ID_QLOGIC) {
                printk("qlogicisp : 0x%04x is not QLogic vendor ID\n",
                       vendor_id);
index 1b915e3..beedc53 100644 (file)
@@ -513,7+513,7 @@ typedef struct icbRevLvl {
 typedef struct icbUnsMask {    /* I'm totally guessing here */
     unchar op;
     volatile unchar mask[14];  /* mask bits                 */
-#ifdef 0
+#if 0
     unchar rsvd[12];           /* reserved                  */
 #endif
     volatile unchar vue;       /* vendor-unique error code  */
index 5de6767..34f51d2 100644 (file)
@@ -147,6+147,9 @@ ncp_negotiate_size_and_options(struct ncp_server *server,
        int size, int options, int *ret_size, int *ret_options) {
        int result;
 
+       /* there is minimum */
+       if (size < 512) size = 512;
+
        ncp_init_request(server);
        ncp_add_word(server, htons(size));
        ncp_add_byte(server, options);
@@ -157,7+160,10 @@ ncp_negotiate_size_and_options(struct ncp_server *server,
                return result;
        }
 
-       *ret_size = min(ntohs(ncp_reply_word(server, 0)), size);
+       /* NCP over UDP returns 0 (!!!) */
+       result = ntohs(ncp_reply_word(server, 0));
+       if (result >= 512) size=min(result, size);
+       *ret_size = size;
        *ret_options = ncp_reply_byte(server, 4);
 
        ncp_unlock_server(server);
index bae89c1..f945da6 100644 (file)
 #define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
 #define BSET(buf,pos,val) (BVAL(buf,pos) = (val))
 
-static inline word
+static inline __u16
 WVAL_LH(__u8 * buf, int pos)
 {
        return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8;
 }
-static inline dword
+static inline __u32
 DVAL_LH(__u8 * buf, int pos)
 {
        return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16;
 }
 static inline void
-WSET_LH(__u8 * buf, int pos, word val)
+WSET_LH(__u8 * buf, int pos, __u16 val)
 {
        BSET(buf, pos, val & 0xff);
        BSET(buf, pos + 1, val >> 8);
 }
 static inline void
-DSET_LH(__u8 * buf, int pos, dword val)
+DSET_LH(__u8 * buf, int pos, __u32 val)
 {
        WSET_LH(buf, pos, val & 0xffff);
        WSET_LH(buf, pos + 2, val >> 16);
index 97bb273..eabcd85 100644 (file)
 #include <linux/fs.h>
 #endif
 
-#if defined(i386) || defined(__i386__)
+#if defined(i386) || defined(__i386__) || defined(__alpha__)
 
 /* unsigned integral types */
 #ifndef NTFS_INTEGRAL_TYPES
index 1618135..36ac359 100644 (file)
 #else /* CONFIG_ALPHA_XL */
 
 /* these are for normal APECS family machines, AVANTI/MUSTANG/EB64/PC64 */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define APECS_DMA_WIN_BASE_DEFAULT     (1024*1024*1024)
+#define APECS_DMA_WIN_SIZE_DEFAULT     (1024*1024*1024)
+
+extern unsigned int APECS_DMA_WIN_BASE;
+extern unsigned int APECS_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
 #define APECS_DMA_WIN_BASE     (1024*1024*1024)
 #define APECS_DMA_WIN_SIZE     (1024*1024*1024)
+#endif /* SRM_SETUP */
 
 #endif /* CONFIG_ALPHA_XL */
 
index bec44fe..70c857a 100644 (file)
  * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1).
  */
 
-extern __inline__ void set_bit(unsigned long nr, void * addr)
+extern __inline__ void set_bit(unsigned long nr, volatile void * addr)
 {
        unsigned long oldbit;
        unsigned long temp;
@@ -38,7+38,7 @@ extern __inline__ void set_bit(unsigned long nr, void * addr)
        :"Ir" (1UL << (nr & 31)), "m" (*m));
 }
 
-extern __inline__ void clear_bit(unsigned long nr, void * addr)
+extern __inline__ void clear_bit(unsigned long nr, volatile void * addr)
 {
        unsigned long oldbit;
        unsigned long temp;
@@ -59,7+59,7 @@ extern __inline__ void clear_bit(unsigned long nr, void * addr)
        :"Ir" (1UL << (nr & 31)), "m" (*m));
 }
 
-extern __inline__ void change_bit(unsigned long nr, void * addr)
+extern __inline__ void change_bit(unsigned long nr, volatile void * addr)
 {
        unsigned long temp;
        unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
@@ -76,7+76,8 @@ extern __inline__ void change_bit(unsigned long nr, void * addr)
        :"Ir" (1UL << (nr & 31)), "m" (*m));
 }
 
-extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void * addr)
+extern __inline__ unsigned long test_and_set_bit(unsigned long nr,
+                                                volatile void * addr)
 {
        unsigned long oldbit;
        unsigned long temp;
@@ -99,7+100,8 @@ extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void * addr)
        return oldbit != 0;
 }
 
-extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void * addr)
+extern __inline__ unsigned long test_and_clear_bit(unsigned long nr,
+                                                  volatile void * addr)
 {
        unsigned long oldbit;
        unsigned long temp;
@@ -122,7+124,8 @@ extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void * addr
        return oldbit != 0;
 }
 
-extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void * addr)
+extern __inline__ unsigned long test_and_change_bit(unsigned long nr,
+                                                   volatile void * addr)
 {
        unsigned long oldbit;
        unsigned long temp;
@@ -143,7+146,7 @@ extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void * add
        return oldbit != 0;
 }
 
-extern __inline__ unsigned long test_bit(int nr, const void * addr)
+extern __inline__ unsigned long test_bit(int nr, volatile void * addr)
 {
        return 1UL & (((const int *) addr)[nr >> 5] >> (nr & 31));
 }
index 963cfa8..38269ea 100644 (file)
 
 #define BYTE_ENABLE_SHIFT 5
 #define TRANSFER_LENGTH_SHIFT 3
-#define MEM_SP1_MASK 0x1fffffff  /* Mem sparse space 1 mask is 29 bits */
 
+#define MEM_R1_MASK 0x1fffffff  /* SPARSE Mem region 1 mask is 29 bits */
+#define MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
+#define MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
 
-#define CIA_DMA_WIN_BASE       (1024UL*1024UL*1024UL)
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define CIA_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define CIA_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int CIA_DMA_WIN_BASE;
+extern unsigned int CIA_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define CIA_DMA_WIN_BASE            (1024*1024*1024)
 #define CIA_DMA_WIN_SIZE       (1024*1024*1024)
+#endif /* SRM_SETUP */
 
 /*
  * 21171-CA Control and Status Registers (p4-1)
 #define CIA_IOC_CIA_REV               (IDENT_ADDR + 0x8740000080UL)
 #define CIA_IOC_PCI_LAT               (IDENT_ADDR + 0x87400000C0UL)
 #define CIA_IOC_CIA_CTRL              (IDENT_ADDR + 0x8740000100UL)
+#define CIA_IOC_CIA_CNFG              (IDENT_ADDR + 0x8740000140UL)
 #define CIA_IOC_HAE_MEM               (IDENT_ADDR + 0x8740000400UL)
 #define CIA_IOC_HAE_IO                (IDENT_ADDR + 0x8740000440UL)
 #define CIA_IOC_CFG                   (IDENT_ADDR + 0x8740000480UL)
 #define CIA_IOC_PCI_ERR3              (IDENT_ADDR + 0x8740008880UL)
 
 /*
- * 2117A-CA PCI Address Translation Registers.   I've only defined
- * the first window fully as that's the only one that we're currently using.
- * The other window bases are needed to disable the windows.
+ * 2117A-CA PCI Address Translation Registers.
  */
 #define CIA_IOC_PCI_TBIA              (IDENT_ADDR + 0x8760000100UL)
+
 #define CIA_IOC_PCI_W0_BASE           (IDENT_ADDR + 0x8760000400UL)
 #define CIA_IOC_PCI_W0_MASK           (IDENT_ADDR + 0x8760000440UL)
 #define CIA_IOC_PCI_T0_BASE           (IDENT_ADDR + 0x8760000480UL)
 
 #define CIA_IOC_PCI_W1_BASE           (IDENT_ADDR + 0x8760000500UL)
+#define CIA_IOC_PCI_W1_MASK           (IDENT_ADDR + 0x8760000540UL)
+#define CIA_IOC_PCI_T1_BASE           (IDENT_ADDR + 0x8760000580UL)
+
 #define CIA_IOC_PCI_W2_BASE           (IDENT_ADDR + 0x8760000600UL)
+#define CIA_IOC_PCI_W2_MASK           (IDENT_ADDR + 0x8760000640UL)
+#define CIA_IOC_PCI_T2_BASE           (IDENT_ADDR + 0x8760000680UL)
+
 #define CIA_IOC_PCI_W3_BASE           (IDENT_ADDR + 0x8760000700UL)
+#define CIA_IOC_PCI_W3_MASK           (IDENT_ADDR + 0x8760000740UL)
+#define CIA_IOC_PCI_T3_BASE           (IDENT_ADDR + 0x8760000780UL)
 
 /*
  * 21171-CA System configuration registers (p4-3)
 #define CIA_CONF                       (IDENT_ADDR + 0x8700000000UL)
 #define CIA_IO                         (IDENT_ADDR + 0x8580000000UL)
 #define CIA_SPARSE_MEM                 (IDENT_ADDR + 0x8000000000UL)
+#define CIA_SPARSE_MEM_R2              (IDENT_ADDR + 0x8400000000UL)
+#define CIA_SPARSE_MEM_R3              (IDENT_ADDR + 0x8500000000UL)
 #define CIA_DENSE_MEM                  (IDENT_ADDR + 0x8600000000UL)
 
 /*
@@ -296,13+318,125 @@ extern inline void __outl(unsigned int b, unsigned long addr)
  * 
  */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long cia_sm_base_r1, cia_sm_base_r2, cia_sm_base_r3;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x08);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x08);
+       else
+       {
+#if 0
+         printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= cia_sm_base_r1) &&
+           (addr <= (cia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + CIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= cia_sm_base_r2) &&
+           (addr <= (cia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + CIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= cia_sm_base_r3) &&
+           (addr <= (cia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + CIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x00010001;
+}
+
+#else /* SRM_SETUP */
+
 extern inline unsigned long __readb(unsigned long addr)
 {
        unsigned long result, shift, msb;
 
        shift = (addr & 0x3) * 8 ;
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -317,7+451,7 @@ extern inline unsigned long __readw(unsigned long addr)
 
        shift = (addr & 0x3) * 8;
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -326,17+460,12 @@ extern inline unsigned long __readw(unsigned long addr)
        return 0xffffUL & result;
 }
 
-extern inline unsigned long __readl(unsigned long addr)
-{
-       return *(vuip) (addr + CIA_DENSE_MEM);
-}
-
 extern inline void __writeb(unsigned char b, unsigned long addr)
 {
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -348,13+477,20 @@ extern inline void __writew(unsigned short b, unsigned long addr)
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
        *(vuip) ((addr << 5) + CIA_SPARSE_MEM + 0x08) = b * 0x00010001;
 }
 
+#endif /* SRM_SETUP */
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+       return *(vuip) (addr + CIA_DENSE_MEM);
+}
+
 extern inline void __writel(unsigned int b, unsigned long addr)
 {
        *(vuip) (addr + CIA_DENSE_MEM) = b;
index 733216b..556e744 100644 (file)
@@ -17,7+17,65 @@ extern unsigned int local_irq_count[NR_CPUS];
 
 #else
 
-#error No habla alpha SMP
+/* initially just a straight copy if the i386 code */
+
+#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;
+
+static inline void release_irqlock(int cpu)
+{
+       /* if we didn't own the irq lock, just ignore.. */
+       if (global_irq_holder == (unsigned char) cpu) {
+               global_irq_holder = NO_PROC_ID;
+               spin_unlock(&global_irq_lock);
+        }
+}
+
+/* Ordering of the counter bumps is _deadly_ important. */
+static inline void hardirq_enter(int cpu)
+{
+       ++local_irq_count[cpu];
+        atomic_inc(&global_irq_count);
+}
+
+static inline void hardirq_exit(int cpu)
+{
+       atomic_dec(&global_irq_count);
+        --local_irq_count[cpu];
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+       unsigned long flags;
+       int ret = 1;
+
+        __save_and_cli(flags);
+        if ((atomic_add_return(1, &global_irq_count) != 1) ||
+           (global_irq_lock.lock != 0)) {
+               atomic_dec(&global_irq_count);
+                __restore_flags(flags);
+                ret = 0;
+        } else {
+               ++local_irq_count[cpu];
+                __sti();
+        }
+        return ret;
+}
+
+#define hardirq_endlock(cpu) \
+       do { \
+              __cli(); \
+               hardirq_exit(cpu); \
+               __sti(); \
+       } while (0)
+
+extern void synchronize_irq(void);
 
 #endif /* __SMP__ */
 #endif /* _ALPHA_HARDIRQ_H */
index 4f6c5d0..6909f0b 100644 (file)
 #define EV56_CPU               7       /* EV5.6 (21164)        */
 #define EV6_CPU                        8       /* EV6 (21164)          */
 #define PCA56_CPU              9       /* PCA56 (21164PC)      */
-#define PCA57_CPU              10      /* PCA57 (??)           */
+#define PCA57_CPU              10      /* PCA57 (21164??)      */
 
 /*
  * DEC system types for Alpha systems.  Found in HWRPB.
 #define ST_DEC_AXPPCI_33        11     /* NoName system type   */
 #define ST_DEC_TLASER           12     /* Turbolaser systype   */
 #define ST_DEC_2100_A50                 13     /* Avanti systype       */
-#define ST_DEC_MUSTANG          14     /* Mustang systype      */
 #define ST_DEC_ALCOR            15     /* Alcor (EV5) systype  */
 #define ST_DEC_1000             17     /* Mikasa systype       */
+#define ST_DEC_EB64             18     /* EB64 systype         */
 #define ST_DEC_EB66             19     /* EB66 systype         */
 #define ST_DEC_EB64P            20     /* EB64+ systype        */
-#define ST_DEC_EB66P           -19     /* EB66 systype         */
-#define ST_DEC_EBPC64          -20     /* Cabriolet (AlphaPC64) systype */
-#define ST_DEC_BURNS            21     /* Laptop systype       */
+#define ST_DEC_BURNS            21     /* laptop systype       */
 #define ST_DEC_RAWHIDE          22     /* Rawhide systype      */
 #define ST_DEC_K2               23     /* K2 systype           */
 #define ST_DEC_LYNX             24     /* Lynx systype         */
 #define ST_DEC_EB164            26     /* EB164 systype        */
 #define ST_DEC_NORITAKE                 27     /* Noritake systype     */
 #define ST_DEC_CORTEX           28     /* Cortex systype       */
-#define ST_DEC_MIATA            30     /* MIATA systype        */
+#define ST_DEC_MIATA            30     /* Miata systype        */
 #define ST_DEC_XXM              31     /* XXM systype          */
 #define ST_DEC_TAKARA           32     /* Takara systype       */
 #define ST_DEC_YUKON            33     /* Yukon systype        */
 #define ST_UNOFFICIAL_BIAS     100
 #define ST_DTI_RUFFIAN         101     /* RUFFIAN systype      */
 
-
 struct pcb_struct {
        unsigned long ksp;
        unsigned long usp;
@@ -139,6+136,12 @@ struct memdesc_struct {
        struct memclust_struct cluster[0];
 };
 
+struct dsr_struct {
+       long smm;                       /* SMM nubber used by LMF       */
+       unsigned long  lurt_off;        /* offset to LURT table         */
+       unsigned long  sysname_off;     /* offset to sysname char count */
+};
+
 struct hwrpb_struct {
        unsigned long phys_addr;        /* check: physical address of the hwrpb */
        unsigned long id;               /* check: "HWRPB\0\0\0" */
@@ -178,7+181,7 @@ struct hwrpb_struct {
        unsigned long chksum;
        unsigned long rxrdy;
        unsigned long txrdy;
-       unsigned long dsrdbt_offset;    /* "Dynamic System Recognition Data Block Table" Whee */
+       unsigned long dsr_offset;       /* "Dynamic System Recognition Data Block Table" */
 };
 
 #endif
index da03e68..d2668b9 100644 (file)
@@ -25,7+25,11 @@ extern struct hae {
 /*
  * Virtual -> physical identity mapping starts at this offset
  */
+#ifdef USE_48_BIT_KSEG
+#define IDENT_ADDR     (0xffff800000000000UL)
+#else
 #define IDENT_ADDR     (0xfffffc0000000000UL)
+#endif
 
 #ifdef __KERNEL__
 
@@ -38,11+42,11 @@ extern struct hae {
  */
 extern inline void set_hae(unsigned long new_hae)
 {
-       unsigned long ipl;
-       ipl = swpipl(7);
+       unsigned long ipl = swpipl(7);
        hae.cache = new_hae;
        *hae.reg = new_hae;
        mb();
+       new_hae = *hae.reg; /* read to make sure it was written */
        setipl(ipl);
 }
 
@@ -84,6+88,10 @@ extern void _sethae (unsigned long addr);    /* cached version */
 # include <asm/t2.h>           /* get chip-specific definitions */
 #elif defined(CONFIG_ALPHA_PYXIS)
 # include <asm/pyxis.h>                /* get chip-specific definitions */
+#elif defined(CONFIG_ALPHA_TSUNAMI)
+# include <asm/tsunami.h>      /* get chip-specific definitions */
+#elif defined(CONFIG_ALPHA_MCPCIA)
+# include <asm/mcpcia.h>       /* get chip-specific definitions */
 #else
 # include <asm/jensen.h>
 #endif
index 5c81ff6..e8cc7f9 100644 (file)
 #include <linux/linkage.h>
 #include <linux/config.h>
 
-#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \
-       defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164) || \
+#if   defined(CONFIG_ALPHA_CABRIOLET) || \
+      defined(CONFIG_ALPHA_EB66P)     || \
+      defined(CONFIG_ALPHA_EB164)     || \
+      defined(CONFIG_ALPHA_PC164)     || \
        defined(CONFIG_ALPHA_LX164)
-# define NR_IRQS       33
-#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || \
+
+# define NR_IRQS       35
+
+#elif defined(CONFIG_ALPHA_EB66)      || \
+      defined(CONFIG_ALPHA_EB64P)     || \
        defined(CONFIG_ALPHA_MIKASA)
+
 # define NR_IRQS       32
-#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) || \
-       defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_NORITAKE) || \
-       defined(CONFIG_ALPHA_RUFFIAN)
+
+#elif defined(CONFIG_ALPHA_ALCOR)     || \
+      defined(CONFIG_ALPHA_XLT)       || \
+      defined(CONFIG_ALPHA_MIATA)     || \
+      defined(CONFIG_ALPHA_RUFFIAN)   || \
+      defined(CONFIG_ALPHA_NORITAKE)
+
 # define NR_IRQS       48
-#elif defined(CONFIG_ALPHA_SABLE) || defined(CONFIG_ALPHA_SX164)
+
+#elif defined(CONFIG_ALPHA_SABLE)     || \
+      defined(CONFIG_ALPHA_SX164)
+
 # define NR_IRQS       40
-#else
+
+#elif defined(CONFIG_ALPHA_DP264) || \
+      defined(CONFIG_ALPHA_RAWHIDE)
+
+# define NR_IRQS       64
+
+#elif defined(CONFIG_ALPHA_TAKARA)
+
+# define NR_IRQS       20
+
+#else /* everyone else */
+
 # define NR_IRQS       16
+
 #endif
 
 
index 1eb35a2..9ea03dd 100644 (file)
 
 #include <asm/system.h>
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define LCA_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define LCA_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int LCA_DMA_WIN_BASE;
+extern unsigned int LCA_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
 #define LCA_DMA_WIN_BASE       (1024*1024*1024)
 #define LCA_DMA_WIN_SIZE       (1024*1024*1024)
+#endif /* SRM_SETUP */
 
 /*
  * Memory Controller registers:
diff --git a/include/asm-alpha/mcpcia.h b/include/asm-alpha/mcpcia.h
new file mode 100644 (file)
index 0000000..fd4d488
--- /dev/null
@@ -0,0 +1,668 @@
+#ifndef __ALPHA_MCPCIA__H__
+#define __ALPHA_MCPCIA__H__
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/*
+ * MCPCIA is the internal name for a core logic chipset which provides
+ * PCI access for the RAWHIDE family of systems.
+ *
+ * This file is based on:
+ *
+ * RAWHIDE System Programmer's Manual
+ * 16-May-96
+ * Rev. 1.4
+ *
+ */
+
+/*------------------------------------------------------------------------**
+**                                                                        **
+**  I/O procedures                                                   **
+**                                                                        **
+**      inport[b|w|t|l], outport[b|w|t|l] 8:16:24:32 IO xfers             **
+**     inportbxt: 8 bits only                                            **
+**      inport:    alias of inportw                                       **
+**      outport:   alias of outportw                                      **
+**                                                                        **
+**      inmem[b|w|t|l], outmem[b|w|t|l] 8:16:24:32 ISA memory xfers       **
+**     inmembxt: 8 bits only                                             **
+**      inmem:    alias of inmemw                                         **
+**      outmem:   alias of outmemw                                        **
+**                                                                        **
+**------------------------------------------------------------------------*/
+
+
+/* MCPCIA ADDRESS BIT DEFINITIONS
+ *
+ *  3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |1| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
+ *  |                                                                        \_/ \_/
+ *  |                                                                         |   |
+ *  +-- IO space, not cached.                                   Byte Enable --+   |
+ *                                                              Transfer Length --+
+ *
+ *
+ *
+ *   Byte      Transfer
+ *   Enable    Length    Transfer  Byte    Address
+ *   adr<6:5>  adr<4:3>  Length    Enable  Adder
+ *   ---------------------------------------------
+ *      00        00      Byte      1110   0x000
+ *      01        00      Byte      1101   0x020
+ *      10        00      Byte      1011   0x040
+ *      11        00      Byte      0111   0x060
+ *
+ *      00        01      Word      1100   0x008
+ *      01        01      Word      1001   0x028 <= Not supported in this code.
+ *      10        01      Word      0011   0x048
+ *
+ *      00        10      Tribyte   1000   0x010
+ *      01        10      Tribyte   0001   0x030
+ *
+ *      10        11      Longword  0000   0x058
+ *
+ *      Note that byte enables are asserted low.
+ *
+ */
+
+#define BYTE_ENABLE_SHIFT 5
+#define TRANSFER_LENGTH_SHIFT 3
+
+#define MEM_R1_MASK 0x1fffffff  /* SPARSE Mem region 1 mask is 29 bits */
+#define MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
+#define MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define MCPCIA_DMA_WIN_BASE_DEFAULT    (2*1024*1024*1024U)
+#define MCPCIA_DMA_WIN_SIZE_DEFAULT    (2*1024*1024*1024U)
+
+extern unsigned int MCPCIA_DMA_WIN_BASE;
+extern unsigned int MCPCIA_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define MCPCIA_DMA_WIN_BASE    (2*1024*1024*1024UL)
+#define MCPCIA_DMA_WIN_SIZE    (2*1024*1024*1024UL)
+#endif /* SRM_SETUP */
+
+#define HOSE(h) (((unsigned long)(h)) << 33)
+/*
+ *  General Registers
+ */
+#define MCPCIA_REV(h)          (IDENT_ADDR + 0xf9e0000000UL + HOSE(h))
+#define MCPCIA_WHOAMI(h)       (IDENT_ADDR + 0xf9e0000040UL + HOSE(h))
+#define MCPCIA_PCI_LAT(h)      (IDENT_ADDR + 0xf9e0000080UL + HOSE(h))
+#define MCPCIA_CAP_CTRL(h)     (IDENT_ADDR + 0xf9e0000100UL + HOSE(h))
+#define MCPCIA_HAE_MEM(h)      (IDENT_ADDR + 0xf9e0000400UL + HOSE(h))
+#define MCPCIA_HAE_IO(h)       (IDENT_ADDR + 0xf9e0000440UL + HOSE(h))
+#if 0
+#define MCPCIA_IACK_SC(h)      (IDENT_ADDR + 0xf9e0000480UL + HOSE(h))
+#endif
+#define MCPCIA_HAE_DENSE(h)    (IDENT_ADDR + 0xf9e00004c0UL + HOSE(h))
+
+/*
+ * Interrupt Control registers
+ */
+#define MCPCIA_INT_CTL(h)      (IDENT_ADDR + 0xf9e0000500UL + HOSE(h))
+#define MCPCIA_INT_REQ(h)      (IDENT_ADDR + 0xf9e0000540UL + HOSE(h))
+#define MCPCIA_INT_TARG(h)     (IDENT_ADDR + 0xf9e0000580UL + HOSE(h))
+#define MCPCIA_INT_ADR(h)      (IDENT_ADDR + 0xf9e00005c0UL + HOSE(h))
+#define MCPCIA_INT_ADR_EXT(h)  (IDENT_ADDR + 0xf9e0000600UL + HOSE(h))
+#define MCPCIA_INT_MASK0(h)    (IDENT_ADDR + 0xf9e0000640UL + HOSE(h))
+#define MCPCIA_INT_MASK1(h)    (IDENT_ADDR + 0xf9e0000680UL + HOSE(h))
+#define MCPCIA_INT_ACK0(h)     (IDENT_ADDR + 0xf9f0003f00UL + HOSE(h))
+#define MCPCIA_INT_ACK1(h)     (IDENT_ADDR + 0xf9e0003f40UL + HOSE(h))
+
+/*
+ * Performance Monitor registers
+ */
+#define MCPCIA_PERF_MONITOR(h) (IDENT_ADDR + 0xf9e0000300UL + HOSE(h))
+#define MCPCIA_PERF_CONTROL(h) (IDENT_ADDR + 0xf9e0000340UL + HOSE(h))
+
+/*
+ * Diagnostic Registers
+ */
+#define MCPCIA_CAP_DIAG(h)     (IDENT_ADDR + 0xf9e0000700UL + HOSE(h))
+#define MCPCIA_TOP_OF_MEM(h)   (IDENT_ADDR + 0xf9e00007c0UL + HOSE(h))
+
+/*
+ * Error registers
+ */
+#define MCPCIA_CAP_ERR(h)      (IDENT_ADDR + 0xf9e0000880UL + HOSE(h))
+#define MCPCIA_PCI_ERR1(h)     (IDENT_ADDR + 0xf9e0001040UL + HOSE(h))
+
+/*
+ * PCI Address Translation Registers.
+ */
+#define MCPCIA_SG_TBIA(h)      (IDENT_ADDR + 0xf9e0001300UL + HOSE(h))
+#define MCPCIA_HBASE(h)                (IDENT_ADDR + 0xf9e0001340UL + HOSE(h))
+
+#define MCPCIA_W0_BASE(h)      (IDENT_ADDR + 0xf9e0001400UL + HOSE(h))
+#define MCPCIA_W0_MASK(h)      (IDENT_ADDR + 0xf9e0001440UL + HOSE(h))
+#define MCPCIA_T0_BASE(h)      (IDENT_ADDR + 0xf9e0001480UL + HOSE(h))
+
+#define MCPCIA_W1_BASE(h)      (IDENT_ADDR + 0xf9e0001500UL + HOSE(h))
+#define MCPCIA_W1_MASK(h)      (IDENT_ADDR + 0xf9e0001540UL + HOSE(h))
+#define MCPCIA_T1_BASE(h)      (IDENT_ADDR + 0xf9e0001580UL + HOSE(h))
+
+#define MCPCIA_W2_BASE(h)      (IDENT_ADDR + 0xf9e0001600UL + HOSE(h))
+#define MCPCIA_W2_MASK(h)      (IDENT_ADDR + 0xf9e0001640UL + HOSE(h))
+#define MCPCIA_T2_BASE(h)      (IDENT_ADDR + 0xf9e0001680UL + HOSE(h))
+
+#define MCPCIA_W3_BASE(h)      (IDENT_ADDR + 0xf9e0001700UL + HOSE(h))
+#define MCPCIA_W3_MASK(h)      (IDENT_ADDR + 0xf9e0001740UL + HOSE(h))
+#define MCPCIA_T3_BASE(h)      (IDENT_ADDR + 0xf9e0001780UL + HOSE(h))
+
+/*
+ * Memory spaces:
+ */
+#define MCPCIA_CONF(h)         (IDENT_ADDR + 0xf9c0000000UL + HOSE(h))
+#define MCPCIA_IO(h)           (IDENT_ADDR + 0xf980000000UL + HOSE(h))
+#define MCPCIA_SPARSE(h)       (IDENT_ADDR + 0xf800000000UL + HOSE(h))
+#define MCPCIA_DENSE(h)                (IDENT_ADDR + 0xf900000000UL + HOSE(h))
+#define MCPCIA_IACK_SC(h)      (IDENT_ADDR + 0xf9f0003f00UL + HOSE(h))
+
+#define HAE_ADDRESS            MCPCIA_HAE_MEM(0)
+
+#ifdef __KERNEL__
+
+/*
+ * Translate physical memory address as seen on (PCI) bus into
+ * a kernel virtual address and vv.
+ */
+extern inline unsigned long virt_to_bus(void * address)
+{
+       return virt_to_phys(address) + MCPCIA_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+       return phys_to_virt(address - MCPCIA_DMA_WIN_BASE);
+}
+
+/*
+ * I/O functions:
+ *
+ * MCPCIA, the RAWHIDE family PCI/memory support chipset for the EV5 (21164)
+ * and EV56 (21164a) processors, can use either a sparse address mapping
+ * scheme, or the so-called byte-word PCI address space, to get at PCI memory
+ * and I/O.
+ *
+ * Unfortunately, we can't use BWIO with EV5, so for now, we always use SPARSE.
+ */
+
+#define vuip   volatile unsigned int *
+
+#ifdef DISABLE_BWIO_ENABLED
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+MCPCIA_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+MCPCIA_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+MCPCIA_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+MCPCIA_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+MCPCIA_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+MCPCIA_BW_IO)), "r" (b));
+}
+
+#define inb(port) __inb((port))
+#define inw(port) __inw((port))
+#define inl(port) __inl((port))
+
+#define outb(x, port) __outb((x),(port))
+#define outw(x, port) __outw((x),(port))
+#define outl(x, port) __outl((x),(port))
+
+#else /* BWIO_ENABLED */
+
+extern inline unsigned int __inb(unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       long result = *(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x00);
+       result >>= (addr & 3) * 8;
+       return 0xffUL & result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       unsigned int w;
+
+       asm ("insbl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+       *(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x00) = w;
+       mb();
+}
+
+extern inline unsigned int __inw(unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       long result = *(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x08);
+       result >>= (addr & 3) * 8;
+       return 0xffffUL & result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       unsigned int w;
+
+       asm ("inswl %2,%1,%0" : "r="(w) : "ri"(addr & 0x3), "r"(b));
+       *(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x08) = w;
+       mb();
+}
+
+extern inline unsigned int __inl(unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       return *(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x18);
+}
+
+extern inline void __outl(unsigned int b, unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       *(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x18) = b;
+       mb();
+}
+
+#define inb(port) \
+(__builtin_constant_p((port))?__inb(port):_inb(port))
+
+#define outb(x, port) \
+(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
+
+#endif /* BWIO_ENABLED */
+
+
+/*
+ * Memory functions.  64-bit and 32-bit accesses are done through
+ * dense memory space, everything else through sparse space.
+ * 
+ * For reading and writing 8 and 16 bit quantities we need to 
+ * go through one of the three sparse address mapping regions
+ * and use the HAE_MEM CSR to provide some bits of the address.
+ * The following few routines use only sparse address region 1
+ * which gives 1Gbyte of accessible space which relates exactly
+ * to the amount of PCI memory mapping *into* system address space.
+ * See p 6-17 of the specification but it looks something like this:
+ *
+ * 21164 Address:
+ * 
+ *          3         2         1
+ * 9876543210987654321098765432109876543210
+ * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ *
+ * ZZ = SBZ
+ * BB = Byte offset
+ * LL = Transfer length
+ *
+ * PCI Address:
+ *
+ * 3         2         1
+ * 10987654321098765432109876543210
+ * HHH....PCI.QW.Address........ 00
+ *
+ * HHH = 31:29 HAE_MEM CSR
+ * 
+ */
+
+#ifdef DISABLE_BWIO_ENABLED
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+MCPCIA_BW_MEM)));
+
+       return result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+MCPCIA_BW_MEM)));
+
+       return result;
+}
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+MCPCIA_BW_MEM)));
+
+       return result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+MCPCIA_BW_MEM)), "r" (b));
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+MCPCIA_BW_MEM)), "r" (b));
+}
+
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+MCPCIA_BW_MEM)), "r" (b));
+}
+
+#define readb(addr) __readb((addr))
+#define readw(addr) __readw((addr))
+
+#define writeb(b, addr) __writeb((b),(addr))
+#define writew(b, addr) __writew((b),(addr))
+
+#else /* BWIO_ENABLED */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long mcpcia_sm_base_r1, mcpcia_sm_base_r2, mcpcia_sm_base_r3;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= mcpcia_sm_base_r1) &&
+           (addr <= (mcpcia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + MCPCIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= mcpcia_sm_base_r2) &&
+           (addr <= (mcpcia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + MCPCIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= mcpcia_sm_base_r3) &&
+           (addr <= (mcpcia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + MCPCIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= mcpcia_sm_base_r1) &&
+           (addr <= (mcpcia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + MCPCIA_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= mcpcia_sm_base_r2) &&
+           (addr <= (mcpcia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + MCPCIA_SPARSE_MEM_R2 + 0x08);
+       else
+       if ((addr >= mcpcia_sm_base_r3) &&
+           (addr <= (mcpcia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + MCPCIA_SPARSE_MEM_R3 + 0x08);
+       else
+       {
+#if 0
+         printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= mcpcia_sm_base_r1) &&
+           (addr <= (mcpcia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + MCPCIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= mcpcia_sm_base_r2) &&
+           (addr <= (mcpcia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + MCPCIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= mcpcia_sm_base_r3) &&
+           (addr <= (mcpcia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + MCPCIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= mcpcia_sm_base_r1) &&
+           (addr <= (mcpcia_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + MCPCIA_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= mcpcia_sm_base_r2) &&
+           (addr <= (mcpcia_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + MCPCIA_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= mcpcia_sm_base_r3) &&
+           (addr <= (mcpcia_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + MCPCIA_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x00010001;
+}
+
+#else /* SRM_SETUP */
+
+extern inline unsigned long __readb(unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       unsigned long result, shift, msb, work, temp;
+
+       shift = (addr & 0x3) << 3;
+       msb = addr & 0xE0000000UL;
+       temp = addr & MEM_R1_MASK;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       work = ((temp << 5) + MCPCIA_SPARSE(hose) + 0x00);
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       unsigned long result, shift, msb, work, temp;
+
+       shift = (addr & 0x3) << 3;
+       msb = addr & 0xE0000000UL;
+       temp = addr & MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       work = ((temp << 5) + MCPCIA_SPARSE(hose) + 0x08);
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+        unsigned long msb; 
+
+       msb = addr & 0xE0000000;
+       addr &= MEM_R1_MASK;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       *(vuip) ((addr << 5) + MCPCIA_SPARSE(hose) + 0x00) = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+        unsigned long msb ; 
+
+       msb = addr & 0xE0000000 ;
+       addr &= MEM_R1_MASK ;
+       if (msb != hae.cache) {
+         set_hae(msb);
+       }
+       *(vuip) ((addr << 5) + MCPCIA_SPARSE(hose) + 0x08) = b * 0x00010001;
+}
+#endif /* SRM_SETUP */
+
+extern inline unsigned long __readl(unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       return *(vuip) (addr + MCPCIA_DENSE(hose));
+}
+
+extern inline void __writel(unsigned int b, unsigned long in_addr)
+{
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       *(vuip) (addr + MCPCIA_DENSE(hose)) = b;
+}
+
+#endif /* BWIO_ENABLED */
+
+#define readl(a)       __readl((unsigned long)(a))
+#define writel(v,a)    __writel((v),(unsigned long)(a))
+
+#undef vuip
+
+struct linux_hose_info {
+        struct pci_bus                  pci_bus;
+       struct linux_hose_info         *next;
+       unsigned long                   pci_io_space;
+       unsigned long                   pci_mem_space;
+       unsigned long                   pci_config_space;
+       unsigned long                   pci_sparse_space;
+        unsigned int                    pci_first_busno;
+        unsigned int                    pci_last_busno;
+       unsigned int                    pci_hose_index;
+};
+
+extern unsigned long mcpcia_init (unsigned long mem_start,
+                                unsigned long mem_end);
+extern unsigned long mcpcia_fixup (unsigned long mem_start,
+                                unsigned long mem_end);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Data structure for handling MCPCIA machine checks:
+ */
+struct el_MCPCIA_uncorrected_frame_mcheck {
+        struct el_common header;
+        struct el_common_EV5_uncorrectable_mcheck procdata;
+};
+
+#define RTC_PORT(x)    (0x70 + (x))
+#define RTC_ADDR(x)    (0x80 | (x))
+#define RTC_ALWAYS_BCD 0
+
+#endif /* __ALPHA_MCPCIA__H__ */
index 6f3f367..285fafa 100644 (file)
 #define BROKEN_ASN 1
 #endif
 
-extern unsigned long asn_cache;
+#ifdef __SMP__
+#define WIDTH_THIS_PROCESSOR   5
+/*
+ * last_asn[processor]:
+ * 63                                            0
+ * +-------------+----------------+--------------+
+ * | asn version | this processor | hardware asn |
+ * +-------------+----------------+--------------+
+ */
+extern unsigned long last_asn[];
+#define asn_cache last_asn[p->processor]
 
-#define ASN_VERSION_SHIFT 16
-#define ASN_VERSION_MASK ((~0UL) << ASN_VERSION_SHIFT)
-#define ASN_FIRST_VERSION (1UL << ASN_VERSION_SHIFT)
+#else
+#define WIDTH_THIS_PROCESSOR   0
+/*
+ * asn_cache:
+ * 63                                            0
+ * +------------------------------+--------------+
+ * |         asn version          | hardware asn |
+ * +------------------------------+--------------+
+ */
+extern unsigned long asn_cache;
+#endif /* __SMP__ */
 
-extern inline void get_new_mmu_context(struct task_struct *p,
-       struct mm_struct *mm,
-       unsigned long asn)
-{
-       /* check if it's legal.. */
-       if ((asn & ~ASN_VERSION_MASK) > MAX_ASN) {
-               /* start a new version, invalidate all old asn's */
-               tbiap(); imb();
-               asn = (asn & ASN_VERSION_MASK) + ASN_FIRST_VERSION;
-               if (!asn)
-                       asn = ASN_FIRST_VERSION;
-       }
-       asn_cache = asn + 1;
-       mm->context = asn;                      /* full version + asn */
-       p->tss.asn = asn & ~ASN_VERSION_MASK;   /* just asn */
-}
+#define WIDTH_HARDWARE_ASN     7
+#define ASN_FIRST_VERSION (1UL << (WIDTH_THIS_PROCESSOR + WIDTH_HARDWARE_ASN))
+#define HARDWARE_ASN_MASK ((1UL << WIDTH_HARDWARE_ASN) - 1)
 
 /*
  * NOTE! The way this is set up, the high bits of the "asn_cache" (and
@@ -73,6+78,23 @@ extern inline void get_new_mmu_context(struct task_struct *p,
  * force a new asn for any other processes the next time they want to
  * run.
  */
+extern inline void
+get_new_mmu_context(struct task_struct *p, struct mm_struct *mm)
+{
+       unsigned long asn = asn_cache;
+
+       if ((asn & HARDWARE_ASN_MASK) < MAX_ASN)
+               ++asn;
+       else {
+               tbiap();
+               imb();
+               asn = (asn & ~HARDWARE_ASN_MASK) + ASN_FIRST_VERSION;
+       }
+       asn_cache = asn;
+       mm->context = asn;                      /* full version + asn */
+       p->tss.asn = asn & HARDWARE_ASN_MASK;   /* just asn */
+}
+
 extern inline void get_mmu_context(struct task_struct *p)
 {
 #ifndef BROKEN_ASN
@@ -81,8+103,8 @@ extern inline void get_mmu_context(struct task_struct *p)
        if (mm) {
                unsigned long asn = asn_cache;
                /* Check if our ASN is of an older version and thus invalid */
-               if ((mm->context ^ asn) & ASN_VERSION_MASK)
-                       get_new_mmu_context(p, mm, asn);
+               if ((mm->context ^ asn) & ~HARDWARE_ASN_MASK)
+                       get_new_mmu_context(p, mm);
        }
 #endif
 }
@@ -91,3+113,4 @@ extern inline void get_mmu_context(struct task_struct *p)
 #define destroy_context(mm)    do { } while(0)
 
 #endif
+
index fdb1e4d..3467e61 100644 (file)
@@ -8,6+8,7 @@
  * This hopefully works with any standard alpha page-size, as defined
  * in <asm/page.h> (currently 8192).
  */
+#include <linux/config.h>
 
 #include <asm/system.h>
 #include <asm/mmu_context.h>
@@ -29,6+30,9 @@ static inline void reload_context(struct task_struct *task)
 {
        __asm__ __volatile__(
                "bis %0,%0,$16\n\t"
+#ifdef CONFIG_ALPHA_DP264
+               "zap $16,0xe0,$16\n\t"
+#endif /* DP264 */
                "call_pal %1"
                : /* no outputs */
                : "r" (&task->tss), "i" (PAL_swpctx)
@@ -80,6+84,7 @@ static inline void flush_tlb(void)
        flush_tlb_current(current->mm);
 }
 
+#ifndef __SMP__
 /*
  * Flush everything (kernel mapping may also have
  * changed due to vmalloc/vfree)
@@ -129,6+134,28 @@ static inline void flush_tlb_range(struct mm_struct *mm,
        flush_tlb_mm(mm);
 }
 
+#else /* __SMP__ */
+
+/* ipi_msg_flush_tb is owned by the holder of the global kernel lock. */
+struct ipi_msg_flush_tb_struct {
+       volatile unsigned int flush_tb_mask;
+       union {
+               struct mm_struct *      flush_mm;
+               struct vm_area_struct * flush_vma;
+       } p;
+       unsigned long flush_addr;
+  /*   unsigned long flush_end; */ /* not used by local_flush_tlb_range */
+};
+
+extern struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
+
+#endif /* __SMP__ */
+
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
  * hook is made available.
index 9d3d495..d10408b 100644 (file)
 #ifndef __ALPHA_PYXIS__H__
 #define __ALPHA_PYXIS__H__
 
-#include <linux/config.h> /* CONFIG_ALPHA_RUFFIAN. */
+#include <linux/config.h>
 #include <linux/types.h>
 
 /*
- * PYXIS is the internal name for a cor logic chipset which provides
+ * PYXIS is the internal name for a core logic chipset which provides
  * memory controller and PCI access for the 21164A chip based systems.
  *
  * This file is based on:
 
 #define BYTE_ENABLE_SHIFT 5
 #define TRANSFER_LENGTH_SHIFT 3
-#define MEM_SP1_MASK 0x1fffffff  /* Mem sparse space 1 mask is 29 bits */
 
+#define MEM_R1_MASK 0x1fffffff  /* SPARSE Mem region 1 mask is 29 bits */
+#define MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
+#define MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
 
-#define PYXIS_DMA_WIN_BASE     (1024UL*1024UL*1024UL)
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define PYXIS_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define PYXIS_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int PYXIS_DMA_WIN_BASE;
+extern unsigned int PYXIS_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define PYXIS_DMA_WIN_BASE     (1024*1024*1024)
 #define PYXIS_DMA_WIN_SIZE     (1024*1024*1024)
+#endif /* SRM_SETUP */
 
 /*
  *  General Registers
 #define PYXIS_DIAG_CHECK               (IDENT_ADDR + 0x8740003000UL)
 
 /*
- * Performance Monitor registers (p4-3)
+ * Performance Monitor registers
  */
 #define PYXIS_PERF_MONITOR             (IDENT_ADDR + 0x8740004000UL)
 #define PYXIS_PERF_CONTROL             (IDENT_ADDR + 0x8740004040UL)
 
 /*
- * 21171-CA Error registers (p4-3)
+ * Error registers
  */
 #define PYXIS_ERR                      (IDENT_ADDR + 0x8740008200UL)
 #define PYXIS_STAT                     (IDENT_ADDR + 0x8740008240UL)
 #define PYXIS_PCI_ERR2                 (IDENT_ADDR + 0x8740008880UL)
 
 /*
- *  PCI Address Translation Registers.   I've only defined
- * the first window fully as that's the only one that we're currently using.
- * The other window bases are needed to disable the windows.
+ * PCI Address Translation Registers.
  */
 #define PYXIS_TBIA                     (IDENT_ADDR + 0x8760000100UL)
+
 #define PYXIS_W0_BASE                  (IDENT_ADDR + 0x8760000400UL)
 #define PYXIS_W0_MASK                  (IDENT_ADDR + 0x8760000440UL)
 #define PYXIS_T0_BASE                  (IDENT_ADDR + 0x8760000480UL)
 
 #define PYXIS_W1_BASE                  (IDENT_ADDR + 0x8760000500UL)
+#define PYXIS_W1_MASK                  (IDENT_ADDR + 0x8760000540UL)
+#define PYXIS_T1_BASE                  (IDENT_ADDR + 0x8760000580UL)
+
 #define PYXIS_W2_BASE                  (IDENT_ADDR + 0x8760000600UL)
+#define PYXIS_W2_MASK                  (IDENT_ADDR + 0x8760000640UL)
+#define PYXIS_T2_BASE                  (IDENT_ADDR + 0x8760000680UL)
+
 #define PYXIS_W3_BASE                  (IDENT_ADDR + 0x8760000700UL)
+#define PYXIS_W3_MASK                  (IDENT_ADDR + 0x8760000740UL)
+#define PYXIS_T3_BASE                  (IDENT_ADDR + 0x8760000780UL)
 
 /*
  * Memory Control registers
 #define PYXIS_CONF                     (IDENT_ADDR + 0x8700000000UL)
 #define PYXIS_IO                       (IDENT_ADDR + 0x8580000000UL)
 #define PYXIS_SPARSE_MEM               (IDENT_ADDR + 0x8000000000UL)
+#define PYXIS_SPARSE_MEM_R2            (IDENT_ADDR + 0x8400000000UL)
+#define PYXIS_SPARSE_MEM_R3            (IDENT_ADDR + 0x8500000000UL)
 #define PYXIS_DENSE_MEM                        (IDENT_ADDR + 0x8600000000UL)
 
 /*
+ * Byte/Word PCI Memory Spaces:
+ */
+#define PYXIS_BW_MEM                   (IDENT_ADDR + 0x8800000000UL)
+#define PYXIS_BW_IO                    (IDENT_ADDR + 0x8900000000UL)
+#define PYXIS_BW_CFG_0                 (IDENT_ADDR + 0x8a00000000UL)
+#define PYXIS_BW_CFG_1                 (IDENT_ADDR + 0x8b00000000UL)
+
+/*
  * Interrupt Control registers
  */
 #define PYXIS_INT_REQ                  (IDENT_ADDR + 0x87A0000000UL)
  * Translate physical memory address as seen on (PCI) bus into
  * a kernel virtual address and vv.
  */
-
 #if defined(CONFIG_ALPHA_RUFFIAN)
-/* Ruffian doesn't do 1G PCI window */
+/* Ruffian doesn't do 1G PCI window */
 
 extern inline unsigned long virt_to_bus(void * address)
 {
@@ -192,7+220,7 @@ extern inline void * bus_to_virt(unsigned long address)
 {
        return phys_to_virt(address);
 }
-#else
+#else /* RUFFIAN */
 extern inline unsigned long virt_to_bus(void * address)
 {
        return virt_to_phys(address) + PYXIS_DMA_WIN_BASE;
@@ -207,13+235,86 @@ extern inline void * bus_to_virt(unsigned long address)
 /*
  * I/O functions:
  *
- * PYXIS (the 2117x PCI/memory support chipset for the EV5 (21164)
- * series of processors uses a sparse address mapping scheme to
+ * PYXIS, the 21174 PCI/memory support chipset for the EV56 (21164A)
+ * and PCA56 (21164PC) processors, can use either a sparse address
+ * mapping scheme, or the so-called byte-word PCI address space, to
  * get at PCI memory and I/O.
  */
 
 #define vuip   volatile unsigned int *
 
+#ifdef BWIO_ENABLED
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+PYXIS_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+PYXIS_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+PYXIS_BW_IO)));
+
+       return result;
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+PYXIS_BW_IO)), "r" (b));
+}
+
+#define inb(port) __inb((port))
+#define inw(port) __inw((port))
+#define inl(port) __inl((port))
+
+#define outb(x, port) __outb((x),(port))
+#define outw(x, port) __outw((x),(port))
+#define outl(x, port) __outl((x),(port))
+
+#else /* BWIO_ENABLED */
+
 extern inline unsigned int __inb(unsigned long addr)
 {
        long result = *(vuip) ((addr << 5) + PYXIS_IO + 0x00);
@@ -257,6+358,14 @@ extern inline void __outl(unsigned int b, unsigned long addr)
        mb();
 }
 
+#define inb(port) \
+(__builtin_constant_p((port))?__inb(port):_inb(port))
+
+#define outb(x, port) \
+(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
+
+#endif /* BWIO_ENABLED */
+
 
 /*
  * Memory functions.  64-bit and 32-bit accesses are done through
@@ -290,25+399,197 @@ extern inline void __outl(unsigned int b, unsigned long addr)
  * 
  */
 
-extern inline void pyxis_set_hae(unsigned long new_hae)
+#ifdef BWIO_ENABLED
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+PYXIS_BW_MEM)));
+
+       return result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
 {
-        unsigned long ipl = swpipl(7);
-        hae.cache = new_hae;
-        *hae.reg = new_hae;
-        mb();
-       new_hae = *hae.reg; /* read it to be sure it got out */
-        setipl(ipl);
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+PYXIS_BW_MEM)));
+
+       return result;
 }
 
+extern inline unsigned long __readl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+PYXIS_BW_MEM)));
+
+       return result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+PYXIS_BW_MEM)), "r" (b));
+}
+
+#define readb(addr) __readb((addr))
+#define readw(addr) __readw((addr))
+
+#define writeb(b, addr) __writeb((b),(addr))
+#define writew(b, addr) __writew((b),(addr))
+
+#else /* BWIO_ENABLED */
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long pyxis_sm_base_r1, pyxis_sm_base_r2, pyxis_sm_base_r3;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x08);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x08);
+       else
+       {
+#if 0
+         printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= pyxis_sm_base_r1) &&
+           (addr <= (pyxis_sm_base_r1 + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + PYXIS_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r2) &&
+           (addr <= (pyxis_sm_base_r2 + MEM_R2_MASK)))
+         work = (((addr & MEM_R2_MASK) << 5) + PYXIS_SPARSE_MEM_R2 + 0x00);
+       else
+       if ((addr >= pyxis_sm_base_r3) &&
+           (addr <= (pyxis_sm_base_r3 + MEM_R3_MASK)))
+         work = (((addr & MEM_R3_MASK) << 5) + PYXIS_SPARSE_MEM_R3 + 0x00);
+       else
+       {
+#if 0
+         printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x00010001;
+}
+
+#else /* SRM_SETUP */
+
 extern inline unsigned long __readb(unsigned long addr)
 {
        unsigned long result, shift, msb, work, temp;
 
        shift = (addr & 0x3) << 3;
        msb = addr & 0xE0000000UL;
-       temp = addr & MEM_SP1_MASK ;
+       temp = addr & MEM_R1_MASK ;
        if (msb != hae.cache) {
-         pyxis_set_hae(msb);
+         set_hae(msb);
        }
        work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x00);
        result = *(vuip) work;
@@ -322,9+603,9 @@ extern inline unsigned long __readw(unsigned long addr)
 
        shift = (addr & 0x3) << 3;
        msb = addr & 0xE0000000UL;
-       temp = addr & MEM_SP1_MASK ;
+       temp = addr & MEM_R1_MASK ;
        if (msb != hae.cache) {
-         pyxis_set_hae(msb);
+         set_hae(msb);
        }
        work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x08);
        result = *(vuip) work;
@@ -332,19+613,14 @@ extern inline unsigned long __readw(unsigned long addr)
        return 0x0ffffUL & result;
 }
 
-extern inline unsigned long __readl(unsigned long addr)
-{
-       return *(vuip) (addr + PYXIS_DENSE_MEM);
-}
-
 extern inline void __writeb(unsigned char b, unsigned long addr)
 {
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
-         pyxis_set_hae(msb);
+         set_hae(msb);
        }
        *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x00) = b * 0x01010101;
 }
@@ -354,23+630,25 @@ extern inline void __writew(unsigned short b, unsigned long addr)
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
-         pyxis_set_hae(msb);
+         set_hae(msb);
        }
        *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x08) = b * 0x00010001;
 }
+#endif /* SRM_SETUP */
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+       return *(vuip) (addr + PYXIS_DENSE_MEM);
+}
 
 extern inline void __writel(unsigned int b, unsigned long addr)
 {
        *(vuip) (addr + PYXIS_DENSE_MEM) = b;
 }
 
-#define inb(port) \
-(__builtin_constant_p((port))?__inb(port):_inb(port))
-
-#define outb(x, port) \
-(__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
+#endif /* BWIO_ENABLED */
 
 #define readl(a)       __readl((unsigned long)(a))
 #define writel(v,a)    __writel((v),(unsigned long)(a))
index f7596af..811abc2 100644 (file)
@@ -3,6+3,51 @@
 
 #define cpu_logical_map(cpu)   (cpu)
 
-/* We'll get here eventually.. */
+#ifdef __SMP__
+
+#include <linux/tasks.h>
+
+struct cpuinfo_alpha {
+       unsigned long loops_per_sec;
+       unsigned int next;
+};
+
+extern struct cpuinfo_alpha cpu_data[NR_CPUS];
+
+typedef volatile struct {
+  unsigned int kernel_flag; /* 4 bytes, please */
+  unsigned int akp; /* 4 bytes, please */
+  unsigned long pc;
+  unsigned int cpu;
+} klock_info_t;
+
+extern klock_info_t klock_info;
+
+#define KLOCK_HELD     0xff
+#define KLOCK_CLEAR    0x00
+
+extern int task_lock_depth;
+
+#define PROC_CHANGE_PENALTY     20
+
+extern __volatile__ int cpu_number_map[NR_CPUS];
+
+/* HACK: Cabrio WHAMI return value is bogus if more than 8 bits used.. :-( */
+#define hard_smp_processor_id() \
+({ \
+       register unsigned char __r0 __asm__("$0"); \
+       __asm__ __volatile__( \
+               "call_pal %0" \
+               : /* no output (bound to the template) */ \
+               :"i" (PAL_whami) \
+               :"$0", "$1", "$22", "$23", "$24", "$25", "memory"); \
+       __r0; \
+})
+
+#define smp_processor_id() hard_smp_processor_id()
+
+#endif /* __SMP__ */
+
+#define NO_PROC_ID     (-1)
 
 #endif
index 5f5d692..bd04c6f 100644 (file)
 
 #else
 
-#error "We do not support SMP on alpha yet"
+#include <asm/system.h>
+#include <asm/current.h>
+#include <asm/bitops.h>
+#include <asm/hardirq.h>
+
+#define kernel_lock_held() \
+  (klock_info.kernel_flag && (klock_info.akp == smp_processor_id()))
+
+/* 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;             \
+               mb();                                   \
+       }                                               \
+       release_irqlock(cpu);                           \
+       __sti();                                        \
+} while (0)
+
+#if 1
+#define DEBUG_KERNEL_LOCK
+#else
+#undef DEBUG_KERNEL_LOCK
+#endif
+
+#ifdef DEBUG_KERNEL_LOCK
+extern void ___lock_kernel(klock_info_t *klip, int cpu, long ipl);
+#else /* DEBUG_KERNEL_LOCK */
+static inline void ___lock_kernel(klock_info_t *klip, int cpu, long ipl)
+{
+       long regx;
+
+       __asm__ __volatile__(
+       "1:     ldl_l   %1,%0;"
+       "       blbs    %1,6f;"
+       "       or      %1,1,%1;"
+       "       stl_c   %1,%0;"
+       "       beq     %1,6f;"
+       "4:     mb\n"
+       ".section .text2,\"ax\"\n"
+       "6:     mov %4,$16;"
+       "       call_pal %3;"
+       "7:     ldl %1,%0;"
+       "       blbs %1,7b;"
+       "       bis $31,7,$16;"
+       "       call_pal %3;"
+       "       br 1b\n"
+       ".previous"
+       : "=m,=m" (__dummy_lock(klip)), "=&r,=&r" (regx)
+       : "0,0" (__dummy_lock(klip)), "i,i" (PAL_swpipl), "i,r" (ipl)
+       : "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory"
+       );
+}
+#endif /* DEBUG_KERNEL_LOCK */
+
+#define reacquire_kernel_lock(task, cpu, depth)        \
+do {                                           \
+  if (depth) {                                 \
+    long ipl;                                  \
+    klock_info_t *klip = &klock_info;          \
+    __save_and_cli(ipl);                       \
+    ___lock_kernel(klip, cpu, ipl);            \
+    klip->akp = cpu;                           \
+    (task)->lock_depth = depth;                        \
+    __restore_flags(ipl);                      \
+  }                                            \
+} 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
+ * and can thus disappear.
+ */
+
+#define lock_kernel()                          \
+if (current->lock_depth > 0) {                 \
+     ++current->lock_depth;                    \
+} else {                                       \
+  long ipl;                                    \
+  int cpu = smp_processor_id();                        \
+  klock_info_t *klip = &klock_info;            \
+  __save_and_cli(ipl);                         \
+  ___lock_kernel(klip, cpu, ipl);              \
+  klip->akp = cpu;                             \
+  current->lock_depth = 1;                     \
+  __restore_flags(ipl);                                \
+}
+
+/* Release kernel global lock. */
+#define unlock_kernel()                                \
+if (current->lock_depth > 1) {                 \
+  --current->lock_depth;                       \
+} else {                                       \
+  long ipl;                                    \
+  __save_and_cli(ipl);                         \
+  klock_info.akp = NO_PROC_ID;                 \
+  klock_info.kernel_flag = KLOCK_CLEAR;                \
+  mb();                                                \
+  current->lock_depth = 0;                     \
+  __restore_flags(ipl);                                \
+}  
 
 #endif /* __SMP__ */
 
index 96be9ed..f49bad8 100644 (file)
@@ -1,10+1,9 @@
 #ifndef _ALPHA_SOFTIRQ_H
 #define _ALPHA_SOFTIRQ_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.
- */
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
 extern unsigned int local_bh_count[NR_CPUS];
 
 #define get_active_bhs()       (bh_mask & bh_active)
@@ -42,10+41,50 @@ extern inline void mark_bh(int nr)
        set_bit(nr, &bh_active);
 }
 
+#ifdef __SMP__
+
 /*
- * start_bh_atomic/end_bh_atomic also nest
- * naturally by using a counter
+ * 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 global_bh_lock;
+extern atomic_t global_bh_count;
+
+extern void synchronize_bh(void);
+
+static inline void start_bh_atomic(void)
+{
+       atomic_inc(&global_bh_lock);
+       synchronize_bh();
+}
+
+static inline void end_bh_atomic(void)
+{
+       atomic_dec(&global_bh_lock);
+}
+
+/* These are for the irq's testing the lock */
+static inline int softirq_trylock(int cpu)
+{
+       if (!test_and_set_bit(0,&global_bh_count)) {
+               if (atomic_read(&global_bh_lock) == 0) {
+                       ++local_bh_count[cpu];
+                       return 1;
+               }
+               clear_bit(0,&global_bh_count);
+       }
+       return 0;
+}
+
+static inline void softirq_endlock(int cpu)
+{
+       local_bh_count[cpu]--;
+       clear_bit(0,&global_bh_count);
+}
+
+#else
+
 extern inline void start_bh_atomic(void)
 {
        local_bh_count[smp_processor_id()]++;
@@ -58,19+97,16 @@ extern inline void end_bh_atomic(void)
        local_bh_count[smp_processor_id()]--;
 }
 
-#ifndef __SMP__
-
 /* These are for the irq's testing the lock */
 #define softirq_trylock(cpu) \
   (local_bh_count[cpu] ? 0 : (local_bh_count[cpu] = 1))
+
 #define softirq_endlock(cpu) \
   (local_bh_count[cpu] = 0)
 
-#else
-
-#error FIXME
+#define synchronize_bh()       do { } while (0)
 
-#endif /* __SMP__ */
+#endif /* SMP */
 
 /*
  * These use a mask count to correctly handle
index a384774..1c7afd4 100644 (file)
@@ -45,7+45,10 @@ typedef struct { int dummy; } rwlock_t;
 #define write_lock_irqsave(lock, flags)                do { (flags) = swpipl(7); } while (0)
 #define write_unlock_irqrestore(lock, flags)   setipl(flags)
 
-#else
+#else /* __SMP__ */
+
+#include <linux/kernel.h>
+#include <asm/current.h>
 
 /* Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
@@ -56,12+59,15 @@ typedef struct { int dummy; } rwlock_t;
 typedef struct {
        volatile unsigned long lock;
        unsigned long previous;
+       unsigned long task;
 } spinlock_t;
 
 #define SPIN_LOCK_UNLOCKED { 0, 0 }
 
-#define spin_lock_init(lock)   do { (lock)->lock = 0; (lock)->previous = 0; } while(0)
-#define spin_unlock_wait(lock) do { barrier(); } while(((volatile spinlock_t *)lock)->lock)
+#define spin_lock_init(x) \
+       do { (x)->lock = 0; (x)->previous = 0; } while(0)
+#define spin_unlock_wait(x) \
+       do { barrier(); } while(((volatile spinlock_t *)x)->lock)
 
 typedef struct { unsigned long a[100]; } __dummy_lock_t;
 #define __dummy_lock(lock) (*(__dummy_lock_t *)(lock))
@@ -73,40+79,38 @@ static inline void spin_unlock(spinlock_t * lock)
        :"=m" (__dummy_lock(lock)));
 }
 
+#if 1
+#define DEBUG_SPINLOCK
+#else
+#undef DEBUG_SPINLOCK
+#endif
+
+#ifdef DEBUG_SPINLOCK
+extern void spin_lock(spinlock_t * lock);
+#else
 static inline void spin_lock(spinlock_t * lock)
 {
-       __label__ l1;
        long tmp;
-       long stuck = 0x100000000;
-l1:
+
        /* Use sub-sections to put the actual loop at the end
           of this object file's text section so as to perfect
           branch prediction.  */
        __asm__ __volatile__(
        "1:     ldq_l   %0,%1\n"
-       "       subq    %2,1,%2\n"
        "       blbs    %0,2f\n"
        "       or      %0,1,%0\n"
        "       stq_c   %0,%1\n"
-       "       beq     %0,3f\n"
+       "       beq     %0,2f\n"
        "4:     mb\n"
        ".section .text2,\"ax\"\n"
        "2:     ldq     %0,%1\n"
-       "       subq    %2,1,%2\n"
-       "3:     blt     %2,4b\n"
        "       blbs    %0,2b\n"
        "       br      1b\n"
        ".previous"
        : "=r" (tmp),
-         "=m" (__dummy_lock(lock)),
-         "=r" (stuck)
-       : "2" (stuck));
-
-       if (stuck < 0)
-               printk("spinlock stuck at %p (%lx)\n",&&l1,lock->previous);
-       else
-               lock->previous = (unsigned long) &&l1;
+         "=m" (__dummy_lock(lock)));
 }
+#endif /* DEBUG_SPINLOCK */
 
 #define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
@@ -117,10+121,124 @@ l1:
        do { spin_unlock(lock); __sti(); } while (0)
 
 #define spin_lock_irqsave(lock, flags) \
-       do { flags = swpipl(7); spin_lock(lock); } while (0)
+       do { __save_and_cli(flags); spin_lock(lock); } while (0)
 
 #define spin_unlock_irqrestore(lock, flags) \
-       do { spin_unlock(lock); setipl(flags); } while (0)
+       do { spin_unlock(lock); __restore_flags(flags); } while (0)
+
+/***********************************************************/
+
+#if 1
+#define DEBUG_RWLOCK
+#else
+#undef DEBUG_RWLOCK
+#endif
+
+typedef struct { volatile int write_lock:1, read_counter:31; } rwlock_t;
+
+#define RW_LOCK_UNLOCKED { 0, 0 }
+
+#ifdef DEBUG_RWLOCK
+extern void write_lock(rwlock_t * lock);
+#else
+static inline void write_lock(rwlock_t * lock)
+{
+       long regx, regy;
+
+       __asm__ __volatile__(
+       "1:     ldl_l   %1,%0;"
+       "       blbs    %1,6f;"
+       "       or      %1,1,%2;"
+       "       stl_c   %2,%0;"
+       "       beq     %2,6f;"
+       "       blt     %1,8f;"
+       "4:     mb\n"
+       ".section .text2,\"ax\"\n"
+       "6:     ldl     %1,%0;"
+       "       blbs    %1,6b;"
+       "       br      1b;"
+       "8:     ldl     %1,%0;"
+       "       blt     %1,8b;"
+       "9:     br      4b\n"
+       ".previous"
+       : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy)
+       : "0" (__dummy_lock(lock))
+       );
+}
+#endif /* DEBUG_RWLOCK */
+
+static inline void write_unlock(rwlock_t * lock)
+{
+       __asm__ __volatile__("mb; stl $31,%0" : "=m" (__dummy_lock(lock)));
+}
+
+#ifdef DEBUG_RWLOCK
+extern void _read_lock(rwlock_t * lock);
+#else
+static inline void _read_lock(rwlock_t * lock)
+{
+       long regx;
+
+       __asm__ __volatile__(
+       "1:     ldl_l   %1,%0;"
+       "       blbs    %1,6f;"
+       "       subl    %1,2,%1;"
+       "       stl_c   %1,%0;"
+       "       beq     %1,6f;"
+       "4:     mb\n"
+       ".section .text2,\"ax\"\n"
+       "6:     ldl     %1,%0;"
+       "       blbs    %1,6b;"
+       "       br      1b\n"
+       ".previous"
+       : "=m" (__dummy_lock(lock)), "=&r" (regx)
+       : "0" (__dummy_lock(lock))
+       );
+}
+#endif /* DEBUG_RWLOCK */
+
+#define read_lock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _read_lock(lock); \
+       __restore_flags(flags); \
+} while(0)
+
+static inline void _read_unlock(rwlock_t * lock)
+{
+       long regx;
+       __asm__ __volatile__(
+       "1:     ldl_l   %1,%0;"
+       "       addl    %1,2,%1;"
+       "       stl_c   %1,%0;"
+       "       beq     %1,6f;"
+       ".section .text2,\"ax\"\n"
+       "6:     br      1b\n"
+       ".previous"
+       : "=m" (__dummy_lock(lock)), "=&r" (regx)
+       : "0" (__dummy_lock(lock)));
+}
+
+#define read_unlock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _read_unlock(lock); \
+       __restore_flags(flags); \
+} while(0)
+
+#define read_lock_irq(lock)    do { __cli(); _read_lock(lock); } while (0)
+#define read_unlock_irq(lock)  do { _read_unlock(lock); __sti(); } while (0)
+#define write_lock_irq(lock)   do { __cli(); write_lock(lock); } while (0)
+#define write_unlock_irq(lock) do { write_unlock(lock); __sti(); } while (0)
+
+#define read_lock_irqsave(lock, flags) \
+       do { __save_and_cli(flags); _read_lock(lock); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+       do { _read_unlock(lock); __restore_flags(flags); } while (0)
+#define write_lock_irqsave(lock, flags)        \
+       do { __save_and_cli(flags); write_lock(lock); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+       do { write_unlock(lock); __restore_flags(flags); } while (0)
 
 #endif /* SMP */
 #endif /* _ALPHA_SPINLOCK_H */
index 1a1fb24..72b9131 100644 (file)
  */
 struct el_common {
        unsigned int    size;           /* size in bytes of logout area */
-       int             sbz1    : 31;   /* should be zero */
-       char            retry   :  1;   /* retry flag */
+       int             sbz1    : 30;   /* should be zero */
+       int             err2    :  1;   /* second error */
+       int             retry   :  1;   /* retry flag */
        unsigned int    proc_offset;    /* processor-specific offset */
        unsigned int    sys_offset;     /* system-specific offset */
        unsigned long   code;           /* machine check code */
 };
 
+/* Machine Check Frame for uncorrectable errors (Large format)
+ *      --- This is used to log uncorrectable errors such as
+ *          double bit ECC errors.
+ *      --- These errors are detected by both processor and systems.
+ */
+struct el_common_EV5_uncorrectable_mcheck {
+        unsigned long   shadow[8];        /* Shadow reg. 8-14, 25           */
+        unsigned long   paltemp[24];      /* PAL TEMP REGS.                 */
+        unsigned long   exc_addr;         /* Address of excepting instruction*/
+        unsigned long   exc_sum;          /* Summary of arithmetic traps.   */
+        unsigned long   exc_mask;         /* Exception mask (from exc_sum). */
+        unsigned long   pal_base;         /* Base address for PALcode.      */
+        unsigned long   isr;              /* Interrupt Status Reg.          */
+        unsigned long   icsr;             /* CURRENT SETUP OF EV5 IBOX      */
+        unsigned long   ic_perr_stat;     /* I-CACHE Reg. <11> set Data parity
+                                                         <12> set TAG parity*/
+        unsigned long   dc_perr_stat;     /* D-CACHE error Reg. Bits set to 1:
+                                                     <2> Data error in bank 0
+                                                     <3> Data error in bank 1
+                                                     <4> Tag error in bank 0
+                                                     <5> Tag error in bank 1 */
+        unsigned long   va;               /* Effective VA of fault or miss. */
+        unsigned long   mm_stat;          /* Holds the reason for D-stream 
+                                             fault or D-cache parity errors */
+        unsigned long   sc_addr;          /* Address that was being accessed
+                                             when EV5 detected Secondary cache
+                                             failure.                 */
+        unsigned long   sc_stat;          /* Helps determine if the error was
+                                             TAG/Data parity(Secondary Cache)*/
+        unsigned long   bc_tag_addr;      /* Contents of EV5 BC_TAG_ADDR    */
+        unsigned long   ei_addr;          /* Physical address of any transfer
+                                             that is logged in EV5 EI_STAT */
+        unsigned long   fill_syndrome;    /* For correcting ECC errors.     */
+        unsigned long   ei_stat;          /* Helps identify reason of any 
+                                             processor uncorrectable error
+                                             at its external interface.     */
+        unsigned long   ld_lock;          /* Contents of EV5 LD_LOCK register*/
+};
+
+
 extern void wrent(void *, unsigned long);
 extern void wrkgp(unsigned long);
 extern void wrusp(unsigned long);
@@ -96,6+137,7 @@ __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_draina) : "memory")
        r0; \
 })
 
+#ifdef THE_OLD_VERSION
 #define setipl(ipl) \
 do { \
        register unsigned long __r16 __asm__("$16") = (ipl); \
@@ -117,6+159,27 @@ do { \
                :"$1", "$22", "$23", "$24", "$25", "memory"); \
        __r0; \
 })
+#else
+#define setipl(ipl) \
+do { \
+       __asm__ __volatile__( \
+               "mov %0,$16; call_pal %1" \
+               : /* no output */ \
+               :"i,r" (ipl), "i,i" (PAL_swpipl) \
+               :"$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
+} while (0)
+
+#define swpipl(ipl) \
+({ \
+       register unsigned long __r0 __asm__("$0"); \
+       __asm__ __volatile__( \
+               "mov %0,$16; call_pal %1" \
+               : /* no output (bound to the template) */ \
+               : "i,r" (ipl), "i,i" (PAL_swpipl) \
+               : "$0", "$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
+       __r0; \
+})
+#endif
 
 #define __cli()                        setipl(7)
 #define __sti()                        setipl(0)
@@ -124,12+187,37 @@ do { \
 #define __save_and_cli(flags)  do { (flags) = swpipl(7); } while (0)
 #define __restore_flags(flags) setipl(flags)
 
+#ifdef __SMP__
+
+extern unsigned char global_irq_holder;
+
+#define save_flags(x) \
+do { \
+       (x) = ((global_irq_holder == (unsigned char) smp_processor_id()) \
+               ? 1 \
+               : ((getipl() & 7) ? 2 : 0)); \
+} while (0)
+
+#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
+
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern void __global_restore_flags(unsigned long flags);
+
+#define cli()                   __global_cli()
+#define sti()                   __global_sti()
+#define restore_flags(flags)    __global_restore_flags(flags)
+
+#else /* __SMP__ */
+
 #define cli()                  setipl(7)
 #define sti()                  setipl(0)
 #define save_flags(flags)      do { (flags) = getipl(); } while (0)
 #define save_and_cli(flags)    do { (flags) = swpipl(7); } while (0)
 #define restore_flags(flags)   setipl(flags)
 
+#endif /* __SMP__ */
+
 /*
  * TB routines..
  */
index 1f4f8c7..524d6f7 100644 (file)
@@ -1,6+1,7 @@
 #ifndef __ALPHA_T2__H__
 #define __ALPHA_T2__H__
 
+#include <linux/config.h>
 #include <linux/types.h>
 
 /*
 
 #define BYTE_ENABLE_SHIFT 5
 #define TRANSFER_LENGTH_SHIFT 3
-#define MEM_SP1_MASK 0x1fffffff  /* Mem sparse space 1 mask is 29 bits */
+#define MEM_R1_MASK 0x03ffffff  /* Mem sparse space region 1 mask is 26 bits */
 
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define T2_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define T2_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
 
-#define T2_DMA_WIN_BASE        (1024UL*1024UL*1024UL)
+extern unsigned int T2_DMA_WIN_BASE;
+extern unsigned int T2_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define T2_DMA_WIN_BASE        (1024*1024*1024)
 #define T2_DMA_WIN_SIZE        (1024*1024*1024)
+#endif /* SRM_SETUP */
+
+/* GAMMA-SABLE is a SABLE with EV5-based CPUs */
+#ifdef CONFIG_ALPHA_GAMMA
+#  define GAMMA_BIAS           0x8000000000UL
+#else /* GAMMA */
+#  define GAMMA_BIAS           0x0000000000UL
+#endif /* GAMMA */
 
 /*
  * Memory spaces:
  */
-#define T2_CONF                                (IDENT_ADDR + 0x390000000UL)
-#define T2_IO                          (IDENT_ADDR + 0x3a0000000UL)
-#define T2_SPARSE_MEM                  (IDENT_ADDR + 0x200000000UL)
-#define T2_DENSE_MEM                   (IDENT_ADDR + 0x3c0000000UL)
-
-#define T2_IOCSR                       (IDENT_ADDR + 0x38e000000UL)
-#define T2_CERR1                       (IDENT_ADDR + 0x38e000020UL)
-#define T2_CERR2                       (IDENT_ADDR + 0x38e000040UL)
-#define T2_CERR3                       (IDENT_ADDR + 0x38e000060UL)
-#define T2_PERR1                       (IDENT_ADDR + 0x38e000080UL)
-#define T2_PERR2                       (IDENT_ADDR + 0x38e0000a0UL)
-#define T2_PSCR                                (IDENT_ADDR + 0x38e0000c0UL)
-#define T2_HAE_1                       (IDENT_ADDR + 0x38e0000e0UL)
-#define T2_HAE_2                       (IDENT_ADDR + 0x38e000100UL)
-#define T2_HBASE                       (IDENT_ADDR + 0x38e000120UL)
-#define T2_WBASE1                      (IDENT_ADDR + 0x38e000140UL)
-#define T2_WMASK1                      (IDENT_ADDR + 0x38e000160UL)
-#define T2_TBASE1                      (IDENT_ADDR + 0x38e000180UL)
-#define T2_WBASE2                      (IDENT_ADDR + 0x38e0001a0UL)
-#define T2_WMASK2                      (IDENT_ADDR + 0x38e0001c0UL)
-#define T2_TBASE2                      (IDENT_ADDR + 0x38e0001e0UL)
-#define T2_TLBBR                       (IDENT_ADDR + 0x38e000200UL)
-
-#define T2_HAE_3                       (IDENT_ADDR + 0x38e000240UL)
-#define T2_HAE_4                       (IDENT_ADDR + 0x38e000260UL)
+#define T2_CONF                        (IDENT_ADDR + GAMMA_BIAS + 0x390000000UL)
+#define T2_IO                  (IDENT_ADDR + GAMMA_BIAS + 0x3a0000000UL)
+#define T2_SPARSE_MEM          (IDENT_ADDR + GAMMA_BIAS + 0x200000000UL)
+#define T2_DENSE_MEM           (IDENT_ADDR + GAMMA_BIAS + 0x3c0000000UL)
+
+#define T2_IOCSR               (IDENT_ADDR + GAMMA_BIAS + 0x38e000000UL)
+#define T2_CERR1               (IDENT_ADDR + GAMMA_BIAS + 0x38e000020UL)
+#define T2_CERR2               (IDENT_ADDR + GAMMA_BIAS + 0x38e000040UL)
+#define T2_CERR3               (IDENT_ADDR + GAMMA_BIAS + 0x38e000060UL)
+#define T2_PERR1               (IDENT_ADDR + GAMMA_BIAS + 0x38e000080UL)
+#define T2_PERR2               (IDENT_ADDR + GAMMA_BIAS + 0x38e0000a0UL)
+#define T2_PSCR                        (IDENT_ADDR + GAMMA_BIAS + 0x38e0000c0UL)
+#define T2_HAE_1               (IDENT_ADDR + GAMMA_BIAS + 0x38e0000e0UL)
+#define T2_HAE_2               (IDENT_ADDR + GAMMA_BIAS + 0x38e000100UL)
+#define T2_HBASE               (IDENT_ADDR + GAMMA_BIAS + 0x38e000120UL)
+#define T2_WBASE1              (IDENT_ADDR + GAMMA_BIAS + 0x38e000140UL)
+#define T2_WMASK1              (IDENT_ADDR + GAMMA_BIAS + 0x38e000160UL)
+#define T2_TBASE1              (IDENT_ADDR + GAMMA_BIAS + 0x38e000180UL)
+#define T2_WBASE2              (IDENT_ADDR + GAMMA_BIAS + 0x38e0001a0UL)
+#define T2_WMASK2              (IDENT_ADDR + GAMMA_BIAS + 0x38e0001c0UL)
+#define T2_TBASE2              (IDENT_ADDR + GAMMA_BIAS + 0x38e0001e0UL)
+#define T2_TLBBR               (IDENT_ADDR + GAMMA_BIAS + 0x38e000200UL)
+
+#define T2_HAE_3               (IDENT_ADDR + GAMMA_BIAS + 0x38e000240UL)
+#define T2_HAE_4               (IDENT_ADDR + GAMMA_BIAS + 0x38e000260UL)
 
 #define HAE_ADDRESS                    T2_HAE_1
 
  *                                              
  *
  */
-#define CPU0_BASE               (IDENT_ADDR + 0x380000000L)
-#define CPU1_BASE               (IDENT_ADDR + 0x381000000L)
-#define CPU2_BASE               (IDENT_ADDR + 0x382000000L)
-#define CPU3_BASE               (IDENT_ADDR + 0x383000000L)
-#define MEM0_BASE               (IDENT_ADDR + 0x388000000L)
-#define MEM1_BASE               (IDENT_ADDR + 0x389000000L)
-#define MEM2_BASE               (IDENT_ADDR + 0x38a000000L)
-#define MEM3_BASE               (IDENT_ADDR + 0x38b000000L)
+#define CPU0_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x380000000L)
+#define CPU1_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x381000000L)
+#define CPU2_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x382000000L)
+#define CPU3_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x383000000L)
+#define MEM0_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x388000000L)
+#define MEM1_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x389000000L)
+#define MEM2_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x38a000000L)
+#define MEM3_BASE               (IDENT_ADDR + GAMMA_BIAS + 0x38b000000L)
 
 #ifdef __KERNEL__
 
@@ -198,6+215,133 @@ extern inline void __outl(unsigned int b, unsigned long addr)
  * HHH = 31:29 HAE_MEM CSR
  * 
  */
+#ifdef CONFIG_ALPHA_SRM_SETUP
+
+extern unsigned long t2_sm_base;
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       {
+#if 0
+         printk("__readb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffUL & result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       unsigned long result, shift, work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       {
+#if 0
+         printk("__readw: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffffUL;
+       }
+       shift = (addr & 0x3) << 3;
+       result = *(vuip) work;
+       result >>= shift;
+       return 0x0ffffUL & result;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline unsigned long __readl(unsigned long addr)
+{
+       unsigned long result, work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       else
+       {
+#if 0
+         printk("__readl: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return 0x0ffffffffUL;
+       }
+       result = *(vuip) work;
+       return 0xffffffffUL & result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x00);
+       else
+       {
+#if 0
+         printk("__writeb: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x01010101;
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x08);
+       else
+       {
+#if 0
+         printk("__writew: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b * 0x00010001;
+}
+
+/* on SABLE with T2, we must use SPARSE memory even for 32-bit access */
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+       unsigned long work;
+
+       if ((addr >= t2_sm_base) && (addr <= (t2_sm_base + MEM_R1_MASK)))
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       else
+       if ((addr >= 512*1024) && (addr < 1024*1024)) /* check HOLE */
+         work = (((addr & MEM_R1_MASK) << 5) + T2_SPARSE_MEM + 0x18);
+       {
+#if 0
+         printk("__writel: address 0x%lx not covered by HAE\n", addr);
+#endif
+         return;
+       }
+       *(vuip) work = b;
+}
+
+#else /* SRM_SETUP */
 
 extern inline unsigned long __readb(unsigned long addr)
 {
@@ -205,7+349,7 @@ extern inline unsigned long __readb(unsigned long addr)
 
        shift = (addr & 0x3) * 8 ;
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -220,7+364,7 @@ extern inline unsigned long __readw(unsigned long addr)
 
        shift = (addr & 0x3) * 8;
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -235,7+379,7 @@ extern inline unsigned long __readl(unsigned long addr)
        unsigned long result, msb;
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -248,7+392,7 @@ extern inline void __writeb(unsigned char b, unsigned long addr)
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -260,7+404,7 @@ extern inline void __writew(unsigned short b, unsigned long addr)
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
@@ -273,13+417,15 @@ extern inline void __writel(unsigned int b, unsigned long addr)
         unsigned long msb ; 
 
        msb = addr & 0xE0000000 ;
-       addr &= MEM_SP1_MASK ;
+       addr &= MEM_R1_MASK ;
        if (msb != hae.cache) {
          set_hae(msb);
        }
        *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
 }
 
+#endif /* SRM_SETUP */
+
 #define inb(port) \
 (__builtin_constant_p((port))?__inb(port):_inb(port))
 
diff --git a/include/asm-alpha/tsunami.h b/include/asm-alpha/tsunami.h
new file mode 100644 (file)
index 0000000..2c6be4e
--- /dev/null
@@ -0,0 +1,483 @@
+#ifndef __ALPHA_TSUNAMI__H__
+#define __ALPHA_TSUNAMI__H__
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/*
+ * TSUNAMI/TYPHOON are the internal names for the core logic chipset which
+ * provides memory controller and PCI access for the 21264 based systems.
+ *
+ * This file is based on:
+ *
+ * Tsunami System Programmers Manual
+ * Preliminary, Chapters 2-5
+ *
+ */
+
+#define BYTE_ENABLE_SHIFT 5
+#define TRANSFER_LENGTH_SHIFT 3
+
+#ifdef CONFIG_ALPHA_SRM_SETUP
+/* if we are using the SRM PCI setup, we'll need to use variables instead */
+#define TSUNAMI_DMA_WIN_BASE_DEFAULT    (1024*1024*1024)
+#define TSUNAMI_DMA_WIN_SIZE_DEFAULT    (1024*1024*1024)
+
+extern unsigned int TSUNAMI_DMA_WIN_BASE;
+extern unsigned int TSUNAMI_DMA_WIN_SIZE;
+
+#else /* SRM_SETUP */
+#define TSUNAMI_DMA_WIN_BASE   (1024*1024*1024)
+#define TSUNAMI_DMA_WIN_SIZE   (1024*1024*1024)
+#endif /* SRM_SETUP */
+
+#ifdef USE_48_BIT_KSEG
+#define TS_BIAS 0x80000000000UL
+#else
+#define TS_BIAS 0x10000000000UL
+#endif
+
+/*
+ * CChip and DChip registers
+ */
+#define        TSUNAMI_CSR_CSC         (IDENT_ADDR + TS_BIAS + 0x1A0000000UL)
+#define        TSUNAMI_CSR_MTR         (IDENT_ADDR + TS_BIAS + 0x1A0000040UL)
+#define        TSUNAMI_CSR_MISC        (IDENT_ADDR + TS_BIAS + 0x1A0000080UL)
+#define        TSUNAMI_CSR_MPD         (IDENT_ADDR + TS_BIAS + 0x1A00000C0UL)
+#define        TSUNAMI_CSR_AAR0        (IDENT_ADDR + TS_BIAS + 0x1A0000100UL)
+#define        TSUNAMI_CSR_AAR1        (IDENT_ADDR + TS_BIAS + 0x1A0000140UL)
+#define        TSUNAMI_CSR_AAR2        (IDENT_ADDR + TS_BIAS + 0x1A0000180UL)
+#define        TSUNAMI_CSR_AAR3        (IDENT_ADDR + TS_BIAS + 0x1A00001C0UL)
+#define        TSUNAMI_CSR_DIM0        (IDENT_ADDR + TS_BIAS + 0x1A0000200UL)
+#define        TSUNAMI_CSR_DIM1        (IDENT_ADDR + TS_BIAS + 0x1A0000240UL)
+#define        TSUNAMI_CSR_DIR0        (IDENT_ADDR + TS_BIAS + 0x1A0000280UL)
+#define        TSUNAMI_CSR_DIR1        (IDENT_ADDR + TS_BIAS + 0x1A00002C0UL)
+
+#define        TSUNAMI_CSR_DRIR        (IDENT_ADDR + TS_BIAS + 0x1A0000300UL)
+#define        TSUNAMI_CSR_PRBEN       (IDENT_ADDR + TS_BIAS + 0x1A0000340UL)
+#define        TSUNAMI_CSR_IIC         (IDENT_ADDR + TS_BIAS + 0x1A0000380UL)
+#define        TSUNAMI_CSR_WDR         (IDENT_ADDR + TS_BIAS + 0x1A00003C0UL)
+#define        TSUNAMI_CSR_MPR0        (IDENT_ADDR + TS_BIAS + 0x1A0000400UL)
+#define        TSUNAMI_CSR_MPR1        (IDENT_ADDR + TS_BIAS + 0x1A0000440UL)
+#define        TSUNAMI_CSR_MPR2        (IDENT_ADDR + TS_BIAS + 0x1A0000480UL)
+#define        TSUNAMI_CSR_MPR3        (IDENT_ADDR + TS_BIAS + 0x1A00004C0UL)
+#define        TSUNAMI_CSR_TTR         (IDENT_ADDR + TS_BIAS + 0x1A0000580UL)
+#define        TSUNAMI_CSR_TDR         (IDENT_ADDR + TS_BIAS + 0x1A00005C0UL)
+#define        TSUNAMI_CSR_DSC         (IDENT_ADDR + TS_BIAS + 0x1B0000800UL)
+#define        TSUNAMI_CSR_STR         (IDENT_ADDR + TS_BIAS + 0x1B0000840UL)
+#define        TSUNAMI_CSR_DREV        (IDENT_ADDR + TS_BIAS + 0x1B0000880UL)
+
+/*
+ * PChip registers
+ */
+#define        TSUNAMI_PCHIP0_WSBA0    (IDENT_ADDR + TS_BIAS + 0x180000000UL)
+#define        TSUNAMI_PCHIP0_WSBA1    (IDENT_ADDR + TS_BIAS + 0x180000040UL)
+#define        TSUNAMI_PCHIP0_WSBA2    (IDENT_ADDR + TS_BIAS + 0x180000080UL)
+#define        TSUNAMI_PCHIP0_WSBA3    (IDENT_ADDR + TS_BIAS + 0x1800000C0UL)
+
+#define        TSUNAMI_PCHIP0_WSM0     (IDENT_ADDR + TS_BIAS + 0x180000100UL)
+#define        TSUNAMI_PCHIP0_WSM1     (IDENT_ADDR + TS_BIAS + 0x180000140UL)
+#define        TSUNAMI_PCHIP0_WSM2     (IDENT_ADDR + TS_BIAS + 0x180000180UL)
+#define        TSUNAMI_PCHIP0_WSM3     (IDENT_ADDR + TS_BIAS + 0x1800001C0UL)
+#define        TSUNAMI_PCHIP0_TBA0     (IDENT_ADDR + TS_BIAS + 0x180000200UL)
+#define        TSUNAMI_PCHIP0_TBA1     (IDENT_ADDR + TS_BIAS + 0x180000240UL)
+#define        TSUNAMI_PCHIP0_TBA2     (IDENT_ADDR + TS_BIAS + 0x180000280UL)
+#define        TSUNAMI_PCHIP0_TBA3     (IDENT_ADDR + TS_BIAS + 0x1800002C0UL)
+
+#define        TSUNAMI_PCHIP0_PCTL     (IDENT_ADDR + TS_BIAS + 0x180000300UL)
+#define        TSUNAMI_PCHIP0_PLAT     (IDENT_ADDR + TS_BIAS + 0x180000340UL)
+#define        TSUNAMI_PCHIP0_RESERVED (IDENT_ADDR + TS_BIAS + 0x180000380UL)
+#define        TSUNAMI_PCHIP0_PERROR   (IDENT_ADDR + TS_BIAS + 0x1800003c0UL)
+#define        TSUNAMI_PCHIP0_PERRMASK (IDENT_ADDR + TS_BIAS + 0x180000400UL)
+#define        TSUNAMI_PCHIP0_PERRSET  (IDENT_ADDR + TS_BIAS + 0x180000440UL)
+#define        TSUNAMI_PCHIP0_TLBIV    (IDENT_ADDR + TS_BIAS + 0x180000480UL)
+#define        TSUNAMI_PCHIP0_TLBIA    (IDENT_ADDR + TS_BIAS + 0x1800004C0UL)
+#define        TSUNAMI_PCHIP0_PMONCTL  (IDENT_ADDR + TS_BIAS + 0x180000500UL)
+#define        TSUNAMI_PCHIP0_PMONCNT  (IDENT_ADDR + TS_BIAS + 0x180000540UL)
+
+#define        TSUNAMI_PCHIP1_WSBA0    (IDENT_ADDR + TS_BIAS + 0x380000000UL)
+#define        TSUNAMI_PCHIP1_WSBA1    (IDENT_ADDR + TS_BIAS + 0x380000040UL)
+#define        TSUNAMI_PCHIP1_WSBA2    (IDENT_ADDR + TS_BIAS + 0x380000080UL)
+#define        TSUNAMI_PCHIP1_WSBA3    (IDENT_ADDR + TS_BIAS + 0x3800000C0UL)
+#define        TSUNAMI_PCHIP1_WSM0     (IDENT_ADDR + TS_BIAS + 0x380000100UL)
+#define        TSUNAMI_PCHIP1_WSM1     (IDENT_ADDR + TS_BIAS + 0x380000140UL)
+#define        TSUNAMI_PCHIP1_WSM2     (IDENT_ADDR + TS_BIAS + 0x380000180UL)
+#define        TSUNAMI_PCHIP1_WSM3     (IDENT_ADDR + TS_BIAS + 0x3800001C0UL)
+
+#define        TSUNAMI_PCHIP1_TBA0     (IDENT_ADDR + TS_BIAS + 0x380000200UL)
+#define        TSUNAMI_PCHIP1_TBA1     (IDENT_ADDR + TS_BIAS + 0x380000240UL)
+#define        TSUNAMI_PCHIP1_TBA2     (IDENT_ADDR + TS_BIAS + 0x380000280UL)
+#define        TSUNAMI_PCHIP1_TBA3     (IDENT_ADDR + TS_BIAS + 0x3800002C0UL)
+
+#define        TSUNAMI_PCHIP1_PCTL     (IDENT_ADDR + TS_BIAS + 0x380000300UL)
+#define        TSUNAMI_PCHIP1_PLAT     (IDENT_ADDR + TS_BIAS + 0x380000340UL)
+#define        TSUNAMI_PCHIP1_RESERVED (IDENT_ADDR + TS_BIAS + 0x380000380UL)
+#define        TSUNAMI_PCHIP1_PERROR   (IDENT_ADDR + TS_BIAS + 0x3800003c0UL)
+#define        TSUNAMI_PCHIP1_PERRMASK (IDENT_ADDR + TS_BIAS + 0x380000400UL)
+#define        TSUNAMI_PCHIP1_PERRSET  (IDENT_ADDR + TS_BIAS + 0x380000440UL)
+#define        TSUNAMI_PCHIP1_TLBIV    (IDENT_ADDR + TS_BIAS + 0x380000480UL)
+#define        TSUNAMI_PCHIP1_TLBIA    (IDENT_ADDR + TS_BIAS + 0x3800004C0UL)
+#define        TSUNAMI_PCHIP1_PMONCTL  (IDENT_ADDR + TS_BIAS + 0x380000500UL)
+#define        TSUNAMI_PCHIP1_PMONCNT  (IDENT_ADDR + TS_BIAS + 0x380000540UL)
+
+/*                                                                          */
+/* TSUNAMI Pchip Error register.                                            */
+/*                                                                          */
+#define perror_m_lost 0x1
+#define perror_m_serr 0x2
+#define perror_m_perr 0x4
+#define perror_m_dcrto 0x8
+#define perror_m_sge 0x10
+#define perror_m_ape 0x20
+#define perror_m_ta 0x40
+#define perror_m_rdpe 0x80
+#define perror_m_nds 0x100
+#define perror_m_rto 0x200
+#define perror_m_uecc 0x400
+#define perror_m_cre 0x800
+#define perror_m_addrl 0xFFFFFFFF0000UL
+#define perror_m_addrh 0x7000000000000UL
+#define perror_m_cmd 0xF0000000000000UL
+#define perror_m_syn 0xFF00000000000000UL
+union TPchipPERROR {   
+    struct  {
+        unsigned int perror_v_lost : 1;
+        unsigned perror_v_serr : 1;
+        unsigned perror_v_perr : 1;
+        unsigned perror_v_dcrto : 1;
+        unsigned perror_v_sge : 1;
+        unsigned perror_v_ape : 1;
+        unsigned perror_v_ta : 1;
+        unsigned perror_v_rdpe : 1;
+        unsigned perror_v_nds : 1;
+        unsigned perror_v_rto : 1;
+        unsigned perror_v_uecc : 1;
+        unsigned perror_v_cre : 1;                 
+        unsigned perror_v_rsvd1 : 4;
+        unsigned perror_v_addrl : 32;
+        unsigned perror_v_addrh : 3;
+        unsigned perror_v_rsvd2 : 1;
+        unsigned perror_v_cmd : 4;
+        unsigned perror_v_syn : 8;
+        } perror_r_bits;
+    int perror_q_whole [2];
+    } ;                       
+/*                                                                          */
+/* TSUNAMI Pchip Window Space Base Address register.                        */
+/*                                                                          */
+#define wsba_m_ena 0x1                
+#define wsba_m_sg 0x2
+#define wsba_m_ptp 0x4
+#define wsba_m_addr 0xFFF00000  
+#define wmask_k_sz1gb 0x3FF00000                   
+union TPchipWSBA {
+    struct  {
+        unsigned wsba_v_ena : 1;
+        unsigned wsba_v_sg : 1;
+        unsigned wsba_v_ptp : 1;
+        unsigned wsba_v_rsvd1 : 17;
+        unsigned wsba_v_addr : 12;
+        unsigned wsba_v_rsvd2 : 32;
+        } wsba_r_bits;
+    int wsba_q_whole [2];
+    } ;
+/*                                                                         */
+/* TSUNAMI Pchip Control Register                                          */
+/*                                                                         */
+#define pctl_m_fdsc 0x1
+#define pctl_m_fbtb 0x2
+#define pctl_m_thdis 0x4
+#define pctl_m_chaindis 0x8
+#define pctl_m_tgtlat 0x10
+#define pctl_m_hole 0x20
+#define pctl_m_mwin 0x40
+#define pctl_m_arbena 0x80
+#define pctl_m_prigrp 0x7F00
+#define pctl_m_ppri 0x8000
+#define pctl_m_rsvd1 0x30000
+#define pctl_m_eccen 0x40000
+#define pctl_m_padm 0x80000
+#define pctl_m_cdqmax 0xF00000
+#define pctl_m_rev 0xFF000000
+#define pctl_m_crqmax 0xF00000000UL
+#define pctl_m_ptpmax 0xF000000000UL
+#define pctl_m_pclkx 0x30000000000UL
+#define pctl_m_fdsdis 0x40000000000UL
+#define pctl_m_fdwdis 0x80000000000UL
+#define pctl_m_ptevrfy 0x100000000000UL
+#define pctl_m_rpp 0x200000000000UL
+#define pctl_m_pid 0xC00000000000UL
+#define pctl_m_rsvd2 0xFFFF000000000000UL
+
+union TPchipPCTL {
+    struct {
+       unsigned pctl_v_fdsc : 1;
+       unsigned pctl_v_fbtb : 1;
+       unsigned pctl_v_thdis : 1;
+       unsigned pctl_v_chaindis : 1;
+       unsigned pctl_v_tgtlat : 1;
+       unsigned pctl_v_hole : 1;
+       unsigned pctl_v_mwin : 1;
+       unsigned pctl_v_arbena : 1;
+       unsigned pctl_v_prigrp : 7;
+       unsigned pctl_v_ppri : 1;
+       unsigned pctl_v_rsvd1 : 2;
+       unsigned pctl_v_eccen : 1;
+       unsigned pctl_v_padm : 1;
+       unsigned pctl_v_cdqmax : 4;
+       unsigned pctl_v_rev : 8;
+       unsigned pctl_v_crqmax : 4;
+       unsigned pctl_v_ptpmax : 4;
+       unsigned pctl_v_pclkx : 2;
+       unsigned pctl_v_fdsdis : 1;
+       unsigned pctl_v_fdwdis : 1;
+       unsigned pctl_v_ptevrfy : 1;
+       unsigned pctl_v_rpp : 1;
+       unsigned pctl_v_pid : 2;
+       unsigned pctl_v_rsvd2 : 16;
+       } pctl_r_bits;
+    int pctl_q_whole [2];
+} ;
+/*                                                                          */
+/* TSUNAMI Pchip Error Mask Register.                                       */
+/*                                                                          */
+#define perrmask_m_lost 0x1
+#define perrmask_m_serr 0x2
+#define perrmask_m_perr 0x4
+#define perrmask_m_dcrto 0x8
+#define perrmask_m_sge 0x10
+#define perrmask_m_ape 0x20
+#define perrmask_m_ta 0x40
+#define perrmask_m_rdpe 0x80
+#define perrmask_m_nds 0x100
+#define perrmask_m_rto 0x200
+#define perrmask_m_uecc 0x400
+#define perrmask_m_cre 0x800
+#define perrmask_m_rsvd 0xFFFFFFFFFFFFF000UL
+union TPchipPERRMASK {   
+    struct  {
+        unsigned int perrmask_v_lost : 1;
+        unsigned perrmask_v_serr : 1;
+        unsigned perrmask_v_perr : 1;
+        unsigned perrmask_v_dcrto : 1;
+        unsigned perrmask_v_sge : 1;
+        unsigned perrmask_v_ape : 1;
+        unsigned perrmask_v_ta : 1;
+        unsigned perrmask_v_rdpe : 1;
+        unsigned perrmask_v_nds : 1;
+        unsigned perrmask_v_rto : 1;
+        unsigned perrmask_v_uecc : 1;
+        unsigned perrmask_v_cre : 1;                 
+        unsigned perrmask_v_rsvd1 : 20;
+       unsigned perrmask_v_rsvd2 : 32;
+        } perrmask_r_bits;
+    int perrmask_q_whole [2];
+    } ;                       
+
+/*
+ * Memory spaces:
+ */
+#define TSUNAMI_PCI0_MEM               (IDENT_ADDR + TS_BIAS + 0x000000000UL)
+#define TSUNAMI_PCI0_IACK_SC           (IDENT_ADDR + TS_BIAS + 0x1F8000000UL)
+#define TSUNAMI_PCI0_IO                        (IDENT_ADDR + TS_BIAS + 0x1FC000000UL)
+#define TSUNAMI_PCI0_CONF              (IDENT_ADDR + TS_BIAS + 0x1FE000000UL)
+
+#define TSUNAMI_PCI1_MEM               (IDENT_ADDR + TS_BIAS + 0x200000000UL)
+#define TSUNAMI_PCI1_IACK_SC           (IDENT_ADDR + TS_BIAS + 0x3F8000000UL)
+#define TSUNAMI_PCI1_IO                        (IDENT_ADDR + TS_BIAS + 0x3FC000000UL)
+#define TSUNAMI_PCI1_CONF              (IDENT_ADDR + TS_BIAS + 0x3FE000000UL)
+
+#define HAE_ADDRESS 0
+
+#ifdef __KERNEL__
+
+/*
+ * Translate physical memory address as seen on (PCI) bus into
+ * a kernel virtual address and vv.
+ */
+extern inline unsigned long virt_to_bus(void * address)
+{
+       return virt_to_phys(address) + TSUNAMI_DMA_WIN_BASE;
+}
+
+extern inline void * bus_to_virt(unsigned long address)
+{
+       return phys_to_virt(address - TSUNAMI_DMA_WIN_BASE);
+}
+
+/*
+ * I/O functions:
+ *
+ * TSUNAMI, the 21??? PCI/memory support chipset for the EV6 (21264)
+ * can only use linear accesses to get at PCI memory and I/O spaces.
+ */
+
+/* HACK ALERT! HACK ALERT! */
+/* HACK ALERT! HACK ALERT! */
+
+/* only using PCI bus 0 for now in all routines */
+
+/* HACK ALERT! HACK ALERT! */
+/* HACK ALERT! HACK ALERT! */
+
+
+#define vuip   volatile unsigned int *
+
+extern inline unsigned int __inb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+TSUNAMI_PCI0_IO)));
+
+       return result;
+}
+
+extern inline void __outb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+TSUNAMI_PCI0_IO)), "r" (b));
+}
+
+extern inline unsigned int __inw(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+TSUNAMI_PCI0_IO)));
+
+       return result;
+}
+
+extern inline void __outw(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+TSUNAMI_PCI0_IO)), "r" (b));
+}
+
+extern inline unsigned int __inl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+TSUNAMI_PCI0_IO)));
+
+       return result;
+}
+
+extern inline void __outl(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+TSUNAMI_PCI0_IO)), "r" (b));
+}
+
+/*
+ * Memory functions.  all accesses are done through linear space.
+ */
+
+extern inline unsigned long __readb(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldbu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned char *)(addr+TSUNAMI_PCI0_MEM)));
+
+       return result;
+}
+
+extern inline unsigned long __readw(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldwu %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned short *)(addr+TSUNAMI_PCI0_MEM)));
+
+       return result;
+}
+
+extern inline unsigned long __readl(unsigned long addr)
+{
+       register unsigned long result;
+
+       __asm__ __volatile__ (
+                "ldl %0,%1"
+                : "=r" (result)
+                : "m"  (*(unsigned int *)(addr+TSUNAMI_PCI0_MEM)));
+
+       return result;
+}
+
+extern inline void __writeb(unsigned char b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stb %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned char *)(addr+TSUNAMI_PCI0_MEM)), "r" (b));
+}
+
+extern inline void __writew(unsigned short b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stw %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned short *)(addr+TSUNAMI_PCI0_MEM)), "r" (b));
+}
+
+extern inline void __writel(unsigned int b, unsigned long addr)
+{
+       __asm__ __volatile__ (
+                "stl %1,%0\n\t"
+                "mb"
+                : : "m" (*(unsigned int *)(addr+TSUNAMI_PCI0_MEM)), "r" (b));
+}
+
+#define inb(port) __inb((port))
+#define inw(port) __inw((port))
+#define inl(port) __inl((port))
+
+#define outb(v, port) __outb((v),(port))
+#define outw(v, port) __outw((v),(port))
+#define outl(v, port) __outl((v),(port))
+
+#define readb(a)       __readb((unsigned long)(a))
+#define readw(a)       __readw((unsigned long)(a))
+#define readl(a)       __readl((unsigned long)(a))
+
+#define writeb(v,a)    __writeb((v),(unsigned long)(a))
+#define writew(v,a)    __writew((v),(unsigned long)(a))
+#define writel(v,a)    __writel((v),(unsigned long)(a))
+
+#undef vuip
+
+extern unsigned long tsunami_init (unsigned long mem_start,
+                                unsigned long mem_end);
+
+#endif /* __KERNEL__ */
+
+/*
+ * Data structure for handling TSUNAMI machine checks:
+ */
+struct el_TSUNAMI_sysdata_mcheck {
+};
+
+#define RTC_PORT(x)    (0x70 + (x))
+#define RTC_ADDR(x)    (0x80 | (x))
+#define RTC_ALWAYS_BCD 0
+
+#endif /* __ALPHA_TSUNAMI__H__ */
index b1c21cc..e61802f 100644 (file)
 typedef unsigned short ide_ioreg_t;
 
 #ifndef MAX_HWIFS
-#define MAX_HWIFS      4
+#define MAX_HWIFS      6
 #endif
 
 #define ide_sti()      sti()
@@ -28,6+28,8 @@ static __inline__ int ide_default_irq(ide_ioreg_t base)
                case 0x170: return 15;
                case 0x1e8: return 11;
                case 0x168: return 10;
+               case 0x1e0: return 8;
+               case 0x160: return 12;
                default:
                        return 0;
        }
@@ -40,6+42,8 @@ static __inline__ ide_ioreg_t ide_default_io_base(int index)
                case 1: return 0x170;
                case 2: return 0x1e8;
                case 3: return 0x168;
+               case 4: return 0x1e0;
+               case 5: return 0x160;
                default:
                        return 0;
        }
index 10a7ab6..c195581 100644 (file)
@@ -179,7+179,7 @@ struct thread_struct {
 
 #define start_thread(regs, new_eip, new_esp) do {\
        unsigned long seg = __USER_DS; \
-       __asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg)); \
+       __asm__("movl %w0,%%fs ; movl %w0,%%gs":"=r" (seg) :"0" (seg)); \
        set_fs(USER_DS); \
        regs->xds = seg; \
        regs->xes = seg; \
index ec19b0c..5101379 100644 (file)
@@ -45,75+45,33 @@ extern spinlock_t io_request_lock;
 #endif /* IDE_DRIVER */
 
 #define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
-#ifdef CONFIG_CDROM
-extern int cdrom_init(void);
-#endif CONFIG_CDROM 
-#ifdef CONFIG_ISP16_CDI
+
+/*
+ * Initialization functions.
+ */
 extern int isp16_init(void);
-#endif CONFIG_ISP16_CDI
-#ifdef CONFIG_CDU31A
 extern int cdu31a_init(void);
-#endif CONFIG_CDU31A
-#ifdef CONFIG_ATARI_ACSI
 extern int acsi_init(void);
-#endif CONFIG_ATARI_ACSI
-#ifdef CONFIG_MCD
 extern int mcd_init(void);
-#endif CONFIG_MCD
-#ifdef CONFIG_MCDX
 extern int mcdx_init(void);
-#endif CONFIG_MCDX
-#ifdef CONFIG_SBPCD
 extern int sbpcd_init(void);
-#endif CONFIG_SBPCD
-#ifdef CONFIG_AZTCD
 extern int aztcd_init(void);
-#endif CONFIG_AZTCD
-#ifdef CONFIG_CDU535
 extern int sony535_init(void);
-#endif CONFIG_CDU535
-#ifdef CONFIG_GSCD
 extern int gscd_init(void);
-#endif CONFIG_GSCD
-#ifdef CONFIG_CM206
 extern int cm206_init(void);
-#endif CONFIG_CM206
-#ifdef CONFIG_OPTCD
 extern int optcd_init(void);
-#endif CONFIG_OPTCD
-#ifdef CONFIG_SJCD
 extern int sjcd_init(void);
-#endif CONFIG_SJCD
-#ifdef CONFIG_CDI_INIT
 extern int cdi_init(void);
-#endif CONFIG_CDI_INIT
-#ifdef CONFIG_BLK_DEV_HD
 extern int hd_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE
 extern int ide_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_XD
 extern int xd_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_LOOP
 extern int loop_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_MD
 extern int md_init(void);
-#endif CONFIG_BLK_DEV_MD
-#ifdef CONFIG_APBLOCK
 extern int ap_init(void);
-#endif
-#ifdef CONFIG_DDV
 extern int ddv_init(void);
-#endif
-#ifdef CONFIG_AMIGA_Z2RAM
 extern int z2_init(void);
-#endif
-#ifdef CONFIG_MAC_FLOPPY
 extern int swim3_init(void);
-#endif
+extern int ps2esdi_init(void);
 
 extern void set_device_ro(kdev_t dev,int flag);
 void add_blkdev_randomness(int major);
@@ -135,9+93,6 @@ extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < m
 void initrd_init(void);
 
 #endif
-#ifdef CONFIG_BLK_DEV_PS2
-extern int ps2esdi_init(void);
-#endif
 
 #define RO_IOCTLS(dev,where) \
   case BLKROSET: { int __val;  if (!suser()) return -EACCES; \
index 04f905a..6a2240a 100644 (file)
 
 #define DLIST_INIT(listnam)                                    \
        (listnam).dl_prev = &(listnam);                         \
-       (listnam).dl_last = &(listnam);
+       (listnam).dl_next = &(listnam);
 
 #define DLIST_NEXT(listnam)    listnam.dl_next
 #define DLIST_PREV(listnam)    listnam.dl_prev
        node->listnam.dl_next->listnam.dl_prev =                \
                node->listnam.dl_prev;                          \
        } while (0)
+
+/*
+ * queue-style operations, which have a head and tail
+ */
+
+#define QUEUE_INIT(head, listnam, ptype)                               \
+       (head)->listnam.dl_prev = (head)->listnam.dl_next = (ptype)(head);
+
+#define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam)
+#define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam)
+#define QUEUE_EMPTY(head, listnam) \
+       ((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \
+        ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head)) 
+
+#define QUEUE_ENTER(head, new, listnam, ptype) do {            \
+       (new)->listnam.dl_prev = (ptype)(head);                 \
+       (new)->listnam.dl_next = (head)->listnam.dl_next;       \
+       (head)->listnam.dl_next->listnam.dl_prev = (new);       \
+       (head)->listnam.dl_next = (new);                        \
+       } while (0)
+
+#define QUEUE_REMOVE(head, node, listnam) DLIST_DELETE(node, listnam)
index 020720f..578fcee 100644 (file)
 #define MKISS_MAJOR    55
 #define DSP56K_MAJOR    55   /* DSP56001 processor device */
 
+#define IDE4_MAJOR     56
+#define IDE5_MAJOR     57
+
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
index eb62d23..b70e74e 100644 (file)
 #define  PCI_BASE_ADDRESS_MEM_TYPE_1M  0x02    /* Below 1M */
 #define  PCI_BASE_ADDRESS_MEM_TYPE_64  0x04    /* 64 bit address */
 #define  PCI_BASE_ADDRESS_MEM_PREFETCH 0x08    /* prefetchable? */
-#define  PCI_BASE_ADDRESS_MEM_MASK     (~0x0f)
-#define  PCI_BASE_ADDRESS_IO_MASK      (~0x03)
+#define  PCI_BASE_ADDRESS_MEM_MASK     (~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK      (~0x03UL)
 /* bit 1 is reserved if address_space = 1 */
 
 /* Header type 0 (normal devices) */
 
 #define PCI_VENDOR_ID_CONTAQ           0x1080
 #define PCI_DEVICE_ID_CONTAQ_82C599    0x0600
-/* ??? Alpha SX164 has reference to device nr 0xc693 as a CYPRESS bridge.  */
+#define PCI_DEVICE_ID_CONTAQ_82C693    0xC693
 
 #define PCI_VENDOR_ID_FOREX            0x1083
 
 #define PCI_SLOT(devfn)                (((devfn) >> 3) & 0x1f)
 #define PCI_FUNC(devfn)                ((devfn) & 0x07)
 
+/* create an index into the pci_dev base_address[] array from an offset */
+#define PCI_BASE_INDEX(o) (((o)-PCI_BASE_ADDRESS_0)>>2)
+
 #ifdef __KERNEL__
 /*
  * There is one pci_dev structure for each slot-number/function-number
@@ -987,6+990,7 @@ struct pci_bus {
 
 extern struct pci_bus  pci_root;       /* root bus */
 extern struct pci_dev  *pci_devices;   /* list of all devices */
+extern struct pci_dev   *pci_find_dev (unsigned char bus, unsigned char devfn);
 
 extern unsigned long pci_init (unsigned long mem_start, unsigned long mem_end);
 
index d1f68d0..0ccd625 100644 (file)
 #define CHECKSUM_HW 1
 #define CHECKSUM_UNNECESSARY 2
 
-struct sk_buff_head 
-{
+struct sk_buff_head {
        struct sk_buff  * next;
        struct sk_buff  * prev;
        __u32           qlen;           /* Must be same length as a pointer
                                           for using debugging */
 };
 
-struct sk_buff 
-{
+struct sk_buff {
        struct sk_buff  * next;                 /* Next buffer in list                          */
        struct sk_buff  * prev;                 /* Previous buffer in list                      */
        struct sk_buff_head * list;             /* List we are on                               */
        struct sock     *sk;                    /* Socket we are owned by                       */
-       unsigned long   when;                   /* used to compute rtt's                        */
        struct timeval  stamp;                  /* Time we arrived                              */
        struct device   *dev;                   /* Device we arrived on/are leaving by          */
 
@@ -81,13+78,9 @@ struct sk_buff
 #if (defined(__alpha__) || defined(__sparc64__)) && (defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE))
        char            cb[48];    /* sorry. 64bit pointers have a price */
 #else
-       char            cb[32];
+       char            cb[36];
 #endif
 
-       __u32           seq;                    /* TCP sequence number                          */
-       __u32           end_seq;                /* seq [+ fin] [+ syn] + datalen                */
-       __u32           ack_seq;                /* TCP ack sequence number                      */
-  
        unsigned int    len;                    /* Length of actual data                        */
        unsigned int    csum;                   /* Checksum                                     */
        volatile char   used;                   /* Data moved to user and not MSG_PEEK          */
@@ -102,10+95,6 @@ struct sk_buff
        unsigned short  security;               /* Security level of packet                     */
        unsigned int    truesize;               /* Buffer size                                  */
 
-#ifndef SLAB_SKB
-       atomic_t        count;                  /* reference count                              */
-       struct sk_buff  *data_skb;              /* Link to the actual data skb                  */
-#endif
        unsigned char   *head;                  /* Head of buffer                               */
        unsigned char   *data;                  /* Data head pointer                            */
        unsigned char   *tail;                  /* Tail pointer                                 */
index 78b3364..74cb982 100644 (file)
@@ -260,7+260,7 @@ struct ufs_superblock {
                        __u32   fs_qfmask[2];   /* ~usb_fmask */
                        __s32   fs_state;       /* file system state time stamp */
                } fs_44;
-       } fs_u;
+       } fs_u  __attribute__ ((packed));
        __s32   fs_postblformat;        /* format of positional layout tables */
        __s32   fs_nrpos;               /* number of rotational positions */
        __s32   fs_postbloff;           /* (__s16) rotation block list head */
index f06f94e..d94469d 100644 (file)
@@ -191,8+191,7 @@ struct tcp_sack_block {
        __u32   end_seq;
 };
 
-struct tcp_opt
-{
+struct tcp_opt {
        int     tcp_header_len; /* Bytes of tcp header to send          */
 
 /*
@@ -229,7+228,9 @@ struct tcp_opt
        __u32   snd_cwnd;       /* Sending congestion window            */
        __u32   rto;            /* retransmit timeout                   */
 
-       __u32   packets_out;    /* Packets which are "in flight" */
+       __u32   packets_out;    /* Packets which are "in flight"        */
+       __u32   fackets_out;    /* Non-retrans SACK'd packets           */
+       __u32   retrans_out;    /* Fast-retransmitted packets out       */
        __u32   high_seq;       /* highest sequence number sent by onset of congestion */
 /*
  *     Slow start and congestion control (see also Nagle, and Karn & Partridge)
index 84bf7f5..b5af990 100644 (file)
@@ -266,8+266,6 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
 #define TCP_KEEPALIVE_TIME (180*60*HZ)         /* two hours */
 #define TCP_KEEPALIVE_PROBES   9               /* Max of 9 keepalive probes    */
 #define TCP_KEEPALIVE_PERIOD ((75*HZ)>>2)      /* period of keepalive check    */
-#define TCP_NO_CHECK   0       /* turn to one if you want the default
-                                * to be no checksum                    */
 
 #define TCP_SYNACK_PERIOD      (HZ/2)
 #define TCP_QUICK_TRIES                8  /* How often we try to retransmit, until
@@ -552,6+550,7 @@ extern void tcp_read_wakeup(struct sock *);
 extern void tcp_write_xmit(struct sock *);
 extern void tcp_time_wait(struct sock *);
 extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
+extern void tcp_fack_retransmit(struct sock *);
 extern void tcp_xmit_retransmit_queue(struct sock *);
 extern void tcp_simple_retransmit(struct sock *);
 
@@ -651,10+650,17 @@ extern __inline__ int tcp_raise_window(struct sock *sk)
 
 /* This is what the send packet queueing engine uses to pass
  * TCP per-packet control information to the transmission
- * code.
+ * code.  We also store the host-order sequence numbers in
+ * here too.  This is 36 bytes on 32-bit architectures,
+ * 40 bytes on 64-bit machines, if this grows please adjust
+ * skbuff.h:skbuff->cb[xxx] size appropriately.
  */
 struct tcp_skb_cb {
-       __u8    flags;                  /* TCP header flags.            */
+       struct inet_skb_parm    header; /* For incoming frames          */
+       __u32           seq;            /* Starting sequence number     */
+       __u32           end_seq;        /* SEQ + FIN + SYN + datalen    */
+       unsigned long   when;           /* used to compute rtt's        */
+       __u8            flags;          /* TCP header flags.            */
 
        /* NOTE: These must match up to the flags byte in a
         *       real TCP header.
@@ -666,15+672,35 @@ struct tcp_skb_cb {
 #define TCPCB_FLAG_ACK         0x10
 #define TCPCB_FLAG_URG         0x20
 
-       __u8    sacked;                 /* State flags for SACK/FACK.   */
+       __u8            sacked;         /* State flags for SACK/FACK.   */
 #define TCPCB_SACKED_ACKED     0x01    /* SKB ACK'd by a SACK block    */
 #define TCPCB_SACKED_RETRANS   0x02    /* SKB retransmitted            */
 
-       __u16   urg_ptr;                /* Valid w/URG flags is set.    */
+       __u16           urg_ptr;        /* Valid w/URG flags is set.    */
+       __u32           ack_seq;        /* Sequence number ACK'd        */
 };
 
 #define TCP_SKB_CB(__skb)      ((struct tcp_skb_cb *)&((__skb)->cb[0]))
 
+/* This determines how many packets are "in the network" to the best
+ * or our knowledge.  In many cases it is conservative, but where
+ * detailed information is available from the receiver (via SACK
+ * blocks etc.) we can make more agressive calculations.
+ *
+ * Use this for decisions involving congestion control, use just
+ * tp->packets_out to determine if the send queue is empty or not.
+ *
+ * Read this equation as:
+ *
+ *     "Packets sent once on transmission queue" MINUS
+ *     "Packets acknowledged by FACK information" PLUS
+ *     "Packets fast retransmitted"
+ */
+static __inline__ int tcp_packets_in_flight(struct tcp_opt *tp)
+{
+       return tp->packets_out - tp->fackets_out + tp->retrans_out;
+}
+
 /* This checks if the data bearing packet SKB (usually tp->send_head)
  * should be put on the wire right now.
  */
@@ -682,7+708,6 @@ static __inline__ int tcp_snd_test(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
        int nagle_check = 1;
-       int len;
 
        /*      RFC 1122 - section 4.2.3.4
         *
@@ -697,13+722,12 @@ static __inline__ int tcp_snd_test(struct sock *sk, struct sk_buff *skb)
         *
         *      Don't use the nagle rule for urgent data.
         */
-       len = skb->end_seq - skb->seq;
-       if (!sk->nonagle && len < (sk->mss >> 1) && tp->packets_out && 
+       if (!sk->nonagle && skb->len < (sk->mss >> 1) && tp->packets_out &&
            !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG))
                nagle_check = 0;
 
-       return (nagle_check && tp->packets_out < tp->snd_cwnd &&
-               !after(skb->end_seq, tp->snd_una + tp->snd_wnd) &&
+       return (nagle_check && tcp_packets_in_flight(tp) < tp->snd_cwnd &&
+               !after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
                tp->retransmits == 0);
 }
 
index c6c0f0d..09b69c4 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -632,12+632,14 @@ asmlinkage int sys_shmdt (char *shmaddr)
 {
        struct vm_area_struct *shmd, *shmdnext;
 
+       lock_kernel();
        for (shmd = current->mm->mmap; shmd; shmd = shmdnext) {
                shmdnext = shmd->vm_next;
                if (shmd->vm_ops == &shm_vm_ops
                    && shmd->vm_start - shmd->vm_offset == (ulong) shmaddr)
                        do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
        }
+       unlock_kernel();
        return 0;
 }
 
index d22c8b0..74f5ab7 100644 (file)
@@ -299,7+299,10 @@ static void exit_notify(void)
         *      as a result of our exiting, and if they have any stopped
         *      jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
         */
-       while ((p = current->p_cptr) != NULL) {
+
+       write_lock_irq(&tasklist_lock);
+       while (current->p_cptr != NULL) {
+               p = current->p_cptr;
                current->p_cptr = p->p_osptr;
                p->p_ysptr = NULL;
                p->flags &= ~(PF_PTRACED|PF_TRACESYS);
@@ -318,13+321,19 @@ static void exit_notify(void)
                 * outside, so the child pgrp is now orphaned.
                 */
                if ((p->pgrp != current->pgrp) &&
-                   (p->session == current->session) &&
-                   is_orphaned_pgrp(p->pgrp) &&
-                   has_stopped_jobs(p->pgrp)) {
-                       kill_pg(p->pgrp,SIGHUP,1);
-                       kill_pg(p->pgrp,SIGCONT,1);
+                   (p->session == current->session)) {
+                       int pgrp = p->pgrp;
+
+                       write_unlock_irq(&tasklist_lock);
+                       if (is_orphaned_pgrp(pgrp) && has_stopped_jobs(pgrp)) {
+                               kill_pg(pgrp,SIGHUP,1);
+                               kill_pg(pgrp,SIGCONT,1);
+                       }
+                       write_lock_irq(&tasklist_lock);
                }
        }
+       write_unlock_irq(&tasklist_lock);
+
        if (current->leader)
                disassociate_ctty(1);
 }
index a08aa2c..d419727 100644 (file)
@@ -208,6+208,7 @@ static inline int dup_mmap(struct mm_struct * mm)
        int retval;
 
        flush_cache_mm(current->mm);
+       down(&current->mm->mmap_sem);
        pprev = &mm->mmap;
        for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
                struct file *file;
@@ -257,6+258,7 @@ static inline int dup_mmap(struct mm_struct * mm)
 
 fail_nomem:
        flush_tlb_mm(current->mm);
+       up(&current->mm->mmap_sem);
        return retval;
 }
 
@@ -514,6+516,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
                /* ?? should we just memset this ?? */
                for(i = 0; i < smp_num_cpus; i++)
                        p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0;
+               spin_lock_init(&p->sigmask_lock);
        }
 #endif
        p->lock_depth = 0;
index 7ff40d7..ad3c4a7 100644 (file)
@@ -295,6+295,7 @@ EXPORT_SYMBOL(bh_mask_count);
 EXPORT_SYMBOL(bh_base);
 EXPORT_SYMBOL(add_timer);
 EXPORT_SYMBOL(del_timer);
+EXPORT_SYMBOL(mod_timer);
 EXPORT_SYMBOL(tq_timer);
 EXPORT_SYMBOL(tq_immediate);
 EXPORT_SYMBOL(tq_scheduler);
index 47bb361..0da7a07 100644 (file)
 #include <linux/nfs_fs.h>
 #endif
 
-#ifdef CONFIG_SYSCTL
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
 
 /* External variables not in a header file. */
 extern int panic_timeout;
@@ -1031,7+1031,7 @@ int do_struct (
 }
 
 
-#else /* CONFIG_SYSCTL */
+#else /* CONFIG_PROC_FS && CONFIG_SYSCTL */
 
 
 extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
@@ -1087,7+1087,7 @@ void unregister_sysctl_table(struct ctl_table_header * table)
 {
 }
 
-#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_PROC_FS && CONFIG_SYSCTL */
 
 
 
index f6099fd..006026d 100644 (file)
@@ -129,10+129,13 @@ int free_memory_available(int nr)
        struct free_area_struct * list;
 
        /*
-        * If we have more than 25% of all memory free,
+        * If we have more than about 6% of all memory free,
         * consider it to be good enough for anything.
+        * It may not be, due to fragmentation, but we
+        * don't want to keep on forever trying to find
+        * free unfragmented memory.
         */
-       if (nr_free_pages > num_physpages >> 2)
+       if (nr_free_pages > num_physpages >> 4)
                return nr+1;
 
        list = free_area + NR_MEM_LISTS;
index 57e58f8..abad1e2 100644 (file)
@@ -273,7+273,6 @@ struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask)
        n->csum = skb->csum;
        n->list=NULL;
        n->sk=NULL;
-       n->when=skb->when;
        n->dev=skb->dev;
        n->priority=skb->priority;
        n->protocol=skb->protocol;
@@ -281,9+280,6 @@ struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask)
        n->h.raw=skb->h.raw+offset;
        n->nh.raw=skb->nh.raw+offset;
        n->mac.raw=skb->mac.raw+offset;
-       n->seq=skb->seq;
-       n->end_seq=skb->end_seq;
-       n->ack_seq=skb->ack_seq;
        memcpy(n->cb, skb->cb, sizeof(skb->cb));
        n->used=skb->used;
        n->is_clone=0;
@@ -323,7+319,6 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom)
        memcpy(n->data,skb->data,skb->len);
        n->list=NULL;
        n->sk=NULL;
-       n->when=skb->when;
        n->priority=skb->priority;
        n->protocol=skb->protocol;
        n->dev=skb->dev;
@@ -332,9+327,6 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom)
        n->nh.raw=skb->nh.raw+offset;
        n->mac.raw=skb->mac.raw+offset;
        memcpy(n->cb, skb->cb, sizeof(skb->cb));
-       n->seq=skb->seq;
-       n->end_seq=skb->end_seq;
-       n->ack_seq=skb->ack_seq;
        n->used=skb->used;
        n->is_clone=0;
        atomic_set(&n->users, 1);
index 249fa0b..6997e8d 100644 (file)
@@ -5,7+5,7 @@
  *
  *             AF_INET protocol family socket handler.
  *
- * Version:    $Id: af_inet.c,v 1.66 1998/03/21 07:27:58 davem Exp $
+ * Version:    $Id: af_inet.c,v 1.68 1998/03/27 07:02:42 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -352,7+352,6 @@ static int inet_create(struct socket *sock, int protocol)
                if (protocol && protocol != IPPROTO_TCP)
                        goto free_and_noproto;
                protocol = IPPROTO_TCP;
-               sk->no_check = TCP_NO_CHECK;
                if (ipv4_config.no_pmtu_disc)
                        sk->ip_pmtudisc = IP_PMTUDISC_DONT;
                else
index 025401a..425885c 100644 (file)
@@ -1,7+1,7 @@
 /*
  *     NET3    IP device support routines.
  *
- *     Version: $Id: devinet.c,v 1.19 1998/03/08 20:52:35 davem Exp $
+ *     Version: $Id: devinet.c,v 1.20 1998/03/27 07:02: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
  *
  *     Changes:
  *             Alexey Kuznetsov:       pa_* fields are replaced with ifaddr lists.
              Cyrus Durgin:           updated for kmod
*             Cyrus Durgin:           updated for kmod
  */
 
 #include <linux/config.h>
index f6a50df..7319a26 100644 (file)
@@ -2,10+2,9 @@
  *             IP_MASQ_MOD masq modules support
  *
  *
- * Version:    @(#)ip_masq_mod.c  0.02      97/10/30
- *
  * Author:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *
+ *     $Id: ip_masq_mod.c,v 1.4 1998/03/27 07:02:45 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -287,7+286,6 @@ struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
 
 /*
  *     Module control entry
- *     no need to lock (already locked in ip_masq.c)
  */
 int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
 {
index 08f5c79..85a3824 100644 (file)
@@ -5,7+5,7 @@
  *
  *             The Internet Protocol (IP) output module.
  *
- * Version:    $Id: ip_output.c,v 1.50 1998/03/20 09:12:08 davem Exp $
+ * Version:    $Id: ip_output.c,v 1.51 1998/03/28 00:55:34 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -428,7+428,6 @@ int ip_build_xmit(struct sock *sk,
                        return error;
                }
 
-               skb->when=jiffies;
                skb->priority = sk->priority;
                skb->dst = dst_clone(&rt->u.dst);
                skb_reserve(skb, hh_len);
@@ -573,7+572,6 @@ int ip_build_xmit(struct sock *sk,
                 *      Fill in the control structures
                 */
                 
-               skb->when = jiffies;
                skb->priority = sk->priority;
                skb->dst = dst_clone(&rt->u.dst);
                skb_reserve(skb, hh_len);
@@ -765,7+763,6 @@ void ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                 *      Set up data on packet
                 */
 
-               skb2->when = skb->when;
                skb2->pkt_type = skb->pkt_type;
                skb2->priority = skb->priority;
                skb_reserve(skb2, (dev->hard_header_len+15)&~15);
index d57b7e3..86595e1 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.104 1998/03/22 22:10:30 davem Exp $
+ * Version:    $Id: tcp.c,v 1.107 1998/03/28 00:55:28 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -506,13+506,13 @@ static int tcp_readable(struct sock *sk)
        /* Do until a push or until we are out of data. */
        do {
                /* Found a hole so stops here. */
-               if (before(counted, skb->seq))  /* should not happen */
+               if (before(counted, TCP_SKB_CB(skb)->seq))      /* should not happen */
                        break;
 
                /* Length - header but start from where we are up to
                 * avoid overlaps.
                 */
-               sum = skb->len - (counted - skb->seq);
+               sum = skb->len - (counted - TCP_SKB_CB(skb)->seq);
                if (skb->h.th->syn)
                        sum++;
                if (sum > 0) {
@@ -788,7+788,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
                                 */
                                if (skb_tailroom(skb) > 0 &&
                                    (mss_now - copy) > 0 &&
-                                   tp->snd_nxt < skb->end_seq) {
+                                   tp->snd_nxt < TCP_SKB_CB(skb)->end_seq) {
                                        int last_byte_was_odd = (copy % 4);
 
                                        copy = mss_now - copy;
@@ -809,7+809,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
                                                        copy, skb->csum, &err);
                                        }
                                        tp->write_seq += copy;
-                                       skb->end_seq += copy;
+                                       TCP_SKB_CB(skb)->end_seq += copy;
                                        from += copy;
                                        copied += copy;
                                        seglen -= copy;
@@ -839,7+839,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
                        if(copy > seglen)
                                copy = seglen;
 
-                       tmp = MAX_HEADER + sk->prot->max_header + 15;
+                       tmp = MAX_HEADER + sk->prot->max_header;
                        queue_it = 0;
                        if (copy < min(mss_now, tp->max_window >> 1) &&
                            !(flags & MSG_OOB)) {
@@ -897,8+897,8 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
                        from += copy;
                        copied += copy;
 
-                       skb->seq = tp->write_seq;
-                       skb->end_seq = skb->seq + copy;
+                       TCP_SKB_CB(skb)->seq = tp->write_seq;
+                       TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + copy;
 
                        /* This advances tp->write_seq for us. */
                        tcp_send_skb(sk, skb, queue_it);
@@ -1135,12+1135,12 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                        /* Now that we have two receive queues this 
                         * shouldn't happen.
                         */
-                       if (before(*seq, skb->seq)) {
+                       if (before(*seq, TCP_SKB_CB(skb)->seq)) {
                                printk(KERN_INFO "recvmsg bug: copied %X seq %X\n",
-                                      *seq, skb->seq);
+                                      *seq, TCP_SKB_CB(skb)->seq);
                                break;
                        }
-                       offset = *seq - skb->seq;
+                       offset = *seq - TCP_SKB_CB(skb)->seq;
                        if (skb->h.th->syn)
                                offset--;
                        if (offset < skb->len)
@@ -1225,10+1225,8 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                 *      a crash when cleanup_rbuf() gets called.
                 */
                err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
-               
                if (err) {
                        /* Exception. Bailout! */
-                       *seq -= err;
                        atomic_dec(&skb->users);
                        copied = -EFAULT;
                        break;
@@ -1625,8+1623,16 @@ void tcp_set_keepalive(struct sock *sk, int val)
                tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
 }
 
+extern void __skb_cb_too_small_for_tcp(int, int);
+
 __initfunc(void tcp_init(void))
 {
+       struct sk_buff *skb = NULL;
+
+       if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
+               __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
+                                          sizeof(skb->cb));
+
        tcp_openreq_cachep = kmem_cache_create("tcp_open_request",
                                                   sizeof(struct open_request),
                                               0, SLAB_HWCACHE_ALIGN,
index 1c34e66..d9c5a95 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.98 1998/03/23 22:54:48 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.100 1998/03/28 00:55:31 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -176,7+176,7 @@ static __inline__ void tcp_set_rto(struct tcp_opt *tp)
  * 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
+ * ack bias into account? This needs serious thought. -- erics
  */
 static __inline__ void tcp_bound_rto(struct tcp_opt *tp)
 {
@@ -193,19+193,27 @@ extern __inline__ void tcp_replace_ts_recent(struct tcp_opt *tp, __u32 end_seq)
         * test is last_ack_sent <= end_seq.
         * (RFC1323 stated last_ack_sent < end_seq.)
         */
-       if (!before(end_seq,tp->last_ack_sent)) {
-               tp->ts_recent = tp->rcv_tsval;
-               tp->ts_recent_stamp = jiffies;
+       if (!before(end_seq, tp->last_ack_sent)) {
+               /* PAWS bug workaround wrt. ACK frames, the PAWS discard
+                * extra check below makes sure this can only happen
+                * for pure ACK frames.  -DaveM
+                */
+               if((s32)(tp->rcv_tsval - tp->ts_recent) >= 0) {
+                       tp->ts_recent = tp->rcv_tsval;
+                       tp->ts_recent_stamp = jiffies;
+               }
        }
 }
 
 #define PAWS_24DAYS    (HZ * 60 * 60 * 24 * 24)
 
-extern __inline__ int tcp_paws_discard(struct tcp_opt *tp)
+extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct tcphdr *th, __u16 len)
 {
        /* ts_recent must be younger than 24 days */
        return (((jiffies - tp->ts_recent_stamp) >= PAWS_24DAYS) ||
-               ((s32)(tp->rcv_tsval-tp->ts_recent) < 0));
+               (((s32)(tp->rcv_tsval-tp->ts_recent) < 0) &&
+                /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM */
+                (len != (th->doff * 4))));
 }
 
 
@@ -266,15+274,34 @@ static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp,
                struct sk_buff *skb = skb_peek(&sk->write_queue);
                __u32 start_seq = ntohl(sp->start_seq);
                __u32 end_seq = ntohl(sp->end_seq);
+               int fack_count = 0;
 
                while((skb != NULL) &&
                      (skb != tp->send_head) &&
                      (skb != (struct sk_buff *)&sk->write_queue)) {
+                       /* The retransmission queue is always in order, so
+                        * we can short-circuit the walk early.
+                        */
+                       if(!before(start_seq, TCP_SKB_CB(skb)->end_seq))
+                               break;
+
                        /* We play conservative, we don't allow SACKS to partially
                         * tag a sequence space.
                         */
-                       if(!after(start_seq, skb->seq) && !before(end_seq, skb->end_seq))
+                       fack_count++;
+                       if(!after(start_seq, TCP_SKB_CB(skb)->seq) &&
+                          !before(end_seq, TCP_SKB_CB(skb)->end_seq)) {
+                               /* If this was a retransmitted frame, account for it. */
+                               if(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
+                                       tp->retrans_out--;
                                TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED;
+
+                               /* RULE: All new SACKs will either decrease retrans_out
+                                *       or advance fackets_out.
+                                */
+                               if(fack_count > tp->fackets_out)
+                                       tp->fackets_out = fack_count;
+                       }
                        skb = skb->next;
                }
                sp++; /* Move on to the next SACK block. */
@@ -388,19+415,43 @@ static __inline__ int tcp_fast_parse_options(struct sock *sk, struct tcphdr *th,
        return 1;
 }
 
+#if 0 /* Not working yet... -DaveM */
+static void tcp_compute_tsack(struct sock *sk, struct tcp_opt *tp)
+{
+       struct sk_buff *skb = skb_peek(&sk->write_queue);
+       __u32 tstamp = tp->rcv_tsecr;
+       int fack_count = 0;
+
+       while((skb != NULL) &&
+             (skb != tp->send_head) &&
+             (skb != (struct sk_buff *)&sk->write_queue)) {
+               if(TCP_SKB_CB(skb)->when == tstamp) {
+                       __u8 sacked = TCP_SKB_CB(skb)->sacked;
+
+                       sacked |= TCPCB_SACKED_ACKED;
+                       if(sacked & TCPCB_SACKED_RETRANS)
+                               tp->retrans_out--;
+                       TCP_SKB_CB(skb)->sacked = sacked;
+               }
+               if(!before(TCP_SKB_CB(skb)->when, tstamp))
+                       fack_count++;
+               skb = skb->next;
+       }
+       if(fack_count > tp->fackets_out)
+               tp->fackets_out = fack_count;
+}
+#endif
+
 #define FLAG_DATA              0x01 /* Incoming frame contained data.          */
 #define FLAG_WIN_UPDATE                0x02 /* Incoming ACK was a window update.       */
 #define FLAG_DATA_ACKED                0x04 /* This ACK acknowledged new data.         */
 #define FLAG_RETRANS_DATA_ACKED        0x08 /* "" "" some of which was retransmitted.  */
 
-static __inline__ void clear_fast_retransmit(struct sock *sk)
+static __inline__ void clear_fast_retransmit(struct tcp_opt *tp)
 {
-       struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
+       if (tp->dup_acks > 3)
+               tp->snd_cwnd = tp->snd_ssthresh;
 
-       if (tp->dup_acks > 3) {
-               tp->retrans_head = NULL;
-               tp->snd_cwnd = max(tp->snd_ssthresh, 1);
-       }
        tp->dup_acks = 0;
 }
 
@@ -409,10+460,9 @@ static __inline__ void clear_fast_retransmit(struct sock *sk)
  */
 static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
 {
-       struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
+       struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
-       /*
-        * Note: If not_dup is set this implies we got a
+       /* Note: If not_dup is set this implies we got a
         * data carrying packet or a window update.
         * This carries no new information about possible
         * lost packets, so we have to ignore it for the purposes
@@ -422,22+472,31 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
         * the code below much more complex. For now if I see such
         * a packet I clear the fast retransmit phase.
         */
-
        if (ack == tp->snd_una && tp->packets_out && (not_dup == 0)) {
                /* This is the standard reno style fast retransmit branch. */
 
+#if 0  /* Not working yet... -DaveM */
+               /* If not doing SACK, but doing timestamps, compute timestamp
+                * based pseudo-SACKs when we see duplicate ACKs.
+                */
+               if(!tp->sack_ok && tp->saw_tstamp)
+                       tcp_compute_tsack(sk, tp);
+#endif
                 /* 1. When the third duplicate ack is received, set ssthresh 
                  * to one half the current congestion window, but no less 
                  * than two segments. Retransmit the missing segment.
                  */
                if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
                        tp->dup_acks++;
-                       if (tp->dup_acks == 3) {
+                       if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
                                tp->dup_acks++;
                                 tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
                                 tp->snd_cwnd = tp->snd_ssthresh + 3;
                                tp->high_seq = tp->snd_nxt;
-                                tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+                               if(!tp->fackets_out)
+                                       tcp_retransmit_skb(sk, skb_peek(&sk->write_queue));
+                               else
+                                       tcp_fack_retransmit(sk);
                                 tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
                        }
                }
@@ -446,10+505,22 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
                  * cwnd by the segment size. [...] Transmit a packet...
                  *
                  * Packet transmission will be done on normal flow processing
-                 * since we're not in "retransmit mode"
+                 * since we're not in "retransmit mode".  We do not use duplicate
+                * ACKs to artificially inflate the congestion window when
+                * doing FACK.
                  */
-                if (tp->dup_acks > 3)
-                        tp->snd_cwnd++;
+                if (tp->dup_acks > 3) {
+                       if(!tp->fackets_out) {
+                               tp->snd_cwnd++;
+                       } else {
+                               /* Fill any further holes which may have appeared.
+                                * We may want to change this to run every further
+                                * multiple-of-3 dup ack increments, to be more robust
+                                * against out-of-order packet delivery.  -DaveM
+                                */
+                               tcp_fack_retransmit(sk);
+                       }
+               }
        } else if (tp->high_seq != 0) {
                /* In this branch we deal with clearing the Floyd style
                 * block on duplicate fast retransmits, and if requested
@@ -463,15+534,17 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
                         * Note that we do want to accept a window
                         * update since this is expected with Hoe's algorithm.
                         */
-                       clear_fast_retransmit(sk);
+                       clear_fast_retransmit(tp);
 
                        /* After we have cleared up to high_seq we can
                         * clear the Floyd style block.
                         */
-                       if (after(ack, tp->high_seq))
+                       if (!before(ack, tp->high_seq)) {
                                tp->high_seq = 0;
+                               tp->fackets_out = 0;
+                       }
                } else if (tp->dup_acks >= 3) {
-                       if (sysctl_tcp_hoe_retransmits) {
+                       if (!tp->fackets_out) {
                                /* Hoe Style. We didn't ack the whole
                                 * window. Take this as a cue that
                                 * another packet was lost and retransmit it.
@@ -490,11+563,10 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
                                        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
                                }
                        } else {
-                               /* Reno style. We didn't ack the whole
-                                * window, now we have to drop out of
-                                * fast retransmit and wait for a timeout.
+                               /* FACK style, fill any remaining holes in
+                                * receiver's queue.
                                 */
-                               clear_fast_retransmit(sk);
+                               tcp_fack_retransmit(sk);
                        }
                }
        }
@@ -632,7+704,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
                 * discard it as it's confirmed to have arrived at
                 * the other end.
                 */
-               if (after(skb->end_seq, ack))
+               if (after(TCP_SKB_CB(skb)->end_seq, ack))
                        break;
 
                /* Initial outgoing SYN's get put onto the write_queue
@@ -643,15+715,29 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack,
                 * quickly.  This is severely frowned upon behavior.
                 */
                if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN)) {
+                       __u8 sacked = TCP_SKB_CB(skb)->sacked;
+
                        acked |= FLAG_DATA_ACKED;
-                       if(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
+                       if(sacked & TCPCB_SACKED_RETRANS) {
                                acked |= FLAG_RETRANS_DATA_ACKED;
+
+                               /* XXX The race is, fast retrans frame -->
+                                * XXX retrans timeout sends older frame -->
+                                * XXX ACK arrives for fast retrans frame -->
+                                * XXX retrans_out goes negative --> splat.
+                                * XXX Please help me find a better way -DaveM
+                                */
+                               if(tp->retrans_out)
+                                       tp->retrans_out--;
+                       }
+                       if(tp->fackets_out)
+                               tp->fackets_out--;
                } else {
                        tp->retrans_head = NULL;
                }               
                tp->packets_out--;
-               *seq = skb->seq;
-               *seq_rtt = now - skb->when;
+               *seq = TCP_SKB_CB(skb)->seq;
+               *seq_rtt = now - TCP_SKB_CB(skb)->when;
                skb_unlink(skb);
                kfree_skb(skb);
        }
@@ -672,7+758,7 @@ static void tcp_ack_probe(struct sock *sk, __u32 ack)
        
        /* should always be non-null */
        if (tp->send_head != NULL &&
-           !before (ack + tp->snd_wnd, tp->send_head->end_seq)) {
+           !before (ack + tp->snd_wnd, TCP_SKB_CB(tp->send_head)->end_seq)) {
                tp->backoff = 0;
                tp->pending = 0;
                tcp_clear_xmit_timer(sk, TIME_PROBE0);
@@ -693,6+779,8 @@ static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
        if (tp->retransmits) {
                if (tp->packets_out == 0) {
                        tp->retransmits = 0;
+                       tp->fackets_out = 0;
+                       tp->retrans_out = 0;
                        tp->backoff = 0;
                        tcp_set_rto(tp);
                } else {
@@ -712,7+800,7 @@ static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
 static void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
 {
        struct sk_buff *skb = skb_peek(&sk->write_queue);
-       long when = tp->rto - (jiffies - skb->when);
+       long when = tp->rto - (jiffies - TCP_SKB_CB(skb)->when);
 
        /* Some data was ACK'd, if still retransmitting (due to a
         * timeout), resend more of the retransmit queue.  The
@@ -801,8+889,11 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
        } else {
                /* If we were retransmiting don't count rtt estimate. */
                if (tp->retransmits) {
-                       if (tp->packets_out == 0)
+                       if (tp->packets_out == 0) {
                                tp->retransmits = 0;
+                               tp->fackets_out = 0;
+                               tp->retrans_out = 0;
+                       }
                } else {
                        /* We don't have a timestamp. Can only use
                         * packets that are not retransmitted to determine
@@ -812,12+903,13 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
                         * where the network delay has increased suddenly.
                         * I.e. Karn's algorithm. (SIGCOMM '87, p5.)
                         */
-                       if ((flag & FLAG_DATA_ACKED) &&
-                           !(flag & FLAG_RETRANS_DATA_ACKED)) {
-                               tp->backoff = 0;
-                               tcp_rtt_estimator(tp, seq_rtt);
-                               tcp_set_rto(tp);
-                               tcp_bound_rto(tp);
+                       if (flag & FLAG_DATA_ACKED) {
+                               if(!(flag & FLAG_RETRANS_DATA_ACKED)) {
+                                       tp->backoff = 0;
+                                       tcp_rtt_estimator(tp, seq_rtt);
+                                       tcp_set_rto(tp);
+                                       tcp_bound_rto(tp);
+                               }
                                (*tcp_sys_cong_ctl_f)(sk, seq, ack, seq_rtt);
                        }
                }
@@ -898,7+990,7 @@ int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
         *      (2)  returns to TIME-WAIT state if the SYN turns out 
         *      to be an old duplicate".
         */
-       if(th->syn && !th->rst && after(skb->seq, tw->rcv_nxt)) {
+       if(th->syn && !th->rst && after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) {
                struct sock *sk;
                struct tcp_func *af_specific = tw->af_specific;
                __u32 isn;
@@ -1051,7+1143,7 @@ void tcp_time_wait(struct sock *sk)
  
 static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
 {
-       sk->tp_pinfo.af_tcp.fin_seq = skb->end_seq;
+       sk->tp_pinfo.af_tcp.fin_seq = TCP_SKB_CB(skb)->end_seq;
 
        tcp_send_ack(sk);
 
@@ -1174,14+1266,14 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
         * "in order". ;-)  This also satisfies the requirements
         * of RFC2018 about ordering of SACKs.
         */
-       if(sp->end_seq == skb->seq) {
-               sp->end_seq = skb->end_seq;
+       if(sp->end_seq == TCP_SKB_CB(skb)->seq) {
+               sp->end_seq = TCP_SKB_CB(skb)->end_seq;
                tcp_sack_maybe_coalesce(tp, sp);
-       } else if(sp->start_seq == skb->end_seq) {
+       } else if(sp->start_seq == TCP_SKB_CB(skb)->end_seq) {
                /* Re-ordered arrival, in this case, can be optimized
                 * as well.
                 */
-               sp->start_seq = skb->seq;
+               sp->start_seq = TCP_SKB_CB(skb)->seq;
                tcp_sack_maybe_coalesce(tp, sp);
        } else {
                int cur_sacks = tp->num_sacks;
@@ -1195,12+1287,12 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
                        int this_sack;
 
                        for(this_sack = 1; this_sack < cur_sacks; this_sack++, swap++) {
-                               if((swap->end_seq == skb->seq) ||
-                                  (swap->start_seq == skb->end_seq)) {
-                                       if(swap->end_seq == skb->seq)
-                                               swap->end_seq = skb->end_seq;
+                               if((swap->end_seq == TCP_SKB_CB(skb)->seq) ||
+                                  (swap->start_seq == TCP_SKB_CB(skb)->end_seq)) {
+                                       if(swap->end_seq == TCP_SKB_CB(skb)->seq)
+                                               swap->end_seq = TCP_SKB_CB(skb)->end_seq;
                                        else
-                                               swap->start_seq = skb->seq;
+                                               swap->start_seq = TCP_SKB_CB(skb)->seq;
                                        tcp_sack_swap(sp, swap);
                                        tcp_sack_maybe_coalesce(tp, sp);
                                        return;
@@ -1221,8+1313,8 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
                }
 
                /* Build head SACK, and we're done. */
-               sp->start_seq = skb->seq;
-               sp->end_seq = skb->end_seq;
+               sp->start_seq = TCP_SKB_CB(skb)->seq;
+               sp->end_seq = TCP_SKB_CB(skb)->end_seq;
                if(tp->num_sacks < max_sacks)
                        tp->num_sacks++;
        }
@@ -1236,7+1328,7 @@ static void tcp_sack_remove_skb(struct tcp_opt *tp, struct sk_buff *skb)
 
        /* We know this removed SKB will eat from the front of a SACK. */
        for(this_sack = 0; this_sack < num_sacks; this_sack++, sp++) {
-               if(sp->start_seq == skb->seq)
+               if(sp->start_seq == TCP_SKB_CB(skb)->seq)
                        break;
        }
 
@@ -1247,7+1339,7 @@ static void tcp_sack_remove_skb(struct tcp_opt *tp, struct sk_buff *skb)
        if(this_sack >= num_sacks)
                return;
 
-       sp->start_seq = skb->end_seq;
+       sp->start_seq = TCP_SKB_CB(skb)->end_seq;
        if(!before(sp->start_seq, sp->end_seq)) {
                /* Zap this SACK, by moving forward any other SACKS. */
                for(this_sack += 1; this_sack < num_sacks; this_sack++, sp++) {
@@ -1266,12+1358,12 @@ static void tcp_sack_extend(struct tcp_opt *tp, struct sk_buff *old_skb, struct
        int this_sack;
 
        for(this_sack = 0; this_sack < num_sacks; this_sack++, tp++) {
-               if(sp->end_seq == old_skb->end_seq)
+               if(sp->end_seq == TCP_SKB_CB(old_skb)->end_seq)
                        break;
        }
        if(this_sack >= num_sacks)
                return;
-       sp->end_seq = new_skb->end_seq;
+       sp->end_seq = TCP_SKB_CB(new_skb)->end_seq;
 }
 
 /* This one checks to see if we can put data from the
@@ -1283,23+1375,24 @@ static void tcp_ofo_queue(struct sock *sk)
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
        while ((skb = skb_peek(&tp->out_of_order_queue))) {
-               if (after(skb->seq, tp->rcv_nxt))
+               if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
                        break;
 
-               if (!after(skb->end_seq, tp->rcv_nxt)) {
+               if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
                        SOCK_DEBUG(sk, "ofo packet was already received \n");
                        skb_unlink(skb);
                        kfree_skb(skb);
                        continue;
                }
                SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n",
-                          tp->rcv_nxt, skb->seq, skb->end_seq);
+                          tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
+                          TCP_SKB_CB(skb)->end_seq);
 
                if(tp->sack_ok)
                        tcp_sack_remove_skb(tp, skb);
                skb_unlink(skb);
                skb_queue_tail(&sk->receive_queue, skb);
-               tp->rcv_nxt = skb->end_seq;
+               tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
                if(skb->h.th->fin)
                        tcp_fin(skb, sk, skb->h.th);
        }
@@ -1314,12+1407,12 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
         *  Packets in sequence go to the receive queue.
         *  Out of sequence packets to out_of_order_queue.
         */
-       if (skb->seq == tp->rcv_nxt) {
+       if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
                /* Ok. In sequence. */
        queue_and_out:
                dst_confirm(sk->dst_cache);
                skb_queue_tail(&sk->receive_queue, skb);
-               tp->rcv_nxt = skb->end_seq;
+               tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
                if(skb->h.th->fin) {
                        tcp_fin(skb, sk, skb->h.th);
                } else {
@@ -1341,18+1434,19 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
        }
        
        /* An old packet, either a retransmit or some packet got lost. */
-       if (!after(skb->end_seq, tp->rcv_nxt)) {
+       if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
                /* A retransmit, 2nd most common case.  Force an imediate ack. */
-               SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq);
+               SOCK_DEBUG(sk, "retransmit received: seq %X\n", TCP_SKB_CB(skb)->seq);
                tcp_enter_quickack_mode(tp);
                kfree_skb(skb);
                return;
        }
 
-       if (before(skb->seq, tp->rcv_nxt)) {
+       if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
                /* Partial packet, seq < rcv_next < end_seq */
                SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n",
-                          tp->rcv_nxt, skb->seq, skb->end_seq);
+                          tp->rcv_nxt, TCP_SKB_CB(skb)->seq,
+                          TCP_SKB_CB(skb)->end_seq);
 
                goto queue_and_out;
        }
@@ -1365,20+1459,20 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
        tp->pred_flags = 0;
 
        SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
-                  tp->rcv_nxt, skb->seq, skb->end_seq);
+                  tp->rcv_nxt, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq);
 
        if (skb_peek(&tp->out_of_order_queue) == NULL) {
                /* Initial out of order segment, build 1 SACK. */
                if(tp->sack_ok) {
                        tp->num_sacks = 1;
-                       tp->selective_acks[0].start_seq = skb->seq;
-                       tp->selective_acks[0].end_seq = skb->end_seq;
+                       tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq;
+                       tp->selective_acks[0].end_seq = TCP_SKB_CB(skb)->end_seq;
                }
                skb_queue_head(&tp->out_of_order_queue,skb);
        } else {
                for(skb1=tp->out_of_order_queue.prev; ; skb1 = skb1->prev) {
                        /* Already there. */
-                       if (skb->seq == skb1->seq) {
+                       if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb1)->seq) {
                                if (skb->len >= skb1->len) {
                                        if(tp->sack_ok)
                                                tcp_sack_extend(tp, skb1, skb);
@@ -1394,7+1488,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                                break;
                        }
                        
-                       if (after(skb->seq, skb1->seq)) {
+                       if (after(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb1)->seq)) {
                                skb_append(skb1,skb);
                                if(tp->sack_ok)
                                        tcp_sack_new_ofo_skb(sk, skb);
@@ -1455,8+1549,8 @@ static void tcp_data_snd_check(struct sock *sk)
        struct sk_buff *skb;
 
        if ((skb = tp->send_head)) {
-               if (!after(skb->end_seq, tp->snd_una + tp->snd_wnd) &&
-                   tp->packets_out < tp->snd_cwnd ) {
+               if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
+                   tcp_packets_in_flight(tp) < tp->snd_cwnd) {
                        /* Put more data onto the wire. */
                        tcp_write_xmit(sk);
                } else if (tp->packets_out == 0 && !tp->pending) {
@@ -1616,15+1710,16 @@ static void prune_queue(struct sock *sk)
                        break;
 
                /* Never remove packets that have been already acked */
-               if (before(skb->end_seq, tp->last_ack_sent+1)) {
+               if (before(TCP_SKB_CB(skb)->end_seq, tp->last_ack_sent+1)) {
                        printk(KERN_DEBUG "prune_queue: hit acked data c=%x,%x,%x\n",
-                               tp->copied_seq, skb->end_seq, tp->last_ack_sent);
+                               tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->last_ack_sent);
                        break; 
                }
                skb_unlink(skb);
-               tp->rcv_nxt = skb->seq;
+               tp->rcv_nxt = TCP_SKB_CB(skb)->seq;
                SOCK_DEBUG(sk, "prune_queue: removing %x-%x (c=%x)\n",
-                          skb->seq, skb->end_seq, tp->copied_seq); 
+                          TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
+                          tp->copied_seq); 
                kfree_skb(skb);
                if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) 
                        break;
@@ -1658,13+1753,13 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
         */
        if (tcp_fast_parse_options(sk, th, tp)) {
                if (tp->saw_tstamp) {
-                       if (tcp_paws_discard(tp)) {
+                       if (tcp_paws_discard(tp, th, len)) {
                                if (!th->rst) {
                                        tcp_send_ack(sk);
                                        goto discard;
                                }
                        }
-                       tcp_replace_ts_recent(tp,skb->end_seq);
+                       tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
                }
        }
 
@@ -1678,11+1773,12 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
         *       space for instance)
         */
 
-       if (flg == tp->pred_flags && skb->seq == tp->rcv_nxt) {
+       if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
                if (len <= th->doff*4) {
                        /* Bulk data transfer: sender */
                        if (len == th->doff*4) {
-                               tcp_ack(sk, th, skb->seq, skb->ack_seq, len); 
+                               tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
+                                       TCP_SKB_CB(skb)->ack_seq, len); 
                                kfree_skb(skb); 
                                tcp_data_snd_check(sk);
                                return 0;
@@ -1690,7+1786,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                tcp_statistics.TcpInErrs++;
                                goto discard;
                        }
-               } else if (skb->ack_seq == tp->snd_una) {
+               } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
                        /* Bulk data transfer: receiver */
                        if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) 
                                goto discard;
@@ -1701,7+1797,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                         * It saves dozen of CPU instructions in fast path. --ANK
                         */
                        skb_queue_tail(&sk->receive_queue, skb);
-                       tp->rcv_nxt = skb->end_seq;
+                       tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 
                        /* FIN bit check is not done since if FIN is set in
                         * this frame, the pred_flags won't match up. -DaveM
@@ -1719,11+1815,11 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                }
        }
 
-       if (!tcp_sequence(tp, skb->seq, skb->end_seq)) {
+       if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
                if (!th->rst) {
-                       if (after(skb->seq, tp->rcv_nxt)) {
+                       if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
                                SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
-                                          skb->seq, skb->end_seq,
+                                          TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
                                           tp->rcv_wup, tp->rcv_wnd);
                        }
                        tcp_send_ack(sk);
@@ -1731,7+1827,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                }
        }
 
-       if(th->syn && skb->seq != tp->syn_seq) {
+       if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
                SOCK_DEBUG(sk, "syn in established state\n");
                tcp_statistics.TcpInErrs++;
                tcp_reset(sk, skb);
@@ -1744,7+1840,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
        }
 
        if(th->ack)
-               tcp_ack(sk, th, skb->seq, skb->ack_seq, len);
+               tcp_ack(sk, th, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->ack_seq, len);
        
        /* Process urgent data. */
        tcp_urg(sk, th, len);
@@ -1793,7+1889,7 @@ tcp_check_req(struct sock *sk, struct sk_buff *skb, struct open_request *req)
                flg &= __constant_htonl(0x00170000);
                /* Only SYN set? */
                if (flg == __constant_htonl(0x00020000)) {
-                       if (!after(skb->seq, req->rcv_isn)) {
+                       if (!after(TCP_SKB_CB(skb)->seq, req->rcv_isn)) {
                                /*      retransmited syn.
                                 */
                                req->class->rtx_syn_ack(sk, req); 
@@ -1811,8+1907,8 @@ tcp_check_req(struct sock *sk, struct sk_buff *skb, struct open_request *req)
                 * but we do it here to prevent syn flood attackers
                 * from creating big SYN_RECV sockets.
                 */ 
-               if (!between(skb->ack_seq, req->snt_isn, req->snt_isn+1) ||
-                   !between(skb->seq, req->rcv_isn, 
+               if (!between(TCP_SKB_CB(skb)->ack_seq, req->snt_isn, req->snt_isn+1) ||
+                   !between(TCP_SKB_CB(skb)->seq, req->rcv_isn, 
                             req->rcv_isn+1+req->rcv_wnd)) {
                        req->class->send_reset(skb);
                        return NULL;
@@ -1885,10+1981,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                 * not be in line code. [AC]
                 */
                if(th->ack) {
-                       tp->snd_wl1 = skb->seq;
+                       tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
 
                        /* We got an ack, but it's not a good ack. */
-                       if(!tcp_ack(sk,th, skb->seq, skb->ack_seq, len)) {
+                       if(!tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
+                                   TCP_SKB_CB(skb)->ack_seq, len)) {
                                tcp_statistics.TcpAttemptFails++;
                                return 1;
                        }
@@ -1909,13+2006,13 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                        /* Ok.. it's good. Set up sequence numbers and
                         * move to established.
                         */
-                       tp->rcv_nxt = skb->seq+1;
-                       tp->rcv_wup = skb->seq+1;
+                       tp->rcv_nxt = TCP_SKB_CB(skb)->seq+1;
+                       tp->rcv_wup = TCP_SKB_CB(skb)->seq+1;
 
                        tp->snd_wnd = htons(th->window) << tp->snd_wscale;
-                       tp->snd_wl1 = skb->seq;
-                       tp->snd_wl2 = skb->ack_seq;
-                       tp->fin_seq = skb->seq;
+                       tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+                       tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+                       tp->fin_seq = TCP_SKB_CB(skb)->seq;
 
                        tcp_set_state(sk, TCP_ESTABLISHED);
                        tcp_parse_options(sk, th, tp, 0);
@@ -1983,11+2080,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                        tp->ts_recent_stamp = jiffies;
                                }
                                
-                               tp->rcv_nxt = skb->seq + 1;
-                               tp->rcv_wup = skb->seq + 1;
+                               tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+                               tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
 
                                tp->snd_wnd = htons(th->window);
-                               tp->snd_wl1 = skb->seq;
+                               tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
                                
                                tcp_send_synack(sk);
                                goto discard;
@@ -2008,18+2105,18 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                 * guarantee this.
                 */
                if (tp->saw_tstamp) {
-                       if (tcp_paws_discard(tp)) {
+                       if (tcp_paws_discard(tp, th, len)) {
                                if (!th->rst) {
                                        tcp_send_ack(sk);
                                        goto discard;
                                }
                        }
-                       tcp_replace_ts_recent(tp,skb->end_seq);
+                       tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->end_seq);
                }
        }
 
        /* step 1: check sequence number */
-       if (!tcp_sequence(tp, skb->seq, skb->end_seq)) {
+       if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
                if (!th->rst) {
                        tcp_send_ack(sk);
                        goto discard;
@@ -2050,14+2147,15 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
         *      original syn. 
         */
 
-       if (th->syn && skb->seq!=tp->syn_seq) {
+       if (th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
                tcp_reset(sk, skb);
                return 1;
        }
 
        /* step 5: check the ACK field */
        if (th->ack) {
-               int acceptable = tcp_ack(sk,th,skb->seq, skb->ack_seq,len);
+               int acceptable = tcp_ack(sk, th, TCP_SKB_CB(skb)->seq,
+                                        TCP_SKB_CB(skb)->ack_seq, len);
                
                switch(sk->state) {
                case TCP_SYN_RECV:
@@ -2069,10+2167,10 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                if(!sk->dead)
                                        sk->state_change(sk);           
 
-                               tp->snd_una = skb->ack_seq;
+                               tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
                                tp->snd_wnd = htons(th->window) << tp->snd_wscale;
-                               tp->snd_wl1 = skb->seq;
-                               tp->snd_wl2 = skb->ack_seq;
+                               tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+                               tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
 
                        } else {
                                SOCK_DEBUG(sk, "bad ack\n");
@@ -2117,7+2215,7 @@ step6:
        switch (sk->state) {
        case TCP_CLOSE_WAIT:
        case TCP_CLOSING:
-               if (!before(skb->seq, tp->fin_seq))
+               if (!before(TCP_SKB_CB(skb)->seq, tp->fin_seq))
                        break;
        
        case TCP_FIN_WAIT1:
@@ -2127,7+2225,7 @@ step6:
                 * BSD 4.4 also does reset.
                 */
                if ((sk->shutdown & RCV_SHUTDOWN) && sk->dead) {
-                       if (after(skb->end_seq - th->fin, tp->rcv_nxt)) {
+                       if (after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
                                tcp_reset(sk, skb);
                                return 1;
                        }
index ee53f47..0d3b957 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.119 1998/03/22 19:14:47 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.123 1998/03/28 00:55:30 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -601,8+601,6 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                sk->mtu = 64;   /* Sanity limit */
 
        mss = sk->mtu - sizeof(struct iphdr);
-       if (sk->opt)
-               mss -= sk->opt->optlen;
 
        tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
                                                   sk->sport, usin->sin_port);
@@ -971,8+969,6 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
        }
 
        mss = (rt->u.dst.pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr));
-       if (opt)
-               mss -= opt->optlen;
 
        skb = tcp_make_synack(sk, &rt->u.dst, req, mss);
        if (skb) {
@@ -1098,7+1094,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
 
        req->rcv_wnd = 0;               /* So that tcp_send_synack() knows! */
 
-       req->rcv_isn = skb->seq;
+       req->rcv_isn = TCP_SKB_CB(skb)->seq;
        tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
        tp.in_mss = 536;
        tcp_parse_options(NULL, th, &tp, want_cookie);
@@ -1210,6+1206,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
                newtp->snd_cwnd = 1;
                newtp->rto = TCP_TIMEOUT_INIT;
                newtp->packets_out = 0;
+               newtp->fackets_out = 0;
+               newtp->retrans_out = 0;
                newtp->high_seq = 0;
                newtp->snd_ssthresh = 0x7fffffff;
                newtp->snd_cwnd_cnt = 0;
@@ -1317,8+1315,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        if (mtu < 68)
                mtu = 68;
        snd_mss = mtu - sizeof(struct iphdr);
-       if (opt)
-               snd_mss -= opt->optlen;
 
        newsk = tcp_create_openreq_child(sk, req, skb, snd_mss);
        if (!newsk) 
@@ -1337,8+1333,7 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newsk->opt = req->af.v4_req.opt;
        newsk->mtu = mtu;
 
-       /* Must use the af_specific ops here for the case of IPv6 mapped. */
-       newsk->prot->hash(newsk);
+       tcp_v4_hash(newsk);
        add_to_prot_sklist(newsk);
 
        return newsk;
@@ -1357,7+1352,8 @@ static void tcp_v4_rst_req(struct sock *sk, struct sk_buff *skb)
        if (!req)
                return;
        /* Sequence number check required by RFC793 */
-       if (before(skb->seq, req->snt_isn) || after(skb->seq, req->snt_isn+1))
+       if (before(TCP_SKB_CB(skb)->seq, req->snt_isn) ||
+           after(TCP_SKB_CB(skb)->seq, req->snt_isn+1))
                return;
        tcp_synq_unlink(tp, req, prev);
        req->class->destructor(req);
@@ -1509,9+1505,10 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
        if(!ipsec_sk_policy(sk,skb))
                goto discard_it;
 
-       skb->seq = ntohl(th->seq);
-       skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4;
-       skb->ack_seq = ntohl(th->ack_seq);
+       TCP_SKB_CB(skb)->seq = ntohl(th->seq);
+       TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
+                                   len - th->doff*4);
+       TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
 
        skb->used = 0;
 
index 465ee3f..dea48c1 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.76 1998/03/22 22:10:24 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.79 1998/03/28 00:55:33 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -99,12+99,13 @@ void tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                /* Build TCP header and checksum it. */
                th->source              = sk->sport;
                th->dest                = sk->dport;
-               th->seq                 = htonl(skb->seq);
+               th->seq                 = htonl(TCP_SKB_CB(skb)->seq);
                th->ack_seq             = htonl(tp->rcv_nxt);
                th->doff                = (tcp_header_size >> 2);
                th->res1                = 0;
                *(((__u8 *)th) + 13)    = tcb->flags;
-               th->window              = htons(tcp_select_window(sk));
+               if(!(tcb->flags & TCPCB_FLAG_SYN))
+                       th->window      = htons(tcp_select_window(sk));
                th->check               = 0;
                th->urg_ptr             = ntohs(tcb->urg_ptr);
                if(tcb->flags & TCPCB_FLAG_SYN) {
@@ -114,10+115,10 @@ void tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                                              sysctl_tcp_sack,
                                              sysctl_tcp_window_scaling,
                                              tp->rcv_wscale,
-                                             skb->when);
+                                             TCP_SKB_CB(skb)->when);
                } else {
                        tcp_build_and_update_options((__u32 *)(th + 1),
-                                                    tp, skb->when);
+                                                    tp, TCP_SKB_CB(skb)->when);
                }
                tp->af_specific->send_check(sk, th, skb->len, skb);
 
@@ -136,13+137,13 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb, int force_queue)
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
        /* Advance write_seq and place onto the write_queue. */
-       tp->write_seq += (skb->end_seq - skb->seq);
+       tp->write_seq += (TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq);
        skb_queue_tail(&sk->write_queue, skb);
 
        if (!force_queue && tp->send_head == NULL && tcp_snd_test(sk, skb)) {
                /* Send it out now. */
-               skb->when = jiffies;
-               tp->snd_nxt = skb->end_seq;
+               TCP_SKB_CB(skb)->when = jiffies;
+               tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
                tp->packets_out++;
                tcp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL));
                if(!tcp_timer_is_set(sk, TIME_RETRANS))
@@ -171,9+172,7 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
 
        /* Get a new skb... force flag on. */
        buff = sock_wmalloc(sk,
-                           (nsize +
-                            MAX_HEADER +
-                            sk->prot->max_header + 15),
+                           (nsize + MAX_HEADER + sk->prot->max_header),
                            1, GFP_ATOMIC);
        if (buff == NULL)
                return -1; /* We'll just try again later. */
@@ -182,8+181,8 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
        skb_reserve(buff, MAX_HEADER + sk->prot->max_header);
                
        /* Correct the sequence numbers. */
-       buff->seq = skb->seq + len;
-       buff->end_seq = skb->end_seq;
+       TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len;
+       TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq;
        
        /* PSH and FIN should only be set in the second packet. */
        flags = TCP_SKB_CB(skb)->flags;
@@ -209,7+208,7 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
        buff->csum = csum_partial_copy(skb->data + len, skb_put(buff, nsize),
                                       nsize, 0);
 
-       skb->end_seq -= nsize;
+       TCP_SKB_CB(skb)->end_seq -= nsize;
        skb_trim(skb, skb->len - nsize);
 
        /* Rechecksum original buffer. */
@@ -264,8+263,8 @@ void tcp_write_xmit(struct sock *sk)
 
                        /* Advance the send_head.  This one is going out. */
                        update_send_head(sk);
-                       skb->when = jiffies;
-                       tp->snd_nxt = skb->end_seq;
+                       TCP_SKB_CB(skb)->when = jiffies;
+                       tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
                        tp->packets_out++;
                        tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
                        sent_pkts = 1;
@@ -413,7+412,8 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
                }
        
                /* Update sequence range on original skb. */
-               skb->end_seq += next_skb->end_seq - next_skb->seq;
+               TCP_SKB_CB(skb)->end_seq +=
+                       TCP_SKB_CB(next_skb)->end_seq - TCP_SKB_CB(next_skb)->seq;
 
                /* Merge over control information. */
                flags |= TCP_SKB_CB(next_skb)->flags; /* This moves PSH/FIN etc. over */
@@ -444,9+444,12 @@ void tcp_simple_retransmit(struct sock *sk)
        /* Don't muck with the congestion window here. */
        tp->dup_acks = 0;
        tp->high_seq = tp->snd_nxt;
-
-       /* FIXME: make the current rtt sample invalid */
        tp->retrans_head = NULL; 
+
+       /* Input control flow will see that this was retransmitted
+        * and not use it for RTT calculation in the absence of
+        * the timestamp option.
+        */
        tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)); 
 }
 
@@ -496,11+499,12 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 
        /* Ok, we're gonna send it out, update state. */
        TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_RETRANS;
+       tp->retrans_out++;
 
        /* Make a copy, if the first transmission SKB clone we made
         * is still in somebodies hands, else make a clone.
         */
-       skb->when = jiffies;
+       TCP_SKB_CB(skb)->when = jiffies;
        if(skb_cloned(skb))
                skb = skb_copy(skb, GFP_ATOMIC);
        else
@@ -518,12+522,14 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
  * retransmitted data is acknowledged.  It tries to continue
  * resending the rest of the retransmit queue, until either
  * we've sent it all or the congestion window limit is reached.
+ * If doing SACK, the first ACK which comes back for a timeout
+ * based retransmit packet might feed us FACK information again.
+ * If so, we use it to avoid unnecessarily retransmissions.
  */
 void tcp_xmit_retransmit_queue(struct sock *sk)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
        struct sk_buff *skb;
-       int ct = 0;
 
        if (tp->retrans_head == NULL)
                tp->retrans_head = skb_peek(&sk->write_queue);
@@ -539,19+545,48 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
                        if(tcp_retransmit_skb(sk, skb))
                                break;
                
-                       /* Count retransmissions locally. */
-                       ct++;
-
                        /* Stop retransmitting if we've hit the congestion
                         * window limit.
                         */
-                       if (ct >= tp->snd_cwnd)
+                       if (tp->retrans_out >= tp->snd_cwnd)
                                break;
                }
                update_retrans_head(sk);
        }
 }
 
+/* Using FACK information, retransmit all missing frames at the receiver
+ * up to the forward most SACK'd packet (tp->fackets_out) if the packet
+ * has not been retransmitted already.
+ */
+void tcp_fack_retransmit(struct sock *sk)
+{
+       struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+       struct sk_buff *skb = skb_peek(&sk->write_queue);
+       int packet_cnt = 0;
+
+       while((skb != NULL) &&
+             (skb != tp->send_head) &&
+             (skb != (struct sk_buff *)&sk->write_queue)) {
+               __u8 sacked = TCP_SKB_CB(skb)->sacked;
+
+               if(sacked & (TCPCB_SACKED_ACKED | TCPCB_SACKED_RETRANS))
+                       goto next_packet;
+
+               /* Ok, retransmit it. */
+               if(tcp_retransmit_skb(sk, skb))
+                       break;
+
+               if(tcp_packets_in_flight(tp) >= tp->snd_cwnd)
+                       break;
+next_packet:
+               packet_cnt++;
+               if(packet_cnt >= tp->fackets_out)
+                       break;
+               skb = skb->next;
+       }
+}
+
 /* Send a fin.  The caller locks the socket for us.  This cannot be
  * allowed to fail queueing a FIN frame under any circumstances.
  */
@@ -573,7+608,7 @@ void tcp_send_fin(struct sock *sk)
        if((tp->send_head != NULL) && (skb->len < mss_now)) {
                /* tcp_write_xmit() takes care of the rest. */
                TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
-               skb->end_seq++;
+               TCP_SKB_CB(skb)->end_seq++;
                tp->write_seq++;
        } else {
                /* Socket is locked, keep trying until memory is available. */
@@ -592,8+627,8 @@ void tcp_send_fin(struct sock *sk)
                TCP_SKB_CB(skb)->urg_ptr = 0;
 
                /* FIN eats a sequence byte, write_seq advanced by tcp_send_skb(). */
-               skb->seq = tp->write_seq;
-               skb->end_seq = skb->seq + 1;
+               TCP_SKB_CB(skb)->seq = tp->write_seq;
+               TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
                tcp_send_skb(sk, skb, 0);
        }
 }
@@ -621,9+656,9 @@ void tcp_send_active_reset(struct sock *sk)
        TCP_SKB_CB(skb)->urg_ptr = 0;
 
        /* Send it off. */
-       skb->seq = tp->write_seq;
-       skb->end_seq = skb->seq;
-       skb->when = jiffies;
+       TCP_SKB_CB(skb)->seq = tp->write_seq;
+       TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq;
+       TCP_SKB_CB(skb)->when = jiffies;
        tcp_transmit_skb(sk, skb);
 }
 
@@ -650,10+685,10 @@ int tcp_send_synack(struct sock *sk)
        TCP_SKB_CB(skb)->urg_ptr = 0;
 
        /* SYN eats a sequence byte. */
-       skb->seq = tp->snd_una;
-       skb->end_seq = skb->seq + 1;
+       TCP_SKB_CB(skb)->seq = tp->snd_una;
+       TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
        skb_queue_tail(&sk->write_queue, skb);
-       skb->when = jiffies;
+       TCP_SKB_CB(skb)->when = jiffies;
        tp->packets_out++;
        tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
        return 0;
@@ -705,9+740,9 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        th->ack = 1;
        th->source = sk->sport;
        th->dest = req->rmt_port;
-       skb->seq = req->snt_isn;
-       skb->end_seq = skb->seq + 1;
-       th->seq = htonl(skb->seq);
+       TCP_SKB_CB(skb)->seq = req->snt_isn;
+       TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
+       th->seq = htonl(TCP_SKB_CB(skb)->seq);
        th->ack_seq = htonl(req->rcv_isn + 1);
        if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
                __u8 rcv_wscale; 
@@ -722,10+757,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        }
        th->window = htons(req->rcv_wnd);
 
-       skb->when = jiffies;
+       TCP_SKB_CB(skb)->when = jiffies;
        tcp_syn_build_options((__u32 *)(th + 1), req->mss, req->tstamp_ok,
                              req->sack_ok, req->wscale_ok, req->rcv_wscale,
-                             skb->when);
+                             TCP_SKB_CB(skb)->when);
 
        skb->csum = 0;
        th->doff = (tcp_header_size >> 2);
@@ -774,9+809,9 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mss)
        TCP_SKB_CB(buff)->sacked = 0;
        TCP_SKB_CB(buff)->urg_ptr = 0;
        buff->csum = 0;
-       buff->seq = tp->write_seq++;
-       buff->end_seq = tp->write_seq;
-       tp->snd_nxt = buff->end_seq;
+       TCP_SKB_CB(buff)->seq = tp->write_seq++;
+       TCP_SKB_CB(buff)->end_seq = tp->write_seq;
+       tp->snd_nxt = TCP_SKB_CB(buff)->end_seq;
 
        tp->window_clamp = dst->window;
        tcp_select_initial_window(sock_rspace(sk)/2,sk->mss,
@@ -784,7+819,6 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mss)
                &tp->window_clamp,
                sysctl_tcp_window_scaling,
                &tp->rcv_wscale);
-
        /* Ok, now lock the socket before we make it visible to
         * the incoming packet engine.
         */
@@ -800,10+834,12 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mss)
        tp->rto = dst->rtt;
        tcp_init_xmit_timers(sk);
        tp->retransmits = 0;
+       tp->fackets_out = 0;
+       tp->retrans_out = 0;
 
        /* Send it off. */
        skb_queue_tail(&sk->write_queue, buff);
-       buff->when = jiffies;
+       TCP_SKB_CB(buff)->when = jiffies;
        tp->packets_out++;
        tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL));
        tcp_statistics.TcpActiveOpens++;
@@ -870,8+906,8 @@ void tcp_send_ack(struct sock *sk)
                TCP_SKB_CB(buff)->urg_ptr = 0;
 
                /* Send it off, this clears delayed acks for us. */
-               buff->seq = buff->end_seq = tp->snd_nxt;
-               buff->when = jiffies;
+               TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tp->snd_nxt;
+               TCP_SKB_CB(buff)->when = jiffies;
                tcp_transmit_skb(sk, buff);
        }
 }
@@ -904,13+940,13 @@ void tcp_write_wakeup(struct sock *sk)
                         * must have been a result SWS avoidance ( sender )
                         */
                        win_size = tp->snd_wnd - (tp->snd_nxt - tp->snd_una);
-                       if (win_size < skb->end_seq - skb->seq) {
+                       if (win_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq) {
                                if (tcp_fragment(sk, skb, win_size))
                                        return; /* Let a retransmit get it. */
                        }
                        update_send_head(sk);
-                       skb->when = jiffies;
-                       tp->snd_nxt = skb->end_seq;
+                       TCP_SKB_CB(skb)->when = jiffies;
+                       tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
                        tp->packets_out++;
                        tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
                        if (!tcp_timer_is_set(sk, TIME_RETRANS))
@@ -933,9+969,9 @@ void tcp_write_wakeup(struct sock *sk)
                         * end to send an ack.  Don't queue or clone SKB, just
                         * send it.
                         */
-                       skb->seq = tp->snd_nxt - 1;
-                       skb->end_seq = skb->seq;
-                       skb->when = jiffies;
+                       TCP_SKB_CB(skb)->seq = tp->snd_nxt - 1;
+                       TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq;
+                       TCP_SKB_CB(skb)->when = jiffies;
                        tcp_transmit_skb(sk, skb);
                }
        }
index 58e7e8d..00d0214 100644 (file)
@@ -5,7+5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_timer.c,v 1.43 1998/03/22 22:10:28 davem Exp $
+ * Version:    $Id: tcp_timer.c,v 1.44 1998/03/27 04:07:43 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -362,13+362,17 @@ void tcp_retransmit_timer(unsigned long data)
         */
        if(tp->sack_ok) {
                struct sk_buff *skb = skb_peek(&sk->write_queue);
+               __u8 toclear = TCPCB_SACKED_ACKED;
 
+               if(tp->retransmits == 0)
+                       toclear |= TCPCB_SACKED_RETRANS;
                while((skb != NULL) &&
                      (skb != tp->send_head) &&
                      (skb != (struct sk_buff *)&sk->write_queue)) {
-                       TCP_SKB_CB(skb)->sacked = 0;
+                       TCP_SKB_CB(skb)->sacked &= ~(toclear);
                        skb = skb->next;
                }
+               tp->fackets_out = 0;
        }
 
        /* Retransmission. */
@@ -377,6+381,7 @@ void tcp_retransmit_timer(unsigned long data)
                /* remember window where we lost
                 * "one half of the current window but at least 2 segments"
                 */
+               tp->retrans_out = 0;
                tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
                tp->snd_cwnd_cnt = 0;
                tp->snd_cwnd = 1;
index 6a24bea..902274e 100644 (file)
@@ -7,7+7,7 @@
  *
  *     Adapted from linux/net/ipv4/af_inet.c
  *
- *     $Id: af_inet6.c,v 1.29 1998/03/18 07:52:11 davem Exp $
+ *     $Id: af_inet6.c,v 1.30 1998/03/25 00:23:05 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -79,7+79,6 @@ static int inet6_create(struct socket *sock, int protocol)
                if (protocol && protocol != IPPROTO_TCP) 
                        goto free_and_noproto;
                protocol = IPPROTO_TCP;
-               sk->no_check = TCP_NO_CHECK;
                prot = &tcpv6_prot;
                sock->ops = &inet6_stream_ops;
        } else if(sock->type == SOCK_DGRAM) {
index 4f176cd..5e3446b 100644 (file)
@@ -5,7+5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.68 1998/03/22 19:14:50 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.69 1998/03/28 00:55:36 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -770,7+770,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
 
        req->rcv_wnd = 0;               /* So that tcp_send_synack() knows! */
 
-       req->rcv_isn = skb->seq;
+       req->rcv_isn = TCP_SKB_CB(skb)->seq;
        req->snt_isn = isn;
        tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
        tp.in_mss = 536;
@@ -1012,7+1012,8 @@ static void tcp_v6_rst_req(struct sock *sk, struct sk_buff *skb)
        if (!req)
                return;
        /* Sequence number check required by RFC793 */
-       if (before(skb->seq, req->snt_isn) || after(skb->seq, req->snt_isn+1))
+       if (before(TCP_SKB_CB(skb)->seq, req->snt_isn) ||
+           after(TCP_SKB_CB(skb)->seq, req->snt_isn+1))
                return;
        tcp_synq_unlink(tp, req, prev);
        req->class->destructor(req);
@@ -1078,9+1079,10 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
                        goto no_tcp_socket;
                }
 
-               skb->seq = ntohl(th->seq);
-               skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4;
-               skb->ack_seq = ntohl(th->ack_seq);
+               TCP_SKB_CB(skb)->seq = ntohl(th->seq);
+               TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
+                                           len - th->doff*4);
+               TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
                skb->used = 0;
                if(sk->state == TCP_TIME_WAIT)
                        goto do_time_wait;
index 9ce58d2..8bc8ca2 100644 (file)
@@ -73,6+73,7 @@ extern void destroy_8023_client(struct datalink_proto *);
 /* Skbuff symbols. */
 EXPORT_SYMBOL(skb_push_errstr);
 EXPORT_SYMBOL(skb_put_errstr);
+EXPORT_SYMBOL(skb_queue_lock);
 
 /* Socket layer registration */
 EXPORT_SYMBOL(sock_register);
index d696cd3..f95459b 100644 (file)
@@ -1462,13+1462,10 @@ __initfunc(void sock_init(void))
         
        sk_init();
 
-#ifdef SLAB_SKB
        /*
         *      Initialize skbuff SLAB cache 
         */
        skb_init();
-#endif
-
 
        /*
         *      Wan router layer. 
close