[PATCH] arch/parisc/kernel
authorMatthew Wilcox <willy@debian.org>
Wed, 30 Oct 2002 07:01:13 +0000 (23:01 -0800)
committerLinus Torvalds <torvalds@penguin.transmeta.com>
Wed, 30 Oct 2002 07:01:13 +0000 (23:01 -0800)
Update arch/parisc/kernel.

36 files changed:
arch/parisc/kernel/Makefile
arch/parisc/kernel/asm-offsets.c [new file with mode: 0644]
arch/parisc/kernel/binfmt_elf32.c [new file with mode: 0644]
arch/parisc/kernel/cache.c
arch/parisc/kernel/drivers.c
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c [new file with mode: 0644]
arch/parisc/kernel/hardware.c
arch/parisc/kernel/head.S
arch/parisc/kernel/head64.S [new file with mode: 0644]
arch/parisc/kernel/hpmc.S
arch/parisc/kernel/init_task.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/keyboard.c
arch/parisc/kernel/pa7300lc.c
arch/parisc/kernel/pacache.S [new file with mode: 0644]
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/pci.c
arch/parisc/kernel/pdc_chassis.c [new file with mode: 0644]
arch/parisc/kernel/pdc_cons.c
arch/parisc/kernel/process.c
arch/parisc/kernel/processor.c [new file with mode: 0644]
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/real2.S
arch/parisc/kernel/semaphore.c
arch/parisc/kernel/setup.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/smp.c [new file with mode: 0644]
arch/parisc/kernel/sys32.h [new file with mode: 0644]
arch/parisc/kernel/sys_parisc.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/time.c
arch/parisc/kernel/traps.c
arch/parisc/kernel/unaligned.c [new file with mode: 0644]

index 7a0a315..c01c462 100644 (file)
@@ -2,29 +2,30 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_TARGETS  := head.o init_task.o process.o pdc_cons.o
+ifdef CONFIG_PARISC64
+EXTRA_TARGETS := init_task.o pdc_cons.o process.o head64.o unaligned.o perf.o perf_asm.o
+else
+EXTRA_TARGETS := init_task.o pdc_cons.o process.o head.o unaligned.o
+endif
 
-# Object file lists.
+AFLAGS_entry.o := -traditional
+AFLAGS_pacache.o := -traditional
 
-obj-y          := cache.o setup.o traps.o time.o irq.o \
-                  syscall.o entry.o sys_parisc.o pdc.o ptrace.o hardware.o \
-                  inventory.o drivers.o semaphore.o pa7300lc.o pci-dma.o \
-                  signal.o hpmc.o \
-                  real1.o real2.o led.o parisc_ksyms.o
+export-objs    := parisc_ksyms.o keyboard.o
 
-export-objs    := parisc_ksyms.o
+obj-y          := cache.o pacache.o setup.o traps.o time.o irq.o \
+                  pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \
+                  ptrace.o hardware.o inventory.o drivers.o semaphore.o \
+                  signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
+                  processor.o pdc_chassis.o
 
+obj-$(CONFIG_SMP) += smp.o 
+obj-$(CONFIG_PA11) += pci-dma.o
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_VT) += keyboard.o
-obj-$(CONFIG_PCI_LBA) += lba_pci.o
-# I/O SAPIC is also on IA64 platforms.
-# The two could be merged into a common source some day.
-obj-$(CONFIG_IOSAPIC) += iosapic.o
-obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o
-# Only use one of them: ccio-rm-dma is for PCX-W systems *only*
-# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
-obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
-
-EXTRA_AFLAGS   := -traditional
+obj-$(CONFIG_PARISC64) += binfmt_elf32.o sys_parisc32.o \
+               ioctl32.o signal32.o
+# only supported for PCX-W/U in 64-bit mode at the moment
+obj-$(CONFIG_PARISC64) += perf.o perf_asm.o
 
 include $(TOPDIR)/Rules.make
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
new file mode 100644 (file)
index 0000000..eee69b0
--- /dev/null
@@ -0,0 +1,250 @@
+/* 
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/thread_info.h>
+#include <linux/version.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+#include <asm/pdc.h>
+
+#define DEFINE(sym, val) \
+       asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+#ifdef __LP64__
+#define FRAME_SIZE     128
+#else
+#define FRAME_SIZE     64
+#endif
+
+#define align(x,y) (((x)+FRAME_SIZE+(y)-1) - (((x)+(y)-1)%(y)))
+
+int main(void)
+{
+       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+       DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+       DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
+       DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+       DEFINE(TASK_PERSONALITY, offsetof(struct task_struct, personality));
+       BLANK();
+       DEFINE(TASK_REGS, offsetof(struct task_struct, thread.regs));
+       DEFINE(TASK_PT_PSW, offsetof(struct task_struct, thread.regs.gr[ 0]));
+       DEFINE(TASK_PT_GR1, offsetof(struct task_struct, thread.regs.gr[ 1]));
+       DEFINE(TASK_PT_GR2, offsetof(struct task_struct, thread.regs.gr[ 2]));
+       DEFINE(TASK_PT_GR3, offsetof(struct task_struct, thread.regs.gr[ 3]));
+       DEFINE(TASK_PT_GR4, offsetof(struct task_struct, thread.regs.gr[ 4]));
+       DEFINE(TASK_PT_GR5, offsetof(struct task_struct, thread.regs.gr[ 5]));
+       DEFINE(TASK_PT_GR6, offsetof(struct task_struct, thread.regs.gr[ 6]));
+       DEFINE(TASK_PT_GR7, offsetof(struct task_struct, thread.regs.gr[ 7]));
+       DEFINE(TASK_PT_GR8, offsetof(struct task_struct, thread.regs.gr[ 8]));
+       DEFINE(TASK_PT_GR9, offsetof(struct task_struct, thread.regs.gr[ 9]));
+       DEFINE(TASK_PT_GR10, offsetof(struct task_struct, thread.regs.gr[10]));
+       DEFINE(TASK_PT_GR11, offsetof(struct task_struct, thread.regs.gr[11]));
+       DEFINE(TASK_PT_GR12, offsetof(struct task_struct, thread.regs.gr[12]));
+       DEFINE(TASK_PT_GR13, offsetof(struct task_struct, thread.regs.gr[13]));
+       DEFINE(TASK_PT_GR14, offsetof(struct task_struct, thread.regs.gr[14]));
+       DEFINE(TASK_PT_GR15, offsetof(struct task_struct, thread.regs.gr[15]));
+       DEFINE(TASK_PT_GR16, offsetof(struct task_struct, thread.regs.gr[16]));
+       DEFINE(TASK_PT_GR17, offsetof(struct task_struct, thread.regs.gr[17]));
+       DEFINE(TASK_PT_GR18, offsetof(struct task_struct, thread.regs.gr[18]));
+       DEFINE(TASK_PT_GR19, offsetof(struct task_struct, thread.regs.gr[19]));
+       DEFINE(TASK_PT_GR20, offsetof(struct task_struct, thread.regs.gr[20]));
+       DEFINE(TASK_PT_GR21, offsetof(struct task_struct, thread.regs.gr[21]));
+       DEFINE(TASK_PT_GR22, offsetof(struct task_struct, thread.regs.gr[22]));
+       DEFINE(TASK_PT_GR23, offsetof(struct task_struct, thread.regs.gr[23]));
+       DEFINE(TASK_PT_GR24, offsetof(struct task_struct, thread.regs.gr[24]));
+       DEFINE(TASK_PT_GR25, offsetof(struct task_struct, thread.regs.gr[25]));
+       DEFINE(TASK_PT_GR26, offsetof(struct task_struct, thread.regs.gr[26]));
+       DEFINE(TASK_PT_GR27, offsetof(struct task_struct, thread.regs.gr[27]));
+       DEFINE(TASK_PT_GR28, offsetof(struct task_struct, thread.regs.gr[28]));
+       DEFINE(TASK_PT_GR29, offsetof(struct task_struct, thread.regs.gr[29]));
+       DEFINE(TASK_PT_GR30, offsetof(struct task_struct, thread.regs.gr[30]));
+       DEFINE(TASK_PT_GR31, offsetof(struct task_struct, thread.regs.gr[31]));
+       DEFINE(TASK_PT_FR0, offsetof(struct task_struct, thread.regs.fr[ 0]));
+       DEFINE(TASK_PT_FR1, offsetof(struct task_struct, thread.regs.fr[ 1]));
+       DEFINE(TASK_PT_FR2, offsetof(struct task_struct, thread.regs.fr[ 2]));
+       DEFINE(TASK_PT_FR3, offsetof(struct task_struct, thread.regs.fr[ 3]));
+       DEFINE(TASK_PT_FR4, offsetof(struct task_struct, thread.regs.fr[ 4]));
+       DEFINE(TASK_PT_FR5, offsetof(struct task_struct, thread.regs.fr[ 5]));
+       DEFINE(TASK_PT_FR6, offsetof(struct task_struct, thread.regs.fr[ 6]));
+       DEFINE(TASK_PT_FR7, offsetof(struct task_struct, thread.regs.fr[ 7]));
+       DEFINE(TASK_PT_FR8, offsetof(struct task_struct, thread.regs.fr[ 8]));
+       DEFINE(TASK_PT_FR9, offsetof(struct task_struct, thread.regs.fr[ 9]));
+       DEFINE(TASK_PT_FR10, offsetof(struct task_struct, thread.regs.fr[10]));
+       DEFINE(TASK_PT_FR11, offsetof(struct task_struct, thread.regs.fr[11]));
+       DEFINE(TASK_PT_FR12, offsetof(struct task_struct, thread.regs.fr[12]));
+       DEFINE(TASK_PT_FR13, offsetof(struct task_struct, thread.regs.fr[13]));
+       DEFINE(TASK_PT_FR14, offsetof(struct task_struct, thread.regs.fr[14]));
+       DEFINE(TASK_PT_FR15, offsetof(struct task_struct, thread.regs.fr[15]));
+       DEFINE(TASK_PT_FR16, offsetof(struct task_struct, thread.regs.fr[16]));
+       DEFINE(TASK_PT_FR17, offsetof(struct task_struct, thread.regs.fr[17]));
+       DEFINE(TASK_PT_FR18, offsetof(struct task_struct, thread.regs.fr[18]));
+       DEFINE(TASK_PT_FR19, offsetof(struct task_struct, thread.regs.fr[19]));
+       DEFINE(TASK_PT_FR20, offsetof(struct task_struct, thread.regs.fr[20]));
+       DEFINE(TASK_PT_FR21, offsetof(struct task_struct, thread.regs.fr[21]));
+       DEFINE(TASK_PT_FR22, offsetof(struct task_struct, thread.regs.fr[22]));
+       DEFINE(TASK_PT_FR23, offsetof(struct task_struct, thread.regs.fr[23]));
+       DEFINE(TASK_PT_FR24, offsetof(struct task_struct, thread.regs.fr[24]));
+       DEFINE(TASK_PT_FR25, offsetof(struct task_struct, thread.regs.fr[25]));
+       DEFINE(TASK_PT_FR26, offsetof(struct task_struct, thread.regs.fr[26]));
+       DEFINE(TASK_PT_FR27, offsetof(struct task_struct, thread.regs.fr[27]));
+       DEFINE(TASK_PT_FR28, offsetof(struct task_struct, thread.regs.fr[28]));
+       DEFINE(TASK_PT_FR29, offsetof(struct task_struct, thread.regs.fr[29]));
+       DEFINE(TASK_PT_FR30, offsetof(struct task_struct, thread.regs.fr[30]));
+       DEFINE(TASK_PT_FR31, offsetof(struct task_struct, thread.regs.fr[31]));
+       DEFINE(TASK_PT_SR0, offsetof(struct task_struct, thread.regs.sr[ 0]));
+       DEFINE(TASK_PT_SR1, offsetof(struct task_struct, thread.regs.sr[ 1]));
+       DEFINE(TASK_PT_SR2, offsetof(struct task_struct, thread.regs.sr[ 2]));
+       DEFINE(TASK_PT_SR3, offsetof(struct task_struct, thread.regs.sr[ 3]));
+       DEFINE(TASK_PT_SR4, offsetof(struct task_struct, thread.regs.sr[ 4]));
+       DEFINE(TASK_PT_SR5, offsetof(struct task_struct, thread.regs.sr[ 5]));
+       DEFINE(TASK_PT_SR6, offsetof(struct task_struct, thread.regs.sr[ 6]));
+       DEFINE(TASK_PT_SR7, offsetof(struct task_struct, thread.regs.sr[ 7]));
+       DEFINE(TASK_PT_IASQ0, offsetof(struct task_struct, thread.regs.iasq[0]));
+       DEFINE(TASK_PT_IASQ1, offsetof(struct task_struct, thread.regs.iasq[1]));
+       DEFINE(TASK_PT_IAOQ0, offsetof(struct task_struct, thread.regs.iaoq[0]));
+       DEFINE(TASK_PT_IAOQ1, offsetof(struct task_struct, thread.regs.iaoq[1]));
+       DEFINE(TASK_PT_CR27, offsetof(struct task_struct, thread.regs.cr27));
+       DEFINE(TASK_PT_ORIG_R28, offsetof(struct task_struct, thread.regs.orig_r28));
+       DEFINE(TASK_PT_KSP, offsetof(struct task_struct, thread.regs.ksp));
+       DEFINE(TASK_PT_KPC, offsetof(struct task_struct, thread.regs.kpc));
+       DEFINE(TASK_PT_SAR, offsetof(struct task_struct, thread.regs.sar));
+       DEFINE(TASK_PT_IIR, offsetof(struct task_struct, thread.regs.iir));
+       DEFINE(TASK_PT_ISR, offsetof(struct task_struct, thread.regs.isr));
+       DEFINE(TASK_PT_IOR, offsetof(struct task_struct, thread.regs.ior));
+       BLANK();
+       DEFINE(TASK_SZ, sizeof(struct task_struct));
+       DEFINE(TASK_SZ_ALGN, align(sizeof(struct task_struct), 64));
+       BLANK();
+       DEFINE(PT_PSW, offsetof(struct pt_regs, gr[ 0]));
+       DEFINE(PT_GR1, offsetof(struct pt_regs, gr[ 1]));
+       DEFINE(PT_GR2, offsetof(struct pt_regs, gr[ 2]));
+       DEFINE(PT_GR3, offsetof(struct pt_regs, gr[ 3]));
+       DEFINE(PT_GR4, offsetof(struct pt_regs, gr[ 4]));
+       DEFINE(PT_GR5, offsetof(struct pt_regs, gr[ 5]));
+       DEFINE(PT_GR6, offsetof(struct pt_regs, gr[ 6]));
+       DEFINE(PT_GR7, offsetof(struct pt_regs, gr[ 7]));
+       DEFINE(PT_GR8, offsetof(struct pt_regs, gr[ 8]));
+       DEFINE(PT_GR9, offsetof(struct pt_regs, gr[ 9]));
+       DEFINE(PT_GR10, offsetof(struct pt_regs, gr[10]));
+       DEFINE(PT_GR11, offsetof(struct pt_regs, gr[11]));
+       DEFINE(PT_GR12, offsetof(struct pt_regs, gr[12]));
+       DEFINE(PT_GR13, offsetof(struct pt_regs, gr[13]));
+       DEFINE(PT_GR14, offsetof(struct pt_regs, gr[14]));
+       DEFINE(PT_GR15, offsetof(struct pt_regs, gr[15]));
+       DEFINE(PT_GR16, offsetof(struct pt_regs, gr[16]));
+       DEFINE(PT_GR17, offsetof(struct pt_regs, gr[17]));
+       DEFINE(PT_GR18, offsetof(struct pt_regs, gr[18]));
+       DEFINE(PT_GR19, offsetof(struct pt_regs, gr[19]));
+       DEFINE(PT_GR20, offsetof(struct pt_regs, gr[20]));
+       DEFINE(PT_GR21, offsetof(struct pt_regs, gr[21]));
+       DEFINE(PT_GR22, offsetof(struct pt_regs, gr[22]));
+       DEFINE(PT_GR23, offsetof(struct pt_regs, gr[23]));
+       DEFINE(PT_GR24, offsetof(struct pt_regs, gr[24]));
+       DEFINE(PT_GR25, offsetof(struct pt_regs, gr[25]));
+       DEFINE(PT_GR26, offsetof(struct pt_regs, gr[26]));
+       DEFINE(PT_GR27, offsetof(struct pt_regs, gr[27]));
+       DEFINE(PT_GR28, offsetof(struct pt_regs, gr[28]));
+       DEFINE(PT_GR29, offsetof(struct pt_regs, gr[29]));
+       DEFINE(PT_GR30, offsetof(struct pt_regs, gr[30]));
+       DEFINE(PT_GR31, offsetof(struct pt_regs, gr[31]));
+       DEFINE(PT_FR0, offsetof(struct pt_regs, fr[ 0]));
+       DEFINE(PT_FR1, offsetof(struct pt_regs, fr[ 1]));
+       DEFINE(PT_FR2, offsetof(struct pt_regs, fr[ 2]));
+       DEFINE(PT_FR3, offsetof(struct pt_regs, fr[ 3]));
+       DEFINE(PT_FR4, offsetof(struct pt_regs, fr[ 4]));
+       DEFINE(PT_FR5, offsetof(struct pt_regs, fr[ 5]));
+       DEFINE(PT_FR6, offsetof(struct pt_regs, fr[ 6]));
+       DEFINE(PT_FR7, offsetof(struct pt_regs, fr[ 7]));
+       DEFINE(PT_FR8, offsetof(struct pt_regs, fr[ 8]));
+       DEFINE(PT_FR9, offsetof(struct pt_regs, fr[ 9]));
+       DEFINE(PT_FR10, offsetof(struct pt_regs, fr[10]));
+       DEFINE(PT_FR11, offsetof(struct pt_regs, fr[11]));
+       DEFINE(PT_FR12, offsetof(struct pt_regs, fr[12]));
+       DEFINE(PT_FR13, offsetof(struct pt_regs, fr[13]));
+       DEFINE(PT_FR14, offsetof(struct pt_regs, fr[14]));
+       DEFINE(PT_FR15, offsetof(struct pt_regs, fr[15]));
+       DEFINE(PT_FR16, offsetof(struct pt_regs, fr[16]));
+       DEFINE(PT_FR17, offsetof(struct pt_regs, fr[17]));
+       DEFINE(PT_FR18, offsetof(struct pt_regs, fr[18]));
+       DEFINE(PT_FR19, offsetof(struct pt_regs, fr[19]));
+       DEFINE(PT_FR20, offsetof(struct pt_regs, fr[20]));
+       DEFINE(PT_FR21, offsetof(struct pt_regs, fr[21]));
+       DEFINE(PT_FR22, offsetof(struct pt_regs, fr[22]));
+       DEFINE(PT_FR23, offsetof(struct pt_regs, fr[23]));
+       DEFINE(PT_FR24, offsetof(struct pt_regs, fr[24]));
+       DEFINE(PT_FR25, offsetof(struct pt_regs, fr[25]));
+       DEFINE(PT_FR26, offsetof(struct pt_regs, fr[26]));
+       DEFINE(PT_FR27, offsetof(struct pt_regs, fr[27]));
+       DEFINE(PT_FR28, offsetof(struct pt_regs, fr[28]));
+       DEFINE(PT_FR29, offsetof(struct pt_regs, fr[29]));
+       DEFINE(PT_FR30, offsetof(struct pt_regs, fr[30]));
+       DEFINE(PT_FR31, offsetof(struct pt_regs, fr[31]));
+       DEFINE(PT_SR0, offsetof(struct pt_regs, sr[ 0]));
+       DEFINE(PT_SR1, offsetof(struct pt_regs, sr[ 1]));
+       DEFINE(PT_SR2, offsetof(struct pt_regs, sr[ 2]));
+       DEFINE(PT_SR3, offsetof(struct pt_regs, sr[ 3]));
+       DEFINE(PT_SR4, offsetof(struct pt_regs, sr[ 4]));
+       DEFINE(PT_SR5, offsetof(struct pt_regs, sr[ 5]));
+       DEFINE(PT_SR6, offsetof(struct pt_regs, sr[ 6]));
+       DEFINE(PT_SR7, offsetof(struct pt_regs, sr[ 7]));
+       DEFINE(PT_IASQ0, offsetof(struct pt_regs, iasq[0]));
+       DEFINE(PT_IASQ1, offsetof(struct pt_regs, iasq[1]));
+       DEFINE(PT_IAOQ0, offsetof(struct pt_regs, iaoq[0]));
+       DEFINE(PT_IAOQ1, offsetof(struct pt_regs, iaoq[1]));
+       DEFINE(PT_CR27, offsetof(struct pt_regs, cr27));
+       DEFINE(PT_ORIG_R28, offsetof(struct pt_regs, orig_r28));
+       DEFINE(PT_KSP, offsetof(struct pt_regs, ksp));
+       DEFINE(PT_KPC, offsetof(struct pt_regs, kpc));
+       DEFINE(PT_SAR, offsetof(struct pt_regs, sar));
+       DEFINE(PT_IIR, offsetof(struct pt_regs, iir));
+       DEFINE(PT_ISR, offsetof(struct pt_regs, isr));
+       DEFINE(PT_IOR, offsetof(struct pt_regs, ior));
+       DEFINE(PT_SIZE, sizeof(struct pt_regs));
+       DEFINE(PT_SZ_ALGN, align(sizeof(struct pt_regs), 64));
+       BLANK();
+       DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
+       DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+       DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
+       DEFINE(TI_SEGMENT, offsetof(struct thread_info, addr_limit));
+       DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
+       DEFINE(THREAD_SZ, sizeof(struct thread_info));
+       DEFINE(THREAD_SZ_ALGN, align(sizeof(struct thread_info), 64));
+       BLANK();
+       DEFINE(IRQSTAT_SIRQ_PEND, offsetof(irq_cpustat_t, __softirq_pending));
+       DEFINE(IRQSTAT_SZ, sizeof(irq_cpustat_t));
+       BLANK();
+       DEFINE(ICACHE_BASE, offsetof(struct pdc_cache_info, ic_base));
+       DEFINE(ICACHE_STRIDE, offsetof(struct pdc_cache_info, ic_stride));
+       DEFINE(ICACHE_COUNT, offsetof(struct pdc_cache_info, ic_count));
+       DEFINE(ICACHE_LOOP, offsetof(struct pdc_cache_info, ic_loop));
+       DEFINE(DCACHE_BASE, offsetof(struct pdc_cache_info, dc_base));
+       DEFINE(DCACHE_STRIDE, offsetof(struct pdc_cache_info, dc_stride));
+       DEFINE(DCACHE_COUNT, offsetof(struct pdc_cache_info, dc_count));
+       DEFINE(DCACHE_LOOP, offsetof(struct pdc_cache_info, dc_loop));
+       DEFINE(ITLB_SID_BASE, offsetof(struct pdc_cache_info, it_sp_base));
+       DEFINE(ITLB_SID_STRIDE, offsetof(struct pdc_cache_info, it_sp_stride));
+       DEFINE(ITLB_SID_COUNT, offsetof(struct pdc_cache_info, it_sp_count));
+       DEFINE(ITLB_OFF_BASE, offsetof(struct pdc_cache_info, it_off_base));
+       DEFINE(ITLB_OFF_STRIDE, offsetof(struct pdc_cache_info, it_off_stride));
+       DEFINE(ITLB_OFF_COUNT, offsetof(struct pdc_cache_info, it_off_count));
+       DEFINE(ITLB_LOOP, offsetof(struct pdc_cache_info, it_loop));
+       DEFINE(DTLB_SID_BASE, offsetof(struct pdc_cache_info, dt_sp_base));
+       DEFINE(DTLB_SID_STRIDE, offsetof(struct pdc_cache_info, dt_sp_stride));
+       DEFINE(DTLB_SID_COUNT, offsetof(struct pdc_cache_info, dt_sp_count));
+       DEFINE(DTLB_OFF_BASE, offsetof(struct pdc_cache_info, dt_off_base));
+       DEFINE(DTLB_OFF_STRIDE, offsetof(struct pdc_cache_info, dt_off_stride));
+       DEFINE(DTLB_OFF_COUNT, offsetof(struct pdc_cache_info, dt_off_count));
+       DEFINE(DTLB_LOOP, offsetof(struct pdc_cache_info, dt_loop));
+       BLANK();
+       return 0;
+}
diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c
new file mode 100644 (file)
index 0000000..b2b9e19
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Support for 32-bit Linux/Parisc ELF binaries on 64 bit kernels
+ *
+ * Copyright (C) 2000 John Marvin
+ * Copyright (C) 2000 Hewlett Packard Co.
+ *
+ * Heavily inspired from various other efforts to do the same thing
+ * (ia64,sparc64/mips64)
+ */
+
+/* Make sure include/asm-parisc/elf.h does the right thing */
+
+#define ELF_CLASS      ELFCLASS32
+
+typedef unsigned int elf_greg_t;
+
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/elfcore.h>
+#include "sys32.h"             /* struct timeval32 */
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+       struct elf_siginfo pr_info;     /* Info associated with signal */
+       short   pr_cursig;              /* Current signal */
+       unsigned int pr_sigpend;        /* Set of pending signals */
+       unsigned int pr_sighold;        /* Set of held signals */
+       pid_t   pr_pid;
+       pid_t   pr_ppid;
+       pid_t   pr_pgrp;
+       pid_t   pr_sid;
+       struct timeval32 pr_utime;      /* User time */
+       struct timeval32 pr_stime;      /* System time */
+       struct timeval32 pr_cutime;     /* Cumulative user time */
+       struct timeval32 pr_cstime;     /* Cumulative system time */
+       elf_gregset_t pr_reg;   /* GP registers */
+       int pr_fpvalid;         /* True if math co-processor being used.  */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+       char    pr_state;       /* numeric process state */
+       char    pr_sname;       /* char for pr_state */
+       char    pr_zomb;        /* zombie */
+       char    pr_nice;        /* nice val */
+       unsigned int pr_flag;   /* flags */
+       u16     pr_uid;
+       u16     pr_gid;
+       pid_t   pr_pid, pr_ppid, pr_pgrp, pr_sid;
+       /* Lots missing */
+       char    pr_fname[16];   /* filename of executable */
+       char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#define elf_addr_t     unsigned int
+#define init_elf_binfmt init_elf32_binfmt
+
+#define ELF_PLATFORM  ("PARISC32\0")
+
+#define ELF_CORE_COPY_REGS(dst, pt)    \
+       memset(dst, 0, sizeof(dst));    /* don't leak any "random" bits */ \
+       {       int i; \
+               for (i = 0; i < 32; i++) dst[i] = (elf_greg_t) pt->gr[i]; \
+               for (i = 0; i < 8; i++) dst[32 + i] = (elf_greg_t) pt->sr[i]; \
+       } \
+       dst[40] = (elf_greg_t) pt->iaoq[0]; dst[41] = (elf_greg_t) pt->iaoq[1]; \
+       dst[42] = (elf_greg_t) pt->iasq[0]; dst[43] = (elf_greg_t) pt->iasq[1]; \
+       dst[44] = (elf_greg_t) pt->sar;   dst[45] = (elf_greg_t) pt->iir; \
+       dst[46] = (elf_greg_t) pt->isr;   dst[47] = (elf_greg_t) pt->ior; \
+       dst[48] = (elf_greg_t) mfctl(22); dst[49] = (elf_greg_t) mfctl(0); \
+       dst[50] = (elf_greg_t) mfctl(24); dst[51] = (elf_greg_t) mfctl(25); \
+       dst[52] = (elf_greg_t) mfctl(26); dst[53] = (elf_greg_t) mfctl(27); \
+       dst[54] = (elf_greg_t) mfctl(28); dst[55] = (elf_greg_t) mfctl(29); \
+       dst[56] = (elf_greg_t) mfctl(30); dst[57] = (elf_greg_t) mfctl(31); \
+       dst[58] = (elf_greg_t) mfctl( 8); dst[59] = (elf_greg_t) mfctl( 9); \
+       dst[60] = (elf_greg_t) mfctl(12); dst[61] = (elf_greg_t) mfctl(13); \
+       dst[62] = (elf_greg_t) mfctl(10); dst[63] = (elf_greg_t) mfctl(15);
+
+/*
+ * We should probably use this macro to set a flag somewhere to indicate
+ * this is a 32 on 64 process. We could use PER_LINUX_32BIT, or we
+ * could set a processor dependent flag in the thread_struct.
+ */
+
+#define SET_PERSONALITY(ex, ibcs2) \
+       current->personality = PER_LINUX_32BIT
+
+#include "../../../fs/binfmt_elf.c"
index 713a8b3..646e4c1 100644 (file)
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/seq_file.h>
 
 #include <asm/pdc.h>
 #include <asm/cache.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm/processor.h>
+
+int split_tlb;
+int dcache_stride;
+int icache_stride;
 
 struct pdc_cache_info cache_info;
-#ifndef __LP64__
+#ifndef CONFIG_PA20
 static struct pdc_btlb_info btlb_info;
 #endif
 
-
-void __flush_page_to_ram(unsigned long address)
-{
-       __flush_dcache_range(address, PAGE_SIZE);
-       __flush_icache_range(address, PAGE_SIZE);
-}
-
-
-
-void flush_data_cache(void)
+#ifdef CONFIG_SMP
+void
+flush_data_cache(void)
 {
-       register unsigned long base   = cache_info.dc_base;
-       register unsigned long count  = cache_info.dc_count;
-       register unsigned long loop   = cache_info.dc_loop;
-       register unsigned long stride = cache_info.dc_stride;
-       register unsigned long addr;
-       register long i, j;
-
-       for(i=0,addr=base; i<count; i++,addr+=stride)
-               for(j=0; j<loop; j++)
-                       fdce(addr);
+       smp_call_function((void (*)(void *))flush_data_cache_local, NULL, 1, 1);
+       flush_data_cache_local();
 }
-               
-static inline void flush_data_tlb_space(void)
-{
-       unsigned long base   = cache_info.dt_off_base;
-       unsigned long count  = cache_info.dt_off_count;
-       unsigned long stride = cache_info.dt_off_stride;
-       unsigned long loop   = cache_info.dt_loop;
-
-       unsigned long addr;
-       long i,j;
-       
-       for(i=0,addr=base; i<count; i++,addr+=stride)
-               for(j=0; j<loop; j++)
-                       pdtlbe(addr);
-}
-
-
+#endif
 
-void flush_data_tlb(void)
+void
+flush_cache_all_local(void)
 {
-       unsigned long base   = cache_info.dt_sp_base;
-       unsigned long count  = cache_info.dt_sp_count;
-       unsigned long stride = cache_info.dt_sp_stride;
-       unsigned long space;
-       unsigned long old_sr1;
-       long i;
-       
-       old_sr1 = mfsp(1);
-       
-       for(i=0,space=base; i<count; i++, space+=stride) {
-               mtsp(space,1);
-               flush_data_tlb_space();
-       }
-
-       mtsp(old_sr1, 1);
+       flush_instruction_cache_local();
+       flush_data_cache_local();
 }
 
-static inline void flush_instruction_tlb_space(void)
-{
-       unsigned long base   = cache_info.it_off_base;
-       unsigned long count  = cache_info.it_off_count;
-       unsigned long stride = cache_info.it_off_stride;
-       unsigned long loop   = cache_info.it_loop;
-
-       unsigned long addr;
-       long i,j;
-       
-       for(i=0,addr=base; i<count; i++,addr+=stride)
-               for(j=0; j<loop; j++)
-                       pitlbe(addr);
-}
+/* flushes EVERYTHING (tlb & cache) */
 
-void flush_instruction_tlb(void)
+void
+flush_all_caches(void)
 {
-       unsigned long base   = cache_info.it_sp_base;
-       unsigned long count  = cache_info.it_sp_count;
-       unsigned long stride = cache_info.it_sp_stride;
-       unsigned long space;
-       unsigned long old_sr1;
-       unsigned int i;
-       
-       old_sr1 = mfsp(1);
-       
-       for(i=0,space=base; i<count; i++, space+=stride) {
-               mtsp(space,1);
-               flush_instruction_tlb_space();
-       }
-
-       mtsp(old_sr1, 1);
+       flush_cache_all();
+       flush_tlb_all();
 }
 
-
-void __flush_tlb_space(unsigned long space)
+void
+update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
-       unsigned long old_sr1;
-
-       old_sr1 = mfsp(1);
-       mtsp(space, 1);
-       
-       flush_data_tlb_space();
-       flush_instruction_tlb_space();
-
-       mtsp(old_sr1, 1);
-}
+       struct page *page = pte_page(pte);
 
+       if (VALID_PAGE(page) && page->mapping &&
+           test_bit(PG_dcache_dirty, &page->flags)) {
 
-void flush_instruction_cache(void)
-{
-       register unsigned long base   = cache_info.ic_base;
-       register unsigned long count  = cache_info.ic_count;
-       register unsigned long loop   = cache_info.ic_loop;
-       register unsigned long stride = cache_info.ic_stride;
-       register unsigned long addr;
-       register long i, j;
-       unsigned long old_sr1;
-       
-       old_sr1 = mfsp(1);
-       mtsp(0,1);
-
-       /*
-        * Note: fice instruction has 3 bit space field, so one must
-        *       be specified (otherwise you are justing using whatever
-        *       happens to be in sr0).
-        */
-
-       for(i=0,addr=base; i<count; i++,addr+=stride)
-               for(j=0; j<loop; j++)
-                       fice(addr);
-
-       mtsp(old_sr1, 1);
-}
-
-/* not yet ... fdc() needs to be implemented in cache.h !
-void flush_datacache_range( unsigned int base, unsigned int end )
-{
-    register long offset,offset_add;
-    offset_add = ( (1<<(cache_info.dc_conf.cc_block-1)) * 
-                   cache_info.dc_conf.cc_line ) << 4;
-    for (offset=base; offset<=end; offset+=offset_add)
-       fdc(space,offset);
-    fdc(space,end);
-}
-*/
-
-/* flushes code and data-cache */
-void flush_all_caches(void)
-{
-       flush_instruction_cache();
-       flush_data_cache();
-
-       flush_instruction_tlb();
-       flush_data_tlb();
-
-       asm volatile("sync");
-       asm volatile("syncdma");
-       asm volatile("sync");
+               flush_kernel_dcache_page(page_address(page));
+               clear_bit(PG_dcache_dirty, &page->flags);
+       }
 }
 
-int get_cache_info(char *buffer)
+void
+show_cache_info(struct seq_file *m)
 {
-       char *p = buffer;
-
-       p += sprintf(p, "I-cache\t\t: %ld KB\n", 
+       seq_printf(m, "I-cache\t\t: %ld KB\n", 
                cache_info.ic_size/1024 );
-       p += sprintf(p, "D-cache\t\t: %ld KB (%s)%s\n", 
+       seq_printf(m, "D-cache\t\t: %ld KB (%s)%s\n", 
                cache_info.dc_size/1024,
                (cache_info.dc_conf.cc_wt ? "WT":"WB"),
                (cache_info.dc_conf.cc_sh ? " - shared I/D":"")
        );
 
-       p += sprintf(p, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
+       seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
                cache_info.it_size,
                cache_info.dt_size,
                cache_info.dt_conf.tc_sh ? " - shared with ITLB":""
        );
                
-#ifndef __LP64__
+#ifndef CONFIG_PA20
        /* BTLB - Block TLB */
        if (btlb_info.max_size==0) {
-               p += sprintf(p, "BTLB\t\t: not supported\n" );
+               seq_printf(m, "BTLB\t\t: not supported\n" );
        } else {
-               p += sprintf(p, 
+               seq_printf(m, 
                "BTLB fixed\t: max. %d pages, pagesize=%d (%dMB)\n"
                "BTLB fix-entr.\t: %d instruction, %d data (%d combined)\n"
                "BTLB var-entr.\t: %d instruction, %d data (%d combined)\n",
@@ -225,29 +110,117 @@ int get_cache_info(char *buffer)
                );
        }
 #endif
-
-       return p - buffer;
 }
 
-
 void __init 
-cache_init(void)
+parisc_cache_init(void)
 {
        if(pdc_cache_info(&cache_info)<0)
-               panic("cache_init: pdc_cache_info failed");
+               panic("parisc_cache_init: pdc_cache_info failed");
 
 #if 0
-       printk("ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
+       printk(KERN_DEBUG "ic_size %lx dc_size %lx it_size %lx pdc_cache_info %d*long pdc_cache_cf %d\n",
            cache_info.ic_size,
            cache_info.dc_size,
            cache_info.it_size,
            sizeof (struct pdc_cache_info) / sizeof (long),
            sizeof (struct pdc_cache_cf)
        );
+
+       printk(KERN_DEBUG "dc base %x dc stride %x dc count %x dc loop %d\n",
+           cache_info.dc_base,
+           cache_info.dc_stride,
+           cache_info.dc_count,
+           cache_info.dc_loop);
+
+       printk(KERN_DEBUG "dc conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n",
+           cache_info.dc_conf.cc_alias,
+           cache_info.dc_conf.cc_block,
+           cache_info.dc_conf.cc_line,
+           cache_info.dc_conf.cc_wt,
+           cache_info.dc_conf.cc_sh,
+           cache_info.dc_conf.cc_cst,
+           cache_info.dc_conf.cc_assoc);
+
+       printk(KERN_DEBUG "ic conf: alias %d block %d line %d wt %d sh %d cst %d assoc %d\n",
+           cache_info.ic_conf.cc_alias,
+           cache_info.ic_conf.cc_block,
+           cache_info.ic_conf.cc_line,
+           cache_info.ic_conf.cc_wt,
+           cache_info.ic_conf.cc_sh,
+           cache_info.ic_conf.cc_cst,
+           cache_info.ic_conf.cc_assoc);
+
+       printk(KERN_DEBUG "dt conf: sh %d page %d cst %d aid %d pad1 %d \n",
+           cache_info.dt_conf.tc_sh,
+           cache_info.dt_conf.tc_page,
+           cache_info.dt_conf.tc_cst,
+           cache_info.dt_conf.tc_aid,
+           cache_info.dt_conf.tc_pad1);
+
+       printk(KERN_DEBUG "it conf: sh %d page %d cst %d aid %d pad1 %d \n",
+           cache_info.it_conf.tc_sh,
+           cache_info.it_conf.tc_page,
+           cache_info.it_conf.tc_cst,
+           cache_info.it_conf.tc_aid,
+           cache_info.it_conf.tc_pad1);
 #endif
-#ifndef __LP64__
+
+       split_tlb = 0;
+       if (cache_info.dt_conf.tc_sh == 0 || cache_info.dt_conf.tc_sh == 2) {
+
+           if (cache_info.dt_conf.tc_sh == 2)
+               printk(KERN_WARNING "Unexpected TLB configuration. "
+                       "Will flush I/D separately (could be optimized).\n");
+
+           split_tlb = 1;
+       }
+
+       dcache_stride = ( (1<<(cache_info.dc_conf.cc_block+3)) *
+                        cache_info.dc_conf.cc_line );
+       icache_stride = ( (1<<(cache_info.ic_conf.cc_block+3)) *
+                        cache_info.ic_conf.cc_line );
+#ifndef CONFIG_PA20
        if(pdc_btlb_info(&btlb_info)<0) {
                memset(&btlb_info, 0, sizeof btlb_info);
        }
 #endif
+
+       if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) {
+               printk(KERN_WARNING "Only equivalent aliasing supported\n");
+#ifndef CONFIG_SMP
+               panic("SMP kernel required to avoid non-equivalent aliasing");
+#endif
+       }
+}
+
+void disable_sr_hashing(void)
+{
+    int srhash_type;
+
+    if (boot_cpu_data.cpu_type == pcxl2)
+       return; /* pcxl2 doesn't support space register hashing */
+
+    switch (boot_cpu_data.cpu_type) {
+
+    case pcx:
+       BUG(); /* We shouldn't get here. code in setup.c should prevent it */
+       return;
+
+    case pcxs:
+    case pcxt:
+    case pcxt_:
+       srhash_type = SRHASH_PCXST;
+       break;
+
+    case pcxl:
+       srhash_type = SRHASH_PCXL;
+       break;
+
+    default: /* Currently all PA2.0 machines use the same ins. sequence */
+       srhash_type = SRHASH_PA20;
+       break;
+    }
+
+    disable_sr_hashing_asm(srhash_type);
 }
index ba93bbd..bda0adb 100644 (file)
 /*
-
-drivers.c
-
-Copyright (c) 1999 The Puffin Group 
-
-This is a collection of routines intended to register all the devices
-in a system, and register device drivers.
-
-*/
+ * drivers.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Copyright (c) 1999 The Puffin Group
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
+ * Copyright (c) 2001 Helge Deller <deller@gmx.de>
+ * 
+ * The file handles registering devices and drivers, then matching them.
+ * It's the closest we get to a dating agency.
+ */
 
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
+#include <asm/gsc.h>
 
+/* See comments in include/asm-parisc/pci.h */
+struct pci_dma_ops *hppa_dma_ops;
 
-extern struct hp_hardware *parisc_get_reference(
-       unsigned short hw_type, unsigned long hversion, 
-       unsigned long sversion );
+static struct parisc_driver *pa_drivers;
+static struct parisc_device root;
 
+/* This lock protects the pa_drivers list _only_ since all parisc_devices
+ * are registered before smp_init() is called.  If you wish to add devices
+ * after that, this muct be serialised somehow.  I recommend a semaphore
+ * rather than a spinlock since driver ->probe functions are allowed to
+ * sleep (for example when allocating memory).
+ */
+static spinlock_t pa_lock = SPIN_LOCK_UNLOCKED;
 
-/* I'm assuming there'll never be 64 devices.  We should probably make 
-   this more flexible.  */
+#define for_each_padev(dev) \
+       for (dev = root.child; dev != NULL; dev = next_dev(dev))
 
-#define MAX_DEVICES 64
+#define check_dev(dev) \
+       (dev->id.hw_type != HPHW_FAULTY) ? dev : next_dev(dev)
 
-unsigned int num_devices = 0;
+/**
+ * next_dev - enumerates registered devices
+ * @dev: the previous device returned from next_dev
+ *
+ * next_dev does a depth-first search of the tree, returning parents
+ * before children.  Returns NULL when there are no more devices.
+ */
+struct parisc_device *next_dev(struct parisc_device *dev)
+{
+       if (dev->child) {
+               return check_dev(dev->child);
+       } else if (dev->sibling) {
+               return dev->sibling;
+       }
 
-struct hp_device devices[MAX_DEVICES];
+       /* Exhausted tree at this level, time to go up. */
+       do {
+               dev = dev->parent;
+               if (dev && dev->sibling)
+                       return dev->sibling;
+       } while (dev != &root);
 
-static unsigned long pdc_result[32] __attribute__ ((aligned (16))) = {0,0,0,0};
-static  u8 iodc_data[32] __attribute__ ((aligned (64)));
+       return NULL;
+}
 
-/*
- *     XXX should we be using a locked array ?
+/**
+ * match_device - Report whether this driver can handle this device
+ * @driver: the PA-RISC driver to try
+ * @dev: the PA-RISC device to try
  */
-int register_driver(struct pa_iodc_driver *driver)
+static int match_device(struct parisc_driver *driver, struct parisc_device *dev)
 {
-       unsigned int i;
-       struct hp_device * device;
+       const struct parisc_device_id *ids;
 
-       for (;driver->check;driver++)  {
+       for (ids = driver->id_table; ids->sversion; ids++) {
+               if ((ids->sversion != SVERSION_ANY_ID) &&
+                   (ids->sversion != dev->id.sversion))
+                       continue;
 
-               for (i=0;i<num_devices;i++) {
-                       device = &devices[i];
+               if ((ids->hw_type != HWTYPE_ANY_ID) &&
+                   (ids->hw_type != dev->id.hw_type))
+                       continue;
 
-                       if (device->managed) continue;
+               if ((ids->hversion != HVERSION_ANY_ID) &&
+                   (ids->hversion != dev->id.hversion))
+                       continue;
 
-                       if ((driver->check & DRIVER_CHECK_HWTYPE) &&
-                           (driver->hw_type != device->hw_type))
-                               continue;
-                       if ((driver->check & DRIVER_CHECK_HVERSION) &&
-                           (driver->hversion != device->hversion))
-                               continue;
-                       if ((driver->check & DRIVER_CHECK_HVERSION_REV) &&
-                           (driver->hversion_rev != device->hversion_rev))
-                               continue;
-                       if ((driver->check & DRIVER_CHECK_SVERSION) &&
-                           (driver->sversion != device->sversion))
-                               continue;
-                       if ((driver->check & DRIVER_CHECK_SVERSION_REV) &&
-                           (driver->sversion_rev != device->sversion_rev))
-                               continue;
-                       if ((driver->check & DRIVER_CHECK_OPT) &&
-                           (driver->opt != device->opt))
-                               continue;
-                       if ( (*driver->callback)(device,driver) ==0) {
-                               device->managed=1;
-                       } else {
-                               printk("Warning : device (%d, 0x%x, 0x%x, 0x%x, 0x%x) NOT claimed by %s %s\n",
-                                       device->hw_type,
-                                       device->hversion, device->hversion_rev,
-                                       device->sversion, device->sversion_rev,
-                                       driver->name, driver->version);
-                       }
+               return 1;
+       }
+       return 0;
+}
+
+static void claim_device(struct parisc_driver *driver, struct parisc_device *dev)
+{
+       dev->driver = driver;
+       request_mem_region(dev->hpa, 0x1000, driver->name);
+}
+
+/**
+ * register_parisc_driver - Register this driver if it can handle a device
+ * @driver: the PA-RISC driver to try
+ */
+int register_parisc_driver(struct parisc_driver *driver)
+{
+       struct parisc_device *device;
+
+       if (driver->next) {
+               printk(KERN_WARNING 
+                      "BUG: Skipping previously registered driver: %s\n",
+                      driver->name);
+               return 1;
+       }
+
+       for_each_padev(device) {
+               if (device->driver)
+                       continue;
+               if (!match_device(driver, device))
+                       continue;
+
+               if (driver->probe(device) < 0)
+                       continue;
+               claim_device(driver, device);
+       }
+
+       /* Note that the list is in reverse order of registration.  This
+        * may be significant if we ever actually support hotplug and have
+        * multiple drivers capable of claiming the same chip.
+        */
+
+       spin_lock(&pa_lock);
+       driver->next = pa_drivers;
+       pa_drivers = driver;
+       spin_unlock(&pa_lock);
+
+       return 0;
+}
+
+/**
+ * count_parisc_driver - count # of devices this driver would match
+ * @driver: the PA-RISC driver to try
+ *
+ * Use by IOMMU support to "guess" the right size IOPdir.
+ * Formula is something like memsize/(num_iommu * entry_size).
+ */
+int count_parisc_driver(struct parisc_driver *driver)
+{
+       struct parisc_device *device;
+       int cnt = 0;
+
+       for_each_padev(device) {
+               if (match_device(driver, device))
+                       cnt++;
+       }
+
+       return cnt;
+}
+
+
+
+/**
+ * unregister_parisc_driver - Unregister this driver from the list of drivers
+ * @driver: the PA-RISC driver to unregister
+ */
+int unregister_parisc_driver(struct parisc_driver *driver)
+{
+       struct parisc_device *dev;
+
+       spin_lock(&pa_lock);
+
+       if (pa_drivers == driver) {
+               /* was head of list - update head */
+               pa_drivers = driver->next;
+       } else {
+               struct parisc_driver *prev = pa_drivers;
+
+               while (prev && driver != prev->next) {
+                       prev = prev->next;
+               }
+
+               if (!prev) {
+                       printk(KERN_WARNING "unregister_parisc_driver: %s wasn't registered\n", driver->name);
+               } else {
+                       /* Drop driver from list */
+                       prev->next = driver->next;
+                       driver->next = NULL;
                }
+
        }
+
+       spin_unlock(&pa_lock);
+
+       for_each_padev(dev) {
+               if (dev->driver != driver)
+                       continue;
+               dev->driver = NULL;
+               release_mem_region(dev->hpa, 0x1000);
+       }
+
        return 0;
 }
 
+static struct parisc_device *find_device_by_addr(unsigned long hpa)
+{
+       struct parisc_device *dev;
+       for_each_padev(dev) {
+               if (dev->hpa == hpa)
+                       return dev;
+       }
+       return NULL;
+}
+
+/**
+ * find_pa_parent_type - Find a parent of a specific type
+ * @dev: The device to start searching from
+ * @type: The device type to search for.
+ *
+ * Walks up the device tree looking for a device of the specified type.
+ * If it finds it, it returns it.  If not, it returns NULL.
+ */
+const struct parisc_device *find_pa_parent_type(const struct parisc_device *dev, int type)
+{
+       while (dev != &root) {
+               if (dev->id.hw_type == type)
+                       return dev;
+               dev = dev->parent;
+       }
+
+       return NULL;
+}
+
+static void
+get_node_path(struct parisc_device *dev, struct hardware_path *path)
+{
+       int i = 5;
+       memset(&path->bc, -1, 6);
+       while (dev != &root) {
+               path->bc[i--] = dev->hw_path;
+               dev = dev->parent;
+       }
+}
 
-struct hp_device * register_module(void *hpa)
+static char *print_hwpath(struct hardware_path *path, char *output)
 {
+       int i;
+       for (i = 0; i < 6; i++) {
+               if (path->bc[i] == -1)
+                       continue;
+               output += sprintf(output, "%u/", (unsigned char) path->bc[i]);
+       }
+       output += sprintf(output, "%u", (unsigned char) path->mod);
+       return output;
+}
 
-       struct hp_device * d;
+/**
+ * print_pa_hwpath - Returns hardware path for PA devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PA device.  This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pa_hwpath(struct parisc_device *dev, char *output)
+{
+       struct hardware_path path;
+
+       get_node_path(dev->parent, &path);
+       path.mod = dev->hw_path;
+       return print_hwpath(&path, output);
+}
+
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+/**
+ * get_pci_node_path - Returns hardware path for PCI devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the hardware_path structure with the route to
+ * the specified PCI device.  This structure is suitable for passing to
+ * PDC calls.
+ */
+void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path)
+{
+       struct pci_bus *bus;
+       const struct parisc_device *padev;
+       int i = 5;
+
+       memset(&path->bc, -1, 6);
+       path->mod = PCI_FUNC(dev->devfn);
+       path->bc[i--] = PCI_SLOT(dev->devfn);
+       for (bus = dev->bus; bus->parent; bus = bus->parent) {
+               unsigned int devfn = bus->self->devfn;
+               path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn) << 5);
+       }
+
+       padev = HBA_DATA(bus->sysdata)->dev;
+       while (padev != &root) {
+               path->bc[i--] = padev->hw_path;
+               padev = padev->parent;
+       }
+}
+
+/**
+ * print_pci_hwpath - Returns hardware path for PCI devices
+ * dev: The device to return the path for
+ * output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PCI device.  This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pci_hwpath(struct pci_dev *dev, char *output)
+{
+       struct hardware_path path;
+
+       get_pci_node_path(dev, &path);
+       return print_hwpath(&path, output);
+}
+#endif /* defined(CONFIG_PCI) || defined(CONFIG_ISA) */
+
+
+struct parisc_device * create_tree_node(char id, struct parisc_device *parent,
+               struct parisc_device **insert)
+{
+       struct parisc_device *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+       memset(dev, 0, sizeof(*dev));
+       dev->hw_path = id;
+       dev->id.hw_type = HPHW_FAULTY;
+       dev->parent = parent;
+       dev->sibling = *insert;
+       *insert = dev;
+       return dev;
+}
+
+/**
+ * alloc_tree_node - returns a device entry in the iotree
+ * @parent: the parent node in the tree
+ * @id: the element of the module path for this entry
+ *
+ * Checks all the children of @parent for a matching @id.  If none
+ * found, it allocates a new device and returns it.
+ */
+struct parisc_device *
+alloc_tree_node(struct parisc_device *parent, char id)
+{
+       struct parisc_device *prev;
+       if ((!parent->child) || (parent->child->hw_path > id)) {
+               return create_tree_node(id, parent, &parent->child);
+       }
+
+       prev = parent->child;
+       if (prev->hw_path == id)
+               return prev;
+
+       while (prev->sibling && prev->sibling->hw_path < id) {
+               prev = prev->sibling;
+       }
+
+       if ((prev->sibling) && (prev->sibling->hw_path == id))
+               return prev->sibling;
+
+       return create_tree_node(id, parent, &prev->sibling);
+}
+
+static struct parisc_device *find_parisc_device(struct hardware_path *modpath)
+{
+       int i;
+       struct parisc_device *parent = &root;
+       for (i = 0; i < 6; i++) {
+               if (modpath->bc[i] == -1)
+                       continue;
+               parent = alloc_tree_node(parent, modpath->bc[i]);
+       }
+       return alloc_tree_node(parent, modpath->mod);
+}
+
+struct parisc_device *
+alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path)
+{
        int status;
+       unsigned long bytecnt;
+       u8 iodc_data[32];
+       struct parisc_device *dev;
+       const char *name;
+
+       /* Check to make sure this device has not already been added - Ryan */
+       if (find_device_by_addr(hpa) != NULL)
+               return NULL;
 
-       d = &devices[num_devices];
-       status = pdc_iodc_read(&pdc_result,hpa,0,&iodc_data,32 );
-       if (status !=PDC_RET_OK) {
-               /* There is no device here, so we'll skip it */
+       status = pdc_iodc_read(&bytecnt, hpa, 0, &iodc_data, 32);
+       if (status != PDC_OK)
+               return NULL;
+
+       dev = find_parisc_device(mod_path);
+       if (dev->id.hw_type != HPHW_FAULTY) {
+               char p[64];
+               print_pa_hwpath(dev, p);
+               printk("Two devices have hardware path %s.  Please file a bug with HP.\n"
+                       "In the meantime, you could try rearranging your cards.\n", p);
+               return NULL;
+       }
+
+       dev->id.hw_type = iodc_data[3] & 0x1f;
+       dev->id.hversion = (iodc_data[0] << 4) | ((iodc_data[1] & 0xf0) >> 4);
+       dev->id.hversion_rev = iodc_data[1] & 0x0f;
+       dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
+                       (iodc_data[5] << 8) | iodc_data[6];
+       dev->hpa = hpa;
+       name = parisc_hardware_description(&dev->id);
+       if (name) {
+               strncpy(dev->name, name, sizeof(dev->name)-1);
+       }
+
+       return dev;
+}
+
+/**
+ * register_parisc_device - Locate a driver to manage this device.
+ * @dev: The parisc device.
+ *
+ * Search the driver list for a driver that is willing to manage
+ * this device.
+ */
+int register_parisc_device(struct parisc_device *dev)
+{
+       struct parisc_driver *driver;
+
+       if (!dev)
                return 0;
+
+       if (dev->driver)
+               return 1;
+       
+       spin_lock(&pa_lock);
+
+       /* Locate a driver which agrees to manage this device.  */
+       for (driver = pa_drivers; driver; driver = driver->next) {
+               if (!match_device(driver,dev))
+                       continue;
+               if (driver->probe(dev) == 0)
+                       break;
        }
 
-       d->hw_type = iodc_data[3]&0x1f;
-       d->hversion = (iodc_data[0]<<4)|((iodc_data[1]&0xf0)>>4);
-       d->sversion = 
-               ((iodc_data[4]&0x0f)<<16)|(iodc_data[5]<<8)|(iodc_data[6]);
-       d->hversion_rev = iodc_data[1]&0x0f;
-       d->sversion_rev = iodc_data[4]>>4;
-       d->opt = iodc_data[7];
-       d->hpa = hpa;
-       d->managed=0;
-       d->reference = parisc_get_reference(d->hw_type, d->hversion, 
-                                                               d->sversion);
-               
-       num_devices++;  
+       if (driver != NULL) {
+               claim_device(driver, dev);
+       }
+       spin_unlock(&pa_lock);
+       return driver != NULL;
+}
+
+#define BC_PORT_MASK 0x8
+#define BC_LOWER_PORT 0x8
 
-       return d;
-}      
+#define BUS_CONVERTER(dev) \
+        ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
 
-void print_devices(char * buf) {
+#define IS_LOWER_PORT(dev) \
+        ((gsc_readl(&((struct bc_module *)dev->hpa)->io_status) \
+                & BC_PORT_MASK) == BC_LOWER_PORT)
+
+#define READ_IO_IO_LOW(dev) \
+       (dev->id.hw_type == HPHW_IOA ? \
+               __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low) << 16 : \
+               __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low))
+
+static void walk_native_bus(unsigned long addr, struct parisc_device *parent);
+void walk_lower_bus(struct parisc_device *dev)
+{
 
+       if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
+               return;
+
+       walk_native_bus((unsigned long)(signed int)READ_IO_IO_LOW(dev), dev);
+}
+
+#define MAX_NATIVE_DEVICES 64
+#define NATIVE_DEVICE_OFFSET 0x1000
+
+/**
+ * walk_native_bus -- Probe a bus for devices
+ * @addr: Base address of this bus.
+ * 
+ * A native bus (eg Runway or GSC) may have up to 64 devices on it,
+ * spaced at intervals of 0x1000 bytes.  PDC may not inform us of these
+ * devices, so we have to probe for them.  Unfortunately, we may find
+ * devices which are not physically connected (such as extra serial &
+ * keyboard ports).  This problem is not yet solved.
+ */
+static void walk_native_bus(unsigned long addr, struct parisc_device *parent)
+{
        int i;
-       struct hp_device *d;
-       printk("Found devices:\n");
-       for (i=0;i<num_devices;i++) {   
-               d = &devices[i];
-               printk(KERN_INFO 
-               "%d. %s (%d) at 0x%p, versions 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 
-               i+1,
-               (d->reference) ? d->reference->name : "Unknown device",
-               d->hw_type,d->hpa, d->hversion, d->hversion_rev,
-               d->sversion, d->sversion_rev, d->opt);
+       struct hardware_path path;
+
+       get_node_path(parent, &path);
+       for (i = 0; i < MAX_NATIVE_DEVICES; i++) {
+               unsigned long hpa = (addr + i * NATIVE_DEVICE_OFFSET);
+               struct parisc_device *dev;
 
+               /* Was the device already added by Firmware? */
+               dev = find_device_by_addr(hpa);
+               if (!dev) {
+                       path.mod = i;
+                       dev = alloc_pa_dev(hpa, &path);
+                       if (!dev)
+                               continue;
+
+                       register_parisc_device(dev);
+               }
+               walk_lower_bus(dev);
        }
-       printk("That's a total of %d devices.\n",num_devices);
 }
 
+#define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
 
+/**
+ * walk_central_bus - Find devices attached to the central bus
+ *
+ * PDC doesn't tell us about all devices in the system.  This routine
+ * finds devices connected to the central bus.
+ */
+void walk_central_bus(void)
+{
+       walk_native_bus(CENTRAL_BUS_ADDR, &root);
+}
+
+void fixup_child_irqs(struct parisc_device *parent, int base,
+                       int (*choose_irq)(struct parisc_device *))
+{
+       struct parisc_device *dev;
+
+       if (!parent->child)
+               return;
+
+       for (dev = check_dev(parent->child); dev; dev = dev->sibling) {
+               int irq = choose_irq(dev);
+               if (irq > 0) {
+#ifdef __LP64__
+                       irq += 32;
+#endif
+                       dev->irq = base + irq;
+               }
+       }
+}
+
+static void print_parisc_device(struct parisc_device *dev)
+{
+       char hw_path[64];
+       static int count;
+
+       print_pa_hwpath(dev, hw_path);
+       printk(KERN_INFO "%d. %s (%d) at 0x%lx [%s], versions 0x%x, 0x%x, 0x%x",
+               ++count, dev->name, dev->id.hw_type, dev->hpa, hw_path,
+               dev->id.hversion, dev->id.hversion_rev, dev->id.sversion);
+
+       if (dev->num_addrs) {
+               int k;
+               printk(",  additional addresses: ");
+               for (k = 0; k < dev->num_addrs; k++)
+                       printk("0x%lx ", dev->addr[k]);
+       }
+       printk("\n");
+}
+
+void print_subdevices(struct parisc_device *parent)
+{
+       struct parisc_device *dev;
+       for (dev = parent->child; dev != parent->sibling; dev = next_dev(dev)) {
+               print_parisc_device(dev);
+       }
+}
+
+/**
+ * print_parisc_devices - Print out a list of devices found in this system
+ */
+void print_parisc_devices(void)
+{
+       struct parisc_device *dev;
+       for_each_padev(dev) {
+               print_parisc_device(dev);
+       }
+}
index dbc889a..156e56e 100644 (file)
@@ -1,5 +1,5 @@
-/*------------------------------------------------------------------------------
- * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  *
  * kernel entry points (interruptions, system call wrappers)
  *  Copyright (C) 1999,2000 Philipp Rumpf 
  */
 
 #include <linux/config.h>
-#include <asm/offset.h>
-
-/* the following is the setup i think we should follow:
- * whenever the CPU is interruptible, the following has to be true:
- *  CR30 is the kernel sp or 0 if we currently use the kernel stack
- *  CR31 is the kernel gp */ 
+#include <asm/offsets.h>
 
 /* we have the following possibilities to act on an interruption:
  *  - handle in assembly and use shadowed registers only
  *  - save registers to kernel stack and handle in assembly or C */
 
-       .text
-
-#ifdef __LP64__
-       .level 2.0w
-#endif
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>      /* for LDREG/STREG defines */
 #include <asm/pgtable.h>
 #include <asm/psw.h>
 #include <asm/signal.h>
+#include <asm/unistd.h>
+#include <asm/thread_info.h>
 
 #ifdef __LP64__
-#define FRAME_SIZE     64
+#define FRAME_SIZE     128
+#define CMPIB           cmpib,*
+#define CMPB            cmpb,*
+
+       .level 2.0w
 #else
 #define FRAME_SIZE     64
+#define CMPIB           cmpib,
+#define CMPB            cmpb,
+
+       .level 2.0
+#endif
+
+       .import         pa_dbit_lock,data
+
+       /* space_to_prot macro creates a prot id from a space id */
+
+#if (SPACEID_SHIFT) == 0
+       .macro  space_to_prot spc prot
+       depd,z  \spc,62,31,\prot
+       .endm
+#else
+       .macro  space_to_prot spc prot
+       extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot
+       .endm
 #endif
 
        /* Switch to virtual mapping, trashing only %r1 */
-       .macro  virt_map rfi_type
-       mtsm    %r0
-       tovirt  %r29
-       tovirt  %r30
+       .macro  virt_map
+       rsm     PSW_SM_Q,%r0
+       tovirt_r1 %r29
        mfsp    %sr7, %r1
+       or,=    %r0,%r1,%r0 /* Only save sr7 in sr3 if sr7 != 0 */
        mtsp    %r1, %sr3
        mtsp    %r0, %sr4
        mtsp    %r0, %sr5
        mtsp    %r0, %sr7
        ldil    L%KERNEL_PSW, %r1
        ldo     R%KERNEL_PSW(%r1), %r1
-       LDIL_FIXUP(%r1)
        mtctl   %r1, %cr22
        mtctl   %r0, %cr17
        mtctl   %r0, %cr17
-       ldil    L%.+28, %r1
-       ldo     R%.+24(%r1), %r1
-       LDIL_FIXUP(%r1)
+       ldil    L%4f, %r1
+       ldo     R%4f(%r1), %r1
        mtctl   %r1, %cr18
        ldo     4(%r1), %r1
        mtctl   %r1, %cr18
-       \rfi_type
+       rfir
        nop
+4:
        .endm
 
-       .macro  get_stack
-       mfctl   %cr30, %r1 
-       comib,=,n 0, %r1, 0f   /* forward so predicted not taken */
+       /*
+        * The "get_stack" macros are responsible for determining the
+        * kernel stack value.
+        *
+        * For Faults:
+        *      If sr7 == 0
+        *          Already using a kernel stack, so call the
+        *          get_stack_use_r30 macro to push a pt_regs structure
+        *          on the stack, and store registers there.
+        *      else
+        *          Need to set up a kernel stack, so call the
+        *          get_stack_use_cr30 macro to set up a pointer
+        *          to the pt_regs structure contained within the
+        *          task pointer pointed to by cr30. Set the stack
+        *          pointer to point to the end of the task structure.
+        *
+        * For Interrupts:
+        *      If sr7 == 0
+        *          Already using a kernel stack, check to see if r30
+        *          is already pointing to the per processor interrupt
+        *          stack. If it is, call the get_stack_use_r30 macro
+        *          to push a pt_regs structure on the stack, and store
+        *          registers there. Otherwise, call get_stack_use_cr31
+        *          to get a pointer to the base of the interrupt stack
+        *          and push a pt_regs structure on that stack.
+        *      else
+        *          Need to set up a kernel stack, so call the
+        *          get_stack_use_cr30 macro to set up a pointer
+        *          to the pt_regs structure contained within the
+        *          task pointer pointed to by cr30. Set the stack
+        *          pointer to point to the end of the task structure.
+        *          N.B: We don't use the interrupt stack for the
+        *          first interrupt from userland, because signals/
+        *          resched's are processed when returning to userland,
+        *          and we can sleep in those cases.
+        *
+        * Note that we use shadowed registers for temps until
+        * we can save %r26 and %r29. %r26 is used to preserve
+        * %r8 (a shadowed register) which temporarily contained
+        * either the fault type ("code") or the eirr. We need
+        * to use a non-shadowed register to carry the value over
+        * the rfir in virt_map. We use %r26 since this value winds
+        * up being passed as the argument to either do_cpu_irq_mask
+        * or handle_interruption. %r29 is used to hold a pointer
+        * the register save area, and once again, it needs to
+        * be a non-shadowed register so that it survives the rfir.
+        *
+        * N.B. TASK_SZ_ALGN and PT_SZ_ALGN include space for a stack frame.
+        */
+
+       .macro  get_stack_use_cr30
 
        /* we save the registers in the task struct */
-       ldo     TASK_REGS(%r1), %r29
-       tophys  %r29
-       STREG   %r30, PT_GR30(%r29)
-       STREG   %r1,  PT_CR30(%r29)
-       ldo     TASK_SZ_ALGN(%r1), %r30
-       b       1f                  /* unconditional so predicted taken */      
-       mtctl   %r0,%cr30
-0:
-       /* we put a struct pt_regs on the stack and save the registers there */
-       copy    %r30,%r29
-       ldo     PT_SZ_ALGN(%r30),%r30
-       tophys  %r29
-       STREG   %r30,PT_GR30(%r29)
-       STREG   %r0,PT_CR30(%r29)
-1:
+
+       mfctl   %cr30, %r1
+       tophys  %r1,%r9
+       LDREG   0(%r9), %r1             /* thread_info -> task_struct */
+       tophys  %r1,%r9
+       ldo     TASK_REGS(%r9),%r9
+       STREG   %r30, PT_GR30(%r9)
+       STREG   %r29,PT_GR29(%r9)
+       STREG   %r26,PT_GR26(%r9)
+       copy    %r9,%r29
+       mfctl   %cr30, %r1
+       ldo     THREAD_SZ_ALGN(%r1), %r30
        .endm
 
-       .macro  rest_stack regs
-       LDREG   PT_CR30(\regs), %r1
-       comib,=,n 0, %r1, 2f/* forward so predicted not taken */
+       .macro  get_stack_use_r30
 
-       /* we restore the registers out of the task struct */
-       mtctl   %r1, %cr30
-       LDREG   PT_GR1(\regs), %r1
-       LDREG   PT_GR30(\regs),%r30
-       b       3f
-       LDREG   PT_GR29(\regs),%r29
-2:
-       /* we take a struct pt_regs off the stack */
-       LDREG   PT_GR1(\regs),  %r1
-       LDREG   PT_GR29(\regs), %r29
-       ldo     -PT_SZ_ALGN(%r30), %r30
-3:
-       .endm
+       /* we put a struct pt_regs on the stack and save the registers there */
 
-#ifdef OLD
-       /* fixme interruption handler */
-       .macro  def code
-       /* WARNING!!! THIS IS DEBUG CODE ONLY!!! */
-       b       unimplemented_64bitirq
-       ldi     \code, %r1
-       .align  32
+       tophys  %r30,%r9
+       STREG   %r30,PT_GR30(%r9)
+       ldo     PT_SZ_ALGN(%r30),%r30
+       STREG   %r29,PT_GR29(%r9)
+       STREG   %r26,PT_GR26(%r9)
+       copy    %r9,%r29
        .endm
 
-       /* Use def to enable break - KWDB wants em
-        * (calls traps.c:handle_interruption) */
-       .macro  pass_break code
+       .macro  rest_stack
+       LDREG   PT_GR1(%r29), %r1
+       LDREG   PT_GR30(%r29),%r30
+       LDREG   PT_GR29(%r29),%r29
+       .endm
 
-#else
        /* default interruption handler
         * (calls traps.c:handle_interruption) */
        .macro  def code
-#endif
-       mtctl   %r29, %cr31
-       mtctl   %r1,  %cr28
-       ldi     \code, %r1
        b       intr_save
-       mtctl   %r1, %cr29
+       ldi     \code, %r8
        .align  32
        .endm
 
        /* Interrupt interruption handler
-        * (calls irq.c:do_irq_mask) */
+        * (calls irq.c:do_cpu_irq_mask) */
        .macro  extint code
-       mtctl   %r29, %cr31
-       mtctl   %r1,  %cr28
-       mfctl   %cr23, %r1
-       mtctl   %r1, %cr23
        b       intr_extint
-       mtctl   %r1, %cr29
+       mfsp    %sr7,%r16
        .align  32
        .endm   
 
         */
 
        .macro  itlb_20 code
-
        mfctl   %pcsq, spc
 #ifdef __LP64__
        b       itlb_miss_20w
        .endm
        
 #ifndef __LP64__
-       /* nadtlb miss interruption handler (parisc 1.1 - 32 bit)
-        *
-        * Note: nadtlb misses will be treated
-        * as an ordinary dtlb miss for now.
-        *
-        */
+       /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */
 
        .macro  nadtlb_11 code
 
        mfctl   %isr,spc
-       b       dtlb_miss_11
+       b       nadtlb_miss_11
        mfctl   %ior,va
 
        .align          32
        .endm
 #endif
        
-       /* nadtlb miss interruption handler (parisc 2.0)
-        *
-        * Note: nadtlb misses will be treated
-        * as an ordinary dtlb miss for now.
-        *
-        */
+       /* nadtlb miss interruption handler (parisc 2.0) */
 
        .macro  nadtlb_20 code
 
        mfctl   %isr,spc
 #ifdef __LP64__
-       b       dtlb_miss_20w
+       b       nadtlb_miss_20w
 #else
-       b       dtlb_miss_20
+       b       nadtlb_miss_20
 #endif
        mfctl   %ior,va
 
         * fault_vector_11 and fault_vector_20 are on the
         * same page. This is only necessary as long as we
         * write protect the kernel text, which we may stop
-        * doing once we use large parge translations to cover
+        * doing once we use large page translations to cover
         * the static part of the kernel address space.
         */
 
-
        .export fault_vector_20
 
+       .text
+
        .align 4096
 
 fault_vector_20:
@@ -402,7 +427,11 @@ fault_vector_20:
        def             13
        def             14
        dtlb_20         15
+#if 0
        naitlb_20       16
+#else
+       def             16
+#endif
        nadtlb_20       17
        def             18
        def             19
@@ -446,7 +475,11 @@ fault_vector_11:
        def             13
        def             14
        dtlb_11         15
+#if 0
        naitlb_11       16
+#else
+       def             16
+#endif
        nadtlb_11       17
        def             18
        def             19
@@ -467,7 +500,7 @@ fault_vector_11:
 
        .import         handle_interruption,code
        .import         handle_real_interruption,code
-       .import         do_irq_mask,code
+       .import         do_cpu_irq_mask,code
        .import         parisc_stopkernel,code
        .import         cpu_irq_region,data
 
@@ -492,7 +525,8 @@ __kernel_thread:
        ldo     PT_SZ_ALGN(%r30),%r30
 #ifdef __LP64__
        /* Yo, function pointers in wide mode are little structs... -PB */
-       /* XXX FIXME do we need to honor the fptr's %dp value too? */
+       ldd     24(%r26), %r2
+       STREG   %r2, PT_GR27(%r1)       /* Store childs %dp */
        ldd     16(%r26), %r26
 #endif
        STREG   %r26, PT_GR26(%r1)  /* Store function & argument for child */
@@ -500,15 +534,17 @@ __kernel_thread:
        ldo     CLONE_VM(%r0), %r26   /* Force CLONE_VM since only init_mm */
        or      %r26, %r24, %r26      /* will have kernel mappings.      */
        copy    %r0, %r25
-       bl      do_fork_FIXME_NOW_RETURNS_TASK_STRUCT, %r2
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#endif
+       bl      do_fork, %r2
        copy    %r1, %r24
 
        /* Parent Returns here */
 
-       ldo     -PT_SZ_ALGN(%r30), %r30
-       LDREG   -RP_OFFSET(%r30), %r2
+       LDREG   -PT_SZ_ALGN-RP_OFFSET(%r30), %r2
        bv      %r0(%r2)
-       nop
+       ldo     -PT_SZ_ALGN(%r30), %r30
 
        /*
         * Child Returns here
@@ -520,11 +556,25 @@ __kernel_thread:
        .export ret_from_kernel_thread
 ret_from_kernel_thread:
 
-       LDREG   TASK_PT_GR26-TASK_SZ_ALGN(%r30), %r1
-       LDREG   TASK_PT_GR25-TASK_SZ_ALGN(%r30), %r26
+#if CONFIG_PREEMPT || CONFIG_SMP
+       /* Call schedule_tail first though */
+       bl      schedule_tail, %r2
+       nop
+#endif
+
+       LDREG   -THREAD_SZ_ALGN(%r30), %r1
+       LDREG   TASK_PT_GR25(%r1), %r26
+#ifdef __LP64__
+       LDREG   TASK_PT_GR27(%r1), %r27
+#endif
+       LDREG   TASK_PT_GR26(%r1), %r1
        ble     0(%sr7, %r1)
        copy    %r31, %r2
 
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+       loadgp                          /* Thread could have been in a module */
+#endif
        b       sys_exit
        ldi     0, %r26
 
@@ -532,23 +582,22 @@ ret_from_kernel_thread:
        .export __execve, code
 __execve:
        copy    %r2, %r15
-       copy    %r23, %r17
        copy    %r30, %r16
        ldo     PT_SZ_ALGN(%r30), %r30
        STREG   %r26, PT_GR26(%r16)
        STREG   %r25, PT_GR25(%r16)
        STREG   %r24, PT_GR24(%r16)
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#endif
        bl      sys_execve, %r2
        copy    %r16, %r26
 
-       comib,<>,n 0,%r28,__execve_failed
+       cmpib,=,n 0,%r28,intr_return    /* forward */
 
-       b       intr_return
-       STREG   %r17, PT_CR30(%r16)
-
-__execve_failed:
        /* yes, this will trap and die. */
        copy    %r15, %r2
+       copy    %r16, %r30
        bv      %r0(%r2)
        nop
 
@@ -567,16 +616,19 @@ _switch_to:
 
        ldil    L%_switch_to_ret, %r2
        ldo     R%_switch_to_ret(%r2), %r2
-       LDIL_FIXUP(%r2)
 
        STREG   %r2, TASK_PT_KPC(%r26)
        LDREG   TASK_PT_KPC(%r25), %r2
 
        STREG   %r30, TASK_PT_KSP(%r26)
        LDREG   TASK_PT_KSP(%r25), %r30
-
+#ifdef __LP64__
+       LDREG   8(%r25), %r25
+#else
+       LDREG   4(%r25), %r25
+#endif
        bv      %r0(%r2)
-       nop
+       mtctl   %r25,%cr30
 
 _switch_to_ret:
        mtctl   %r0, %cr0               /* Needed for single stepping */
@@ -587,27 +639,31 @@ _switch_to_ret:
        copy    %r26, %r28
 
        /*
-        * Common rfi return path for interruptions, kernel execve, and some
-        * syscalls.  The sys_rt_sigreturn syscall will return via this path
-        * if the signal was received when the process was running; if the
-        * process was blocked on a syscall then the normal syscall_exit
-        * path is used.  All syscalls for traced proceses exit via
-        * intr_restore.
-        * Note that the following code uses a "relied upon translation". See
-        * the parisc ACD for details. The ssm is necessary due to a PCXT bug.
+        * Common rfi return path for interruptions, kernel execve, and
+        * sys_rt_sigreturn (sometimes).  The sys_rt_sigreturn syscall will
+        * return via this path if the signal was received when the process
+        * was running; if the process was blocked on a syscall then the
+        * normal syscall_exit path is used.  All syscalls for traced
+        * proceses exit via intr_restore.
+        *
+        * XXX If any syscalls that change a processes space id ever exit
+        * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
+        * adjust IASQ[0..1].
+        *
+        * Note that the following code uses a "relied upon translation".
+        * See the parisc ACD for details. The ssm is necessary due to a
+        * PCXT bug.
         */
 
        .align 4096
 
        .export syscall_exit_rfi
 syscall_exit_rfi:
-       copy    %r30,%r16
-       /* FIXME! depi below has hardcoded dependency on kernel stack size */
-       depi    0,31,14,%r16 /* get task pointer */
+       mfctl   %cr30,%r16
+       LDREG   0(%r16), %r16           /* thread_info -> task_struct */
        ldo     TASK_REGS(%r16),%r16
        /* Force iaoq to userspace, as the user has had access to our current
-        * context via sigcontext.
-        * XXX do we need any other protection here?
+        * context via sigcontext. Also Filter the PSW for the same reason.
         */
        LDREG   PT_IAOQ0(%r16),%r19
        depi    3,31,2,%r19
@@ -615,57 +671,84 @@ syscall_exit_rfi:
        LDREG   PT_IAOQ1(%r16),%r19
        depi    3,31,2,%r19
        STREG   %r19,PT_IAOQ1(%r16)
-       
+       LDREG   PT_PSW(%r16),%r19
+       ldil    L%USER_PSW_MASK,%r1
+       ldo     R%USER_PSW_MASK(%r1),%r1
+#ifdef __LP64__
+       ldil    L%USER_PSW_HI_MASK,%r20
+       ldo     R%USER_PSW_HI_MASK(%r20),%r20
+       depd    %r20,31,32,%r1
+#endif
+       and     %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
+       ldil    L%USER_PSW,%r1
+       ldo     R%USER_PSW(%r1),%r1
+       or      %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
+       STREG   %r19,PT_PSW(%r16)
+
+       /*
+        * If we aren't being traced, we never saved space registers
+        * (we don't store them in the sigcontext), so set them
+        * to "proper" values now (otherwise we'll wind up restoring
+        * whatever was last stored in the task structure, which might
+        * be inconsistant if an interrupt occured while on the gateway
+        * page) Note that we may be "trashing" values the user put in
+        * them, but we don't support the the user changing them.
+        */
+
+       STREG   %r0,PT_SR2(%r16)
+       mfsp    %sr3,%r19
+       STREG   %r19,PT_SR0(%r16)
+       STREG   %r19,PT_SR1(%r16)
+       STREG   %r19,PT_SR3(%r16)
+       STREG   %r19,PT_SR4(%r16)
+       STREG   %r19,PT_SR5(%r16)
+       STREG   %r19,PT_SR6(%r16)
+       STREG   %r19,PT_SR7(%r16)
+
 intr_return:
+       ssm     PSW_SM_I, %r0
 
        /* Check for software interrupts */
 
        .import irq_stat,data
 
-       ldil    L%irq_stat,%r19
-       ldo     R%irq_stat(%r19),%r19
-       LDIL_FIXUP(%r19)
-
+       ldil    L%irq_stat,%r19
+       ldo     R%irq_stat(%r19),%r19
 #ifdef CONFIG_SMP
-       copy    %r30,%r1
-       /* FIXME! depi below has hardcoded dependency on kernel stack size */
-       depi    0,31,14,%r1 /* get task pointer */
-       ldw     TASK_PROCESSOR(%r1),%r20 /* get cpu # - int */
-#if (IRQSTAT_SZ == 32)
-       dep     %r20,26,27,%r20 /* shift left 5 bits */
+       mfctl   %cr30,%r1
+       ldw     TI_CPU(%r1),%r1 /* get cpu # - int */
+       /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
+       ** irq_stat[] is defined using ____cacheline_aligned.
+       */
+#ifdef __LP64__
+       shld    %r1, 6, %r20
 #else
-#error IRQSTAT_SZ changed, fix dep
-#endif /* IRQSTAT_SZ */
-       add     %r19,%r20,%r19
+       shlw    %r1, 5, %r20
+#endif
+       add     %r19,%r20,%r19  /* now have &irq_stat[smp_processor_id()] */
 #endif /* CONFIG_SMP */
 
-       ldw     IRQSTAT_SI_ACTIVE(%r19),%r20    /* hardirq.h: unsigned int */
-       ldw     IRQSTAT_SI_MASK(%r19),%r19      /* hardirq.h: unsigned int */
-       and     %r19,%r20,%r20
-       comib,<>,n 0,%r20,intr_do_softirq /* forward */
+       LDREG   IRQSTAT_SIRQ_PEND(%r19),%r20    /* hardirq.h: unsigned long */
+       cmpib,<>,n 0,%r20,intr_do_softirq /* forward */
 
 intr_check_resched:
 
        /* check for reschedule */
-       copy    %r30,%r1
-       /* FIXME! depi below has hardcoded dependency on kernel stack size */
-       depi    0,31,14,%r1 /* get task pointer */
-#error LDREG     TASK_NEED_RESCHED(%r1),%r19   /* sched.h: long need_resched */
-       comib,<>,n 0,%r19,intr_do_resched /* forward */
+       mfctl   %cr30,%r1
+       LDREG   TI_FLAGS(%r1),%r19      /* sched.h: TIF_NEED_RESCHED */
+       bb,<,n  %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
 
 intr_check_sig:
        /* As above */
-       copy    %r30,%r1
-       depi    0,31,14,%r1 /* get task pointer */
-#error ldw     TASK_SIGPENDING(%r1),%r19       /* sched.h: int sigpending */
-       comib,<>,n 0,%r19,intr_do_signal /* forward */
+       mfctl   %cr30,%r1
+       LDREG   TI_FLAGS(%r1),%r19      /* sched.h: TIF_SIGPENDING */
+       bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */
 
 intr_restore:
-       copy            %r16, %r29
-       ldo             PT_FR31(%r29), %r29
-       rest_fp         %r29
-       copy            %r16, %r29
-       rest_general    %r29
+       copy            %r16,%r29
+       ldo             PT_FR31(%r29),%r1
+       rest_fp         %r1
+       rest_general    %r29
        ssm             0,%r0
        nop
        nop
@@ -674,10 +757,10 @@ intr_restore:
        nop
        nop
        nop
-       tophys          %r29
-       mtsm            %r0
+       tophys_r1       %r29
+       rsm             (PSW_SM_Q|PSW_SM_P|PSW_SM_D|PSW_SM_I),%r0
        rest_specials   %r29
-       rest_stack      %r29
+       rest_stack
        rfi
        nop
        nop
@@ -691,88 +774,173 @@ intr_restore:
        .import do_softirq,code
 intr_do_softirq:
        bl      do_softirq,%r2
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#else
        nop
+#endif
        b       intr_check_resched
        nop
 
        .import schedule,code
 intr_do_resched:
        /* Only do reschedule if we are returning to user space */
-       LDREG     PT_SR7(%r16), %r20
-       comib,= 0,%r20,intr_restore /* backward */
+       LDREG   PT_IASQ0(%r16), %r20
+       CMPIB= 0,%r20,intr_restore /* backward */
+       nop
+       LDREG   PT_IASQ1(%r16), %r20
+       CMPIB= 0,%r20,intr_restore /* backward */
        nop
 
-       bl      schedule,%r2
-       ssm     PSW_SM_I, %r0
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#endif
+
+       ldil    L%intr_return, %r2
+       b       schedule
+       ldo     R%intr_return(%r2), %r2 /* return to intr_return, not here */
 
-       /* It's OK to leave I bit on */
-       b       intr_return /* start over if we got a resched */
-       nop
 
        .import do_signal,code
 intr_do_signal:
        /* Only do signals if we are returning to user space */
-       LDREG   PT_SR7(%r16), %r20
-       comib,= 0,%r20,intr_restore /* backward */
+       LDREG   PT_IASQ0(%r16), %r20
+       CMPIB= 0,%r20,intr_restore /* backward */
+       nop
+       LDREG   PT_IASQ1(%r16), %r20
+       CMPIB= 0,%r20,intr_restore /* backward */
        nop
 
        copy    %r0, %r24                       /* unsigned long in_syscall */
        copy    %r16, %r25                      /* struct pt_regs *regs */
        ssm     PSW_SM_I, %r0
-#error bl      do_signal,%r2
+#ifdef __LP64__
+       ldo     -16(%r30),%r29                  /* Reference param save area */
+#endif
+#warning TAUSQ FIXME, this is wrong
+       bl      do_signal,%r2
        copy    %r0, %r26                       /* sigset_t *oldset = NULL */
 
        b       intr_restore
        nop
 
-       /* CR28 - saved GR1
-        * CR29 - argument for do_irq_mask */
+       /*
+        * External interrupts.
+        */
 
-       /* External interrupts */
 intr_extint:
-       get_stack
+       CMPIB=,n 0,%r16,1f
+       get_stack_use_cr30
+       b,n 3f
+
+1:
+#if 0  /* Interrupt Stack support not working yet! */
+       mfctl   %cr31,%r1
+       copy    %r30,%r17
+       /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/
+#ifdef __LP64__
+       depdi   0,63,15,%r17
+#else
+       depi    0,31,15,%r17
+#endif
+       CMPB=,n %r1,%r17,2f
+       get_stack_use_cr31
+       b,n 3f
+#endif
+2:
+       get_stack_use_r30
+
+3:
        save_specials   %r29
-       virt_map        rfi
+       virt_map
        save_general    %r29
 
-       ldo             PT_FR0(%r29), %r24
-       save_fp         %r24
+       ldo     PT_FR0(%r29), %r24
+       save_fp %r24
        
        loadgp
 
-       copy            %r29, %r24      /* arg2 is pt_regs */
-       copy            %r29, %r16      /* save pt_regs */
-#ifdef CONFIG_KWDB
-       copy            %r29, %r3       /* KWDB - update frame pointer (gr3) */
-#endif
+       copy    %r29, %r25      /* arg1 is pt_regs */
+       copy    %r29, %r16      /* save pt_regs */
 
-       /* sorry to put this cruft in the interrupt path */
-       ldil            L%cpu_irq_region, %r25
-       ldo             R%cpu_irq_region(%r25), %r25
-       bl              do_irq_mask,%r2
 #ifdef __LP64__
-       LDIL_FIXUP(%r25)
+       ldo     -16(%r30),%r29  /* Reference param save area */
 #else
        nop
 #endif
-
-       b               intr_return
-       nop
+       
+       /*
+        * We need to either load the CPU's ID or IRQ region.
+        * Until we have "per CPU" IRQ regions, this is easy.
+        */
+       ldil    L%cpu_irq_region, %r26
+       ldil    L%intr_return, %r2
+       ldo     R%cpu_irq_region(%r26), %r26
+       
+       b       do_cpu_irq_mask
+       ldo     R%intr_return(%r2), %r2 /* return to intr_return, not here */
 
        /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
 
        .export         intr_save, code /* for os_hpmc */
 
 intr_save:
-       get_stack
+       mfsp    %sr7,%r16
+       CMPIB=,n 0,%r16,1f
+       get_stack_use_cr30
+       b       2f
+       copy    %r8,%r26
+
+1:
+       get_stack_use_r30
+       copy    %r8,%r26
+
+2:
        save_specials   %r29
 
-       mfctl           %cr20, %r1
-       STREG           %r1, PT_ISR(%r29)
-       mfctl           %cr21, %r1
-       STREG           %r1, PT_IOR(%r29)
+       /* If this trap is a itlb miss, skip saving/adjusting isr/ior */
+
+       /*
+        * FIXME: 1) Use a #define for the hardwired "6" below (and in
+        *           traps.c.
+        *        2) Once we start executing code above 4 Gb, we need
+        *           to adjust iasq/iaoq here in the same way we
+        *           adjust isr/ior below.
+        */
+
+       CMPIB=,n        6,%r26,skip_save_ior
+
+       /* save_specials left ipsw value in r8 for us to test */
+
+       mfctl           %cr20, %r16 /* isr */
+       mfctl           %cr21, %r17 /* ior */
+
+#ifdef __LP64__
+       /*
+        * If the interrupted code was running with W bit off (32 bit),
+        * clear the b bits (bits 0 & 1) in the ior.
+        */
+       extrd,u,*<>     %r8,PSW_W_BIT,1,%r0
+       depdi           0,1,2,%r17
+
+       /*
+        * FIXME: This code has hardwired assumptions about the split
+        *        between space bits and offset bits. This will change
+        *        when we allow alternate page sizes.
+        */
+
+       /* adjust isr/ior. */
+
+       extrd,u         %r16,63,7,%r1    /* get high bits from isr for ior */
+       depd            %r1,31,7,%r17    /* deposit them into ior */
+       depdi           0,63,7,%r16      /* clear them from isr */
+#endif
+       STREG           %r16, PT_ISR(%r29)
+       STREG           %r17, PT_IOR(%r29)
+
 
-       virt_map        rfi
+skip_save_ior:
+       virt_map
        save_general    %r29
 
        ldo             PT_FR0(%r29), %r25
@@ -781,15 +949,16 @@ intr_save:
        loadgp
 
        copy            %r29, %r25      /* arg1 is pt_regs */
-#ifdef CONFIG_KWDB
-       copy            %r29, %r3       /* KWDB - update frame pointer (gr3) */
+#ifdef __LP64__
+       ldo             -16(%r30),%r29  /* Reference param save area */
 #endif
 
-       bl              handle_interruption,%r2
-       copy            %r29, %r16      /* save pt_regs */
+       ldil            L%intr_return, %r2
+       copy            %r25, %r16      /* save pt_regs */
+
+       b               handle_interruption
+       ldo             R%intr_return(%r2), %r2 /* return to intr_return */
 
-       b               intr_return
-       nop
 
        /*
         * Note for all tlb miss handlers:
@@ -821,10 +990,9 @@ intr_save:
 #ifdef __LP64__
 
 dtlb_miss_20w:
-
-       extrd,u         spc,31,7,t1     /* adjust va */
+       extrd,u         spc,63,7,t1     /* adjust va */
        depd            t1,31,7,va      /* adjust va */
-       depdi           0,31,7,spc      /* adjust space */
+       depdi           0,63,7,spc      /* adjust space */
        mfctl           %cr25,ptp       /* Assume user space miss */
        or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
        mfctl           %cr24,ptp       /* Load kernel pgd instead */
@@ -832,20 +1000,20 @@ dtlb_miss_20w:
 
        mfsp            %sr7,t0         /* Get current space */
        or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,dtlb_fault /* forward */
+       cmpb,*<>,n       t0,spc,dtlb_fault /* forward */
 
        /* First level page table lookup */
 
        ldd,s           t1(ptp),ptp
        extrd,u         va,42,9,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
        depdi           0,63,12,ptp     /* clear prot bits */
 
        /* Second level page table lookup */
 
        ldd,s           t0(ptp),ptp
        extrd,u         va,51,9,t0     /* get third-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
        depdi           0,63,12,ptp     /* clear prot bits */
 
        /* Third level page table lookup */
@@ -853,7 +1021,7 @@ dtlb_miss_20w:
        shladd           t0,3,ptp,ptp
        ldi             _PAGE_ACCESSED,t1
        ldd              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20w
 
        /* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -861,11 +1029,9 @@ dtlb_miss_20w:
        and,*<>         t1,pte,%r0      /* test and nullify if already set */
        std             t0,0(ptp)       /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       
-       depd            pte,8,7,prot
-       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
-       depdi           1,12,1,prot
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
+
        extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
        depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
        extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -874,11 +1040,106 @@ dtlb_miss_20w:
        /* Get rid of prot bits and convert to page addr for idtlbt */
 
        depdi           0,63,12,pte
-       extrd,u         pte,56,32,pte
-       idtlbt          %r16,%r17
+       extrd,u         pte,56,52,pte
+       idtlbt          pte,prot
+
+       rfir
+       nop
+
+dtlb_check_alias_20w:
+
+       /* Check to see if fault is in the temporary alias region */
+
+       cmpib,*<>,n     0,spc,dtlb_fault /* forward */
+       ldil            L%(TMPALIAS_MAP_START),t0
+       copy            va,t1
+       depdi           0,63,23,t1
+       cmpb,*<>,n      t0,t1,dtlb_fault /* forward */
+       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+       depd,z          prot,8,7,prot
+
+       /*
+        * OK, it is in the temp alias region, check whether "from" or "to".
+        * Check "subtle" note in pacache.S re: r23/r26.
+        */
+
+       extrd,u,*=      va,41,1,r0
+       or,*tr          %r23,%r0,pte    /* If "from" use "from" page */
+       or,*            %r26,%r0,pte    /* else "to", use "to" page  */
+
+       idtlbt          pte,prot
 
        rfir
        nop
+
+nadtlb_miss_20w:
+       extrd,u         spc,63,7,t1     /* adjust va */
+       depd            t1,31,7,va      /* adjust va */
+       depdi           0,63,7,spc      /* adjust space */
+       mfctl           %cr25,ptp       /* Assume user space miss */
+       or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extrd,u         va,33,9,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
+       cmpb,*<>,n       t0,spc,nadtlb_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldd,s           t1(ptp),ptp
+       extrd,u         va,42,9,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       ldd,s           t0(ptp),ptp
+       extrd,u         va,51,9,t0     /* get third-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+       depdi           0,63,12,ptp     /* clear prot bits */
+
+       /* Third level page table lookup */
+
+       shladd           t0,3,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldd              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20w
+
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
+
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,52,pte
+       idtlbt          pte,prot
+
+       rfir
+       nop
+
+nadtlb_check_flush_20w:
+       bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+       /* Insert a "flush only" translation */
+
+       depdi,z         7,7,3,prot
+       depdi           1,10,1,prot
+
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,52,pte
+       idtlbt          pte,prot
+
+       rfir
+       nop
+
 #else
 
 dtlb_miss_11:
@@ -889,13 +1150,13 @@ dtlb_miss_11:
 
        mfsp            %sr7,t0         /* Get current space */
        or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,dtlb_fault /* forward */
+       cmpb,<>,n       t0,spc,dtlb_fault /* forward */
 
        /* First level page table lookup */
 
        ldwx,s          t1(ptp),ptp
        extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_11
        depi            0,31,12,ptp     /* clear prot bits */
 
        /* Second level page table lookup */
@@ -903,7 +1164,7 @@ dtlb_miss_11:
        sh2addl          t0,ptp,ptp
        ldi             _PAGE_ACCESSED,t1
        ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_11
 
        /* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -911,8 +1172,8 @@ dtlb_miss_11:
        and,<>          t1,pte,%r0      /* test and nullify if already set */
        stw             t0,0(ptp)       /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       dep             pte,8,7,prot
+       zdep            spc,30,15,prot  /* create prot id from space */
+       dep             pte,8,7,prot    /* add in prot bits from pte */
 
        extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
        depi            1,12,1,prot
@@ -937,9 +1198,108 @@ dtlb_miss_11:
        rfir
        nop
 
-dtlb_miss_20:
-       .level 2.0
+dtlb_check_alias_11:
+
+       /* Check to see if fault is in the temporary alias region */
+
+       cmpib,<>,n      0,spc,dtlb_fault /* forward */
+       ldil            L%(TMPALIAS_MAP_START),t0
+       copy            va,t1
+       depwi           0,31,23,t1
+       cmpb,<>,n       t0,t1,dtlb_fault /* forward */
+       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+       depw,z          prot,8,7,prot
+
+       /*
+        * OK, it is in the temp alias region, check whether "from" or "to".
+        * Check "subtle" note in pacache.S re: r23/r26.
+        */
+
+       extrw,u,=       va,9,1,r0
+       or,tr           %r23,%r0,pte    /* If "from" use "from" page */
+       or              %r26,%r0,pte    /* else "to", use "to" page  */
+
+       idtlba          pte,(va)
+       idtlbp          prot,(va)
+
+       rfir
+       nop
+
+nadtlb_miss_11:
+       mfctl           %cr25,ptp       /* Assume user space miss */
+       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_11
+
+       zdep            spc,30,15,prot  /* create prot id from space */
+       dep             pte,8,7,prot    /* add in prot bits from pte */
+
+       extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
+       depi            1,12,1,prot
+       extru,=         pte,_PAGE_USER_BIT,1,r0
+       depi            7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extru,=         pte,_PAGE_GATEWAY_BIT,1,r0
+       depi            0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlba */
+
+       depi            0,31,12,pte
+       extru           pte,24,25,pte
+
+       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mtsp            spc,%sr1
+
+       idtlba          pte,(%sr1,va)
+       idtlbp          prot,(%sr1,va)
+
+       mtsp            t0, %sr1        /* Restore sr1 */
+
+       rfir
+       nop
+
+nadtlb_check_flush_11:
+       bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+       /* Insert a "flush only" translation */
+
+       zdepi           7,7,3,prot
+       depi            1,10,1,prot
+
+       /* Get rid of prot bits and convert to page addr for idtlba */
+
+       depi            0,31,12,pte
+       extru           pte,24,25,pte
+
+       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mtsp            spc,%sr1
+
+       idtlba          pte,(%sr1,va)
+       idtlbp          prot,(%sr1,va)
+
+       mtsp            t0, %sr1        /* Restore sr1 */
 
+       rfir
+       nop
+
+dtlb_miss_20:
        mfctl           %cr25,ptp       /* Assume user space miss */
        or,<>           %r0,spc,%r0     /* If it is user space, nullify */
        mfctl           %cr24,ptp       /* Load kernel pgd instead */
@@ -947,13 +1307,13 @@ dtlb_miss_20:
 
        mfsp            %sr7,t0         /* Get current space */
        or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,dtlb_fault /* forward */
+       cmpb,<>,n       t0,spc,dtlb_fault /* forward */
 
        /* First level page table lookup */
 
        ldwx,s          t1(ptp),ptp
        extru           va,19,10,t0     /* get second-level index */
-       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_fault
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,dtlb_check_alias_20
        depi            0,31,12,ptp     /* clear prot bits */
 
        /* Second level page table lookup */
@@ -961,7 +1321,7 @@ dtlb_miss_20:
        sh2addl          t0,ptp,ptp
        ldi             _PAGE_ACCESSED,t1
        ldw              0(ptp),pte
-       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_check_alias_20
 
        /* Check whether the "accessed" bit was set, otherwise do so */
 
@@ -969,11 +1329,9 @@ dtlb_miss_20:
        and,<>          t1,pte,%r0      /* test and nullify if already set */
        stw             t0,0(ptp)       /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       
-       depd            pte,8,7,prot
-       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
-       depdi           1,12,1,prot
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
+
        extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
        depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
        extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -981,16 +1339,145 @@ dtlb_miss_20:
 
        /* Get rid of prot bits and convert to page addr for idtlbt */
 
-       depdi           0,63,12,pte
-       extrd,u         pte,56,25,pte
-       idtlbt          %r16,%r17
+       extrd,s         pte,35,4,t0
+       depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0 
+        extrd,u,*tr     pte,56,25,pte 
+       extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */ 
+       idtlbt          pte,prot
+
+       rfir
+       nop
+
+dtlb_check_alias_20:
+
+       /* Check to see if fault is in the temporary alias region */
+
+       cmpib,<>,n      0,spc,dtlb_fault /* forward */
+       ldil            L%(TMPALIAS_MAP_START),t0
+       copy            va,t1
+       depwi           0,31,23,t1
+       cmpb,<>,n       t0,t1,dtlb_fault /* forward */
+       ldi             (_PAGE_DIRTY|_PAGE_WRITE|_PAGE_READ),prot
+       depd,z          prot,8,7,prot
+
+       /*
+        * OK, it is in the temp alias region, check whether "from" or "to".
+        * Check "subtle" note in pacache.S re: r23/r26.
+        */
+
+       extrw,u,=       va,9,1,r0
+       or,tr           %r23,%r0,pte    /* If "from" use "from" page */
+       or              %r26,%r0,pte    /* else "to", use "to" page  */
+
+       idtlbt          pte,prot
+
+       rfir
+       nop
+
+nadtlb_miss_20:
+       mfctl           %cr25,ptp       /* Assume user space miss */
+       or,<>           %r0,spc,%r0     /* If it is user space, nullify */
+       mfctl           %cr24,ptp       /* Load kernel pgd instead */
+       extru           va,9,10,t1      /* Get pgd index */
+
+       mfsp            %sr7,t0         /* Get current space */
+       or,=            %r0,t0,%r0      /* If kernel, nullify following test */
+       cmpb,<>,n       t0,spc,nadtlb_fault /* forward */
+
+       /* First level page table lookup */
+
+       ldwx,s          t1(ptp),ptp
+       extru           va,19,10,t0     /* get second-level index */
+       bb,>=,n         ptp,_PAGE_PRESENT_BIT,nadtlb_emulate
+       depi            0,31,12,ptp     /* clear prot bits */
+
+       /* Second level page table lookup */
+
+       sh2addl          t0,ptp,ptp
+       ldi             _PAGE_ACCESSED,t1
+       ldw              0(ptp),pte
+       bb,>=,n          pte,_PAGE_PRESENT_BIT,nadtlb_check_flush_20
+
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
+
+       extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
+       depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
+       extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
+       depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
+
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+        extrd,s         pte,35,4,t0
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+        idtlbt          pte,prot
+
+       rfir
+       nop
+
+nadtlb_check_flush_20:
+       bb,>=,n          pte,_PAGE_FLUSH_BIT,nadtlb_emulate
+
+       /* Insert a "flush only" translation */
+
+       depdi,z         7,7,3,prot
+       depdi           1,10,1,prot
 
-       .level          1.1
+       /* Get rid of prot bits and convert to page addr for idtlbt */
+
+       depdi           0,63,12,pte
+       extrd,u         pte,56,32,pte
+       idtlbt          pte,prot
 
        rfir
        nop
 #endif
 
+nadtlb_emulate:
+
+       /*
+        * Non access misses can be caused by fdc,fic,pdc,lpa,probe and
+        * probei instructions. We don't want to fault for these
+        * instructions (not only does it not make sense, it can cause
+        * deadlocks, since some flushes are done with the mmap
+        * semaphore held). If the translation doesn't exist, we can't
+        * insert a translation, so have to emulate the side effects
+        * of the instruction. Since we don't insert a translation
+        * we can get a lot of faults during a flush loop, so it makes
+        * sense to try to do it here with minimum overhead. We only
+        * emulate fdc,fic & pdc instructions whose base and index
+        * registers are not shadowed. We defer everything else to the
+        * "slow" path.
+        */
+
+       mfctl           %cr19,%r9 /* Get iir */
+       ldi             0x280,%r16
+       and             %r9,%r16,%r17
+       cmpb,<>,n       %r16,%r17,nadtlb_fault /* Not fdc,fic,pdc */
+       bb,>=,n         %r9,26,nadtlb_nullify  /* m bit not set, just nullify */
+       b,l             get_register,%r25
+       extrw,u         %r9,15,5,%r8           /* Get index register # */
+       CMPIB=,n        -1,%r1,nadtlb_fault    /* have to use slow path */
+       copy            %r1,%r24
+       b,l             get_register,%r25
+       extrw,u         %r9,10,5,%r8           /* Get base register # */
+       CMPIB=,n        -1,%r1,nadtlb_fault    /* have to use slow path */
+       b,l             set_register,%r25
+       add,l           %r1,%r24,%r1           /* doesn't affect c/b bits */
+
+nadtlb_nullify:
+       mfctl           %cr22,%r8              /* Get ipsw */
+       ldil            L%PSW_N,%r9
+       or              %r8,%r9,%r8            /* Set PSW_N */
+       mtctl           %r8,%cr22
+
+       rfir
+       nop
+
 #ifdef __LP64__
 itlb_miss_20w:
 
@@ -999,9 +1486,9 @@ itlb_miss_20w:
         * on the gateway page which is in the kernel address space.
         */
 
-       extrd,u         spc,31,7,t1     /* adjust va */
+       extrd,u         spc,63,7,t1     /* adjust va */
        depd            t1,31,7,va      /* adjust va */
-       depdi           0,31,7,spc      /* adjust space */
+       depdi           0,63,7,spc      /* adjust space */
        cmpib,*=        0,spc,itlb_miss_kernel_20w
        extrd,u         va,33,9,t1      /* Get pgd index */
 
@@ -1039,11 +1526,9 @@ itlb_miss_common_20w:
        and,*<>         t1,pte,%r0      /* test and nullify if already set */
        std             t0,0(ptp)       /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       
-       depd            pte,8,7,prot
-       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
-       depdi           1,12,1,prot
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
+
        extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
        depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
        extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1053,7 +1538,7 @@ itlb_miss_common_20w:
 
        depdi           0,63,12,pte
        extrd,u         pte,56,32,pte
-       iitlbt          %r16,%r17
+       iitlbt          pte,prot
 
        rfir
        nop
@@ -1070,14 +1555,14 @@ itlb_miss_11:
         * on the gateway page which is in the kernel address space.
         */
 
-       comib,=         0,spc,itlb_miss_kernel_11
+       cmpib,=         0,spc,itlb_miss_kernel_11
        extru           va,9,10,t1      /* Get pgd index */
 
        mfctl           %cr25,ptp       /* load user pgd */
 
        mfsp            %sr7,t0         /* Get current space */
        or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,itlb_fault /* forward */
+       cmpb,<>,n       t0,spc,itlb_fault /* forward */
 
        /* First level page table lookup */
 
@@ -1100,8 +1585,8 @@ itlb_miss_common_11:
        and,<>          t1,pte,%r0      /* test and nullify if already set */
        stw             t0,0(ptp)       /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       dep             pte,8,7,prot
+       zdep            spc,30,15,prot  /* create prot id from space */
+       dep             pte,8,7,prot    /* add in prot bits from pte */
 
        extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
        depi            1,12,1,prot
@@ -1137,14 +1622,14 @@ itlb_miss_20:
         * on the gateway page which is in the kernel address space.
         */
 
-       comib,=         0,spc,itlb_miss_kernel_20
+       cmpib,=         0,spc,itlb_miss_kernel_20
        extru           va,9,10,t1      /* Get pgd index */
 
        mfctl           %cr25,ptp       /* load user pgd */
 
        mfsp            %sr7,t0         /* Get current space */
        or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,itlb_fault /* forward */
+       cmpb,<>,n       t0,spc,itlb_fault /* forward */
 
        /* First level page table lookup */
 
@@ -1167,13 +1652,9 @@ itlb_miss_common_20:
        and,<>          t1,pte,%r0      /* test and nullify if already set */
        stw             t0,0(ptp)       /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       
-       .level 2.0
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
 
-       depd            pte,8,7,prot
-       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
-       depdi           1,12,1,prot
        extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
        depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
        extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1181,10 +1662,12 @@ itlb_miss_common_20:
 
        /* Get rid of prot bits and convert to page addr for iitlbt */
 
-       depdi           0,63,12,pte
-       extrd,u         pte,56,25,pte
-       iitlbt          %r16,%r17
-       .level          1.1
+        extrd,s         pte,35,4,t0 
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte 
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+       iitlbt          pte,prot
 
        rfir
        nop
@@ -1198,11 +1681,10 @@ itlb_miss_kernel_20:
 #ifdef __LP64__
 
 dbit_trap_20w:
-
-       extrd,u         spc,31,7,t1     /* adjust va */
+       extrd,u         spc,63,7,t1     /* adjust va */
        depd            t1,31,7,va      /* adjust va */
        depdi           0,1,2,va        /* adjust va */
-       depdi           0,31,7,spc      /* adjust space */
+       depdi           0,63,7,spc      /* adjust space */
        mfctl           %cr25,ptp       /* Assume user space miss */
        or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
        mfctl           %cr24,ptp       /* Load kernel pgd instead */
@@ -1210,7 +1692,7 @@ dbit_trap_20w:
 
        mfsp            %sr7,t0         /* Get current space */
        or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,dbit_fault /* forward */
+       cmpb,*<>,n       t0,spc,dbit_fault /* forward */
 
        /* First level page table lookup */
 
@@ -1229,6 +1711,18 @@ dbit_trap_20w:
        /* Third level page table lookup */
 
        shladd           t0,3,ptp,ptp
+#ifdef CONFIG_SMP
+       CMPIB=,n        0,spc,dbit_nolock_20w
+       ldil            L%PA(pa_dbit_lock),t0
+       ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_20w:
+       ldcw            0(t0),t1
+       cmpib,=         0,t1,dbit_spin_20w
+       nop
+
+dbit_nolock_20w:
+#endif
        ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
        ldd              0(ptp),pte
        bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1238,11 +1732,9 @@ dbit_trap_20w:
        or              t1,pte,pte
        std             pte,0(ptp)      /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       
-       depd            pte,8,7,prot
-       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
-       depdi           1,12,1,prot
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
+
        extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
        depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
        extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
@@ -1251,8 +1743,15 @@ dbit_trap_20w:
        /* Get rid of prot bits and convert to page addr for idtlbt */
 
        depdi           0,63,12,pte
-       extrd,u         pte,56,32,pte
-       idtlbt          %r16,%r17
+       extrd,u         pte,56,52,pte
+       idtlbt          pte,prot
+#ifdef CONFIG_SMP
+       CMPIB=,n        0,spc,dbit_nounlock_20w
+       ldi             1,t1
+       stw             t1,0(t0)
+
+dbit_nounlock_20w:
+#endif
 
        rfir
        nop
@@ -1266,7 +1765,7 @@ dbit_trap_11:
 
        mfsp            %sr7,t0         /* Get current space */
        or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,dbit_fault /* forward */
+       cmpb,<>,n       t0,spc,dbit_fault /* forward */
 
        /* First level page table lookup */
 
@@ -1278,6 +1777,18 @@ dbit_trap_11:
        /* Second level page table lookup */
 
        sh2addl          t0,ptp,ptp
+#ifdef CONFIG_SMP
+       CMPIB=,n        0,spc,dbit_nolock_11
+       ldil            L%PA(pa_dbit_lock),t0
+       ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_11:
+       ldcw            0(t0),t1
+       cmpib,=         0,t1,dbit_spin_11
+       nop
+
+dbit_nolock_11:
+#endif
        ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
        ldw              0(ptp),pte
        bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1287,8 +1798,8 @@ dbit_trap_11:
        or              t1,pte,pte
        stw             pte,0(ptp)      /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       dep             pte,8,7,prot
+       zdep            spc,30,15,prot  /* create prot id from space */
+       dep             pte,8,7,prot    /* add in prot bits from pte */
 
        extru,=         pte,_PAGE_NO_CACHE_BIT,1,r0
        depi            1,12,1,prot
@@ -1302,13 +1813,20 @@ dbit_trap_11:
        depi            0,31,12,pte
        extru           pte,24,25,pte
 
-       mfsp            %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
+       mfsp            %sr1,t1  /* Save sr1 so we can use it in tlb inserts */
        mtsp            spc,%sr1
 
        idtlba          pte,(%sr1,va)
        idtlbp          prot,(%sr1,va)
 
-       mtsp            t0, %sr1     /* Restore sr1 */
+       mtsp            t1, %sr1     /* Restore sr1 */
+#ifdef CONFIG_SMP
+       CMPIB=,n        0,spc,dbit_nounlock_11
+       ldi             1,t1
+       stw             t1,0(t0)
+
+dbit_nounlock_11:
+#endif
 
        rfir
        nop
@@ -1321,7 +1839,7 @@ dbit_trap_20:
 
        mfsp            %sr7,t0         /* Get current space */
        or,=            %r0,t0,%r0      /* If kernel, nullify following test */
-       comb,<>,n       t0,spc,dbit_fault /* forward */
+       cmpb,<>,n       t0,spc,dbit_fault /* forward */
 
        /* First level page table lookup */
 
@@ -1333,6 +1851,18 @@ dbit_trap_20:
        /* Second level page table lookup */
 
        sh2addl          t0,ptp,ptp
+#ifdef CONFIG_SMP
+       CMPIB=,n        0,spc,dbit_nolock_20
+       ldil            L%PA(pa_dbit_lock),t0
+       ldo             R%PA(pa_dbit_lock)(t0),t0
+
+dbit_spin_20:
+       ldcw            0(t0),t1
+       cmpib,=         0,t1,dbit_spin_20
+       nop
+
+dbit_nolock_20:
+#endif
        ldi             (_PAGE_ACCESSED|_PAGE_DIRTY),t1
        ldw              0(ptp),pte
        bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
@@ -1342,25 +1872,28 @@ dbit_trap_20:
        or              t1,pte,pte
        stw             pte,0(ptp)      /* write back pte */
 
-       copy            spc,prot        /* init prot with faulting space */
-       
-       .level 2.0
+       space_to_prot   spc prot        /* create prot id from space */
+       depd            pte,8,7,prot    /* add in prot bits from pte */
 
-       depd            pte,8,7,prot
-       extrd,u,*=      pte,_PAGE_NO_CACHE_BIT+32,1,r0
-       depdi           1,12,1,prot
        extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
        depdi           7,11,3,prot   /* Set for user space (1 rsvd for read) */
        extrd,u,*=      pte,_PAGE_GATEWAY_BIT+32,1,r0
        depdi           0,11,2,prot     /* If Gateway, Set PL2 to 0 */
 
-       /* Get rid of prot bits and convert to page addr for idtlbt */
+        extrd,s         pte,35,4,t0 
+        depdi           0,63,12,pte     /* clear lower 12 bits */
+        addi,=          1,t0,0
+        extrd,u,*tr     pte,56,25,pte 
+        extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
+        idtlbt          pte,prot
 
-       depdi           0,63,12,pte
-       extrd,u         pte,56,25,pte
-       idtlbt          %r16,%r17
+#ifdef CONFIG_SMP
+       CMPIB=,n        0,spc,dbit_nounlock_20
+       ldi             1,t1
+       stw             t1,0(t0)
 
-       .level          1.1
+dbit_nounlock_20:
+#endif
 
        rfir
        nop
@@ -1369,50 +1902,24 @@ dbit_trap_20:
        .import handle_interruption,code
 
 kernel_bad_space:
-       b               tlb_fault
-       ldi             31,%r1  /* Use an unused code */
+       b               intr_save
+       ldi             31,%r8  /* Use an unused code */
 
 dbit_fault:
-       b               tlb_fault
-       ldi             20,%r1
+       b               intr_save
+       ldi             20,%r8
 
 itlb_fault:
-       b               tlb_fault
-       ldi             6,%r1
-
-dtlb_fault:
-       ldi             15,%r1
-
-       /* Fall Through */
+       b               intr_save
+       ldi             6,%r8
 
-tlb_fault:
-       mtctl           %r1,%cr29
-       mtctl           %r29,%cr31
+nadtlb_fault:
+       b               intr_save
+       ldi             17,%r8
 
-       get_stack
-       save_specials   %r29            /* Note this saves a trashed r1 */
-
-       SAVE_CR         (%cr20, PT_ISR(%r29))
-       SAVE_CR         (%cr21, PT_IOR(%r29))
-
-       virt_map        rfir
-
-       STREG           %r1,PT_GR1(%r29)        /* save good value after rfir */
-
-       save_general    %r29
-
-       ldo     PT_FR0(%r29), %r25
-       save_fp         %r25
-       
-       loadgp
-
-       copy            %r29, %r25
-
-       bl              handle_interruption, %r2
-       copy            %r29, %r16
-
-       b               intr_return
-       nop
+dtlb_fault:
+       b               intr_save
+       ldi             15,%r8
 
        /* Register saving semantics for system calls:
 
@@ -1475,21 +1982,25 @@ tlb_fault:
        .endm
 
        .export sys_fork_wrapper
+       .export child_return
 sys_fork_wrapper:
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
+       mfctl   %cr30,%r1               /* get pt regs */
+       LDREG   0(%r1),%r1
+       ldo     TASK_REGS(%r1),%r1
        reg_save %r1
+       mfctl   %cr27, %r3
+       STREG   %r3, PT_CR27(%r1)
 
        STREG   %r2,-RP_OFFSET(%r30)
        ldo     FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#endif
 
        /* These are call-clobbered registers and therefore
           also syscall-clobbered (we hope). */
        STREG   %r2,PT_GR19(%r1)        /* save for child */
-       STREG   %r30,PT_GR20(%r1)
-       ldil    L%child_return, %r3
-       ldo     R%child_return(%r3), %r3
-       LDIL_FIXUP(%r3)
-       STREG   %r3,PT_GR21(%r1)        /* save for child */
+       STREG   %r30,PT_GR21(%r1)
 
        LDREG   PT_GR30(%r1),%r25
        copy    %r1,%r24
@@ -1499,53 +2010,73 @@ sys_fork_wrapper:
        LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
 wrapper_exit:
        ldo     -FRAME_SIZE(%r30),%r30          /* get the stackframe */
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1    /* get pt regs */
+       mfctl   %cr30,%r1               /* get pt regs */
+       LDREG   0(%r1),%r1
+       ldo     TASK_REGS(%r1),%r1
 
+       LDREG   PT_CR27(%r1), %r3
+       mtctl   %r3, %cr27
        reg_restore %r1
 
+       /* strace expects syscall # to be preserved in r20 */
+       ldi     __NR_fork,%r20
        bv %r0(%r2)
-       nop
+       STREG   %r20,PT_GR20(%r1)
 
        /* Set the return value for the child */
 child_return:
-       LDREG   TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+#if CONFIG_SMP || CONFIG_PREEMPT
+       bl      schedule_tail, %r2
+       nop
+#endif
+
+       mfctl   %cr30,%r2
+       LDREG   0(%r2),%r2
+       LDREG   TASK_PT_GR19(%r2),%r2
        b       wrapper_exit
        copy    %r0,%r28
 
        
        .export sys_clone_wrapper
 sys_clone_wrapper:
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
+       mfctl   %cr30,%r1               /* get pt regs */
+       LDREG   0(%r1),%r1
+       ldo     TASK_REGS(%r1),%r1
        reg_save %r1
+       mfctl   %cr27, %r3
+       STREG   %r3, PT_CR27(%r1)
 
        STREG   %r2,-RP_OFFSET(%r30)
        ldo     FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#endif
 
-       STREG   %r30,PT_GR20(%r1)
-       ldil    L%child_return,%r3
-       ldo     R%child_return(%r3),%r3
-       LDIL_FIXUP(%r3)
-
+       STREG   %r2,PT_GR19(%r1)        /* save for child */
+       STREG   %r30,PT_GR21(%r1)
        bl      sys_clone,%r2
-       STREG   %r3,PT_GR21(%r1)        /* save for child */
+       copy    %r1,%r24
 
        b       wrapper_exit
        LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
 
-
        .export sys_vfork_wrapper
 sys_vfork_wrapper:
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
+       mfctl   %cr30,%r1               /* get pt regs */
+       LDREG   0(%r1),%r1
+       ldo     TASK_REGS(%r1),%r1
        reg_save %r1
+       mfctl   %cr27, %r3
+       STREG   %r3, PT_CR27(%r1)
 
        STREG   %r2,-RP_OFFSET(%r30)
        ldo     FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#endif
 
-       STREG   %r30,PT_GR20(%r1)
-       ldil    L%child_return,%r3
-       ldo     R%child_return(%r3),%r3
-       LDIL_FIXUP(%r3)
-       STREG   %r3,PT_GR21(%r1)        /* save for child */
+       STREG   %r2,PT_GR19(%r1)        /* save for child */
+       STREG   %r30,PT_GR21(%r1)
 
        bl      sys_vfork,%r2
        copy    %r1,%r26
@@ -1555,7 +2086,9 @@ sys_vfork_wrapper:
 
        
        .macro  execve_wrapper execve
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get pt regs */
+       mfctl   %cr30,%r1               /* get pt regs */
+       LDREG   0(%r1),%r1
+       ldo     TASK_REGS(%r1),%r1
 
        /*
         * Do we need to save/restore r3-r18 here?
@@ -1567,6 +2100,9 @@ sys_vfork_wrapper:
 
        STREG %r2,-RP_OFFSET(%r30)
        ldo FRAME_SIZE(%r30),%r30
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#endif
        bl \execve,%r2
        copy %r1,%arg0
 
@@ -1576,7 +2112,7 @@ sys_vfork_wrapper:
        /* If exec succeeded we need to load the args */
 
        ldo -1024(%r0),%r1
-       comb,>>= %r28,%r1,error_\execve
+       cmpb,>>= %r28,%r1,error_\execve
        copy %r2,%r19
 
 error_\execve:
@@ -1600,17 +2136,27 @@ sys32_execve_wrapper:
 
        .export sys_rt_sigreturn_wrapper
 sys_rt_sigreturn_wrapper:
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r26
+       mfctl   %cr30,%r26              /* get pt regs */
+       LDREG   0(%r26),%r26
+       ldo     TASK_REGS(%r26),%r26
        /* Don't save regs, we are going to restore them from sigcontext. */
        STREG   %r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+       ldo     FRAME_SIZE(%r30), %r30
+       bl      sys_rt_sigreturn,%r2
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#else
        bl      sys_rt_sigreturn,%r2
        ldo     FRAME_SIZE(%r30), %r30
+#endif
 
        ldo     -FRAME_SIZE(%r30), %r30
        LDREG   -RP_OFFSET(%r30), %r2
 
        /* FIXME: I think we need to restore a few more things here. */
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get pt regs */
+       mfctl   %cr30,%r1               /* get pt regs */
+       LDREG   0(%r1),%r1
+       ldo     TASK_REGS(%r1),%r1
        reg_restore %r1
 
        /* If the signal was received while the process was blocked on a
@@ -1623,29 +2169,65 @@ sys_rt_sigreturn_wrapper:
        .export sys_sigaltstack_wrapper
 sys_sigaltstack_wrapper:
        /* Get the user stack pointer */
-       LDREG   -TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
+       mfctl   %cr30,%r24
+       LDREG   0(%r24),%r24
+       LDREG   TASK_PT_GR30(%r24),%r24
        STREG   %r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+       ldo     FRAME_SIZE(%r30), %r30
+       bl      do_sigaltstack,%r2
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#else
        bl      do_sigaltstack,%r2
        ldo     FRAME_SIZE(%r30), %r30
+#endif
 
        ldo     -FRAME_SIZE(%r30), %r30
        LDREG   -RP_OFFSET(%r30), %r2
        bv      %r0(%r2)
        nop
 
+#ifdef __LP64__
+       .export sys32_sigaltstack_wrapper
+sys32_sigaltstack_wrapper:
+       /* Get the user stack pointer */
+       mfctl   %cr30,%r24
+       LDREG   0(%r24),%r24
+       LDREG   TASK_PT_GR30(%r24),%r24
+       STREG   %r2, -RP_OFFSET(%r30)
+       ldo     FRAME_SIZE(%r30), %r30
+       bl      do_sigaltstack32,%r2
+       ldo     -16(%r30),%r29          /* Reference param save area */
+
+       ldo     -FRAME_SIZE(%r30), %r30
+       LDREG   -RP_OFFSET(%r30), %r2
+       bv      %r0(%r2)
+       nop
+#endif
+
        .export sys_rt_sigsuspend_wrapper
 sys_rt_sigsuspend_wrapper:
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r24
+       mfctl   %cr30,%r24              /* get pt regs */
+       LDREG   0(%r24),%r24
+       ldo     TASK_REGS(%r24),%r24
        reg_save %r24
 
        STREG   %r2, -RP_OFFSET(%r30)
+#ifdef __LP64__
+       ldo     FRAME_SIZE(%r30), %r30
+       bl      sys_rt_sigsuspend,%r2
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#else
        bl      sys_rt_sigsuspend,%r2
        ldo     FRAME_SIZE(%r30), %r30
+#endif
 
        ldo     -FRAME_SIZE(%r30), %r30
        LDREG   -RP_OFFSET(%r30), %r2
 
-       ldo     TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1
+       mfctl   %cr30,%r1               /* get pt regs */
+       LDREG   0(%r1),%r1
+       ldo     TASK_REGS(%r1),%r1
        reg_restore %r1
 
        bv      %r0(%r2)
@@ -1658,66 +2240,90 @@ syscall_exit:
           values. */
        /* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
         * via syscall_exit_rfi if the signal was received while the process
-        * was running.  All traced processes will probably exit via
-        * syscall_exit_rfi in the future.
+        * was running.
         */
 
        /* save return value now */
 
-       STREG     %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30)
+       mfctl     %cr30, %r1
+       LDREG     0(%r1),%r1
+       STREG     %r28,TASK_PT_GR28(%r1)
+
+       /* Save other hpux returns if personality is PER_HPUX */
+
+/* <linux/personality.h> cannot be easily included */
+#define PER_HPUX 0x10
+       LDREG     TASK_PERSONALITY(%r1),%r19
+#warning the ldo+CMPIB could probably be done better but 0x10 i soutside of range of CMPIB
+       ldo       -PER_HPUX(%r19), %r19
+       CMPIB<>,n 0,%r19,1f
+       STREG     %r22,TASK_PT_GR22(%r1)
+       STREG     %r29,TASK_PT_GR29(%r1)
+1:
+
+       /* Seems to me that dp could be wrong here, if the syscall involved
+        * calling a module, and nothing got round to restoring dp on return.
+        */
+       loadgp
 
 syscall_check_bh:
 
-/* #ifdef NOTNOW */
        /* Check for software interrupts */
 
        .import irq_stat,data
 
        ldil    L%irq_stat,%r19
        ldo     R%irq_stat(%r19),%r19
-       LDIL_FIXUP(%r19)
 
 #ifdef CONFIG_SMP
        /* sched.h: int processor */
-       ldw     TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r20 /* get cpu # */
-#if (IRQSTAT_SZ == 32)
-       dep     %r20,26,27,%r20 /* shift left 5 bits */
+       /* %r26 is used as scratch register to index into irq_stat[] */
+       ldw     TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
+
+       /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
+#ifdef __LP64__
+       shld    %r26, 6, %r20
 #else
-#error IRQSTAT_SZ changed, fix dep
-#endif /* IRQSTAT_SZ */
-       add     %r19,%r20,%r19
+       shlw    %r26, 5, %r20
+#endif
+       add     %r19,%r20,%r19  /* now have &irq_stat[smp_processor_id()] */
 #endif /* CONFIG_SMP */
 
-       ldw     IRQSTAT_SI_ACTIVE(%r19),%r20    /* hardirq.h: unsigned int */
-       ldw     IRQSTAT_SI_MASK(%r19),%r19      /* hardirq.h: unsigned int */
-       and     %r19,%r20,%r20
-       comib,<>,n 0,%r20,syscall_do_softirq /* forward */
-/* #endif */
-
+       LDREG   IRQSTAT_SIRQ_PEND(%r19),%r20    /* hardirq.h: unsigned long */
+       cmpib,<>,n 0,%r20,syscall_do_softirq /* forward */
 
 syscall_check_resched:
 
        /* check for reschedule */
 
-#error LDREG  TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19     /* long */
-       comib,<>,n 0,%r19,syscall_do_resched /* forward */
+       LDREG  TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19    /* long */
+       bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
 
 syscall_check_sig:
-       ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get task ptr */
+       /* These should be the same effect, but which is faster? */
+#if 1
+       mfctl   %cr30,%r1
+#else
+       ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1    /* get thread info ptr */
+#endif
        /* check for pending signals */
-#error ldw     TASK_SIGPENDING(%r1),%r19
-       comib,<>,n 0,%r19,syscall_do_signal  /* forward */
+       LDREG    TI_FLAGS(%r1),%r19
+       bb,<,n   %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */
 
 syscall_restore:
-       /* disable interrupts while dicking with the kernel stack, */
-       /* or life can become unpleasant */
-       rsm     PSW_SM_I, %r20
-#error LDREG   TASK_PTRACE(%r1), %r19          /* Are we being ptraced? */
-       bb,<,n  %r19,31,syscall_restore_rfi
-       LDREG   TASK_PT_GR20(%r1),%r19
-       mtctl   %r19, %cr27
+       mfctl   %cr30,%r1
+       LDREG   TI_FLAGS(%r1), %r19             /* Are we being ptraced? */
+       bb,<    %r19, 31-TIF_SYSCALL_TRACE,syscall_restore_rfi
+       LDREG   0(%r1),%r1                         /* delay slot! */
+       ldo     TASK_PT_FR31(%r1),%r19             /* reload fpregs */
+       rest_fp %r19
+
+       LDREG   TASK_PT_SAR(%r1),%r19              /* restore SAR */
+       mtsar   %r19
 
        LDREG   TASK_PT_GR2(%r1),%r2               /* restore user rp */
+       LDREG   TASK_PT_GR19(%r1),%r19
+       LDREG   TASK_PT_GR20(%r1),%r20
        LDREG   TASK_PT_GR21(%r1),%r21
        LDREG   TASK_PT_GR22(%r1),%r22
        LDREG   TASK_PT_GR23(%r1),%r23
@@ -1727,43 +2333,31 @@ syscall_restore:
        LDREG   TASK_PT_GR27(%r1),%r27     /* restore user dp */
        LDREG   TASK_PT_GR28(%r1),%r28     /* syscall return value */
        LDREG   TASK_PT_GR29(%r1),%r29
-       LDREG   TASK_PT_GR30(%r1),%r30     /* restore user sp */
        LDREG   TASK_PT_GR31(%r1),%r31     /* restore syscall rp */
-       ldo     TASK_PT_FR31(%r1),%r19             /* reload fpregs */
-       rest_fp %r19
-       LDREG   TASK_PT_SAR(%r1),%r19              /* restore SAR */
-       mtsar   %r19
-       LDREG   TASK_PT_GR19(%r1),%r19
 
-       mtctl   %r1,%cr30                          /* intrhandler okay. */
+       rsm     PSW_SM_I, %r0
+       LDREG   TASK_PT_GR30(%r1),%r30             /* restore user sp */
        mfsp    %sr3,%r1                           /* Get users space id */
+       mtsp    %r1,%sr7                           /* Restore sr7 */
+       ssm     PSW_SM_I, %r0
        mtsp    %r1,%sr4                           /* Restore sr4 */
        mtsp    %r1,%sr5                           /* Restore sr5 */
        mtsp    %r1,%sr6                           /* Restore sr6 */
 
        depi    3,31,2,%r31                        /* ensure return to user mode. */
 
-       mtsm    %r20                               /* restore irq state  */
-       mfctl   %cr27,%r20
-       
-       /*
-        * Due to a dependency in the tlb miss handlers on sr7, it
-        * is essential that sr7 get set in the delay slot.
-        */
-
 #ifdef __LP64__
-
-       /* Note the be (and mtsp) is executed in narrow mode. This is OK
-        * for 32 bit processes, but won't work once we support 64 bit
-        * processes.
+       /* Since we are returning to a 32 bit user process, we always
+        * clear the W bit. This means that the be (and mtsp) gets
+        * executed in narrow mode, but that is OK, since we are
+        * returning to a 32 bit process. When we support 64 bit processes
+        * we won't clear the W bit, so the be will run in wide mode.
         */
 
-       rsm     PSW_SM_W, %r0
        be      0(%sr3,%r31)                       /* return to user space */
-       mtsp    %r1,%sr7                           /* Restore sr7 */
+       rsm     PSW_SM_W, %r0
 #else
-       be      0(%sr3,%r31)                       /* return to user space */
-       mtsp    %r1,%sr7                           /* Restore sr7 */
+       be,n    0(%sr3,%r31)                       /* return to user space */
 #endif
 
        /* We have to return via an RFI, so that PSW T and R bits can be set
@@ -1772,45 +2366,55 @@ syscall_restore:
         * the most efficient way of doing things, but it works.
         */
 syscall_restore_rfi:
+       LDREG   TASK_PTRACE(%r1), %r19
        ldo     -1(%r0),%r2                        /* Set recovery cntr to -1 */
        mtctl   %r2,%cr0                           /*   for immediate trap */
-       copy    %r0,%r2                            /* Create a reasonable PSW */
+       LDREG   TASK_PT_PSW(%r1),%r2               /* Get old PSW */
+       ldi     0x0b,%r20                          /* Create new PSW */
+       depi    -1,13,1,%r20                       /* C, Q, D, and I bits */
+       bb,>=,n %r19,15,try_tbit                   /* PT_SINGLESTEP */
+       depi    -1,27,1,%r20                       /* R bit */
+try_tbit:
+       bb,>=,n %r19,14,psw_setup                  /* PT_BLOCKSTEP, see ptrace.c */
+       depi    -1,7,1,%r20                        /* T bit */
+psw_setup:
+       STREG   %r20,TASK_PT_PSW(%r1)
+
+       /* Always store space registers, since sr3 can be changed (e.g. fork) */
+
+       mfsp    %sr3,%r25
+       STREG   %r25,TASK_PT_SR3(%r1)
+       STREG   %r25,TASK_PT_SR4(%r1)
+       STREG   %r25,TASK_PT_SR5(%r1)
+       STREG   %r25,TASK_PT_SR6(%r1)
+       STREG   %r25,TASK_PT_SR7(%r1)
+       STREG   %r25,TASK_PT_IASQ0(%r1)
+       STREG   %r25,TASK_PT_IASQ1(%r1)
+
        /* XXX W bit??? */
-       depi    -1,13,1,%r2
-       depi    -1,28,1,%r2
-       depi    -1,30,1,%r2
-       depi    -1,31,1,%r2
-       bb,<,n  %r19,15,set_rbit                   /* PT_SINGLESTEP */
-       bb,>=,n %r19,14,set_nobit                  /* PT_BLOCKSTEP, see ptrace.c */
-set_tbit:
-       depi    -1,7,1,%r2
-       b,n     set_nobit
-set_rbit:
-       depi    -1,27,1,%r2
-set_nobit:
-       STREG   %r2,TASK_PT_PSW(%r1)
-       STREG   %r1,TASK_PT_CR30(%r1)
+       /* Now if old D bit is clear, it means we didn't save all registers
+        * on syscall entry, so do that now.  This only happens on TRACEME
+        * calls, or if someone attached to us while we were on a syscall.
+        * We could make this more efficient by not saving r3-r18, but
+        * then we wouldn't be able to use the common intr_restore path.
+        * It is only for traced processes anyway, so performance is not
+        * an issue.
+        */
+       bb,<    %r2,30,pt_regs_ok                  /* Branch if D set */
+       ldo     TASK_REGS(%r1),%r25
+       reg_save %r25                              /* Save r3 to r18 */
        mfsp    %sr0,%r2
        STREG   %r2,TASK_PT_SR0(%r1)
        mfsp    %sr1,%r2
        STREG   %r2,TASK_PT_SR1(%r1)
        mfsp    %sr2,%r2
        STREG   %r2,TASK_PT_SR2(%r1)
-       mfsp    %sr3,%r2
-       STREG   %r2,TASK_PT_SR3(%r1)
-       STREG   %r2,TASK_PT_SR4(%r1)
-       STREG   %r2,TASK_PT_SR5(%r1)
-       STREG   %r2,TASK_PT_SR6(%r1)
-       STREG   %r2,TASK_PT_SR7(%r1)
-       STREG   %r2,TASK_PT_IASQ0(%r1)
-       STREG   %r2,TASK_PT_IASQ1(%r1)
+pt_regs_ok:
        LDREG   TASK_PT_GR31(%r1),%r2
        depi    3,31,2,%r2                         /* ensure return to user mode. */
        STREG   %r2,TASK_PT_IAOQ0(%r1)
        ldo     4(%r2),%r2
        STREG   %r2,TASK_PT_IAOQ1(%r1)
-       ldo     TASK_REGS(%r1),%r25
-       reg_save %r25                              /* Save r3 to r18 */
        copy    %r25,%r16
        b       intr_restore
        nop
@@ -1825,7 +2429,11 @@ syscall_do_softirq:
        .import schedule,code
 syscall_do_resched:
        bl      schedule,%r2
+#ifdef __LP64__
+       ldo     -16(%r30),%r29          /* Reference param save area */
+#else
        nop
+#endif
        b       syscall_check_bh  /* if resched, we start over again */
        nop
 
@@ -1835,33 +2443,175 @@ syscall_do_signal:
           FIXME: After this point the process structure should be
           consistent with all the relevant state of the process
           before the syscall.  We need to verify this. */
+       LDREG   0(%r1),%r1
        ldo     TASK_REGS(%r1), %r25            /* struct pt_regs *regs */
        reg_save %r25
 
        ldi     1, %r24                         /* unsigned long in_syscall */
 
-#error bl      do_signal,%r2
+#ifdef __LP64__
+       ldo     -16(%r30),%r29                  /* Reference param save area */
+#endif
+#warning TAUSQ FIXME, this is wrong
+       bl      do_signal,%r2
        copy    %r0, %r26                       /* sigset_t *oldset = NULL */
 
-       ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30), %r1     /* reload task ptr */
+       mfctl   %cr30,%r1                       /* reload task ptr */
+       LDREG   0(%r1),%r1
        ldo     TASK_REGS(%r1), %r20            /* reload pt_regs */
        reg_restore %r20
 
        b,n     syscall_restore
 
-#ifdef __LP64__
-unimplemented_64bitirq:
-       ssm PSW_SM_Q+PSW_SM_I, %r0
-       /* indicate that we had an interrupt */
-       ldi     0x77, %r28
-       ldi     0x77, %r29
-       /* save interrupt registers in GRs for diagnosis */
-       mfctl %cr17, %r17
-       mfctl %cr18, %r18
-       mfctl %cr19, %r19
-       mfctl %cr20, %r20
-       mfctl %cr21, %r21
-       mfctl %cr22, %r22
-       b,n .
+       /*
+        * get_register is used by the non access tlb miss handlers to
+        * copy the value of the general register specified in r8 into
+        * r1. This routine can't be used for shadowed registers, since
+        * the rfir will restore the original value. So, for the shadowed
+        * registers we put a -1 into r1 to indicate that the register
+        * should not be used (the register being copied could also have
+        * a -1 in it, but that is OK, it just means that we will have
+        * to use the slow path instead).
+        */
+
+get_register:
+       blr     %r8,%r0
        nop
-#endif
+       bv      %r0(%r25)    /* r0 */
+       copy    %r0,%r1
+       bv      %r0(%r25)    /* r1 - shadowed */
+       ldi     -1,%r1
+       bv      %r0(%r25)    /* r2 */
+       copy    %r2,%r1
+       bv      %r0(%r25)    /* r3 */
+       copy    %r3,%r1
+       bv      %r0(%r25)    /* r4 */
+       copy    %r4,%r1
+       bv      %r0(%r25)    /* r5 */
+       copy    %r5,%r1
+       bv      %r0(%r25)    /* r6 */
+       copy    %r6,%r1
+       bv      %r0(%r25)    /* r7 */
+       copy    %r7,%r1
+       bv      %r0(%r25)    /* r8 - shadowed */
+       ldi     -1,%r1
+       bv      %r0(%r25)    /* r9 - shadowed */
+       ldi     -1,%r1
+       bv      %r0(%r25)    /* r10 */
+       copy    %r10,%r1
+       bv      %r0(%r25)    /* r11 */
+       copy    %r11,%r1
+       bv      %r0(%r25)    /* r12 */
+       copy    %r12,%r1
+       bv      %r0(%r25)    /* r13 */
+       copy    %r13,%r1
+       bv      %r0(%r25)    /* r14 */
+       copy    %r14,%r1
+       bv      %r0(%r25)    /* r15 */
+       copy    %r15,%r1
+       bv      %r0(%r25)    /* r16 - shadowed */
+       ldi     -1,%r1
+       bv      %r0(%r25)    /* r17 - shadowed */
+       ldi     -1,%r1
+       bv      %r0(%r25)    /* r18 */
+       copy    %r18,%r1
+       bv      %r0(%r25)    /* r19 */
+       copy    %r19,%r1
+       bv      %r0(%r25)    /* r20 */
+       copy    %r20,%r1
+       bv      %r0(%r25)    /* r21 */
+       copy    %r21,%r1
+       bv      %r0(%r25)    /* r22 */
+       copy    %r22,%r1
+       bv      %r0(%r25)    /* r23 */
+       copy    %r23,%r1
+       bv      %r0(%r25)    /* r24 - shadowed */
+       ldi     -1,%r1
+       bv      %r0(%r25)    /* r25 - shadowed */
+       ldi     -1,%r1
+       bv      %r0(%r25)    /* r26 */
+       copy    %r26,%r1
+       bv      %r0(%r25)    /* r27 */
+       copy    %r27,%r1
+       bv      %r0(%r25)    /* r28 */
+       copy    %r28,%r1
+       bv      %r0(%r25)    /* r29 */
+       copy    %r29,%r1
+       bv      %r0(%r25)    /* r30 */
+       copy    %r30,%r1
+       bv      %r0(%r25)    /* r31 */
+       copy    %r31,%r1
+
+       /*
+        * set_register is used by the non access tlb miss handlers to
+        * copy the value of r1 into the general register specified in
+        * r8.
+        */
+
+set_register:
+       blr     %r8,%r0
+       nop
+       bv      %r0(%r25)    /* r0 (silly, but it is a place holder) */
+       copy    %r1,%r0
+       bv      %r0(%r25)    /* r1 */
+       copy    %r1,%r1
+       bv      %r0(%r25)    /* r2 */
+       copy    %r1,%r2
+       bv      %r0(%r25)    /* r3 */
+       copy    %r1,%r3
+       bv      %r0(%r25)    /* r4 */
+       copy    %r1,%r4
+       bv      %r0(%r25)    /* r5 */
+       copy    %r1,%r5
+       bv      %r0(%r25)    /* r6 */
+       copy    %r1,%r6
+       bv      %r0(%r25)    /* r7 */
+       copy    %r1,%r7
+       bv      %r0(%r25)    /* r8 */
+       copy    %r1,%r8
+       bv      %r0(%r25)    /* r9 */
+       copy    %r1,%r9
+       bv      %r0(%r25)    /* r10 */
+       copy    %r1,%r10
+       bv      %r0(%r25)    /* r11 */
+       copy    %r1,%r11
+       bv      %r0(%r25)    /* r12 */
+       copy    %r1,%r12
+       bv      %r0(%r25)    /* r13 */
+       copy    %r1,%r13
+       bv      %r0(%r25)    /* r14 */
+       copy    %r1,%r14
+       bv      %r0(%r25)    /* r15 */
+       copy    %r1,%r15
+       bv      %r0(%r25)    /* r16 */
+       copy    %r1,%r16
+       bv      %r0(%r25)    /* r17 */
+       copy    %r1,%r17
+       bv      %r0(%r25)    /* r18 */
+       copy    %r1,%r18
+       bv      %r0(%r25)    /* r19 */
+       copy    %r1,%r19
+       bv      %r0(%r25)    /* r20 */
+       copy    %r1,%r20
+       bv      %r0(%r25)    /* r21 */
+       copy    %r1,%r21
+       bv      %r0(%r25)    /* r22 */
+       copy    %r1,%r22
+       bv      %r0(%r25)    /* r23 */
+       copy    %r1,%r23
+       bv      %r0(%r25)    /* r24 */
+       copy    %r1,%r24
+       bv      %r0(%r25)    /* r25 */
+       copy    %r1,%r25
+       bv      %r0(%r25)    /* r26 */
+       copy    %r1,%r26
+       bv      %r0(%r25)    /* r27 */
+       copy    %r1,%r27
+       bv      %r0(%r25)    /* r28 */
+       copy    %r1,%r28
+       bv      %r0(%r25)    /* r29 */
+       copy    %r1,%r29
+       bv      %r0(%r25)    /* r30 */
+       copy    %r1,%r30
+       bv      %r0(%r25)    /* r31 */
+       copy    %r1,%r31
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
new file mode 100644 (file)
index 0000000..ed978ea
--- /dev/null
@@ -0,0 +1,1150 @@
+/* arch/parisc/kernel/pdc.c  - safe pdc access routines
+ *
+ * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
+ * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
+ *
+ * only these routines should be used out of the real kernel (i.e. everything
+ * using virtual addresses) for obvious reasons */
+
+/*     I think it would be in everyone's best interest to follow this
+ *     guidelines when writing PDC wrappers:
+ *
+ *      - the name of the pdc wrapper should match one of the macros
+ *        used for the first two arguments
+ *      - don't use caps for random parts of the name
+ *      - use the static PDC result buffers and "copyout" to structs
+ *        supplied by the caller to encapsulate alignment restrictions
+ *      - hold pdc_lock while in PDC or using static result buffers
+ *      - use __pa() to convert virtual (kernel) pointers to physical
+ *        ones.
+ *      - the name of the struct used for pdc return values should equal
+ *        one of the macros used for the first two arguments to the
+ *        corresponding PDC call
+ *      - keep the order of arguments
+ *      - don't be smart (setting trailing NUL bytes for strings, return
+ *        something useful even if the call failed) unless you are sure
+ *        it's not going to affect functionality or performance
+ *
+ *     Example:
+ *     int pdc_cache_info(struct pdc_cache_info *cache_info )
+ *     {
+ *             int retval;
+ *
+ *             spin_lock_irq(&pdc_lock);
+ *             retval = mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+ *             convert_to_wide(pdc_result);
+ *             memcpy(cache_info, pdc_result, sizeof(*cache_info));
+ *             spin_unlock_irq(&pdc_lock);
+ *
+ *             return retval;
+ *     }
+ *                                     prumpf  991016  
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/system.h>
+#include <asm/processor.h>     /* for boot_cpu_data */
+
+#include <stdarg.h>
+
+static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long pdc_result[32] __attribute__ ((aligned (8)));
+static unsigned long pdc_result2[32] __attribute__ ((aligned (8)));
+
+/* on all currently-supported platforms, IODC I/O calls are always
+ * 32-bit calls, and MEM_PDC calls are always the same width as the OS.
+ * This means Cxxx boxes can't run wide kernels right now. -PB
+ *
+ * CONFIG_PDC_NARROW has been added to allow 64-bit kernels to run on
+ * systems with 32-bit MEM_PDC calls. This will allow wide kernels to
+ * run on Cxxx boxes now. -RB
+ *
+ * Note that some PAT boxes may have 64-bit IODC I/O...
+ */
+
+#ifdef __LP64__
+long real64_call(unsigned long function, ...);
+#endif
+long real32_call(unsigned long function, ...);
+
+#if defined(__LP64__) && ! defined(CONFIG_PDC_NARROW)
+#define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc
+#   define mem_pdc_call(args...) real64_call(MEM_PDC, args)
+#else
+#define MEM_PDC (unsigned long)PAGE0->mem_pdc
+#   define mem_pdc_call(args...) real32_call(MEM_PDC, args)
+#endif
+
+
+/**
+ * f_extend - Convert PDC addresses to kernel addresses.
+ * @address: Address returned from PDC.
+ *
+ * This function is used to convert PDC addresses into kernel addresses
+ * when the PDC address size and kernel address size are different.
+ */
+static unsigned long f_extend(unsigned long address)
+{
+#ifdef CONFIG_PDC_NARROW
+       if((address & 0xff000000) == 0xf0000000)
+               return 0xf0f0f0f000000000 | (u32)address;
+
+       if((address & 0xf0000000) == 0xf0000000)
+               return 0xffffffff00000000 | (u32)address;
+#endif
+       return address;
+}
+
+/**
+ * convert_to_wide - Convert the return buffer addresses into kernel addresses.
+ * @address: The return buffer from PDC.
+ *
+ * This function is used to convert the return buffer addresses retrieved from PDC
+ * into kernel addresses when the PDC address size and kernel address size are
+ * different.
+ */
+static void convert_to_wide(unsigned long *addr)
+{
+#ifdef CONFIG_PDC_NARROW
+       int i;
+       unsigned *p = (unsigned int *)addr;
+       for(i = 31; i >= 0; --i)
+               addr[i] = p[i];
+#endif
+}
+
+/**
+ * pdc_emergency_unlock - Unlock the linux pdc lock
+ *
+ * This call unlocks the linux pdc lock in case we need some PDC functions
+ * (like pdc_add_valid) during kernel stack dump.
+ */
+void pdc_emergency_unlock(void)
+{
+        spin_unlock(&pdc_lock);
+}
+
+
+/**
+ * pdc_add_valid - Verify address can be accessed without causing a HPMC.
+ * @address: Address to be verified.
+ *
+ * This PDC call attempts to read from the specified address and verifies
+ * if the address is valid.
+ * 
+ * The return value is PDC_OK (0) in case accessing this address is valid.
+ */
+int pdc_add_valid(unsigned long address)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, address);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_chassis_info - Return chassis information.
+ * @result: The return buffer.
+ * @chassis_info: The memory buffer address.
+ * @len: The size of the memory buffer address.
+ *
+ * An HVERSION dependent call for returning the chassis information.
+ */
+int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        memcpy(&pdc_result, chassis_info, sizeof(*chassis_info));
+        memcpy(&pdc_result2, led_info, len);
+        retval = mem_pdc_call(PDC_CHASSIS, PDC_RETURN_CHASSIS_INFO,
+                              __pa(pdc_result), __pa(pdc_result2), len);
+        memcpy(chassis_info, pdc_result, sizeof(*chassis_info));
+        memcpy(led_info, pdc_result2, len);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_pat_chassis_send_log - Sends a PDC PAT CHASSIS log message.
+ * @retval: -1 on error, 0 on success. Other value are PDC errors
+ * 
+ * Must be correctly formatted or expect system crash
+ */
+#ifdef __LP64__
+int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
+{
+       if (!is_pdc_pat())
+               return -1;
+
+       int retval = 0;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_CHASSIS_LOG, PDC_PAT_CHASSIS_WRITE_LOG, __pa(&state), __pa(&data));
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+#endif
+
+/**
+ * pdc_chassis_disp - Updates display
+ * @retval: -1 on error, 0 on success
+ *
+ * Works on old PDC only (E class, others?)
+ */
+int pdc_chassis_disp(unsigned long disp)
+{
+       int retval = 0;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_coproc_cfg - To identify coprocessors attached to the processor.
+ * @pdc_coproc_info: Return buffer address.
+ *
+ * This PDC call returns the presence and status of all the coprocessors
+ * attached to the processor.
+ */
+int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result));
+        convert_to_wide(pdc_result);
+        pdc_coproc_info->ccr_functional = pdc_result[0];
+        pdc_coproc_info->ccr_present = pdc_result[1];
+        pdc_coproc_info->revision = pdc_result[17];
+        pdc_coproc_info->model = pdc_result[18];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_iodc_read - Read data from the modules IODC.
+ * @actcnt: The actual number of bytes.
+ * @hpa: The HPA of the module for the iodc read.
+ * @index: The iodc entry point.
+ * @iodc_data: A buffer memory for the iodc options.
+ * @iodc_data_size: Size of the memory buffer.
+ *
+ * This PDC call reads from the IODC of the module specified by the hpa
+ * argument.
+ */
+int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
+                 void *iodc_data, unsigned int iodc_data_size)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_IODC, PDC_IODC_READ, __pa(pdc_result), hpa, 
+                             index, __pa(pdc_result2), iodc_data_size);
+       convert_to_wide(pdc_result);
+       *actcnt = pdc_result[0];
+       memcpy(iodc_data, pdc_result2, iodc_data_size);
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_system_map_find_mods - Locate unarchitected modules.
+ * @pdc_mod_info: Return buffer address.
+ * @mod_path: pointer to dev path structure.
+ * @mod_index: fixed address module index.
+ *
+ * To locate and identify modules which reside at fixed I/O addresses, which
+ * do not self-identify via architected bus walks.
+ */
+int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
+                            struct pdc_module_path *mod_path, long mod_index)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result), 
+                             __pa(pdc_result2), mod_index);
+       convert_to_wide(pdc_result);
+       memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info));
+       memcpy(mod_path, pdc_result2, sizeof(*mod_path));
+       spin_unlock_irq(&pdc_lock);
+
+       pdc_mod_info->mod_addr = f_extend(pdc_mod_info->mod_addr);
+       return retval;
+}
+
+/**
+ * pdc_system_map_find_addrs - Retrieve additional address ranges.
+ * @pdc_addr_info: Return buffer address.
+ * @mod_index: Fixed address module index.
+ * @addr_index: Address range index.
+ * 
+ * Retrieve additional information about subsequent address ranges for modules
+ * with multiple address ranges.  
+ */
+int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info, 
+                             long mod_index, long addr_index)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, __pa(pdc_result),
+                             mod_index, addr_index);
+       convert_to_wide(pdc_result);
+       memcpy(pdc_addr_info, pdc_result, sizeof(*pdc_addr_info));
+       spin_unlock_irq(&pdc_lock);
+
+       pdc_addr_info->mod_addr = f_extend(pdc_addr_info->mod_addr);
+       return retval;
+}
+
+/**
+ * pdc_model_info - Return model information about the processor.
+ * @model: The return buffer.
+ *
+ * Returns the version numbers, identifiers, and capabilities from the processor module.
+ */
+int pdc_model_info(struct pdc_model *model) 
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_INFO, __pa(pdc_result), 0);
+       convert_to_wide(pdc_result);
+       memcpy(model, pdc_result, sizeof(*model));
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_model_sysmodel - Get the system model name.
+ * @name: A char array of at least 81 characters.
+ *
+ * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L)
+ */
+int pdc_model_sysmodel(char *name)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_SYSMODEL, __pa(pdc_result),
+                              OS_ID_HPUX, __pa(name));
+        convert_to_wide(pdc_result);
+
+        if (retval == PDC_OK) {
+                name[pdc_result[0]] = '\0'; /* add trailing '\0' */
+        } else {
+                name[0] = 0;
+        }
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_versions - Identify the version number of each processor.
+ * @cpu_id: The return buffer.
+ * @id: The id of the processor to check.
+ *
+ * Returns the version number for each processor component.
+ *
+ * This comment was here before, but I do not know what it means :( -RB
+ * id: 0 = cpu revision, 1 = boot-rom-version
+ */
+int pdc_model_versions(unsigned long *versions, int id)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_VERSIONS, __pa(pdc_result), id);
+        convert_to_wide(pdc_result);
+        *versions = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_cpuid - Returns the CPU_ID.
+ * @cpu_id: The return buffer.
+ *
+ * Returns the CPU_ID value which uniquely identifies the cpu portion of
+ * the processor module.
+ */
+int pdc_model_cpuid(unsigned long *cpu_id)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CPU_ID, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        *cpu_id = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_model_capabilities - Returns the platform capabilities.
+ * @capabilities: The return buffer.
+ *
+ * Returns information about platform support for 32- and/or 64-bit
+ * OSes, IO-PDIR coherency, and virtual aliasing.
+ */
+int pdc_model_capabilities(unsigned long *capabilities)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+        retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        *capabilities = pdc_result[0];
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_cache_info - Return cache and TLB information.
+ * @cache_info: The return buffer.
+ *
+ * Returns information about the processor's cache and TLB.
+ */
+int pdc_cache_info(struct pdc_cache_info *cache_info)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_INFO, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        memcpy(cache_info, pdc_result, sizeof(*cache_info));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifndef CONFIG_PA20
+/**
+ * pdc_btlb_info - Return block TLB information.
+ * @btlb: The return buffer.
+ *
+ * Returns information about the hardware Block TLB.
+ */
+int pdc_btlb_info(struct pdc_btlb_info *btlb) 
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INFO, __pa(pdc_result), 0);
+        memcpy(btlb, pdc_result, sizeof(*btlb));
+        spin_unlock_irq(&pdc_lock);
+
+        if(retval < 0) {
+                btlb->max_size = 0;
+        }
+        return retval;
+}
+
+/**
+ * pdc_mem_map_hpa - Find fixed module information.  
+ * @address: The return buffer
+ * @mod_path: pointer to dev path structure.
+ *
+ * This call was developed for S700 workstations to allow the kernel to find
+ * the I/O devices (Core I/O). In the future (Kittyhawk and beyond) this
+ * call will be replaced (on workstations) by the architected PDC_SYSTEM_MAP
+ * call.
+ *
+ * This call is supported by all existing S700 workstations (up to  Gecko).
+ */
+int pdc_mem_map_hpa(struct pdc_memory_map *address,
+               struct pdc_module_path *mod_path)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        memcpy(pdc_result2, mod_path, sizeof(*mod_path));
+        retval = mem_pdc_call(PDC_MEM_MAP, PDC_MEM_MAP_HPA, __pa(pdc_result),
+                               __pa(pdc_result2));
+        memcpy(address, pdc_result, sizeof(*address));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+#endif /* !CONFIG_PA20 */
+
+/**
+ * pdc_lan_station_id - Get the LAN address.
+ * @lan_addr: The return buffer.
+ * @hpa: The network device HPA.
+ *
+ * Get the LAN station address when it is not directly available from the LAN hardware.
+ */
+int pdc_lan_station_id(char *lan_addr, unsigned long hpa)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
+                       __pa(pdc_result), hpa);
+       if (retval < 0) {
+               /* FIXME: else read MAC from NVRAM */
+               memset(lan_addr, 0, PDC_LAN_STATION_ID_SIZE);
+       } else {
+               memcpy(lan_addr, pdc_result, PDC_LAN_STATION_ID_SIZE);
+       }
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+
+/**
+ * pdc_get_initiator - Get the SCSI Interface Card params (SCSI ID, SDTR, SE or LVD)
+ * @hwpath: fully bc.mod style path to the device.
+ * @scsi_id: what someone told firmware the ID should be.
+ * @period: time in cycles 
+ * @width: 8 or 16-bit wide bus
+ * @mode: 0,1,2 -> SE,HVD,LVD signalling mode
+ *
+ * Get the SCSI operational parameters from PDC.
+ * Needed since HPUX never used BIOS or symbios card NVRAM.
+ * Most ncr/sym cards won't have an entry and just use whatever
+ * capabilities of the card are (eg Ultra, LVD). But there are
+ * several cases where it's useful:
+ *    o set SCSI id for Multi-initiator clusters,
+ *    o cable too long (ie SE scsi 10Mhz won't support 6m length),
+ *    o bus width exported is less than what the interface chip supports.
+ */
+int pdc_get_initiator( struct hardware_path *hwpath, unsigned char *scsi_id,
+       unsigned long *period, char *width, char *mode)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+
+/* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
+#define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
+       strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 9) == 0)
+
+       retval = mem_pdc_call(PDC_INITIATOR, PDC_GET_INITIATOR, 
+                             __pa(pdc_result), __pa(hwpath));
+
+
+       if (retval >= PDC_OK) {
+               *scsi_id = (unsigned char) pdc_result[0];
+
+               /* convert Bus speed in Mhz to period (in 1/10 ns) */
+               switch(pdc_result[1]) {
+               /*
+               ** case  0:   driver determines rate
+               ** case -1:   Settings are uninitialized.
+               */
+               case  5:  *period = 2000; break;
+               case 10:  *period = 1000; break;
+               case 20:  *period = 500; break;
+               case 40:  *period = 250; break;
+               default: /* Do nothing */ break;
+               }
+
+               /* 
+               ** pdc_result[2]        PDC suggested SCSI id
+               ** pdc_result[3]        PDC suggested SCSI rate
+               */
+
+               if (IS_SPROCKETS()) {
+                       /*
+                       ** Revisit: PAT PDC do the same thing?
+                       ** A500 also exports 50-pin SE SCSI.
+                       **      0 == 8-bit
+                       **      1 == 16-bit
+                       */
+                       *width = (char) pdc_result[4];
+
+                       /* ...in case someone needs it in the future.
+                       ** sym53c8xx.c comments say it can't autodetect
+                       ** for 825/825A/875 chips.
+                       **      0 == SE, 1 == HVD, 2 == LVD
+                       */
+                       *mode = (char) pdc_result[5]; 
+               }
+       }
+
+       spin_unlock_irq(&pdc_lock);
+       return retval >= PDC_OK;
+}
+
+
+/**
+ * pdc_pci_irt_size - Get the number of entries in the interrupt routing table.
+ * @num_entries: The return value.
+ * @hpa: The HPA for the device.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */ 
+int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE, 
+                             __pa(pdc_result), hpa);
+       convert_to_wide(pdc_result);
+       *num_entries = pdc_result[0];
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/** 
+ * pdc_pci_irt - Get the PCI interrupt routing table.
+ * @num_entries: The number of entries in the table.
+ * @hpa: The Hard Physical Address of the device.
+ * @tbl: 
+ *
+ * Get the PCI interrupt routing table for the device at the given HPA.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */
+int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       pdc_result[0] = num_entries;
+       retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, 
+                             __pa(pdc_result), hpa, __pa(tbl));
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+
+/**
+ * pdc_tod_read - Read the Time-Of-Day clock.
+ * @tod: The return buffer:
+ *
+ * Read the Time-Of-Day clock
+ */
+int pdc_tod_read(struct pdc_tod *tod)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(pdc_result), 0);
+        convert_to_wide(pdc_result);
+        memcpy(tod, pdc_result, sizeof(*tod));
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/**
+ * pdc_tod_set - Set the Time-Of-Day clock.
+ * @sec: The number of seconds since epoch.
+ * @usec: The number of micro seconds.
+ *
+ * Set the Time-Of-Day clock.
+ */ 
+int pdc_tod_set(unsigned long sec, unsigned long usec)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifdef __LP64__
+int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+               struct pdc_memory_table *tbl, unsigned long entries)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_MEM, PDC_MEM_TABLE, __pa(pdc_result), __pa(pdc_result2), entries);
+       convert_to_wide(pdc_result);
+       memcpy(r_addr, pdc_result, sizeof(*r_addr));
+       memcpy(tbl, pdc_result2, entries * sizeof(*tbl));
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+#endif /* __LP64__ */
+
+/* FIXME: Is this pdc used?  I could not find type reference to ftc_bitmap
+ * so I guessed at unsigned long.  Someone who knows what this does, can fix
+ * it later. :)
+ */
+int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_FIRM_TEST_RESET,
+                              PDC_FIRM_TEST_MAGIC, ftc_bitmap);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/*
+ * pdc_do_reset - Reset the system.
+ *
+ * Reset the system.
+ */
+int pdc_do_reset()
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);
+        retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+/*
+ * pdc_soft_power_info - Enable soft power switch.
+ * @power_reg: address of soft power register
+ *
+ * Return the absolute address of the soft power switch register
+ */
+int __init pdc_soft_power_info(unsigned long *power_reg)
+{
+       int retval;
+
+       *power_reg = (unsigned long) (-1);
+       
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_INFO, __pa(pdc_result), 0);
+       if (retval == PDC_OK) {
+                convert_to_wide(pdc_result);
+                *power_reg = f_extend(pdc_result[0]);
+       }
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/*
+ * pdc_soft_power_button - Control the soft power button behaviour
+ * @sw_control: 0 for hardware control, 1 for software control 
+ *
+ *
+ * This PDC function places the soft power button under software or
+ * hardware control.
+ * Under software control the OS may control to when to allow to shut 
+ * down the system. Under hardware control pressing the power button 
+ * powers off the system immediately.
+ */
+int pdc_soft_power_button(int sw_control)
+{
+       int retval;
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control);
+       spin_unlock_irq(&pdc_lock);
+       return retval;
+}
+
+/*
+ * pdc_suspend_usb - Stop USB controller
+ *
+ * If PDC used the usb controller, the usb controller
+ * is still running and will crash the machines during iommu 
+ * setup, because of still running DMA. This PDC call
+ * stops the USB controller
+ */
+void pdc_suspend_usb(void)
+{
+       spin_lock_irq(&pdc_lock);  
+       mem_pdc_call(PDC_IO, PDC_IO_SUSPEND_USB, 0);
+       spin_unlock_irq(&pdc_lock);
+}
+
+/**
+ * pdc_iodc_putc - Console character print using IODC.
+ * @c: the character to output.
+ *
+ * Note that only these special chars are architected for console IODC io:
+ * BEL, BS, CR, and LF. Others are passed through.
+ * Since the HP console requires CR+LF to perform a 'newline', we translate
+ * "\n" to "\r\n".
+ */
+void pdc_iodc_putc(unsigned char c)
+{
+        /* XXX Should we spinlock posx usage */
+        static int posx;        /* for simple TAB-Simulation... */
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+        unsigned int n;
+       unsigned int flags;
+
+        switch (c) {
+        case '\n':
+                iodc_dbuf[0] = '\r';
+                iodc_dbuf[1] = '\n';
+                n = 2;
+                posx = 0;
+                break;
+        case '\t':
+                pdc_iodc_putc(' ');
+                while (posx & 7)        /* expand TAB */
+                        pdc_iodc_putc(' ');
+                return;         /* return since IODC can't handle this */
+        case '\b':
+                posx-=2;                /* BS */
+        default:
+                iodc_dbuf[0] = c;
+                n = 1;
+                posx++;
+                break;
+        }
+
+        spin_lock_irqsave(&pdc_lock, flags);
+        real32_call(PAGE0->mem_cons.iodc_io,
+                    (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+                    PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+                    __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
+        spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+/**
+ * pdc_iodc_outc - Console character print using IODC (without conversions).
+ * @c: the character to output.
+ *
+ * Write the character directly to the IODC console.
+ */
+void pdc_iodc_outc(unsigned char c)
+{
+       unsigned int n, flags;
+
+       /* fill buffer with one caracter and print it */
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+
+       n = 1;
+       iodc_dbuf[0] = c;
+
+       spin_lock_irqsave(&pdc_lock, flags);
+       real32_call(PAGE0->mem_cons.iodc_io,
+                   (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+                   PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+                   __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
+       spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+/**
+ * pdc_iodc_getc - Read a character (non-blocking) from the PDC console.
+ *
+ * Read a character (non-blocking) from the PDC console, returns -1 if
+ * key is not present.
+ */
+int pdc_iodc_getc(void)
+{
+       unsigned int flags;
+        static int __attribute__((aligned(8)))   iodc_retbuf[32];
+        static char __attribute__((aligned(64))) iodc_dbuf[4096];
+       int ch;
+       int status;
+
+       /* Bail if no console input device. */
+       if (!PAGE0->mem_kbd.iodc_io)
+               return 0;
+       
+       /* wait for a keyboard (rs232)-input */
+       spin_lock_irqsave(&pdc_lock, flags);
+       real32_call(PAGE0->mem_kbd.iodc_io,
+                   (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
+                   PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers), 
+                   __pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
+
+       ch = *iodc_dbuf;
+       status = *iodc_retbuf;
+       spin_unlock_irqrestore(&pdc_lock, flags);
+
+       if (status == 0)
+           return -1;
+       
+       return ch;
+}
+
+int pdc_sti_call(unsigned long func, unsigned long flags,
+                 unsigned long inptr, unsigned long outputr,
+                 unsigned long glob_cfg)
+{
+        int retval;
+
+        spin_lock_irq(&pdc_lock);  
+        retval = real32_call(func, flags, inptr, outputr, glob_cfg);
+        spin_unlock_irq(&pdc_lock);
+
+        return retval;
+}
+
+#ifdef __LP64__
+/**
+ * pdc_pat_cell_get_number - Returns the cell number.
+ * @cell_info: The return buffer.
+ *
+ * This PDC call returns the cell number of the cell from which the call
+ * is made.
+ */
+int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_NUMBER, __pa(pdc_result));
+       memcpy(cell_info, pdc_result, sizeof(*cell_info));
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_pat_cell_module - Retrieve the cell's module information.
+ * @actcnt: The number of bytes written to mem_addr.
+ * @ploc: The physical location.
+ * @mod: The module index.
+ * @view_type: The view of the address type.
+ * @mem_addr: The return buffer.
+ *
+ * This PDC call returns information about each module attached to the cell
+ * at the specified location.
+ */
+int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod,
+                       unsigned long view_type, void *mem_addr)
+{
+       int retval;
+       static struct pdc_pat_cell_mod_maddr_block result __attribute__ ((aligned (8)));
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, __pa(pdc_result), 
+                             ploc, mod, view_type, __pa(&result));
+       if(!retval) {
+               *actcnt = pdc_result[0];
+               memcpy(mem_addr, &result, *actcnt);
+       }
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_pat_cpu_get_number - Retrieve the cpu number.
+ * @cpu_info: The return buffer.
+ * @hpa: The Hard Physical Address of the CPU.
+ *
+ * Retrieve the cpu number for the cpu at the specified HPA.
+ */
+int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
+                             __pa(&pdc_result), hpa);
+       memcpy(cpu_info, pdc_result, sizeof(*cpu_info));
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_pat_get_irt_size - Retrieve the number of entries in the cell's interrupt table.
+ * @num_entries: The return value.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ */
+int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE,
+                             __pa(pdc_result), cell_num);
+       *num_entries = pdc_result[0];
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_pat_get_irt - Retrieve the cell's interrupt table.
+ * @r_addr: The return buffer.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the actual interrupt table for the specified cell.
+ */
+int pdc_pat_get_irt(void *r_addr, unsigned long cell_num)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE,
+                             __pa(r_addr), cell_num);
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+
+/**
+ * pdc_pat_pd_get_addr_map - Retrieve information about memory address ranges.
+ * @actlen: The return buffer.
+ * @mem_addr: Pointer to the memory buffer.
+ * @count: The number of bytes to read from the buffer.
+ * @offset: The offset with respect to the beginning of the buffer.
+ *
+ */
+int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, 
+                           unsigned long count, unsigned long offset)
+{
+       int retval;
+
+       spin_lock_irq(&pdc_lock);
+       retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_ADDR_MAP, __pa(pdc_result), 
+                             __pa(pdc_result2), count, offset);
+       *actual_len = pdc_result[0];
+       memcpy(mem_addr, pdc_result2, *actual_len);
+       spin_unlock_irq(&pdc_lock);
+
+       return retval;
+}
+#endif /* __LP64__ */
+
+
+/***************** 32-bit real-mode calls ***********/
+/* The struct below is used
+ * to overlay real_stack (real2.S), preparing a 32-bit call frame.
+ * real32_call_asm() then uses this stack in narrow real mode
+ */
+
+struct narrow_stack {
+       /* use int, not long which is 64 bits */
+       unsigned int arg13;
+       unsigned int arg12;
+       unsigned int arg11;
+       unsigned int arg10;
+       unsigned int arg9;
+       unsigned int arg8;
+       unsigned int arg7;
+       unsigned int arg6;
+       unsigned int arg5;
+       unsigned int arg4;
+       unsigned int arg3;
+       unsigned int arg2;
+       unsigned int arg1;
+       unsigned int arg0;
+       unsigned int frame_marker[8];
+       unsigned int sp;
+       /* in reality, there's nearly 8k of stack after this */
+};
+
+long real32_call(unsigned long fn, ...)
+{
+       va_list args;
+       extern struct narrow_stack real_stack;
+       extern unsigned long real32_call_asm(unsigned int *,
+                                            unsigned int *, 
+                                            unsigned int);
+       
+       va_start(args, fn);
+       real_stack.arg0 = va_arg(args, unsigned int);
+       real_stack.arg1 = va_arg(args, unsigned int);
+       real_stack.arg2 = va_arg(args, unsigned int);
+       real_stack.arg3 = va_arg(args, unsigned int);
+       real_stack.arg4 = va_arg(args, unsigned int);
+       real_stack.arg5 = va_arg(args, unsigned int);
+       real_stack.arg6 = va_arg(args, unsigned int);
+       real_stack.arg7 = va_arg(args, unsigned int);
+       real_stack.arg8 = va_arg(args, unsigned int);
+       real_stack.arg9 = va_arg(args, unsigned int);
+       real_stack.arg10 = va_arg(args, unsigned int);
+       real_stack.arg11 = va_arg(args, unsigned int);
+       real_stack.arg12 = va_arg(args, unsigned int);
+       real_stack.arg13 = va_arg(args, unsigned int);
+       va_end(args);
+       
+       return real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+}
+
+#ifdef __LP64__
+/***************** 64-bit real-mode calls ***********/
+
+struct wide_stack {
+       unsigned long arg0;
+       unsigned long arg1;
+       unsigned long arg2;
+       unsigned long arg3;
+       unsigned long arg4;
+       unsigned long arg5;
+       unsigned long arg6;
+       unsigned long arg7;
+       unsigned long arg8;
+       unsigned long arg9;
+       unsigned long arg10;
+       unsigned long arg11;
+       unsigned long arg12;
+       unsigned long arg13;
+       unsigned long frame_marker[2];  /* rp, previous sp */
+       unsigned long sp;
+       /* in reality, there's nearly 8k of stack after this */
+};
+
+long real64_call(unsigned long fn, ...)
+{
+       va_list args;
+       extern struct wide_stack real_stack;
+       extern unsigned long real64_call_asm(unsigned long *,
+                                            unsigned long *, 
+                                            unsigned long);
+    
+       va_start(args, fn);
+       real_stack.arg0 = va_arg(args, unsigned long);
+       real_stack.arg1 = va_arg(args, unsigned long);
+       real_stack.arg2 = va_arg(args, unsigned long);
+       real_stack.arg3 = va_arg(args, unsigned long);
+       real_stack.arg4 = va_arg(args, unsigned long);
+       real_stack.arg5 = va_arg(args, unsigned long);
+       real_stack.arg6 = va_arg(args, unsigned long);
+       real_stack.arg7 = va_arg(args, unsigned long);
+       real_stack.arg8 = va_arg(args, unsigned long);
+       real_stack.arg9 = va_arg(args, unsigned long);
+       real_stack.arg10 = va_arg(args, unsigned long);
+       real_stack.arg11 = va_arg(args, unsigned long);
+       real_stack.arg12 = va_arg(args, unsigned long);
+       real_stack.arg13 = va_arg(args, unsigned long);
+       va_end(args);
+       
+       return real64_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+}
+
+#endif /* __LP64__ */
+
index 75d5c66..cb69214 100644 (file)
@@ -5,7 +5,7 @@
  * 
  *    Based on the document "PA-RISC 1.1 I/O Firmware Architecture 
  *    Reference Specification", March 7, 1999, version 0.96.  This
- *    is available at ?.
+ *    is available at http://parisc-linux.org/documentation/
  *
  *    Copyright 1999 by Alex deVries <adevries@thepuffingroup.com>
  *    and copyright 1999 The Puffin Group Inc.
 #include <asm/hardware.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-
-#define HPHW_NUM_TYPES 3431
-
-static char * hw_type_name[16] = {
-       "Processor",
-       "Memory",
-       "B DMA",
-       "Obsolete",
-       "A DMA",
-       "A Direct",
-       "Obsolete",
-       "Bus Converter Port",
-       "HP CIO Adapter",
-       "Console",
-       "Foreign I/O Module",
-       "Bus Adapter",
-       "IOA (?)",
-       "Bus Bridge to Foreign Bus",
-       "HP Clothing: Fabric Component"
-};
+#include <linux/init.h>
 
 /*
- *     XXX     Could this be __init ??
+ *     HP PARISC Hardware Database
+ *     Access to this database is only possible during bootup
+ *     so don't reference this table after starting the init process
  */
  
-static struct hp_hardware hp_hardware_list[] = {
+static struct hp_hardware hp_hardware_list[] __initdata = {
        {HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
        {HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
        {HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
@@ -169,9 +152,10 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_NPROC,0x59A,0x4,0x91,"Unlisted but reserved"},
        {HPHW_NPROC,0x59A,0x4,0x81,"Unlisted but reserved"},
        {HPHW_NPROC,0x59B,0x4,0x81,"Raven U 160 (9000/780/C160)"},
+       {HPHW_NPROC,0x59C,0x4,0x81,"Raven U 180 (9000/780/C180)"},
        {HPHW_NPROC,0x59D,0x4,0x81,"Raven U 200 (9000/780/C200)"},
        {HPHW_NPROC,0x59E,0x4,0x91,"ThunderHawk T' 120"},
-       {HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780/\?\?\?\?)"},
+       {HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780)"},
        {HPHW_NPROC,0x5A0,0x4,0x81,"UL 1w T120 1MB/1MB (841/D260,D360)"},
        {HPHW_NPROC,0x5A1,0x4,0x91,"UL 2w T120 1MB/1MB (851/D260,D360)"},
        {HPHW_NPROC,0x5A2,0x4,0x81,"UL 1w U160 512K/512K (861/D270,D370)"},
@@ -201,7 +185,7 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_NPROC,0x5B8,0x4,0x91,"SPP2250 240 MHz"},
        {HPHW_NPROC,0x5B9,0x4,0x81,"UL 1w U+/240 (350/550)"},
        {HPHW_NPROC,0x5BA,0x4,0x91,"UL 2w U+/240 (350/550)"},
-       {HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W "},
+       {HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W"},
        {HPHW_NPROC,0x5BC,0x4,0x91,"AllegroLow W"},
        {HPHW_NPROC,0x5BD,0x4,0x91,"Forte W 2-way"},
        {HPHW_NPROC,0x5BE,0x4,0x91,"Prelude W"},
@@ -212,12 +196,41 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_NPROC,0x5C3,0x4,0x91,"Sonata 360"},
        {HPHW_NPROC,0x5C4,0x4,0x91,"Rhapsody 440"},
        {HPHW_NPROC,0x5C5,0x4,0x91,"Rhapsody 360"},
-       {HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780/\?\?\?\?)"},
+       {HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780)"},
        {HPHW_NPROC,0x5C7,0x4,0x91,"Halfdome W 440"},
        {HPHW_NPROC,0x5C8,0x4,0x81,"Lego 360 processor"},
        {HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"},
        {HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"},
        {HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"},
+       {HPHW_NPROC,0x5CC,0x4,0x91,"Prelude W 440"},
+       {HPHW_NPROC,0x5CD,0x4,0x91,"SPP2600"},
+       {HPHW_NPROC,0x5CE,0x4,0x91,"M2600"},
+       {HPHW_NPROC,0x5CF,0x4,0x81,"Allegro W+"},
+       {HPHW_NPROC,0x5D0,0x4,0x81,"Kazoo W+"},
+       {HPHW_NPROC,0x5D1,0x4,0x91,"Forte W+ 2w"},
+       {HPHW_NPROC,0x5D2,0x4,0x91,"Forte W+ 4w"},
+       {HPHW_NPROC,0x5D3,0x4,0x91,"Prelude W+ 540"},
+       {HPHW_NPROC,0x5D4,0x4,0x91,"Duet W+"},
+       {HPHW_NPROC,0x5D5,0x4,0x91,"Crescendo 550"},
+       {HPHW_NPROC,0x5D6,0x4,0x81,"Crescendo DC- 440"},
+       {HPHW_NPROC,0x5D7,0x4,0x91,"Keystone W+"},
+       {HPHW_NPROC,0x5D8,0x4,0x91,"Rhapsody wave 2 W+ DC-"},
+       {HPHW_NPROC,0x5D9,0x4,0x91,"Rhapsody wave 2 W+"},
+       {HPHW_NPROC,0x5DA,0x4,0x91,"Marcato W+ DC-"},
+       {HPHW_NPROC,0x5DB,0x4,0x91,"Marcato W+"},
+       {HPHW_NPROC,0x5DC,0x4,0x91,"Allegro W2"},
+       {HPHW_NPROC,0x5DD,0x4,0x81,"Duet W2"},
+       {HPHW_NPROC,0x5DE,0x4,0x81,"Piccolo W+"},
+       {HPHW_NPROC,0x5DF,0x4,0x81,"Cantata W2"},
+       {HPHW_NPROC,0x5E0,0x4,0x91,"Cantata DC- W2"},
+       {HPHW_NPROC,0x5E1,0x4,0x91,"Crescendo DC- W2"},
+       {HPHW_NPROC,0x5E2,0x4,0x91,"Crescendo 650 W2"},
+       {HPHW_NPROC,0x5E3,0x4,0x91,"Crescendo 750 W2"},
+       {HPHW_NPROC,0x5E4,0x4,0x91,"Keystone/Matterhorn W2 750"},
+       {HPHW_NPROC,0x5E5,0x4,0x91,"PowerBar W+"},
+       {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
+       {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
+       {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
        {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
        {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
        {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
@@ -243,7 +256,7 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_NPROC,0x616,0x4,0x81,"Piranha 120"},
        {HPHW_NPROC,0x617,0x4,0x81,"Jason 50"},
        {HPHW_NPROC,0x618,0x4,0x81,"Jason 100"},
-       {HPHW_NPROC,0x619,0x4,0x81,"Mirage 80 "},
+       {HPHW_NPROC,0x619,0x4,0x81,"Mirage 80"},
        {HPHW_NPROC,0x61A,0x4,0x81,"SAIC L-80"},
        {HPHW_NPROC,0x61B,0x4,0x81,"Rocky1 L-60"},
        {HPHW_NPROC,0x61C,0x4,0x81,"Anole T (743/T)"},
@@ -311,6 +324,7 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_A_DMA, 0x004, 0x00050, 0x80, "Lanbrusca 802.3 (36967A)"}, 
        {HPHW_A_DMA, 0x004, 0x00056, 0x80, "HP-PB LoQuix FDDI"}, 
        {HPHW_A_DMA, 0x004, 0x00057, 0x80, "HP-PB LoQuix FDDI (28670A)"}, 
+       {HPHW_A_DMA, 0x004, 0x0005E, 0x00, "Gecko Add-on Token Ring"}, 
        {HPHW_A_DMA, 0x012, 0x00089, 0x80, "Barracuda Add-on FW-SCSI"}, 
        {HPHW_A_DMA, 0x013, 0x00089, 0x80, "Bluefish Add-on FW-SCSI"}, 
        {HPHW_A_DMA, 0x014, 0x00089, 0x80, "Shrike Add-on FW-SCSI"}, 
@@ -319,6 +333,7 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"}, 
        {HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"}, 
        {HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"}, 
+       {HPHW_A_DMA, 0x03b, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"}, 
        {HPHW_A_DMA, 0x03d, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"},
        {HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"}, 
        {HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"}, 
@@ -440,6 +455,8 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_BA, 0x801, 0x00081, 0x0, "Hitachi Tiny 80 Core BA"}, 
        {HPHW_BA, 0x004, 0x0008B, 0x0, "Anole Optional PCMCIA BA"}, 
        {HPHW_BA, 0x004, 0x0008E, 0x0, "GSC ITR Wax BA"}, 
+       {HPHW_BA, 0x00C, 0x0008E, 0x0, "Gecko Optional Wax BA"}, 
+       {HPHW_BA, 0x010, 0x0008E, 0x0, "Pace Wax BA"}, 
        {HPHW_BA, 0x011, 0x0008E, 0x0, "SuperPace Wax BA"}, 
        {HPHW_BA, 0x012, 0x0008E, 0x0, "Mirage Jr Wax BA"}, 
        {HPHW_BA, 0x013, 0x0008E, 0x0, "Mirage Wax BA"}, 
@@ -489,7 +506,7 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_BA, 0x800, 0x00090, 0x0, "Hitachi Tiny 64 Wax EISA BA"}, 
        {HPHW_BA, 0x801, 0x00090, 0x0, "Hitachi Tiny 80 Wax EISA BA"}, 
        {HPHW_BA, 0x01A, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
-       {HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 64 TIMI BA"}, 
+       {HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 100 TIMI BA"}, 
        {HPHW_BA, 0x034, 0x00093, 0x0, "Anole T TIMI BA"}, 
        {HPHW_BA, 0x04A, 0x00093, 0x0, "Anole L2 132 TIMI BA"}, 
        {HPHW_BA, 0x04C, 0x00093, 0x0, "Anole L2 165 TIMI BA"}, 
@@ -551,6 +568,7 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, 
        {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, 
        {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, 
+       {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, 
        {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, 
        {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, 
        {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, 
@@ -588,14 +606,14 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_FIO, 0x00D, 0x00072, 0x0, "Strider-33 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x00E, 0x00072, 0x0, "Trailways-50 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x00F, 0x00072, 0x0, "Trailways-33 Core LAN (802.3)"}, 
-       {HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core LAN (802.3)"}, 
        {HPHW_FIO, 0x019, 0x00072, 0x0, "Scorpio Sr. Core LAN (802.3)"}, 
        {HPHW_FIO, 0x020, 0x00072, 0x0, "Scorpio 100 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x021, 0x00072, 0x0, "Spectra 50 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x022, 0x00072, 0x0, "Spectra 75 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x023, 0x00072, 0x0, "Spectra 100 Core LAN (802.3)"}, 
-       {HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core LAN (802.3)"}, 
        {HPHW_FIO, 0x026, 0x00072, 0x0, "CoralII Jaguar Core LAN (802.3)"}, 
        {HPHW_FIO, 0x004, 0x00073, 0x0, "Cobra Core HIL"}, 
        {HPHW_FIO, 0x005, 0x00073, 0x0, "Coral Core HIL"}, 
@@ -694,8 +712,8 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"}, 
        {HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"}, 
        {HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"}, 
-       {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ wSE FWSCSI Core Centronics"}, 
-       {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ wDiff FWSCSI Core Centronics"}, 
+       {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ w SE FWSCSI Core Centronics"}, 
+       {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ w Diff FWSCSI Core Centronics"}, 
        {HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"}, 
        {HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"}, 
        {HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"}, 
@@ -861,66 +879,66 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_FIO, 0x02E, 0x00083, 0x0, "UL 350 Core PC Floppy"}, 
        {HPHW_FIO, 0x02F, 0x00083, 0x0, "UL 550 Core PC Floppy"}, 
        {HPHW_FIO, 0x032, 0x00083, 0x0, "Raven T' Core PC Floppy"}, 
-       {HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floopy"}, 
-       {HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floopy"}, 
-       {HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floopy"}, 
-       {HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floopy"}, 
-       {HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floopy"}, 
-       {HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floopy"}, 
-       {HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floopy"}, 
-       {HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floopy"}, 
-       {HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floopy"}, 
-       {HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floopy"}, 
-       {HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floopy"}, 
-       {HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floopy"}, 
-       {HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floopy"}, 
-       {HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floopy"}, 
-       {HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floopy"}, 
-       {HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floopy"}, 
-       {HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floopy"}, 
-       {HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PC Keyboard"}, 
-       {HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PC Keyboard"}, 
-       {HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PC Keyboard"}, 
-       {HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PC Keyboard"}, 
-       {HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PC Keyboard"}, 
-       {HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PC Keyboard"}, 
-       {HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PC Keyboard"}, 
-       {HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PC Keyboard"}, 
-       {HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PC Keyboard"}, 
-       {HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core Keyboard"}, 
-       {HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core Keyboard"}, 
-       {HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PC Keyboard"}, 
-       {HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PC Keyboard"}, 
-       {HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PC Keyboard"}, 
-       {HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PC Keyboard"}, 
-       {HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PC Keyboard"}, 
-       {HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PC Keyboard"}, 
-       {HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PC Keyboard"}, 
-       {HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PC Keyboard"}, 
+       {HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floppy"}, 
+       {HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floppy"}, 
+       {HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floppy"}, 
+       {HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floppy"}, 
+       {HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floppy"}, 
+       {HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floppy"}, 
+       {HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floppy"}, 
+       {HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floppy"}, 
+       {HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floppy"}, 
+       {HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floppy"}, 
+       {HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floppy"}, 
+       {HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floppy"}, 
+       {HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floppy"}, 
+       {HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floppy"}, 
+       {HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floppy"}, 
+       {HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floppy"}, 
+       {HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floppy"},
+       {HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PS/2 Port"}, 
+       {HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PS/2 Port"}, 
+       {HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PS/2 Port"}, 
+       {HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PS/2 Port"}, 
+       {HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PS/2 Port"}, 
+       {HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PS/2 Port"}, 
+       {HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PS/2 Port"}, 
+       {HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PS/2 Port"}, 
+       {HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PS/2 Port"}, 
+       {HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PS/2 Port"}, 
+       {HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PS/2 Port"}, 
+       {HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PS/2 Port"}, 
+       {HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PS/2 Port"}, 
+       {HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PS/2 Port"}, 
+       {HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PS/2 Port"}, 
        {HPHW_FIO, 0x004, 0x00085, 0x0, "Solo GSC Optional Graphics"}, 
        {HPHW_FIO, 0x005, 0x00085, 0x0, "Duet GSC Optional Graphics"}, 
        {HPHW_FIO, 0x008, 0x00085, 0x0, "Anole Artist Optional Graphics"}, 
@@ -969,18 +987,17 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_FIO, 0x034, 0x00088, 0x0, "Anole T VME Networking"}, 
        {HPHW_FIO, 0x04A, 0x00088, 0x0, "Anole L2 132 VME Networking"}, 
        {HPHW_FIO, 0x04C, 0x00088, 0x0, "Anole L2 165 VME Networking"}, 
-       {HPHW_FIO, 0x03B, 0x00089, 0x0, "Raven U/L2 Core FW-SCSI"}, 
-       {HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional Lan (802.3)"}, 
-       {HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional LAN (802.3)"}, 
+       {HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x01F, 0x0008A, 0x0, "SkyHawk 100/120 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x027, 0x0008A, 0x0, "Piranha 100 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x028, 0x0008A, 0x0, "Mirage Jr Core LAN (802.3)"}, 
@@ -991,24 +1008,24 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_FIO, 0x02E, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x02F, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x032, 0x0008A, 0x0, "Raven T' Core LAN (802.3)"}, 
-       {HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core LAN (802.3)"}, 
        {HPHW_FIO, 0x045, 0x0008A, 0x0, "Rocky1 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x046, 0x0008A, 0x0, "Rocky2 120 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x047, 0x0008A, 0x0, "Rocky2 150 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x04B, 0x0008A, 0x0, "Anole L2 132 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x04D, 0x0008A, 0x0, "Anole L2 165 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x04E, 0x0008A, 0x0, "Kiji L2 132 Core LAN (802.3)"}, 
-       {HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x058, 0x0008A, 0x0, "FireHawk 200 Core LAN (802.3)"}, 
-       {HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core Lan (802.3)"}, 
-       {HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core Lan (802.3)"}, 
+       {HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core LAN (802.3)"}, 
+       {HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core LAN (802.3)"}, 
        {HPHW_FIO, 0x004, 0x0008C, 0x0, "SkyHawk 100/120 Wax RS-232"}, 
        {HPHW_FIO, 0x005, 0x0008C, 0x0, "SAIC L-80 Wax RS-232"}, 
        {HPHW_FIO, 0x006, 0x0008C, 0x0, "Raven U/L2 Dino RS-232"}, 
@@ -1099,14 +1116,15 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_FIO, 0x005, 0x0008F, 0x0, "Rocky1 Boot Rom"}, 
        {HPHW_FIO, 0x006, 0x0008F, 0x0, "Rocky2 120 Boot Rom"}, 
        {HPHW_FIO, 0x007, 0x0008F, 0x0, "Rocky2 150 Boot Rom"}, 
-       {HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS2 Keyboard"}, 
-       {HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS2 Keyboard"}, 
-       {HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS2 Keyboard"}, 
-       {HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS2 Keyboard"}, 
-       {HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS2 Keyboard"}, 
-       {HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS2 Keyboard"}, 
-       {HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS2 Keyboard"}, 
-       {HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG lan"}, 
+       {HPHW_FIO, 0x01B, 0x0008F, 0x0, "Anole 100 Boot Rom"}, 
+       {HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS/2 Port"}, 
+       {HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG LAN"}, 
        {HPHW_FIO, 0x023, 0x00099, 0x0, "Rocky1 Wax HPIB"}, 
        {HPHW_FIO, 0x048, 0x00099, 0x0, "Rocky2 120 Clark/Dino HPIB"}, 
        {HPHW_FIO, 0x049, 0x00099, 0x0, "Rocky2 150 Clark/Dino HPIB"}, 
@@ -1114,14 +1132,14 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_FIO, 0x004, 0x000A2, 0x0, "Forte Core PCI 10/100BT LAN"}, 
        {HPHW_FIO, 0x005, 0x000A2, 0x0, "AllegroLow PCI 10/100BT LAN"}, 
        {HPHW_FIO, 0x006, 0x000A2, 0x0, "AllegroHIgh Core PCI 10/100BT LAN"}, 
-       {HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in Lan"}, 
-       {HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT Lan"}, 
-       {HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI Lan"}, 
-       {HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI Lan"}, 
-       {HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI Lan"}, 
-       {HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI Lan"}, 
-       {HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI Lan"}, 
-       {HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI Lan"}, 
+       {HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in LAN"}, 
+       {HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT LAN"}, 
+       {HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI LAN"}, 
+       {HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI LAN"}, 
+       {HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI LAN"}, 
+       {HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI LAN"}, 
+       {HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI LAN"}, 
+       {HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI LAN"}, 
        {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI LVD Ultra2 SCSI"}, 
        {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI SE UltraSCSI"}, 
        {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI IDE/ATAPI CD-ROM"}, 
@@ -1157,160 +1175,19 @@ static struct hp_hardware hp_hardware_list[] = {
        {HPHW_IOA, 0x185, 0x0000B, 0x00, "Java BC Summit Port"}, 
        {HPHW_IOA, 0x1FF, 0x0000B, 0x00, "Hitachi Ghostview Summit Port"}, 
        {HPHW_IOA, 0x580, 0x0000B, 0x10, "U2-IOA BC Runway Port"}, 
-       {HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"}, 
-       {HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"}, 
-       {HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"}, 
+       {HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"},
+       {HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"},
+       {HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"},
        {HPHW_MEMORY, 0x002, 0x00008, 0x00, "MID_BUS"}, 
-       {HPHW_MEMORY, 0x00C, 0x00008, 0x08, "Kahlua 8MB"}, 
-       {HPHW_MEMORY, 0x00D, 0x00008, 0x08, "Kahlua 4MB"}, 
-       {HPHW_MEMORY, 0x00E, 0x00008, 0x08, "Tequila 16MB"}, 
-       {HPHW_MEMORY, 0x00F, 0x00008, 0x08, "Tequila 32MB"}, 
-       {HPHW_MEMORY, 0x040, 0x00008, 0x00, "Hitachi"}, 
-       {HPHW_MEMORY, 0x004, 0x00009, 0x00, "Cheetah"}, 
-       {HPHW_MEMORY, 0x005, 0x00009, 0x00, "Emerald"}, 
-       {HPHW_MEMORY, 0x008, 0x00009, 0x00, "Indigo 3MB/5MB"}, 
-       {HPHW_MEMORY, 0x00C, 0x00009, 0x00, "Indigo 8MB"}, 
-       {HPHW_MEMORY, 0x00D, 0x00009, 0x00, "Paradise 4MB"}, 
-       {HPHW_MEMORY, 0x00E, 0x00009, 0x00, "Burgundy Onboard"}, 
-       {HPHW_MEMORY, 0x012, 0x00009, 0x00, "Indigo 12MB/20MB"}, 
-       {HPHW_MEMORY, 0x013, 0x00009, 0x00, "Cobra"}, 
-       {HPHW_MEMORY, 0x014, 0x00009, 0x00, "Nova"}, 
-       {HPHW_MEMORY, 0x015, 0x00009, 0x00, "Coral"}, 
-       {HPHW_MEMORY, 0x016, 0x00009, 0x00, "Bushmaster"}, 
-       {HPHW_MEMORY, 0x017, 0x00009, 0x00, "Scorpio"}, 
-       {HPHW_MEMORY, 0x018, 0x00009, 0x00, "Flounder"}, 
-       {HPHW_MEMORY, 0x019, 0x00009, 0x00, "Hardball"}, 
-       {HPHW_MEMORY, 0x01A, 0x00009, 0x00, "CoralII 99"}, 
-       {HPHW_MEMORY, 0x01B, 0x00009, 0x00, "Scorpio Jr."}, 
-       {HPHW_MEMORY, 0x01C, 0x00009, 0x00, "Strider-50 (715T)"}, 
-       {HPHW_MEMORY, 0x01D, 0x00009, 0x00, "Strider-33 (707T)"}, 
-       {HPHW_MEMORY, 0x01E, 0x00009, 0x00, "Trailways-50 (715S)"}, 
-       {HPHW_MEMORY, 0x01F, 0x00009, 0x00, "Trailways-33 (707S)"}, 
-       {HPHW_MEMORY, 0x020, 0x00009, 0x00, "Pace"}, 
-       {HPHW_MEMORY, 0x021, 0x00009, 0x00, "Sidewinder"}, 
-       {HPHW_MEMORY, 0x022, 0x00009, 0x00, "Orville"}, 
-       {HPHW_MEMORY, 0x023, 0x00009, 0x00, "Wilbur"}, 
-       {HPHW_MEMORY, 0x026, 0x00009, 0x00, "Gecko"}, 
-       {HPHW_MEMORY, 0x027, 0x00009, 0x00, "Scorpio Sr."}, 
-       {HPHW_MEMORY, 0x028, 0x00009, 0x00, "Scorpio 100"}, 
-       {HPHW_MEMORY, 0x029, 0x00009, 0x00, "Spectra 50"}, 
-       {HPHW_MEMORY, 0x02A, 0x00009, 0x00, "CoralII 132"}, 
-       {HPHW_MEMORY, 0x02F, 0x00009, 0x00, "KittyHawk DC2-"}, 
-       {HPHW_MEMORY, 0x030, 0x00009, 0x00, "Spectra 75"}, 
-       {HPHW_MEMORY, 0x031, 0x00009, 0x00, "Spectra 100"}, 
-       {HPHW_MEMORY, 0x032, 0x00009, 0x00, "KittyHawk DC3"}, 
-       {HPHW_MEMORY, 0x033, 0x00009, 0x00, "Fast Pace"}, 
-       {HPHW_MEMORY, 0x034, 0x00009, 0x00, "Snake Eagle"}, 
-       {HPHW_MEMORY, 0x035, 0x00009, 0x00, "Anole 64"}, 
-       {HPHW_MEMORY, 0x036, 0x00009, 0x00, "Anole 100"}, 
-       {HPHW_MEMORY, 0x037, 0x00009, 0x00, "Snake Cheetah"}, 
-       {HPHW_MEMORY, 0x038, 0x00009, 0x00, "Gecko 80"}, 
-       {HPHW_MEMORY, 0x039, 0x00009, 0x00, "Gecko 100"}, 
-       {HPHW_MEMORY, 0x03A, 0x00009, 0x00, "Gecko 120"}, 
-       {HPHW_MEMORY, 0x03B, 0x00009, 0x00, "Gila 80"}, 
-       {HPHW_MEMORY, 0x03C, 0x00009, 0x00, "Gila 100"}, 
-       {HPHW_MEMORY, 0x03D, 0x00009, 0x00, "Gila 120"}, 
-       {HPHW_MEMORY, 0x03E, 0x00009, 0x00, "Scorpio-L 80"}, 
-       {HPHW_MEMORY, 0x03F, 0x00009, 0x00, "Scorpio-L 100"}, 
-       {HPHW_MEMORY, 0x040, 0x00009, 0x00, "Scorpio-L 120"}, 
-       {HPHW_MEMORY, 0x041, 0x00009, 0x00, "Spectra-L 80"}, 
-       {HPHW_MEMORY, 0x042, 0x00009, 0x00, "Spectra-L 100"}, 
-       {HPHW_MEMORY, 0x043, 0x00009, 0x00, "Spectra-L 120"}, 
-       {HPHW_MEMORY, 0x044, 0x00009, 0x00, "Piranha 100"}, 
-       {HPHW_MEMORY, 0x045, 0x00009, 0x00, "Piranha 120"}, 
-       {HPHW_MEMORY, 0x046, 0x00009, 0x00, "Jason 50"}, 
-       {HPHW_MEMORY, 0x047, 0x00009, 0x00, "Jason 100"}, 
-       {HPHW_MEMORY, 0x049, 0x00009, 0x00, "SkyHawk 100/120"}, 
-       {HPHW_MEMORY, 0x04A, 0x00009, 0x00, "Mirage Jr"}, 
-       {HPHW_MEMORY, 0x04B, 0x00009, 0x00, "Mirage 100"}, 
-       {HPHW_MEMORY, 0x04C, 0x00009, 0x00, "Mirage 100+"}, 
-       {HPHW_MEMORY, 0x04D, 0x00009, 0x00, "Electra 100"}, 
-       {HPHW_MEMORY, 0x04E, 0x00009, 0x00, "Electra 120"}, 
-       {HPHW_MEMORY, 0x04F, 0x00009, 0x00, "Mirage 80"}, 
-       {HPHW_MEMORY, 0x050, 0x00009, 0x00, "UL Proc 1 way T'100"}, 
-       {HPHW_MEMORY, 0x051, 0x00009, 0x00, "UL Proc 1 way T'120"}, 
-       {HPHW_MEMORY, 0x052, 0x00009, 0x00, "UL Proc 2 way T'100"}, 
-       {HPHW_MEMORY, 0x053, 0x00009, 0x00, "KittyHawk DC3-"}, 
-       {HPHW_MEMORY, 0x054, 0x00009, 0x00, "UL Proc 2 way T'120"}, 
-       {HPHW_MEMORY, 0x055, 0x00009, 0x00, "Raven 120 mem"}, 
-       {HPHW_MEMORY, 0x056, 0x00009, 0x00, "UL Proc L 75"}, 
-       {HPHW_MEMORY, 0x057, 0x00009, 0x00, "UL Proc L 100"}, 
-       {HPHW_MEMORY, 0x058, 0x00009, 0x00, "Anole T"}, 
-       {HPHW_MEMORY, 0x059, 0x00009, 0x00, "SAIC L-80"}, 
-       {HPHW_MEMORY, 0x05A, 0x00009, 0x00, "Merlin+ L2 180"}, 
-       {HPHW_MEMORY, 0x05B, 0x00009, 0x00, "Raven U 200 2-way"}, 
-       {HPHW_MEMORY, 0x05C, 0x00009, 0x00, "Raven U 180+"}, 
-       {HPHW_MEMORY, 0x05D, 0x00009, 0x00, "Raven U 200"}, 
-       {HPHW_MEMORY, 0x05E, 0x00009, 0x00, "Rocky2 150 Memory"}, 
-       {HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
-       {HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
-       {HPHW_MEMORY, 0x05F, 0x00009, 0x00, "SPP2000 Memory"}, 
-       {HPHW_MEMORY, 0x060, 0x00009, 0x00, "Merlin L2 132"}, 
-       {HPHW_MEMORY, 0x061, 0x00009, 0x00, "Merlin+ L2 132"}, 
        {HPHW_MEMORY, 0x063, 0x00009, 0x00, "712/132 L2 Upgrade"}, 
        {HPHW_MEMORY, 0x064, 0x00009, 0x00, "712/160 L2 Upgrade"}, 
        {HPHW_MEMORY, 0x065, 0x00009, 0x00, "715/132 L2 Upgrade"}, 
-       {HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"}, 
-       {HPHW_MEMORY, 0x067, 0x00009, 0x00, "Merlin 160/ThunderHawk Memory"}, 
-       {HPHW_MEMORY, 0x068, 0x00009, 0x00, "LightningHawk Memory"}, 
-       {HPHW_MEMORY, 0x069, 0x00009, 0x00, "Rocky1 Memory"}, 
-       {HPHW_MEMORY, 0x06A, 0x00009, 0x00, "Raven L2 132"}, 
-       {HPHW_MEMORY, 0x06B, 0x00009, 0x00, "Raven L2 160"}, 
-       {HPHW_MEMORY, 0x06C, 0x00009, 0x00, "Raven L2 187"}, 
-       {HPHW_MEMORY, 0x06D, 0x00009, 0x00, "Raven L2 200"}, 
-       {HPHW_MEMORY, 0x06E, 0x00009, 0x00, "Raven U 230"}, 
-       {HPHW_MEMORY, 0x06F, 0x00009, 0x00, "Raven U 240"}, 
-       {HPHW_MEMORY, 0x070, 0x00009, 0x00, "Rocky2 120 Memory"}, 
-       {HPHW_MEMORY, 0x071, 0x00009, 0x00, "Raven U 160"}, 
-       {HPHW_MEMORY, 0x072, 0x00009, 0x00, "Raven U 180"}, 
-       {HPHW_MEMORY, 0x072, 0x00009, 0x00, "UL Proc 1 way T'120 1MB/1MB"}, 
-       {HPHW_MEMORY, 0x073, 0x00009, 0x00, "UL Proc 2 way T'120 1MB/1MB"}, 
-       {HPHW_MEMORY, 0x074, 0x00009, 0x00, "Anole L2 132 memory"}, 
-       {HPHW_MEMORY, 0x075, 0x00009, 0x00, "Anole L2 165 memory"}, 
-       {HPHW_MEMORY, 0x076, 0x00009, 0x00, "UL 1 way U160 512K/512K memory"}, 
-       {HPHW_MEMORY, 0x077, 0x00009, 0x00, "UL 2 way U160 512K/512K memory"}, 
-       {HPHW_MEMORY, 0x078, 0x00009, 0x00, "Kiji L2 132 memory"}, 
-       {HPHW_MEMORY, 0x079, 0x00009, 0x00, "UL 1 way U160 1M/1M memory"}, 
-       {HPHW_MEMORY, 0x07A, 0x00009, 0x00, "UL 2 way U160 1M/1M memory"}, 
-       {HPHW_MEMORY, 0x07B, 0x00009, 0x00, "UL 1 way U180 1M/1M memory"}, 
-       {HPHW_MEMORY, 0x07C, 0x00009, 0x00, "UL 2 way U180 1M/1M memory"}, 
-       {HPHW_MEMORY, 0x07D, 0x00009, 0x00, "UL 1 way U240 U+ 2M/2M memory"}, 
-       {HPHW_MEMORY, 0x07E, 0x00009, 0x00, "UL 2 way U240 U+ 2M/2M memory"}, 
-       {HPHW_MEMORY, 0x07F, 0x00009, 0x00, "UL L2 132 memory"}, 
-       {HPHW_MEMORY, 0x080, 0x00009, 0x00, "UL L2 160 memory"}, 
-       {HPHW_MEMORY, 0x081, 0x00009, 0x00, "Merlin Jr 132 memory"}, 
-       {HPHW_MEMORY, 0x082, 0x00009, 0x00, "FireHawk 200 Memory"}, 
-       {HPHW_MEMORY, 0x083, 0x00009, 0x00, "SummitHawk Memory"}, 
-       {HPHW_MEMORY, 0x084, 0x00009, 0x00, "Jade Upgrade Memory"}, 
-       {HPHW_MEMORY, 0x085, 0x00009, 0x00, "SPP2500 Memory"}, 
-       {HPHW_MEMORY, 0x086, 0x00009, 0x00, "AllegroHigh Memory"}, 
-       {HPHW_MEMORY, 0x087, 0x00009, 0x00, "AllegroLow Memory"}, 
-       {HPHW_MEMORY, 0x088, 0x00009, 0x00, "Forte 2w Memory"}, 
-       {HPHW_MEMORY, 0x089, 0x00009, 0x00, "Forte 4w Memory"}, 
-       {HPHW_MEMORY, 0x08A, 0x00009, 0x00, "Staccato L2 132 Memory"}, 
-       {HPHW_MEMORY, 0x08B, 0x00009, 0x00, "Staccato L2 180 Memory"}, 
-       {HPHW_MEMORY, 0x090, 0x00009, 0x00, "Prelude SMC Memory"}, 
-       {HPHW_MEMORY, 0x091, 0x00009, 0x00, "Lego 360 Memory"}, 
-       {HPHW_MEMORY, 0x7FF, 0x00009, 0x00, "NEC Aska memory"}, 
-       {HPHW_MEMORY, 0x800, 0x00009, 0x00, "Hitachi Tiny 64"}, 
-       {HPHW_MEMORY, 0x801, 0x00009, 0x00, "Hitachi Tiny 80"}, 
-       {HPHW_MEMORY, 0x8FF, 0x00009, 0x00, "Hitachi X memory"}, 
-       {HPHW_MEMORY, 0x091, 0x00009, 0x00, "M2250 Memory"}, 
-       {HPHW_MEMORY, 0x092, 0x00009, 0x00, "M2500 Memory"}, 
-       {HPHW_MEMORY, 0x093, 0x00009, 0x00, "Sonata 440 Memory"}, 
-       {HPHW_MEMORY, 0x094, 0x00009, 0x00, "Sonata 360 Memory"}, 
-       {HPHW_MEMORY, 0x095, 0x00009, 0x00, "Rhapsody 440 Memory"}, 
-       {HPHW_MEMORY, 0x096, 0x00009, 0x00, "Rhapsody 360 Memory"}, 
-       {HPHW_MEMORY, 0x097, 0x00009, 0x00, "Raven W 360 Memory"}, 
-       {HPHW_MEMORY, 0x098, 0x00009, 0x00, "Halfdome W 440 Memory"}, 
-       {HPHW_MEMORY, 0x099, 0x00009, 0x00, "Rhapsody DC- 440 Memory"}, 
-       {HPHW_MEMORY, 0x09A, 0x00009, 0x00, "Rhapsody DC- 360 Memory"}, 
-       {HPHW_MEMORY, 0x09B, 0x00009, 0x00, "Crescendo Memory"}, 
+       {HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"},
        {HPHW_OTHER, 0x004, 0x00030, 0x00, "Master"}, 
        {HPHW_OTHER, 0x004, 0x00034, 0x00, "Slave"}, 
        {HPHW_OTHER, 0x004, 0x00038, 0x00, "EDU"}, 
        {HPHW_OTHER, 0x004, 0x00049, 0x00, "LGB Control"}, 
-        {0, }                  /* leave the last entry empty ! */
+       {HPHW_FAULTY, 0, }  /* Special Marker for last entry */
 };
 
 
@@ -1318,7 +1195,7 @@ static struct hp_cpu_type_mask {
        unsigned short model;
        unsigned short mask;
        enum cpu_type cpu;
-} hp_cpu_type_mask_list[] = {
+} hp_cpu_type_mask_list[] __initdata = {
 
        { 0x0000, 0x0ff0, pcx    },  /* 0x0000 - 0x000f */
        { 0x0048, 0x0ff0, pcxl   },  /* 0x0040 - 0x004f */
@@ -1350,8 +1227,10 @@ static struct hp_cpu_type_mask {
        { 0x0592, 0x0fff, pcxt_  },  /* 0x0592 - 0x0592 */
        { 0x0593, 0x0fff, pcxu   },  /* 0x0593 - 0x0593 */
        { 0x0594, 0x0ffc, pcxu   },  /* 0x0594 - 0x0597 */
-       { 0x0598, 0x0ffc, pcxu   },  /* 0x0598 - 0x059b */
-       { 0x059c, 0x0ffe, pcxu_  },  /* 0x059c - 0x059d */
+       { 0x0598, 0x0ffe, pcxu_  },  /* 0x0598 - 0x0599 */
+       { 0x059a, 0x0ffe, pcxu   },  /* 0x059a - 0x059b */
+       { 0x059c, 0x0fff, pcxu   },  /* 0x059c - 0x059c */
+       { 0x059d, 0x0fff, pcxu_  },  /* 0x059d - 0x059d */
        { 0x059e, 0x0fff, pcxt_  },  /* 0x059e - 0x059e */
        { 0x059f, 0x0fff, pcxu   },  /* 0x059f - 0x059f */
        { 0x05a0, 0x0ffe, pcxt_  },  /* 0x05a0 - 0x05a1 */
@@ -1370,7 +1249,27 @@ static struct hp_cpu_type_mask {
        { 0x05ba, 0x0fff, pcxu_  },  /* 0x05ba - 0x05ba */
        { 0x05bb, 0x0fff, pcxw   },  /* 0x05bb - 0x05bb */
        { 0x05bc, 0x0ffc, pcxw   },  /* 0x05bc - 0x05bf */
-       { 0x05c0, 0x0fc0, pcxw   },  /* 0x05c0 - 0x05ff */
+       { 0x05c0, 0x0ffc, pcxw   },  /* 0x05c0 - 0x05c3 */
+       { 0x05c4, 0x0ffe, pcxw   },  /* 0x05c4 - 0x05c5 */
+       { 0x05c6, 0x0fff, pcxw   },  /* 0x05c6 - 0x05c6 */
+       { 0x05c7, 0x0fff, pcxw_  },  /* 0x05c7 - 0x05c7 */
+       { 0x05c8, 0x0ffc, pcxw   },  /* 0x05c8 - 0x05cb */
+       { 0x05cc, 0x0ffe, pcxw   },  /* 0x05cc - 0x05cd */
+       { 0x05ce, 0x0ffe, pcxw_  },  /* 0x05ce - 0x05cf */
+       { 0x05d0, 0x0ffc, pcxw_  },  /* 0x05d0 - 0x05d3 */
+       { 0x05d4, 0x0ffe, pcxw_  },  /* 0x05d4 - 0x05d5 */
+       { 0x05d6, 0x0fff, pcxw   },  /* 0x05d6 - 0x05d6 */
+       { 0x05d7, 0x0fff, pcxw_  },  /* 0x05d7 - 0x05d7 */
+       { 0x05d8, 0x0ffc, pcxw_  },  /* 0x05d8 - 0x05db */
+       { 0x05dc, 0x0ffe, pcxw2  },  /* 0x05dc - 0x05dd */
+       { 0x05de, 0x0fff, pcxw_  },  /* 0x05de - 0x05de */
+       { 0x05df, 0x0fff, pcxw2  },  /* 0x05df - 0x05df */
+       { 0x05e0, 0x0ffc, pcxw2  },  /* 0x05e0 - 0x05e3 */
+       { 0x05e4, 0x0fff, pcxw2  },  /* 0x05e4 - 0x05e4 */
+       { 0x05e5, 0x0fff, pcxw_  },  /* 0x05e5 - 0x05e5 */
+       { 0x05e6, 0x0ffe, pcxw2  },  /* 0x05e6 - 0x05e7 */
+       { 0x05e8, 0x0ff8, pcxw2  },  /* 0x05e8 - 0x05ef */
+       { 0x05f0, 0x0ff0, pcxw2  },  /* 0x05f0 - 0x05ff */
        { 0x0600, 0x0ff0, pcxl   },  /* 0x0600 - 0x060f */
        { 0x0610, 0x0ff0, pcxl   },  /* 0x0610 - 0x061f */
        { 0x0000, 0x0000, pcx    }      /* terminate table */
@@ -1386,36 +1285,51 @@ char *cpu_name_version[][2] = {
        [pcxu]  { "PA8000 (PCX-U)",     "2.0" },
        [pcxu_] { "PA8200 (PCX-U+)",    "2.0" },
        [pcxw]  { "PA8500 (PCX-W)",     "2.0" },
-       [pcxw_] { "PA8600 (PCX-W+)",    "2.0" }
+       [pcxw_] { "PA8600 (PCX-W+)",    "2.0" },
+       [pcxw2] { "PA8700 (PCX-W2)",    "2.0" }
 };
 
-char *parisc_getHWtype(unsigned short hw_type)
-{
-       if (hw_type <= HPHW_CIO) {
-               return hw_type_name[hw_type];
-       } else {
-               return "Unknown Type";
-       }
-}
-
-char *parisc_getHWdescription(unsigned short hw_type, unsigned long hversion,
-               unsigned long sversion)
+const char * __init
+parisc_hardware_description(struct parisc_device_id *id)
 {
        struct hp_hardware *listptr;
        
-       for (listptr = hp_hardware_list; listptr->name; listptr++) {
-               if ((listptr->hw_type==hw_type) &&
-                               (listptr->hversion==hversion) &&
-                               (listptr->sversion==sversion)){
+       for (listptr = hp_hardware_list; listptr->hw_type != HPHW_FAULTY; listptr++) {
+               if ((listptr->hw_type == id->hw_type) &&
+                               (listptr->hversion == id->hversion) &&
+                               (listptr->sversion == id->sversion)){
                        return listptr->name;
                }
        }
+
+       /*
+        * ok, the above hardware table isn't complete, and we haven't found
+        * our device in this table. So let's now try to find a generic name
+        * to describe the given hardware...
+        */
+       switch (id->hw_type) {
+               case HPHW_NPROC:
+                       return "Unknown machine";
+
+               case HPHW_A_DIRECT:
+                       switch (id->sversion) {
+                               case 0x0D: return "MUX port";
+                               case 0x0E: return "RS-232 port";
+                       }
+                       break;
+                       
+               case HPHW_MEMORY:
+                       return "Memory";
+                       
+       }
+       
        return "unknown device";
 }
 
 
 /* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */
-enum cpu_type parisc_get_cpu_type(unsigned long hversion)
+enum cpu_type __init
+parisc_get_cpu_type(unsigned long hversion)
 {
        struct hp_cpu_type_mask *ptr;
        unsigned short model = ((unsigned short) (hversion)) >> 4;
@@ -1424,23 +1338,8 @@ enum cpu_type parisc_get_cpu_type(unsigned long hversion)
                if (ptr->model == (model & ptr->mask))
                        return ptr->cpu;
        }
-       panic("parisc_get_cpu_type() could not identify CPU type\n");
+       panic("could not identify CPU type\n");
 
        return pcx;     /* not reached: */
 }
 
-
-struct hp_hardware *parisc_get_reference(unsigned short hw_type,
-               unsigned long hversion, unsigned long sversion)
-{
-       struct hp_hardware *listptr = hp_hardware_list;
-
-       for (listptr = hp_hardware_list; listptr->name; listptr++) {
-               if ((listptr->hw_type == hw_type) &&
-                               (listptr->hversion == hversion) &&
-                               (listptr->sversion == sversion)) {
-                       return listptr;
-               }
-       }
-       return NULL;
-}
index ce45dd6..f57e991 100644 (file)
@@ -8,17 +8,14 @@
  * Copyright 1999 SuSE GmbH (Philipp Rumpf)
  * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
  *
- * Initial Version 04-23-1999 by Helge Deller (helge.deller@ruhr-uni-bochum.de)
+ * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
  */
 
+#include <linux/autoconf.h>    /* for CONFIG_SMP */
 
-#include <asm/offset.h>
+#include <asm/offsets.h>
 #include <asm/psw.h>
 
-#define __ASSEMBLY__
-/*********
-#include <asm/pdc.h>
-*********/
 #include <asm/assembly.h>
 #include <asm/pgtable.h>
 
@@ -36,9 +33,18 @@ __setup_start:
        .export __setup_end
 __setup_end:
 
+       .data
+
+       .export boot_args
+boot_args:
+       .word 0 /* arg0 */
+       .word 0 /* arg1 */
+       .word 0 /* arg2 */
+       .word 0 /* arg3 */
+
        .text
        .align  4       
-       .import init_task_union,data
+       .import init_thread_union,data
        .import $global$                /* forward declaration */
        .import fault_vector_11,code    /* IVA parisc 1.1 32 bit */
        .import fault_vector_20,code    /* IVA parisc 2.0 32 bit */
@@ -52,43 +58,129 @@ stext:
        .callinfo
 
        /* Make sure sr4-sr7 are set to zero for the kernel address space */
+       mtsp    %r0,%sr4
+       mtsp    %r0,%sr5
+       mtsp    %r0,%sr6
+       mtsp    %r0,%sr7
 
-       mtsp            %r0,%sr4
-       mtsp            %r0,%sr5
-       mtsp            %r0,%sr6
-       mtsp            %r0,%sr7
+       /* Clear BSS (shouldn't the boot loader do this?) */
 
-       /* Initialize startup VM. Just map first 8 MB of memory */
+       .import _edata,data
+       .import _end,data
 
+       ldil            L%PA(_edata),%r3
+       ldo             R%PA(_edata)(%r3),%r3
+       ldil            L%PA(_end),%r4
+       ldo             R%PA(_end)(%r4),%r4
+$bss_loop:
+       cmpb,<<,n       %r3,%r4,$bss_loop
+       stb,ma          %r0,1(%r3)
+
+       /* Save away the arguments the boot loader passed in (32 bit args) */
+
+       ldil            L%PA(boot_args),%r1
+       ldo             R%PA(boot_args)(%r1),%r1
+       stw,ma          %arg0,4(%r1)
+       stw,ma          %arg1,4(%r1)
+       stw,ma          %arg2,4(%r1)
+       stw,ma          %arg3,4(%r1)
+
+       /* Initialize startup VM. Just map first 8 MB of memory */
        ldil            L%PA(pg0),%r1
        ldo             R%PA(pg0)(%r1),%r1
        ldo             _PAGE_TABLE(%r1),%r3
+
        ldil            L%PA(swapper_pg_dir),%r4
        ldo             R%PA(swapper_pg_dir)(%r4),%r4
        mtctl           %r4,%cr24       /* Initialize kernel root pointer */
        mtctl           %r4,%cr25       /* Initialize user root pointer */
-       stw             %r3,0xc00(%r4)  /* Hardwired 0xc0000000 kernel vaddr start */
+
+#if (__PAGE_OFFSET != 0x10000000UL)
+Error! Code below (the next two stw's) needs to be changed
+#endif
+
+       stw             %r3,0x100(%r4)  /* Hardwired 0x1... kernel Vaddr start*/
        ldo             0x1000(%r3),%r3
-       stw             %r3,0xc04(%r4)
-       ldo             _PAGE_KERNEL(%r0),%r3 /* Hardwired 0x0 phys addr start */
+       stw             %r3,0x104(%r4)
+       ldo             _PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
 $pgt_fill_loop:
        stwm            %r3,4(%r1)
        ldo             0x1000(%r3),%r3
        bb,>=           %r3,8,$pgt_fill_loop
        nop
 
+
+       /* Load the return address...er...crash 'n burn */
+       copy            %r0,%r2
+
+       /* And the RFI Target address too */
+       ldil            L%start_kernel,%r11
+       ldo             R%start_kernel(%r11),%r11
+
+       /* And the initial task pointer */
+
+       ldil            L%init_thread_union,%r6
+       ldo             R%init_thread_union(%r6),%r6
+       mtctl           %r6,%cr30
+
+       /* And the stack pointer too */
+
+       ldo             THREAD_SZ_ALGN(%r6),%sp
+
+       /* And the interrupt stack */
+
+       ldil            L%interrupt_stack,%r6
+       ldo             R%interrupt_stack(%r6),%r6
+       mtctl           %r6,%cr31
+
+#ifdef CONFIG_SMP
+       /* Set the smp rendevous address into page zero.
+       ** It would be safer to do this in init_smp_config() but
+       ** it's just way easier to deal with here because
+       ** of 64-bit function ptrs and the address is local to this file.
+       */
+       ldil            L%PA(smp_slave_stext),%r10
+       ldo             R%PA(smp_slave_stext)(%r10),%r10
+       stw             %r10,0x10(%r0)  /* MEM_RENDEZ */
+       stw             %r0,0x28(%r0)   /* MEM_RENDEZ_HI - assume addr < 4GB */
+
+       /* FALLTHROUGH */
+       .procend
+
+       /*
+       ** Code Common to both Monarch and Slave processors.
+       ** Entry:
+       **    %r11 must contain RFI target address.
+       **    %r25/%r26 args to pass to target function
+       **    %r2  in case rfi target decides it didn't like something
+       **
+       ** Caller must init: SR4-7, %sp, %r10, %cr24/25, 
+       */
+common_stext:
+       .proc
+       .callinfo
+#else
+       /* Clear PDC entry point - we won't use it */
+       stw             %r0,0x10(%r0)   /* MEM_RENDEZ */
+       stw             %r0,0x28(%r0)   /* MEM_RENDEZ_HI */
+#endif
+
+       /* PARANOID: clear user scratch/user space SR's */
+       mtsp    %r0,%sr0
+       mtsp    %r0,%sr1
+       mtsp    %r0,%sr2
+       mtsp    %r0,%sr3
+
+       /* Initialize Protection Registers */
+       mtctl   %r0,%cr8
+       mtctl   %r0,%cr9
+       mtctl   %r0,%cr12
+       mtctl   %r0,%cr13
+
        /* Initialize the global data pointer */
        ldil            L%$global$,%dp
        ldo             R%$global$(%dp),%dp
-       
-       /* And the stack pointer, physical too */
-       ldil            L%init_task_union+TASK_SZ_ALGN,%sp
-       ldo             R%init_task_union+TASK_SZ_ALGN(%sp),%sp
 
-       /* we need this to take interruptions directly after the rfi below */
-       /* (which we need for PA2.0 boxes) */
-       mtctl           %r0, %cr30
-       
        /*
         * Set up our interrupt table.  HPMCs might not work after this! 
         *
@@ -96,7 +188,6 @@ $pgt_fill_loop:
         * following short sequence of instructions can determine this
         * (without being illegal on a PA1.1 machine).
         */
-       
        ldi             32,%r10
        mtctl           %r10,%cr11
        .level 2.0
@@ -114,30 +205,30 @@ $is_pa20:
 $install_iva:
        mtctl           %r10,%cr14
 
-       /* Disable (most) interruptions */
-       mtsm            %r0                     
-       
+       /* Disable Q bit so we can load the iia queue */
+       rsm            PSW_SM_Q,%r0
+
        /* kernel PSW:
-        *  - no interruptions except for HPMC and TOC (which are handled by PDC)
+        *  - no interruptions except HPMC and TOC (which are handled by PDC)
         *  - Q bit set (IODC / PDC interruptions)
         *  - big-endian
         *  - virtually mapped
         */
-
        ldil            L%KERNEL_PSW,%r10
        ldo             R%KERNEL_PSW(%r10),%r10
        mtctl           %r10,%ipsw
-       
-       /* Set the space pointers for the post-RFI world */
-       mtctl           %r0,%cr17               /* Clear two-level IIA Space Queue */
-       mtctl           %r0,%cr17               /*    effectively setting kernel space. */
 
-       /* And the return address(es) too */
-       ldil            L%start_parisc,%r10
-       ldo             R%start_parisc(%r10),%r10
-       mtctl           %r10,%cr18
-       ldo             4(%r10),%r10
-       mtctl           %r10,%cr18
+       /* Set the space pointers for the post-RFI world
+       ** Clear the two-level IIA Space Queue, effectively setting
+       ** Kernel space.
+       */
+       mtctl           %r0,%cr17
+       mtctl           %r0,%cr17
+
+       /* Load RFI target into PC queue */
+       mtctl           %r11,%cr18
+       ldo             4(%r11),%r11
+       mtctl           %r11,%cr18
 
        /* Jump to hyperspace */
        rfi
@@ -145,6 +236,71 @@ $install_iva:
 
        .procend
 
+#ifdef CONFIG_SMP
+
+       .import smp_init_current_idle_task,data
+       .import smp_callin,code
+
+smp_callin_rtn:
+        .proc
+       .callinfo
+       break   1,1             /*  Break if returned from start_secondary */
+       nop
+       nop
+        .procend
+
+/***************************************************************************
+*
+* smp_slave_stext is executed by all non-monarch Processors when the Monarch
+* pokes the slave CPUs in smp.c:smp_boot_cpus().
+*
+* Once here, registers values are initialized in order to branch to virtual
+* mode. Once all available/eligible CPUs are in virtual mode, all are
+* released and start out by executing their own idle task.
+*****************************************************************************/
+
+
+smp_slave_stext:
+        .proc
+       .callinfo
+
+       /*
+       ** Initialize Space registers
+       */
+       mtsp       %r0,%sr4
+       mtsp       %r0,%sr5
+       mtsp       %r0,%sr6
+       mtsp       %r0,%sr7
+
+       /*  Initialize the SP - monarch sets up smp_init_current_idle_task */
+       ldil            L%PA(smp_init_current_idle_task),%sp
+       ldo             R%PA(smp_init_current_idle_task)(%sp),%sp
+       ldw             0(%sp),%sp      /* load task address */
+       mtctl           %sp,%cr30       /* store in cr30 */
+       addil           L%TASK_SZ_ALGN,%sp      /* stack is above task */
+       ldo             R%TASK_SZ_ALGN(%r1),%sp
+
+       /* point CPU to kernel page tables */
+       ldil            L%PA(swapper_pg_dir),%r4
+       ldo             R%PA(swapper_pg_dir)(%r4),%r4
+       mtctl           %r4,%cr24       /* Initialize kernel root pointer */
+       mtctl           %r4,%cr25       /* Initialize user root pointer */
+
+       /* Load RFI *return* address in case smp_callin bails */
+       ldil            L%smp_callin_rtn,%r2
+       ldo             R%smp_callin_rtn(%r2),%r2
+
+       /* Load RFI target address.  */
+       ldil            L%smp_callin,%r11
+       ldo             R%smp_callin(%r11),%r11
+       
+       /* ok...common code can handle the rest */
+       b               common_stext
+       nop
+
+       .procend
+#endif /* CONFIG_SMP */
+
        .data
 
        .align  4
diff --git a/arch/parisc/kernel/head64.S b/arch/parisc/kernel/head64.S
new file mode 100644 (file)
index 0000000..6d040a0
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999 by Helge Deller
+ * Copyright 1999 SuSE GmbH (Philipp Rumpf)
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2000 Hewlett Packard (Paul Bame, bame@puffin.external.hp.com)
+ * Copyright (C) 2001 Grant Grundler (Hewlett Packard)
+ *
+ * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
+ */
+
+
+#include <linux/autoconf.h>    /* for CONFIG_SMP */
+
+#include <asm/offsets.h>
+#include <asm/psw.h>
+
+#include <asm/assembly.h>
+#include <asm/pgtable.h>
+#include <asm/pdc.h>           /* for PDC_PSW defines */
+
+
+       .level 2.0w
+
+       .section        .initcall.init
+       .align          4
+       .export __initcall_start
+__initcall_start:
+       .export __initcall_end
+__initcall_end:
+       .export __setup_start
+__setup_start:
+       .export __setup_end
+__setup_end:
+
+       .data
+
+       .export boot_args
+boot_args:
+       .word 0 /* arg0 */
+       .word 0 /* arg1 */
+       .word 0 /* arg2 */
+       .word 0 /* arg3 */
+
+       .text
+       .align  4       
+
+       .export stext
+       .export _stext,data             /* Kernel want it this way! */
+_stext:
+stext:
+       .proc
+       .callinfo
+
+       /* Make sure sr4-sr7 are set to zero for the kernel address space */
+       mtsp    %r0,%sr4
+       mtsp    %r0,%sr5
+       mtsp    %r0,%sr6
+       mtsp    %r0,%sr7
+
+       /* Clear BSS (shouldn't the boot loader do this?) */
+
+       .import _edata,data
+       .import _end,data
+
+       ldil            L%PA(_edata),%r3
+       ldo             R%PA(_edata)(%r3),%r3
+       ldil            L%PA(_end),%r4
+       ldo             R%PA(_end)(%r4),%r4
+$bss_loop:
+       cmpb,<<,n       %r3,%r4,$bss_loop
+       stb,ma          %r0,1(%r3)
+
+       /* Save away the arguments the boot loader passed in (32 bit args) */
+
+       ldil            L%PA(boot_args),%r1
+       ldo             R%PA(boot_args)(%r1),%r1
+       stw,ma          %arg0,4(%r1)
+       stw,ma          %arg1,4(%r1)
+       stw,ma          %arg2,4(%r1)
+       stw,ma          %arg3,4(%r1)
+
+       /* Initialize startup VM. Just map first 8 MB of memory */
+
+       ldil            L%PA(pg0),%r1
+       ldo             R%PA(pg0)(%r1),%r1
+
+       ldil            L%PA(pmd0),%r5
+       ldo             R%PA(pmd0)(%r5),%r5
+       ldo             _PAGE_TABLE(%r5),%r3
+
+       ldil            L%PA(swapper_pg_dir),%r4
+       ldo             R%PA(swapper_pg_dir)(%r4),%r4
+
+       mtctl           %r4,%cr24       /* Initialize kernel root pointer */
+       mtctl           %r4,%cr25       /* Initialize user root pointer */
+
+#if (__PAGE_OFFSET != 0x10000000UL)
+Error! Code below (the next five std's) needs to be changed
+#endif
+
+       std             %r3,0x00(%r4)   /* Hardwired 0x1... kernel Vaddr start*/
+
+       ldo             _PAGE_TABLE(%r1),%r3
+       std             %r3,0x400(%r5)  /* Hardwired 0x1... kernel Vaddr start*/
+       ldo             0x1000(%r3),%r3
+       std             %r3,0x408(%r5)
+       ldo             0x1000(%r3),%r3
+       std             %r3,0x410(%r5)
+       ldo             0x1000(%r3),%r3
+       std             %r3,0x418(%r5)
+
+       ldo             _PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
+$pgt_fill_loop:
+       std,ma          %r3,8(%r1)
+       ldo             0x1000(%r3),%r3
+       bb,>=           %r3,8,$pgt_fill_loop
+       nop
+
+       /* And the RFI Target address too */
+       load32          start_kernel, %r11
+
+       /* And the stack pointer too */
+       load32          PA(init_thread_union+THREAD_SZ_ALGN),%sp
+
+       /* And the initial task pointer */
+
+       load32          init_thread_union,%r6
+       mtctl           %r6,%cr30
+
+       /* And the interrupt stack */
+
+       load32          interrupt_stack,%r6
+       mtctl           %r6,%cr31
+
+       /* Act like PDC just called us - that's how slave CPUs enter */
+#define MEM_PDC_LO 0x388
+#define MEM_PDC_HI 0x35C
+       ldw             MEM_PDC_LO(%r0),%r3
+       ldw             MEM_PDC_HI(%r0),%r6
+       depd            %r6, 31, 32, %r3        /* move to upper word */
+
+#ifdef CONFIG_SMP
+       /* Set the smp rendevous address into page zero.
+       ** It would be safer to do this in init_smp_config() but
+       ** it's just way easier to deal with here because
+       ** of 64-bit function ptrs and the address is local to this file.
+       */
+       ldil            L%PA(smp_slave_stext),%r10
+       ldo             R%PA(smp_slave_stext)(%r10),%r10
+       stw             %r10,0x10(%r0)  /* MEM_RENDEZ */
+       stw             %r0,0x28(%r0)   /* MEM_RENDEZ_HI - assume addr < 4GB */
+
+       /* FALLTHROUGH */
+       .procend
+
+       /*
+       ** Code Common to both Monarch and Slave processors.
+       ** Entry:
+       **    %r3       PDCE_PROC address
+       **    %r11      RFI target address.
+       **
+       ** Caller must init: SR4-7, %sp, %r10, %cr24/25, 
+       */
+common_stext:
+       .proc
+       .callinfo
+#else /* CONFIG_SMP */
+       /* Clear PDC's CPU handoff address - we won't use it */
+       stw             %r0,0x10(%r0)   /* MEM_RENDEZ */
+       stw             %r0,0x28(%r0)   /* MEM_RENDEZ_HI */
+#endif /* CONFIG_SMP */
+
+       /* Save the rfi target address */
+       std             %r11,  TASK_PT_GR11-TASK_SZ_ALGN(%sp)
+
+#ifndef CONFIG_PDC_NARROW
+       /* Switch to wide mode; Superdome doesn't support narrow PDC
+       ** calls.
+       */
+1:     mfia            %rp             /* clear upper part of pcoq */
+       ldo             2f-1b(%rp),%rp
+       depdi           0,31,32,%rp
+       bv              (%rp)
+       ssm             PSW_SM_W,%r0
+2:
+#endif /* CONFIG_PDC_NARROW */
+
+       /* Set Wide mode as the "Default" (eg for traps)
+       ** First trap occurs *right* after (or part of) rfi for slave CPUs.
+       ** Someday, palo might not do this for the Monarch either.
+       */
+
+       ldo             PDC_PSW(%r0),%arg0              /* 21 */
+       ldo             PDC_PSW_SET_DEFAULTS(%r0),%arg1 /* 2 */
+       ldo             PDC_PSW_WIDE_BIT(%r0),%arg2     /* 2 */
+
+       load32          PA(stext_pdc_ret), %rp
+
+       bv              (%r3)
+       copy            %r0,%arg3
+
+stext_pdc_ret:
+       /* restore rfi target address*/
+       ldd             TASK_PT_GR11-TASK_SZ_ALGN(%sp), %r11
+
+       /* PARANOID: clear user scratch/user space SR's */
+       mtsp    %r0,%sr0
+       mtsp    %r0,%sr1
+       mtsp    %r0,%sr2
+       mtsp    %r0,%sr3
+
+       /* Initialize Protection Registers */
+       mtctl   %r0,%cr8
+       mtctl   %r0,%cr9
+       mtctl   %r0,%cr12
+       mtctl   %r0,%cr13
+
+       /* Prepare to RFI! Man all the cannons! */
+       tovirt_r1       %sp
+
+       /* Initialize the global data pointer */
+       load32          __gp,%dp
+
+       /* Set up our interrupt table.  HPMCs might not work after this! */
+       ldil            L%PA(fault_vector_20),%r10
+       ldo             R%PA(fault_vector_20)(%r10),%r10
+       mtctl           %r10,%cr14
+
+       b               aligned_rfi
+       nop
+
+       /* the magic spell */
+       .align          256
+aligned_rfi:
+       ssm             0,0
+       nop             /* 1 */
+       nop             /* 2 */
+       nop             /* 3 */
+       nop             /* 4 */
+       nop             /* 5 */
+       nop             /* 6 */
+       nop             /* 7 */
+       nop             /* 8 */
+
+       /* turn off troublesome PSW bits */
+       rsm             PSW_Q+PSW_I+PSW_D+PSW_P+PSW_R, %r0
+
+       /* kernel PSW:
+        *  - no interruptions except HPMC and TOC (which are handled by PDC)
+        *  - Q bit set (IODC / PDC interruptions)
+        *  - big-endian
+        *  - virtually mapped
+        */
+       load32          KERNEL_PSW,%r10
+       mtctl           %r10,%ipsw
+
+       /* Set the space pointers for the post-RFI world
+       ** Clear the two-level IIA Space Queue, effectively setting
+       ** Kernel space.
+       */
+       mtctl           %r0,%cr17
+       mtctl           %r0,%cr17
+
+       /* Load RFI target into PC queue */
+       mtctl           %r11,%cr18
+       ldo             4(%r11),%r11
+       mtctl           %r11,%cr18
+
+       /* Jump to hyperspace */
+       rfi
+       nop
+
+       .procend
+
+
+#ifdef CONFIG_SMP
+
+       .import smp_init_current_idle_task,data
+       .import smp_callin,code
+
+/***************************************************************************
+*
+* smp_slave_stext is executed by all non-monarch Processors when the Monarch
+* pokes the slave CPUs in smp.c:smp_boot_cpus().
+*
+* Once here, registers values are initialized in order to branch to virtual
+* mode. Once all available/eligible CPUs are in virtual mode, all are
+* released and start out by executing their own idle task.
+*****************************************************************************/
+
+
+smp_slave_stext:
+        .proc
+       .callinfo
+
+       /*
+       ** Initialize Space registers
+       */
+       mtsp       %r0,%sr4
+       mtsp       %r0,%sr5
+       mtsp       %r0,%sr6
+       mtsp       %r0,%sr7
+
+       /*  Initialize the SP - monarch sets up smp_init_current_idle_task */
+       load32          PA(smp_init_current_idle_task),%sp
+       ldd             0(%sp),%sp      /* load task address */
+       mtctl           %sp,%cr30       /* store in cr30 */
+       ldo             TASK_SZ_ALGN(%sp),%sp
+       tophys_r1       %sp
+
+       /* point CPU to kernel page tables */
+       load32          PA(swapper_pg_dir),%r4
+       mtctl           %r4,%cr24       /* Initialize kernel root pointer */
+       mtctl           %r4,%cr25       /* Initialize user root pointer */
+
+       /* Setup PDCE_PROC entry */
+       copy            %arg0,%r3
+
+       /* Load RFI target address.  */
+       load32          smp_callin, %r11
+       
+       /* ok...common code can handle the rest */
+       b               common_stext
+       nop
+
+       .procend
+#endif /* CONFIG_SMP */
+
index c77aee0..aad7323 100644 (file)
@@ -43,7 +43,6 @@
        .level          1.1
        .data
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/pdc.h>
 
@@ -262,12 +261,10 @@ os_hpmc_5:
        mtsp    %r0, %sr6
        mtsp    %r0, %sr7
 
-       tovirt  %r30        /* make sp virtual */
+       tovirt_r1 %r30      /* make sp virtual */
 
        rsm 8,%r0           /* Clear Q bit */
-       ldi     1,%r1
-       mtctl   %r1,%cr29   /* Set trap code to "1" for HPMC */
-       mtctl   %r0,%cr30   /* Force interruptions to use hpmc stack */
+       ldi     1,%r8       /* Set trap code to "1" for HPMC */
        ldil    L%PA(intr_save), %r1
        ldo     R%PA(intr_save)(%r1), %r1
        be      0(%sr7,%r1)
index 602d85a..47c599d 100644 (file)
@@ -9,7 +9,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
@@ -19,11 +19,21 @@ struct mm_struct init_mm = INIT_MM(init_mm);
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
-union task_union init_task_union 
-       __attribute__((section("init_task"), aligned(4096))) = { INIT_TASK(init_task_union.task) };
+unsigned char interrupt_stack[ISTACK_SIZE] __attribute__ ((section("init_istack"), aligned(4096)));
+union thread_union init_thread_union
+       __attribute__((aligned(128))) __attribute__((__section__(".data.init_task"))) =
+               { INIT_THREAD_INFO(init_task) };
 
-unsigned long swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { 0, };
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(4096))) = { {0}, };
 #ifdef __LP64__
 unsigned long pmd0[PTRS_PER_PMD] __attribute__ ((aligned(4096))) = { 0, };
 #endif
 unsigned long pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((aligned(4096))) = { 0, };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+__asm__(".data");
+struct task_struct init_task = INIT_TASK(init_task);
index ab97cff..2957cfb 100644 (file)
-
-/* Copyright (c) 1999 The Puffin Group */
-/* Written by David Kennedy and Alex deVries */
+/*
+ * inventory.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Copyright (c) 1999 The Puffin Group (David Kennedy and Alex deVries)
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett-Packard
+ *
+ * These are the routines to discover what hardware exists in this box.
+ * This task is complicated by there being 3 different ways of
+ * performing an inventory, depending largely on the age of the box.
+ * The recommended way to do this is to check to see whether the machine
+ * is a `Snake' first, then try System Map, then try PAT.  We try System
+ * Map before checking for a Snake -- this probably doesn't cause any
+ * problems, but...
+ */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/pdc.h>
+#include <asm/processor.h>
+#include <asm/page.h>
 
 /*
 ** Debug options
-**    DEBUG_PAT        Dump details which PDC PAT provides about ranges/devices.
+** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices.
 */
 #undef DEBUG_PAT
 
-extern char *parisc_getHWtype(unsigned short hw_type);
+int pdc_type = PDC_TYPE_ILLEGAL;
+
+void __init setup_pdc(void)
+{
+       long status;
+       unsigned int bus_id;
+       struct pdc_system_map_mod_info module_result;
+       struct pdc_module_path module_path;
+       struct pdc_model model;
+#ifdef __LP64__
+       struct pdc_pat_cell_num cell_info;
+#endif
 
-extern struct hp_device * register_module(void *hpa);
-extern void print_devices(char * buf);
+       /* Determine the pdc "type" used on this machine */
 
+       printk(KERN_INFO "Determining PDC firmware type: ");
 
-int pdc_hpa_processor(void *address);
+       status = pdc_system_map_find_mods(&module_result, &module_path, 0);
+       if (status == PDC_OK) {
+               pdc_type = PDC_TYPE_SYSTEM_MAP;
+               printk("System Map.\n");
+               return;
+       }
 
-#ifndef __LP64__ 
-static u8 iodc_data[32] __attribute__ ((aligned (64)));
-static struct pdc_model model __attribute__ ((aligned (8)));
+       /*
+        * If the machine doesn't support PDC_SYSTEM_MAP then either it
+        * is a pdc pat box, or it is an older box. All 64 bit capable
+        * machines are either pdc pat boxes or they support PDC_SYSTEM_MAP.
+        */
+
+       /*
+        * TODO: We should test for 64 bit capability and give a
+        * clearer message.
+        */
+
+#ifdef __LP64__
+       status = pdc_pat_cell_get_number(&cell_info);
+       if (status == PDC_OK) {
+               pdc_type = PDC_TYPE_PAT;
+               printk("64 bit PAT.\n");
+               return;
+       }
 #endif
-static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-static struct pdc_hpa processor_hpa __attribute__ ((aligned (8)));
-static struct pdc_system_map module_result __attribute__ ((aligned (8)));
-static struct pdc_module_path module_path __attribute__ ((aligned (8)));
+
+       /* Check the CPU's bus ID.  There's probably a better test.  */
+
+       status = pdc_model_info(&model);
+
+       bus_id = (model.hversion >> (4 + 7)) & 0x1f;
+
+       switch (bus_id) {
+       case 0x4:               /* 720, 730, 750, 735, 755 */
+       case 0x6:               /* 705, 710 */
+       case 0x7:               /* 715, 725 */
+       case 0x8:               /* 745, 747, 742 */
+       case 0xA:               /* 712 and similiar */
+       case 0xC:               /* 715/64, at least */
+
+               pdc_type = PDC_TYPE_SNAKE;
+               printk("Snake.\n");
+               return;
+
+       default:                /* Everything else */
+
+               printk("Unsupported.\n");
+               panic("If this is a 64-bit machine, please try a 64-bit kernel.\n");
+       }
+}
+
+#define PDC_PAGE_ADJ_SHIFT (PAGE_SHIFT - 12) /* pdc pages are always 4k */
+
+static void __init
+set_pmem_entry(physmem_range_t *pmem_ptr, unsigned long start,
+              unsigned long pages4k)
+{
+       /* Rather than aligning and potentially throwing away
+        * memory, we'll assume that any ranges are already
+        * nicely aligned with any reasonable page size, and
+        * panic if they are not (it's more likely that the
+        * pdc info is bad in this case).
+        */
+
+       if (   ((start & (PAGE_SIZE - 1)) != 0)
+           || ((pages4k & ((1UL << PDC_PAGE_ADJ_SHIFT) - 1)) != 0) ) {
+
+               panic("Memory range doesn't align with page size!\n");
+       }
+
+       pmem_ptr->start_pfn = (start >> PAGE_SHIFT);
+       pmem_ptr->pages = (pages4k >> PDC_PAGE_ADJ_SHIFT);
+}
+
+static void __init pagezero_memconfig(void)
+{
+       unsigned long npages;
+
+       /* Use the 32 bit information from page zero to create a single
+        * entry in the pmem_ranges[] table.
+        *
+        * We currently don't support machines with contiguous memory
+        * >= 4 Gb, who report that memory using 64 bit only fields
+        * on page zero. It's not worth doing until it can be tested,
+        * and it is not clear we can support those machines for other
+        * reasons.
+        *
+        * If that support is done in the future, this is where it
+        * should be done.
+        */
+
+       npages = (PAGE_ALIGN(PAGE0->imm_max_mem) >> PAGE_SHIFT);
+       set_pmem_entry(pmem_ranges,0UL,npages);
+       npmem_ranges = 1;
+}
 
 #ifdef __LP64__
-#include <asm/pdcpat.h>
 
-int pdc_pat = 0;
+/* All of the PDC PAT specific code is 64-bit only */
 
 /*
 **  The module object is filled via PDC_PAT_CELL[Return Cell Module].
@@ -47,30 +164,36 @@ int pdc_pat = 0;
 **
 */
 
-static int
-pat_query_module( ulong pcell_loc, ulong mod_index)
+static int __init 
+pat_query_module(ulong pcell_loc, ulong mod_index)
 {
-       extern int num_devices;
-       extern struct hp_device devices[];
-
        pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
-        struct hp_device * dev = &devices[num_devices];
-       uint64_t temp;             /* 64-bit scratch value */
-       long status;               /* PDC return value status */
+       unsigned long bytecnt;
+       unsigned long temp;     /* 64-bit scratch value */
+       long status;            /* PDC return value status */
+       struct parisc_device *dev;
 
        /* return cell module (PA or Processor view) */
-       status = pdc_pat_cell_module(& pdc_result, pcell_loc, mod_index,
-               PA_VIEW, & pa_pdc_cell);
+       status = pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+                                    PA_VIEW, &pa_pdc_cell);
 
-       if (status != PDC_RET_OK) {
+       if (status != PDC_OK) {
                /* no more cell modules or error */
                return status;
        }
 
+       temp = pa_pdc_cell.cba;
+       dev = alloc_pa_dev(PAT_GET_CBA(temp), &pa_pdc_cell.mod_path);
+       if (!dev) {
+               return PDC_NE_MOD;
+       }
+
+       /* alloc_pa_dev sets dev->hpa */
+
        /*
-       ** save parameters in the hp_device
+       ** save parameters in the parisc_device
        ** (The idea being the device driver will call pdc_pat_cell_module()
-       ** and store the results in it's own data structure.)
+       ** and store the results in its own data structure.)
        */
        dev->pcell_loc = pcell_loc;
        dev->mod_index = mod_index;
@@ -79,319 +202,411 @@ pat_query_module( ulong pcell_loc, ulong mod_index)
        /* REVISIT: who is the consumer of this? not sure yet... */
        dev->mod_info = pa_pdc_cell.mod_info;   /* pass to PAT_GET_ENTITY() */
        dev->pmod_loc = pa_pdc_cell.mod_location;
-       dev->mod_path = pa_pdc_cell.mod_path;
 
-       temp = pa_pdc_cell.cba;
-       register_module((void *) PAT_GET_CBA(temp));    /* fills in dev->hpa */
+       register_parisc_device(dev);    /* advertise device */
 
 #ifdef DEBUG_PAT
+       pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
        /* dump what we see so far... */
        switch (PAT_GET_ENTITY(dev->mod_info)) {
-               ulong i;
+               unsigned long i;
 
        case PAT_ENTITY_PROC:
-               printk ("PAT_ENTITY_PROC: id_eid 0x%lx\n", pa_pdc_cell.mod[0]);
+               printk(KERN_DEBUG "PAT_ENTITY_PROC: id_eid 0x%lx\n",
+                       pa_pdc_cell.mod[0]);
                break;
 
        case PAT_ENTITY_MEM:
-               printk ("PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
-                       pa_pdc_cell.mod[0],
-                       pa_pdc_cell.mod[1],
+               printk(KERN_DEBUG 
+                       "PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
+                       pa_pdc_cell.mod[0], pa_pdc_cell.mod[1], 
                        pa_pdc_cell.mod[2]);
                break;
        case PAT_ENTITY_CA:
-               printk ("PAT_ENTITY_CA: %ld\n",pcell_loc);
+               printk(KERN_DEBUG "PAT_ENTITY_CA: %ld\n", pcell_loc);
                break;
 
        case PAT_ENTITY_PBC:
-               printk ("PAT_ENTITY_PBC: ");
+               printk(KERN_DEBUG "PAT_ENTITY_PBC: ");
                goto print_ranges;
 
        case PAT_ENTITY_SBA:
-               printk ("PAT_ENTITY_SBA: ");
+               printk(KERN_DEBUG "PAT_ENTITY_SBA: ");
                goto print_ranges;
 
        case PAT_ENTITY_LBA:
-               printk ("PAT_ENTITY_LBA: ");
+               printk(KERN_DEBUG "PAT_ENTITY_LBA: ");
 
-print_ranges:
-               printk ("ranges %ld\n", pa_pdc_cell.mod[1]);
+ print_ranges:
+               pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+                                   IO_VIEW, &io_pdc_cell);
+               printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell.mod[1]);
                for (i = 0; i < pa_pdc_cell.mod[1]; i++) {
-                       printk ("       %ld: 0x%016lx 0x%016lx 0x%016lx\n", i,
-                               pa_pdc_cell.mod[2+i*3], /* type */
-                               pa_pdc_cell.mod[3+i*3], /* start */
-                               pa_pdc_cell.mod[4+i*3]);        /* finish (ie end) */
+                       printk(KERN_DEBUG 
+                               "  PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+                               i, pa_pdc_cell.mod[2 + i * 3],  /* type */
+                               pa_pdc_cell.mod[3 + i * 3],     /* start */
+                               pa_pdc_cell.mod[4 + i * 3]);    /* finish (ie end) */
+                       printk(KERN_DEBUG 
+                               "  IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", 
+                               i, io_pdc_cell.mod[2 + i * 3],  /* type */
+                               io_pdc_cell.mod[3 + i * 3],     /* start */
+                               io_pdc_cell.mod[4 + i * 3]);    /* finish (ie end) */
                }
-               printk("\n");
+               printk(KERN_DEBUG "\n");
                break;
        }
 #endif /* DEBUG_PAT */
-       return PDC_RET_OK;
+       return PDC_OK;
 }
 
 
-static int do_pat_inventory(void)
+/* pat pdc can return information about a variety of different
+ * types of memory (e.g. firmware,i/o, etc) but we only care about
+ * the usable physical ram right now. Since the firmware specific
+ * information is allocated on the stack, we'll be generous, in
+ * case there is a lot of other information we don't care about.
+ */
+
+#define PAT_MAX_RANGES (4 * MAX_PHYSMEM_RANGES)
+
+static void __init pat_memconfig(void)
 {
-       ulong mod_index=0;
-       int status;
-       ulong cell_num;
-       ulong pcell_loc;
+       unsigned long actual_len;
+       struct pdc_pat_pd_addr_map_entry mem_table[PAT_MAX_RANGES+1];
+       struct pdc_pat_pd_addr_map_entry *mtbl_ptr;
+       physmem_range_t *pmem_ptr;
+       long status;
+       int entries;
+       unsigned long length;
+       int i;
 
-       pdc_pat = (pdc_pat_cell_get_number(&pdc_result) == PDC_OK);
-       if (!pdc_pat)
-       {
-               return 0;
-       }
+       length = (PAT_MAX_RANGES + 1) * sizeof(struct pdc_pat_pd_addr_map_entry);
 
-       cell_num = pdc_result[0];       /* Cell number call was made */
+       status = pdc_pat_pd_get_addr_map(&actual_len, mem_table, length, 0L);
 
-       /* As of PDC PAT ARS 2.5, ret[1] is NOT architected! */
-       pcell_loc = pdc_result[1];      /* Physical location of the cell */
+       if ((status != PDC_OK)
+           || ((actual_len % sizeof(struct pdc_pat_pd_addr_map_entry)) != 0)) {
 
-#ifdef DEBUG_PAT
-       printk("CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_num, pcell_loc);
-#endif
+               /* The above pdc call shouldn't fail, but, just in
+                * case, just use the PAGE0 info.
+                */
 
-        status = pdc_pat_cell_num_to_loc(&pdc_result, cell_num);
-        if (status == PDC_BAD_OPTION)
-       {
-               /* Prelude (and it's successors: Lclass, A400/500) only
-               ** implement PDC_PAT_CELL sub-options 0 and 2.
-               ** "Home cook'n is best anyhow!"
-               */
-       } else if (PDC_OK == status) {
-               /* so far only Halfdome supports this */
-               pcell_loc = pdc_result[0];
-       } else {
-               panic("WTF? CELL_GET_NUMBER give me invalid cell number?");
+               printk("\n\n\n");
+               printk(KERN_WARNING "WARNING! Could not get full memory configuration. "
+                       "All memory may not be used!\n\n\n");
+               pagezero_memconfig();
+               return;
        }
 
-       while (PDC_RET_OK == pat_query_module(pcell_loc, mod_index))
-       {
-               mod_index++;
+       entries = actual_len / sizeof(struct pdc_pat_pd_addr_map_entry);
+
+       if (entries > PAT_MAX_RANGES) {
+               printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+               printk(KERN_WARNING "Some memory may not be used!\n");
        }
 
-       return mod_index;
-}
-#endif /* __LP64__ */
+       /* Copy information into the firmware independent pmem_ranges
+        * array, skipping types we don't care about. Notice we said
+        * "may" above. We'll use all the entries that were returned.
+        */
+
+       npmem_ranges = 0;
+       mtbl_ptr = mem_table;
+       pmem_ptr = pmem_ranges; /* Global firmware independent table */
+       for (i = 0; i < entries; i++,mtbl_ptr++) {
+               if (   (mtbl_ptr->entry_type != PAT_MEMORY_DESCRIPTOR)
+                   || (mtbl_ptr->memory_type != PAT_MEMTYPE_MEMORY)
+                   || (mtbl_ptr->pages == 0)
+                   || (   (mtbl_ptr->memory_usage != PAT_MEMUSE_GENERAL)
+                       && (mtbl_ptr->memory_usage != PAT_MEMUSE_GI)
+                       && (mtbl_ptr->memory_usage != PAT_MEMUSE_GNI) ) ) {
+
+                       continue;
+               }
 
-static int do_newer_workstation_inventory(void)
-{
-       long status;
-       int i, num = 0;
+               if (npmem_ranges == MAX_PHYSMEM_RANGES) {
+                       printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+                       printk(KERN_WARNING "Some memory will not be used!\n");
+                       break;
+               }
 
-       /* So the idea here is to simply try one SYSTEM_MAP call.  If 
-          that one works, great, otherwise do it another way */
+               set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+               npmem_ranges++;
+       }
+}
 
-       status = pdc_system_map_find_mods(&module_result,&module_path,0);
+static int __init pat_inventory(void)
+{
+       int status;
+       ulong mod_index = 0;
+       struct pdc_pat_cell_num cell_info;
 
-       if (status == PDC_RET_OK) {
-               /* This is for newer non-PDC-PAT boxes */
+       /*
+       ** Note:  Prelude (and it's successors: Lclass, A400/500) only
+       **        implement PDC_PAT_CELL sub-options 0 and 2.
+       */
+       status = pdc_pat_cell_get_number(&cell_info);
+       if (status != PDC_OK) {
+               return 0;
+       }
 
-               printk("a newer box...\n");
-               for(i=0, status=PDC_RET_OK; status != PDC_RET_NE_PROC && 
-                       status != PDC_RET_NE_MOD ;i++) {
+#ifdef DEBUG_PAT
+       printk(KERN_DEBUG "CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_info.cell_num, 
+              cell_info.cell_loc);
+#endif
 
-                       status = pdc_system_map_find_mods(&module_result,&module_path,i);
-                       if (status == PDC_RET_OK) {
-                               num++;
-                               register_module(module_result.mod_addr);
-                       }
-               }
+       while (PDC_OK == pat_query_module(cell_info.cell_loc, mod_index)) {
+               mod_index++;
        }
 
-       return (num > 0);
+       return mod_index;
 }
 
-#ifndef __LP64__
-static struct  pdc_memory_map r_addr __attribute__ ((aligned (8)));
-
-static int really_do_oldhw_inventory(void)
+/* We only look for extended memory ranges on a 64 bit capable box */
+static void __init sprockets_memconfig(void)
 {
-       int i, mod, num = 0;
-       int status;
-       unsigned int hw_type;
-       unsigned int func;
-
-       /* This is undocumented at the time of writing, but basically 
-          we're setting up mod_path so that bc[0..4]=0xff, and step
-          through mod to get the "Path Structure for GSC Modules".  If
-          it works, use the returned HPA and determine the hardware type.  */
-
-       for (i=0;i<6;i++) module_path.bc[i]=0xff;
-
-       for (mod=0;mod<16;mod++) {
-               char *stype = NULL;
+       struct pdc_memory_table_raddr r_addr;
+       struct pdc_memory_table mem_table[MAX_PHYSMEM_RANGES];
+       struct pdc_memory_table *mtbl_ptr;
+       physmem_range_t *pmem_ptr;
+       long status;
+       int entries;
+       int i;
 
-               module_path.mod=mod;
-               status = pdc_mem_map_hpa(&r_addr, &module_path);
-               if (status!=PDC_RET_OK) continue;
-       
-               status = pdc_iodc_read(&pdc_result,(void *) r_addr.hpa,
-                       0, &iodc_data,32 );
-               if (status!=PDC_RET_OK) continue;
-               hw_type = iodc_data[3]&0x1f;
+       status = pdc_mem_mem_table(&r_addr,mem_table,
+                               (unsigned long)MAX_PHYSMEM_RANGES);
 
-               switch (hw_type)
-               {
-               case HPHW_NPROC:        /* 0 */
-                       stype="Processor"; break;
+       if (status != PDC_OK) {
 
-               case HPHW_MEMORY:       /* 1 */
-                       stype="Memory"; break;
+               /* The above pdc call only works on boxes with sprockets
+                * firmware (newer B,C,J class). Other non PAT PDC machines
+                * do support more than 3.75 Gb of memory, but we don't
+                * support them yet.
+                */
 
-               case HPHW_B_DMA:        /* 2 */
-                       stype="Type B DMA"; break;
+               pagezero_memconfig();
+               return;
+       }
 
-               case HPHW_A_DMA:        /* 4 */
-                       stype="Type A DMA"; break;
+       if (r_addr.entries_total > MAX_PHYSMEM_RANGES) {
+               printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+               printk(KERN_WARNING "Some memory will not be used!\n");
+       }
 
-               case HPHW_A_DIRECT:     /* 5 */
-                       stype="Type A Direct"; break;
+       entries = (int)r_addr.entries_returned;
 
-               case HPHW_BCPORT:       /* 7 */
-                       stype="Bus Converter Port"; break;
+       npmem_ranges = 0;
+       mtbl_ptr = mem_table;
+       pmem_ptr = pmem_ranges; /* Global firmware independent table */
+       for (i = 0; i < entries; i++,mtbl_ptr++) {
+               set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+               npmem_ranges++;
+       }
+}
 
-               case HPHW_CONSOLE:      /* 9 */
-                       stype="Console"; break;
+#else   /* !__LP64__ */
 
-               case HPHW_FIO:          /* 10 - Graphics */
-                       stype="Foreign I/O (Graphics)"; break;
+#define pat_inventory() do { } while (0)
+#define pat_memconfig() do { } while (0)
+#define sprockets_memconfig() pagezero_memconfig()
 
-               case HPHW_BA:           /* 11 - Bus Adapter */
-                       stype="Bus Adapter"; break;
+#endif /* !__LP64__ */
 
-               case HPHW_IOA:          /* 12 */
-                       stype="I/O Adapter"; break;
 
-               case HPHW_BRIDGE:       /* 13 */
-                       stype="Bridge"; break;
+#ifndef CONFIG_PA20
 
-               case HPHW_FABRIC:       /* 14 */
-                       stype="Fabric"; break;
+/* Code to support Snake machines (7[2350], 7[235]5, 715/Scorpio) */
 
-               case HPHW_FAULTY:       /* 31 */
-                       stype="Faulty HW"; break;
+static struct parisc_device * __init
+legacy_create_device(struct pdc_memory_map *r_addr,
+               struct pdc_module_path *module_path)
+{
+       struct parisc_device *dev;
+       int status = pdc_mem_map_hpa(r_addr, module_path);
+       if (status != PDC_OK)
+               return NULL;
 
-               case HPHW_OTHER:        /* 42 */
-               default:        
-                       printk("Don't know this hw_type: %d\n", hw_type);
-                       break;
-               }
+       dev = alloc_pa_dev(r_addr->hpa, &module_path->path);
+       if (dev == NULL)
+               return NULL;
 
-               // This is kluged. But don't want to replicate code for
-               // most of the above cases.
-               if (stype) {
-#ifdef DBG_PDC_QUERY
-                       // parisc/kernel/drivers.c
-                       extern int num_devices; 
-                       extern struct hp_device devices[];
-                       struct hp_hardware *h;
-#endif
+       register_parisc_device(dev);
+       return dev;
+}
 
-                       status = pdc_mem_map_hpa(&r_addr, &module_path);
-                       if (status==PDC_RET_OK && register_module((void *) r_addr.hpa) != NULL)
-                                       num++;
-
-
-                   if (hw_type == HPHW_BA) {
-                       /* Now, we're checking for devices for each
-                          module.  I seem to think that the
-                          modules in question are Lasi (2), 2nd Lasi (6)
-                          Wax (5).  To do this, set bc[5]=0, and set
-                          bc[4] to the module, and step through the
-                          functions. */
-
-                       for (i=0;i<4;i++) module_path.bc[i]=0xff;
-                       module_path.bc[4]=mod;
-                       for (func=0;func<16;func++) {
-                               module_path.mod = func;
-                               module_path.bc[5]=0;
-                               status = pdc_mem_map_hpa(&r_addr, &module_path);
-                               if (status!=PDC_RET_OK) continue;
-                               if (register_module((void *) r_addr.hpa) != NULL) 
-                                       num++;
-                       }
+/**
+ * snake_inventory
+ *
+ * Before PDC_SYSTEM_MAP was invented, the PDC_MEM_MAP call was used.
+ * To use it, we initialise the mod_path.bc to 0xff and try all values of
+ * mod to get the HPA for the top-level devices.  Bus adapters may have
+ * sub-devices which are discovered by setting bc[5] to 0 and bc[4] to the
+ * module, then trying all possible functions.
+ */
+static void __init snake_inventory(void)
+{
+       int mod;
+       for (mod = 0; mod < 16; mod++) {
+               struct parisc_device *dev;
+               struct pdc_module_path module_path;
+               struct pdc_memory_map r_addr;
+               unsigned int func;
+
+               memset(module_path.path.bc, 0xff, 6);
+               module_path.path.mod = mod;
+               dev = legacy_create_device(&r_addr, &module_path);
+               if ((!dev) || (dev->id.hw_type != HPHW_BA))
+                       continue;
+
+               memset(module_path.path.bc, 0xff, 4);
+               module_path.path.bc[4] = mod;
+
+               for (func = 0; func < 16; func++) {
+                       module_path.path.bc[5] = 0;
+                       module_path.path.mod = func;
+                       legacy_create_device(&r_addr, &module_path);
                }
-               // reset module_path.bc[]
-               for (i=0;i<6;i++) module_path.bc[i]=0xff;
+       }
+}
 
+#else /* CONFIG_PA20 */
+#define snake_inventory() do { } while (0)
+#endif  /* CONFIG_PA20 */
+
+/* Common 32/64 bit based code goes here */
+
+/**
+ * add_system_map_addresses - Add additional addresses to the parisc device.
+ * @dev: The parisc device.
+ * @num_addrs: Then number of addresses to add;
+ * @module_instance: The system_map module instance.
+ *
+ * This function adds any additional addresses reported by the system_map
+ * firmware to the parisc device.
+ */
+static void __init
+add_system_map_addresses(struct parisc_device *dev, int num_addrs, 
+                        int module_instance)
+{
+       int i;
+       long status;
+       struct pdc_system_map_addr_info addr_result;
 
-#ifdef DBG_PDC_QUERY
-//
-// Let print_devices() dump everything which is registered.
-//
-                       h = devices[num_devices-1].reference;
+       dev->addr = kmalloc(num_addrs * sizeof(unsigned long), GFP_KERNEL);
+       if(!dev->addr) {
+               printk(KERN_ERR "%s %s(): memory allocation failure\n",
+                      __FILE__, __FUNCTION__);
+               return;
+       }
 
-                       if (h) stype = h->name;
-                       printk("Found %s at %d\n", stype, module_path.mod);
-#endif
+       for(i = 1; i <= num_addrs; ++i) {
+               status = pdc_system_map_find_addrs(&addr_result, 
+                                                  module_instance, i);
+               if(PDC_OK == status) {
+                       dev->addr[dev->num_addrs] = (unsigned long)addr_result.mod_addr;
+                       dev->num_addrs++;
+               } else {
+                       printk(KERN_WARNING 
+                              "Bad PDC_FIND_ADDRESS status return (%ld) for index %d\n",
+                              status, i);
                }
        }
-       return num;
 }
 
-static int
-do_old_inventory(void)
+/**
+ * do_system_map_inventory - Retrieve firmware devices via SYSTEM_MAP.
+ *
+ * This function attempts to retrieve and register all the devices firmware
+ * knows about via the SYSTEM_MAP PDC call.
+ */
+static void __init system_map_inventory(void)
 {
-        unsigned int bus_id;
-       long status;
-       int ok = 0;
+       int i;
+       long status = PDC_OK;
+    
+       /*
+        * first stop the usb controller, otherwise the machine
+        * might crash during iommu setup
+        */
+       pdc_suspend_usb();
+
+       for (i = 0; status != PDC_BAD_PROC && status != PDC_NE_MOD; i++) {
+               struct parisc_device *dev;
+               struct pdc_system_map_mod_info module_result;
+               struct pdc_module_path module_path;
+
+               status = pdc_system_map_find_mods(&module_result,
+                               &module_path, i);
+               if (status != PDC_OK)
+                       continue;
+               
+               dev = alloc_pa_dev(module_result.mod_addr, &module_path.path);
+               if (!dev)
+                       continue;
+               
+               register_parisc_device(dev);
+
+               /* if available, get the additional addresses for a module */
+               if (!module_result.add_addrs)
+                       continue;
+
+               add_system_map_addresses(dev, module_result.add_addrs, i);
+       }
 
-       printk(" an older box...\n");
+       walk_central_bus();
+       return;
+}
 
-       /* Here, we're going to check the model, and decide
-          if we should even bother trying. */
+void __init do_memory_inventory(void)
+{
+       switch (pdc_type) {
 
-       status = pdc_model_info(&model);
+       case PDC_TYPE_PAT:
+               pat_memconfig();
+               break;
 
-       bus_id = (model.hversion >> (4+7) ) &0x1f;
+       case PDC_TYPE_SYSTEM_MAP:
+               sprockets_memconfig();
+               break;
 
-       /* Here, we're checking the HVERSION of the CPU.
-          We're only checking the 0th CPU, since it'll
-          be the same on an SMP box. */
+       case PDC_TYPE_SNAKE:
+               pagezero_memconfig();
+               return;
 
-       switch (bus_id) {
-               case 0x4:       /* 720, 730, 750, 735, 755 */
-               case 0x6:       /* 705, 710 */
-               case 0x7:       /* 715, 725 */
-               case 0x8:       /* 745, 747, 742 */
-               case 0xA:       /* 712 and similiar */
-               case 0xC:       /* 715/64, at least */
-
-               /* Do inventory using MEM_MAP */
-               really_do_oldhw_inventory();
-               ok = 1;
-               break;
-       default:        /* Everything else */
-               printk("This is a very very old machine, with a bus_id of 0x%x.\n",bus_id);
-               panic("This will probably never run Linux.\n");
+       default:
+               panic("Unknown PDC type!\n");
        }
 
-       return ok;
+       if (npmem_ranges == 0 || pmem_ranges[0].start_pfn != 0) {
+               printk(KERN_WARNING "Bad memory configuration returned!\n");
+               printk(KERN_WARNING "Some memory may not be used!\n");
+               pagezero_memconfig();
+       }
 }
 
-#endif /* !__LP64__ */
+void __init do_device_inventory(void)
+{
+       printk(KERN_INFO "Searching for devices...\n");
 
-void do_inventory(void){
-       if((pdc_hpa_processor(&processor_hpa))<0){
-               printk(KERN_INFO "Couldn't get the HPA of the processor.\n" );
-       }
+       switch (pdc_type) {
+
+       case PDC_TYPE_PAT:
+               pat_inventory();
+               break;
 
-       printk("Searching for devices in PDC firmware... ");
-       printk("processor hpa 0x%lx\n", processor_hpa.hpa);
+       case PDC_TYPE_SYSTEM_MAP:
+               system_map_inventory();
+               break;
 
-       if (!(
-               do_newer_workstation_inventory()
-#ifdef __LP64__
-               || do_pat_inventory()
-#else /* __LP64__ */
-               || do_old_inventory()
-#endif /* __LP64__ */
-           ))
-       {
-           panic("I can't get the hardware inventory on this machine");
+       case PDC_TYPE_SNAKE:
+               snake_inventory();
+               break;
+
+       default:
+               panic("Unknown PDC type!\n");
        }
-       print_devices(NULL);
-}
 
+       printk(KERN_INFO "Found devices:\n");
+       print_parisc_devices();
+}
index 45411f2..c8ef298 100644 (file)
@@ -1,13 +1,10 @@
-/* $Id: irq.c,v 1.8 2000/02/08 02:01:17 grundler Exp $
- *
+/* 
  * Code to handle x86 style IRQs plus some generic interrupt stuff.
  *
- * This is not in any way SMP-clean.
- *
  * Copyright (C) 1992 Linus Torvalds
  * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
- * Copyright (C) 1999 SuSE GmbH (Author: Philipp Rumpf, prumpf@tux.org)
- * Copyright (C) 2000 Hewlett Packard Corp (Co-Author: Grant Grundler, grundler@cup.hp.com)
+ * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
+ * Copyright (C) 1999-2000 Grant Grundler
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/config.h>
 #include <linux/bitops.h>
-#include <asm/bitops.h>
+#include <linux/config.h>
 #include <asm/pdc.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/kernel_stat.h>
 #include <linux/signal.h>
-#include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
 #include <linux/irq.h>
 #include <linux/seq_file.h>
+#include <linux/spinlock.h>
 
 #include <asm/cache.h>
 
 #undef DEBUG_IRQ
+#undef PARISC_IRQ_CR16_COUNTS
 
 extern void timer_interrupt(int, void *, struct pt_regs *);
 extern void ipi_interrupt(int, void *, struct pt_regs *);
 
 #ifdef DEBUG_IRQ
-#define DBG_IRQ(x...)   printk(x)
+#define DBG_IRQ(irq, x)        if ((irq) != TIMER_IRQ) printk x
 #else /* DEBUG_IRQ */
-#define DBG_IRQ(x...)
+#define DBG_IRQ(irq, x)        do { } while (0)
 #endif /* DEBUG_IRQ */
 
-#define EIEM_MASK(irq) (1L<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
-#define CLEAR_EIEM_BIT(irq) set_eiem(get_eiem() & ~EIEM_MASK(irq))
-#define SET_EIEM_BIT(irq) set_eiem(get_eiem() | EIEM_MASK(irq))
+#define EIEM_MASK(irq)       (1UL<<(MAX_CPU_IRQ-IRQ_OFFSET(irq)))
+
+/* Bits in EIEM correlate with cpu_irq_action[].
+** Numbered *Big Endian*! (ie bit 0 is MSB)
+*/
+static unsigned long cpu_eiem = 0;
+
+static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;  /* protect IRQ regions */
+
+#ifdef CONFIG_SMP
+static void cpu_set_eiem(void *info)
+{
+       set_eiem((unsigned long) info);
+}
+#endif
 
-static void disable_cpu_irq(void *unused, int irq)
+static inline void disable_cpu_irq(void *unused, int irq)
 {
-       CLEAR_EIEM_BIT(irq);
+       unsigned long eirr_bit = EIEM_MASK(irq);
+
+       cpu_eiem &= ~eirr_bit;
+       set_eiem(cpu_eiem);
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
 }
 
 static void enable_cpu_irq(void *unused, int irq)
 {
-       unsigned long mask = EIEM_MASK(irq);
+       unsigned long eirr_bit = EIEM_MASK(irq);
 
-       mtctl(mask, 23);
-       SET_EIEM_BIT(irq);
+       mtctl(eirr_bit, 23);    /* clear EIRR bit before unmasking */
+       cpu_eiem |= eirr_bit;
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
+       set_eiem(cpu_eiem);
+}
+
+/* mask and disable are the same at the CPU level
+** Difference is enable clears pending interrupts
+*/
+#define mask_cpu_irq   disable_cpu_irq
+
+static inline void unmask_cpu_irq(void *unused, int irq)
+{
+       unsigned long eirr_bit = EIEM_MASK(irq);
+       cpu_eiem |= eirr_bit;
+       /* NOTE: sending an IPI will cause do_cpu_irq_mask() to
+       ** handle *any* unmasked pending interrupts.
+       ** ie We don't need to check for pending interrupts here.
+       */
+        smp_call_function(cpu_set_eiem, (void *) cpu_eiem, 1, 1);
+       set_eiem(cpu_eiem);
 }
 
 static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
-       [IRQ_OFFSET(TIMER_IRQ)] { timer_interrupt, 0, 0, "timer", NULL, NULL },
-       [IRQ_OFFSET(IPI_IRQ)]   { ipi_interrupt, 0, 0, "IPI", NULL, NULL },
+       [IRQ_OFFSET(TIMER_IRQ)] { handler: timer_interrupt, name: "timer", },
+#ifdef CONFIG_SMP
+       [IRQ_OFFSET(IPI_IRQ)]   { handler: ipi_interrupt,   name: "IPI", },
+#endif
 };
 
 struct irq_region cpu_irq_region = {
-       { disable_cpu_irq, enable_cpu_irq, NULL, NULL },
-       { &cpu_data[0], "PA-PIC", IRQ_REG_MASK|IRQ_REG_DIS, IRQ_FROM_REGION(CPU_IRQ_REGION)},
-       cpu_irq_actions
+       ops:    { disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq },
+       data:   { dev: &cpu_data[0],
+                 name: "PA-CPU-00",
+                 irqbase: IRQ_FROM_REGION(CPU_IRQ_REGION), },
+       action: cpu_irq_actions,
 };
 
 struct irq_region *irq_region[NR_IRQ_REGS] = {
-       [ 0 ] NULL,             /* abuse will data page fault (aka code 15) */
+       [ 0 ]              NULL, /* reserved for EISA, else causes data page fault (aka code 15) */
        [ CPU_IRQ_REGION ] &cpu_irq_region,
 };
 
 
+/*
+** Generic interfaces that device drivers can use:
+**    mask_irq()       block IRQ
+**    unmask_irq()     re-enable IRQ and trigger if IRQ is pending
+**    disable_irq()    block IRQ
+**    enable_irq()     clear pending and re-enable IRQ
+*/
 
-/* we special-case the real IRQs here, which feels right given the relatively
- * high cost of indirect calls.  If anyone is bored enough to benchmark this
- * and find out whether I am right, feel free to.   prumpf */
-
-static inline void mask_irq(int irq)
+void mask_irq(int irq)
 {
        struct irq_region *region;
-       
-#ifdef DEBUG_IRQ
-       if (irq != TIMER_IRQ)
-#endif
-       DBG_IRQ("mask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
-
-       if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
-               region = irq_region[IRQ_REGION(irq)];
-               if(region->data.flags & IRQ_REG_MASK)
-                       region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
-       } else {
-               CLEAR_EIEM_BIT(irq);
-       }
+
+       DBG_IRQ(irq, ("mask_irq(%d) %d+%d eiem 0x%lx\n", irq,
+                               IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+       irq = irq_cannonicalize(irq);
+       region = irq_region[IRQ_REGION(irq)];
+       if (region->ops.mask_irq)
+               region->ops.mask_irq(region->data.dev, IRQ_OFFSET(irq));
 }
 
-static inline void unmask_irq(int irq)
+void unmask_irq(int irq)
 {
        struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-       if (irq != TIMER_IRQ)
-#endif
-       DBG_IRQ("unmask_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
-
-       if(IRQ_REGION(irq) != CPU_IRQ_REGION) {
-               region = irq_region[IRQ_REGION(irq)];
-               if(region->data.flags & IRQ_REG_MASK)
-                       region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
-       } else {
-               SET_EIEM_BIT(irq);
-       }
+       DBG_IRQ(irq, ("unmask_irq(%d) %d+%d eiem 0x%lx\n", irq,
+                               IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+       irq = irq_cannonicalize(irq);
+       region = irq_region[IRQ_REGION(irq)];
+       if (region->ops.unmask_irq)
+               region->ops.unmask_irq(region->data.dev, IRQ_OFFSET(irq));
 }
 
 void disable_irq(int irq)
 {
        struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-       if (irq != TIMER_IRQ)
-#endif
-       DBG_IRQ("disable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+       DBG_IRQ(irq, ("disable_irq(%d) %d+%d eiem 0x%lx\n", irq,
+                               IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+       irq = irq_cannonicalize(irq);
        region = irq_region[IRQ_REGION(irq)];
-
-       if(region->data.flags & IRQ_REG_DIS)
+       if (region->ops.disable_irq)
                region->ops.disable_irq(region->data.dev, IRQ_OFFSET(irq));
        else
                BUG();
 }
 
-void enable_irq(int irq) 
+void enable_irq(int irq)
 {
        struct irq_region *region;
 
-#ifdef DEBUG_IRQ
-       if (irq != TIMER_IRQ)
-#endif
-       DBG_IRQ("enable_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
+       DBG_IRQ(irq, ("enable_irq(%d) %d+%d eiem 0x%lx\n", irq,
+                               IRQ_REGION(irq), IRQ_OFFSET(irq), cpu_eiem));
+       irq = irq_cannonicalize(irq);
        region = irq_region[IRQ_REGION(irq)];
 
-       if(region->data.flags & IRQ_REG_DIS)
+       if (region->ops.enable_irq)
                region->ops.enable_irq(region->data.dev, IRQ_OFFSET(irq));
        else
                BUG();
@@ -164,56 +189,88 @@ void enable_irq(int irq)
 int show_interrupts(struct seq_file *p, void *v)
 {
 #ifdef CONFIG_PROC_FS
-       int i, j;
-       int regnr, irq_no;
-       struct irq_region *region;
-       struct irqaction *action, *mainaction;
+       unsigned int regnr = 0;
+
+       seq_puts(p, "     ");
+#if 0 /* def CONFIG_SMP */
+       for (; regnr < smp_num_cpus; regnr++)
+#endif
+               seq_printf(p, "      CPU%d ", regnr);
 
-       seq_puts(p, "           ");
-       for (j=0; j<smp_num_cpus; j++)
-               seq_printf(p, "CPU%d       ",j);
+#ifdef PARISC_IRQ_CR16_COUNTS
+       seq_printf(p, "[min/avg/max] (CPU cycle counts)");
+#endif
        seq_putc(p, '\n');
 
+       /* We don't need *irqsave lock variants since this is
+       ** only allowed to change while in the base context.
+       */
+       spin_lock(&irq_lock);
        for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) {
-           region = irq_region[regnr];
-           if (!region || !region->action)
+           unsigned int i;
+           struct irq_region *region = irq_region[regnr];
+
+            if (!region || !region->action)
                continue;
-           
-           mainaction = region->action;
 
            for (i = 0; i <= MAX_CPU_IRQ; i++) {
-               action = mainaction++;
-               if (!action || !action->name)
-                   continue;
-               
-               irq_no = IRQ_FROM_REGION(regnr) + i;
-               
+               struct irqaction *action = &region->action[i];
+               unsigned int irq_no = IRQ_FROM_REGION(regnr) + i;
+#if 0 /* def CONFIG_SMP */
+/* We currently direct all Interrupts at the Monarch.
+ * The right way to handle SMP IRQ stats is to have one IRQ region/CPU.
+ */
+               unsigned int j;
+#endif
+
+               if (!action->handler)
+                       continue;
+
                seq_printf(p, "%3d: ", irq_no);
-#ifndef CONFIG_SMP
+#if 1 /* ndef CONFIG_SMP */
                seq_printf(p, "%10u ", kstat_irqs(irq_no));
 #else
                for (j = 0; j < smp_num_cpus; j++)
                    seq_printf(p, "%10u ",
                            kstat.irqs[cpu_logical_map(j)][irq_no]);
 #endif
-               seq_printf(p, " %14s", 
+               seq_printf(p, " %14s",
                            region->data.name ? region->data.name : "N/A");
+#ifndef PARISC_IRQ_CR16_COUNTS
                seq_printf(p, "  %s", action->name);
 
-               for (action=action->next; action; action = action->next)
-                   seq_printf(p, ", %s", action->name);
+               while ((action = action->next))
+                       seq_printf(p, ", %s", action->name);
+#else
+               for ( ;action; action = action->next) {
+                       unsigned int i, avg, min, max;
+
+                       min = max = action->cr16_hist[0];
+
+                       for (avg = i = 0; i < PARISC_CR16_HIST_SIZE; i++) {
+                               int hist = action->cr16_hist[i];
+
+                               if (hist) {
+                                       avg += hist;
+                               } else
+                                       break;
+
+                               if (hist > max) max = hist;
+                               if (hist < min) min = hist;
+                       }
+
+                       avg /= i;
+                       seq_printf(p, " %s[%d/%d/%d]", action->name,
+                                       min,avg,max);
+               }
+#endif
+
                seq_putc(p, '\n');
-           }                
-       }  
+           }
+       }
+       spin_unlock(&irq_lock);
 
        seq_putc(p, '\n');
-#if CONFIG_SMP
-       seq_puts(p, "LOC: ");
-       for (j = 0; j < smp_num_cpus; j++)
-               seq_printf(p, "%10u ",
-                       apic_timer_irqs[cpu_logical_map(j)]);
-       seq_putc(p, '\n');
-#endif
 #endif /* CONFIG_PROC_FS */
        return 0;
 }
@@ -234,8 +291,8 @@ txn_alloc_irq(void)
        int irq;
 
        /* never return irq 0 cause that's the interval timer */
-       for(irq=1; irq<=MAX_CPU_IRQ; irq++) {
-               if(cpu_irq_region.action[irq].handler == NULL) {
+       for (irq = 1; irq <= MAX_CPU_IRQ; irq++) {
+               if (cpu_irq_region.action[irq].handler == NULL) {
                        return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq);
                }
        }
@@ -248,9 +305,7 @@ int
 txn_claim_irq(int irq)
 {
        if (irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)].handler ==NULL)
-       {
                return irq;
-       }
 
        /* unlikely, but be prepared */
        return -1;
@@ -261,10 +316,10 @@ txn_alloc_addr(int virt_irq)
 {
        struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev);
 
-       if (0==dev) {
+       if (!dev) {
                printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n",
                        virt_irq,dev);
-               return(0UL);
+               return 0;
        }
        return (dev->txn_addr);
 }
@@ -277,7 +332,7 @@ txn_alloc_addr(int virt_irq)
 ** V-class (EPIC):          6 bits
 ** N/L-class/A500:          8 bits (iosapic)
 ** PCI 2.2 MSI:             16 bits (I think)
-** Existing PCI devices:    32-bits (NCR c720/ATM/GigE/HyperFabric)
+** Existing PCI devices:    32-bits (all Symbios SCSI/ATM/HyperFabric)
 **
 ** On the service provider side:
 ** o PA 1.1 (and PA2.0 narrow mode)     5-bits (width of EIR register)
@@ -302,117 +357,204 @@ txn_alloc_data(int virt_irq, unsigned int bits_wide)
                panic("Sorry -- didn't allocate valid IRQ for this device\n");
        }
 
-       return(IRQ_OFFSET(virt_irq));
+       return (IRQ_OFFSET(virt_irq));
 }
 
-
-/* FIXME: SMP, flags, bottom halves, rest */
 void do_irq(struct irqaction *action, int irq, struct pt_regs * regs)
 {
        int cpu = smp_processor_id();
 
-       irq_enter(cpu, irq);
+       irq_enter();
+       ++kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
 
-#ifdef DEBUG_IRQ
-       if (irq != TIMER_IRQ)
+       DBG_IRQ(irq, ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)));
+
+       for (; action; action = action->next) {
+#ifdef PARISC_IRQ_CR16_COUNTS
+               unsigned long cr_start = mfctl(16);
 #endif
-       DBG_IRQ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq));
-       if (action->handler == NULL)
-               printk(KERN_ERR "No handler for interrupt %d !\n", irq);
 
-       for(; action && action->handler; action = action->next) {
+               if (action->handler == NULL) {
+                       if (IRQ_REGION(irq) == EISA_IRQ_REGION && irq_region[EISA_IRQ_REGION]) {
+                               /* were we called due to autodetecting (E)ISA irqs ? */
+                               unsigned int *status;
+                               status = &irq_region[EISA_IRQ_REGION]->data.status[IRQ_OFFSET(irq)];
+                               if (*status & IRQ_AUTODETECT) {
+                                       *status &= ~IRQ_WAITING;
+                                       continue; 
+                               }
+                       }
+                       printk(KERN_ERR "IRQ:  CPU:%d No handler for IRQ %d !\n", cpu, irq);
+                       continue;
+               }
+
                action->handler(irq, action->dev_id, regs);
+
+#ifdef PARISC_IRQ_CR16_COUNTS
+               {
+                       unsigned long cr_end = mfctl(16);
+                       unsigned long tmp = cr_end - cr_start;
+                       /* check for roll over */
+                       cr_start = (cr_end < cr_start) ?  -(tmp) : (tmp);
+               }
+               action->cr16_hist[action->cr16_idx++] = (int) cr_start;
+               action->cr16_idx &= PARISC_CR16_HIST_SIZE - 1;
+#endif
        }
-       
-       irq_exit(cpu, irq);
 
-       /* don't need to care about unmasking and stuff */
-       do_softirq();
+       irq_exit();
+}
+
+
+/* ONLY called from entry.S:intr_extint() */
+void do_cpu_irq_mask(struct irq_region *region, struct pt_regs *regs)
+{
+       unsigned long eirr_val;
+       unsigned int i=3;       /* limit time in interrupt context */
+
+       /*
+        * PSW_I or EIEM bits cannot be enabled until after the
+        * interrupts are processed.
+        * timer_interrupt() assumes it won't get interrupted when it
+        * holds the xtime_lock...an unmasked interrupt source could
+        * interrupt and deadlock by trying to grab xtime_lock too.
+        * Keeping PSW_I and EIEM disabled avoids this.
+        */
+       set_eiem(0UL);  /* disable all extr interrupt for now */
+
+       /* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
+        * 2) We loop here on EIRR contents in order to avoid
+        *    nested interrupts or having to take another interupt
+        *    when we could have just handled it right away.
+        * 3) Limit the number of times we loop to make sure other
+        *    processing can occur.
+        */
+       while ((eirr_val = (mfctl(23) & cpu_eiem)) && --i) {
+               unsigned long bit = (1UL<<MAX_CPU_IRQ);
+               unsigned int irq = 0;
+
+               mtctl(eirr_val, 23); /* reset bits we are going to process */
+
+#ifdef DEBUG_IRQ
+               if (eirr_val != (1UL << MAX_CPU_IRQ))
+                       printk(KERN_DEBUG "do_cpu_irq_mask  %x\n", eirr_val);
+#endif
+
+               for (; eirr_val && bit; bit>>=1, irq++)
+               {
+                       unsigned int irq_num;
+                       if (!(bit&eirr_val))
+                               continue;
+
+                       /* clear bit in mask - can exit loop sooner */
+                       eirr_val &= ~bit;
+
+                       irq_num = region->data.irqbase + irq;
+                       do_irq(&region->action[irq], irq_num, regs);
+               }
+       }
+       set_eiem(cpu_eiem);
 }
 
+
+/* Called from second level IRQ regions: eg dino or iosapic. */
 void do_irq_mask(unsigned long mask, struct irq_region *region, struct pt_regs *regs)
 {
        unsigned long bit;
-       int irq;
-       int cpu = smp_processor_id();
+       unsigned int irq;
 
 #ifdef DEBUG_IRQ
-       if (mask != (1L << MAX_CPU_IRQ))
-           printk("do_irq_mask %08lx %p %p\n", mask, region, regs);
+       if (mask != (1L<<MAX_CPU_IRQ))
+           printk(KERN_DEBUG "do_irq_mask %08lx %p %p\n", mask, region, regs);
 #endif
 
-       for(bit=(1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
-               int irq_num;
-               if(!(bit&mask))
+       for (bit = (1L<<MAX_CPU_IRQ), irq = 0; mask && bit; bit>>=1, irq++) {
+               unsigned int irq_num;
+               if (!(bit&mask))
                        continue;
 
+               mask &= ~bit;   /* clear bit in mask - can exit loop sooner */
                irq_num = region->data.irqbase + irq;
 
-               ++kstat.irqs[cpu][IRQ_FROM_REGION(CPU_IRQ_REGION) | irq];
-               if (IRQ_REGION(irq_num) != CPU_IRQ_REGION)
-                   ++kstat.irqs[cpu][irq_num];
-
                mask_irq(irq_num);
                do_irq(&region->action[irq], irq_num, regs);
                unmask_irq(irq_num);
        }
 }
 
-static inline int alloc_irqregion(void)
+
+static inline int find_free_region(void)
 {
        int irqreg;
 
-       for(irqreg=1; irqreg<=(NR_IRQ_REGS); irqreg++) {
-               if(irq_region[irqreg] == NULL)
+       for (irqreg=1; irqreg <= (NR_IRQ_REGS); irqreg++) {
+               if (irq_region[irqreg] == NULL)
                        return irqreg;
        }
 
        return 0;
 }
 
-struct irq_region *alloc_irq_region(
-       int count, struct irq_region_ops *ops, unsigned long flags,
-       const char *name, void *dev)
+
+/*****
+ * alloc_irq_region - allocate/init a new IRQ region
+ * @count: number of IRQs in this region.
+ * @ops: function table with request/release/mask/unmask/etc.. entries.
+ * @name: name of region owner for /proc/interrupts output.
+ * @dev: private data to associate with the new IRQ region.
+ *
+ * Every IRQ must become a MMIO write to the CPU's EIRR in
+ * order to get CPU service. The IRQ region represents the
+ * number of unique events the region handler can (or must)
+ * identify. For PARISC CPU, that's the width of the EIR Register.
+ * IRQ regions virtualize IRQs (eg EISA or PCI host bus controllers)
+ * for line based devices.
+ */
+struct irq_region *alloc_irq_region( int count, struct irq_region_ops *ops,
+                                       const char *name, void *dev)
 {
        struct irq_region *region;
        int index;
 
-       index = alloc_irqregion();
+       index = find_free_region();
+       if (index == 0) {
+               printk(KERN_ERR "Maximum number of irq regions exceeded. Increase NR_IRQ_REGS!\n");
+               return NULL;
+       }
 
-       if((IRQ_REGION(count-1)))
+       if ((IRQ_REGION(count-1)))
                return NULL;
-       
+
        if (count < IRQ_PER_REGION) {
-           DBG_IRQ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n", 
-                       IRQ_PER_REGION, name, count);
+           DBG_IRQ(0, ("alloc_irq_region() using minimum of %d irq lines for %s (%d)\n",
+                       IRQ_PER_REGION, name, count));
            count = IRQ_PER_REGION;
        }
 
-       if(flags & IRQ_REG_MASK)
-               if(!(ops->mask_irq && ops->unmask_irq))
-                       return NULL;
-                       
-       if(flags & IRQ_REG_DIS)
-               if(!(ops->disable_irq && ops->enable_irq))
+       /* if either mask *or* unmask is set, both have to be set. */
+       if((ops->mask_irq || ops->unmask_irq) &&
+               !(ops->mask_irq && ops->unmask_irq))
                        return NULL;
 
-       if((irq_region[index]))
-               return NULL;
+       /* ditto for enable/disable */
+       if( (ops->disable_irq || ops->enable_irq) &&
+               !(ops->disable_irq && ops->enable_irq) )
+                       return NULL;
 
-       region = kmalloc(sizeof *region, GFP_ATOMIC);
-       if(!region)
+       region = kmalloc(sizeof(*region), GFP_ATOMIC);
+       if (!region)
                return NULL;
+       memset(region, 0, sizeof(*region));
 
-       region->action = kmalloc(sizeof *region->action * count, GFP_ATOMIC);
-       if(!region->action) {
+       region->action = kmalloc(count * sizeof(*region->action), GFP_ATOMIC);
+       if (!region->action) {
                kfree(region);
                return NULL;
        }
-       memset(region->action, 0, sizeof *region->action * count);
+       memset(region->action, 0, count * sizeof(*region->action));
 
        region->ops = *ops;
        region->data.irqbase = IRQ_FROM_REGION(index);
-       region->data.flags = flags;
        region->data.name = name;
        region->data.dev = dev;
 
@@ -420,14 +562,12 @@ struct irq_region *alloc_irq_region(
 
        return irq_region[index];
 }
-       
 
-       
 /* FIXME: SMP, flags, bottom halves, rest */
 
-int request_irq(unsigned int irq, 
+int request_irq(unsigned int irq,
                void (*handler)(int, void *, struct pt_regs *),
-               unsigned long irqflags, 
+               unsigned long irqflags,
                const char * devname,
                void *dev_id)
 {
@@ -436,13 +576,19 @@ int request_irq(unsigned int irq,
 #if 0
        printk(KERN_INFO "request_irq(%d, %p, 0x%lx, %s, %p)\n",irq, handler, irqflags, devname, dev_id);
 #endif
-       if(!handler) {
+
+       irq = irq_cannonicalize(irq);
+       /* request_irq()/free_irq() may not be called from interrupt context. */
+       if (in_interrupt())
+               BUG();
+
+       if (!handler) {
                printk(KERN_ERR "request_irq(%d,...): Augh! No handler for irq!\n",
                        irq);
                return -EINVAL;
        }
 
-       if ((IRQ_REGION(irq) == 0) || irq_region[IRQ_REGION(irq)] == NULL) {
+       if (irq_region[IRQ_REGION(irq)] == NULL) {
                /*
                ** Bug catcher for drivers which use "char" or u8 for
                ** the IRQ number. They lose the region number which
@@ -453,19 +599,24 @@ int request_irq(unsigned int irq,
                return -EINVAL;
        }
 
-       action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
+       spin_lock(&irq_lock);
+       action = &(irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)]);
 
-       if(action->handler) {
-               while(action->next)
+       /* First one is preallocated. */
+       if (action->handler) {
+               /* But it's in use...find the tail and allocate a new one */
+               while (action->next)
                        action = action->next;
 
-               action->next = kmalloc(sizeof *action, GFP_ATOMIC);
+               action->next = kmalloc(sizeof(*action), GFP_ATOMIC);
+               memset(action->next, 0, sizeof(*action));
 
                action = action->next;
-       }                       
+       }
 
-       if(!action) {
-               printk(KERN_ERR "request_irq():Augh! No action!\n") ;
+       if (!action) {
+               spin_unlock(&irq_lock);
+               printk(KERN_ERR "request_irq(): Augh! No action!\n") ;
                return -ENOMEM;
        }
 
@@ -475,6 +626,7 @@ int request_irq(unsigned int irq,
        action->name = devname;
        action->next = NULL;
        action->dev_id = dev_id;
+       spin_unlock(&irq_lock);
 
        enable_irq(irq);
        return 0;
@@ -484,14 +636,22 @@ void free_irq(unsigned int irq, void *dev_id)
 {
        struct irqaction *action, **p;
 
+       /* See comments in request_irq() about interrupt context */
+       irq = irq_cannonicalize(irq);
+       
+       if (in_interrupt()) BUG();
+
+       spin_lock(&irq_lock);
        action = &irq_region[IRQ_REGION(irq)]->action[IRQ_OFFSET(irq)];
 
-       if(action->dev_id == dev_id) {
-               if(action->next == NULL)
+       if (action->dev_id == dev_id) {
+               if (action->next == NULL) {
                        action->handler = NULL;
-               else
-                       memcpy(action, action->next, sizeof *action);
+               } else {
+                       memcpy(action, action->next, sizeof(*action));
+               }
 
+               spin_unlock(&irq_lock);
                return;
        }
 
@@ -506,27 +666,175 @@ void free_irq(unsigned int irq, void *dev_id)
                *p = action->next;
                kfree(action);
 
+               spin_unlock(&irq_lock);
                return;
        }
 
+       spin_unlock(&irq_lock);
        printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
 }
 
-unsigned long probe_irq_on (void)
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *     probe_irq_on    - begin an interrupt autodetect
+ *
+ *     Commence probing for an interrupt. The interrupts are scanned
+ *     and a mask of potential interrupt lines is returned.
+ *
+ */
+
+/* TODO: spin_lock_irq(desc->lock -> irq_lock) */
+
+unsigned long probe_irq_on(void)
 {
-       return 0;
+       unsigned int i;
+       unsigned long val;
+       unsigned long delay;
+       struct irq_region *region;
+
+       /* support for irq autoprobing is limited to EISA (irq region 0) */
+       region = irq_region[EISA_IRQ_REGION];
+       if (!EISA_bus || !region)
+               return 0;
+
+       down(&probe_sem);
+
+       /*
+        * enable any unassigned irqs
+        * (we must startup again here because if a longstanding irq
+        * happened in the previous stage, it may have masked itself)
+        */
+       for (i = EISA_MAX_IRQS-1; i > 0; i--) {
+               struct irqaction *action;
+               
+               spin_lock_irq(&irq_lock);
+               action = region->action + i;
+               if (!action->handler) {
+                       region->data.status[i] |= IRQ_AUTODETECT | IRQ_WAITING;
+                       region->ops.enable_irq(region->data.dev,i);
+               }
+               spin_unlock_irq(&irq_lock);
+       }
+
+       /*
+        * Wait for spurious interrupts to trigger
+        */
+       for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+               /* about 100ms delay */ barrier();
+
+       /*
+        * Now filter out any obviously spurious interrupts
+        */
+       val = 0;
+       for (i = 0; i < EISA_MAX_IRQS; i++) {
+               unsigned int status;
+
+               spin_lock_irq(&irq_lock);
+               status = region->data.status[i];
+
+               if (status & IRQ_AUTODETECT) {
+                       /* It triggered already - consider it spurious. */
+                       if (!(status & IRQ_WAITING)) {
+                               region->data.status[i] = status & ~IRQ_AUTODETECT;
+                               region->ops.disable_irq(region->data.dev,i);
+                       } else
+                               if (i < BITS_PER_LONG)
+                                       val |= (1 << i);
+               }
+               spin_unlock_irq(&irq_lock);
+       }
+
+       return val;
 }
 
-int probe_irq_off (unsigned long irqs)
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source).
+ */
+
+/**
+ *     probe_irq_off   - end an interrupt autodetect
+ *     @val: mask of potential interrupts (unused)
+ *
+ *     Scans the unused interrupt lines and returns the line which
+ *     appears to have triggered the interrupt. If no interrupt was
+ *     found then zero is returned. If more than one interrupt is
+ *     found then minus the first candidate is returned to indicate
+ *     their is doubt.
+ *
+ *     The interrupt probe logic state is returned to its previous
+ *     value.
+ *
+ *     BUGS: When used in a module (which arguably shouldnt happen)
+ *     nothing prevents two IRQ probe callers from overlapping. The
+ *     results of this are non-optimal.
+ */
+int probe_irq_off(unsigned long val)
 {
-       return 0;
+        struct irq_region *region;
+       int i, irq_found, nr_irqs;
+
+        /* support for irq autoprobing is limited to EISA (irq region 0) */
+        region = irq_region[EISA_IRQ_REGION];
+        if (!EISA_bus || !region)
+               return 0;
+
+       nr_irqs = 0;
+       irq_found = 0;
+       for (i = 0; i < EISA_MAX_IRQS; i++) {
+               unsigned int status;
+               
+               spin_lock_irq(&irq_lock);
+               status = region->data.status[i];
+
+                if (status & IRQ_AUTODETECT) {
+                       if (!(status & IRQ_WAITING)) {
+                               if (!nr_irqs)
+                                       irq_found = i;
+                               nr_irqs++;
+                       }
+                       region->ops.disable_irq(region->data.dev,i);
+                       region->data.status[i] = status & ~IRQ_AUTODETECT;
+               }
+               spin_unlock_irq(&irq_lock);
+       }
+       up(&probe_sem);
+
+       if (nr_irqs > 1)
+               irq_found = -irq_found;
+       return irq_found;
 }
 
 
 void __init init_IRQ(void)
 {
+       local_irq_disable();    /* PARANOID - should already be disabled */
+       mtctl(-1L, 23);         /* EIRR : clear all pending external intr */
+#ifdef CONFIG_SMP
+       if (!cpu_eiem)
+               cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+#else
+       cpu_eiem = EIEM_MASK(TIMER_IRQ);
+#endif
+        set_eiem(cpu_eiem);    /* EIEM : enable all external intr */
+
 }
 
-void init_irq_proc(void)
+#ifdef CONFIG_PROC_FS
+/* called from kernel/sysctl.c:sysctl_init() */
+void __init init_irq_proc(void)
 {
 }
+#endif
index 05044db..f6aa4f8 100644 (file)
@@ -1,4 +1,12 @@
 /*
+ *  WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *  ---------------------------------------------------------------
+ *  This source file will be removed as soon as we have converted
+ *  hp_psaux.c and hp_keyb.c to the input layer !
+ *  
+ */
+
+/*
  *  linux/arch/parisc/kernel/keyboard.c
  *
  *  Alex deVries <adevries@thepuffingroup.com>
@@ -7,8 +15,10 @@
  *  Copyright 2000 Philipp Rumpf
  */
 
+#include <linux/errno.h>
 #include <linux/keyboard.h>
 #include <asm/keyboard.h>
+#include <linux/module.h>
 
 static int def_setkeycode(unsigned int x, unsigned int y)
 {
@@ -43,20 +53,29 @@ static void def_init_hw(void)
 
 static char def_sysrq_xlate[NR_KEYS];
 
-static struct kbd_ops def_kbd_ops = {
-       setkeycode:     def_setkeycode,
-       getkeycode:     def_getkeycode,
-       translate:      def_translate,
-       unexpected_up:  def_unexpected_up,
-       leds:           def_leds,
-       init_hw:        def_init_hw,
-
-       sysrq_key:      0xff,
+#define DEFAULT_KEYB_OPS \
+       setkeycode:     def_setkeycode, \
+       getkeycode:     def_getkeycode, \
+       translate:      def_translate, \
+       unexpected_up:  def_unexpected_up, \
+       leds:           def_leds, \
+       init_hw:        def_init_hw, \
+       sysrq_key:      0xff, \
        sysrq_xlate:    def_sysrq_xlate,
+
+static struct kbd_ops def_kbd_ops = {
+       DEFAULT_KEYB_OPS
 };
 
 struct kbd_ops *kbd_ops = &def_kbd_ops;
 
+void unregister_kbd_ops(void)
+{
+       struct kbd_ops new_kbd_ops = { DEFAULT_KEYB_OPS };
+       register_kbd_ops(&new_kbd_ops);
+}
+EXPORT_SYMBOL(unregister_kbd_ops);
+
 void register_kbd_ops(struct kbd_ops *ops)
 {
        if(ops->setkeycode)
index 307e4b2..1589e45 100644 (file)
@@ -4,11 +4,12 @@
  *
  *   Copyright (C) 2000 Philipp Rumpf */
 
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
 #include <asm/gsc.h>
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
-#include <linux/smp.h>
-#include <linux/kernel.h>
 
 /* CPU register indices */
 
 #define DIOERR         0xf0ec
 #define HIDMAMEM       0xf0f4
 
-/* read CPU Diagnose register index */
-static u32 diag_read(int index)
-{
-       return 0;
-}
-
 /* this returns the HPA of the CPU it was called on */
 static u32 cpu_hpa(void)
 {
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
new file mode 100644 (file)
index 0000000..f8548e4
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ *  Parisc tlb and cache flushing support
+ *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * NOTE: fdc,fic, and pdc instructions that use base register modification
+ *       should only use index and base registers that are not shadowed,
+ *       so that the fast path emulation in the non access miss handler
+ *       can be used.
+ */
+
+#ifdef __LP64__
+#define ADDIB   addib,*
+#define CMPB    cmpb,*
+#define ANDCM   andcm,*
+
+       .level 2.0w
+#else
+#define ADDIB   addib,
+#define CMPB    cmpb,
+#define ANDCM   andcm
+
+       .level 2.0
+#endif
+
+#include <asm/assembly.h>
+#include <asm/psw.h>
+#include <asm/pgtable.h>
+#include <asm/cache.h>
+
+       .text
+       .align 128
+
+       .export flush_tlb_all_local,code
+
+flush_tlb_all_local:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       /*
+        * The pitlbe and pdtlbe instructions should only be used to
+        * flush the entire tlb. Also, there needs to be no intervening
+        * tlb operations, e.g. tlb misses, so the operation needs
+        * to happen in real mode with all interruptions disabled.
+        */
+
+       /*
+        * Once again, we do the rfi dance ... some day we need examine
+        * all of our uses of this type of code and see what can be
+        * consolidated.
+        */
+
+       rsm     PSW_SM_I,%r19      /* relied upon translation! */
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       
+       rsm     PSW_SM_Q,%r0       /* Turn off Q bit to load iia queue */
+       ldil    L%REAL_MODE_PSW, %r1
+       ldo     R%REAL_MODE_PSW(%r1), %r1
+       mtctl   %r1, %cr22
+       mtctl   %r0, %cr17
+       mtctl   %r0, %cr17
+       ldil    L%PA(1f),%r1
+       ldo     R%PA(1f)(%r1),%r1
+       mtctl   %r1, %cr18
+       ldo     4(%r1), %r1
+       mtctl   %r1, %cr18
+       rfi
+       nop
+
+1:      ldil            L%PA(cache_info),%r1
+       ldo             R%PA(cache_info)(%r1),%r1
+
+       /* Flush Instruction Tlb */
+
+       LDREG           ITLB_SID_BASE(%r1),%r20
+       LDREG           ITLB_SID_STRIDE(%r1),%r21
+       LDREG           ITLB_SID_COUNT(%r1),%r22
+       LDREG           ITLB_OFF_BASE(%r1),%arg0
+       LDREG           ITLB_OFF_STRIDE(%r1),%arg1
+       LDREG           ITLB_OFF_COUNT(%r1),%arg2
+       LDREG           ITLB_LOOP(%r1),%arg3
+
+       ADDIB=          -1,%arg3,fitoneloop     /* Preadjust and test */
+       movb,<,n        %arg3,%r31,fitdone      /* If loop < 0, skip */
+       copy            %arg0,%r28              /* Init base addr */
+
+fitmanyloop:                                    /* Loop if LOOP >= 2 */
+       mtsp            %r20,%sr1
+       add             %r21,%r20,%r20          /* increment space */
+       copy            %arg2,%r29              /* Init middle loop count */
+
+fitmanymiddle:                                  /* Loop if LOOP >= 2 */
+       ADDIB>          -1,%r31,fitmanymiddle   /* Adjusted inner loop decr */
+       pitlbe          0(%sr1,%r28)
+       pitlbe,m        %arg1(%sr1,%r28)        /* Last pitlbe and addr adjust */
+       ADDIB>          -1,%r29,fitmanymiddle   /* Middle loop decr */
+       copy            %arg3,%r31              /* Re-init inner loop count */
+
+       movb,tr         %arg0,%r28,fitmanyloop  /* Re-init base addr */
+       ADDIB<=,n       -1,%r22,fitdone         /* Outer loop count decr */
+
+fitoneloop:                                     /* Loop if LOOP = 1 */
+       mtsp            %r20,%sr1
+       copy            %arg0,%r28              /* init base addr */
+       copy            %arg2,%r29              /* init middle loop count */
+
+fitonemiddle:                                   /* Loop if LOOP = 1 */
+       ADDIB>          -1,%r29,fitonemiddle    /* Middle loop count decr */
+       pitlbe,m        %arg1(%sr1,%r28)        /* pitlbe for one loop */
+
+       ADDIB>          -1,%r22,fitoneloop      /* Outer loop count decr */
+       add             %r21,%r20,%r20          /* increment space */
+
+fitdone:
+
+       /* Flush Data Tlb */
+
+       LDREG           DTLB_SID_BASE(%r1),%r20
+       LDREG           DTLB_SID_STRIDE(%r1),%r21
+       LDREG           DTLB_SID_COUNT(%r1),%r22
+       LDREG           DTLB_OFF_BASE(%r1),%arg0
+       LDREG           DTLB_OFF_STRIDE(%r1),%arg1
+       LDREG           DTLB_OFF_COUNT(%r1),%arg2
+       LDREG           DTLB_LOOP(%r1),%arg3
+
+       ADDIB=          -1,%arg3,fdtoneloop     /* Preadjust and test */
+       movb,<,n        %arg3,%r31,fdtdone      /* If loop < 0, skip */
+       copy            %arg0,%r28              /* Init base addr */
+
+fdtmanyloop:                                    /* Loop if LOOP >= 2 */
+       mtsp            %r20,%sr1
+       add             %r21,%r20,%r20          /* increment space */
+       copy            %arg2,%r29              /* Init middle loop count */
+
+fdtmanymiddle:                                  /* Loop if LOOP >= 2 */
+       ADDIB>          -1,%r31,fdtmanymiddle   /* Adjusted inner loop decr */
+       pdtlbe          0(%sr1,%r28)
+       pdtlbe,m        %arg1(%sr1,%r28)        /* Last pdtlbe and addr adjust */
+       ADDIB>          -1,%r29,fdtmanymiddle   /* Middle loop decr */
+       copy            %arg3,%r31              /* Re-init inner loop count */
+
+       movb,tr         %arg0,%r28,fdtmanyloop  /* Re-init base addr */
+       ADDIB<=,n       -1,%r22,fdtdone         /* Outer loop count decr */
+
+fdtoneloop:                                     /* Loop if LOOP = 1 */
+       mtsp            %r20,%sr1
+       copy            %arg0,%r28              /* init base addr */
+       copy            %arg2,%r29              /* init middle loop count */
+
+fdtonemiddle:                                   /* Loop if LOOP = 1 */
+       ADDIB>          -1,%r29,fdtonemiddle    /* Middle loop count decr */
+       pdtlbe,m        %arg1(%sr1,%r28)        /* pdtlbe for one loop */
+
+       ADDIB>          -1,%r22,fdtoneloop      /* Outer loop count decr */
+       add             %r21,%r20,%r20          /* increment space */
+
+fdtdone:
+
+       /* Switch back to virtual mode */
+
+       rsm     PSW_SM_Q,%r0       /* clear Q bit to load iia queue */
+       ldil    L%KERNEL_PSW, %r1
+       ldo     R%KERNEL_PSW(%r1), %r1
+       or      %r1,%r19,%r1    /* Set I bit if set on entry */
+       mtctl   %r1, %cr22
+       mtctl   %r0, %cr17
+       mtctl   %r0, %cr17
+       ldil    L%(2f), %r1
+       ldo     R%(2f)(%r1), %r1
+       mtctl   %r1, %cr18
+       ldo     4(%r1), %r1
+       mtctl   %r1, %cr18
+       rfi
+       nop
+
+2:      bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export flush_instruction_cache_local,code
+       .import cache_info,data
+
+flush_instruction_cache_local:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       mtsp            %r0,%sr1
+       ldil            L%cache_info,%r1
+       ldo             R%cache_info(%r1),%r1
+
+       /* Flush Instruction Cache */
+
+       LDREG           ICACHE_BASE(%r1),%arg0
+       LDREG           ICACHE_STRIDE(%r1),%arg1
+       LDREG           ICACHE_COUNT(%r1),%arg2
+       LDREG           ICACHE_LOOP(%r1),%arg3
+       ADDIB=          -1,%arg3,fioneloop      /* Preadjust and test */
+       movb,<,n        %arg3,%r31,fisync       /* If loop < 0, do sync */
+
+fimanyloop:                                     /* Loop if LOOP >= 2 */
+       ADDIB>          -1,%r31,fimanyloop      /* Adjusted inner loop decr */
+       fice            0(%sr1,%arg0)
+       fice,m          %arg1(%sr1,%arg0)       /* Last fice and addr adjust */
+       movb,tr         %arg3,%r31,fimanyloop   /* Re-init inner loop count */
+       ADDIB<=,n       -1,%arg2,fisync         /* Outer loop decr */
+
+fioneloop:                                      /* Loop if LOOP = 1 */
+       ADDIB>          -1,%arg2,fioneloop      /* Outer loop count decr */
+       fice,m          %arg1(%sr1,%arg0)       /* Fice for one loop */
+
+fisync:
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export flush_data_cache_local,code
+       .import cache_info,data
+
+flush_data_cache_local:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       mtsp            %r0,%sr1
+       ldil            L%cache_info,%r1
+       ldo             R%cache_info(%r1),%r1
+
+       /* Flush Data Cache */
+
+       LDREG           DCACHE_BASE(%r1),%arg0
+       LDREG           DCACHE_STRIDE(%r1),%arg1
+       LDREG           DCACHE_COUNT(%r1),%arg2
+       LDREG           DCACHE_LOOP(%r1),%arg3
+       rsm             PSW_SM_I,%r22
+       ADDIB=          -1,%arg3,fdoneloop      /* Preadjust and test */
+       movb,<,n        %arg3,%r31,fdsync       /* If loop < 0, do sync */
+
+fdmanyloop:                                     /* Loop if LOOP >= 2 */
+       ADDIB>          -1,%r31,fdmanyloop      /* Adjusted inner loop decr */
+       fdce            0(%sr1,%arg0)
+       fdce,m          %arg1(%sr1,%arg0)       /* Last fdce and addr adjust */
+       movb,tr         %arg3,%r31,fdmanyloop   /* Re-init inner loop count */
+       ADDIB<=,n       -1,%arg2,fdsync         /* Outer loop decr */
+
+fdoneloop:                                      /* Loop if LOOP = 1 */
+       ADDIB>          -1,%arg2,fdoneloop      /* Outer loop count decr */
+       fdce,m          %arg1(%sr1,%arg0)       /* Fdce for one loop */
+
+fdsync:
+       syncdma
+       sync
+       mtsm    %r22
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export copy_user_page_asm,code
+
+copy_user_page_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldi 64,%r1
+
+       /*
+        * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+        * bundles (very restricted rules for bundling). It probably
+        * does OK on PCXU and better, but we could do better with
+        * ldd/std instructions. Note that until (if) we start saving
+        * the full 64 bit register values on interrupt, we can't
+        * use ldd/std on a 32 bit kernel.
+        */
+
+
+1:
+       ldw 0(%r25),%r19
+       ldw 4(%r25),%r20
+       ldw 8(%r25),%r21
+       ldw 12(%r25),%r22
+       stw %r19,0(%r26)
+       stw %r20,4(%r26)
+       stw %r21,8(%r26)
+       stw %r22,12(%r26)
+       ldw 16(%r25),%r19
+       ldw 20(%r25),%r20
+       ldw 24(%r25),%r21
+       ldw 28(%r25),%r22
+       stw %r19,16(%r26)
+       stw %r20,20(%r26)
+       stw %r21,24(%r26)
+       stw %r22,28(%r26)
+       ldw 32(%r25),%r19
+       ldw 36(%r25),%r20
+       ldw 40(%r25),%r21
+       ldw 44(%r25),%r22
+       stw %r19,32(%r26)
+       stw %r20,36(%r26)
+       stw %r21,40(%r26)
+       stw %r22,44(%r26)
+       ldw 48(%r25),%r19
+       ldw 52(%r25),%r20
+       ldw 56(%r25),%r21
+       ldw 60(%r25),%r22
+       stw %r19,48(%r26)
+       stw %r20,52(%r26)
+       stw %r21,56(%r26)
+       stw %r22,60(%r26)
+       ldo 64(%r26),%r26
+       ADDIB>  -1,%r1,1b
+       ldo 64(%r25),%r25
+
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+#if (TMPALIAS_MAP_START >= 0x80000000UL)
+Warning TMPALIAS_MAP_START changed. If > 2 Gb, code in pacache.S is bogus
+#endif
+
+/*
+ * NOTE: Code in clear_user_page has a hard coded dependency on the
+ *       maximum alias boundary being 4 Mb. We've been assured by the
+ *       parisc chip designers that there will not ever be a parisc
+ *       chip with a larger alias boundary (Never say never :-) ).
+ *
+ *       Subtle: the dtlb miss handlers support the temp alias region by
+ *       "knowing" that if a dtlb miss happens within the temp alias
+ *       region it must have occurred while in clear_user_page. Since
+ *       this routine makes use of processor local translations, we
+ *       don't want to insert them into the kernel page table. Instead,
+ *       we load up some general registers (they need to be registers
+ *       which aren't shadowed) with the physical page numbers (preshifted
+ *       for tlb insertion) needed to insert the translations. When we
+ *       miss on the translation, the dtlb miss handler inserts the
+ *       translation into the tlb using these values:
+ *
+ *          %r26 physical page (shifted for tlb insert) of "to" translation
+ *          %r23 physical page (shifted for tlb insert) of "from" translation
+ */
+
+#if 0
+
+       /*
+        * We can't do this since copy_user_page is used to bring in
+        * file data that might have instructions. Since the data would
+        * then need to be flushed out so the i-fetch can see it, it
+        * makes more sense to just copy through the kernel translation
+        * and flush it.
+        *
+        * I'm still keeping this around because it may be possible to
+        * use it if more information is passed into copy_user_page().
+        * Have to do some measurements to see if it is worthwhile to
+        * lobby for such a change.
+        */
+
+       .export copy_user_page_asm,code
+
+copy_user_page_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%(__PAGE_OFFSET),%r1
+       sub     %r26,%r1,%r26
+       sub     %r25,%r1,%r23  /* move physical addr into non shadowed reg */
+
+       ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+       extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+       extrd,u %r23,56,32,%r23 /* convert phys addr to tlb insert format */
+       depd    %r24,63,22,%r28 /* Form aliased virtual address 'to' */
+       depdi   0,63,12,%r28    /* Clear any offset bits */
+       copy    %r28,%r29
+       depdi   1,41,1,%r29     /* Form aliased virtual address 'from' */
+#else
+       extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+       extrw,u %r23,24,25,%r23 /* convert phys addr to tlb insert format */
+       depw    %r24,31,22,%r28 /* Form aliased virtual address 'to' */
+       depwi   0,31,12,%r28    /* Clear any offset bits */
+       copy    %r28,%r29
+       depwi   1,9,1,%r29      /* Form aliased virtual address 'from' */
+#endif
+
+       /* Purge any old translations */
+
+       pdtlb   0(%r28)
+       pdtlb   0(%r29)
+
+       ldi 64,%r1
+
+       /*
+        * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+        * bundles (very restricted rules for bundling). It probably
+        * does OK on PCXU and better, but we could do better with
+        * ldd/std instructions. Note that until (if) we start saving
+        * the full 64 bit register values on interrupt, we can't
+        * use ldd/std on a 32 bit kernel.
+        */
+
+
+1:
+       ldw 0(%r29),%r19
+       ldw 4(%r29),%r20
+       ldw 8(%r29),%r21
+       ldw 12(%r29),%r22
+       stw %r19,0(%r28)
+       stw %r20,4(%r28)
+       stw %r21,8(%r28)
+       stw %r22,12(%r28)
+       ldw 16(%r29),%r19
+       ldw 20(%r29),%r20
+       ldw 24(%r29),%r21
+       ldw 28(%r29),%r22
+       stw %r19,16(%r28)
+       stw %r20,20(%r28)
+       stw %r21,24(%r28)
+       stw %r22,28(%r28)
+       ldw 32(%r29),%r19
+       ldw 36(%r29),%r20
+       ldw 40(%r29),%r21
+       ldw 44(%r29),%r22
+       stw %r19,32(%r28)
+       stw %r20,36(%r28)
+       stw %r21,40(%r28)
+       stw %r22,44(%r28)
+       ldw 48(%r29),%r19
+       ldw 52(%r29),%r20
+       ldw 56(%r29),%r21
+       ldw 60(%r29),%r22
+       stw %r19,48(%r28)
+       stw %r20,52(%r28)
+       stw %r21,56(%r28)
+       stw %r22,60(%r28)
+       ldo 64(%r28),%r28
+       ADDIB>  -1,%r1,1b
+       ldo 64(%r29),%r29
+
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+#endif
+
+       .export clear_user_page_asm,code
+
+clear_user_page_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       tophys_r1 %r26
+
+       ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+       extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+       depd    %r25,63,22,%r28 /* Form aliased virtual address 'to' */
+       depdi   0,63,12,%r28    /* Clear any offset bits */
+#else
+       extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+       depw    %r25,31,22,%r28 /* Form aliased virtual address 'to' */
+       depwi   0,31,12,%r28    /* Clear any offset bits */
+#endif
+
+       /* Purge any old translation */
+
+       pdtlb   0(%r28)
+
+       ldi 64,%r1
+
+1:
+       stw %r0,0(%r28)
+       stw %r0,4(%r28)
+       stw %r0,8(%r28)
+       stw %r0,12(%r28)
+       stw %r0,16(%r28)
+       stw %r0,20(%r28)
+       stw %r0,24(%r28)
+       stw %r0,28(%r28)
+       stw %r0,32(%r28)
+       stw %r0,36(%r28)
+       stw %r0,40(%r28)
+       stw %r0,44(%r28)
+       stw %r0,48(%r28)
+       stw %r0,52(%r28)
+       stw %r0,56(%r28)
+       stw %r0,60(%r28)
+       ADDIB>  -1,%r1,1b
+       ldo 64(%r28),%r28
+
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export flush_kernel_dcache_page
+
+flush_kernel_dcache_page:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%dcache_stride,%r1
+       ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+       depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+       depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+       add     %r26,%r25,%r25
+       sub     %r25,%r23,%r25
+
+
+1:      fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       fdc,m   %r23(%r26)
+       CMPB<<  %r26,%r25,1b
+       fdc,m   %r23(%r26)
+
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export purge_kernel_dcache_page
+
+purge_kernel_dcache_page:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%dcache_stride,%r1
+       ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+       depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+       depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+       add      %r26,%r25,%r25
+       sub      %r25,%r23,%r25
+
+1:      pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       pdc,m   %r23(%r26)
+       CMPB<<  %r26,%r25,1b
+       pdc,m   %r23(%r26)
+
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+#if 0
+       /* Currently not used, but it still is a possible alternate
+        * solution.
+        */
+
+       .export flush_alias_page
+
+flush_alias_page:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       tophys_r1 %r26
+
+       ldil    L%(TMPALIAS_MAP_START),%r28
+#ifdef __LP64__
+       extrd,u %r26,56,32,%r26 /* convert phys addr to tlb insert format */
+       depd    %r25,63,22,%r28 /* Form aliased virtual address 'to' */
+       depdi   0,63,12,%r28    /* Clear any offset bits */
+#else
+       extrw,u %r26,24,25,%r26 /* convert phys addr to tlb insert format */
+       depw    %r25,31,22,%r28 /* Form aliased virtual address 'to' */
+       depwi   0,31,12,%r28    /* Clear any offset bits */
+#endif
+
+       /* Purge any old translation */
+
+       pdtlb   0(%r28)
+
+       ldil    L%dcache_stride,%r1
+       ldw     R%dcache_stride(%r1),%r23
+
+#ifdef __LP64__
+       depdi,z 1,63-PAGE_SHIFT,1,%r29
+#else
+       depwi,z 1,31-PAGE_SHIFT,1,%r29
+#endif
+       add      %r28,%r29,%r29
+       sub      %r29,%r23,%r29
+
+1:      fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       fdc,m   %r23(%r28)
+       CMPB<<  %r28,%r29,1b
+       fdc,m   %r23(%r28)
+
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+#endif
+
+       .export flush_user_dcache_range_asm
+
+flush_user_dcache_range_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%dcache_stride,%r1
+       ldw     R%dcache_stride(%r1),%r23
+       ldo     -1(%r23),%r21
+       ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+       fdc,m   %r23(%sr3,%r26)
+
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export flush_kernel_dcache_range_asm
+
+flush_kernel_dcache_range_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%dcache_stride,%r1
+       ldw     R%dcache_stride(%r1),%r23
+       ldo     -1(%r23),%r21
+       ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+       fdc,m   %r23(%r26)
+
+       sync
+       syncdma
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export flush_user_icache_range_asm
+
+flush_user_icache_range_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%icache_stride,%r1
+       ldw     R%icache_stride(%r1),%r23
+       ldo     -1(%r23),%r21
+       ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+       fic,m   %r23(%sr3,%r26)
+
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export flush_kernel_icache_page
+
+flush_kernel_icache_page:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%icache_stride,%r1
+       ldw     R%icache_stride(%r1),%r23
+
+#ifdef __LP64__
+       depdi,z 1,63-PAGE_SHIFT,1,%r25
+#else
+       depwi,z 1,31-PAGE_SHIFT,1,%r25
+#endif
+       add     %r26,%r25,%r25
+       sub     %r25,%r23,%r25
+
+
+1:      fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       fic,m   %r23(%r26)
+       CMPB<<  %r26,%r25,1b
+       fic,m   %r23(%r26)
+
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .export flush_kernel_icache_range_asm
+
+flush_kernel_icache_range_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil    L%icache_stride,%r1
+       ldw     R%icache_stride(%r1),%r23
+       ldo     -1(%r23),%r21
+       ANDCM   %r26,%r21,%r26
+
+1:      CMPB<<,n %r26,%r25,1b
+       fic,m   %r23(%r26)
+
+       sync
+       bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .align 128
+
+       .export disable_sr_hashing_asm,code
+
+disable_sr_hashing_asm:
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       /* Switch to real mode */
+
+       ssm     0,%r0           /* relied upon translation! */
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       
+       rsm     (PSW_SM_Q|PSW_SM_I),%r0 /* disable Q&I to load the iia queue */
+       ldil    L%REAL_MODE_PSW, %r1
+       ldo     R%REAL_MODE_PSW(%r1), %r1
+       mtctl   %r1, %cr22
+       mtctl   %r0, %cr17
+       mtctl   %r0, %cr17
+       ldil    L%PA(1f),%r1
+       ldo     R%PA(1f)(%r1),%r1
+       mtctl   %r1, %cr18
+       ldo     4(%r1), %r1
+       mtctl   %r1, %cr18
+       rfi
+       nop
+
+1:      cmpib,=,n SRHASH_PCXST,%r26,srdis_pcxs
+       cmpib,=,n SRHASH_PCXL,%r26,srdis_pcxl
+       cmpib,=,n SRHASH_PA20,%r26,srdis_pa20
+       b,n       srdis_done
+
+srdis_pcxs:
+
+       /* Disable Space Register Hashing for PCXS,PCXT,PCXT' */
+
+       .word           0x141c1a00  /* mfdiag %dr0,%r28 */
+       .word           0x141c1a00  /* must issue twice */
+       depwi           0,18,1,%r28 /* Clear DHE (dcache hash enable) */
+       depwi           0,20,1,%r28 /* Clear IHE (icache hash enable) */
+       .word           0x141c1600  /* mtdiag %r28,%dr0 */
+       .word           0x141c1600  /* must issue twice */
+       b,n             srdis_done
+
+srdis_pcxl:
+
+       /* Disable Space Register Hashing for PCXL */
+
+       .word           0x141c0600  /* mfdiag %dr0,%r28 */
+       depwi           0,28,2,%r28 /* Clear DHASH_EN & IHASH_EN */
+       .word           0x141c0240  /* mtdiag %r28,%dr0 */
+       b,n             srdis_done
+
+srdis_pa20:
+
+       /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+ */
+
+       .word           0x144008bc  /* mfdiag %dr2,%r28 */
+       depdi           0,54,1,%r28 /* clear DIAG_SPHASH_ENAB (bit 54) */
+       .word           0x145c1840  /* mtdiag %r28,%dr2 */
+
+srdis_done:
+
+       /* Switch back to virtual mode */
+
+       rsm     PSW_SM_Q,%r0           /* clear Q bit to load iia queue */
+       ldil    L%KERNEL_PSW, %r1
+       ldo     R%KERNEL_PSW(%r1), %r1
+       mtctl   %r1, %cr22
+       mtctl   %r0, %cr17
+       mtctl   %r0, %cr17
+       ldil    L%(2f), %r1
+       ldo     R%(2f)(%r1), %r1
+       mtctl   %r1, %cr18
+       ldo     4(%r1), %r1
+       mtctl   %r1, %cr18
+       rfi
+       nop
+
+2:      bv      %r0(%r2)
+       nop
+       .exit
+
+       .procend
+
+       .end
index 8d40cad..c67403a 100644 (file)
@@ -14,16 +14,28 @@ EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strstr);
 
+#include <asm/hardware.h>      /* struct parisc_device for asm/pci.h */
 #include <linux/pci.h>
 EXPORT_SYMBOL(hppa_dma_ops);
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+EXPORT_SYMBOL(get_pci_node_path);
+#endif
+
+#ifdef CONFIG_IOMMU_CCIO
+EXPORT_SYMBOL(ccio_get_fake);
+#endif
 
+#include <linux/sched.h>
 #include <asm/irq.h>
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -31,39 +43,102 @@ EXPORT_SYMBOL(disable_irq);
 #include <asm/processor.h>
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(boot_cpu_data);
+EXPORT_SYMBOL(map_hpux_gateway_page);
+#ifdef CONFIG_EISA
+EXPORT_SYMBOL(EISA_bus);
+#endif
+
+#include <linux/pm.h>
+EXPORT_SYMBOL(pm_power_off);
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(synchronize_irq);
+#endif /* CONFIG_SMP */
 
-#include <asm/system.h>
-EXPORT_SYMBOL(__global_sti);
-EXPORT_SYMBOL(__global_cli);
-EXPORT_SYMBOL(__global_save_flags);
-EXPORT_SYMBOL(__global_restore_flags);
-
+#include <asm/atomic.h>
+EXPORT_SYMBOL(__xchg8);
+EXPORT_SYMBOL(__xchg32);
+EXPORT_SYMBOL(__cmpxchg_u32);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__atomic_hash);
+#endif
+#ifdef __LP64__
+EXPORT_SYMBOL(__xchg64);
+EXPORT_SYMBOL(__cmpxchg_u64);
 #endif
 
 #include <asm/uaccess.h>
 EXPORT_SYMBOL(lcopy_to_user);
 EXPORT_SYMBOL(lcopy_from_user);
+EXPORT_SYMBOL(lstrnlen_user);
+EXPORT_SYMBOL(lclear_user);
 
+#ifndef __LP64__
 /* Needed so insmod can set dp value */
-
-extern int data_start;
-
-EXPORT_SYMBOL_NOVERS(data_start);
+extern int $global$;
+EXPORT_SYMBOL_NOVERS($global$);
+#endif
 
 #include <asm/gsc.h>
-EXPORT_SYMBOL(_gsc_writeb);
-EXPORT_SYMBOL(_gsc_writew);
-EXPORT_SYMBOL(_gsc_writel);
-EXPORT_SYMBOL(_gsc_readb);
-EXPORT_SYMBOL(_gsc_readw);
-EXPORT_SYMBOL(_gsc_readl);
-EXPORT_SYMBOL(busdevice_alloc_irq);
-EXPORT_SYMBOL(register_driver);
-EXPORT_SYMBOL(gsc_alloc_irq);
+EXPORT_SYMBOL(register_parisc_driver);
+EXPORT_SYMBOL(unregister_parisc_driver);
 EXPORT_SYMBOL(pdc_iodc_read);
+#ifdef CONFIG_GSC
+EXPORT_SYMBOL(gsc_alloc_irq);
+#endif
+
+#include <asm/io.h>
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memset_io);
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+#endif
+
+#include <asm/cache.h>
+EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
+EXPORT_SYMBOL(flush_kernel_dcache_page);
+EXPORT_SYMBOL(flush_all_caches);
+
+#include <asm/unistd.h>
+extern long sys_open(const char *, int, int);
+extern off_t sys_lseek(int, off_t, int);
+extern int sys_read(int, char *, int);
+extern int sys_write(int, const char *, int);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_write);
+
+#include <asm/semaphore.h>
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down);
+
+#include <linux/in6.h>
+#include <asm/checksum.h>
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+#include <asm/pdc.h>
+EXPORT_SYMBOL(pdc_add_valid);
+EXPORT_SYMBOL(pdc_lan_station_id);
+EXPORT_SYMBOL(pdc_get_initiator);
 
 extern void $$divI(void);
 extern void $$divU(void);
@@ -95,7 +170,9 @@ EXPORT_SYMBOL_NOVERS($$divU);
 EXPORT_SYMBOL_NOVERS($$remI);
 EXPORT_SYMBOL_NOVERS($$remU);
 EXPORT_SYMBOL_NOVERS($$mulI);
+#ifndef __LP64__
 EXPORT_SYMBOL_NOVERS($$mulU);
+#endif
 EXPORT_SYMBOL_NOVERS($$divU_3);
 EXPORT_SYMBOL_NOVERS($$divU_5);
 EXPORT_SYMBOL_NOVERS($$divU_6);
@@ -116,15 +193,25 @@ EXPORT_SYMBOL_NOVERS($$divI_14);
 EXPORT_SYMBOL_NOVERS($$divI_15);
 
 extern void __ashrdi3(void);
+extern void __ashldi3(void);
+extern void __lshrdi3(void);
+extern void __muldi3(void);
 
 EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__ashldi3);
+EXPORT_SYMBOL_NOVERS(__lshrdi3);
+EXPORT_SYMBOL_NOVERS(__muldi3);
 
 #ifdef __LP64__
 extern void __divdi3(void);
 extern void __udivdi3(void);
+extern void __umoddi3(void);
+extern void __moddi3(void);
 
 EXPORT_SYMBOL_NOVERS(__divdi3);
 EXPORT_SYMBOL_NOVERS(__udivdi3);
+EXPORT_SYMBOL_NOVERS(__umoddi3);
+EXPORT_SYMBOL_NOVERS(__moddi3);
 #endif
 
 #ifndef __LP64__
index 9b08f96..55a9f54 100644 (file)
@@ -1,5 +1,7 @@
 /*
-** Dynamic DMA mapping support.
+** PARISC 1.1 Dynamic DMA mapping support.
+** This implementation is for PA-RISC platforms that do not support
+** I/O TLBs (aka DMA address translation hardware).
 ** See Documentation/DMA-mapping.txt for interface definitions.
 **
 **      (c) Copyright 1999,2000 Hewlett-Packard Company
@@ -7,36 +9,28 @@
 **     (c) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
 **      (c) Copyright 2000 John Marvin
 **
-** This implementation is for PA-RISC platforms that do not support
-** I/O TLBs (aka DMA address translation hardware).
-**
 ** "leveraged" from 2.3.47: arch/ia64/kernel/pci-dma.c.
 ** (I assume it's from David Mosberger-Tang but there was no Copyright)
 **
 ** AFAIK, all PA7100LC and PA7300LC platforms can use this code.
-** All PA2.0 machines but V-class can alias xxx_alloc_consistent()
-** to use regular cacheable memory.
 **
 ** - ggg
 */
 
-#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/mm.h>
-#include <linux/string.h>
 #include <linux/pci.h>
-#include <linux/init.h>
-
+#include <linux/proc_fs.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
+#include <linux/string.h>
+#include <linux/types.h>
 
+#include <asm/cacheflush.h>
+#include <asm/dma.h>    /* for DMA_CHUNK_SIZE */
 #include <asm/io.h>
 #include <asm/page.h>  /* get_order */
-#include <asm/dma.h>    /* for DMA_CHUNK_SIZE */
-
-#include <linux/proc_fs.h>
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
 
 static struct proc_dir_entry * proc_gsc_root = NULL;
 static int pcxl_proc_info(char *buffer, char **start, off_t offset, int length);
@@ -117,7 +111,7 @@ static inline int map_pmd_uncached(pmd_t * pmd, unsigned long vaddr,
        if (end > PGDIR_SIZE)
                end = PGDIR_SIZE;
        do {
-               pte_t * pte = pte_alloc_kernel(pmd, vaddr);
+               pte_t * pte = pte_alloc_kernel(&init_mm, pmd, vaddr);
                if (!pte)
                        return -ENOMEM;
                if (map_pte_uncached(pte, orig_vaddr, end - vaddr, paddr_ptr))
@@ -139,7 +133,7 @@ static inline int map_uncached_pages(unsigned long vaddr, unsigned long size,
        do {
                pmd_t *pmd;
                
-               pmd = pmd_alloc_kernel(dir, vaddr);
+               pmd = pmd_alloc(NULL, dir, vaddr);
                if (!pmd)
                        return -ENOMEM;
                if (map_pmd_uncached(pmd, vaddr, end - vaddr, &paddr))
@@ -164,7 +158,7 @@ static inline void unmap_uncached_pte(pmd_t * pmd, unsigned long vaddr,
                pmd_clear(pmd);
                return;
        }
-       pte = pte_offset(pmd, vaddr);
+       pte = pte_offset_map(pmd, vaddr);
        vaddr &= ~PMD_MASK;
        end = vaddr + size;
        if (end > PMD_SIZE)
@@ -347,7 +341,7 @@ pcxl_dma_init(void)
     pcxl_res_hint = 0;
     pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL,
                                            get_order(pcxl_res_size));
-
+    memset(pcxl_res_map, 0, pcxl_res_size);
     proc_gsc_root = proc_mkdir("gsc", 0);
     create_proc_info_entry("dino", 0, proc_gsc_root, pcxl_proc_info);
     return 0;
@@ -431,10 +425,10 @@ static int pa11_dma_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int
            BUG();
 
        for (i = 0; i < nents; i++, sglist++ ) {
-               sg_dma_address(sglist) = (dma_addr_t) virt_to_phys(sglist->address);
+               unsigned long vaddr = sg_virt_addr(sglist);
+               sg_dma_address(sglist) = (dma_addr_t) virt_to_phys(vaddr);
                sg_dma_len(sglist) = sglist->length;
-               flush_kernel_dcache_range((unsigned long)sglist->address,
-                               sglist->length);
+               flush_kernel_dcache_range(vaddr, sglist->length);
        }
        return nents;
 }
@@ -452,7 +446,7 @@ static void pa11_dma_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, i
        /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
 
        for (i = 0; i < nents; i++, sglist++ )
-               flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length);
+               flush_kernel_dcache_range(sg_virt_addr(sglist), sglist->length);
        return;
 }
 
@@ -471,7 +465,7 @@ static void pa11_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sglist, in
        /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */
 
        for (i = 0; i < nents; i++, sglist++ )
-               flush_kernel_dcache_range((unsigned long) sglist->address, sglist->length);
+               flush_kernel_dcache_range(sg_virt_addr(sglist), sglist->length);
 }
 
 struct pci_dma_ops pcxl_dma_ops = {
@@ -510,7 +504,6 @@ struct pci_dma_ops pcx_dma_ops = {
        pa11_dma_sync_sg                        /* dma_sync_sg */
 };
 
-struct pci_dma_ops *hppa_dma_ops;
 
 static int pcxl_proc_info(char *buf, char **start, off_t offset, int len)
 {
index 20d3311..649ad35 100644 (file)
@@ -6,25 +6,32 @@
  *
  * Copyright (C) 1997, 1998 Ralf Baechle
  * Copyright (C) 1999 SuSE GmbH
- * Copyright (C) 1999 Hewlett-Packard Company
- * Copyright (C) 1999, 2000 Grant Grundler
+ * Copyright (C) 1999-2001 Hewlett-Packard Company
+ * Copyright (C) 1999-2001 Grant Grundler
  */
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>                /* for __init and __devinit */
 #include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>      /* for memcpy() */
+#include <linux/slab.h>
 
+#include <asm/io.h>
 #include <asm/system.h>
+#include <asm/cache.h>         /* for L1_CACHE_BYTES */
 
-#ifdef CONFIG_PCI
+#define DEBUG_RESOURCES 0
+#define DEBUG_CONFIG 0
 
-#undef DEBUG_RESOURCES
+#if DEBUG_CONFIG
+# define DBGC(x...)     printk(KERN_DEBUG x)
+#else
+# define DBGC(x...)
+#endif
 
-#ifdef DEBUG_RESOURCES
-#define DBG_RES(x...)  printk(x)
+
+#if DEBUG_RESOURCES
+#define DBG_RES(x...)  printk(KERN_DEBUG x)
 #else
 #define DBG_RES(x...)
 #endif
@@ -42,14 +49,13 @@ int pci_post_reset_delay = 50;
 struct pci_port_ops *pci_port;
 struct pci_bios_ops *pci_bios;
 
-struct pci_hba_data *hba_list = NULL;
-int hba_count = 0;
+int pci_hba_count = 0;
 
 /*
 ** parisc_pci_hba used by pci_port->in/out() ops to lookup bus data.
 */
 #define PCI_HBA_MAX 32
-static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
+struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
 
 
 /********************************************************************
@@ -58,24 +64,31 @@ static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
 **
 *********************************************************************/
 
-#define PCI_PORT_HBA(a) ((a)>>16)
-#define PCI_PORT_ADDR(a) ((a) & 0xffffUL)
+/* EISA port numbers and PCI port numbers share the same interface.  Some
+ * machines have both EISA and PCI adapters installed.  Rather than turn
+ * pci_port into an array, we reserve bus 0 for EISA and call the EISA
+ * routines if the access is to a port on bus 0.  We don't want to fix
+ * EISA and ISA drivers which assume port space is <= 0xffff.
+ */
 
-/* KLUGE : inb needs to be defined differently for PCI devices than
-** for other bus interfaces. Doing this at runtime sucks but is the
-** only way one driver binary can support devices on different bus types.
-**
-*/
+#ifdef CONFIG_EISA
+#define EISA_IN(size) if (EISA_bus && (b == 0)) return eisa_in##size(addr)
+#define EISA_OUT(size) if (EISA_bus && (b == 0)) return eisa_out##size(d, addr)
+#else
+#define EISA_IN(size)
+#define EISA_OUT(size)
+#endif
 
 #define PCI_PORT_IN(type, size) \
 u##size in##type (int addr) \
 { \
        int b = PCI_PORT_HBA(addr); \
        u##size d = (u##size) -1; \
+       EISA_IN(size); \
        ASSERT(pci_port); /* make sure services are defined */ \
        ASSERT(parisc_pci_hba[b]); /* make sure ioaddr are "fixed up" */ \
        if (parisc_pci_hba[b] == NULL) { \
-               printk(KERN_WARNING "\nPCI Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \
+               printk(KERN_WARNING "\nPCI or EISA Host Bus Adapter %d not registered. in" #size "(0x%x) returning -1\n", b, addr); \
        } else { \
                d = pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \
        } \
@@ -91,6 +104,7 @@ PCI_PORT_IN(l, 32)
 void out##type (u##size d, int addr) \
 { \
        int b = PCI_PORT_HBA(addr); \
+       EISA_OUT(size); \
        ASSERT(pci_port); \
        pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \
 }
@@ -104,18 +118,17 @@ PCI_PORT_OUT(l, 32)
 /*
  * BIOS32 replacement.
  */
-void pcibios_init(void)
+static int __init pcibios_init(void)
 {
-       ASSERT(pci_bios != NULL);
+       if (!pci_bios)
+               return -1;
 
-       if (pci_bios)
-       {
-               if (pci_bios->init) {
-                       (*pci_bios->init)();
-               } else {
-                       printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
-               }
+       if (pci_bios->init) {
+               pci_bios->init();
+       } else {
+               printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
        }
+       return 0;
 }
 
 
@@ -124,17 +137,10 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 {
        ASSERT(pci_bios != NULL);
 
-        /* If this is a bridge, get the current bases */
-       if (bus->self) {
-               pci_read_bridge_bases(bus);
-       }
-
-       if (pci_bios) {
-               if (pci_bios->fixup_bus) {
-                       (*pci_bios->fixup_bus)(bus);
-               } else {
-                       printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
-               }
+       if (pci_bios->fixup_bus) {
+               pci_bios->fixup_bus(bus);
+       } else {
+               printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
        }
 }
 
@@ -144,14 +150,6 @@ char *pcibios_setup(char *str)
        return str;
 }
 
-#endif /* defined(CONFIG_PCI) */
-
-
-
-/* -------------------------------------------------------------------
-** linux-2.4: NEW STUFF 
-** --------------------
-*/
 
 /*
 ** Used in drivers/pci/quirks.c
@@ -201,19 +199,11 @@ void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
 ** ------------------------------------
 ** PAT PDC systems need this routine. PA legacy PDC does not.
 **
-** Used by alpha/arm: 
-** alpha/kernel/pci.c:common_init_pci()
-** (or arm/kernel/pci.c:pcibios_init())
-**    drivers/pci/setup.c:pci_assign_unassigned_resources()
-**        drivers/pci/setup.c:pdev_assign_unassigned_resources()
-**            arch/<foo>/kernel/pci.c:pcibios_update_resource()
+** When BAR's are configured by linux, this routine will update
+** configuration space with the "normalized" address. "root" indicates
+** where the range starts and res is some portion of that range.
 **
-** When BAR's are configured by linux, this routine
-** will update configuration space with the "normalized"
-** address. "root" indicates where the range starts and res
-** is some portion of that range.
-**
-** For all PA-RISC systems except V-class, root->start would be zero.
+** VCLASS: For all PA-RISC systems except V-class, root->start would be zero.
 **
 ** PAT PDC can tell us which MMIO ranges are available or already in use.
 ** I/O port space and such are not memory mapped anyway for PA-Risc.
@@ -234,7 +224,7 @@ pcibios_update_resource(
                barnum, res->start, res->end, (int) res->flags);
 
        if (barnum >= PCI_BRIDGE_RESOURCES) {
-               /* handled in pbus_set_ranges_data() */
+               /* handled in PCI-PCI bridge specific support */
                return;
        }
 
@@ -248,8 +238,7 @@ pcibios_update_resource(
        if (res->flags & IORESOURCE_IO) {
                barval = PCI_PORT_ADDR(res->start);
        } else if (res->flags & IORESOURCE_MEM) {
-               /* This should work for VCLASS too */
-               barval = res->start & 0xffffffffUL;
+               barval = PCI_BUS_ADDR(HBA_DATA(dev->bus->sysdata), res->start);
        } else {
                panic("pcibios_update_resource() WTF? flags not IO or MEM");
        }
@@ -267,7 +256,7 @@ pcibios_update_resource(
            == (PCI_BASE_ADDRESS_SPACE_MEMORY
                | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
                pci_write_config_dword(dev, where+4, 0);
-               printk(KERN_WARNING "PCI: dev %s type 64-bit\n", dev->name);
+               DBGC("PCIBIOS: dev %s type 64-bit\n", dev->name);
        }
 }
 
@@ -290,25 +279,79 @@ void
 pcibios_set_master(struct pci_dev *dev)
 {
        u8 lat;
+
+       /* If someone already mucked with this, don't touch it. */
        pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
        if (lat >= 16) return;
 
        /*
        ** HP generally has fewer devices on the bus than other architectures.
+       ** upper byte is PCI_LATENCY_TIMER.
        */
-       printk("PCIBIOS: Setting latency timer of %s to 128\n", dev->slot_name);
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+        pci_write_config_word(dev, PCI_CACHE_LINE_SIZE,
+                               (0x80 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
 }
 
 
+void __init
+pcibios_init_bus(struct pci_bus *bus)
+{
+       struct pci_dev *dev = bus->self;
+
+       /* We deal only with pci controllers and pci-pci bridges. */
+       if (dev && (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+               return;
+       
+       if (dev) {
+               unsigned short bridge_ctl;
+
+               /* PCI-PCI bridge - set the cache line and default latency
+                  (32) for primary and secondary buses. */
+               pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
+
+               /* Read bridge control */
+               pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bridge_ctl);
+               pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl
+                               | PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR);
+
+       }
+}
+
+
+/*
+** KLUGE: Link the child and parent resources - generic PCI didn't
+*/
+static void
+pcibios_link_hba_resources( struct resource *hba_res, struct resource *r)
+{
+       if (!r->parent) {
+               r->parent = hba_res;
+
+               /* reverse link is harder *sigh*  */
+               if (r->parent->child) {
+                       if (r->parent->sibling) {
+                               struct resource *next = r->parent->sibling;
+                               while (next->sibling)
+                                        next = next->sibling;
+                               next->sibling = r;
+                       } else {
+                               r->parent->sibling = r;
+                       }
+               } else
+                       r->parent->child = r;
+       }
+}
+
 /*
-** called by drivers/pci/setup-res.c:pbus_set_ranges().
+** called by drivers/pci/setup-res.c:pci_setup_bridge().
 */
 void pcibios_fixup_pbus_ranges(
        struct pci_bus *bus,
        struct pbus_set_ranges_data *ranges
        )
 {
+       struct pci_hba_data *hba = HBA_DATA(bus->sysdata);
+
        /*
        ** I/O space may see busnumbers here. Something
        ** in the form of 0xbbxxxx where bb is the bus num
@@ -319,9 +362,20 @@ void pcibios_fixup_pbus_ranges(
        ranges->io_start = PCI_PORT_ADDR(ranges->io_start);
        ranges->io_end   = PCI_PORT_ADDR(ranges->io_end);
 
+       /* Convert MMIO addr to PCI addr (undo global virtualization) */
+       ranges->mem_start = PCI_BUS_ADDR(hba, ranges->mem_start);
+       ranges->mem_end   = PCI_BUS_ADDR(hba, ranges->mem_end);
+
        DBG_RES("pcibios_fixup_pbus_ranges(%02x, [%lx,%lx %lx,%lx])\n", bus->number,
                ranges->io_start, ranges->io_end,
                ranges->mem_start, ranges->mem_end);
+
+       /* KLUGE ALERT
+       ** if this resource isn't linked to a "parent", then it seems
+       ** to be a child of the HBA - lets link it in.
+       */
+       pcibios_link_hba_resources(&hba->io_space, bus->resource[0]);
+       pcibios_link_hba_resources(&hba->lmmio_space, bus->resource[1]);
 }
 
 #define MAX(val1, val2)   ((val1) > (val2) ? (val1) : (val2))
@@ -355,114 +409,22 @@ pcibios_align_resource(void *data, struct resource *res,
        align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
 
        /* Align to largest of MIN or input size */
-       mask = MAX(size, align) - 1;
+       mask = MAX(alignment, align) - 1;
        res->start += mask;
        res->start &= ~mask;
 
        /*
        ** WARNING : caller is expected to update "end" field.
        ** We can't since it might really represent the *size*.
-       ** The difference is "end = start + size" vs "end += size".
+       ** The difference is "end = start + size" vs "end += start".
        */
 }
 
 
-#define ROUND_UP(x, a)         (((x) + (a) - 1) & ~((a) - 1))
-
-void __devinit
-pcibios_size_bridge(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
-{
-       struct pbus_set_ranges_data inner;
-       struct pci_dev *dev;
-       struct pci_dev *bridge = bus->self;
-       struct list_head *ln;
-
-       /* set reasonable default "window" for pcibios_align_resource */
-       inner.io_start  = inner.io_end  = 0;
-       inner.mem_start = inner.mem_end = 0;
-
-       /* Collect information about how our direct children are layed out. */
-       for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-               int i;
-               dev = pci_dev_b(ln);
-
-               /* Skip bridges here - we'll catch them below */
-               if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
-                       continue;
-
-               for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-                       struct resource res;
-                       unsigned long size;
-
-                       if (dev->resource[i].flags == 0)
-                               continue;
-
-                       memcpy(&res, &dev->resource[i], sizeof(res));
-                       size = res.end - res.start + 1;
-
-                       if (res.flags & IORESOURCE_IO) {
-                               res.start = inner.io_end;
-                               pcibios_align_resource(dev, &res, size, 0);
-                               inner.io_end += res.start + size;
-                       } else if (res.flags & IORESOURCE_MEM) {
-                               res.start = inner.mem_end;
-                               pcibios_align_resource(dev, &res, size, 0);
-                               inner.mem_end = res.start + size;
-                       }
-
-               DBG_RES("    %s  inner size %lx/%x IO %lx MEM %lx\n",
-                       dev->slot_name,
-                       size, res.flags, inner.io_end, inner.mem_end);
-               }
-       }
-
-       /* And for all of the subordinate busses. */
-       for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
-               pcibios_size_bridge(pci_bus_b(ln), &inner);
-
-       /* turn the ending locations into sizes (subtract start) */
-       inner.io_end -= inner.io_start - 1;
-       inner.mem_end -= inner.mem_start - 1;
-
-       /* Align the sizes up by bridge rules */
-       inner.io_end = ROUND_UP(inner.io_end, 4*1024) - 1;
-       inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024) - 1;
-
-       /* PPB - PCI bridge Device will normaller also have "outer" != NULL. */
-       if (bridge) {
-               /* Adjust the bus' allocation requirements */
-               /* PPB's pci device Bridge resources */
-
-               bus->resource[0] = &bridge->resource[PCI_BRIDGE_RESOURCES];
-               bus->resource[1] = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
-               
-               bus->resource[0]->start = bus->resource[1]->start  = 0;
-               bus->resource[0]->parent= bus->resource[1]->parent = NULL;
-
-               bus->resource[0]->end    = inner.io_end;
-               bus->resource[0]->flags  = IORESOURCE_IO;
-
-               bus->resource[1]->end    = inner.mem_end;
-               bus->resource[1]->flags  = IORESOURCE_MEM;
-       }
-
-       /* adjust parent's resource requirements */
-       if (outer) {
-               outer->io_end = ROUND_UP(outer->io_end, 4*1024);
-               outer->io_end += inner.io_end;
-
-               outer->mem_end = ROUND_UP(outer->mem_end, 1*1024*1024);
-               outer->mem_end += inner.mem_end;
-       }
-}
-
-#undef ROUND_UP
-
-
 int __devinit
-pcibios_enable_device(struct pci_dev *dev)
+pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-       u16 cmd, old_cmd;
+       u16 cmd;
        int idx;
 
        /*
@@ -470,13 +432,19 @@ pcibios_enable_device(struct pci_dev *dev)
        ** enable all the same bits. We just make sure they are here.
        */
        pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       old_cmd = cmd;
 
        /*
        ** See if any resources have been allocated
+       ** While "regular" PCI devices only use 0-5, Bridges use a few
+       ** beyond that for window registers.
        */
-        for (idx=0; idx<6; idx++) {
+        for (idx=0; idx<DEVICE_COUNT_RESOURCE; idx++) {
                struct resource *r = &dev->resource[idx];
+
+               /* only setup requested resources */
+               if (!(mask & (1<<idx)))
+                       continue;
+
                if (r->flags & IORESOURCE_IO)
                        cmd |= PCI_COMMAND_IO;
                if (r->flags & IORESOURCE_MEM)
@@ -484,7 +452,7 @@ pcibios_enable_device(struct pci_dev *dev)
        }
 
        /*
-       ** System error and Parity Error reporting are enabled by default.
+       ** Enable System error and Parity Error reporting by default.
        ** Devices that do NOT want those behaviors should clear them
        ** (eg PCI graphics, possibly networking).
        ** Interfaces like SCSI certainly should not. We want the
@@ -493,30 +461,48 @@ pcibios_enable_device(struct pci_dev *dev)
        */
        cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
 
-       if (cmd != old_cmd) {
-               printk("PCIBIOS: Enabling device %s (%04x -> %04x)\n",
-                       dev->slot_name, old_cmd, cmd);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-       }
-
+#if 0
+       /* If bridge/bus controller has FBB enabled, child must too. */
+       if (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_FAST_BACK)
+               cmd |= PCI_COMMAND_FAST_BACK;
+#endif
+       DBGC("PCIBIOS: Enabling device %s cmd 0x%04x\n", dev->slot_name, cmd);
+       pci_write_config_word(dev, PCI_COMMAND, cmd);
        return 0;
 }
 
-
-void __devinit
-pcibios_assign_unassigned_resources(struct pci_bus *bus)
+void __init
+pcibios_setup_host_bridge(struct pci_bus *bus)
 {
-       struct list_head *ln;
+       ASSERT(pci_bios != NULL);
 
-        for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next)
+#if 0
+       if (pci_bios)
        {
-               pdev_assign_unassigned_resources(pci_dev_b(ln));
+               if (pci_bios->setup_host_bridge) {
+                       (*pci_bios->setup_host_bridge)(bus);
+               }
        }
+#endif
+}
+
+
+/*
+** Mostly copied from drivers/pci/setup-bus.c:pci_assign_unassigned_resources()
+*/
+void __devinit
+pcibios_assign_unassigned_resources(struct pci_bus *bus)
+{
+       /* from drivers/pci/setup-bus.c */
+       extern void pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges);
 
-        /* And for all of the sub-busses.  */
-       for (ln=bus->children.next; ln != &bus->children; ln=ln->next)
-               pcibios_assign_unassigned_resources(pci_bus_b(ln));
+       struct pbus_set_ranges_data ranges;
 
+       ranges.io_end = ranges.io_start
+                               = bus->resource[0]->start + PCIBIOS_MIN_IO;
+       ranges.mem_end = ranges.mem_start
+                               = bus->resource[1]->start + PCIBIOS_MIN_MEM;
+       pbus_assign_resources(bus, &ranges);
 }
 
 /*
@@ -524,14 +510,11 @@ pcibios_assign_unassigned_resources(struct pci_bus *bus)
 */
 void pcibios_register_hba(struct pci_hba_data *hba)
 {
-       hba->next = hba_list;
-       hba_list = hba;
-
-       ASSERT(hba_count < PCI_HBA_MAX);
+       ASSERT(pci_hba_count < PCI_HBA_MAX);
 
-       /*
-       ** pci_port->in/out() uses parisc_pci_hba to lookup parameter.
-       */
-       parisc_pci_hba[hba_count] = hba;
-       hba->hba_num = hba_count++;
+       /* pci_port->in/out() uses parisc_pci_hba to lookup parameter. */
+       parisc_pci_hba[pci_hba_count] = hba;
+       hba->hba_num = pci_hba_count++;
 }
+
+subsys_initcall(pcibios_init);
diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c
new file mode 100644 (file)
index 0000000..b0e4518
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *             arch/parisc/kernel/pdc_chassis.c
+ *
+ *             Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ *             Copyright (C) 2002 Thibaut Varene <varenet@esiee.fr>
+ *
+ *
+ *             This program is free software; you can redistribute it and/or modify
+ *             it under the terms of the GNU General Public License as published by
+ *             the Free Software Foundation; either version 2, or (at your option)
+ *             any later version.
+ *      
+ *             This program is distributed in the hope that it will be useful,
+ *             but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *             GNU General Public License for more details.
+ *      
+ *             You should have received a copy of the GNU General Public License
+ *             along with this program; if not, write to the Free Software
+ *             Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef PDC_CHASSIS_DEBUG
+#ifdef PDC_CHASSIS_DEBUG
+#define DPRINTK(fmt, args...)  printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+
+#include <asm/pdc_chassis.h>
+#include <asm/processor.h>
+
+static int pdc_chassis_old = 0;        
+
+
+/** 
+ * pdc_chassis_checkold() - Checks for old PDC_CHASSIS compatibility
+ * @pdc_chassis_old: 1 if old pdc chassis style
+ * 
+ * Currently, only E class and A180 are known to work with this.
+ * Inspired by Christoph Plattner
+ */
+
+static void __init pdc_chassis_checkold(void)
+{
+       switch(CPU_HVERSION) {
+               case 0x480:             /* E25 */
+               case 0x481:             /* E35 */
+               case 0x482:             /* E45 */
+               case 0x483:             /* E55 */
+               case 0x516:             /* A180 */
+                       pdc_chassis_old = 1;
+                       break;
+
+               default:
+                       break;
+       }
+       DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
+}
+
+
+/**
+ * pdc_chassis_panic_event() - Called by the panic handler.
+ *
+ * As soon as a panic occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_panic_event(struct notifier_block *this,
+                       unsigned long event, void *ptr)
+{
+       pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+               return NOTIFY_DONE;
+}   
+
+
+static struct notifier_block pdc_chassis_panic_block = {
+       notifier_call: pdc_chassis_panic_event,
+       priority: INT_MAX,
+};
+
+
+/**
+ * parisc_reboot_event() - Called by the reboot handler.
+ *
+ * As soon as a reboot occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_reboot_event(struct notifier_block *this,
+                       unsigned long event, void *ptr)
+{
+       pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+               return NOTIFY_DONE;
+}   
+
+
+static struct notifier_block pdc_chassis_reboot_block = {
+       notifier_call: pdc_chassis_reboot_event,
+       priority: INT_MAX,
+};
+
+
+/**
+ * parisc_pdc_chassis_init() - Called at boot time.
+ */
+
+void __init parisc_pdc_chassis_init(void)
+{
+       DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
+
+       /* initialize panic notifier chain */
+       notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block);
+
+       /* initialize reboot notifier chain */
+       register_reboot_notifier(&pdc_chassis_reboot_block);
+
+       /* Check for old LED Panel */
+       pdc_chassis_checkold();
+}
+
+
+/** 
+ * pdc_chassis_send_status() - Sends a predefined message to the chassis,
+ * and changes the front panel LEDs according to the new system state
+ * @retval: PDC call return value.
+ *
+ * Only machines with 64 bits PDC PAT and E-class are supported atm.
+ * 
+ * returns 0 if no error, -1 if no supported PDC is present or invalid message,
+ * else returns the appropriate PDC error code.
+ * 
+ * For a list of predefined messages, see asm-parisc/pdc_chassis.h
+ */
+
+int pdc_chassis_send_status(int message)
+{
+       /* Maybe we should do that in an other way ? */
+       int retval = 0;
+
+       DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message);
+
+#ifdef __LP64__        /* pdc_pat_chassis_send_log is defined only when #ifdef __LP64__ */
+       if (is_pdc_pat()) {
+               switch(message) {
+                       case PDC_CHASSIS_DIRECT_BSTART:
+                               retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BSTART, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+                               break;
+                       
+                       case PDC_CHASSIS_DIRECT_BCOMPLETE:
+                               retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BCOMPLETE, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+                               break;
+                       
+                       case PDC_CHASSIS_DIRECT_SHUTDOWN:
+                               retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_SHUTDOWN, PDC_CHASSIS_LSTATE_NONOS);
+                               break;
+                       
+                       case PDC_CHASSIS_DIRECT_PANIC:
+                               retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_PANIC, PDC_CHASSIS_LSTATE_RUN_CRASHREC);
+                               break;
+               
+                       case PDC_CHASSIS_DIRECT_LPMC:
+                               retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_LPMC, PDC_CHASSIS_LSTATE_RUN_SYSINT);
+                               break;
+
+                       case PDC_CHASSIS_DIRECT_HPMC:
+                               retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_HPMC, PDC_CHASSIS_LSTATE_RUN_NCRIT);
+                               break;
+
+                       default:
+                               retval = -1;
+               }
+       } else retval = -1;
+#else
+       if (pdc_chassis_old) {
+               switch (message) {
+                       case PDC_CHASSIS_DIRECT_BSTART:
+                       case PDC_CHASSIS_DIRECT_BCOMPLETE:
+                               retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
+                               break;
+                                                       
+                       case PDC_CHASSIS_DIRECT_SHUTDOWN:
+                               retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_SHUT));
+                               break;
+                       
+                       case PDC_CHASSIS_DIRECT_HPMC:
+                       case PDC_CHASSIS_DIRECT_PANIC:
+                               retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_FLT));
+                               break;
+               
+                       case PDC_CHASSIS_DIRECT_LPMC:
+                               retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_WARN));
+                               break;
+
+                       default:
+                               retval = -1;
+               }
+       } else retval = -1;
+#endif
+               
+       return retval;
+}
index e88ee40..264adf6 100644 (file)
+/*
+ *  linux/arch/parisc/kernel/pdc_console.c
+ *
+ *  The PDC console is a simple console, which can be used for debugging 
+ *  boot related problems on HP PA-RISC machines.
+ *
+ *  This code uses the ROM (=PDC) based functions to read and write characters
+ *  from and to PDC's boot path.
+ *  Since all character read from that path must be polled, this code never
+ *  can or will be a fully functional linux console.
+ */
+
+/* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. 
+ * On production kernels EARLY_BOOTUP_DEBUG should be undefined. */
+#undef EARLY_BOOTUP_DEBUG
+
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/major.h>
 #include <asm/page.h>
 #include <asm/types.h>
 #include <asm/system.h>
-#include <asm/pdc.h>   /* for iodc_call() proto and friends */
-#include <asm/real.h>
+#include <asm/pdc.h>           /* for iodc_call() proto and friends */
 
-static int __attribute__((aligned(8)))   iodc_retbuf[32];
-static char __attribute__((aligned(64))) iodc_dbuf[4096];
-
-/*
- * pdc_putc:
- * Console character print using IODC.
- *
- * Note that only these special chars are architected for console IODC io:
- * BEL, BS, CR, and LF. Others are passed through.
- * Since the HP console requires CR+LF to perform a 'newline', we translate
- * "\n" to "\r\n".
- */
-
-static int posx;       /* for simple TAB-Simulation... */
-
-/* XXX Should we spinlock posx usage */
-
-void pdc_putc(unsigned char c)
-{
-       unsigned int n;
-       unsigned long flags;
-
-       switch (c) {
-       case '\n':
-               iodc_dbuf[0] = '\r'; 
-               iodc_dbuf[1] = '\n';
-                       n = 2;
-                       posx = 0;
-               break;
-       case '\t':
-               pdc_putc(' ');
-               while (posx & 7)        /* expand TAB */
-                       pdc_putc(' ');
-               return;         /* return since IODC can't handle this */
-       case '\b':
-               posx-=2;                /* BS */
-       default:
-               iodc_dbuf[0] = c;
-               n = 1;
-               posx++;
-               break;
-       }
-       {
-               real32_call(PAGE0->mem_cons.iodc_io,
-                       (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
-                       PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
-                       __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
-       }
-}
 
 static void pdc_console_write(struct console *co, const char *s, unsigned count)
 {
        while(count--)
-               pdc_putc(*s++);
+               pdc_iodc_putc(*s++);
 }
 
-int pdc_console_wait_key(struct console *co)
+void pdc_outc(unsigned char c)
 {
-       int ch = 'X';
-       int status;
-
-       /* Bail if no console input device. */
-       if (!PAGE0->mem_kbd.iodc_io)
-               return 0;
-       
-       /* wait for a keyboard (rs232)-input */
-       do {
-               unsigned long flags;
-
-               save_flags(flags);
-               cli();
-               status = real32_call(PAGE0->mem_kbd.iodc_io,
-                       (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
-                       PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers),
-                       __pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
-               restore_flags(flags);
-               ch = *iodc_dbuf;        /* save the character directly to ch */
-       } while (*iodc_retbuf == 0);    /* wait for a key */
-       return ch;
+       pdc_iodc_outc(c);
 }
 
-int pdc_getc(void)
+
+int pdc_console_poll_key(struct console *co)
 {
-       return pdc_console_wait_key(NULL);
+       return pdc_iodc_getc();
 }
 
 static int pdc_console_setup(struct console *co, char *options)
@@ -102,17 +52,34 @@ static int pdc_console_setup(struct console *co, char *options)
        return 0;
 }
 
+#ifdef CONFIG_PDC_CONSOLE
+static kdev_t pdc_console_device (struct console *c)
+{
+        return mk_kdev(PDCCONS_MAJOR, 0);
+}
+#endif
+
+#ifdef CONFIG_PDC_CONSOLE
+#define PDC_CONSOLE_DEVICE pdc_console_device
+#else
+#define PDC_CONSOLE_DEVICE NULL
+#endif
+
 static struct console pdc_cons = {
        name:           "ttyB",
        write:          pdc_console_write,
+       device:         PDC_CONSOLE_DEVICE,
        setup:          pdc_console_setup,
-       flags:          CON_PRINTBUFFER|CON_ENABLED,  // |CON_CONSDEV,
+       flags:          CON_PRINTBUFFER|CON_ENABLED,
        index:          -1,
 };
 
 static int pdc_console_initialized;
+extern unsigned long con_start;        /* kernel/printk.c */
+extern unsigned long log_end;  /* kernel/printk.c */
 
-void pdc_console_init(void)
+
+static void pdc_console_init_force(void)
 {
        if (pdc_console_initialized)
                return;
@@ -122,23 +89,32 @@ void pdc_console_init(void)
        if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
                memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
 
-       pdc_console_write(0, "PDC Console Initialized\n", 24);
        /* register the pdc console */
        register_console(&pdc_cons);
 }
 
+void pdc_console_init(void)
+{
+#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
+       pdc_console_init_force();
+#endif
+#ifdef EARLY_BOOTUP_DEBUG
+       printk(KERN_INFO "Initialized PDC Console for debugging.\n");
+#endif
+}
+
 
 /* Unregister the pdc console with the printk console layer */
 void pdc_console_die(void)
 {
-       printk("Switching from PDC console\n");
        if (!pdc_console_initialized)
                return;
        --pdc_console_initialized;
-       
-#ifdef CONFIG_VT_CONSOLE
-       schedule_console_callback();
-#endif
+
+       printk(KERN_INFO "Switching from PDC console\n");
+
+       /* Don't repeat what we've already printed */
+       con_start = log_end;
 
        unregister_console(&pdc_cons);
 }
@@ -155,17 +131,17 @@ void pdc_console_die(void)
 void pdc_console_restart(void)
 {
        struct console *console;
-       extern int log_size;
 
        if (pdc_console_initialized)
                return;
 
-       while ((console = console_drivers) != (struct console *)0)
+       while ((console = console_drivers) != NULL)
                unregister_console(console_drivers);
 
-       log_size = 0;
-       pdc_console_init();
-       printk("Switched to PDC console\n");
-       return;
+       /* Don't repeat what we've already printed */
+       con_start = log_end;
+       
+       /* force registering the pdc console */
+       pdc_console_init_force();
 }
 
index fecfdd4..ce28318 100644 (file)
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/elf.h>
+#include <linux/personality.h>
 
 #include <asm/machdep.h>
-#include <asm/offset.h>
+#include <asm/offsets.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/gsc.h>
 #include <asm/processor.h>
+#include <asm/pdc_chassis.h>
 
-spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
+int hlt_counter;
 
-#ifdef __LP64__
-/* The 64-bit code should work equally well in 32-bit land but I didn't
- * want to take the time to confirm that.  -PB
- */
-extern unsigned int ret_from_kernel_thread;
-#else
-asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
-#endif
-
-
-int hlt_counter=0;
+/*
+ * Power off function, if any
+ */ 
+void (*pm_power_off)(void);
 
 void disable_hlt(void)
 {
@@ -60,6 +56,11 @@ void enable_hlt(void)
        hlt_counter--;
 }
 
+void default_idle(void)
+{
+       barrier();
+}
+
 /*
  * The idle thread. There's no useful work to be
  * done, so just try to conserve power and have a
@@ -69,9 +70,6 @@ void enable_hlt(void)
 void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
-       init_idle();
-       current->nice = 20;
-
        while (1) {
                while (!need_resched())
                        barrier();
@@ -80,35 +78,90 @@ void cpu_idle(void)
        }
 }
 
-void __init reboot_setup(char *str, int *ints)
-{
-}
 
-struct notifier_block *mach_notifier;
+#ifdef __LP64__
+#define COMMAND_GLOBAL  0xfffffffffffe0030UL
+#else
+#define COMMAND_GLOBAL  0xfffe0030
+#endif
 
-void machine_restart(char *ptr)
-{
-       notifier_call_chain(&mach_notifier, MACH_RESTART, ptr);
-}
+#define CMD_RESET       5       /* reset any module */
 
-void machine_halt(void)
+/*
+** The Wright Brothers and Gecko systems have a H/W problem
+** (Lasi...'nuf said) may cause a broadcast reset to lockup
+** the system. An HVERSION dependent PDC call was developed
+** to perform a "safe", platform specific broadcast reset instead
+** of kludging up all the code.
+**
+** Older machines which do not implement PDC_BROADCAST_RESET will
+** return (with an error) and the regular broadcast reset can be
+** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
+** the PDC call will not return (the system will be reset).
+*/
+void machine_restart(char *cmd)
 {
-       notifier_call_chain(&mach_notifier, MACH_HALT, NULL);
-}
+#ifdef FASTBOOT_SELFTEST_SUPPORT
+       /*
+        ** If user has modified the Firmware Selftest Bitmap,
+        ** run the tests specified in the bitmap after the
+        ** system is rebooted w/PDC_DO_RESET.
+        **
+        ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
+        **
+        ** Using "directed resets" at each processor with the MEM_TOC
+        ** vector cleared will also avoid running destructive
+        ** memory self tests. (Not implemented yet)
+        */
+       if (ftc_bitmap) {
+               pdc_do_firm_test_reset(ftc_bitmap);
+       }
+#endif
+       /* set up a new led state on systems shipped with a LED State panel */
+       pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+       
+       /* "Normal" system reset */
+       pdc_do_reset();
+
+       /* Nope...box should reset with just CMD_RESET now */
+       gsc_writel(CMD_RESET, COMMAND_GLOBAL);
+
+       /* Wait for RESET to lay us to rest. */
+       while (1) ;
 
-void machine_power_on(void)
-{
-       notifier_call_chain(&mach_notifier, MACH_POWER_ON, NULL);
 }
 
-void machine_power_off(void)
+void machine_halt(void)
 {
-       notifier_call_chain(&mach_notifier, MACH_POWER_OFF, NULL);
+       /*
+       ** The LED/ChassisCodes are updated by the led_halt()
+       ** function, called by the reboot notifier chain.
+       */
 }
 
 
-void machine_heartbeat(void)
+/*
+ * This routine is called from sys_reboot to actually turn off the
+ * machine 
+ */
+void machine_power_off(void)
 {
+       /* If there is a registered power off handler, call it. */
+       if(pm_power_off)
+               pm_power_off();
+
+       /* Put the soft power button back under hardware control.
+        * If the user had already pressed the power button, the
+        * following call will immediately power off. */
+       pdc_soft_power_button(0);
+       
+       pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+               
+       /* It seems we have no way to power the system off via
+        * software. The user has to press the button himself. */
+
+       printk(KERN_EMERG "System shut down completed.\n"
+              KERN_EMERG "Please power this system off now.");
 }
 
 
@@ -137,6 +190,9 @@ void exit_thread(void)
 
 void flush_thread(void)
 {
+       /* Only needs to handle fpu stuff or perf monitors.
+       ** REVISIT: several arches implement a "lazy fpu state".
+       */
        set_fs(USER_DS);
 }
 
@@ -147,6 +203,7 @@ void release_thread(struct task_struct *dead_task)
 /*
  * Fill in the FPU structure for a core dump.
  */
+
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r)
 {
        memcpy(r, regs->fr, sizeof *r);
@@ -160,7 +217,8 @@ sys_clone(unsigned long clone_flags, unsigned long usp,
          struct pt_regs *regs)
 {
        struct task_struct *p;
-       p = do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0);
+       int *user_tid = (int *)regs->gr[26];
+       p = do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0, user_tid);
        return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -168,7 +226,7 @@ int
 sys_vfork(struct pt_regs *regs)
 {
        struct task_struct *p;
-       p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0);
+       p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL);
        return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -178,7 +236,14 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
            struct task_struct * p, struct pt_regs * pregs)
 {
        struct pt_regs * cregs = &(p->thread.regs);
-       long ksp;
+       struct thread_info *ti = p->thread_info;
+       
+       /* We have to use void * instead of a function pointer, because
+        * function pointers aren't a pointer to the function on 64-bit.
+        * Make them const so the compiler knows they live in .text */
+       extern void * const ret_from_kernel_thread;
+       extern void * const child_return;
+       extern void * const hpux_child_return;
 
        *cregs = *pregs;
 
@@ -195,34 +260,37 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
         * in zero for usp.
         */
        if (usp == 0) {
-               /* Kernel Thread */
-               ksp = (((unsigned long)(p)) + TASK_SZ_ALGN);
-               cregs->ksp = ksp;           /* always return to kernel */
-#ifdef __LP64__
+               /* kernel thread */
+               cregs->ksp = (((unsigned long)(ti)) + THREAD_SZ_ALGN);
+               /* Must exit via ret_from_kernel_thread in order
+                * to call schedule_tail()
+                */
                cregs->kpc = (unsigned long) &ret_from_kernel_thread;
-#else
-               cregs->kpc = (unsigned long) ret_from_kernel_thread;
-#endif
-
                /*
                 * Copy function and argument to be called from
                 * ret_from_kernel_thread.
                 */
+#ifdef __LP64__
+               cregs->gr[27] = pregs->gr[27];
+#endif
                cregs->gr[26] = pregs->gr[26];
                cregs->gr[25] = pregs->gr[25];
-
        } else {
-               /* User Thread:
-                *
-                * Use same stack depth as parent when in wrapper
-                *
+               /* user thread */
+               /*
                 * Note that the fork wrappers are responsible
-                * for setting gr[20] and gr[21].
+                * for setting gr[21].
                 */
 
-               cregs->ksp = ((unsigned long)(p))
-                       + (pregs->gr[20] & (INIT_TASK_SIZE - 1));
-               cregs->kpc = pregs->gr[21];
+               /* Use same stack depth as parent */
+               cregs->ksp = ((unsigned long)(ti))
+                       + (pregs->gr[21] & (INIT_THREAD_SIZE - 1));
+               cregs->gr[30] = usp;
+               if (p->personality == PER_HPUX) {
+                       cregs->kpc = (unsigned long) &hpux_child_return;
+               } else {
+                       cregs->kpc = (unsigned long) &child_return;
+               }
        }
 
        return 0;
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
new file mode 100644 (file)
index 0000000..254a082
--- /dev/null
@@ -0,0 +1,374 @@
+/*    $Id: processor.c,v 1.1 2002/07/20 16:27:06 rhirst Exp $
+ *
+ *    Initial setup-routines for HP 9000 based hardware.
+ *
+ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *    Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de>
+ *    Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
+ *    Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
+ *    Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *    Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
+ *
+ *    Initial PA-RISC Version: 04-23-1999 by Helge Deller
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#define PCI_DEBUG
+#include <linux/pci.h>
+#undef PCI_DEBUG
+
+#include <asm/cache.h>
+#include <asm/hardware.h>      /* for register_parisc_driver() stuff */
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/irq.h>           /* for struct irq_region */
+
+struct system_cpuinfo_parisc boot_cpu_data;
+struct cpuinfo_parisc cpu_data[NR_CPUS];
+
+/*
+**     PARISC CPU driver - claim "device" and initialize CPU data structures.
+**
+** Consolidate per CPU initialization into (mostly) one module.
+** Monarch CPU will initialize boot_cpu_data which shouldn't
+** change once the system has booted.
+**
+** The callback *should* do per-instance initialization of
+** everything including the monarch. "Per CPU" init code in
+** setup.c:start_parisc() has migrated here and start_parisc()
+** will call register_parisc_driver(&cpu_driver) before calling do_inventory().
+**
+** The goal of consolidating CPU initialization into one place is
+** to make sure all CPU's get initialized the same way.
+** The code path not shared is how PDC hands control of the CPU to the OS.
+** The initialization of OS data structures is the same (done below).
+*/
+
+/**
+ * processor_probe - Determine if processor driver should claim this device.
+ * @dev: The device which has been found.
+ *
+ * Determine if processor driver should claim this chip (return 0) or not 
+ * (return 1).  If so, initialize the chip and tell other partners in crime 
+ * they have work to do.
+ */
+static int __init processor_probe(struct parisc_device *dev)
+{
+       unsigned long txn_addr;
+       unsigned long cpuid;
+       struct cpuinfo_parisc *p;
+
+#ifndef CONFIG_SMP
+       if (boot_cpu_data.cpu_count > 0) {
+               printk(KERN_INFO "CONFIG_SMP=n  ignoring additional CPUs\n");
+               return 1;
+       }
+#endif
+
+       /* logical CPU ID and update global counter
+        * May get overwritten by PAT code.
+        */
+       cpuid = boot_cpu_data.cpu_count;
+       txn_addr = dev->hpa;    /* for legacy PDC */
+
+#ifdef __LP64__
+       if (is_pdc_pat()) {
+               ulong status;
+               unsigned long bytecnt;
+               pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
+#undef USE_PAT_CPUID
+#ifdef USE_PAT_CPUID
+               struct pdc_pat_cpu_num cpu_info;
+#endif
+
+               status = pdc_pat_cell_module(&bytecnt, dev->pcell_loc,
+                       dev->mod_index, PA_VIEW, &pa_pdc_cell);
+
+               ASSERT(PDC_OK == status);
+
+               /* verify it's the same as what do_pat_inventory() found */
+               ASSERT(dev->mod_info == pa_pdc_cell.mod_info);
+               ASSERT(dev->pmod_loc == pa_pdc_cell.mod_location);
+
+               txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
+
+#ifdef USE_PAT_CPUID
+/* We need contiguous numbers for cpuid. Firmware's notion
+ * of cpuid is for physical CPUs and we just don't care yet.
+ * We'll care when we need to query PAT PDC about a CPU *after*
+ * boot time (ie shutdown a CPU from an OS perspective).
+ */
+               /* get the cpu number */
+               status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa);
+
+               ASSERT(PDC_OK == status);
+
+               if (cpu_info.cpu_num >= NR_CPUS) {
+                       printk(KERN_WARNING "IGNORING CPU at 0x%x,"
+                               " cpu_slot_id > NR_CPUS"
+                               " (%ld > %d)\n",
+                               dev->hpa, cpu_info.cpu_num, NR_CPUS);
+                       /* Ignore CPU since it will only crash */
+                       boot_cpu_data.cpu_count--;
+                       return 1;
+               } else {
+                       cpuid = cpu_info.cpu_num;
+               }
+#endif
+       }
+#endif
+
+       p = &cpu_data[cpuid];
+       boot_cpu_data.cpu_count++;
+
+       /* initialize counters */
+       memset(p, 0, sizeof(struct cpuinfo_parisc));
+
+       p->dev = dev;           /* Save IODC data in case we need it */
+       p->hpa = dev->hpa;      /* save CPU hpa */
+       p->cpuid = cpuid;       /* save CPU id */
+       p->txn_addr = txn_addr; /* save CPU IRQ address */
+#ifdef CONFIG_SMP
+       p->lock = SPIN_LOCK_UNLOCKED;
+
+       /*
+       ** FIXME: review if any other initialization is clobbered
+       **      for boot_cpu by the above memset().
+       */
+
+       /* stolen from init_percpu_prof() */
+       cpu_data[cpuid].prof_counter = 1;
+       cpu_data[cpuid].prof_multiplier = 1;
+#endif
+
+       /*
+       ** CONFIG_SMP: init_smp_config() will attempt to get CPU's into
+       ** OS control. RENDEZVOUS is the default state - see mem_set above.
+       **      p->state = STATE_RENDEZVOUS;
+       */
+
+       /*
+       ** itimer and ipi IRQ handlers are statically initialized in
+       ** arch/parisc/kernel/irq.c. ie Don't need to register them.
+       */
+       p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+
+       return 0;
+}
+
+/**
+ * collect_boot_cpu_data - Fill the boot_cpu_data structure.
+ *
+ * This function collects and stores the generic processor information
+ * in the boot_cpu_data structure.
+ */
+void __init collect_boot_cpu_data(void)
+{
+       memset(&boot_cpu_data, 0, sizeof(boot_cpu_data));
+
+       boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
+
+       /* get CPU-Model Information... */
+#define p ((unsigned long *)&boot_cpu_data.pdc.model)
+       if (pdc_model_info(&boot_cpu_data.pdc.model) == PDC_OK)
+               printk(KERN_INFO 
+                       "model %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+                       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
+#undef p
+
+       if (pdc_model_versions(&boot_cpu_data.pdc.versions, 0) == PDC_OK)
+               printk(KERN_INFO "vers  %08lx\n", 
+                       boot_cpu_data.pdc.versions);
+
+       if (pdc_model_cpuid(&boot_cpu_data.pdc.cpuid) == PDC_OK)
+               printk(KERN_INFO "CPUID vers %ld rev %ld (0x%08lx)\n",
+                       (boot_cpu_data.pdc.cpuid >> 5) & 127,
+                       boot_cpu_data.pdc.cpuid & 31,
+                       boot_cpu_data.pdc.cpuid);
+
+       if (pdc_model_capabilities(&boot_cpu_data.pdc.capabilities) == PDC_OK)
+               printk(KERN_INFO "capabilities 0x%lx\n",
+                       boot_cpu_data.pdc.capabilities);
+
+       if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name) == PDC_OK)
+               printk(KERN_INFO "model %s\n",
+                       boot_cpu_data.pdc.sys_model_name);
+
+       boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
+       boot_cpu_data.sversion =  boot_cpu_data.pdc.model.sversion;
+
+       boot_cpu_data.cpu_type =
+                       parisc_get_cpu_type(boot_cpu_data.hversion);
+
+       boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
+       boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
+}
+
+
+/**
+ * init_cpu_profiler - enable/setup per cpu profiling hooks.
+ * @cpunum: The processor instance.
+ *
+ * FIXME: doesn't do much yet...
+ */
+static inline void __init
+init_percpu_prof(int cpunum)
+{
+       cpu_data[cpunum].prof_counter = 1;
+       cpu_data[cpunum].prof_multiplier = 1;
+}
+
+
+/**
+ * init_per_cpu - Handle individual processor initializations.
+ * @cpunum: logical processor number.
+ *
+ * This function handles initialization for *every* CPU
+ * in the system:
+ *
+ * o Set "default" CPU width for trap handlers
+ *
+ * o Enable FP coprocessor
+ *   REVISIT: this could be done in the "code 22" trap handler.
+ *     (frowands idea - that way we know which processes need FP
+ *     registers saved on the interrupt stack.)
+ *   NEWS FLASH: wide kernels need FP coprocessor enabled to handle
+ *     formatted printing of %lx for example (double divides I think)
+ *
+ * o Enable CPU profiling hooks.
+ */
+int __init init_per_cpu(int cpunum)
+{
+       int ret;
+       struct pdc_coproc_cfg coproc_cfg;
+
+       ret = pdc_coproc_cfg(&coproc_cfg);
+
+       if(ret >= 0 && coproc_cfg.ccr_functional) {
+               mtctl(coproc_cfg.ccr_functional, 10);  /* 10 == Coprocessor Control Reg */
+
+               /* FWIW, FP rev/model is a more accurate way to determine
+               ** CPU type. CPU rev/model has some ambiguous cases.
+               */
+               cpu_data[cpunum].fp_rev = coproc_cfg.revision;
+               cpu_data[cpunum].fp_model = coproc_cfg.model;
+
+               printk(KERN_INFO  "FP[%d] enabled: Rev %ld Model %ld\n",
+                       cpunum, coproc_cfg.revision, coproc_cfg.model);
+
+               /*
+               ** store status register to stack (hopefully aligned)
+               ** and clear the T-bit.
+               */
+               asm volatile ("fstd    %fr0,8(%sp)");
+
+       } else {
+               printk(KERN_WARNING  "WARNING: No FP CoProcessor?!"
+                       " (coproc_cfg.ccr_functional == 0x%lx, expected 0xc0)\n"
+#ifdef __LP64__
+                       "Halting Machine - FP required\n"
+#endif
+                       , coproc_cfg.ccr_functional);
+#ifdef __LP64__
+               mdelay(100);    /* previous chars get pushed to console */
+               panic("FP CoProc not reported");
+#endif
+       }
+
+       /* FUTURE: Enable Performance Monitor : ccr bit 0x20 */
+       init_percpu_prof(cpunum);
+
+       return ret;
+}
+
+/*
+ * Display cpu info for all cpu's.
+ */
+int
+show_cpuinfo (struct seq_file *m, void *v)
+{
+       int     n;
+
+       for(n=0; n<boot_cpu_data.cpu_count; n++) {
+#ifdef CONFIG_SMP
+               if (0 == cpu_data[n].hpa)
+                       continue;
+#ifdef ENTRY_SYS_CPUS
+#error iCOD support wants to show CPU state here
+#endif
+#endif
+               seq_printf(m, "processor\t: %d\n"
+                               "cpu family\t: PA-RISC %s\n",
+                                n, boot_cpu_data.family_name);
+
+               seq_printf(m, "cpu\t\t: %s\n",  boot_cpu_data.cpu_name );
+
+               /* cpu MHz */
+               seq_printf(m, "cpu MHz\t\t: %d.%06d\n",
+                                boot_cpu_data.cpu_hz / 1000000,
+                                boot_cpu_data.cpu_hz % 1000000  );
+
+               seq_printf(m, "model\t\t: %s\n"
+                               "model name\t: %s\n",
+                                boot_cpu_data.pdc.sys_model_name,
+                                cpu_data[n].dev ? 
+                                cpu_data[n].dev->name : "Unknown" );
+
+               seq_printf(m, "hversion\t: 0x%08x\n"
+                               "sversion\t: 0x%08x\n",
+                                boot_cpu_data.hversion,
+                                boot_cpu_data.sversion );
+
+               /* print cachesize info */
+               show_cache_info(m);
+
+               seq_printf(m, "bogomips\t: %lu.%02lu\n",
+                            loops_per_jiffy / (500000 / HZ),
+                            (loops_per_jiffy / (5000 / HZ)) % 100);
+
+               seq_printf(m, "software id\t: %ld\n\n",
+                               boot_cpu_data.pdc.model.sw_id);
+       }
+       return 0;
+}
+
+static struct parisc_device_id processor_tbl[] = {
+       { HPHW_NPROC, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, SVERSION_ANY_ID },
+       { 0, }
+};
+
+static struct parisc_driver cpu_driver = {
+       name:           "CPU",
+       id_table:       processor_tbl,
+       probe:          processor_probe
+};
+
+/**
+ * processor_init - Processor initalization procedure.
+ *
+ * Register this driver.
+ */
+void __init processor_init(void)
+{
+       register_parisc_driver(&cpu_driver);
+}
index d44e023..7cc6d20 100644 (file)
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/processor.h>
-#include <asm/offset.h>
+#include <asm/offsets.h>
 
 /* These are used in entry.S, syscall_restore_rfi.  We need to record the
  * current stepping mode somewhere other than in PSW, because there is no
 #define PT_SINGLESTEP  0x10000
 #define PT_BLOCKSTEP   0x20000
 
+/* PSW bits we allow the debugger to modify */
+#define USER_PSW_BITS  (PSW_N | PSW_V | PSW_CB)
+
+#undef DEBUG_PTRACE
+
+#ifdef DEBUG_PTRACE
+#define DBG(x) printk x
+#else
+#define DBG(x)
+#endif
+
+#ifdef __LP64__
+
+#define CHILD_IS_32BIT (child->personality == PER_LINUX_32BIT)
+
+/* This function is needed to translate 32 bit pt_regs offsets in to
+ * 64 bit pt_regs offsets.  For example, a 32 bit gdb under a 64 bit kernel
+ * will request offset 12 if it wants gr3, but the lower 32 bits of
+ * the 64 bit kernels view of gr3 will be at offset 28 (3*8 + 4).
+ * This code relies on a 32 bit pt_regs being comprised of 32 bit values
+ * except for the fp registers which (a) are 64 bits, and (b) follow
+ * the gr registers at the start of pt_regs.  The 32 bit pt_regs should
+ * be half the size of the 64 bit pt_regs, plus 32*4 to allow for fr[]
+ * being 64 bit in both cases.
+ */
+
+static long translate_usr_offset(long offset)
+{
+       if (offset < 0)
+               return -1;
+       else if (offset <= 32*4)        /* gr[0..31] */
+               return offset * 2 + 4;
+       else if (offset <= 32*4+32*8)   /* gr[0..31] + fr[0..31] */
+               return offset + 32*4;
+       else if (offset < sizeof(struct pt_regs)/2 + 32*4)
+               return offset * 2 + 4 - 32*8;
+       else
+               return -1;
+}
+#endif
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -49,6 +91,9 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
 {
        struct task_struct *child;
        long ret;
+#ifdef DEBUG_PTRACE
+       long oaddr=addr, odata=data;
+#endif
 
        lock_kernel();
        ret = -EPERM;
@@ -78,27 +123,41 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
                ret = ptrace_attach(child);
                goto out_tsk;
        }
-       ret = -ESRCH;
-       if (!(child->ptrace & PT_PTRACED))
-               goto out_tsk;
-       if (child->state != TASK_STOPPED) {
-               if (request != PTRACE_KILL)
-                       goto out_tsk;
-       }
-       if (child->p_pptr != current)
+
+       ret = ptrace_check_attach(child, request == PTRACE_KILL);
+       if (ret < 0)
                goto out_tsk;
 
        switch (request) {
        case PTRACE_PEEKTEXT: /* read word at location addr. */ 
        case PTRACE_PEEKDATA: {
-               unsigned long tmp;
                int copied;
 
-               copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-               ret = -EIO;
-               if (copied != sizeof(tmp))
-                       goto out_tsk;
-               ret = put_user(tmp,(unsigned long *) data);
+#ifdef __LP64__
+               if (CHILD_IS_32BIT) {
+                       unsigned int tmp;
+
+                       addr &= 0xffffffffL;
+                       copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+                       ret = -EIO;
+                       if (copied != sizeof(tmp))
+                               goto out_tsk;
+                       ret = put_user(tmp,(unsigned int *) data);
+                       DBG(("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
+                               request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
+                               pid, oaddr, odata, ret, tmp));
+               }
+               else
+#endif
+               {
+                       unsigned long tmp;
+
+                       copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+                       ret = -EIO;
+                       if (copied != sizeof(tmp))
+                               goto out_tsk;
+                       ret = put_user(tmp,(unsigned long *) data);
+               }
                goto out_tsk;
        }
 
@@ -106,22 +165,53 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
        case PTRACE_POKETEXT: /* write the word at location addr. */
        case PTRACE_POKEDATA:
                ret = 0;
-               if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-                       goto out_tsk;
+#ifdef __LP64__
+               if (CHILD_IS_32BIT) {
+                       unsigned int tmp = (unsigned int)data;
+                       DBG(("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
+                               request == PTRACE_POKETEXT ? "TEXT" : "DATA",
+                               pid, oaddr, odata));
+                       addr &= 0xffffffffL;
+                       if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
+                               goto out_tsk;
+               }
+               else
+#endif
+               {
+                       if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+                               goto out_tsk;
+               }
                ret = -EIO;
                goto out_tsk;
 
-       /* Read the word at location addr in the USER area.  This will need
-          to change when the kernel no longer saves all regs on a syscall. */
+       /* Read the word at location addr in the USER area.  For ptraced
+          processes, the kernel saves all regs on a syscall. */
        case PTRACE_PEEKUSR: {
-               unsigned long tmp;
-
                ret = -EIO;
-               if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
-                       goto out_tsk;
+#ifdef __LP64__
+               if (CHILD_IS_32BIT) {
+                       unsigned int tmp;
 
-               tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
-               ret = put_user(tmp, (unsigned long *) data);
+                       if (addr & (sizeof(int)-1))
+                               goto out_tsk;
+                       if ((addr = translate_usr_offset(addr)) < 0)
+                               goto out_tsk;
+
+                       tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
+                       ret = put_user(tmp, (unsigned int *) data);
+                       DBG(("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
+                               pid, oaddr, odata, ret, addr, tmp));
+               }
+               else
+#endif
+               {
+                       unsigned long tmp;
+
+                       if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
+                               goto out_tsk;
+                       tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
+                       ret = put_user(tmp, (unsigned long *) data);
+               }
                goto out_tsk;
        }
 
@@ -133,32 +223,81 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
           exit. */
        case PTRACE_POKEUSR:
                ret = -EIO;
-               if ((addr & 3) || (unsigned long) addr >= sizeof(struct pt_regs))
-                       goto out_tsk;
-               /* XXX This test probably needs adjusting.  We probably want to
-                * allow writes to some bits of PSW, and may want to block writes
-                * to (some) space registers.  Some register values written here
-                * may be ignored in entry.S:syscall_restore_rfi; e.g. iaoq is
-                * written with r31/r31+4, and not with the values in pt_regs.
+               /* Some register values written here may be ignored in
+                * entry.S:syscall_restore_rfi; e.g. iaoq is written with
+                * r31/r31+4, and not with the values in pt_regs.
+                */
+                /* PT_PSW=0, so this is valid for 32 bit processes under 64
+                * bit kernels.
                 */
-               /* Allow writing of gr1-gr31, fr*, sr*, iasq*, iaoq*, sar */
-               if (addr == PT_PSW || (addr > PT_IAOQ1 && addr != PT_SAR))
+               if (addr == PT_PSW) {
+                       /* PT_PSW=0, so this is valid for 32 bit processes
+                        * under 64 bit kernels.
+                        *
+                        * Allow writing to Nullify, Divide-step-correction,
+                        * and carry/borrow bits.
+                        * BEWARE, if you set N, and then single step, it wont
+                        * stop on the nullified instruction.
+                        */
+                       DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx)\n",
+                               pid, oaddr, odata));
+                       data &= USER_PSW_BITS;
+                       task_regs(child)->gr[0] &= ~USER_PSW_BITS;
+                       task_regs(child)->gr[0] |= data;
+                       ret = 0;
                        goto out_tsk;
-
-               *(unsigned long *) ((char *) task_regs(child) + addr) = data;
-               ret = 0;
-               goto out_tsk;
+               }
+#ifdef __LP64__
+               if (CHILD_IS_32BIT) {
+                       if (addr & (sizeof(int)-1))
+                               goto out_tsk;
+                       if ((addr = translate_usr_offset(addr)) < 0)
+                               goto out_tsk;
+                       DBG(("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
+                               pid, oaddr, odata, addr));
+                       if (addr >= PT_FR0 && addr <= PT_FR31) {
+                               /* Special case, fp regs are 64 bits anyway */
+                               *(unsigned int *) ((char *) task_regs(child) + addr) = data;
+                               ret = 0;
+                       }
+                       else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
+                                       addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
+                                       addr == PT_SAR+4) {
+                               /* Zero the top 32 bits */
+                               *(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0;
+                               *(unsigned int *) ((char *) task_regs(child) + addr) = data;
+                               ret = 0;
+                       }
+                       goto out_tsk;
+               }
+               else
+#endif
+               {
+                       if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
+                               goto out_tsk;
+                       if ((addr >= PT_GR1 && addr <= PT_GR31) ||
+                                       addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
+                                       (addr >= PT_FR0 && addr <= PT_FR31) ||
+                                       addr == PT_SAR) {
+                               *(unsigned long *) ((char *) task_regs(child) + addr) = data;
+                               ret = 0;
+                       }
+                       goto out_tsk;
+               }
 
        case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
        case PTRACE_CONT:
                ret = -EIO;
+               DBG(("sys_ptrace(%s)\n",
+                       request == PTRACE_SYSCALL ? "SYSCALL" : "CONT"));
                if ((unsigned long) data > _NSIG)
                        goto out_tsk;
                child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
-               if (request == PTRACE_SYSCALL)
-                       child->ptrace |= PT_TRACESYS;
-               else
-                       child->ptrace &= ~PT_TRACESYS;
+               if (request == PTRACE_SYSCALL) {
+                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               } else {
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               }               
                child->exit_code = data;
                goto out_wake_notrap;
 
@@ -168,16 +307,19 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
                 * sigkill.  perhaps it should be put in the status
                 * that it wants to exit.
                 */
+               DBG(("sys_ptrace(KILL)\n"));
                if (child->state == TASK_ZOMBIE)        /* already dead */
                        goto out_tsk;
                child->exit_code = SIGKILL;
                goto out_wake_notrap;
 
        case PTRACE_SINGLEBLOCK:
+               DBG(("sys_ptrace(SINGLEBLOCK)\n"));
                ret = -EIO;
                if ((unsigned long) data > _NSIG)
                        goto out_tsk;
-               child->ptrace &= ~(PT_TRACESYS|PT_SINGLESTEP);
+               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               child->ptrace &= ~PT_SINGLESTEP;
                child->ptrace |= PT_BLOCKSTEP;
                child->exit_code = data;
 
@@ -189,10 +331,12 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
                goto out_wake;
 
        case PTRACE_SINGLESTEP:
+               DBG(("sys_ptrace(SINGLESTEP)\n"));
                ret = -EIO;
                if ((unsigned long) data > _NSIG)
                        goto out_tsk;
-               child->ptrace &= ~(PT_TRACESYS|PT_BLOCKSTEP);
+               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               child->ptrace &= ~PT_BLOCKSTEP;
                child->ptrace |= PT_SINGLESTEP;
                child->exit_code = data;
 
@@ -208,10 +352,7 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
                        pa_psw(child)->y = 0;
                        pa_psw(child)->z = 0;
                        pa_psw(child)->b = 0;
-                       pa_psw(child)->r = 0;
-                       pa_psw(child)->t = 0;
-                       pa_psw(child)->h = 0;
-                       pa_psw(child)->l = 0;
+                       ptrace_disable(child);
                        /* Don't wake up the child, but let the
                           parent know something happened. */
                        si.si_code = TRAP_TRACE;
@@ -249,25 +390,24 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
        }
 
 out_wake_notrap:
-       /* make sure the trap bits are not set */
-       pa_psw(child)->r = 0;
-       pa_psw(child)->t = 0;
-       pa_psw(child)->h = 0;
-       pa_psw(child)->l = 0;
+       ptrace_disable(child);
 out_wake:
        wake_up_process(child);
        ret = 0;
 out_tsk:
-       free_task_struct(child);
+       put_task_struct(child);
 out:
        unlock_kernel();
+       DBG(("sys_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
+               request, pid, oaddr, odata, ret));
        return ret;
 }
 
 void syscall_trace(void)
 {
-       if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
-                       (PT_PTRACED|PT_TRACESYS))
+       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+               return;
+       if (!(current->ptrace & PT_PTRACED))
                return;
        current->exit_code = SIGTRAP;
        current->state = TASK_STOPPED;
index eb1425e..3cf3bd1 100644 (file)
@@ -7,7 +7,6 @@
  * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
  *
  */
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/psw.h>
 
@@ -31,8 +30,11 @@ save_cr_space:
 
 /************************ 32-bit real-mode calls ***********************/
 /* This can be called in both narrow and wide kernels */
+
        .text
+
        .export real32_call_asm
+
        /* unsigned long real32_call_asm(unsigned int *sp,
         *              unsigned int *arg0p,
         *              unsigned int iodc_fn)
@@ -40,6 +42,7 @@ save_cr_space:
         *      arg0p points to where saved arg values may be found
         *      iodc_fn is the IODC function to call
         */
+
 real32_call_asm:
        STREG   %rp, -RP_OFFSET(%sp)    /* save RP */
 #ifdef __LP64__
@@ -61,7 +64,7 @@ real32_call_asm:
        ldw     -12(%arg1), %arg3
        ldw     -4(%arg1), %arg1        /* obviously must do this one last! */
 
-       tophys  %sp
+       tophys_r1  %sp
 
        b,l     rfi_virt2real,%r2
        nop
@@ -88,7 +91,7 @@ ric_ret:
        b,l     rfi_real2virt,%r2
        nop
 
-       tovirt  %sp
+       tovirt_r1 %sp
        LDREG   -REG_SZ(%sp), %sp       /* restore SP */
 #ifdef __LP64__
        LDREG   -1*REG_SZ(%sp), %r27
@@ -150,14 +153,14 @@ rfi_virt2real:
        nop
        nop
        
-       mtsm            0               /* disable interruptions */
+       rsm             (PSW_SM_Q|PSW_SM_I),%r0  /* disable Q & I bits to load iia queue */
        mtctl           0, %cr17        /* space 0 */
        mtctl           0, %cr17
        load32          PA(rfi_v2r_1), %r1
        mtctl           %r1, %cr18
        ldo             4(%r1), %r1
        mtctl           %r1, %cr18
-       load32          PDC_PSW, %r1
+       load32          REAL_MODE_PSW, %r1
        mtctl           %r1, %cr22
        rfi
        
@@ -170,7 +173,7 @@ rfi_virt2real:
        nop
        nop
 rfi_v2r_1:
-       tophys  %r2
+       tophys_r1 %r2
        bv      0(%r2)
        nop
 
@@ -187,7 +190,7 @@ rfi_real2virt:
        nop
        nop
        
-       mtsm            0               /* disable interruptions */
+       rsm             PSW_SM_Q,%r0    /* disable Q bit to load iia queue */
        mtctl           0, %cr17        /* space 0 */
        mtctl           0, %cr17
        load32          (rfi_r2v_1), %r1
@@ -207,7 +210,7 @@ rfi_real2virt:
        nop
        nop
 rfi_r2v_1:
-       tovirt  %r2
+       tovirt_r1 %r2
        bv      0(%r2)
        nop
 
@@ -246,7 +249,7 @@ real64_call_asm:
        ldd     7*REG_SZ(%arg1), %r19
        ldd     1*REG_SZ(%arg1), %arg1          /* do this one last! */
 
-       tophys  %sp
+       tophys_r1 %sp
 
        b,l     rfi_virt2real,%r2
        nop
@@ -265,10 +268,18 @@ r64_ret:
        b,l     rfi_real2virt,%r2
        nop
 
-       tovirt  %sp
+       tovirt_r1 %sp
        ldd     -8(%sp), %sp            /* restore SP */
        ldd     -0x10(%sp), %rp         /* restore RP */
        bv      0(%rp)
        nop
 
 #endif
+       .export pc_in_user_space
+       .text
+       /* Doesn't belong here but I couldn't find a nicer spot. */
+       /* Should never get called, only used by profile stuff in time.c */
+pc_in_user_space:
+       bv,n    0(%rp)
+       nop
+
index edec8e6..ffb4851 100644 (file)
 /*
- * Just taken from alpha implementation.
- * This can't work well, perhaps.
- */
-/*
- *  Generic semaphore code. Buyer beware. Do your own
- * specific changes in <asm/semaphore-helper.h>
+ * Semaphore implementation Copyright (c) 2001 Matthew Wilcox, Hewlett-Packard
  */
 
 #include <linux/sched.h>
-#include <asm/semaphore-helper.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
 
 /*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to sleep, while the "waking" variable is
- * incremented when the "up()" code goes to wake up waiting
- * processes.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
+ * Semaphores are complex as we wish to avoid using two variables.
+ * `count' has multiple roles, depending on its value.  If it is positive
+ * or zero, there are no waiters.  The functions here will never be
+ * called; see <asm/semaphore.h>
  *
- * waking_non_zero() (from asm/semaphore.h) must execute
- * atomically.
+ * When count is -1 it indicates there is at least one task waiting
+ * for the semaphore.
  *
- * When __up() is called, the count was negative before
- * incrementing it, and we need to wake up somebody.
+ * When count is less than that, there are '- count - 1' wakeups
+ * pending.  ie if it has value -3, there are 2 wakeups pending.
  *
- * This routine adds one to the count of processes that need to
- * wake up and exit.  ALL waiting processes actually wake up but
- * only the one that gets to the "waking" field first will gate
- * through and acquire the semaphore.  The others will go back
- * to sleep.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
+ * Note that these functions are only called when there is contention
+ * on the lock, and as such all this is the "non-critical" part of the
+ * whole semaphore business. The critical part is the inline stuff in
+ * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
  */
 void __up(struct semaphore *sem)
 {
-       wake_one_more(sem);
+       sem->count--;
        wake_up(&sem->wait);
 }
 
-/*
- * Perform the "down" function.  Return zero for semaphore acquired,
- * return negative for signalled out of the function.
- *
- * If called from __down, the return is ignored and the wait loop is
- * not interruptible.  This means that a task waiting on a semaphore
- * using "down()" cannot be killed until someone does an "up()" on
- * the semaphore.
- *
- * If called from __down_interruptible, the return value gets checked
- * upon return.  If the return value is negative then the task continues
- * with the negative value in the return register (it can be tested by
- * the caller).
- *
- * Either form may be used in conjunction with "up()".
- *
- */
-
+#define wakers(count) (-1 - count)
 
-#define DOWN_HEAD(task_state)                                          \
+#define DOWN_HEAD                                                      \
+       int ret = 0;                                                    \
+       DECLARE_WAITQUEUE(wait, current);                               \
                                                                        \
+       /* Note that someone is waiting */                              \
+       if (sem->count == 0)                                            \
+               sem->count = -1;                                        \
                                                                        \
-       current->state = (task_state);                                  \
-       add_wait_queue(&sem->wait, &wait);                              \
-                                                                       \
-       /*                                                              \
-        * Ok, we're set up.  sem->count is known to be less than zero  \
-        * so we must wait.                                             \
-        *                                                              \
-        * We can let go the lock for purposes of waiting.              \
-        * We re-acquire it after awaking so as to protect              \
-        * all semaphore operations.                                    \
-        *                                                              \
-        * If "up()" is called before we call waking_non_zero() then    \
-        * we will catch it right away.  If it is called later then     \
-        * we will have to go through a wakeup cycle to catch it.       \
-        *                                                              \
-        * Multiple waiters contend for the semaphore lock to see       \
-        * who gets to gate through and who has to wait some more.      \
-        */                                                             \
-       for (;;) {
+       /* protected by the sentry still -- use unlocked version */     \
+       wait.flags = WQ_FLAG_EXCLUSIVE;                                 \
+       __add_wait_queue_tail(&sem->wait, &wait);                       \
+ lost_race:                                                            \
+       spin_unlock_irq(&sem->sentry);                                  \
+
+#define DOWN_TAIL                                                      \
+       spin_lock_irq(&sem->sentry);                                    \
+       if (wakers(sem->count) == 0 && ret == 0)                        \
+               goto lost_race; /* Someone stole our wakeup */          \
+       __remove_wait_queue(&sem->wait, &wait);                         \
+       current->state = TASK_RUNNING;                                  \
+       if (!waitqueue_active(&sem->wait) && (sem->count < 0))          \
+               sem->count = wakers(sem->count);
 
-#define DOWN_TAIL(task_state)                  \
-               current->state = (task_state);  \
-       }                                       \
-       current->state = TASK_RUNNING;          \
-       remove_wait_queue(&sem->wait, &wait);
+#define UPDATE_COUNT                                                   \
+       sem->count += (sem->count < 0) ? 1 : - 1;
+       
 
 void __down(struct semaphore * sem)
 {
-       DECLARE_WAITQUEUE(wait, current);
+       DOWN_HEAD
+
+       for(;;) {
+               set_task_state(current, TASK_UNINTERRUPTIBLE);
+               /* we can _read_ this without the sentry */
+               if (sem->count != -1)
+                       break;
+               schedule();
+       }
 
-       DOWN_HEAD(TASK_UNINTERRUPTIBLE)
-       if (waking_non_zero(sem))
-               break;
-       schedule();
-       DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+       DOWN_TAIL
+       UPDATE_COUNT
 }
 
 int __down_interruptible(struct semaphore * sem)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int ret = 0;
+       DOWN_HEAD
 
-       DOWN_HEAD(TASK_INTERRUPTIBLE)
+       for(;;) {
+               set_task_state(current, TASK_INTERRUPTIBLE);
+               /* we can _read_ this without the sentry */
+               if (sem->count != -1)
+                       break;
 
-       ret = waking_non_zero_interruptible(sem, current);
-       if (ret)
-       {
-               if (ret == 1)
-                       /* ret != 0 only if we get interrupted -arca */
-                       ret = 0;
-               break;
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+               schedule();
        }
-       schedule();
-       DOWN_TAIL(TASK_INTERRUPTIBLE)
-       return ret;
-}
 
-int __down_trylock(struct semaphore * sem)
-{
-       return waking_non_zero_trylock(sem);
+       DOWN_TAIL
+
+       if (!ret) {
+               UPDATE_COUNT
+       }
+
+       return ret;
 }
index a14b5ac..6ac6d24 100644 (file)
@@ -1,12 +1,13 @@
 /*    $Id: setup.c,v 1.8 2000/02/02 04:42:38 prumpf Exp $
  *
  *    Initial setup-routines for HP 9000 based hardware.
- * 
+ *
  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *    Modifications for PA-RISC (C) 1999 Helge Deller <helge.deller@ruhr-uni-bochum.de>
+ *    Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de>
  *    Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
  *    Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
  *    Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ *    Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
  *
  *    Initial PA-RISC Version: 04-23-1999 by Helge Deller
  *
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *    GNU General Public License for more details.
- * 
+ *
  *    You should have received a copy of the GNU General Public License
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
 
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/ptrace.h>
-#include <linux/sched.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/user.h>
-#include <linux/tty.h>
 #include <linux/config.h>
-#include <linux/fs.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/blk.h>          /* for initrd_start and initrd_end */
 #include <linux/init.h>
-#include <linux/interrupt.h>
 #include <linux/console.h>
-#include <linux/bootmem.h>
-#include <linux/delay.h>
+#include <linux/seq_file.h>
+#define PCI_DEBUG
 #include <linux/pci.h>
-#include <linux/threads.h>
+#undef PCI_DEBUG
+#include <linux/proc_fs.h>
 
-#include <asm/cache.h>
-#include <asm/hardware.h>      /* for register_driver() stuff */
 #include <asm/processor.h>
-#include <asm/page.h>
 #include <asm/pdc.h>
 #include <asm/led.h>
-#include <asm/real.h>
-#include <asm/system.h>
 #include <asm/machdep.h>       /* for pa7300lc_init() proto */
-
-#include <asm/irq.h>           /* for struct irq_region */
-#include <asm/pdcpat.h>                /* for PA_VIEW PDC_PAT_CPU_GET_NUMBER etc */
-
-#include <linux/proc_fs.h>
+#include <asm/pdc_chassis.h>
 
 #define COMMAND_LINE_SIZE 1024
 char   saved_command_line[COMMAND_LINE_SIZE];
+char   command_line[COMMAND_LINE_SIZE];
 
-/*
-** KLUGE ALERT!
-**
-** We *really* should be using a combination of request_resource()
-** and request_region()! But request_region() requires kmalloc since
-** returns a new struct resource. And kmalloc just isn't available
-** until after mem_init() is called from start_kernel().
-**
-** FIXME: assume contiguous memory initially.
-**     Additional chunks of memory might be added to sysram_resource.sibling.
-*/
-static struct resource sysrom_resource  = {
-       name: "System ROM", start: 0x0f0000000UL, end: 0x0f00fffffUL,
-       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-       parent: &iomem_resource, sibling: NULL, child: NULL };
-
-static struct resource pdcdata_resource;
-
-static struct resource sysram_resource  = {
-       name: "System RAM", start: 0UL, end: ~0UL /* bogus */,
-       flags: IORESOURCE_MEM,
-       parent: &iomem_resource, sibling: &sysrom_resource, child: &pdcdata_resource};
-
-extern char _text;     /* start of kernel code, defined by linker */
-extern int  data_start; 
-extern char _edata;    /* end of data, begin BSS, defined by linker */
-extern char _end;      /* end of BSS, defined by linker */
-
-static struct resource data_resource    = {
-       name: "kernel Data", start: virt_to_phys(&data_start), end: virt_to_phys(&_end)-1,
-       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-       parent: &sysram_resource, sibling: NULL, child: NULL};
-
-static struct resource code_resource = {
-       name: "Kernel Code", start: virt_to_phys(&_text), end: virt_to_phys(&data_start)-1,
-       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-       parent: &sysram_resource, sibling: &data_resource, child: NULL};
-
-static struct resource pdcdata_resource = {
-       name: "PDC data (Page Zero)", start: 0, end: 0x9ff,
-       flags: IORESOURCE_BUSY | IORESOURCE_MEM,
-       parent: &sysram_resource, sibling: &code_resource, child: NULL};
-
-
-
-
-struct system_cpuinfo_parisc boot_cpu_data;
-struct cpuinfo_parisc cpu_data[NR_CPUS];
-
-extern void do_inventory(void);
-extern void cache_init(void);
-extern struct hp_device * register_module(void *hpa);
-
-static int cpu_driver_callback(struct hp_device *, struct pa_iodc_driver *);
-
-static struct pa_iodc_driver cpu_drivers_for[] = {
-       {HPHW_NPROC, 0x0, 0x0, 0x0, 0, 0,
-               DRIVER_CHECK_HWTYPE,
-               "CPU", "PARISC", (void *) cpu_driver_callback},
-       {0,0,0,0,0,0,
-               0,
-               (char *) NULL, (char *) NULL, (void *) NULL }
-};
+/* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */
+struct proc_dir_entry * proc_runway_root = NULL;
+struct proc_dir_entry * proc_gsc_root = NULL;
 
-static long fallback_cpu_hpa[] = { 0xfffa0000L, 0xfffbe000L, 0x0 };
+#ifdef CONFIG_EISA
+int EISA_bus;  /* This has to go somewhere in architecture specific code. */
+#endif
 
+void __init setup_cmdline(char **cmdline_p)
+{
+       extern unsigned int boot_args[];
 
-/*
-**     PARISC CPU driver - claim "device" and initialize CPU data structures.
-**
-** Consolidate per CPU initialization into (mostly) one module.
-** Monarch CPU will initialize boot_cpu_data which shouldn't
-** change once the system has booted.
-**
-** The callback *should* do per-instance initialization of
-** everything including the monarch. Some of the code that's
-** in setup.c:start_parisc() should migrate here and start_parisc()
-** should "register_driver(cpu_driver_for)" before calling
-** do_inventory().
-**
-** The goal of consolidating CPU initialization into one place is
-** to make sure all CPU's get initialized the same way.
-** It would be nice if the even the manarch through the exact same code path.
-** (up to rendevous at least).
-*/
-#undef ASSERT
-#define ASSERT(expr) \
-       if(!(expr)) { \
-               printk( "\n" __FILE__ ":%d: Assertion " #expr " failed!\n",__LINE__); \
-               panic(#expr); \
+       /* Collect stuff passed in from the boot loader */
+
+       /* boot_args[0] is free-mem start, boot_args[1] is ptr to command line */
+       if (boot_args[0] < 64) {
+               /* called from hpux boot loader */
+               saved_command_line[0] = '\0';
+       } else {
+               strcpy(saved_command_line, (char *)__va(boot_args[1]));
+
+#ifdef CONFIG_BLK_DEV_INITRD
+               if (boot_args[2] != 0) /* did palo pass us a ramdisk? */
+               {
+                   initrd_start = (unsigned long)__va(boot_args[2]);
+                   initrd_end = (unsigned long)__va(boot_args[3]);
+               }
+#endif
        }
 
-static int
-cpu_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri)
+       strcpy(command_line, saved_command_line);
+       *cmdline_p = command_line;
+}
+
+#ifdef CONFIG_PA11
+void __init dma_ops_init(void)
 {
-#ifdef __LP64__
-       extern int pdc_pat;     /* arch/parisc/kernel/inventory.c */
-       static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0};
-#endif
-       struct cpuinfo_parisc *p;
+       switch (boot_cpu_data.cpu_type) {
+       case pcx:
+               /*
+                * We've got way too many dependencies on 1.1 semantics
+                * to support 1.0 boxes at this point.
+                */
+               panic(  "PA-RISC Linux currently only supports machines that conform to\n"
+                       "the PA-RISC 1.1 or 2.0 architecture specification.\n");
 
-#ifndef CONFIG_SMP
-       if (boot_cpu_data.cpu_count > 0) {
-               printk(KERN_INFO "CONFIG_SMP disabled - not claiming addional CPUs\n");
-               return(1);
+       case pcxs:
+       case pcxt:
+               hppa_dma_ops = &pcx_dma_ops;
+               break;
+       case pcxl2:
+               pa7300lc_init();
+       case pcxl: /* falls through */
+               hppa_dma_ops = &pcxl_dma_ops;
+               break;
+       default:
+               break;
        }
+}
 #endif
 
-       p = &cpu_data[boot_cpu_data.cpu_count];
-       boot_cpu_data.cpu_count++;
-
-/* TODO: Enable FP regs - done early in start_parisc() now */
-
-       /* initialize counters */
-       memset(p, 0, sizeof(struct cpuinfo_parisc));
+extern int init_per_cpu(int cpuid);
+extern void collect_boot_cpu_data(void);
 
-       p->hpa = (unsigned long) d->hpa; /* save CPU hpa */
+void __init setup_arch(char **cmdline_p)
+{
+       init_per_cpu(smp_processor_id());       /* Set Modes & Enable FP */
 
 #ifdef __LP64__
-       if (pdc_pat) {
-               ulong status;
-               pdc_pat_cell_mod_maddr_block_t pa_pdc_cell;
-
-               status = pdc_pat_cell_module(& pdc_result, d->pcell_loc,
-                       d->mod_index, PA_VIEW, & pa_pdc_cell);
-
-               ASSERT(PDC_RET_OK == status);
-
-               /* verify it's the same as what do_pat_inventory() found */
-               ASSERT(d->mod_info == pa_pdc_cell.mod_info);
-               ASSERT(d->pmod_loc == pa_pdc_cell.mod_location);
-               ASSERT(d->mod_path == pa_pdc_cell.mod_path);
-
-               p->txn_addr = pa_pdc_cell.mod[0];   /* id_eid for IO sapic */
-
-               /* get the cpu number */
-               status = mem_pdc_call( PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
-                               __pa(& pdc_result), d->hpa);
+       printk(KERN_INFO "The 64-bit Kernel has started...\n");
+#else
+       printk(KERN_INFO "The 32-bit Kernel has started...\n");
+#endif
 
-               ASSERT(PDC_RET_OK == status);
+       pdc_console_init();
 
-               p->cpuid = pdc_result[0];
+#ifdef CONFIG_PDC_NARROW
+       printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
+#endif
+       setup_pdc();
+       setup_cmdline(cmdline_p);
+       collect_boot_cpu_data();
+       do_memory_inventory();  /* probe for physical memory */
+       parisc_cache_init();
+       paging_init();
 
-       } else
+#ifdef CONFIG_CHASSIS_LCD_LED
+       /* initialize the LCD/LED after boot_cpu_data is available ! */
+        led_init();                            /* LCD/LED initialization */
 #endif
-       {
-               p->txn_addr = (unsigned long) d->hpa;   /* for normal parisc */
 
-               /* logical CPU ID and update global counter */
-               p->cpuid = boot_cpu_data.cpu_count - 1;
-       }
+#ifdef CONFIG_PA11
+       dma_ops_init();
+#endif
 
-       /*
-       ** itimer and ipi IRQ handlers are statically initialized in
-       ** arch/parisc/kernel/irq.c
-       */
-       p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+#ifdef CONFIG_VT
+# if defined(CONFIG_STI_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+        conswitchp = &dummy_con;        /* we use take_over_console() later ! */
+# endif
+#endif
 
-       return(0);
 }
 
+/*
+ * Display cpu info for all cpu's.
+ * for parisc this is in processor.c
+ */
+extern int show_cpuinfo (struct seq_file *m, void *v);
 
-void __xchg_called_with_bad_pointer(void)
+static void *
+c_start (struct seq_file *m, loff_t *pos)
 {
-    printk(KERN_EMERG "xchg() called with bad pointer !\n");
+       /* Looks like the caller will call repeatedly until we return
+        * 0, signaling EOF perhaps.  This could be used to sequence
+        * through CPUs for example.  Since we print all cpu info in our
+        * show_cpuinfo() disregarding 'pos' (which I assume is 'v' above)
+        * we only allow for one "position".  */
+       return ((long)*pos < 1) ? (void *)1 : NULL;
 }
 
-
-/* Some versions of IODC don't list the CPU, and since we don't walk
- * the bus yet, we have to probe for processors at well known hpa
- * addresses.  
- */
-
-void __init register_fallback_cpu (void)
+static void *
+c_next (struct seq_file *m, void *v, loff_t *pos)
 {
-       struct hp_device *d = NULL;
-       int i = 0;
-       
-#ifdef CONFIG_SMP
-#error "Revisit CPU fallback addresses for SMP (Assuming bus walk hasn't been implemented)"
-#endif
-       printk ("No CPUs reported by firmware - probing...\n");
-       
-       while (fallback_cpu_hpa[i]) {
-               
-               d = register_module ((void *) fallback_cpu_hpa[i]);
-               
-               if (d > 0) {
-                       printk ("Found CPU at %lx\n", fallback_cpu_hpa[i]);
-                       cpu_driver_callback (d, 0);
-                       return;
-               }
-               
-               i++;
-       }
-       
-       panic ("No CPUs found.  System halted.\n");
-       return;
+       ++*pos;
+       return c_start(m, pos);
 }
 
-
-/*
- * Get CPU information and store it in the boot_cpu_data structure.  */
-void __init collect_boot_cpu_data(void)
+static void
+c_stop (struct seq_file *m, void *v)
 {
-       memset(&boot_cpu_data,0,sizeof(boot_cpu_data));
-
-       boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
-
-       /* get CPU-Model Information... */
-#define p ((unsigned long *)&boot_cpu_data.pdc.model)
-       if(pdc_model_info(&boot_cpu_data.pdc.model)==0)
-               printk("model   %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-                       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
-#undef p
-
-       if(pdc_model_versions(&boot_cpu_data.pdc.versions, 0)==0)
-               printk("vers    %08lx\n", boot_cpu_data.pdc.versions.cpuid);
-
-       if(pdc_model_cpuid(&boot_cpu_data.pdc.cpuid)==0)
-               printk("cpuid   %08lx\n", boot_cpu_data.pdc.cpuid.cpuid);
-       
-       printk("CPUID   vers %ld rev %ld\n",
-               (boot_cpu_data.pdc.cpuid.cpuid >> 5) & 127,
-               boot_cpu_data.pdc.cpuid.cpuid & 31);
-
-       if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name)==0)
-               printk("model   %s\n",boot_cpu_data.pdc.sys_model_name);
-
-       boot_cpu_data.model_name = parisc_getHWdescription(HPHW_NPROC,
-               boot_cpu_data.pdc.model.hversion>>4,
-               boot_cpu_data.pdc.model.sversion>>8);
-       
-       boot_cpu_data.hversion =  boot_cpu_data.pdc.model.hversion;
-       boot_cpu_data.sversion =  boot_cpu_data.pdc.model.sversion;
-
-       boot_cpu_data.cpu_type =
-                       parisc_get_cpu_type(boot_cpu_data.pdc.model.hversion);
-
-       boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
-       boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
 }
 
+struct seq_operations cpuinfo_op = {
+       start:  c_start,
+       next:   c_next,
+       stop:   c_stop,
+       show:   show_cpuinfo
+};
 
-#ifdef __LP64__
-#define COMMAND_GLOBAL  0xfffffffffffe0030UL
-#else
-#define COMMAND_GLOBAL  0xfffe0030
-#endif
-
-#define CMD_RESET       5       /* reset any module */
-
-/*
-** The Wright Brothers and Gecko systems have a H/W problem
-** (Lasi...'nuf said) may cause a broadcast reset to lockup
-** the system. An HVERSION dependent PDC call was developed
-** to perform a "safe", platform specific broadcast reset instead
-** of kludging up all the code.
-**
-** Older machines which do not implement PDC_BROADCAST_RESET will
-** return (with an error) and the regular broadcast reset can be
-** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
-** the PDC call will not return (the system will be reset).
-*/
-static int
-reset_parisc(struct notifier_block *self, unsigned long command, void *ptr)
+static void parisc_proc_mkdir(void)
 {
-       printk("%s: %s(cmd=%lu)\n", __FILE__, __FUNCTION__, command);
-
-       switch(command) {
-       case MACH_RESTART:
-#ifdef FASTBOOT_SELFTEST_SUPPORT
-               /*
-               ** If user has modified the Firmware Selftest Bitmap,
-               ** run the tests specified in the bitmap after the
-               ** system is rebooted w/PDC_DO_RESET.
-               **
-               ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
-               **
-               ** Using "directed resets" at each processor with the MEM_TOC
-               ** vector cleared will also avoid running destructive
-               ** memory self tests. (Not implemented yet)
-               */
-               if (ftc_bitmap) {
-                       mem_pdc_call( PDC_BROADCAST_RESET,
-                               PDC_DO_FIRM_TEST_RESET, PDC_FIRM_TEST_MAGIC,
-                               ftc_bitmap);
+       /*
+       ** Can't call proc_mkdir() until after proc_root_init() has been
+       ** called by start_kernel(). In other words, this code can't
+       ** live in arch/.../setup.c because start_parisc() calls
+       ** start_kernel().
+       */
+       switch (boot_cpu_data.cpu_type) {
+       case pcxl:
+       case pcxl2:
+               if (NULL == proc_gsc_root)
+               {
+                       proc_gsc_root = proc_mkdir("bus/gsc", 0);
                }
-#endif
-
-               /* "Normal" system reset */
-               (void) mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET,
-                       0L, 0L, 0L);
-
-               /* Nope...box should reset with just CMD_RESET now */
-               gsc_writel(CMD_RESET, COMMAND_GLOBAL);
-
-               /* Wait for RESET to lay us to rest. */
-               while (1) ;
-
                break;
+        case pcxt_:
+        case pcxu:
+        case pcxu_:
+        case pcxw:
+        case pcxw_:
+        case pcxw2:
+                if (NULL == proc_runway_root)
+                {
+                        proc_runway_root = proc_mkdir("bus/runway", 0);
+                }
+                break;
        }
-       return NOTIFY_DONE;
 }
 
-static struct notifier_block parisc_block = { reset_parisc, NULL, 0 };
-
-
-/*  start_parisc() will be called from head.S to setup our new memory_start 
-    and actually start our kernel !
-    Memory-Layout is:
-       - Kernel-Image (code+data+BSS)
-       - Stack (stack-size see below!, stack-setup-code is in head.S)
-       - memory_start at end of stack..
-*/
+static struct resource central_bus = {
+       name:   "Central Bus",
+       start:  (unsigned long)0xfffffffffff80000,
+       end:    (unsigned long)0xfffffffffffaffff,
+       flags:  IORESOURCE_MEM,
+};
 
-unsigned long mem_start, mem_max;
-unsigned long start_pfn, max_pfn;
-extern asmlinkage void __init start_kernel(void);
+static struct resource local_broadcast = {
+       name:   "Local Broadcast",
+       start:  (unsigned long)0xfffffffffffb0000,
+       end:    (unsigned long)0xfffffffffffdffff,
+       flags:  IORESOURCE_MEM,
+};
 
-#define PFN_UP(x)      (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x)    ((x) >> PAGE_SHIFT)
-#define PFN_PHYS(x)    ((x) << PAGE_SHIFT)
+static struct resource global_broadcast = {
+       name:   "Global Broadcast",
+       start:  (unsigned long)0xfffffffffffe0000,
+       end:    (unsigned long)0xffffffffffffffff,
+       flags:  IORESOURCE_MEM,
+};
 
-void __init start_parisc(unsigned arg0, unsigned arg1,
-                        unsigned arg2, unsigned arg3)
+int __init parisc_init_resources(void)
 {
-       register unsigned long ccr;
-       unsigned long memory_start;
-
-       /* Clear BSS */
-
-       {
-               char *p = &_edata, *q = &_end;
-
-               while (p < q) {
-                       *p++ = 0;
-               }
+       int result;
+
+       result = request_resource(&iomem_resource, &central_bus);
+       if (result < 0) {
+               printk(KERN_ERR 
+                      "%s: failed to claim %s address space!\n", 
+                      __FILE__, central_bus.name);
+               return result;
        }
 
-
-       pdc_console_init();
-
-#ifdef __LP64__
-       printk("The 64-bit Kernel has started...\n");
-#else
-       printk("The 32-bit Kernel has started...\n");
-#endif
-
-       /*
-       ** Enable FP coprocessor
-       **
-       ** REVISIT: ccr should be set by PDC_COPROC results to support PA1.0.
-       ** Hardcoding works for PA1.1 processors.
-       **
-       ** REVISIT: this could be done in the "code 22" trap handler.
-       ** (frowands idea - that way we know which processes need FP
-       ** registers saved on the interrupt stack.)
-       **
-       ** NEWS FLASH: wide kernels need FP coprocessor enabled to handle
-       ** formatted printing of %lx for example (double divides I think)
-       */
-       ccr = 0xc0;
-       mtctl(ccr, 10);
-       printk("Enabled FP coprocessor\n");
-
-#ifdef __LP64__
-       printk( "If this is the LAST MESSAGE YOU SEE, you're probably using\n"
-               "32-bit millicode by mistake.\n");
-#endif
-
-       memory_start = (unsigned long) &_end;
-       memory_start = (memory_start + PAGE_SIZE) & PAGE_MASK;
-       printk("Free memory starts at: 0x%lx\n", memory_start);
-
-       /* Collect stuff passed in from the boot loader */
-       printk(KERN_WARNING  "%s(0x%x,0x%x,0x%x,0x%x)\n", 
-                   __FUNCTION__, arg0, arg1, arg2, arg3);
-
-       /* arg0 is free-mem start, arg1 is ptr to command line */
-       if (arg0 < 64) {
-               /* called from hpux boot loader */
-               saved_command_line[0] = '\0';
-       } else {
-               strcpy(saved_command_line, (char *)__va(arg1));
-               printk("PALO command line: '%s'\nPALO initrd %x-%x\n",
-                   saved_command_line, arg2, arg3);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-               if (arg2 != 0) /* did palo pass us a ramdisk? */
-               {
-                   initrd_start = (unsigned long)__va(arg2);
-                   initrd_end = (unsigned long)__va(arg3);
-               }
-#endif
+       result = request_resource(&iomem_resource, &local_broadcast);
+       if (result < 0) {
+               printk(KERN_ERR 
+                      "%s: failed to claim %saddress space!\n", 
+                      __FILE__, local_broadcast.name);
+               return result;
        }
 
-       mem_start = __pa(memory_start);
-#define MAX_MEM (512*1024*1024)
-       mem_max = (PAGE0->imm_max_mem > MAX_MEM ? MAX_MEM : PAGE0->imm_max_mem);
-
-       collect_boot_cpu_data();
+       result = request_resource(&iomem_resource, &global_broadcast);
+       if (result < 0) {
+               printk(KERN_ERR 
+                      "%s: failed to claim %s address space!\n", 
+                      __FILE__, global_broadcast.name);
+               return result;
+       }
 
-       /* initialize the LCD/LED after boot_cpu_data is available ! */
-        led_init();                            /* LCD/LED initialization */
+       return 0;
+}
 
-       do_inventory();                         /* probe for hardware */
-        register_driver(cpu_drivers_for);      /* claim all the CPUs */
+extern void gsc_init(void);
+extern void processor_init(void);
+extern void ccio_init(void);
+extern void dino_init(void);
+extern void iosapic_init(void);
+extern void lba_init(void);
+extern void sba_init(void);
+extern void eisa_init(void);
 
-       if (boot_cpu_data.cpu_count == 0)
-           register_fallback_cpu();
+static int __init parisc_init(void)
+{
+       parisc_proc_mkdir();
+       parisc_init_resources();
+       do_device_inventory();                  /* probe for hardware */
 
-       printk("CPU(s): %d x %s at %d.%06d MHz\n", 
+       parisc_pdc_chassis_init();
+       
+       /* set up a new led state on systems shipped LED State panel */
+       pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);
+       
+       processor_init();
+       printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
                        boot_cpu_data.cpu_count,
                        boot_cpu_data.cpu_name,
-                       boot_cpu_data.cpu_hz / 1000000, 
+                       boot_cpu_data.cpu_hz / 1000000,
                        boot_cpu_data.cpu_hz % 1000000  );
 
-       switch (boot_cpu_data.cpu_type) {
-       case pcx:
-       case pcxs:
-       case pcxt:
-               hppa_dma_ops = &pcx_dma_ops;
-               break;
-       case pcxl2:
-               pa7300lc_init();
-       case pcxl: /* falls through */
-               hppa_dma_ops = &pcxl_dma_ops;
-               break;
-       default:
-               break;
-       }
-
-#if 1
-       /* KLUGE! this really belongs in kernel/resource.c! */
-       iomem_resource.end = ~0UL;
+       /* These are in a non-obvious order, will fix when we have an iotree */
+#if defined(CONFIG_IOSAPIC)
+       iosapic_init();
 #endif
-       sysram_resource.end = mem_max - 1;
-       notifier_chain_register(&mach_notifier, &parisc_block);
-       start_kernel();         /* now back to arch-generic code... */
-}
-
-void __init setup_arch(char **cmdline_p)
-{
-       unsigned long bootmap_size;
-       unsigned long start_pfn;
-       unsigned long mem_free;
-
-       *cmdline_p = saved_command_line;
-
-       /* initialize bootmem */
-
-       start_pfn = PFN_UP(mem_start);
-       max_pfn = PFN_DOWN(mem_max);
-
-       bootmap_size = init_bootmem(start_pfn, max_pfn);
-
-       mem_start += bootmap_size;
-       mem_free = mem_max - mem_start;
-
-       /* free_bootmem handles rounding nicely */
-       printk("free_bootmem(0x%lx, 0x%lx)\n", (unsigned long)mem_start,
-                       (unsigned long)mem_free);
-       free_bootmem(mem_start, mem_free);
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       printk("initrd: %08x-%08x\n", (int) initrd_start, (int) initrd_end);
-
-       if (initrd_end != 0) {
-               initrd_below_start_ok = 1;
-               reserve_bootmem(__pa(initrd_start), initrd_end - initrd_start);
-       }
+#if defined(CONFIG_IOMMU_SBA)
+       sba_init();
+#endif
+#if defined(CONFIG_PCI_LBA)
+       lba_init();
 #endif
 
-       cache_init();
-
-       paging_init();
-
-       if((unsigned long)&init_task_union&(INIT_TASK_SIZE - 1)) {
-               printk("init_task_union not aligned.  Please recompile the kernel after changing the first line in arch/parisc/kernel/init_task.c from \n\"#define PAD 0\" to\n\"#define PAD 1\" or vice versa\n");
-               for(;;);
-       }
-
+       /* CCIO before any potential subdevices */
+#if defined(CONFIG_IOMMU_CCIO)
+       ccio_init();
+#endif
 
-#ifdef CONFIG_SERIAL_CONSOLE
-       /* nothing */
-#elif CONFIG_VT
-#if   defined(CONFIG_STI_CONSOLE)
-       conswitchp = &dummy_con;        /* we use take_over_console() later ! */
-#elif defined(CONFIG_IODC_CONSOLE)
-       conswitchp = &prom_con;         /* it's currently really "prom_con" */
-#elif defined(CONFIG_DUMMY_CONSOLE)
-       conswitchp = &dummy_con;
+       /*
+        * Need to register Asp & Wax before the EISA adapters for the IRQ
+        * regions.  EISA must come before PCI to be sure it gets IRQ region
+        * 0.
+        */
+#if defined(CONFIG_GSC_LASI) || defined(CONFIG_GSC_WAX)
+       gsc_init();
 #endif
+#ifdef CONFIG_EISA
+       eisa_init();
+#endif
+#if defined(CONFIG_GSC_DINO)
+       dino_init();
 #endif
 
-}
-
-#ifdef CONFIG_PROC_FS
-/*
- *     Get CPU information for use by procfs.
- */
-
-int get_cpuinfo(char *buffer)
-{
-       char              *p = buffer;
-       int               n;
-
-       for(n=0; n<boot_cpu_data.cpu_count; n++) {
-#ifdef CONFIG_SMP
-               if (!(cpu_online_map & (1<<n)))
-                       continue;
+#ifdef CONFIG_CHASSIS_LCD_LED
+       register_led_regions(); /* register LED port info in procfs */
 #endif
-               p += sprintf(p, "processor\t: %d\n"
-                               "cpu family\t: PA-RISC %s\n",
-                               n, boot_cpu_data.family_name);
 
-               p += sprintf(p, "cpu\t\t: %s\n",  boot_cpu_data.cpu_name );
-       
-               /* cpu MHz */
-               p += sprintf(p, "cpu MHz\t\t: %d.%06d\n",
-                                boot_cpu_data.cpu_hz / 1000000, 
-                                boot_cpu_data.cpu_hz % 1000000  );
-
-               p += sprintf(p, "model\t\t: %s\n"
-                               "model name\t: %s\n",
-                               boot_cpu_data.pdc.sys_model_name,
-                               boot_cpu_data.model_name);
-
-               p += sprintf(p, "hversion\t: 0x%08x\n"
-                               "sversion\t: 0x%08x\n",
-                               boot_cpu_data.hversion,
-                               boot_cpu_data.sversion );
-
-               p += get_cache_info(p);
-               /* print cachesize info ? */
-               p += sprintf(p, "bogomips\t: %lu.%02lu\n",
-                            (loops_per_sec+2500)/500000,
-                            ((loops_per_sec+2500)/5000) % 100);
-       }
-       return p - buffer;
+       return 0;
 }
-#endif
+
+arch_initcall(parisc_init);
 
index b2bf262..8f395d5 100644 (file)
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <asm/ucontext.h>
+#include <asm/rt_sigframe.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
 #define DEBUG_SIG 0
 
+#if DEBUG_SIG
+#define DBG(x) printk x
+#else
+#define DBG(x)
+#endif
+
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-extern long sys_wait4 (int, int *, int, struct rusage *);
 int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall);
 
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
-       if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
-               return -EFAULT;
        if (from->si_code < 0)
                return __copy_to_user(to, from, sizeof(siginfo_t));
        else {
@@ -109,11 +113,11 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
 #endif
        sigdelsetmask(&newset, ~_BLOCKABLE);
 
-       spin_lock_irq(&current->sigmask_lock);
+       spin_lock_irq(&current->sig->siglock);
        saveset = current->blocked;
        current->blocked = newset;
        recalc_sigpending();
-       spin_unlock_irq(&current->sigmask_lock);
+       spin_unlock_irq(&current->sig->siglock);
 
        regs->gr[28] = -EINTR;
        while (1) {
@@ -128,30 +132,15 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
  * Do a signal return - restore sigcontext.
  */
 
-struct rt_sigframe {
-       unsigned int tramp[4];
-       struct siginfo info;
-       struct ucontext uc;
-};
-
 /* Trampoline for calling rt_sigreturn() */
 #define INSN_LDI_R25_0  0x34190000 /* ldi  0,%r25 (in_syscall=0) */
 #define INSN_LDI_R25_1  0x34190002 /* ldi  1,%r25 (in_syscall=1) */
 #define INSN_LDI_R20    0x3414015a /* ldi  __NR_rt_sigreturn,%r20 */
 #define INSN_BLE_SR2_R0  0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */
-#define INSN_NOP        0x80000240 /* nop */
+#define INSN_NOP        0x08000240 /* nop */
 /* For debugging */
 #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
 
-/*
- * The 32-bit ABI wants at least 48 bytes for a function call frame:
- * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
- * which Linux/parisc uses is sp-20 for the saved return pointer...)
- * Then, the stack pointer must be rounded to a cache line (64 bytes).
- */
-#define PARISC_RT_SIGFRAME_SIZE                                        \
-       (((sizeof(struct rt_sigframe) + 48) + 63) & -64)
-
 static long
 restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
 {
@@ -162,10 +151,7 @@ restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
        err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq));
        err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq));
        err |= __get_user(regs->sar, &sc->sc_sar);
-
-#if DEBUG_SIG
-       printk("restore_sigcontext: r28 is %ld\n", regs->gr[28]);
-#endif
+       DBG(("restore_sigcontext: r28 is %ld\n", regs->gr[28]));
        return err;
 }
 
@@ -180,30 +166,22 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
        /* Unwind the user stack to get the rt_sigframe structure. */
        frame = (struct rt_sigframe *)
                (usp - PARISC_RT_SIGFRAME_SIZE);
-#if DEBUG_SIG
-       printk("in sys_rt_sigreturn, frame is %p\n", frame);
-#endif
+       DBG(("in sys_rt_sigreturn, frame is %p\n", frame));
 
-       /* Verify that it's a good sigcontext before using it */
-       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
-               goto give_sigsegv;
        if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
                goto give_sigsegv;
 
        sigdelsetmask(&set, ~_BLOCKABLE);
-       spin_lock_irq(&current->sigmask_lock);
+       spin_lock_irq(&current->sig->siglock);
        current->blocked = set;
        recalc_sigpending();
-       spin_unlock_irq(&current->sigmask_lock);
+       spin_unlock_irq(&current->sig->siglock);
 
        /* Good thing we saved the old gr[30], eh? */
        if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
                goto give_sigsegv;
 
-#if DEBUG_SIG
-       printk("usp: %#08lx stack %p",
-              usp, &frame->uc.uc_stack);
-#endif
+       DBG(("usp: %#08lx stack %p", usp, &frame->uc.uc_stack));
 
        /* I don't know why everyone else assumes they can call this
            with a pointer to a stack_t on the kernel stack.  That
@@ -218,16 +196,14 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
        if (in_syscall)
                regs->gr[31] = regs->iaoq[0];
 #if DEBUG_SIG
-       printk("returning to %#lx\n", regs->iaoq[0]);
-       printk("in sys_rt_sigreturn:\n");
+       DBG(("returning to %#lx\n", regs->iaoq[0]));
+       DBG(("in sys_rt_sigreturn:\n"));
        show_regs(regs);
 #endif
        return;
 
 give_sigsegv:
-#if DEBUG_SIG
-       printk("fuckup in sys_rt_sigreturn, sending SIGSEGV\n");
-#endif
+       DBG(("sys_rt_sigreturn sending SIGSEGV\n"));
        si.si_signo = SIGSEGV;
        si.si_errno = 0;
        si.si_code = SI_KERNEL;
@@ -246,7 +222,7 @@ static inline void *
 get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
 {
        if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
-               sp = current->sas_ss_sp + current->sas_ss_size;
+               sp = current->sas_ss_sp; /* Stacks grow up! */
 
        return (void *) sp; /* Stacks grow up.  Fun. */
 }
@@ -265,24 +241,22 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, int in_syscall)
                /* regs->iaoq is undefined in the syscall return path */
                err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]);
                err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]);
-#if DEBUG_SIG
-               printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->gr[31], regs->gr[31]);
-#endif
+               err |= __put_user(regs->sr[3], &sc->sc_iasq[0]);
+               err |= __put_user(regs->sr[3], &sc->sc_iasq[1]);
+               DBG(("setup_sigcontext: iaoq %#lx/%#lx\n",
+                       regs->gr[31], regs->gr[31]));
        } else {
                err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq));
                err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq));
-#if DEBUG_SIG
-               printk("setup_sigcontext: iaoq %#lx/%#lx\n", regs->iaoq[0], regs->iaoq[1]);
-#endif
+               DBG(("setup_sigcontext: iaoq %#lx/%#lx\n", 
+                       regs->iaoq[0], regs->iaoq[1]));
        }
 
        err |= __put_user(flags, &sc->sc_flags);
        err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr));
        err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
        err |= __put_user(regs->sar, &sc->sc_sar);
-#if DEBUG_SIG
-       printk("setup_sigcontext: r28 is %ld\n", regs->gr[28]);
-#endif
+       DBG(("setup_sigcontext: r28 is %ld\n", regs->gr[28]));
 
        return err;
 }
@@ -297,22 +271,9 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        int err = 0;
 
        usp = regs->gr[30];
-       /* access_ok is broken, so do a simplistic "are we stomping on
-           kernel space" assertion. */
-       if (usp > PAGE_OFFSET) {
-               printk("setup_rt_frame: called on kernel space (usp=%#lx),  NOW YOU MUST DIE!!!\n",
-                      usp);
-               show_regs(regs);
-               while(1);
-       }
-               
        frame = get_sigframe(ka, usp, sizeof(*frame));
-       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
 
-#if DEBUG_SIG
-       printk("setup_rt_frame 1: frame %p info %p\n", frame, info);
-#endif
+       DBG(("setup_rt_frame 1: frame %p info %p\n", frame, info));
 
        err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t));
        err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
@@ -337,8 +298,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        {
                int sid;
                asm ("mfsp %%sr3,%0" : "=r" (sid));
-               printk("flushing 64 bytes at space %#x offset %p\n",
-                      sid, frame->tramp);
+               DBG(("flushing 64 bytes at space %#x offset %p\n",
+                      sid, frame->tramp));
        }
 #endif
 
@@ -387,6 +348,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        if (in_syscall)
                regs->gr[31] = (HACK) haddr;
        else {
+               regs->gr[0] = USER_PSW;
                regs->iaoq[0] = (HACK) haddr | 3;
                regs->iaoq[1] = regs->iaoq[0] + 4;
        }
@@ -395,26 +357,20 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->gr[26] = sig;               /* signal number */
        regs->gr[25] = (HACK) &frame->info; /* siginfo pointer */
        regs->gr[24] = (HACK) &frame->uc;   /* ucontext pointer */
-#if DEBUG_SIG
-       printk("making sigreturn frame: %#lx + %#lx = %#lx\n",
+       DBG(("making sigreturn frame: %#lx + %#x = %#lx\n",
               regs->gr[30], PARISC_RT_SIGFRAME_SIZE,
-              regs->gr[30] + PARISC_RT_SIGFRAME_SIZE);
-#endif
+              regs->gr[30] + PARISC_RT_SIGFRAME_SIZE));
        /* Raise the user stack pointer to make a proper call frame. */
        regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE);
 
-#if DEBUG_SIG
-       printk("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
+       DBG(("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
               current->comm, current->pid, frame, regs->gr[30],
-              regs->iaoq[0], regs->iaoq[1], rp);
-#endif
+              regs->iaoq[0], regs->iaoq[1], rp));
 
        return 1;
 
 give_sigsegv:
-#if DEBUG_SIG
-       printk("fuckup in setup_rt_frame, sending SIGSEGV\n");
-#endif
+       DBG(("setup_rt_frame sending SIGSEGV\n"));
        if (sig == SIGSEGV)
                ka->sa.sa_handler = SIG_DFL;
        si.si_signo = SIGSEGV;
@@ -437,10 +393,9 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
 {
        struct k_sigaction *ka = &current->sig->action[sig-1];
 
-#if DEBUG_SIG
-       printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
-              sig, ka, info, oldset, regs);
-#endif
+       DBG(("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",
+              sig, ka, info, oldset, regs));
+       
        /* Set up the stack frame */
        if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
                return 0;
@@ -449,11 +404,11 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
                ka->sa.sa_handler = SIG_DFL;
 
        if (!(ka->sa.sa_flags & SA_NODEFER)) {
-               spin_lock_irq(&current->sigmask_lock);
+               spin_lock_irq(&current->sig->siglock);
                sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
                sigaddset(&current->blocked,sig);
                recalc_sigpending();
-               spin_unlock_irq(&current->sigmask_lock);
+               spin_unlock_irq(&current->sig->siglock);
        }
        return 1;
 }
@@ -469,6 +424,7 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
  * registers).  As noted below, the syscall number gets restored for
  * us due to the magic of delayed branching.
  */
+
 asmlinkage int
 do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
 {
@@ -476,10 +432,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
        struct k_sigaction *ka;
        int signr;
 
-#if DEBUG_SIG
-       printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
-              oldset, regs, regs->sr[7], current->sigpending, in_syscall);
-#endif
+       DBG(("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",
+              oldset, regs, regs->sr[7], current->sigpending, in_syscall));
+
        /* Everyone else checks to see if they are in kernel mode at
           this point and exits if that's the case.  I'm not sure why
           we would be called in that case, but for some reason we
@@ -488,9 +443,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
        if (!oldset)
                oldset = &current->blocked;
 
-#if DEBUG_SIG
-       printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]);
-#endif
+       DBG(("do_signal: oldset %08lx:%08lx\n", 
+               oldset->sig[0], oldset->sig[1]));
+
 
        signr = get_signal_to_deliver(&info, regs);
        if (signr > 0) {
@@ -499,18 +454,14 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
                        /* Check the return code */
                        switch (regs->gr[28]) {
                        case -ERESTARTNOHAND:
-#if DEBUG_SIG
-                               printk("ERESTARTNOHAND: returning -EINTR\n");
-#endif
+                               DBG(("ERESTARTNOHAND: returning -EINTR\n"));
                                regs->gr[28] = -EINTR;
                                break;
 
                        case -ERESTARTSYS:
                                ka = &current->sig->action[signr-1];
                                if (!(ka->sa.sa_flags & SA_RESTART)) {
-#if DEBUG_SIG
-                                       printk("ERESTARTSYS: putting -EINTR\n");
-#endif
+                                       DBG(("ERESTARTSYS: putting -EINTR\n"));
                                        regs->gr[28] = -EINTR;
                                        break;
                                }
@@ -529,9 +480,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
                   delivery failed, we need to continue to iterate in
                   this loop so we can deliver the SIGSEGV... */
                if (handle_signal(signr, &info, oldset, regs, in_syscall)) {
-#if DEBUG_SIG
-                       printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]);
-#endif
+                       DBG((KERN_DEBUG
+                               "Exiting do_signal (success), regs->gr[28] = %ld\n",
+                               regs->gr[28]));
                        return 1;
                }
        }
@@ -551,8 +502,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall)
                        regs->gr[28] = regs->orig_r28;
                }
        }
-#if DEBUG_SIG
-       printk("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28]);
-#endif
+       
+       DBG(("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", 
+               regs->gr[28]));
+
        return 0;
 }
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
new file mode 100644 (file)
index 0000000..50dd068
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+** SMP Support
+**
+** Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+** Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+** Copyright (C) 2001 Grant Grundler <grundler@parisc-linux.org>
+** 
+** Lots of stuff stolen from arch/alpha/kernel/smp.c
+** ...and then parisc stole from arch/ia64/kernel/smp.c. Thanks David! :^)
+**
+** Thanks to John Curry and Ullas Ponnadi. I learned alot from their work.
+** -grant (1/12/2001)
+**
+**     This program is free software; you can redistribute it and/or modify
+**     it under the terms of the GNU General Public License as published by
+**      the Free Software Foundation; either version 2 of the License, or
+**      (at your option) any later version.
+*/
+#define __KERNEL_SYSCALLS__
+#undef ENTRY_SYS_CPUS  /* syscall support for iCOD-like functionality */
+
+#include <linux/autoconf.h>
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/current.h>
+#include <asm/delay.h>
+#include <asm/pgalloc.h>       /* for flush_tlb_all() proto/macro */
+
+#include <asm/io.h>
+#include <asm/irq.h>           /* for CPU_IRQ_REGION and friends */
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <asm/cacheflush.h>
+
+#define kDEBUG 0
+
+spinlock_t pa_dbit_lock = SPIN_LOCK_UNLOCKED;
+
+spinlock_t smp_lock = SPIN_LOCK_UNLOCKED;
+
+volatile struct task_struct *smp_init_current_idle_task;
+
+static volatile int smp_commenced = 0;   /* Set when the idlers are all forked */
+static volatile int cpu_now_booting = 0;      /* track which CPU is booting */
+volatile unsigned long cpu_online_map = 0;   /* Bitmap of online CPUs */
+#define IS_LOGGED_IN(cpunum) (test_bit(cpunum, (atomic_t *)&cpu_online_map))
+
+int smp_num_cpus = 1;
+int smp_threads_ready = 0;
+unsigned long cache_decay_ticks;
+static int max_cpus = -1;                           /* Command line */
+unsigned long cpu_present_mask;
+
+struct smp_call_struct {
+       void (*func) (void *info);
+       void *info;
+       long wait;
+       atomic_t unstarted_count;
+       atomic_t unfinished_count;
+};
+static volatile struct smp_call_struct *smp_call_function_data;
+
+enum ipi_message_type {
+       IPI_NOP=0,
+       IPI_RESCHEDULE=1,
+       IPI_CALL_FUNC,
+       IPI_CPU_START,
+       IPI_CPU_STOP,
+       IPI_CPU_TEST
+};
+
+
+/********** SMP inter processor interrupt and communication routines */
+
+#undef PER_CPU_IRQ_REGION
+#ifdef PER_CPU_IRQ_REGION
+/* XXX REVISIT Ignore for now.
+**    *May* need this "hook" to register IPI handler
+**    once we have perCPU ExtIntr switch tables.
+*/
+static void
+ipi_init(int cpuid)
+{
+
+       /* If CPU is present ... */
+#ifdef ENTRY_SYS_CPUS
+       /* *and* running (not stopped) ... */
+#error iCOD support wants state checked here.
+#endif
+
+#error verify IRQ_OFFSET(IPI_IRQ) is ipi_interrupt() in new IRQ region
+
+       if(IS_LOGGED_IN(cpuid) )
+       {
+               switch_to_idle_task(current);
+       }
+
+       return;
+}
+#endif
+
+
+/*
+** Yoink this CPU from the runnable list... 
+**
+*/
+static void
+halt_processor(void) 
+{
+#ifdef ENTRY_SYS_CPUS
+#error halt_processor() needs rework
+/*
+** o migrate I/O interrupts off this CPU.
+** o leave IPI enabled - __cli() will disable IPI.
+** o leave CPU in online map - just change the state
+*/
+       cpu_data[this_cpu].state = STATE_STOPPED;
+       mark_bh(IPI_BH);
+#else
+       /* REVISIT : redirect I/O Interrupts to another CPU? */
+       /* REVISIT : does PM *know* this CPU isn't available? */
+       clear_bit(smp_processor_id(), (void *)&cpu_online_map);
+       local_irq_disable();
+       for (;;)
+               ;
+#endif
+}
+
+
+void
+ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
+{
+       int this_cpu = smp_processor_id();
+       struct cpuinfo_parisc *p = &cpu_data[this_cpu];
+       unsigned long ops;
+       unsigned long flags;
+
+       /* Count this now; we may make a call that never returns. */
+       p->ipi_count++;
+
+       mb();   /* Order interrupt and bit testing. */
+
+       for (;;) {
+               spin_lock_irqsave(&(p->lock),flags);
+               ops = p->pending_ipi;
+               p->pending_ipi = 0;
+               spin_unlock_irqrestore(&(p->lock),flags);
+
+               mb(); /* Order bit clearing and data access. */
+
+               if (!ops)
+                   break;
+
+               while (ops) {
+                       unsigned long which = ffz(~ops);
+
+                       switch (which) {
+                       case IPI_RESCHEDULE:
+#if (kDEBUG>=100)
+                               printk(KERN_DEBUG "CPU%d IPI_RESCHEDULE\n",this_cpu);
+#endif /* kDEBUG */
+                               ops &= ~(1 << IPI_RESCHEDULE);
+                               /*
+                                * Reschedule callback.  Everything to be
+                                * done is done by the interrupt return path.
+                                */
+                               break;
+
+                       case IPI_CALL_FUNC:
+#if (kDEBUG>=100)
+                               printk(KERN_DEBUG "CPU%d IPI_CALL_FUNC\n",this_cpu);
+#endif /* kDEBUG */
+                               ops &= ~(1 << IPI_CALL_FUNC);
+                               {
+                                       volatile struct smp_call_struct *data;
+                                       void (*func)(void *info);
+                                       void *info;
+                                       int wait;
+
+                                       data = smp_call_function_data;
+                                       func = data->func;
+                                       info = data->info;
+                                       wait = data->wait;
+
+                                       mb();
+                                       atomic_dec ((atomic_t *)&data->unstarted_count);
+
+                                       /* At this point, *data can't
+                                        * be relied upon.
+                                        */
+
+                                       (*func)(info);
+
+                                       /* Notify the sending CPU that the
+                                        * task is done.
+                                        */
+                                       mb();
+                                       if (wait)
+                                               atomic_dec ((atomic_t *)&data->unfinished_count);
+                               }
+                               break;
+
+                       case IPI_CPU_START:
+#if (kDEBUG>=100)
+                               printk(KERN_DEBUG "CPU%d IPI_CPU_START\n",this_cpu);
+#endif /* kDEBUG */
+                               ops &= ~(1 << IPI_CPU_START);
+#ifdef ENTRY_SYS_CPUS
+                               p->state = STATE_RUNNING;
+#endif
+                               break;
+
+                       case IPI_CPU_STOP:
+#if (kDEBUG>=100)
+                               printk(KERN_DEBUG "CPU%d IPI_CPU_STOP\n",this_cpu);
+#endif /* kDEBUG */
+                               ops &= ~(1 << IPI_CPU_STOP);
+#ifdef ENTRY_SYS_CPUS
+#else
+                               halt_processor();
+#endif
+                               break;
+
+                       case IPI_CPU_TEST:
+#if (kDEBUG>=100)
+                               printk(KERN_DEBUG "CPU%d is alive!\n",this_cpu);
+#endif /* kDEBUG */
+                               ops &= ~(1 << IPI_CPU_TEST);
+                               break;
+
+                       default:
+                               printk(KERN_CRIT "Unknown IPI num on CPU%d: %lu\n",
+                                       this_cpu, which);
+                               ops &= ~(1 << which);
+                               return;
+                       } /* Switch */
+               } /* while (ops) */
+       }
+       return;
+}
+
+
+static inline void
+ipi_send(int cpu, enum ipi_message_type op)
+{
+       struct cpuinfo_parisc *p = &cpu_data[cpu];
+       unsigned long flags;
+
+       spin_lock_irqsave(&(p->lock),flags);
+       p->pending_ipi |= 1 << op;
+       __raw_writel(IRQ_OFFSET(IPI_IRQ), cpu_data[cpu].hpa);
+       spin_unlock_irqrestore(&(p->lock),flags);
+}
+
+
+static inline void
+send_IPI_single(int dest_cpu, enum ipi_message_type op)
+{
+       if (dest_cpu == NO_PROC_ID) {
+               BUG();
+               return;
+       }
+
+       ipi_send(dest_cpu, op);
+}
+
+static inline void
+send_IPI_allbutself(enum ipi_message_type op)
+{
+       int i;
+       
+       for (i = 0; i < smp_num_cpus; i++) {
+               if (i != smp_processor_id())
+                       send_IPI_single(i, op);
+       }
+}
+
+inline void 
+smp_send_stop(void)    { send_IPI_allbutself(IPI_CPU_STOP); }
+
+static inline void
+smp_send_start(void)   { send_IPI_allbutself(IPI_CPU_START); }
+
+void 
+smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); }
+
+
+/**
+ * Run a function on all other CPUs.
+ *  <func>     The function to run. This must be fast and non-blocking.
+ *  <info>     An arbitrary pointer to pass to the function.
+ *  <retry>    If true, keep retrying until ready.
+ *  <wait>     If true, wait until function has completed on other CPUs.
+ *  [RETURNS]   0 on success, else a negative status code.
+ *
+ * Does not return until remote CPUs are nearly ready to execute <func>
+ * or have executed.
+ */
+
+int
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
+{
+       struct smp_call_struct data;
+       long timeout;
+       static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+       
+       data.func = func;
+       data.info = info;
+       data.wait = wait;
+       atomic_set(&data.unstarted_count, smp_num_cpus - 1);
+       atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+       if (retry) {
+               spin_lock (&lock);
+               while (smp_call_function_data != 0)
+                       barrier();
+       }
+       else {
+               spin_lock (&lock);
+               if (smp_call_function_data) {
+                       spin_unlock (&lock);
+                       return -EBUSY;
+               }
+       }
+
+       smp_call_function_data = &data;
+       spin_unlock (&lock);
+       
+       /*  Send a message to all other CPUs and wait for them to respond  */
+       send_IPI_allbutself(IPI_CALL_FUNC);
+
+       /*  Wait for response  */
+       timeout = jiffies + HZ;
+       while ( (atomic_read (&data.unstarted_count) > 0) &&
+               time_before (jiffies, timeout) )
+               barrier ();
+
+       /* We either got one or timed out. Release the lock */
+
+       mb();
+       smp_call_function_data = NULL;
+       if (atomic_read (&data.unstarted_count) > 0) {
+               printk(KERN_CRIT "SMP CALL FUNCTION TIMED OUT! (cpu=%d)\n",
+                     smp_processor_id());
+               return -ETIMEDOUT;
+       }
+
+       while (wait && atomic_read (&data.unfinished_count) > 0)
+                       barrier ();
+
+       return 0;
+}
+
+
+
+/*
+ *     Setup routine for controlling SMP activation
+ *
+ *     Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ *     activation entirely (the MPS table probe still happens, though).
+ *
+ *     Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ *     greater than 0, limits the maximum number of CPUs activated in
+ *     SMP mode to <NUM>.
+ */
+
+static int __init nosmp(char *str)
+{
+       max_cpus = 0;
+       return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
+{
+       get_option(&str, &max_cpus);
+       return 1;
+}
+
+__setup("maxcpus=", maxcpus);
+
+/*
+ * Flush all other CPU's tlb and then mine.  Do this with smp_call_function()
+ * as we want to ensure all TLB's flushed before proceeding.
+ */
+
+extern void flush_tlb_all_local(void);
+
+void
+smp_flush_tlb_all(void)
+{
+       smp_call_function((void (*)(void *))flush_tlb_all_local, NULL, 1, 1);
+       flush_tlb_all_local();
+}
+
+
+void 
+smp_do_timer(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+       struct cpuinfo_parisc *data = &cpu_data[cpu];
+
+        if (!--data->prof_counter) {
+               data->prof_counter = data->prof_multiplier;
+               update_process_times(user_mode(regs));
+       }
+}
+
+/*
+ * Called by secondaries to update state and initialize CPU registers.
+ */
+static void __init
+smp_cpu_init(int cpunum)
+{
+       extern int init_per_cpu(int);  /* arch/parisc/kernel/setup.c */
+       extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
+
+       /* Set modes and Enable floating point coprocessor */
+       (void) init_per_cpu(cpunum);
+
+       disable_sr_hashing();
+
+       mb();
+
+       /* Well, support 2.4 linux scheme as well. */
+       if (test_and_set_bit(cpunum, (unsigned long *) (&cpu_online_map)))
+       {
+               extern void machine_halt(void); /* arch/parisc.../process.c */
+
+               printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
+               machine_halt();
+       }  
+
+       /* Initialise the idle task for this CPU */
+       atomic_inc(&init_mm.mm_count);
+       current->active_mm = &init_mm;
+       if(current->mm)
+               BUG();
+       enter_lazy_tlb(&init_mm, current, cpunum);
+
+       init_IRQ();   /* make sure no IRQ's are enabled or pending */
+}
+
+
+/*
+ * Slaves start using C here. Indirectly called from smp_slave_stext.
+ * Do what start_kernel() and main() do for boot strap processor (aka monarch)
+ */
+void __init smp_callin(void)
+{
+       extern void cpu_idle(void);     /* arch/parisc/kernel/process.c */
+       int slave_id = cpu_now_booting;
+#if 0
+       void *istack;
+#endif
+
+       smp_cpu_init(slave_id);
+
+#if 0  /* NOT WORKING YET - see entry.S */
+       istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER);
+       if (istack == NULL) {
+           printk(KERN_CRIT "Failed to allocate interrupt stack for cpu %d\n",slave_id);
+           BUG();
+       }
+       mtctl(istack,31);
+#endif
+
+       flush_cache_all_local(); /* start with known state */
+       flush_tlb_all_local();
+
+       local_irq_enable();  /* Interrupts have been off until now */
+
+       /* Slaves wait here until Big Poppa daddy say "jump" */
+       mb();   /* PARANOID */
+       while (!smp_commenced) ;
+       mb();   /* PARANOID */
+
+       cpu_idle();      /* Wait for timer to schedule some work */
+
+       /* NOTREACHED */
+       panic("smp_callin() AAAAaaaaahhhh....\n");
+}
+
+/*
+ * Create the idle task for a new Slave CPU.  DO NOT use kernel_thread()
+ * because that could end up calling schedule(). If it did, the new idle
+ * task could get scheduled before we had a chance to remove it from the
+ * run-queue...
+ */
+static struct task_struct *fork_by_hand(void)
+{
+       struct pt_regs regs;  
+
+       /*
+        * don't care about the regs settings since
+        * we'll never reschedule the forked task.
+        */
+       return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL);
+}
+
+
+/*
+ * Bring one cpu online.
+ */
+static int smp_boot_one_cpu(int cpuid, int cpunum)
+{
+       struct task_struct *idle;
+       long timeout;
+
+       /* 
+        * Create an idle task for this CPU.  Note the address wed* give 
+        * to kernel_thread is irrelevant -- it's going to start
+        * where OS_BOOT_RENDEVZ vector in SAL says to start.  But
+        * this gets all the other task-y sort of data structures set
+        * up like we wish.   We need to pull the just created idle task 
+        * off the run queue and stuff it into the init_tasks[] array.  
+        * Sheesh . . .
+        */
+
+       if ((idle = fork_by_hand()) == 0) 
+               panic("SMP: fork failed for CPU:%d", cpuid);
+
+       init_idle(idle, cpunum);
+       unhash_process(idle);
+       idle->thread_info->cpu = cpunum;
+
+       /* Let _start know what logical CPU we're booting
+       ** (offset into init_tasks[],cpu_data[])
+       */
+       cpu_now_booting = cpunum;
+
+       /* 
+       ** boot strap code needs to know the task address since
+       ** it also contains the process stack.
+       */
+       smp_init_current_idle_task = idle ;
+       mb();
+
+       /*
+       ** This gets PDC to release the CPU from a very tight loop.
+       ** See MEM_RENDEZ comments in head.S.
+       */
+       __raw_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpunum].hpa);
+       mb();
+
+       /* 
+        * OK, wait a bit for that CPU to finish staggering about. 
+        * Slave will set a bit when it reaches smp_cpu_init() and then
+        * wait for smp_commenced to be 1.
+        * Once we see the bit change, we can move on.
+        */
+       for (timeout = 0; timeout < 10000; timeout++) {
+               if(IS_LOGGED_IN(cpunum)) {
+                       /* Which implies Slave has started up */
+                       cpu_now_booting = 0;
+                       smp_init_current_idle_task = NULL;
+                       goto alive ;
+               }
+               udelay(100);
+               barrier();
+       }
+
+       put_task_struct(idle);
+       idle = NULL;
+
+       printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid);
+       return -1;
+
+alive:
+       /* Remember the Slave data */
+#if (kDEBUG>=100)
+       printk(KERN_DEBUG "SMP: CPU:%d (num %d) came alive after %ld _us\n",
+               cpuid,  cpunum, timeout * 100);
+#endif /* kDEBUG */
+#ifdef ENTRY_SYS_CPUS
+       cpu_data[cpunum].state = STATE_RUNNING;
+#endif
+       return 0;
+}
+
+
+
+
+/*
+** inventory.c:do_inventory() has already 'discovered' the additional CPU's.
+** We are ready to wrest them from PDC's control now.
+** Called by smp_init bring all the secondaries online and hold them.  
+**
+** o Setup of the IPI irq handler is done in irq.c.
+** o MEM_RENDEZ is initialzed in head.S:stext()
+**
+*/
+void __init smp_boot_cpus(void)
+{
+       int i, cpu_count = 1;
+       unsigned long bogosum = loops_per_jiffy; /* Count Monarch */
+
+       /* REVISIT - assumes first CPU reported by PAT PDC is BSP */
+       int bootstrap_processor=cpu_data[0].cpuid;      /* CPU ID of BSP */
+
+       /* Setup BSP mappings */
+       printk(KERN_DEBUG "SMP: bootstrap CPU ID is %d\n",bootstrap_processor);
+       init_task.thread_info->cpu = bootstrap_processor; 
+       current->thread_info->cpu = bootstrap_processor;
+       cpu_online_map = 1 << bootstrap_processor; /* Mark Boostrap processor as present */
+       current->active_mm = &init_mm;
+
+#ifdef ENTRY_SYS_CPUS
+       cpu_data[0].state = STATE_RUNNING;
+#endif
+       cpu_present_mask = 1UL << bootstrap_processor;
+
+       /* Nothing to do when told not to.  */
+       if (max_cpus == 0) {
+               printk(KERN_INFO "SMP mode deactivated.\n");
+               return;
+       }
+
+       if (max_cpus != -1) 
+               printk(KERN_INFO "Limiting CPUs to %d\n", max_cpus);
+
+       /* We found more than one CPU.... */
+       if (boot_cpu_data.cpu_count > 1) {
+
+               for (i = 0; i < NR_CPUS; i++) {
+                       if (cpu_data[i].cpuid == NO_PROC_ID || 
+                           cpu_data[i].cpuid == bootstrap_processor)
+                               continue;
+
+                       if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0)
+                               continue;
+
+                       bogosum += loops_per_jiffy;
+                       cpu_count++; /* Count good CPUs only... */
+                       
+                       cpu_present_mask |= 1UL << i;
+                       
+                       /* Bail when we've started as many CPUS as told to */
+                       if (cpu_count == max_cpus)
+                               break;
+               }
+       }
+       if (cpu_count == 1) {
+               printk(KERN_INFO "SMP: Bootstrap processor only.\n");
+       }
+
+       /*
+        * FIXME very rough.
+        */
+       cache_decay_ticks = HZ/100;
+
+       printk(KERN_INFO "SMP: Total %d of %d processors activated "
+              "(%lu.%02lu BogoMIPS noticed) (Present Mask: %lu).\n",
+              cpu_count, boot_cpu_data.cpu_count, (bogosum + 25) / 5000,
+              ((bogosum + 25) / 50) % 100, cpu_present_mask);
+
+       smp_num_cpus = cpu_count;
+#ifdef PER_CPU_IRQ_REGION
+       ipi_init();
+#endif
+       return;
+}
+
+/* 
+ * Called from main.c by Monarch Processor.
+ * After this, any CPU can schedule any task.
+ */
+void smp_commence(void)
+{
+       smp_commenced = 1;
+       mb();
+       return;
+}
+
+/*
+ * XXX FIXME : do nothing
+ */
+void smp_cpus_done(unsigned int cpu_max)
+{
+       smp_threads_ready = 1;
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+       smp_boot_cpus();
+}
+
+int __devinit __cpu_up(unsigned int cpu)
+{
+       return cpu_online(cpu) ? 0 : -ENOSYS;
+}
+
+
+
+#ifdef ENTRY_SYS_CPUS
+/* Code goes along with:
+**    entry.s:        ENTRY_NAME(sys_cpus)   / * 215, for cpu stat * /
+*/
+int sys_cpus(int argc, char **argv)
+{
+       int i,j=0;
+       extern int current_pid(int cpu);
+
+       if( argc > 2 ) {
+               printk("sys_cpus:Only one argument supported\n");
+               return (-1);
+       }
+       if ( argc == 1 ){
+       
+#ifdef DUMP_MORE_STATE
+               for(i=0; i<NR_CPUS; i++) {
+                       int cpus_per_line = 4;
+                       if(IS_LOGGED_IN(i)) {
+                               if (j++ % cpus_per_line)
+                                       printk(" %3d",i);
+                               else
+                                       printk("\n %3d",i);
+                       }
+               }
+               printk("\n"); 
+#else
+               printk("\n 0\n"); 
+#endif
+       } else if((argc==2) && !(strcmp(argv[1],"-l"))) {
+               printk("\nCPUSTATE  TASK CPUNUM CPUID HARDCPU(HPA)\n");
+#ifdef DUMP_MORE_STATE
+               for(i=0;i<NR_CPUS;i++) {
+                       if (!IS_LOGGED_IN(i))
+                               continue;
+                       if (cpu_data[i].cpuid != NO_PROC_ID) {
+                               switch(cpu_data[i].state) {
+                                       case STATE_RENDEZVOUS:
+                                               printk("RENDEZVS ");
+                                               break;
+                                       case STATE_RUNNING:
+                                               printk((current_pid(i)!=0) ? "RUNNING  " : "IDLING   ");
+                                               break;
+                                       case STATE_STOPPED:
+                                               printk("STOPPED  ");
+                                               break;
+                                       case STATE_HALTED:
+                                               printk("HALTED   ");
+                                               break;
+                                       default:
+                                               printk("%08x?", cpu_data[i].state);
+                                               break;
+                               }
+                               if(IS_LOGGED_IN(i)) {
+                                       printk(" %4d",current_pid(i));
+                               }       
+                               printk(" %6d",cpu_number_map(i));
+                               printk(" %5d",i);
+                               printk(" 0x%lx\n",cpu_data[i].hpa);
+                       }       
+               }
+#else
+               printk("\n%s  %4d      0     0 --------",
+                       (current->pid)?"RUNNING ": "IDLING  ",current->pid); 
+#endif
+       } else if ((argc==2) && !(strcmp(argv[1],"-s"))) { 
+#ifdef DUMP_MORE_STATE
+               printk("\nCPUSTATE   CPUID\n");
+               for (i=0;i<NR_CPUS;i++) {
+                       if (!IS_LOGGED_IN(i))
+                               continue;
+                       if (cpu_data[i].cpuid != NO_PROC_ID) {
+                               switch(cpu_data[i].state) {
+                                       case STATE_RENDEZVOUS:
+                                               printk("RENDEZVS");break;
+                                       case STATE_RUNNING:
+                                               printk((current_pid(i)!=0) ? "RUNNING " : "IDLING");
+                                               break;
+                                       case STATE_STOPPED:
+                                               printk("STOPPED ");break;
+                                       case STATE_HALTED:
+                                               printk("HALTED  ");break;
+                                       default:
+                               }
+                               printk("  %5d\n",i);
+                       }       
+               }
+#else
+               printk("\n%s    CPU0",(current->pid==0)?"RUNNING ":"IDLING  "); 
+#endif
+       } else {
+               printk("sys_cpus:Unknown request\n");
+               return (-1);
+       }
+       return 0;
+}
+#endif /* ENTRY_SYS_CPUS */
+
+#ifdef CONFIG_PROC_FS
+int __init
+setup_profiling_timer(unsigned int multiplier)
+{
+       return -EINVAL;
+}
+#endif
diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h
new file mode 100644 (file)
index 0000000..c2e6d50
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _PARISC64_KERNEL_SYS32_H
+#define _PARISC64_KERNEL_SYS32_H
+
+/* Call a kernel syscall which will use kernel space instead of user
+ * space for its copy_to/from_user.
+ */
+#define KERNEL_SYSCALL(ret, syscall, args...) \
+{ \
+    mm_segment_t old_fs = get_fs(); \
+    set_fs(KERNEL_DS); \
+    ret = syscall(args); \
+    set_fs (old_fs); \
+}
+
+struct timeval32 {
+       int tv_sec;
+       int tv_usec;
+};
+
+typedef __u32 __sighandler_t32;
+
+#include <linux/signal.h>
+typedef struct {
+       unsigned int sig[_NSIG_WORDS * 2];
+} sigset_t32;
+
+struct sigaction32 {
+       __sighandler_t32 sa_handler;
+       unsigned int sa_flags;
+       sigset_t32 sa_mask;             /* mask last for extensibility */
+};
+
+#endif
index b8addfe..c89bcc7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/arch/parisc/kernel/sys_parisc.c
  *
- * this implements the missing syscalls.
+ * this implements syscalls which are handled per-arch.
  */
 
 #include <asm/uaccess.h>
 #include <linux/linkage.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/shm.h>
 #include <linux/smp_lock.h>
 
-/* for some reason, "old_readdir" is the only syscall which does not begin
- * with "sys_", which breaks the ENTRY_* macros in syscall.S so I "fixed"
- * it here.
- */
-
-int sys_old_readdir(unsigned int fd, void *dirent, unsigned int count)
-{
-    return old_readdir(fd, dirent, count);
-}
-
 int sys_pipe(int *fildes)
 {
        int fd[2];
        int error;
 
-       lock_kernel();
        error = do_pipe(fd);
-       unlock_kernel();
        if (!error) {
                if (copy_to_user(fildes, fd, 2*sizeof(int)))
                        error = -EFAULT;
@@ -37,40 +26,117 @@ int sys_pipe(int *fildes)
        return error;
 }
 
-int sys_mmap(unsigned long addr, unsigned long len,
-               unsigned long prot, unsigned long flags, unsigned long fd,
-               unsigned long offset)
+static unsigned long get_unshared_area(unsigned long addr, unsigned long len)
 {
-       struct file * file = NULL;
-       int error;
+       struct vm_area_struct *vma;
 
-       down_write(&current->mm->mmap_sem);
-       lock_kernel();
+       if (!addr)
+               addr = TASK_UNMAPPED_BASE;
+       addr = PAGE_ALIGN(addr);
+
+       for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+               /* At this point:  (!vma || addr < vma->vm_end). */
+               if (TASK_SIZE - len < addr)
+                       return -ENOMEM;
+               if (!vma || addr + len <= vma->vm_start)
+                       return addr;
+               addr = vma->vm_end;
+       }
+}
+
+#define DCACHE_ALIGN(addr) (((addr) + (SHMLBA - 1)) &~ (SHMLBA - 1))
+
+static unsigned long get_shared_area(struct inode *inode, unsigned long addr,
+               unsigned long len, unsigned long pgoff)
+{
+       struct vm_area_struct *vma, *first_vma;
+       int offset;
+
+       first_vma = list_entry(inode->i_mapping->i_mmap_shared.next, struct vm_area_struct, shared);
+       offset = (first_vma->vm_start + ((pgoff - first_vma->vm_pgoff) << PAGE_SHIFT)) & (SHMLBA - 1);
+
+       if (!addr)
+               addr = TASK_UNMAPPED_BASE;
+       addr = DCACHE_ALIGN(addr - offset) + offset;
+
+       for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+               /* At this point:  (!vma || addr < vma->vm_end). */
+               if (TASK_SIZE - len < addr)
+                       return -ENOMEM;
+               if (!vma || addr + len <= vma->vm_start)
+                       return addr;
+               addr = DCACHE_ALIGN(vma->vm_end - offset) + offset;
+               if (addr < vma->vm_end) /* handle wraparound */
+                       return -ENOMEM;
+       }
+}
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+               unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+       struct inode *inode = NULL;
+
+       if (len > TASK_SIZE)
+               return -ENOMEM;
+
+       if (filp) {
+               inode = filp->f_dentry->d_inode;
+       }
+
+       if (inode && (flags & MAP_SHARED) && (!list_empty(&inode->i_mapping->i_mmap_shared))) {
+               addr = get_shared_area(inode, addr, len, pgoff);
+       } else {
+               addr = get_unshared_area(addr, len);
+       }
+       return addr;
+}
+
+static unsigned long do_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags, unsigned long fd,
+       unsigned long pgoff)
+{
+       struct file * file = NULL;
+       unsigned long error = -EBADF;
        if (!(flags & MAP_ANONYMOUS)) {
-               error = -EBADF;
                file = fget(fd);
                if (!file)
                        goto out;
        }
+
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-       error = do_mmap(file, addr, len, prot, flags, offset);
+
+       down_write(&current->mm->mmap_sem);
+       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+       up_write(&current->mm->mmap_sem);
+
        if (file != NULL)
                fput(file);
 out:
-       unlock_kernel();
-       up_write(&current->mm->mmap_sem);
        return error;
 }
 
-int sys_ioperm(unsigned long from, unsigned long num, int on)
+asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags, unsigned long fd,
+       unsigned long pgoff)
 {
-       return -ENOSYS;
+       /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
+          we have. */
+       return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+               unsigned long prot, unsigned long flags, unsigned long fd,
+               unsigned long offset)
+{
+       if (!(offset & ~PAGE_MASK)) {
+               return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+       } else {
+               return -EINVAL;
+       }
 }
 
-long sys_shmat_wrapper(int shmid, void *shmaddr, int shmflag)
+long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag)
 {
-       extern int sys_shmat(int shmid, char *shmaddr, int shmflg,
-                            unsigned long * raddr);
        unsigned long raddr;
        int r;
 
@@ -79,3 +145,114 @@ long sys_shmat_wrapper(int shmid, void *shmaddr, int shmflag)
                return r;
        return raddr;
 }
+
+
+/*
+ * FIXME, please remove this crap as soon as possible
+ *
+ * This is here to fix up broken glibc structures, 
+ * which are already fixed in newer glibcs
+ */
+#include <linux/msg.h>
+#include <linux/sem.h>
+#include <linux/shm.h>
+#include "sys32.h"
+
+struct broken_ipc_perm
+{
+    key_t key;                 /* Key.  */
+    uid_t uid;                 /* Owner's user ID.  */
+    gid_t gid;                 /* Owner's group ID.  */
+    uid_t cuid;                        /* Creator's user ID.  */
+    gid_t cgid;                        /* Creator's group ID.  */
+    unsigned short int mode;           /* Read/write permission.  */
+    unsigned short int __pad1;
+    unsigned short int seq;            /* Sequence number.  */
+    unsigned short int __pad2;
+    unsigned long int __unused1;
+    unsigned long int __unused2;
+};
+                   
+struct broken_shmid64_ds {
+       struct broken_ipc_perm  shm_perm;       /* operation perms */
+       size_t                  shm_segsz;      /* size of segment (bytes) */
+#ifndef __LP64__
+       unsigned int            __pad1;
+#endif
+       __kernel_time_t         shm_atime;      /* last attach time */
+#ifndef __LP64__
+       unsigned int            __pad2;
+#endif
+       __kernel_time_t         shm_dtime;      /* last detach time */
+#ifndef __LP64__
+       unsigned int            __pad3;
+#endif
+       __kernel_time_t         shm_ctime;      /* last change time */
+       __kernel_pid_t          shm_cpid;       /* pid of creator */
+       __kernel_pid_t          shm_lpid;       /* pid of last operator */
+       unsigned int            shm_nattch;     /* no. of current attaches */
+       unsigned int            __unused1;
+       unsigned int            __unused2;
+};
+
+static void convert_broken_perm (struct broken_ipc_perm *out, struct ipc64_perm *in)
+{
+       out->key  = in->key;
+       out->uid  = in->uid;
+       out->gid  = in->gid;
+       out->cuid = in->cuid;
+       out->cgid = in->cgid;
+       out->mode = in->mode;
+       out->seq  = in->seq;
+}
+
+static int copyout_broken_shmid64(struct broken_shmid64_ds *buf, struct shmid64_ds *sbuf)
+{
+       struct broken_shmid64_ds tbuf;
+       
+       memset(&tbuf, 0, sizeof tbuf);
+       convert_broken_perm (&tbuf.shm_perm, &sbuf->shm_perm);
+       tbuf.shm_segsz = sbuf->shm_segsz;
+       tbuf.shm_atime = sbuf->shm_atime;
+       tbuf.shm_dtime = sbuf->shm_dtime;
+       tbuf.shm_ctime = sbuf->shm_ctime;
+       tbuf.shm_cpid = sbuf->shm_cpid;
+       tbuf.shm_lpid = sbuf->shm_lpid;
+       tbuf.shm_nattch = sbuf->shm_nattch;
+       return copy_to_user(buf, &tbuf, sizeof tbuf);
+}
+
+int sys_msgctl_broken(int msqid, int cmd, struct msqid_ds *buf)
+{
+       return sys_msgctl (msqid, cmd & ~IPC_64, buf);
+}
+
+int sys_semctl_broken(int semid, int semnum, int cmd, union semun arg)
+{
+       return sys_semctl (semid, semnum, cmd & ~IPC_64, arg);
+}
+
+int sys_shmctl_broken(int shmid, int cmd, struct shmid64_ds *buf)
+{
+       struct shmid64_ds sbuf;
+       int err;
+
+       if (cmd & IPC_64) {
+               cmd &= ~IPC_64;
+               if (cmd == IPC_STAT || cmd == SHM_STAT) {
+                       KERNEL_SYSCALL(err, sys_shmctl, shmid, cmd, (struct shmid_ds *)&sbuf);
+                       if (err == 0)
+                               err = copyout_broken_shmid64((struct broken_shmid64_ds *)buf, &sbuf);
+                       return err;
+               }
+       }
+       return sys_shmctl (shmid, cmd, (struct shmid_ds *)buf);
+}
+
+/*
+ * This changes the io permissions bitmap in the current task.
+ */
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+{
+       return -ENOSYS;
+}
index 3c70143..92356a7 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  * 
  * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
  * Licensed under the GNU GPL.
@@ -7,15 +7,14 @@
  * sorry about the wall, puffin..
  */
 
-#include <asm/offset.h>
+#include <asm/offsets.h>
 #include <asm/unistd.h>
 #include <asm/errno.h>
 #include <asm/psw.h>
+#include <asm/thread_info.h>
 
-#define __ASSEMBLY__
 #include <asm/assembly.h>
 #include <asm/processor.h>
-#include <linux/version.h>
 
 #ifdef __LP64__
        .level          2.0w
        .level          1.1
 #endif
        .text
-       
+
+#ifdef __LP64__
+#define FRAME_SIZE     128
+#else
+#define FRAME_SIZE     64
+#endif
+
        .import syscall_exit,code
        .import syscall_exit_rfi,code
        .export linux_gateway_page
        .align 4096
 linux_gateway_page:
 
+       .rept 56
+       break   0,0
+       .endr
+
+set_thread_pointer:
+       gate    .+8, %r0                /* increase privilege */
+       depi    3, 31, 2, %r31          /* Ensure we return into user mode. */
+       be      0(%sr7,%r31)            /* return to user space */
+       mtctl   %r26, %cr27             /* move arg0 to the control register */
+
+       .rept 4
        break   0,0
+       .endr
 
+/* This address must remain fixed, or user binaries go splat. */
        .align 256
 linux_gateway_entry:
-       mfsp    %sr7,%r1                        /* we must set sr3 to the space */
-       mtsp    %r1,%sr3                        /* of the user before the gate */
        gate    .+8, %r0                        /* become privileged */
        mtsp    %r0,%sr4                        /* get kernel space into sr4 */
        mtsp    %r0,%sr5                        /* get kernel space into sr5 */
        mtsp    %r0,%sr6                        /* get kernel space into sr6 */
-       mtsp    %r0,%sr7                        /* get kernel space into sr7 */
+       mfsp    %sr7,%r1                        /* save user sr7 */
+       mtsp    %r1,%sr3                        /* and store it in sr3 */
+
 #ifdef __LP64__
        /* for now we can *always* set the W bit on entry to the syscall
         * since we don't support wide userland processes.  We could
@@ -58,16 +76,42 @@ linux_gateway_entry:
         * whether to do narrow or wide syscalls. -PB
         */
        ssm     PSW_SM_W, %r0
+       /* The top halves of argument registers must be cleared on syscall
+        * entry.
+        */
+       depdi   0, 31, 32, %r26
+       depdi   0, 31, 32, %r25
+       depdi   0, 31, 32, %r24
+       depdi   0, 31, 32, %r23
+       depdi   0, 31, 32, %r22
+       depdi   0, 31, 32, %r21
 #endif
-       mtctl   %r28,%cr27
-       rsm     PSW_I, %r28                     /* no ints for a bit  */
-       mfctl   %cr30,%r1                       /* get the kernel task ptr */
-       mtctl   %r0,%cr30                       /* zero it (flag) */
+       mfctl   %cr30,%r1
+       xor     %r1,%r30,%r30                   /* ye olde xor trick */
+       xor     %r1,%r30,%r1
+       xor     %r1,%r30,%r30
+       ldo     THREAD_SZ_ALGN+FRAME_SIZE(%r30),%r30  /* set up kernel stack */
+
+       /* N.B.: It is critical that we don't set sr7 to 0 until r30
+        *       contains a valid kernel stack pointer. It is also
+        *       critical that we don't start using the kernel stack
+        *       until after sr7 has been set to 0.
+        */
+
+       mtsp    %r0,%sr7                        /* get kernel space into sr7 */
+       STREG   %r1,0(%r30)                     /* Stick r1 (usp) here for now */
+       mfctl   %cr30,%r1                       /*  get task ptr in %r1 */
+       LDREG   0(%r1),%r1
 
        /* Save some registers for sigcontext and potential task
           switch (see entry.S for the details of which ones are
-          saved/restored) */
+          saved/restored).  TASK_PT_PSW is zeroed so we can see whether
+          a process is on a syscall or not.  For an interrupt the real
+          PSW value is stored.  This is needed for gdb and sys_ptrace. */
+       STREG   %r0,  TASK_PT_PSW(%r1)
        STREG   %r2,  TASK_PT_GR2(%r1)          /* preserve rp */
+       LDREG   0(%r30), %r2                    /* get users sp back */
+       STREG   %r2,  TASK_PT_GR30(%r1)         /* ... and save it */
        STREG   %r19, TASK_PT_GR19(%r1)
        STREG   %r20, TASK_PT_GR20(%r1)
        STREG   %r21, TASK_PT_GR21(%r1)
@@ -77,11 +121,9 @@ linux_gateway_entry:
        STREG   %r25, TASK_PT_GR25(%r1)         /* 2nd argument */
        STREG   %r26, TASK_PT_GR26(%r1)         /* 1st argument */
        STREG   %r27, TASK_PT_GR27(%r1)         /* user dp */
-       mfctl   %cr27,%r19
-       STREG   %r19, TASK_PT_GR28(%r1)         /* return value 0 */
-       STREG   %r19, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
+       STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
+       STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
        STREG   %r29, TASK_PT_GR29(%r1)         /* return value 1 */
-       STREG   %r30, TASK_PT_GR30(%r1)         /* preserve userspace sp */
        STREG   %r31, TASK_PT_GR31(%r1)         /* preserve syscall return ptr */
        
        ldo     TASK_PT_FR0(%r1), %r27          /* save fpregs from the kernel */
@@ -92,27 +134,24 @@ linux_gateway_entry:
 
        loadgp
 
-       ldo     TASK_SZ_ALGN+64(%r1),%r30       /* set up kernel stack */
-
-#ifndef __LP64__
-       /* no need to save these on stack because in wide mode the first 8
+#ifdef __LP64__
+       ldo     -16(%r30),%r29                  /* Reference param save area */
+#else
+       /* no need to save these on stack in wide mode because the first 8
         * args are passed in registers */
        stw     %r22, -52(%r30)                 /* 5th argument */
        stw     %r21, -56(%r30)                 /* 6th argument */
 #endif
 
-       /* for some unknown reason, task_struct.ptrace is an unsigned long so use LDREG */
-       LDREG   TASK_PTRACE(%r1), %r19          /* Are we being ptraced? */
-       mtsm    %r28                            /* irqs back  */
-
-       bb,<,n  %r19, 31, .Ltracesys            /* must match PT_PTRACE bit */
+       mfctl   %cr30, %r1
+       LDREG   TI_FLAGS(%r1), %r19
+       bb,<,n  %r19,31-TIF_SYSCALL_TRACE,.Ltracesys
        
        /* Note!  We cannot use the syscall table that is mapped
        nearby since the gateway page is mapped execute-only. */
 
        ldil    L%sys_call_table, %r1
        ldo     R%sys_call_table(%r1), %r19
-       LDIL_FIXUP(%r19)
        
        comiclr,>>=     __NR_Linux_syscalls, %r20, %r0
        b,n     .Lsyscall_nosys
@@ -131,13 +170,11 @@ linux_gateway_entry:
        comb,=  %r2,%r20,.Lrt_sigreturn
 .Lin_syscall:
        ldil    L%syscall_exit,%r2
-       LDIL_FIXUP(%r2)
        be      0(%sr7,%r19)
        ldo     R%syscall_exit(%r2),%r2
 .Lrt_sigreturn:
        comib,<> 0,%r25,.Lin_syscall
        ldil    L%syscall_exit_rfi,%r2
-       LDIL_FIXUP(%r2)
        be      0(%sr7,%r19)
        ldo     R%syscall_exit_rfi(%r2),%r2
 
@@ -149,7 +186,6 @@ linux_gateway_entry:
 .Lsyscall_nosys:
 syscall_nosys:
        ldil    L%syscall_exit,%r1
-       LDIL_FIXUP(%r1)
        be      R%syscall_exit(%sr7,%r1)
        ldo     -ENOSYS(%r0),%r28                  /* set errno */
 
@@ -159,12 +195,18 @@ syscall_nosys:
 .Ltracesys:
 tracesys:
        /* Need to save more registers so the debugger can see where we
-        * are.
+        * are.  This saves only the lower 8 bits of PSW, so that the C
+        * bit is still clear on syscalls, and the D bit is set if this
+        * full register save path has been executed.  We check the D
+        * bit on syscall_return_rfi to determine which registers to
+        * restore.  An interrupt results in a full PSW saved with the
+        * C bit set, a non-straced syscall entry results in C and D clear
+        * in the saved PSW.
         */
-       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
-       ssm     0,%r2                           /* Lower 8 bits only!! */
-       STREG   %r2,TASK_PT_PSW(%r1)
-       STREG   %r1,TASK_PT_CR30(%r1)
+       ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+       LDREG   0(%r1), %r1
+       ssm     0,%r2
+       STREG   %r2,TASK_PT_PSW(%r1)            /* Lower 8 bits only!! */
        mfsp    %sr0,%r2
        STREG   %r2,TASK_PT_SR0(%r1)
        mfsp    %sr1,%r2
@@ -204,18 +246,16 @@ tracesys:
        /* Finished saving things for the debugger */
 
        ldil    L%syscall_trace,%r1
-       LDIL_FIXUP(%r1)
        ldil    L%tracesys_next,%r2
-       LDIL_FIXUP(%r2)
        be      R%syscall_trace(%sr7,%r1)
        ldo     R%tracesys_next(%r2),%r2
        
 tracesys_next: 
        ldil    L%sys_call_table,%r1
-       LDIL_FIXUP(%r1)
        ldo     R%sys_call_table(%r1), %r19
 
-       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+       LDREG   0(%r1), %r1
        LDREG   TASK_PT_GR20(%r1), %r20
        LDREG   TASK_PT_GR26(%r1), %r26         /* Restore the users args */
        LDREG   TASK_PT_GR25(%r1), %r25
@@ -224,6 +264,7 @@ tracesys_next:
 #ifdef __LP64__
        LDREG   TASK_PT_GR22(%r1), %r22
        LDREG   TASK_PT_GR21(%r1), %r21
+       ldo     -16(%r30),%r29                  /* Reference param save area */
 #endif
 
        comiclr,>>=     __NR_Linux_syscalls, %r20, %r0
@@ -243,7 +284,6 @@ tracesys_next:
        comb,=  %r2,%r20,.Ltrace_rt_sigreturn
 .Ltrace_in_syscall:
        ldil    L%tracesys_exit,%r2
-       LDIL_FIXUP(%r2)
        be      0(%sr7,%r19)
        ldo     R%tracesys_exit(%r2),%r2
 
@@ -251,30 +291,36 @@ tracesys_next:
        makes a direct call to syscall_trace. */
        
 tracesys_exit:
-       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+       LDREG   0(%r1), %r1
+#ifdef __LP64__
+       ldo     -16(%r30),%r29                  /* Reference param save area */
+#endif
        bl      syscall_trace, %r2
        STREG   %r28,TASK_PT_GR28(%r1)          /* save return value now */
-       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+       LDREG   0(%r1), %r1
        LDREG   TASK_PT_GR28(%r1), %r28         /* Restore return val. */
 
        ldil    L%syscall_exit,%r1
-       LDIL_FIXUP(%r1)
        be,n    R%syscall_exit(%sr7,%r1)
 
 .Ltrace_rt_sigreturn:
        comib,<> 0,%r25,.Ltrace_in_syscall
        ldil    L%tracesys_sigexit,%r2
-       LDIL_FIXUP(%r2)
        be      0(%sr7,%r19)
        ldo     R%tracesys_sigexit(%r2),%r2
 
 tracesys_sigexit:
-       ldo     -TASK_SZ_ALGN-64(%r30),%r1      /* get task ptr */
+       ldo     -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
+       LDREG   0(%r1), %r1
+#ifdef __LP64__
+       ldo     -16(%r30),%r29                  /* Reference param save area */
+#endif
        bl      syscall_trace, %r2
        nop
 
        ldil    L%syscall_exit_rfi,%r1
-       LDIL_FIXUP(%r1)
        be,n    R%syscall_exit_rfi(%sr7,%r1)
 
 #ifdef __LP64__
@@ -284,7 +330,7 @@ tracesys_sigexit:
  */
 #define ENTRY_SAME(_name_) .dword sys_##_name_
 #define ENTRY_DIFF(_name_) .dword sys32_##_name_
-#define ENTRY_UHOH(_name_) .dword sys32_unimplemented
+#define ENTRY_UHOH(_name_) .dword sys32_##unimplemented
 #else
 #define ENTRY_SAME(_name_) .word sys_##_name_
 #define ENTRY_DIFF(_name_) .word sys_##_name_
@@ -316,7 +362,7 @@ sys_call_table:
        ENTRY_SAME(socket)
        /* struct stat is MAYBE identical wide and narrow ?? */
        ENTRY_DIFF(newstat)
-       ENTRY_SAME(lseek)
+       ENTRY_DIFF(lseek)
        ENTRY_SAME(getpid)              /* 20 */
        /* the 'void * data' parameter may need re-packing in wide */
        ENTRY_DIFF(mount)
@@ -391,8 +437,8 @@ sys_call_table:
        ENTRY_DIFF(getrlimit)
        ENTRY_DIFF(getrusage)
        /* struct timeval and timezone are maybe?? consistent wide and narrow */
-       ENTRY_SAME(gettimeofday)
-       ENTRY_SAME(settimeofday)
+       ENTRY_DIFF(gettimeofday)
+       ENTRY_DIFF(settimeofday)
        ENTRY_SAME(getgroups)   /* 80 */
        ENTRY_SAME(setgroups)
        /* struct socketaddr... */
@@ -402,12 +448,12 @@ sys_call_table:
        ENTRY_DIFF(newlstat)
        ENTRY_SAME(readlink)    /* 85 */
        /* suspect we'll need some work for narrow shlibs on wide kernel */
+       /* NOTE this doesn't get used when I boot 32-bit userspace */
+       /* containing working shlib apps -- can this be nuked? */
        ENTRY_UHOH(uselib)
        ENTRY_SAME(swapon)
        ENTRY_SAME(reboot)
-       /* argh! struct dirent contains a long */
-       ENTRY_UHOH(old_readdir)
-       /* I'm not certain about off_t... */
+       ENTRY_SAME(mmap2)
        ENTRY_SAME(mmap)                /* 90 */
        ENTRY_SAME(munmap)
        ENTRY_SAME(truncate)
@@ -419,28 +465,27 @@ sys_call_table:
        ENTRY_SAME(recv)
        ENTRY_DIFF(statfs)
        ENTRY_DIFF(fstatfs)             /* 100 */
-       ENTRY_SAME(ni_syscall)
+       ENTRY_SAME(stat64)
        /* don't think hppa glibc even provides an entry pt for this
         * so disable for now */
        ENTRY_UHOH(socketcall)
        ENTRY_SAME(syslog)
        /* even though manpage says struct timeval contains longs, ours has
         * time_t and suseconds_t -- both of which are safe wide/narrow */
-       ENTRY_SAME(setitimer)
-       ENTRY_SAME(getitimer)   /* 105 */
+       ENTRY_DIFF(setitimer)
+       ENTRY_DIFF(getitimer)   /* 105 */
        ENTRY_SAME(capget)
        ENTRY_SAME(capset)
-       ENTRY_SAME(pread)
-       ENTRY_SAME(pwrite)
+       ENTRY_SAME(pread64)
+       ENTRY_SAME(pwrite64)
        ENTRY_SAME(getcwd)              /* 110 */
        ENTRY_SAME(vhangup)
-       ENTRY_SAME(ni_syscall)
+       ENTRY_SAME(fstat64)
        ENTRY_SAME(vfork_wrapper)
        /* struct rusage contains longs... */
        ENTRY_DIFF(wait4)
        ENTRY_SAME(swapoff)             /* 115 */
-       /* struct sysinfo contains longs */
-       ENTRY_SAME(sysinfo)
+       ENTRY_DIFF(sysinfo)
        ENTRY_SAME(shutdown)
        ENTRY_SAME(fsync)
        ENTRY_SAME(madvise)
@@ -450,7 +495,7 @@ sys_call_table:
        /* struct sockaddr... */
        ENTRY_SAME(recvfrom)
        /* struct timex contains longs */
-       ENTRY_UHOH(adjtimex)
+       ENTRY_DIFF(adjtimex)
        ENTRY_SAME(mprotect)    /* 125 */
        /* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
        ENTRY_DIFF(sigprocmask)
@@ -461,12 +506,11 @@ sys_call_table:
        ENTRY_SAME(delete_module)
        /* struct kernel_sym contains a long. Linus never heard of size_t? */
        ENTRY_DIFF(get_kernel_syms)     /* 130 */
-       ENTRY_SAME(quotactl)
+       /* time_t inside struct dqblk */
+       ENTRY_DIFF(quotactl) /* -- FIXME, doesn't work */
        ENTRY_SAME(getpgid)
        ENTRY_SAME(fchdir)
-       /* bdflush(func, addr) where func has least-significant-bit set means
-        * addr is a pointer to long :-( */
-       ENTRY_UHOH(bdflush)
+       ENTRY_SAME(bdflush)
        ENTRY_SAME(sysfs)               /* 135 */
        ENTRY_SAME(personality)
        ENTRY_SAME(ni_syscall)  /* for afs_syscall */
@@ -479,12 +523,12 @@ sys_call_table:
        ENTRY_DIFF(getdents)
        /* it is POSSIBLE that select will be OK because even though fd_set
         * contains longs, the macros and sizes are clever. */
-       ENTRY_SAME(select)
+       ENTRY_DIFF(select)
        ENTRY_SAME(flock)
        ENTRY_SAME(msync)
        /* struct iovec contains pointers */
-       ENTRY_UHOH(readv)               /* 145 */
-       ENTRY_UHOH(writev)
+       ENTRY_DIFF(readv)               /* 145 */
+       ENTRY_DIFF(writev)
        ENTRY_SAME(getsid)
        ENTRY_SAME(fdatasync)
        /* struct __sysctl_args is a mess */
@@ -509,13 +553,12 @@ sys_call_table:
        ENTRY_SAME(mremap)
        ENTRY_SAME(setresuid)
        ENTRY_SAME(getresuid)   /* 165 */
-       /* might work, but in general signals need a thorough review */
-       ENTRY_UHOH(sigaltstack_wrapper)
+       ENTRY_DIFF(sigaltstack_wrapper)
        /* struct passed back to user can contain long symbol values */
        ENTRY_DIFF(query_module)
        ENTRY_SAME(poll)
        /* structs contain pointers and an in_addr... */
-       ENTRY_UHOH(nfsservctl)
+       ENTRY_DIFF(nfsservctl)
        ENTRY_SAME(setresgid)   /* 170 */
        ENTRY_SAME(getresgid)
        ENTRY_SAME(prctl)
@@ -525,36 +568,50 @@ sys_call_table:
        ENTRY_DIFF(rt_sigprocmask)      /* 175 */
        ENTRY_DIFF(rt_sigpending)
        ENTRY_UHOH(rt_sigtimedwait)
-       ENTRY_UHOH(rt_sigqueueinfo)
+       /* even though the struct siginfo_t is different, it appears like
+        * all the paths use values which should be same wide and narrow.
+        * Also the struct is padded to 128 bytes which means we don't have
+        * to worry about faulting trying to copy in a larger 64-bit
+        * struct from a 32-bit user-space app.
+        */
+       ENTRY_SAME(rt_sigqueueinfo)
        ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
        ENTRY_SAME(chown)               /* 180 */
-       /* *sockopt() might work... */
-       ENTRY_SAME(setsockopt)
+       /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
+       ENTRY_DIFF(setsockopt)
        ENTRY_SAME(getsockopt)
-       /* struct msghdr contains pointers... */
-       ENTRY_UHOH(sendmsg)
-       ENTRY_UHOH(recvmsg)
+       ENTRY_DIFF(sendmsg)
+       ENTRY_DIFF(recvmsg)
        ENTRY_SAME(semop)               /* 185 */
        ENTRY_SAME(semget)
-       /* needs a more careful review */
-       ENTRY_UHOH(semctl)
-       /* struct msgbuf contains a long */
-       ENTRY_UHOH(msgsnd)
-       ENTRY_UHOH(msgrcv)
+       ENTRY_DIFF(semctl_broken)
+       ENTRY_DIFF(msgsnd)
+       ENTRY_DIFF(msgrcv)
        ENTRY_SAME(msgget)              /* 190 */
-       /* struct msqid_ds contains pointers */
-       ENTRY_UHOH(msgctl)
+       ENTRY_SAME(msgctl_broken)
        ENTRY_SAME(shmat_wrapper)
        ENTRY_SAME(shmdt)
        ENTRY_SAME(shmget)
-       /***************/
-       /* struct shmid_ds contains pointers */
-       ENTRY_UHOH(shmctl)              /* 195 */
+       ENTRY_SAME(shmctl_broken)               /* 195 */
        ENTRY_SAME(ni_syscall)          /* streams1 */
        ENTRY_SAME(ni_syscall)          /* streams2 */
-       ENTRY_SAME(gettid)
-       ENTRY_SAME(tkill)
-
+       ENTRY_SAME(lstat64)
+       ENTRY_DIFF(truncate64)
+       ENTRY_DIFF(ftruncate64) /* 200 */
+       ENTRY_SAME(getdents64)
+       ENTRY_DIFF(fcntl64)
+#ifdef CONFIG_XFS_FS
+       ENTRY_SAME(attrctl)
+       ENTRY_SAME(acl_get)
+       ENTRY_SAME(acl_set)            /* 205 */
+#else
+       ENTRY_SAME(ni_syscall)
+       ENTRY_SAME(ni_syscall)
+       ENTRY_SAME(ni_syscall)
+#endif
+       ENTRY_SAME(gettid)             
+       ENTRY_SAME(readahead)          
+       ENTRY_SAME(ni_syscall)          /* tkill */
 .end
 
        /* Make sure nothing else is placed on this page */
index e028e6f..2e6274c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/arm/kernel/time.c
+ *  linux/arch/parisc/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
  *  Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King
@@ -10,6 +10,7 @@
  * 1998-12-20  Updated NTP code according to technical memorandum Jan '96
  *             "A Kernel Model for Precision Timekeeping" by Dave Mills
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -20,6 +21,7 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/profile.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
 u64 jiffies_64;
 
+/* xtime and wall_jiffies keep wall-clock time */
+extern unsigned long wall_jiffies;
 extern rwlock_t xtime_lock;
 
-static int timer_value;
-static int timer_delta;
-static struct pdc_tod tod_data __attribute__((aligned(8)));
+static long clocktick; /* timer cycles per tick */
+static long halftick;
 
-void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#ifdef CONFIG_SMP
+extern void smp_do_timer(struct pt_regs *regs);
+#endif
+
+static inline void
+parisc_do_profile(unsigned long pc)
 {
-       int old;
-       int lost = 0;
-       int cr16;
-       
-       old = timer_value;
+       extern char _stext;
+
+       if (!prof_buffer)
+               return;
+
+       pc -= (unsigned long) &_stext;
+       pc >>= prof_shift;
+       /*
+        * Don't ignore out-of-bounds PC values silently,
+        * put them into the last histogram slot, so if
+        * present, they will show up as a sharp peak.
+        */
+       if (pc > prof_len - 1)
+               pc = prof_len - 1;
+       atomic_inc((atomic_t *)&prof_buffer[pc]);
+}
 
-       cr16 = mfctl(16);
-       while((timer_value - cr16) < (timer_delta / 2)) {
-               timer_value += timer_delta;
-               lost++;
+void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       long now = mfctl(16);
+       long next_tick;
+       int nticks;
+       int cpu = smp_processor_id();
+
+       /* initialize next_tick to time at last clocktick */
+
+       next_tick = cpu_data[cpu].it_value;
+
+       /* since time passes between the interrupt and the mfctl()
+        * above, it is never true that last_tick + clocktick == now.  If we
+        * never miss a clocktick, we could set next_tick = last_tick + clocktick
+        * but maybe we'll miss ticks, hence the loop.
+        *
+        * Variables are *signed*.
+        */
+
+       nticks = 0;
+       while((next_tick - now) < halftick) {
+               next_tick += clocktick;
+               nticks++;
+       }
+       mtctl(next_tick, 16);
+       cpu_data[cpu].it_value = next_tick;
+
+       while (nticks--) {
+#ifdef CONFIG_SMP
+               smp_do_timer(regs);
+#endif
+               if (cpu == 0) {
+                       write_lock(&xtime_lock);
+#ifndef CONFIG_SMP
+                       extern int pc_in_user_space;
+                       if (!user_mode(regs))
+                               parisc_do_profile(regs->iaoq[0]);
+                       else
+                               parisc_do_profile((unsigned long)&pc_in_user_space);
+#endif
+                       do_timer(regs);
+                       write_unlock(&xtime_lock);
+               }
        }
-
-       mtctl(timer_value ,16);
-
-       do_timer(regs);
     
-       led_interrupt_func();
+#ifdef CONFIG_CHASSIS_LCD_LED
+       /* Only schedule the led tasklet on cpu 0, and only if it
+        * is enabled.
+        */
+       if (cpu == 0 && !atomic_read(&led_tasklet.count))
+               tasklet_schedule(&led_tasklet);
+#endif
+
+       /* check soft power switch status */
+       if (cpu == 0 && !atomic_read(&power_tasklet.count))
+               tasklet_schedule(&power_tasklet);
 }
 
-void do_gettimeofday(struct timeval *tv)
+/*** converted from ia64 ***/
+/*
+ * Return the number of micro-seconds that elapsed since the last
+ * update to wall time (aka xtime aka wall_jiffies).  The xtime_lock
+ * must be at least read-locked when calling this routine.
+ */
+static inline unsigned long
+gettimeoffset (void)
 {
-       unsigned long flags;
-       
+#ifndef CONFIG_SMP
+       /*
+        * FIXME: This won't work on smp because jiffies are updated by cpu 0.
+        *    Once parisc-linux learns the cr16 difference between processors,
+        *    this could be made to work.
+        */
+       long last_tick;
+       long elapsed_cycles;
+
+       /* it_value is the intended time of the next tick */
+       last_tick = cpu_data[smp_processor_id()].it_value;
+
+       /* Subtract one tick and account for possible difference between
+        * when we expected the tick and when it actually arrived.
+        * (aka wall vs real)
+        */
+       last_tick -= clocktick * (jiffies - wall_jiffies + 1);
+       elapsed_cycles = mfctl(16) - last_tick;
+
+       /* the precision of this math could be improved */
+       return elapsed_cycles / (PAGE0->mem_10msec / 10000);
+#else
+       return 0;
+#endif
+}
+
+void
+do_gettimeofday (struct timeval *tv)
+{
+       unsigned long flags, usec, sec;
+
        read_lock_irqsave(&xtime_lock, flags);
-       tv->tv_sec = xtime.tv_sec;
-       tv->tv_usec = xtime.tv_usec;
+       {
+               usec = gettimeoffset();
+       
+               sec = xtime.tv_sec;
+               usec += (xtime.tv_nsec / 1000);
+       }
        read_unlock_irqrestore(&xtime_lock, flags);
 
+       while (usec >= 1000000) {
+               usec -= 1000000;
+               ++sec;
+       }
+
+       tv->tv_sec = sec;
+       tv->tv_usec = usec;
 }
 
-void do_settimeofday(struct timeval *tv)
+void
+do_settimeofday (struct timeval *tv)
 {
        write_lock_irq(&xtime_lock);
-       xtime.tv_sec = tv->tv_sec;
-       xtime.tv_usec = tv->tv_usec;
+       {
+               /*
+                * This is revolting. We need to set "xtime"
+                * correctly. However, the value in this location is
+                * the value at the most recent update of wall time.
+                * Discover what correction gettimeofday would have
+                * done, and then undo it!
+                */
+               tv->tv_usec -= gettimeoffset();
+               tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+
+               while (tv->tv_usec < 0) {
+                       tv->tv_usec += 1000000;
+                       tv->tv_sec--;
+               }
+
+               xtime.tv_sec = tv->tv_sec;
+               xtime.tv_nsec = (tv->tv_usec * 1000);
+               time_adjust = 0;                /* stop active adjtime() */
+               time_status |= STA_UNSYNC;
+               time_maxerror = NTP_PHASE_LIMIT;
+               time_esterror = NTP_PHASE_LIMIT;
+       }
        write_unlock_irq(&xtime_lock);
 }
 
+
 void __init time_init(void)
 {
-       timer_delta = (100 * PAGE0->mem_10msec) / HZ;
+       unsigned long next_tick;
+       static struct pdc_tod tod_data;
+
+       clocktick = (100 * PAGE0->mem_10msec) / HZ;
+       halftick = clocktick / 2;
 
-       /* make the first timer interrupt go off in one second */
-       timer_value = mfctl(16) + (HZ * timer_delta);
-       mtctl(timer_value, 16);
+       /* Setup clock interrupt timing */
 
+       next_tick = mfctl(16);
+       next_tick += clocktick;
+       cpu_data[smp_processor_id()].it_value = next_tick;
+
+       /* kick off Itimer (CR16) */
+       mtctl(next_tick, 16);
 
        if(pdc_tod_read(&tod_data) == 0) {
+               write_lock_irq(&xtime_lock);
                xtime.tv_sec = tod_data.tod_sec;
-               xtime.tv_usec = tod_data.tod_usec;
+               xtime.tv_nsec = tod_data.tod_usec * 1000;
+               write_unlock_irq(&xtime_lock);
        } else {
                printk(KERN_ERR "Error reading tod clock\n");
                xtime.tv_sec = 0;
-               xtime.tv_usec = 0;
+               xtime.tv_nsec = 0;
        }
-
 }
-
index 67e0466..f108dbc 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/console.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/unaligned.h>
 #include <asm/atomic.h>
-
 #include <asm/smp.h>
 #include <asm/pdc.h>
+#include <asm/pdc_chassis.h>
 
-#ifdef CONFIG_KWDB
-#include <kdb/break.h>         /* for BI2_KGDB_GDB */
-#include <kdb/kgdb_types.h>    /* for __() */
-#include <kdb/save_state.h>    /* for struct save_state */
-#include <kdb/kgdb_machine.h>  /* for pt_regs_to_ssp and ssp_to_pt_regs */
-#include <kdb/trap.h>          /* for I_BRK_INST */
-#endif /* CONFIG_KWDB */
+#include "../math-emu/math-emu.h"      /* for handle_fpe() */
 
+#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
+                         /*  dumped to the console via printk)          */
 
-static inline void console_verbose(void)
-{
-       extern int console_loglevel;
-       console_loglevel = 15;
-}
-
-
-void page_exception(void);
-
-/*
- * These constants are for searching for possible module text
- * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
-
-static void printbinary(unsigned long x, int nbits)
+static int printbinary(char *buf, unsigned long x, int nbits)
 {
        unsigned long mask = 1UL << (nbits - 1);
        while (mask != 0) {
-               printk(mask & x ? "1" : "0");
+               *buf++ = (mask & x ? '1' : '0');
                mask >>= 1;
        }
+       *buf = '\0';
+
+       return nbits;
 }
 
-void show_regs(struct pt_regs *regs)
-{
-       int i;
 #ifdef __LP64__
-#define RFMT " %016lx"
+#define RFMT "%016lx"
 #else
-#define RFMT " %08lx"
+#define RFMT "%08lx"
 #endif
 
-       printk("\n"); /* don't want to have that pretty register dump messed up */
+void show_regs(struct pt_regs *regs)
+{
+       int i;
+       char buf[128], *p;
+       char *level;
+       unsigned long cr30;
+       unsigned long cr31;
+
+       level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT;
+
+       printk("%s\n", level); /* don't want to have that pretty register dump messed up */
 
-       printk("     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\nPSW: ");
-       printbinary(regs->gr[0], 32);
-       printk("    %s\n", print_tainted());
+       printk("%s     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
+       printbinary(buf, regs->gr[0], 32);
+       printk("%sPSW: %s %s\n", level, buf, print_tainted());
 
        for (i = 0; i < 32; i += 4) {
                int j;
-               printk("r%d-%d\t", i, i + 3);
+               p = buf;
+               p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3);
                for (j = 0; j < 4; j++) {
-                       printk(RFMT, i + j == 0 ? 0 : regs->gr[i + j]);
+                       p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]);
                }
-               printk("\n");
+               printk("%s\n", buf);
        }
 
        for (i = 0; i < 8; i += 4) {
                int j;
-               printk("sr%d-%d\t", i, i + 4);
+               p = buf;
+               p += sprintf(p, "%ssr%d-%d  ", level, i, i + 3);
                for (j = 0; j < 4; j++) {
-                       printk(RFMT, regs->sr[i + j]);
+                       p += sprintf(p, " " RFMT, regs->sr[i + j]);
                }
-               printk("\n");
+               printk("%s\n", buf);
        }
 
-#if REDICULOUSLY_VERBOSE
-       for (i = 0; i < 32; i++) {
-               printk("FR%2d : %016lx  ", i, regs->fr[i]);
-               if ((i & 1) == 1)
-                       printk("\n");
+#if RIDICULOUSLY_VERBOSE
+       for (i = 0; i < 32; i += 2)
+               printk("%sFR%02d : %016lx  FR%2d : %016lx", level, i,
+                               regs->fr[i], i+1, regs->fr[i+1]);
+#endif
+
+       cr30 = mfctl(30);
+       cr31 = mfctl(31);
+       printk("%s\n", level);
+       printk("%sIASQ: " RFMT " " RFMT " IAOQ: " RFMT " " RFMT "\n",
+              level, regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
+       printk("%s IIR: %08lx    ISR: " RFMT "  IOR: " RFMT "\n",
+              level, regs->iir, regs->isr, regs->ior);
+       printk("%s CPU: %8d   CR30: " RFMT " CR31: " RFMT "\n",
+              level, current_thread_info()->cpu, cr30, cr31);
+       printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
+}
+
+
+void dump_stack(void)
+{
+       unsigned long stack;
+       show_trace(&stack);
+}
+
+
+static int kstack_depth_to_print = 48;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+#ifdef CONFIG_MODULES
+       struct module *mod;
+#endif
+       extern char _stext, _etext;
+
+       if (addr >= (unsigned long) &_stext &&
+           addr <= (unsigned long) &_etext)
+               return 1;
+
+#ifdef CONFIG_MODULES
+       for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+               /* mod_bound tests for addr being inside the vmalloc'ed
+                * module area. Of course it'd be better to test only
+                * for the .text subset... */
+               if (mod_bound(addr, 0, mod))
+                       return 1;
        }
 #endif
 
-       printk("\nIASQ:" RFMT RFMT " IAOQ:" RFMT RFMT "\n",
-              regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
-       printk(" IIR: %08lx    ISR:" RFMT "  IOR:" RFMT "\nORIG_R28:" RFMT
-              "\n", regs->iir, regs->isr, regs->ior, regs->orig_r28);
+       return 0;
+}
+
+void show_stack(unsigned long *sp)
+{
+       unsigned long *stack;
+       int i;
+
+       /*
+        * debugging aid: "show_stack(NULL);" prints the
+        * back trace for this cpu.
+        */
+       if (sp==NULL)
+               sp = (unsigned long*)&sp;
+
+       stack = sp;
+       printk("\n" KERN_CRIT "Stack Dump:\n");
+       printk(KERN_CRIT " " RFMT ":  ", (unsigned long) stack);
+       for (i=0; i < kstack_depth_to_print; i++) {
+               if (((long) stack & (THREAD_SIZE-1)) == 0)
+                       break;
+               if (i && ((i & 0x03) == 0))
+                       printk("\n" KERN_CRIT " " RFMT ":  ",
+                               (unsigned long) stack);
+               printk(RFMT " ", *stack--);
+       }
+       printk("\n" KERN_CRIT "\n");
+       show_trace(sp);
 }
 
-void
-die_if_kernel (char *str, struct pt_regs *regs, long err)
+
+void show_trace(unsigned long *stack)
 {
+       unsigned long *startstack;
+       unsigned long addr;
+       int i;
+
+       startstack = (unsigned long *)((unsigned long)stack & ~(THREAD_SIZE - 1));
+       i = 1;
+       printk("Kernel addresses on the stack:\n");
+       while (stack >= startstack) {
+               addr = *stack--;
+               /*
+                * If the address is either in the text segment of the
+                * kernel, or in the region which contains vmalloc'ed
+                * memory, it *may* be the address of a calling
+                * routine; if so, print it so that someone tracing
+                * down the cause of the crash will be able to figure
+                * out the call path that was taken.
+                */
+               if (kernel_text_address(addr)) {
+                       printk(" [<" RFMT ">] ", addr);
+#ifdef CONFIG_KALLSYMS
+                       print_symbol("%s\n", addr);
+#else
+                       if ((i & 0x03) == 0)
+                               printk("\n");
+#endif
+                       i++;
+               }
+       }
+       printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+       show_trace((unsigned long *)tsk->thread.regs.ksp);
+}
+
+void die_if_kernel(char *str, struct pt_regs *regs, long err)
+{
+       /* Amuse the user in a SPARC fashion */
+       printk(
+"      _______________________________ \n"
+"     < Your System ate a SPARC! Gah! >\n"
+"      ------------------------------- \n"
+"             \\   ^__^\n"
+"              \\  (xx)\\_______\n"
+"                 (__)\\       )\\/\\\n"
+"                  U  ||----w |\n"
+"                     ||     ||\n");
+
        if (user_mode(regs)) {
-#if 1
+#ifdef PRINT_USER_FAULTS
                if (err == 0)
                        return; /* STFU */
 
                /* XXX for debugging only */
-               printk ("!!die_if_kernel: %s(%d): %s %ld\n",
+               printk(KERN_DEBUG "%s (pid %d): %s (code %ld)\n",
                        current->comm, current->pid, str, err);
                show_regs(regs);
 #endif
                return;
        }
-
-       printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
-
+       
+       /* unlock the pdc lock if necessary */
+       pdc_emergency_unlock();
+
+       /* maybe the kernel hasn't booted very far yet and hasn't been able 
+        * to initialize the serial or STI console. In that case we should 
+        * re-enable the pdc console, so that the user will be able to 
+        * identify the problem. */
+       if (!console_drivers)
+               pdc_console_restart();
+       
+       printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
+               current->comm, current->pid, str, err);
        show_regs(regs);
 
        /* Wot's wrong wif bein' racy? */
        if (current->thread.flags & PARISC_KERNEL_DEATH) {
-               printk("die_if_kernel recursion detected.\n");
-               sti();
+               printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
+               local_irq_enable();
                while (1);
        }
+
        current->thread.flags |= PARISC_KERNEL_DEATH;
        do_exit(SIGSEGV);
 }
 
-asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
-{
-}
-
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
-{
-}
-
-#ifndef CONFIG_MATH_EMULATION
-
-asmlinkage void math_emulate(long arg)
-{
-}
-
-#endif /* CONFIG_MATH_EMULATION */
-
 int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs)
 {
        return syscall(regs);
 }
 
-struct {
-       int retval;
-
-       int (*func) (void *, struct pt_regs *);
-       void * data;
-} ipi_action[NR_CPUS];
-
-void ipi_interrupt(int irq, void *unused, struct pt_regs *regs)
-{
-       int cpu = smp_processor_id();
-
-       if(!ipi_action[cpu].func)
-               BUG();
-
-       ipi_action[cpu].retval =
-               ipi_action[cpu].func(ipi_action[cpu].data, regs);
-}
-
 /* gdb uses break 4,8 */
 #define GDB_BREAK_INSN 0x10004
 void handle_gdb_break(struct pt_regs *regs, int wot)
@@ -199,19 +287,17 @@ void handle_gdb_break(struct pt_regs *regs, int wot)
 void handle_break(unsigned iir, struct pt_regs *regs)
 {
        struct siginfo si;
-#ifdef CONFIG_KWDB
-       struct save_state ssp;
-#endif /* CONFIG_KWDB */   
 
-       flush_all_caches();
        switch(iir) {
        case 0x00:
-               /* show registers, halt */
-               cli();
-               printk("break 0,0: pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+               printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n",
                       current->pid, current->comm);
+#endif
                die_if_kernel("Breakpoint", regs, 0);
+#ifdef PRINT_USER_FAULTS
                show_regs(regs);
+#endif
                si.si_code = TRAP_BRKPT;
                si.si_addr = (void *) (regs->iaoq[0] & ~3);
                si.si_signo = SIGTRAP;
@@ -223,33 +309,12 @@ void handle_break(unsigned iir, struct pt_regs *regs)
                handle_gdb_break(regs, TRAP_BRKPT);
                break;
 
-#ifdef CONFIG_KWDB
-
-       case KGDB_BREAK_INSN:
-               mtctl(0, 15);
-               pt_regs_to_ssp(regs, &ssp);
-               kgdb_trap(I_BRK_INST, &ssp, 1);
-               ssp_to_pt_regs(&ssp, regs);
-               break;
-
-       case KGDB_INIT_BREAK_INSN:
-               mtctl(0, 15);
-               pt_regs_to_ssp(regs, &ssp);
-               kgdb_trap(I_BRK_INST, &ssp, 1);
-               ssp_to_pt_regs(&ssp, regs);
-
-               /* Advance pcoq to skip break */
-               regs->iaoq[0] = regs->iaoq[1];
-               regs->iaoq[1] += 4;
-               break;
-
-#endif /* CONFIG_KWDB */
-
        default:
-               set_eiem(0);
-               printk("break %#08x: pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+               printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
                       iir, current->pid, current->comm);
                show_regs(regs);
+#endif
                si.si_signo = SIGTRAP;
                si.si_code = TRAP_BRKPT;
                si.si_addr = (void *) (regs->iaoq[0] & ~3);
@@ -258,336 +323,285 @@ void handle_break(unsigned iir, struct pt_regs *regs)
        }
 }
 
-/* Format of the floating-point exception registers. */
-struct exc_reg {
-       unsigned int exception : 6;
-       unsigned int ei : 26;
-};
-
-/* Macros for grabbing bits of the instruction format from the 'ei'
-   field above. */
-/* Major opcode 0c and 0e */
-#define FP0CE_UID(i) (((i) >> 6) & 3)
-#define FP0CE_CLASS(i) (((i) >> 9) & 3)
-#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
-#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
-#define FP0C_FORMAT(i) (((i) >> 11) & 3)
-#define FP0E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 0c, uid 2 (performance monitoring) */
-#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
-
-/* Major opcode 2e (fused operations).   */
-#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
-#define FP2E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 26 (FMPYSUB) */
-/* Major opcode 06 (FMPYADD) */
-#define FPx6_FORMAT(i) ((i) & 0x1f)
-
-/* Flags and enable bits of the status word. */
-#define FPSW_FLAGS(w) ((w) >> 27)
-#define FPSW_ENABLE(w) ((w) & 0x1f)
-#define FPSW_V (1<<4)
-#define FPSW_Z (1<<3)
-#define FPSW_O (1<<2)
-#define FPSW_U (1<<1)
-#define FPSW_I (1<<0)
-
-/* Emulate a floating point instruction if necessary and possible
-   (this will be moved elsewhere eventually).  Return zero if
-   successful or if emulation was not required, -1 if the instruction
-   is actually illegal or unimplemented.  The status word passed as
-   the first parameter will be modified to signal exceptions, if
-   any. */
-
-/* FIXME!!!  This is really incomplete and, at the moment, most
-   illegal FP instructions will simply act as no-ops.  Obviously that
-   is *not* what we want.  Also we don't even try to handle exception
-   types other than the 'unimplemented' ones. */
-int
-fp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs)
-{
-       switch (exc.exception) {
-       case 0x3:  /* Unimplemented, opcode 06 */
-               break;
-       case 0x9:  /* Unimplemented, opcode 0c */
-               /* We do not support quadword operations, end of
-                   story.  There's no support for them in GCC. */
-               if (FP0C_FORMAT(exc.ei) == 3)
-                       return -1; /* SIGILL */
-               /* Fall through. */
-       case 0xa:  /* Unimplemented, opcode 0e */
-               if (FP0CE_CLASS(exc.ei) == 1) {
-                       /* FCNV instructions of various sorts. */
-               } else {
-                       if (FP0CE_CLASS(exc.ei == 0)
-                           && FP0CE_SUBOP(exc.ei == 5)) {
-                               /* FRND instructions should be
-                                   emulated, at some point, I
-                                   guess. */
-                               return -1; /* SIGILL */
-                       }
-               }
-               break;
-       case 0x23: /* Unimplemented, opcode 26 */
-               break;
-       case 0x2b: /* Unimplemented, opcode 2e */
-               break;
-       case 0x1:  /* Unimplemented, opcode 0e/0c */
-               /* FIXME: How the hell are we supposed to tell which
-                   opcode it is? */
-               break;
-       default:
-               return -1; /* Punt */
-       }
 
+int handle_toc(void)
+{
+       printk(KERN_CRIT "TOC call.\n");
        return 0;
 }
 
-/* Handle a floating point exception.  Return zero if the faulting
-   instruction can be completed successfully. */
-int
-handle_fpe(struct pt_regs *regs)
+static void default_trap(int code, struct pt_regs *regs)
 {
-       struct siginfo si;
-       union {
-               struct fpsw {
-                       /* flag bits */
-                       unsigned int fv : 1;
-                       unsigned int fz : 1;
-                       unsigned int fo : 1;
-                       unsigned int fu : 1;
-                       unsigned int fi : 1;
-
-                       unsigned int c : 1;
-                       unsigned int pad1 : 4;
-                       unsigned int cq : 11;
-                       unsigned int rm : 2;
-                       unsigned int pad2 : 2;
-                       unsigned int t : 1;
-                       unsigned int d : 1;
-
-                       /* enable bits */
-                       unsigned int ev : 1;
-                       unsigned int ez : 1;
-                       unsigned int eo : 1;
-                       unsigned int eu : 1;
-                       unsigned int ei : 1;
-               } status;
-               u32 word;
-       } sw;
-       struct exc_reg excepts[7];
-       unsigned int code = 0;
-       unsigned int throw;
-
-       /* Status word = FR0L. */
-       memcpy(&sw, regs->fr, sizeof(sw));
-       /* Exception words = FR0R-FR3R. */
-       memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts));
-
-       /* This is all CPU dependent.  Since there is no public
-           documentation on the PA2.0 processors we will just assume
-           everything is like the 7100/7100LC/7300LC for now.
-
-          Specifically: All exceptions are marked as "unimplemented"
-          in the exception word, and the only exception word used is
-          excepts[1]. */
-
-       /* Try to emulate the instruction.  Also determine if it is
-           really an illegal instruction in the process.
-
-          FIXME: fp_emul_insn() only checks for the "unimplemented"
-          exceptions at the moment.  So this may break horribly on
-          PA2.0, where we may want to also check to see if we should
-          just send SIGFPE (or maybe not, let's see the documentation
-          first...) */
-       if (fp_emul_insn(&sw.word, excepts[1], regs) == -1)
-               goto send_sigill;
-
-       /* Take the intersection of the flag bits in the FPSW and the
-           enable bits in the FPSW. */
-       throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word);
-
-       /* Concoct an appropriate si_code.  Of course we don't know
-           what to do if multiple exceptions were enabled and multiple
-           flags were set.  Maybe that's why HP/UX doesn't implement
-           feenableexcept(). */
-
-       if (throw == 0)
-               goto success; /* Duh. */
-       else if (throw & FPSW_V)
-               code = FPE_FLTINV;
-       else if (throw & FPSW_Z)
-               code = FPE_FLTDIV;
-       else if (throw & FPSW_O)
-               code = FPE_FLTOVF;
-       else if (throw & FPSW_U)
-               code = FPE_FLTUND;
-       else if (throw & FPSW_I)
-               code = FPE_FLTRES;
-
-#if 1 /* Debugging... */
-       printk("Unemulated floating point exception, pid=%d (%s)\n",
-              current->pid, current->comm);
+       printk(KERN_ERR "Trap %d on CPU %d\n", code, smp_processor_id());
        show_regs(regs);
-       {
-               int i;
-               printk("FP Status: %08x\n", sw.word);
-               printk("FP Exceptions:\n");
-               for (i = 0; i < 7; i++) {
-                       printk("\tExcept%d: exception %03x insn %06x\n",
-                              i, excepts[i].exception, excepts[i].ei);
-               }
-       }
-#endif
+}
 
-       /* FIXME: Should we clear the flag bits, T bit, and exception
-           registers here? */
+void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
 
-       si.si_signo = SIGFPE;
-       si.si_errno = 0;
-       si.si_code = code;
-       si.si_addr = (void *) regs->iaoq[0];
-       force_sig_info(SIGFPE, &si, current);
-       return -1;
 
- send_sigill:
-       si.si_signo = SIGILL;
-       si.si_errno = 0;
-       si.si_code = ILL_COPROC;
-       si.si_addr = (void *) regs->iaoq[0];
-       force_sig_info(SIGILL, &si, current);
-       return -1;
-
- success:
-       /* We absolutely have to clear the T bit and exception
-           registers to allow the process to recover.  Otherwise every
-           subsequent floating point instruction will trap. */
-       sw.status.t = 0;
-       memset(excepts, 0, sizeof(excepts));
-
-       memcpy(regs->fr, &sw, sizeof(sw));
-       memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts));
-       return 0;
-}
-
-int handle_toc(void)
+void transfer_pim_to_trap_frame(struct pt_regs *regs)
 {
-       return 0;
+    register int i;
+    extern unsigned int hpmc_pim_data[];
+    struct pdc_hpmc_pim_11 *pim_narrow;
+    struct pdc_hpmc_pim_20 *pim_wide;
+
+    if (boot_cpu_data.cpu_type >= pcxu) {
+
+       pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
+
+       /*
+        * Note: The following code will probably generate a
+        * bunch of truncation error warnings from the compiler.
+        * Could be handled with an ifdef, but perhaps there
+        * is a better way.
+        */
+
+       regs->gr[0] = pim_wide->cr[22];
+
+       for (i = 1; i < 32; i++)
+           regs->gr[i] = pim_wide->gr[i];
+
+       for (i = 0; i < 32; i++)
+           regs->fr[i] = pim_wide->fr[i];
+
+       for (i = 0; i < 8; i++)
+           regs->sr[i] = pim_wide->sr[i];
+
+       regs->iasq[0] = pim_wide->cr[17];
+       regs->iasq[1] = pim_wide->iasq_back;
+       regs->iaoq[0] = pim_wide->cr[18];
+       regs->iaoq[1] = pim_wide->iaoq_back;
+
+       regs->sar  = pim_wide->cr[11];
+       regs->iir  = pim_wide->cr[19];
+       regs->isr  = pim_wide->cr[20];
+       regs->ior  = pim_wide->cr[21];
+    }
+    else {
+       pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
+
+       regs->gr[0] = pim_narrow->cr[22];
+
+       for (i = 1; i < 32; i++)
+           regs->gr[i] = pim_narrow->gr[i];
+
+       for (i = 0; i < 32; i++)
+           regs->fr[i] = pim_narrow->fr[i];
+
+       for (i = 0; i < 8; i++)
+           regs->sr[i] = pim_narrow->sr[i];
+
+       regs->iasq[0] = pim_narrow->cr[17];
+       regs->iasq[1] = pim_narrow->iasq_back;
+       regs->iaoq[0] = pim_narrow->cr[18];
+       regs->iaoq[1] = pim_narrow->iaoq_back;
+
+       regs->sar  = pim_narrow->cr[11];
+       regs->iir  = pim_narrow->cr[19];
+       regs->isr  = pim_narrow->cr[20];
+       regs->ior  = pim_narrow->cr[21];
+    }
+
+    /*
+     * The following fields only have meaning if we came through
+     * another path. So just zero them here.
+     */
+
+    regs->ksp = 0;
+    regs->kpc = 0;
+    regs->orig_r28 = 0;
 }
 
-void default_trap(int code, struct pt_regs *regs)
+
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
 {
-       printk("Trap %d on CPU %d\n", code, smp_processor_id());
+       static spinlock_t terminate_lock = SPIN_LOCK_UNLOCKED;
 
-       show_regs(regs);
-}
+       set_eiem(0);
+       local_irq_disable();
+       spin_lock(&terminate_lock);
 
-void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
+       /* unlock the pdc lock if necessary */
+       pdc_emergency_unlock();
 
+       /* restart pdc console if necessary */
+       if (!console_drivers)
+               pdc_console_restart();
 
-#ifdef CONFIG_KWDB
-int
-debug_call (void) {
-    printk ("Debug call.\n");
-    return 0;
-}
+       if (code == 1)
+           transfer_pim_to_trap_frame(regs);
 
-int
-debug_call_leaf (void) {
-    return 0;
-}
-#endif /* CONFIG_KWDB */
+       show_stack((unsigned long *)regs->gr[30]);
+
+       printk("\n");
+       printk(KERN_CRIT "%s: Code=%d regs=%p (Addr=" RFMT ")\n",
+                       msg, code, regs, offset);
+       show_regs(regs);
 
-extern void do_page_fault(struct pt_regs *, int, unsigned long);
-extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
-extern void transfer_pim_to_trap_frame(struct pt_regs *);
-extern void pdc_console_restart(void);
+       spin_unlock(&terminate_lock);
+
+       /* put soft power button back under hardware control;
+        * if the user had pressed it once at any time, the 
+        * system will shut down immediately right here. */
+       pdc_soft_power_button(0);
+       
+       for(;;)
+           ;
+}
 
 void handle_interruption(int code, struct pt_regs *regs)
 {
        unsigned long fault_address = 0;
        unsigned long fault_space = 0;
        struct siginfo si;
-#ifdef CONFIG_KWDB
-       struct save_state ssp;
-#endif /* CONFIG_KWDB */   
 
        if (code == 1)
            pdc_console_restart();  /* switch back to pdc if HPMC */
        else
-           sti();
-
-#ifdef __LP64__
-
-       /*
-        * FIXME:
-        * For 32 bit processes we don't want the b bits (bits 0 & 1)
-        * in the ior. This is more appropriately handled in the tlb
-        * miss handlers. Changes need to be made to support addresses
-        * >32 bits for 64 bit processes.
-        */
-
-       regs->ior &= 0x3FFFFFFFFFFFFFFFUL;
-#endif
+           local_irq_enable();
 
 #if 0
-       printk("interrupted with code %d, regs %p\n", code, regs);
-       show_regs(regs);
+       printk(KERN_CRIT "Interruption # %d\n", code);
 #endif
 
        switch(code) {
+
        case  1:
-               parisc_terminate("High Priority Machine Check (HPMC)",regs,code,0);
+               /* High-priority machine check (HPMC) */
+               
+               /* set up a new led state on systems shipped with a LED State panel */
+               pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC);
+                   
+               parisc_terminate("High Priority Machine Check (HPMC)",
+                               regs, code, 0);
                /* NOT REACHED */
-       case  3: /* Recovery counter trap */
+               
+       case  2:
+               /* Power failure interrupt */
+               printk(KERN_CRIT "Power failure interrupt !\n");
+               return;
+
+       case  3:
+               /* Recovery counter trap */
                regs->gr[0] &= ~PSW_R;
                if (regs->iasq[0])
                        handle_gdb_break(regs, TRAP_TRACE);
-               /* else this must be the start of a syscall - just let it
-                * run.
-                */
+               /* else this must be the start of a syscall - just let it run */
                return;
 
        case  5:
+               /* Low-priority machine check */
+               pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
+               
                flush_all_caches();
                cpu_lpmc(5, regs);
                return;
 
        case  6:
+               /* Instruction TLB miss fault/Instruction page fault */
                fault_address = regs->iaoq[0];
                fault_space   = regs->iasq[0];
                break;
 
-       case  9: /* Break Instruction */
+       case  8:
+               /* Illegal instruction trap */
+               die_if_kernel("Illegal instruction", regs, code);
+               si.si_code = ILL_ILLOPC;
+               goto give_sigill;
+
+       case  9:
+               /* Break instruction trap */
                handle_break(regs->iir,regs);
                return;
+       
+       case 10:
+               /* Privileged operation trap */
+               die_if_kernel("Privileged operation", regs, code);
+               si.si_code = ILL_PRVOPC;
+               goto give_sigill;
+       
+       case 11:
+               /* Privileged register trap */
+               if ((regs->iir & 0xffdfffe0) == 0x034008a0) {
+
+                       /* This is a MFCTL cr26/cr27 to gr instruction.
+                        * PCXS traps on this, so we need to emulate it.
+                        */
+
+                       if (regs->iir & 0x00200000)
+                               regs->gr[regs->iir & 0x1f] = mfctl(27);
+                       else
+                               regs->gr[regs->iir & 0x1f] = mfctl(26);
+
+                       regs->iaoq[0] = regs->iaoq[1];
+                       regs->iaoq[1] += 4;
+                       regs->iasq[0] = regs->iasq[1];
+                       return;
+               }
+
+               die_if_kernel("Privileged register usage", regs, code);
+               si.si_code = ILL_PRVREG;
+       give_sigill:
+               si.si_signo = SIGILL;
+               si.si_errno = 0;
+               si.si_addr = (void *) regs->iaoq[0];
+               force_sig_info(SIGILL, &si, current);
+               return;
+
+       case 12:
+               /* Overflow Trap, let the userland signal handler do the cleanup */
+               si.si_signo = SIGFPE;
+               si.si_code = FPE_INTOVF;
+               si.si_addr = (void *) regs->iaoq[0];
+               force_sig_info(SIGFPE, &si, current);
+               return;
 
        case 14:
                /* Assist Exception Trap, i.e. floating point exception. */
                die_if_kernel("Floating point exception", regs, 0); /* quiet */
                handle_fpe(regs);
                return;
-       case 15:
-       case 16:  /* Non-Access TLB miss faulting address is in IOR */
+
        case 17:
-       case 26:
+               /* Non-access data TLB miss fault/Non-access data page fault */
+               /* TODO: Still need to add slow path emulation code here */
+               pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+               
                fault_address = regs->ior;
-               fault_space   = regs->isr;
+               parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
+
+       case 18:
+               /* PCXS only -- later cpu's split this into types 26,27 & 28 */
+               /* Check for unaligned access */
+               if (check_unaligned(regs)) {
+                       handle_unaligned(regs);
+                       return;
+               }
+               /* Fall Through */
 
-               if (code == 26 && fault_space == 0)
-                   parisc_terminate("Data access rights fault in kernel",regs,code,fault_address);
+       case 15: /* Data TLB miss fault/Data page fault */
+       case 26: /* PCXL: Data memory access rights trap */
+               fault_address = regs->ior;
+               fault_space   = regs->isr;
                break;
 
        case 19:
+               /* Data memory break trap */
                regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
                /* fall thru */
        case 21:
+               /* Page reference trap */
                handle_gdb_break(regs, TRAP_HWBKPT);
                return;
 
-       case 25: /* Taken branch trap */
+       case 25:
+               /* Taken branch trap */
                regs->gr[0] &= ~PSW_T;
                if (regs->iasq[0])
                        handle_gdb_break(regs, TRAP_BRANCH);
@@ -596,48 +610,64 @@ void handle_interruption(int code, struct pt_regs *regs)
                 */
                return;
 
-#if 0 /* def CONFIG_KWDB */
-       case I_TAKEN_BR:        /* 25 */
-               mtctl(0, 15);
-               pt_regs_to_ssp(regs, &ssp);
-               kgdb_trap(I_TAKEN_BR, &ssp, 1);
-               ssp_to_pt_regs(&ssp, regs);
-               break;
-#endif /* CONFIG_KWDB */
+       case  7:  
+               /* Instruction access rights */
+               /* PCXL: Instruction memory protection trap */
+
+               /*
+                * This could be caused by either: 1) a process attempting
+                * to execute within a vma that does not have execute
+                * permission, or 2) an access rights violation caused by a
+                * flush only translation set up by ptep_get_and_clear().
+                * So we check the vma permissions to differentiate the two.
+                * If the vma indicates we have execute permission, then
+                * the cause is the latter one. In this case, we need to
+                * call do_page_fault() to fix the problem.
+                */
 
-       case  8:
-               die_if_kernel("Illegal instruction", regs, code);
-               si.si_code = ILL_ILLOPC;
-               goto give_sigill;
+               if (user_mode(regs)) {
+                       struct vm_area_struct *vma;
 
-       case 10:
-               die_if_kernel("Priviledged operation - shouldn't happen!", regs, code);
-               si.si_code = ILL_PRVOPC;
-               goto give_sigill;
-       case 11:
-               die_if_kernel("Priviledged register - shouldn't happen!", regs, code);
-               si.si_code = ILL_PRVREG;
-       give_sigill:
-               si.si_signo = SIGILL;
+                       down_read(&current->mm->mmap_sem);
+                       vma = find_vma(current->mm,regs->iaoq[0]);
+                       if (vma && (regs->iaoq[0] >= vma->vm_start)
+                               && (vma->vm_flags & VM_EXEC)) {
+
+                               fault_address = regs->iaoq[0];
+                               fault_space = regs->iasq[0];
+
+                               up_read(&current->mm->mmap_sem);
+                               break; /* call do_page_fault() */
+                       }
+                       up_read(&current->mm->mmap_sem);
+               }
+               /* Fall Through */
+
+       case 27: 
+               /* Data memory protection ID trap */
+               die_if_kernel("Protection id trap", regs, code);
+               si.si_code = SEGV_MAPERR;
+               si.si_signo = SIGSEGV;
                si.si_errno = 0;
-               si.si_addr = (void *) regs->iaoq[0];
-               force_sig_info(SIGILL, &si, current);
+               if (code == 7)
+                   si.si_addr = (void *) regs->iaoq[0];
+               else
+                   si.si_addr = (void *) regs->ior;
+               force_sig_info(SIGSEGV, &si, current);
                return;
 
-       case 28:  /* Unaligned just causes SIGBUS for now */
-               die_if_kernel("Unaligned data reference", regs, code);
-               si.si_code = BUS_ADRALN;
-               si.si_signo = SIGBUS;
-               si.si_errno = 0;
-               si.si_addr = (void *) regs->ior;
-               force_sig_info(SIGBUS, &si, current);
+       case 28: 
+               /* Unaligned data reference trap */
+               handle_unaligned(regs);
                return;
 
        default:
                if (user_mode(regs)) {
-                       printk("\nhandle_interruption() pid=%d command='%s'\n",
+#ifdef PRINT_USER_FAULTS
+                       printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n",
                            current->pid, current->comm);
                        show_regs(regs);
+#endif
                        /* SIGBUS, for lack of a better one. */
                        si.si_signo = SIGBUS;
                        si.si_code = BUS_OBJERR;
@@ -646,18 +676,22 @@ void handle_interruption(int code, struct pt_regs *regs)
                        force_sig_info(SIGBUS, &si, current);
                        return;
                }
-               parisc_terminate("Unexpected Interruption!",regs,code,0);
+               pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+               
+               parisc_terminate("Unexpected interruption", regs, code, 0);
                /* NOT REACHED */
        }
 
        if (user_mode(regs)) {
            if (fault_space != regs->sr[7]) {
+#ifdef PRINT_USER_FAULTS
                if (fault_space == 0)
-                       printk("User Fault on Kernel Space ");
-               else /* this case should never happen, but whatever... */
-                       printk("User Fault (long pointer) ");
+                       printk(KERN_DEBUG "User Fault on Kernel Space ");
+               else
+                       printk(KERN_DEBUG "User Fault (long pointer) ");
                printk("pid=%d command='%s'\n", current->pid, current->comm);
                show_regs(regs);
+#endif
                si.si_signo = SIGSEGV;
                si.si_errno = 0;
                si.si_code = SEGV_MAPERR;
@@ -672,158 +706,17 @@ void handle_interruption(int code, struct pt_regs *regs)
             * The kernel should never fault on its own address space.
             */
 
-           if (fault_space == 0)
-                   parisc_terminate("Kernel Fault",regs,code,fault_address);
-       }
-
-#ifdef CONFIG_KWDB
-       debug_call_leaf ();
-#endif /* CONFIG_KWDB */
-
-       do_page_fault(regs, code, fault_address);
-
-       /*
-        * This should not be necessary.
-        * However, we do not currently
-        * implement flush_page_to_ram.
-        *
-        * The problem is that if we just
-        * brought in some code through the
-        * D-cache, the I-cache may not see
-        * it since it hasn't been flushed
-        * to ram.
-        */
-
-/*     flush_all_caches(); */
-
-#if 0
-       printk("returning %p\n", regs);
-/*     show_regs(regs); */
-#endif
-
-       return;
-
-}
-
-void show_stack(unsigned long sp)
-{
-#if 1
-       if ((sp & 0xc0000000UL) == 0xc0000000UL) {
-
-           __u32 *stackptr;
-           __u32 *dumpptr;
-
-           /* Stack Dump! */
-
-           stackptr = (__u32 *)sp;
-           dumpptr  = (__u32 *)(sp & ~(INIT_TASK_SIZE - 1));
-           printk("\nDumping Stack from %p to %p:\n",dumpptr,stackptr);
-           while (dumpptr < stackptr) {
-               printk("%04x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-                   ((__u32)dumpptr) & 0xffff,
-                   dumpptr[0], dumpptr[1], dumpptr[2], dumpptr[3],
-                   dumpptr[4], dumpptr[5], dumpptr[6], dumpptr[7]);
-               dumpptr += 8;
+           if (fault_space == 0) 
+           {
+               pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+               parisc_terminate("Kernel Fault", regs, code, fault_address);
+       
            }
        }
-#endif
-}
 
-
-void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
-{
-       set_eiem(0);
-       cli();
-
-       if (code == 1)
-           transfer_pim_to_trap_frame(regs);
-
-#if 1
-       show_stack(regs->gr[30]);
-#endif
-
-       printk("\n%s: Code=%d regs=%p (Addr=%08lx)\n",msg,code,regs,offset);
-       show_regs(regs);
-
-       for(;;)
-           ;
+       do_page_fault(regs, code, fault_address);
 }
 
-void transfer_pim_to_trap_frame(struct pt_regs *regs)
-{
-    register int i;
-    extern unsigned int hpmc_pim_data[];
-    struct pdc_hpmc_pim_11 *pim_narrow;
-    struct pdc_hpmc_pim_20 *pim_wide;
-
-    if (boot_cpu_data.cpu_type >= pcxu) {
-
-       pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
-
-       /*
-        * Note: The following code will probably generate a
-        * bunch of truncation error warnings from the compiler.
-        * Could be handled with an ifdef, but perhaps there
-        * is a better way.
-        */
-
-       regs->gr[0] = pim_wide->cr[22];
-
-       for (i = 1; i < 32; i++)
-           regs->gr[i] = pim_wide->gr[i];
-
-       for (i = 0; i < 32; i++)
-           regs->fr[i] = pim_wide->fr[i];
-
-       for (i = 0; i < 8; i++)
-           regs->sr[i] = pim_wide->sr[i];
-
-       regs->iasq[0] = pim_wide->cr[17];
-       regs->iasq[1] = pim_wide->iasq_back;
-       regs->iaoq[0] = pim_wide->cr[18];
-       regs->iaoq[1] = pim_wide->iaoq_back;
-
-       regs->cr30 = pim_wide->cr[30];
-       regs->sar  = pim_wide->cr[11];
-       regs->iir  = pim_wide->cr[19];
-       regs->isr  = pim_wide->cr[20];
-       regs->ior  = pim_wide->cr[21];
-    }
-    else {
-       pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
-
-       regs->gr[0] = pim_narrow->cr[22];
-
-       for (i = 1; i < 32; i++)
-           regs->gr[i] = pim_narrow->gr[i];
-
-       for (i = 0; i < 32; i++)
-           regs->fr[i] = pim_narrow->fr[i];
-
-       for (i = 0; i < 8; i++)
-           regs->sr[i] = pim_narrow->sr[i];
-
-       regs->iasq[0] = pim_narrow->cr[17];
-       regs->iasq[1] = pim_narrow->iasq_back;
-       regs->iaoq[0] = pim_narrow->cr[18];
-       regs->iaoq[1] = pim_narrow->iaoq_back;
-
-       regs->cr30 = pim_narrow->cr[30];
-       regs->sar  = pim_narrow->cr[11];
-       regs->iir  = pim_narrow->cr[19];
-       regs->isr  = pim_narrow->cr[20];
-       regs->ior  = pim_narrow->cr[21];
-    }
-
-    /*
-     * The following fields only have meaning if we came through
-     * another path. So just zero them here.
-     */
-
-    regs->ksp = 0;
-    regs->kpc = 0;
-    regs->orig_r28 = 0;
-}
 
 int __init check_ivt(void *iva)
 {
@@ -835,7 +728,7 @@ int __init check_ivt(void *iva)
        extern void os_hpmc(void);
        extern void os_hpmc_end(void);
 
-       if(strcmp((char *)iva, "cows can fly"))
+       if (strcmp((char *)iva, "cows can fly"))
                return -1;
 
        ivap = (u32 *)iva;
@@ -850,10 +743,10 @@ int __init check_ivt(void *iva)
 
        hpmcp = (u32 *)os_hpmc;
 
-       for(i=0; i<length/4; i++)
+       for (i=0; i<length/4; i++)
            check += *hpmcp++;
 
-       for(i=0; i<8; i++)
+       for (i=0; i<8; i++)
            check += ivap[i];
 
        ivap[5] = -check;
@@ -868,11 +761,8 @@ extern const void fault_vector_20;
 
 void __init trap_init(void)
 {
-       volatile long eiem;
        void *iva;
 
-       printk("trap_init\n");
-       
        if (boot_cpu_data.cpu_type >= pcxu)
                iva = (void *) &fault_vector_20;
        else
@@ -882,12 +772,6 @@ void __init trap_init(void)
                iva = (void *) &fault_vector_11;
 #endif
 
-       if(check_ivt(iva))
+       if (check_ivt(iva))
                panic("IVT invalid");
-
-       mtctl(0, 30);
-       mtctl(90000000, 16);
-       set_eiem(-1L);
-       mtctl(-1L, 23);
-       asm volatile ("rsm 0,%0" : "=r" (eiem));
 }
diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c
new file mode 100644 (file)
index 0000000..ceaaa3d
--- /dev/null
@@ -0,0 +1,434 @@
+/*    $Id: unaligned.c,v 1.1 2002/07/20 16:27:06 rhirst Exp $
+ *
+ *    Unaligned memory access handler
+ *
+ *    Copyright (C) 2001 Randolph Chung <tausq@debian.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#include <asm/smp.h>
+#include <asm/pdc.h>
+
+/* #define DEBUG_UNALIGNED 1 */
+
+#ifdef DEBUG_UNALIGNED
+#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#ifdef __LP64__
+#define RFMT "%016lx"
+#else
+#define RFMT "%08lx"
+#endif
+
+/* 1111 1100 0000 0000 0001 0011 1100 0000 */
+#define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6) 
+#define OPCODE2(a,b)   ((a)<<26|(b)<<1)
+#define OPCODE3(a,b)   ((a)<<26|(b)<<2)
+#define OPCODE4(a)     ((a)<<26)
+#define OPCODE1_MASK   OPCODE1(0x3f,1,0xf)
+#define OPCODE2_MASK   OPCODE2(0x3f,1)
+#define OPCODE3_MASK   OPCODE3(0x3f,1)
+#define OPCODE4_MASK    OPCODE4(0x3f)
+
+/* skip LDB (index) */
+#define OPCODE_LDH_I   OPCODE1(0x03,0,0x1)
+#define OPCODE_LDW_I   OPCODE1(0x03,0,0x2)
+#define OPCODE_LDD_I   OPCODE1(0x03,0,0x3)
+#define OPCODE_LDDA_I  OPCODE1(0x03,0,0x4)
+/* skip LDCD (index) */
+#define OPCODE_LDWA_I  OPCODE1(0x03,0,0x6)
+/* skip LDCW (index) */
+/* skip LDB (short) */
+#define OPCODE_LDH_S   OPCODE1(0x03,1,0x1)
+#define OPCODE_LDW_S   OPCODE1(0x03,1,0x2)
+#define OPCODE_LDD_S   OPCODE1(0x03,1,0x3)
+#define OPCODE_LDDA_S  OPCODE1(0x03,1,0x4)
+/* skip LDCD (short) */
+#define OPCODE_LDWA_S  OPCODE1(0x03,1,0x6)
+/* skip LDCW (short) */
+/* skip STB */
+#define OPCODE_STH     OPCODE1(0x03,1,0x9)
+#define OPCODE_STW     OPCODE1(0x03,1,0xa)
+#define OPCODE_STD     OPCODE1(0x03,1,0xb)
+/* skip STBY */
+/* skip STDBY */
+#define OPCODE_STWA    OPCODE1(0x03,1,0xe)
+#define OPCODE_STDA    OPCODE1(0x03,1,0xf)
+
+#define OPCODE_LDD_L   OPCODE2(0x14,0)
+#define OPCODE_FLDD_L  OPCODE2(0x14,1)
+#define OPCODE_STD_L   OPCODE2(0x1c,0)
+#define OPCODE_FSTD_L  OPCODE2(0x1c,1)
+
+#define OPCODE_LDW_M   OPCODE3(0x17,1)
+#define OPCODE_FLDW_L  OPCODE3(0x17,0)
+#define OPCODE_FSTW_L  OPCODE3(0x1f,0)
+#define OPCODE_STW_M   OPCODE3(0x1f,1)
+
+#define OPCODE_LDH_L    OPCODE4(0x11)
+#define OPCODE_LDW_L    OPCODE4(0x12)
+#define OPCODE_LDW_L2   OPCODE4(0x13)
+#define OPCODE_STH_L    OPCODE4(0x19)
+#define OPCODE_STW_L    OPCODE4(0x1A)
+#define OPCODE_STW_L2   OPCODE4(0x1B)
+
+
+
+void die_if_kernel (char *str, struct pt_regs *regs, long err);
+
+static int emulate_load(struct pt_regs *regs, int len, int toreg)
+{
+       unsigned long saddr = regs->ior;
+       unsigned long val = 0;
+       int ret = 0;
+
+       if (regs->isr != regs->sr[7])
+       {
+               printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
+                       regs->isr, regs->sr[7]);
+               return 1;
+       }
+
+       DPRINTF("load " RFMT ":" RFMT " to r%d for %d bytes\n", 
+               regs->isr, regs->ior, toreg, len);
+
+       __asm__ __volatile__  (
+"       mfsp %%sr1, %%r20\n"
+"       mtsp %6, %%sr1\n"
+"      copy %%r0, %0\n"
+"0:    ldbs,ma 1(%%sr1,%4), %%r19\n"
+"      addi -1, %5, %5\n"
+"      cmpib,>= 0, %5, 2f\n"
+"      or %%r19, %0, %0\n"
+"      b 0b\n"
+       
+#ifdef __LP64__
+       "depd,z %0, 55, 56, %0\n"
+#else
+       "depw,z %0, 23, 24, %0\n"
+#endif
+       
+"1:    ldi     10, %1\n"
+"2:     mtsp %%r20, %%sr1\n"
+"      .section __ex_table,\"a\"\n"
+#ifdef __LP64__
+       ".dword 0b, (1b-0b)\n"
+#else
+       ".word 0b, (1b-0b)\n"
+#endif
+       ".previous\n" 
+       : "=r" (val), "=r" (ret)
+       : "0" (val), "1" (ret), "r" (saddr), "r" (len), "r" (regs->isr)
+       : "r19", "r20" );
+
+       DPRINTF("val = 0x" RFMT "\n", val);
+
+       regs->gr[toreg] = val;
+
+       return ret;
+}
+
+static int emulate_store(struct pt_regs *regs, int len, int frreg)
+{
+       int ret = 0;
+#ifdef __LP64__
+       unsigned long val = regs->gr[frreg] << (64 - (len << 3));
+#else
+       unsigned long val = regs->gr[frreg] << (32 - (len << 3));
+#endif
+
+       if (regs->isr != regs->sr[7])
+       {
+               printk(KERN_CRIT "isr verification failed (isr: " RFMT ", sr7: " RFMT "\n",
+                       regs->isr, regs->sr[7]);
+               return 1;
+       }
+
+       DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for %d bytes\n", frreg, 
+               regs->gr[frreg], regs->isr, regs->ior, len);
+
+
+       __asm__ __volatile__ (
+"       mfsp %%sr1, %%r20\n"           /* save sr1 */
+"       mtsp %5, %%sr1\n"
+#ifdef __LP64__
+"0:    extrd,u %2, 7, 8, %%r19\n"
+#else
+"0:    extrw,u %2, 7, 8, %%r19\n"
+#endif
+"1:    stb,ma %%r19, 1(%%sr1, %3)\n"
+"      addi -1, %4, %4\n"
+"      cmpib,>= 0, %4, 3f\n"
+       
+#ifdef __LP64__
+       "depd,z %2, 55, 56, %2\n"
+#else
+       "depw,z %2, 23, 24, %2\n"
+#endif
+
+"      b 0b\n"
+"      nop\n"
+
+"2:    ldi 11, %0\n"
+"3:     mtsp %%r20, %%sr1\n"
+"      .section __ex_table,\"a\"\n"
+#ifdef __LP64__
+       ".dword 1b, (2b-1b)\n"
+#else
+       ".word 1b, (2b-1b)\n"
+#endif
+       ".previous\n" 
+       : "=r" (ret)
+       : "0" (ret), "r" (val), "r" (regs->ior), "r" (len), "r" (regs->isr)
+       : "r19", "r20" );
+
+       return ret;
+}
+
+
+void handle_unaligned(struct pt_regs *regs)
+{
+       unsigned long unaligned_count = 0;
+       unsigned long last_time = 0;
+       int ret = -1;
+       struct siginfo si;
+
+       /* if the unaligned access is inside the kernel:
+        *   if the access is caused by a syscall, then we fault the calling
+        *     user process
+        *   otherwise we halt the kernel
+        */
+       if (!user_mode(regs))
+       {
+               const struct exception_table_entry *fix;
+
+               /* see if the offending code have its own
+                * exception handler 
+                */ 
+
+               fix = search_exception_table(regs->iaoq[0]);
+               if (fix)
+               {
+                       /* lower bits of fix->skip are flags
+                        * upper bits are the handler addr
+                        */
+                       if (fix->skip & 1)
+                               regs->gr[8] = -EFAULT;
+                       if (fix->skip & 2)
+                               regs->gr[9] = 0;
+
+                       regs->iaoq[0] += ((fix->skip) & ~3);
+                       regs->iaoq[1] = regs->iaoq[0] + 4;
+                       regs->gr[0] &= ~PSW_B;
+
+                       return;
+               }
+       }
+
+       /* log a message with pacing */
+       if (user_mode(regs))
+       {
+               if (unaligned_count > 5 && jiffies - last_time > 5*HZ)
+               {
+                       unaligned_count = 0;
+                       last_time = jiffies;
+               }
+               if (++unaligned_count < 5)
+               {
+                       char buf[256];
+                       sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n",
+                               current->comm, current->pid, regs->ior, regs->iaoq[0]);
+                       printk(KERN_WARNING "%s", buf);
+#ifdef DEBUG_UNALIGNED
+                       show_regs(regs);
+#endif         
+               }
+       }
+
+       /* TODO: make this cleaner... */
+       switch (regs->iir & OPCODE1_MASK)
+       {
+       case OPCODE_LDH_I:
+       case OPCODE_LDH_S:
+               ret = emulate_load(regs, 2, regs->iir & 0x1f);
+               break;
+
+       case OPCODE_LDW_I:
+       case OPCODE_LDWA_I:
+       case OPCODE_LDW_S:
+       case OPCODE_LDWA_S:
+               ret = emulate_load(regs, 4, regs->iir&0x1f);
+               break;
+
+       case OPCODE_LDD_I:
+       case OPCODE_LDDA_I:
+       case OPCODE_LDD_S:
+       case OPCODE_LDDA_S:
+               ret = emulate_load(regs, 8, regs->iir&0x1f);
+               break;
+
+       case OPCODE_STH:
+               ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+               break;
+
+       case OPCODE_STW:
+       case OPCODE_STWA:
+               ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+               break;
+
+       case OPCODE_STD:
+       case OPCODE_STDA:
+               ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+               break;
+       }
+       switch (regs->iir & OPCODE2_MASK)
+       {
+       case OPCODE_LDD_L:
+       case OPCODE_FLDD_L:
+               ret = emulate_load(regs, 8, (regs->iir>>16)&0x1f);
+               break;
+
+       case OPCODE_STD_L:
+       case OPCODE_FSTD_L:
+               ret = emulate_store(regs, 8, (regs->iir>>16)&0x1f);
+               break;
+       }
+       switch (regs->iir & OPCODE3_MASK)
+       {
+       case OPCODE_LDW_M:
+       case OPCODE_FLDW_L:
+               ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+               break;
+
+       case OPCODE_FSTW_L:
+       case OPCODE_STW_M:
+               ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+               break;
+       }
+       switch (regs->iir & OPCODE4_MASK)
+       {
+       case OPCODE_LDH_L:
+               ret = emulate_load(regs, 2, (regs->iir>>16)&0x1f);
+               break;
+       case OPCODE_LDW_L:
+       case OPCODE_LDW_L2:
+               ret = emulate_load(regs, 4, (regs->iir>>16)&0x1f);
+               break;
+       case OPCODE_STH_L:
+               ret = emulate_store(regs, 2, (regs->iir>>16)&0x1f);
+               break;
+       case OPCODE_STW_L:
+       case OPCODE_STW_L2:
+               ret = emulate_store(regs, 4, (regs->iir>>16)&0x1f);
+               break;
+       }
+
+       if (ret < 0)
+               printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
+
+       DPRINTF("ret = %d\n", ret);
+
+       if (ret)
+       {
+               printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
+               die_if_kernel("Unaligned data reference", regs, 28);
+
+               /* couldn't handle it ... */
+               si.si_signo = SIGBUS;
+               si.si_errno = 0;
+               si.si_code = BUS_ADRALN;
+               si.si_addr = (void *)regs->ior;
+               force_sig_info(SIGBUS, &si, current);
+               
+               return;
+       }
+
+       /* else we handled it, advance the PC.... */
+       regs->iaoq[0] = regs->iaoq[1];
+       regs->iaoq[1] = regs->iaoq[0] + 4;
+}
+
+/*
+ * NB: check_unaligned() is only used for PCXS processors right
+ * now, so we only check for PA1.1 encodings at this point.
+ */
+
+int
+check_unaligned(struct pt_regs *regs)
+{
+       unsigned long align_mask;
+
+       /* Get alignment mask */
+
+       align_mask = 0UL;
+       switch (regs->iir & OPCODE1_MASK) {
+
+       case OPCODE_LDH_I:
+       case OPCODE_LDH_S:
+       case OPCODE_STH:
+               align_mask = 1UL;
+               break;
+
+       case OPCODE_LDW_I:
+       case OPCODE_LDWA_I:
+       case OPCODE_LDW_S:
+       case OPCODE_LDWA_S:
+       case OPCODE_STW:
+       case OPCODE_STWA:
+               align_mask = 3UL;
+               break;
+
+       default:
+               switch (regs->iir & OPCODE4_MASK) {
+               case OPCODE_LDH_L:
+               case OPCODE_STH_L:
+                       align_mask = 1UL;
+                       break;
+               case OPCODE_LDW_L:
+               case OPCODE_LDW_L2:
+               case OPCODE_STW_L:
+               case OPCODE_STW_L2:
+                       align_mask = 3UL;
+                       break;
+               }
+               break;
+       }
+
+       return (int)(regs->ior & align_mask);
+}