summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /arch
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/boot/main.c142
-rw-r--r--arch/alpha/config.in11
-rw-r--r--arch/alpha/defconfig1
-rw-r--r--arch/alpha/kernel/entry.S556
-rw-r--r--arch/alpha/kernel/osf_sys.c73
-rw-r--r--arch/alpha/kernel/process.c31
-rw-r--r--arch/alpha/kernel/proto.h3
-rw-r--r--arch/alpha/kernel/setup.c9
-rw-r--r--arch/alpha/kernel/smc37c669.c33
-rw-r--r--arch/alpha/kernel/smp.c28
-rw-r--r--arch/alpha/kernel/sys_dp264.c6
-rw-r--r--arch/alpha/kernel/sys_miata.c2
-rw-r--r--arch/alpha/kernel/sys_sx164.c2
-rw-r--r--arch/alpha/kernel/time.c45
-rw-r--r--arch/alpha/kernel/traps.c97
-rw-r--r--arch/alpha/lib/clear_user.S1
-rw-r--r--arch/alpha/lib/copy_user.S4
-rw-r--r--arch/alpha/lib/io.c11
-rw-r--r--arch/alpha/lib/strlen_user.S3
-rw-r--r--arch/alpha/lib/strncpy_from_user.S2
-rw-r--r--arch/alpha/math-emu/fp-emul.c91
-rw-r--r--arch/alpha/math-emu/ieee-math.c39
-rw-r--r--arch/alpha/math-emu/ieee-math.h2
-rw-r--r--arch/arm/defconfig1
-rw-r--r--arch/arm/kernel/sys_arm.c6
-rw-r--r--arch/arm/kernel/time.c1
-rw-r--r--arch/arm/mm/Makefile27
-rw-r--r--arch/arm/mm/fault-armo.c161
-rw-r--r--arch/arm/mm/fault-armv.c525
-rw-r--r--arch/arm/mm/fault-common.c188
-rw-r--r--arch/arm/mm/init.c90
-rw-r--r--arch/arm/mm/ioremap.c149
-rw-r--r--arch/arm/mm/mm-arc.c82
-rw-r--r--arch/arm/mm/mm-armv.c6
-rw-r--r--arch/arm/mm/mm-ebsa285.c39
-rw-r--r--arch/arm/mm/mm-footbridge.c91
-rw-r--r--arch/arm/mm/mm-vnc.c31
-rw-r--r--arch/arm/mm/proc-arm2,3.S20
-rw-r--r--arch/arm/mm/proc-arm6,7.S61
-rw-r--r--arch/arm/mm/proc-sa110.S122
-rw-r--r--arch/arm/mm/small_page.c73
-rw-r--r--arch/i386/config.in4
-rw-r--r--arch/i386/defconfig12
-rw-r--r--arch/i386/kernel/bios32.c135
-rw-r--r--arch/i386/kernel/entry.S2
-rw-r--r--arch/i386/kernel/i386_ksyms.c7
-rw-r--r--arch/i386/kernel/io_apic.c133
-rw-r--r--arch/i386/kernel/irq.c237
-rw-r--r--arch/i386/kernel/irq.h34
-rw-r--r--arch/i386/kernel/mca.c548
-rw-r--r--arch/i386/kernel/mtrr.c909
-rw-r--r--arch/i386/kernel/process.c6
-rw-r--r--arch/i386/kernel/ptrace.c11
-rw-r--r--arch/i386/kernel/setup.c135
-rw-r--r--arch/i386/kernel/smp.c166
-rw-r--r--arch/i386/kernel/time.c177
-rw-r--r--arch/i386/kernel/traps.c8
-rw-r--r--arch/i386/kernel/visws_apic.c8
-rw-r--r--arch/i386/lib/semaphore.S9
-rw-r--r--arch/m68k/Makefile15
-rw-r--r--arch/m68k/atari/atakeyb.c4
-rw-r--r--arch/m68k/bvme6000/config.c4
-rw-r--r--arch/m68k/config.in117
-rw-r--r--arch/m68k/defconfig1
-rw-r--r--arch/m68k/hp300/hil.c9
-rw-r--r--arch/m68k/kernel/entry.S20
-rw-r--r--arch/m68k/kernel/head.S148
-rw-r--r--arch/m68k/kernel/ints.c14
-rw-r--r--arch/m68k/kernel/m68k_defs.h47
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c4
-rw-r--r--arch/m68k/kernel/process.c12
-rw-r--r--arch/m68k/kernel/ptrace.c11
-rw-r--r--arch/m68k/kernel/setup.c88
-rw-r--r--arch/m68k/kernel/time.c3
-rw-r--r--arch/m68k/lib/semaphore.S10
-rw-r--r--arch/m68k/mac/mackeyb.c6
-rw-r--r--arch/m68k/mm/init.c22
-rw-r--r--arch/m68k/mm/kmap.c27
-rw-r--r--arch/m68k/mm/memory.c14
-rw-r--r--arch/m68k/mvme147/147ints.c142
-rw-r--r--arch/m68k/mvme147/Makefile14
-rw-r--r--arch/m68k/mvme147/config.c240
-rw-r--r--arch/m68k/mvme16x/config.c4
-rw-r--r--arch/m68k/q40/Makefile14
-rw-r--r--arch/m68k/q40/README121
-rw-r--r--arch/m68k/q40/config.c425
-rw-r--r--arch/m68k/q40/q40ints.c347
-rw-r--r--arch/m68k/sun3x/Makefile14
-rw-r--r--arch/m68k/sun3x/config.c128
-rw-r--r--arch/m68k/sun3x/dvma.c162
-rw-r--r--arch/m68k/sun3x/sbus.c44
-rw-r--r--arch/m68k/sun3x/time.c83
-rw-r--r--arch/m68k/sun3x/time.h9
-rw-r--r--arch/mips/config.in4
-rw-r--r--arch/mips/defconfig17
-rw-r--r--arch/mips/kernel/irixelf.c38
-rw-r--r--arch/mips/kernel/ptrace.c17
-rw-r--r--arch/mips/kernel/r2300_switch.S21
-rw-r--r--arch/mips/kernel/r4k_switch.S19
-rw-r--r--arch/mips/kernel/sysirix.c3
-rw-r--r--arch/mips/kernel/time.c3
-rw-r--r--arch/mips/kernel/traps.c6
-rw-r--r--arch/mips/mm/loadmmu.c4
-rw-r--r--arch/mips/sgi/kernel/indy_timer.c9
-rw-r--r--arch/ppc/8xx_io/commproc.c7
-rw-r--r--arch/ppc/8xx_io/enet.c175
-rw-r--r--arch/ppc/Makefile9
-rw-r--r--arch/ppc/apus_defconfig1
-rw-r--r--arch/ppc/boot/Makefile86
-rw-r--r--arch/ppc/boot/head.S116
-rw-r--r--arch/ppc/boot/kbd.c55
-rw-r--r--arch/ppc/boot/misc.c695
-rw-r--r--arch/ppc/boot/mkprep.c11
-rw-r--r--arch/ppc/boot/of1275.c427
-rw-r--r--arch/ppc/boot/of1275.h421
-rw-r--r--arch/ppc/boot/piggyback.c64
-rw-r--r--arch/ppc/chrp_defconfig1
-rw-r--r--arch/ppc/chrpboot/Makefile10
-rw-r--r--arch/ppc/coffboot/Makefile10
-rw-r--r--arch/ppc/common_defconfig185
-rw-r--r--arch/ppc/config.in29
-rw-r--r--arch/ppc/defconfig99
-rw-r--r--arch/ppc/kernel/Makefile5
-rw-r--r--arch/ppc/kernel/align.c24
-rw-r--r--arch/ppc/kernel/apus_setup.c231
-rw-r--r--arch/ppc/kernel/chrp_pci.c343
-rw-r--r--arch/ppc/kernel/chrp_setup.c578
-rw-r--r--arch/ppc/kernel/chrp_time.c6
-rw-r--r--arch/ppc/kernel/feature.c4
-rw-r--r--arch/ppc/kernel/head.S454
-rw-r--r--arch/ppc/kernel/i8259.c130
-rw-r--r--arch/ppc/kernel/i8259.h12
-rw-r--r--arch/ppc/kernel/idle.c32
-rw-r--r--arch/ppc/kernel/indirect_pci.c121
-rw-r--r--arch/ppc/kernel/irq.c1012
-rw-r--r--arch/ppc/kernel/local_irq.h45
-rw-r--r--arch/ppc/kernel/mbx_pci.c17
-rw-r--r--arch/ppc/kernel/mbx_setup.c377
-rw-r--r--arch/ppc/kernel/misc.S71
-rw-r--r--arch/ppc/kernel/mk_defs.c3
-rw-r--r--arch/ppc/kernel/open_pic.c48
-rw-r--r--arch/ppc/kernel/open_pic.h11
-rw-r--r--arch/ppc/kernel/openpic.c35
-rw-r--r--arch/ppc/kernel/pci.c254
-rw-r--r--arch/ppc/kernel/pci.h36
-rw-r--r--arch/ppc/kernel/pmac_pci.c69
-rw-r--r--arch/ppc/kernel/pmac_pic.c362
-rw-r--r--arch/ppc/kernel/pmac_pic.h15
-rw-r--r--arch/ppc/kernel/pmac_setup.c245
-rw-r--r--arch/ppc/kernel/ppc8xx_pic.c49
-rw-r--r--arch/ppc/kernel/ppc8xx_pic.h9
-rw-r--r--arch/ppc/kernel/ppc_defs.h69
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c30
-rw-r--r--arch/ppc/kernel/prep_nvram.c173
-rw-r--r--arch/ppc/kernel/prep_pci.c738
-rw-r--r--arch/ppc/kernel/prep_setup.c597
-rw-r--r--arch/ppc/kernel/prep_time.c220
-rw-r--r--arch/ppc/kernel/process.c126
-rw-r--r--arch/ppc/kernel/prom.c263
-rw-r--r--arch/ppc/kernel/ptrace.c19
-rw-r--r--arch/ppc/kernel/setup.c600
-rw-r--r--arch/ppc/kernel/signal.c29
-rw-r--r--arch/ppc/kernel/smp.c249
-rw-r--r--arch/ppc/kernel/softemu8xx.c19
-rw-r--r--arch/ppc/kernel/syscalls.c5
-rw-r--r--arch/ppc/kernel/time.c284
-rw-r--r--arch/ppc/kernel/time.h21
-rw-r--r--arch/ppc/kernel/traps.c9
-rw-r--r--arch/ppc/lib/locks.c91
-rw-r--r--arch/ppc/lib/strcase.c11
-rw-r--r--arch/ppc/lib/string.S19
-rw-r--r--arch/ppc/mbx_defconfig90
-rw-r--r--arch/ppc/mbxboot/Makefile101
-rw-r--r--arch/ppc/mbxboot/head.S200
-rw-r--r--arch/ppc/mbxboot/mbxtty.c (renamed from arch/ppc/boot/mbxtty.c)0
-rw-r--r--arch/ppc/mbxboot/misc.c637
-rw-r--r--arch/ppc/mbxboot/offset4
-rw-r--r--arch/ppc/mbxboot/size4
-rw-r--r--arch/ppc/mm/fault.c3
-rw-r--r--arch/ppc/mm/init.c157
-rw-r--r--arch/ppc/pmac_defconfig2
-rw-r--r--arch/ppc/prep_defconfig1
-rw-r--r--arch/sparc/boot/piggyback.c11
-rw-r--r--arch/sparc/config.in16
-rw-r--r--arch/sparc/defconfig63
-rw-r--r--arch/sparc/kernel/Makefile2
-rw-r--r--arch/sparc/kernel/devices.c18
-rw-r--r--arch/sparc/kernel/entry.S40
-rw-r--r--arch/sparc/kernel/head.S19
-rw-r--r--arch/sparc/kernel/irq.c201
-rw-r--r--arch/sparc/kernel/pcic.c9
-rw-r--r--arch/sparc/kernel/process.c131
-rw-r--r--arch/sparc/kernel/ptrace.c12
-rw-r--r--arch/sparc/kernel/setup.c24
-rw-r--r--arch/sparc/kernel/signal.c76
-rw-r--r--arch/sparc/kernel/smp.c1
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c7
-rw-r--r--arch/sparc/kernel/sun4d_irq.c4
-rw-r--r--arch/sparc/kernel/sun4d_smp.c2
-rw-r--r--arch/sparc/kernel/sun4m_irq.c4
-rw-r--r--arch/sparc/kernel/sun4m_smp.c6
-rw-r--r--arch/sparc/kernel/sys_sparc.c13
-rw-r--r--arch/sparc/kernel/systbls.S8
-rw-r--r--arch/sparc/kernel/time.c19
-rw-r--r--arch/sparc/kernel/traps.c28
-rw-r--r--arch/sparc/kernel/unaligned.c4
-rw-r--r--arch/sparc/lib/Makefile7
-rw-r--r--arch/sparc/lib/atomic.S14
-rw-r--r--arch/sparc/lib/bitops.S85
-rw-r--r--arch/sparc/lib/debuglocks.c36
-rw-r--r--arch/sparc/lib/irqlock.S65
-rw-r--r--arch/sparc/lib/lshrdi3.S29
-rw-r--r--arch/sparc/math-emu/fabss.c2
-rw-r--r--arch/sparc/math-emu/fcmpd.c2
-rw-r--r--arch/sparc/math-emu/fcmped.c2
-rw-r--r--arch/sparc/math-emu/fcmpeq.c2
-rw-r--r--arch/sparc/math-emu/fcmpes.c2
-rw-r--r--arch/sparc/math-emu/fcmpq.c2
-rw-r--r--arch/sparc/math-emu/fcmps.c2
-rw-r--r--arch/sparc/math-emu/fdmulq.c3
-rw-r--r--arch/sparc/math-emu/fdtoq.c3
-rw-r--r--arch/sparc/math-emu/fdtos.c3
-rw-r--r--arch/sparc/math-emu/fnegs.c2
-rw-r--r--arch/sparc/math-emu/fqtod.c3
-rw-r--r--arch/sparc/math-emu/fqtos.c3
-rw-r--r--arch/sparc/math-emu/fsmuld.c3
-rw-r--r--arch/sparc/math-emu/fstod.c3
-rw-r--r--arch/sparc/math-emu/fstoq.c3
-rw-r--r--arch/sparc/math-emu/math.c91
-rw-r--r--arch/sparc/math-emu/sfp-machine.h133
-rw-r--r--arch/sparc/mm/Makefile2
-rw-r--r--arch/sparc/mm/fault.c13
-rw-r--r--arch/sparc/mm/init.c40
-rw-r--r--arch/sparc/mm/iommu.c63
-rw-r--r--arch/sparc/mm/nosrmmu.c12
-rw-r--r--arch/sparc/mm/srmmu.c144
-rw-r--r--arch/sparc/mm/sun4c.c12
-rw-r--r--arch/sparc/mm/viking.S157
-rw-r--r--arch/sparc/vmlinux.lds4
-rw-r--r--arch/sparc64/Makefile3
-rw-r--r--arch/sparc64/config.in59
-rw-r--r--arch/sparc64/defconfig72
-rw-r--r--arch/sparc64/kernel/Makefile4
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c116
-rw-r--r--arch/sparc64/kernel/central.c310
-rw-r--r--arch/sparc64/kernel/cpu.c14
-rw-r--r--arch/sparc64/kernel/devices.c24
-rw-r--r--arch/sparc64/kernel/dtlb_backend.S18
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S12
-rw-r--r--arch/sparc64/kernel/ebus.c39
-rw-r--r--arch/sparc64/kernel/entry.S176
-rw-r--r--arch/sparc64/kernel/head.S49
-rw-r--r--arch/sparc64/kernel/ioctl32.c314
-rw-r--r--arch/sparc64/kernel/irq.c652
-rw-r--r--arch/sparc64/kernel/itlb_base.S17
-rw-r--r--arch/sparc64/kernel/process.c106
-rw-r--r--arch/sparc64/kernel/psycho.c433
-rw-r--r--arch/sparc64/kernel/ptrace.c27
-rw-r--r--arch/sparc64/kernel/setup.c44
-rw-r--r--arch/sparc64/kernel/smp.c260
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c22
-rw-r--r--arch/sparc64/kernel/starfire.c121
-rw-r--r--arch/sparc64/kernel/sys_sparc.c15
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c512
-rw-r--r--arch/sparc64/kernel/systbls.S12
-rw-r--r--arch/sparc64/kernel/time.c31
-rw-r--r--arch/sparc64/kernel/trampoline.S20
-rw-r--r--arch/sparc64/kernel/traps.c22
-rw-r--r--arch/sparc64/kernel/ttable.S6
-rw-r--r--arch/sparc64/kernel/unaligned.c75
-rw-r--r--arch/sparc64/math-emu/fabsq.c2
-rw-r--r--arch/sparc64/math-emu/faddd.c3
-rw-r--r--arch/sparc64/math-emu/faddq.c3
-rw-r--r--arch/sparc64/math-emu/fadds.c3
-rw-r--r--arch/sparc64/math-emu/fcmpeq.c2
-rw-r--r--arch/sparc64/math-emu/fcmpq.c2
-rw-r--r--arch/sparc64/math-emu/fdivd.c10
-rw-r--r--arch/sparc64/math-emu/fdivq.c10
-rw-r--r--arch/sparc64/math-emu/fdivs.c11
-rw-r--r--arch/sparc64/math-emu/fdmulq.c3
-rw-r--r--arch/sparc64/math-emu/fdtoi.c2
-rw-r--r--arch/sparc64/math-emu/fdtoq.c3
-rw-r--r--arch/sparc64/math-emu/fdtos.c3
-rw-r--r--arch/sparc64/math-emu/fdtox.c2
-rw-r--r--arch/sparc64/math-emu/fitoq.c3
-rw-r--r--arch/sparc64/math-emu/fmuld.c3
-rw-r--r--arch/sparc64/math-emu/fmulq.c3
-rw-r--r--arch/sparc64/math-emu/fmuls.c3
-rw-r--r--arch/sparc64/math-emu/fnegq.c2
-rw-r--r--arch/sparc64/math-emu/fqtod.c3
-rw-r--r--arch/sparc64/math-emu/fqtoi.c2
-rw-r--r--arch/sparc64/math-emu/fqtos.c3
-rw-r--r--arch/sparc64/math-emu/fqtox.c2
-rw-r--r--arch/sparc64/math-emu/fsmuld.c3
-rw-r--r--arch/sparc64/math-emu/fsqrtd.c3
-rw-r--r--arch/sparc64/math-emu/fsqrtq.c3
-rw-r--r--arch/sparc64/math-emu/fsqrts.c3
-rw-r--r--arch/sparc64/math-emu/fstod.c3
-rw-r--r--arch/sparc64/math-emu/fstoi.c2
-rw-r--r--arch/sparc64/math-emu/fstoq.c3
-rw-r--r--arch/sparc64/math-emu/fstox.c2
-rw-r--r--arch/sparc64/math-emu/fsubd.c3
-rw-r--r--arch/sparc64/math-emu/fsubq.c3
-rw-r--r--arch/sparc64/math-emu/fsubs.c3
-rw-r--r--arch/sparc64/math-emu/fxtoq.c3
-rw-r--r--arch/sparc64/math-emu/math.c97
-rw-r--r--arch/sparc64/math-emu/op-2.h8
-rw-r--r--arch/sparc64/math-emu/op-common.h28
-rw-r--r--arch/sparc64/math-emu/sfp-machine.h130
-rw-r--r--arch/sparc64/math-emu/soft-fp.h35
-rw-r--r--arch/sparc64/mm/fault.c141
-rw-r--r--arch/sparc64/mm/generic.c39
-rw-r--r--arch/sparc64/mm/init.c480
-rw-r--r--arch/sparc64/mm/ultra.S17
-rw-r--r--arch/sparc64/prom/memory.c14
-rw-r--r--arch/sparc64/prom/misc.c116
-rw-r--r--arch/sparc64/solaris/fs.c12
-rw-r--r--arch/sparc64/solaris/systbl.S4
318 files changed, 18664 insertions, 7464 deletions
diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c
index c2d4e657e..dd4e47ab5 100644
--- a/arch/alpha/boot/main.c
+++ b/arch/alpha/boot/main.c
@@ -22,61 +22,27 @@
extern int vsprintf(char *, const char *, va_list);
extern unsigned long switch_to_osf_pal(unsigned long nr,
struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa,
- unsigned long vptb, unsigned long *kstk);
-
-int printk(const char * fmt, ...)
-{
- va_list args;
- int i, j, written, remaining, num_nl;
- static char buf[1024];
- char * str;
-
- va_start(args, fmt);
- i = vsprintf(buf, fmt, args);
- va_end(args);
-
- /* expand \n into \r\n: */
-
- num_nl = 0;
- for (j = 0; j < i; ++j) {
- if (buf[j] == '\n')
- ++num_nl;
- }
- remaining = i + num_nl;
- for (j = i - 1; j >= 0; --j) {
- buf[j + num_nl] = buf[j];
- if (buf[j] == '\n') {
- --num_nl;
- buf[j + num_nl] = '\r';
- }
- }
-
- str = buf;
- do {
- written = puts(str, remaining);
- remaining -= written;
- str += written;
- } while (remaining > 0);
- return i;
-}
-
-#define hwrpb (*INIT_HWRPB)
+ unsigned long *vptb);
+struct hwrpb_struct *hwrpb = INIT_HWRPB;
+static struct pcb_struct pcb_va[1];
/*
* Find a physical address of a virtual object..
*
* This is easy using the virtual page table address.
*/
-struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb)
+
+static inline void *
+find_pa(unsigned long *vptb, void *ptr)
{
- unsigned long address = (unsigned long) pcb;
+ unsigned long address = (unsigned long) ptr;
unsigned long result;
result = vptb[address >> 13];
result >>= 32;
result <<= 13;
result |= address & 0x1fff;
- return (struct pcb_struct *) result;
+ return (void *) result;
}
/*
@@ -88,30 +54,19 @@ struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb)
* code has the L1 page table identity-map itself in the second PTE
* in the L1 page table. Thus the L1-page is virtually addressable
* itself (through three levels) at virtual address 0x200802000.
- *
- * As we don't want it there anyway, we also move the L1 self-map
- * up as high as we can, so that the last entry in the L1 page table
- * maps the page tables.
- *
- * As a result, the OSF/1 pal-code will instead use a virtual page table
- * map located at 0xffffffe00000000.
*/
-#define pcb_va ((struct pcb_struct *) 0x20000000)
-#define old_vptb (0x0000000200000000UL)
-#define new_vptb (0xfffffffe00000000UL)
-void pal_init(void)
+
+#define VPTB ((unsigned long *) 0x200000000)
+#define L1 ((unsigned long *) 0x200802000)
+
+void
+pal_init(void)
{
- unsigned long i, rev, sum;
- unsigned long *L1, *l;
+ unsigned long i, rev;
struct percpu_struct * percpu;
struct pcb_struct * pcb_pa;
- /* Find the level 1 page table and duplicate it in high memory */
- L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */
- L1[1023] = L1[1];
-
- percpu = (struct percpu_struct *) (hwrpb.processor_offset + (unsigned long) &hwrpb),
-
+ /* Create the dummy PCB. */
pcb_va->ksp = 0;
pcb_va->usp = 0;
pcb_va->ptbr = L1[1] >> 32;
@@ -119,39 +74,32 @@ void pal_init(void)
pcb_va->pcc = 0;
pcb_va->unique = 0;
pcb_va->flags = 1;
- pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va);
- printk("Switching to OSF PAL-code .. ");
+ pcb_va->res1 = 0;
+ pcb_va->res2 = 0;
+ pcb_pa = find_pa(VPTB, pcb_va);
+
/*
* a0 = 2 (OSF)
- * a1 = return address, but we give the asm the virtual addr of the PCB
+ * a1 = return address, but we give the asm the vaddr of the PCB
* a2 = physical addr of PCB
* a3 = new virtual page table pointer
- * a4 = KSP (but we give it 0, asm sets it)
+ * a4 = KSP (but the asm sets it)
*/
- i = switch_to_osf_pal(
- 2,
- pcb_va,
- pcb_pa,
- new_vptb,
- 0);
+ srm_printk("Switching to OSF PAL-code .. ");
+
+ i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB);
if (i) {
- printk("failed, code %ld\n", i);
+ srm_printk("failed, code %ld\n", i);
halt();
}
- rev = percpu->pal_revision = percpu->palcode_avail[2];
- hwrpb.vptb = new_vptb;
+ percpu = (struct percpu_struct *)
+ (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB);
+ rev = percpu->pal_revision = percpu->palcode_avail[2];
- /* update checksum: */
- sum = 0;
- for (l = (unsigned long *) &hwrpb; l < (unsigned long *) &hwrpb.chksum; ++l)
- sum += *l;
- hwrpb.chksum = sum;
+ srm_printk("Ok (rev %lx)\n", rev);
- printk("Ok (rev %lx)\n", rev);
- /* remove the old virtual page-table mapping */
- L1[1] = 0;
- flush_tlb_all();
+ tbia(); /* do it directly in case we are SMP */
}
static inline long openboot(void)
@@ -159,15 +107,15 @@ static inline long openboot(void)
char bootdev[256];
long result;
- result = dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255);
+ result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_DEV, bootdev, 255);
if (result < 0)
return result;
- return dispatch(CCB_OPEN, bootdev, result & 255);
+ return srm_dispatch(CCB_OPEN, bootdev, result & 255);
}
static inline long close(long dev)
{
- return dispatch(CCB_CLOSE, dev);
+ return srm_dispatch(CCB_CLOSE, dev);
}
static inline long load(long dev, unsigned long addr, unsigned long count)
@@ -176,15 +124,15 @@ static inline long load(long dev, unsigned long addr, unsigned long count)
extern char _end;
long result, boot_size = &_end - (char *) BOOT_ADDR;
- result = dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255);
+ result = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255);
if (result < 0)
return result;
result &= 255;
bootfile[result] = '\0';
if (result)
- printk("Boot file specification (%s) not implemented\n",
+ srm_printk("Boot file specification (%s) not implemented\n",
bootfile);
- return dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1);
+ return srm_dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1);
}
/*
@@ -208,27 +156,27 @@ void start_kernel(void)
int nbytes;
char envval[256];
- printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n");
- if (hwrpb.pagesize != 8192) {
- printk("Expected 8kB pages, got %ldkB\n", hwrpb.pagesize >> 10);
+ srm_printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n");
+ if (INIT_HWRPB->pagesize != 8192) {
+ srm_printk("Expected 8kB pages, got %ldkB\n", INIT_HWRPB->pagesize >> 10);
return;
}
pal_init();
dev = openboot();
if (dev < 0) {
- printk("Unable to open boot device: %016lx\n", dev);
+ srm_printk("Unable to open boot device: %016lx\n", dev);
return;
}
dev &= 0xffffffff;
- printk("Loading vmlinux ...");
+ srm_printk("Loading vmlinux ...");
i = load(dev, START_ADDR, KERNEL_SIZE);
close(dev);
if (i != KERNEL_SIZE) {
- printk("Failed (%lx)\n", i);
+ srm_printk("Failed (%lx)\n", i);
return;
}
- nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
+ nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
envval, sizeof(envval));
if (nbytes < 0) {
nbytes = 0;
@@ -236,7 +184,7 @@ void start_kernel(void)
envval[nbytes] = '\0';
strcpy((char*)ZERO_PAGE, envval);
- printk(" Ok\nNow booting the kernel\n");
+ srm_printk(" Ok\nNow booting the kernel\n");
runkernel();
for (i = 0 ; i < 0x100000000 ; i++)
/* nothing */;
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 4e64ee826..d632cdbb9 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -54,12 +54,10 @@ unset CONFIG_PCI CONFIG_ALPHA_EISA
unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
-unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
if [ "$CONFIG_ALPHA_GENERIC" = "y" ]
then
define_bool CONFIG_PCI y
- define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
fi
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]
then
@@ -108,7 +106,7 @@ then
then
define_bool CONFIG_ALPHA_EV5 y
else
- define_bool CONFIG_ALPHA_EV4 y
+ define_bool CONFIG_ALPHA_EV4 y
fi
define_bool CONFIG_ALPHA_T2 y
fi
@@ -141,11 +139,6 @@ if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
then
define_bool CONFIG_ALPHA_EV4 y
fi
-if [ "$CONFIG_ALPHA_EV4" = "y" ]
-then
- # EV45 and older do not support all rounding modes in hw:
- define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
-fi
if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
@@ -243,7 +236,7 @@ fi
endmenu
mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index cfd366eb5..c557d66ec 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -91,7 +91,6 @@ CONFIG_PARIDE_PARPORT=y
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 380af2c9c..b4e71bf56 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -6,8 +6,6 @@
#include <asm/system.h>
-#define halt .long PAL_halt
-#define rti .long PAL_rti
#define SIGCHLD 20
#define NR_SYSCALLS 371
@@ -98,7 +96,7 @@
call_pal PAL_swpipl; \
stq $21,HAE_CACHE($19); \
stq $21,0($20); \
- bis $0,$0,$16; \
+ mov $0,$16; \
call_pal PAL_swpipl; \
ldq $0,0($30); \
ldq $1,8($30); \
@@ -127,8 +125,8 @@
entInt:
SAVE_ALL
lda $8,0x3fff
- bic $30,$8,$8
lda $26,ret_from_sys_call
+ bic $30,$8,$8
jsr $31,do_entInt
.end entInt
@@ -170,8 +168,8 @@ entMM:
entArith:
SAVE_ALL
lda $8,0x3fff
- bic $30,$8,$8
lda $26,ret_from_sys_call
+ bic $30,$8,$8
jsr $31,do_entArith
.end entArith
@@ -181,11 +179,23 @@ entArith:
entIF:
SAVE_ALL
lda $8,0x3fff
- bic $30,$8,$8
lda $26,ret_from_sys_call
+ bic $30,$8,$8
jsr $31,do_entIF
.end entIF
+.align 3
+.globl entDbg
+.ent entDbg
+entDbg:
+ SAVE_ALL
+ lda $8,0x3fff
+ lda $26,ret_from_sys_call
+ bic $30,$8,$8
+ jsr $31,do_entDbg
+.end entDbg
+
+
/*
* Fork() is one of the special system calls: it needs to
* save the callee-saved regs so that the regs can be found
@@ -200,18 +210,18 @@ entIF:
kernel_clone:
.frame $30, 0, $26
.prologue 0
- subq $30,6*8,$30
- stq $31,0($30)
- stq $26,8($30)
- stq $29,16($30)
- stq $16,24($30)
- stq $17,32($30)
- stq $18,40($30)
- bis $31,2,$0 /* Register v0: syscall nr for fork() */
+ subq $30,6*8,$30
+ stq $31,0($30)
+ stq $26,8($30)
+ stq $29,16($30)
+ stq $16,24($30)
+ stq $17,32($30)
+ stq $18,40($30)
+ bis $31,2,$0 /* Register v0: syscall nr for fork() */
SAVE_ALL
- bsr $26,sys_clone
- stq $0,0($30)
- br $31,ret_from_sys_call
+ bsr $26,sys_clone
+ stq $0,0($30)
+ br ret_from_sys_call
.end kernel_clone
/*
@@ -221,32 +231,32 @@ kernel_clone:
.globl __kernel_thread
.ent __kernel_thread
__kernel_thread:
- ldgp $29,0($27) /* we can be called from a module */
+ ldgp $29,0($27) /* we can be called from a module */
.frame $30, 4*8, $26
- subq $30,4*8,$30
- stq $10,16($30)
- stq $9,8($30)
- stq $26,0($30)
+ subq $30,4*8,$30
+ stq $10,16($30)
+ stq $9,8($30)
+ stq $26,0($30)
.prologue 1
- bis $17,$17,$9 /* save fn */
- bis $18,$18,$10 /* save arg */
- bsr $26,kernel_clone
- bne $20,1f /* $20 is non-zero in child */
- ldq $26,0($30)
- ldq $9,8($30)
- ldq $10,16($30)
- addq $30,4*8,$30
- ret $31,($26),1
+ mov $17,$9 /* save fn */
+ mov $18,$10 /* save arg */
+ bsr $26,kernel_clone
+ bne $20,1f /* $20 is non-zero in child */
+ ldq $26,0($30)
+ ldq $9,8($30)
+ ldq $10,16($30)
+ addq $30,4*8,$30
+ ret $31,($26),1
/* this is in child: look out as we don't have any stack here.. */
-1: bis $9,$9,$27 /* get fn */
- lda $8,0x3fff
- bis $10,$10,$16 /* get arg */
- bic $30,$8,$8 /* get current */
- jsr $26,($27)
+1: mov $9,$27 /* get fn */
+ lda $8,0x3fff
+ mov $10,$16 /* get arg */
+ bic $30,$8,$8 /* get current */
+ jsr $26,($27)
ldgp $29,0($26)
- bis $0,$0,$16
- jsr $26,sys_exit
- call_pal PAL_halt
+ mov $0,$16
+ mov $31,$26
+ jsr $31,sys_exit
.end __kernel_thread
/*
@@ -274,202 +284,199 @@ __kernel_execve:
.align 3
.ent do_switch_stack
do_switch_stack:
- lda $30,-SWITCH_STACK_SIZE($30)
- stq $9,0($30)
- stq $10,8($30)
- stq $11,16($30)
- stq $12,24($30)
- stq $13,32($30)
- stq $14,40($30)
- stq $15,48($30)
- stq $26,56($30)
- stt $f0,64($30)
- stt $f1,72($30)
- stt $f2,80($30)
- stt $f3,88($30)
- stt $f4,96($30)
- stt $f5,104($30)
- stt $f6,112($30)
- stt $f7,120($30)
- stt $f8,128($30)
- stt $f9,136($30)
- stt $f10,144($30)
- stt $f11,152($30)
- stt $f12,160($30)
- stt $f13,168($30)
- stt $f14,176($30)
- stt $f15,184($30)
- stt $f16,192($30)
- stt $f17,200($30)
- stt $f18,208($30)
- stt $f19,216($30)
- stt $f20,224($30)
- stt $f21,232($30)
- stt $f22,240($30)
- stt $f23,248($30)
- stt $f24,256($30)
- stt $f25,264($30)
- stt $f26,272($30)
- stt $f27,280($30)
- mf_fpcr $f0 # get fpcr
- stt $f28,288($30)
- stt $f29,296($30)
- stt $f30,304($30)
- stt $f0,312($30) # save fpcr in slot of $f31
- ldt $f0,64($30) # dont let "do_switch_stack" change fp state.
- ret $31,($1),1
+ lda $30,-SWITCH_STACK_SIZE($30)
+ stq $9,0($30)
+ stq $10,8($30)
+ stq $11,16($30)
+ stq $12,24($30)
+ stq $13,32($30)
+ stq $14,40($30)
+ stq $15,48($30)
+ stq $26,56($30)
+ stt $f0,64($30)
+ stt $f1,72($30)
+ stt $f2,80($30)
+ stt $f3,88($30)
+ stt $f4,96($30)
+ stt $f5,104($30)
+ stt $f6,112($30)
+ stt $f7,120($30)
+ stt $f8,128($30)
+ stt $f9,136($30)
+ stt $f10,144($30)
+ stt $f11,152($30)
+ stt $f12,160($30)
+ stt $f13,168($30)
+ stt $f14,176($30)
+ stt $f15,184($30)
+ stt $f16,192($30)
+ stt $f17,200($30)
+ stt $f18,208($30)
+ stt $f19,216($30)
+ stt $f20,224($30)
+ stt $f21,232($30)
+ stt $f22,240($30)
+ stt $f23,248($30)
+ stt $f24,256($30)
+ stt $f25,264($30)
+ stt $f26,272($30)
+ stt $f27,280($30)
+ mf_fpcr $f0 # get fpcr
+ stt $f28,288($30)
+ stt $f29,296($30)
+ stt $f30,304($30)
+ stt $f0,312($30) # save fpcr in slot of $f31
+ ldt $f0,64($30) # dont let "do_switch_stack" change fp state.
+ ret $31,($1),1
.end do_switch_stack
.align 3
.ent undo_switch_stack
undo_switch_stack:
- ldq $9,0($30)
- ldq $10,8($30)
- ldq $11,16($30)
- ldq $12,24($30)
- ldq $13,32($30)
- ldq $14,40($30)
- ldq $15,48($30)
- ldq $26,56($30)
- ldt $f30,312($30) # get saved fpcr
- ldt $f0,64($30)
- ldt $f1,72($30)
- ldt $f2,80($30)
- ldt $f3,88($30)
- mt_fpcr $f30 # install saved fpcr
- ldt $f4,96($30)
- ldt $f5,104($30)
- ldt $f6,112($30)
- ldt $f7,120($30)
- ldt $f8,128($30)
- ldt $f9,136($30)
- ldt $f10,144($30)
- ldt $f11,152($30)
- ldt $f12,160($30)
- ldt $f13,168($30)
- ldt $f14,176($30)
- ldt $f15,184($30)
- ldt $f16,192($30)
- ldt $f17,200($30)
- ldt $f18,208($30)
- ldt $f19,216($30)
- ldt $f20,224($30)
- ldt $f21,232($30)
- ldt $f22,240($30)
- ldt $f23,248($30)
- ldt $f24,256($30)
- ldt $f25,264($30)
- ldt $f26,272($30)
- ldt $f27,280($30)
- ldt $f28,288($30)
- ldt $f29,296($30)
- ldt $f30,304($30)
- lda $30,SWITCH_STACK_SIZE($30)
- ret $31,($1),1
+ ldq $9,0($30)
+ ldq $10,8($30)
+ ldq $11,16($30)
+ ldq $12,24($30)
+ ldq $13,32($30)
+ ldq $14,40($30)
+ ldq $15,48($30)
+ ldq $26,56($30)
+ ldt $f30,312($30) # get saved fpcr
+ ldt $f0,64($30)
+ ldt $f1,72($30)
+ ldt $f2,80($30)
+ ldt $f3,88($30)
+ mt_fpcr $f30 # install saved fpcr
+ ldt $f4,96($30)
+ ldt $f5,104($30)
+ ldt $f6,112($30)
+ ldt $f7,120($30)
+ ldt $f8,128($30)
+ ldt $f9,136($30)
+ ldt $f10,144($30)
+ ldt $f11,152($30)
+ ldt $f12,160($30)
+ ldt $f13,168($30)
+ ldt $f14,176($30)
+ ldt $f15,184($30)
+ ldt $f16,192($30)
+ ldt $f17,200($30)
+ ldt $f18,208($30)
+ ldt $f19,216($30)
+ ldt $f20,224($30)
+ ldt $f21,232($30)
+ ldt $f22,240($30)
+ ldt $f23,248($30)
+ ldt $f24,256($30)
+ ldt $f25,264($30)
+ ldt $f26,272($30)
+ ldt $f27,280($30)
+ ldt $f28,288($30)
+ ldt $f29,296($30)
+ ldt $f30,304($30)
+ lda $30,SWITCH_STACK_SIZE($30)
+ ret $31,($1),1
.end undo_switch_stack
.align 3
.globl entUna
.ent entUna
entUna:
- lda $30,-256($30)
- stq $0,0($30)
- ldq $0,256($30) /* get PS */
- stq $1,8($30)
- stq $2,16($30)
- stq $3,24($30)
- and $0,8,$0 /* user mode? */
- stq $4,32($30)
- bne $0,entUnaUser /* yup -> do user-level unaligned fault */
- stq $5,40($30)
- stq $6,48($30)
- stq $7,56($30)
- stq $8,64($30)
- stq $9,72($30)
- stq $10,80($30)
- stq $11,88($30)
- stq $12,96($30)
- stq $13,104($30)
- stq $14,112($30)
- stq $15,120($30)
+ lda $30,-256($30)
+ stq $0,0($30)
+ ldq $0,256($30) /* get PS */
+ stq $1,8($30)
+ stq $2,16($30)
+ stq $3,24($30)
+ and $0,8,$0 /* user mode? */
+ stq $4,32($30)
+ bne $0,entUnaUser /* yup -> do user-level unaligned fault */
+ stq $5,40($30)
+ stq $6,48($30)
+ stq $7,56($30)
+ stq $8,64($30)
+ stq $9,72($30)
+ stq $10,80($30)
+ stq $11,88($30)
+ stq $12,96($30)
+ stq $13,104($30)
+ stq $14,112($30)
+ stq $15,120($30)
/* 16-18 PAL-saved */
- stq $19,152($30)
- stq $20,160($30)
- stq $21,168($30)
- stq $22,176($30)
- stq $23,184($30)
- stq $24,192($30)
- stq $25,200($30)
- stq $26,208($30)
- stq $27,216($30)
- stq $28,224($30)
- stq $29,232($30)
- stq $30,240($30)
- stq $31,248($30)
- lda $8,0x3fff
- bic $30,$8,$8
- jsr $26,do_entUna
- ldq $0,0($30)
- ldq $1,8($30)
- ldq $2,16($30)
- ldq $3,24($30)
- ldq $4,32($30)
- ldq $5,40($30)
- ldq $6,48($30)
- ldq $7,56($30)
- ldq $8,64($30)
- ldq $9,72($30)
- ldq $10,80($30)
- ldq $11,88($30)
- ldq $12,96($30)
- ldq $13,104($30)
- ldq $14,112($30)
- ldq $15,120($30)
+ stq $19,152($30)
+ stq $20,160($30)
+ stq $21,168($30)
+ stq $22,176($30)
+ stq $23,184($30)
+ stq $24,192($30)
+ stq $25,200($30)
+ stq $26,208($30)
+ stq $27,216($30)
+ stq $28,224($30)
+ stq $29,232($30)
+ lda $8,0x3fff
+ stq $31,248($30)
+ bic $30,$8,$8
+ jsr $26,do_entUna
+ ldq $0,0($30)
+ ldq $1,8($30)
+ ldq $2,16($30)
+ ldq $3,24($30)
+ ldq $4,32($30)
+ ldq $5,40($30)
+ ldq $6,48($30)
+ ldq $7,56($30)
+ ldq $8,64($30)
+ ldq $9,72($30)
+ ldq $10,80($30)
+ ldq $11,88($30)
+ ldq $12,96($30)
+ ldq $13,104($30)
+ ldq $14,112($30)
+ ldq $15,120($30)
/* 16-18 PAL-saved */
- ldq $19,152($30)
- ldq $20,160($30)
- ldq $21,168($30)
- ldq $22,176($30)
- ldq $23,184($30)
- ldq $24,192($30)
- ldq $25,200($30)
- ldq $26,208($30)
- ldq $27,216($30)
- ldq $28,224($30)
- ldq $29,232($30)
- ldq $30,240($30)
- lda $30,256($30)
- rti
+ ldq $19,152($30)
+ ldq $20,160($30)
+ ldq $21,168($30)
+ ldq $22,176($30)
+ ldq $23,184($30)
+ ldq $24,192($30)
+ ldq $25,200($30)
+ ldq $26,208($30)
+ ldq $27,216($30)
+ ldq $28,224($30)
+ ldq $29,232($30)
+ lda $30,256($30)
+ call_pal PAL_rti
.end entUna
.align 3
.ent entUnaUser
entUnaUser:
- ldq $0,0($30) /* restore original $0 */
- lda $30,256($30) /* pop entUna's stack frame */
- SAVE_ALL /* setup normal kernel stack */
- lda $30,-56($30)
- stq $9,0($30)
- stq $10,8($30)
- stq $11,16($30)
- stq $12,24($30)
- stq $13,32($30)
- stq $14,40($30)
- stq $15,48($30)
- lda $8,0x3fff
- addq $30,56,$19
- bic $30,$8,$8
- jsr $26,do_entUnaUser
- ldq $9,0($30)
- ldq $10,8($30)
- ldq $11,16($30)
- ldq $12,24($30)
- ldq $13,32($30)
- ldq $14,40($30)
- ldq $15,48($30)
- lda $30,56($30)
- br $31,ret_from_sys_call
-
+ ldq $0,0($30) /* restore original $0 */
+ lda $30,256($30) /* pop entUna's stack frame */
+ SAVE_ALL /* setup normal kernel stack */
+ lda $30,-56($30)
+ stq $9,0($30)
+ stq $10,8($30)
+ stq $11,16($30)
+ stq $12,24($30)
+ stq $13,32($30)
+ stq $14,40($30)
+ stq $15,48($30)
+ lda $8,0x3fff
+ addq $30,56,$19
+ bic $30,$8,$8
+ jsr $26,do_entUnaUser
+ ldq $9,0($30)
+ ldq $10,8($30)
+ ldq $11,16($30)
+ ldq $12,24($30)
+ ldq $13,32($30)
+ ldq $14,40($30)
+ ldq $15,48($30)
+ lda $30,56($30)
+ br ret_from_sys_call
.end entUnaUser
/*
@@ -479,36 +486,36 @@ entUnaUser:
.globl sys_fork
.ent sys_fork
sys_fork:
- bsr $1,do_switch_stack
- bis $31,SIGCHLD,$16
- bis $31,$31,$17
- bis $30,$30,$18
- jsr $26,alpha_clone
- bsr $1,undo_switch_stack
- ret $31,($26),1
+ bsr $1,do_switch_stack
+ bis $31,SIGCHLD,$16
+ mov $31,$17
+ mov $30,$18
+ jsr $26,alpha_clone
+ bsr $1,undo_switch_stack
+ ret $31,($26),1
.end sys_fork
.align 3
.globl sys_clone
.ent sys_clone
sys_clone:
- bsr $1,do_switch_stack
+ bsr $1,do_switch_stack
/* arg1 and arg2 come from the user */
- bis $30,$30,$18
- jsr $26,alpha_clone
- bsr $1,undo_switch_stack
- ret $31,($26),1
+ mov $30,$18
+ jsr $26,alpha_clone
+ bsr $1,undo_switch_stack
+ ret $31,($26),1
.end sys_clone
.align 3
.globl sys_vfork
.ent sys_vfork
sys_vfork:
- bsr $1,do_switch_stack
- bis $30,$30,$16
- jsr $26,alpha_vfork
- bsr $1,undo_switch_stack
- ret $31,($26),1
+ bsr $1,do_switch_stack
+ mov $30,$16
+ jsr $26,alpha_vfork
+ bsr $1,undo_switch_stack
+ ret $31,($26),1
.end sys_vfork
.align 3
@@ -516,12 +523,12 @@ sys_vfork:
.ent alpha_switch_to
alpha_switch_to:
.prologue 0
- bsr $1,do_switch_stack
+ bsr $1,do_switch_stack
call_pal PAL_swpctx
- lda $16,-2($31)
- call_pal PAL_tbi
- bsr $1,undo_switch_stack
- ret $31,($26),1
+ unop
+ bsr $1,undo_switch_stack
+ mov $17,$0
+ ret $31,($26),1
.end alpha_switch_to
/*
@@ -580,7 +587,7 @@ ret_from_reschedule:
bne $5,signal_return
restore_all:
RESTORE_ALL
- rti
+ call_pal PAL_rti
/* PTRACE syscall handler */
@@ -608,7 +615,7 @@ strace:
s8addq $0,$2,$2
beq $1,1f
ldq $27,0($2)
-1: jsr $26,($27),alpha_ni_syscall
+1: jsr $26,($27),sys_gettimeofday
ldgp $29,0($26)
/* check return.. */
@@ -634,15 +641,15 @@ strace_error:
stq $1,72($30) /* a3 for return */
bsr $1,do_switch_stack
- bis $19,$19,$9 /* save old syscall number */
- bis $20,$20,$10 /* save old a3 */
+ mov $19,$9 /* save old syscall number */
+ mov $20,$10 /* save old a3 */
jsr $26,syscall_trace
- bis $9,$9,$19
- bis $10,$10,$20
+ mov $9,$19
+ mov $10,$20
bsr $1,undo_switch_stack
- bis $31,$31,$26 /* tell "ret_from_sys_call" that we can restart */
- br $31,ret_from_sys_call
+ mov $31,$26 /* tell "ret_from_sys_call" we can restart */
+ br ret_from_sys_call
.align 3
handle_bottom_half:
@@ -653,7 +660,7 @@ handle_bottom_half:
ldq $19,0($30)
ldq $20,8($30)
addq $30,16,$30
- br $31,ret_from_handle_bh
+ br ret_from_handle_bh
.align 3
syscall_error:
@@ -671,38 +678,35 @@ syscall_error:
subq $31,$0,$0 /* with error in v0 */
addq $31,1,$1 /* set a3 for errno return */
stq $0,0($30)
- bis $31,$31,$26 /* tell "ret_from_sys_call" we can restart */
+ mov $31,$26 /* tell "ret_from_sys_call" we can restart */
stq $1,72($30) /* a3 for return */
- br $31,ret_from_sys_call
+ br ret_from_sys_call
ret_success:
stq $0,0($30)
stq $31,72($30) /* a3=0 => no error */
- br $31,ret_from_sys_call
+ br ret_from_sys_call
.align 3
signal_return:
- bis $30,$30,$17
+ mov $30,$17
br $1,do_switch_stack
- bis $30,$30,$18
- bis $31,$31,$16
+ mov $30,$18
+ mov $31,$16
jsr $26,do_signal
bsr $1,undo_switch_stack
- br $31,restore_all
+ br restore_all
.end entSys
#ifdef __SMP__
- .globl ret_from_smpfork
+ .globl ret_from_smp_fork
.align 3
-.ent ret_from_smpfork
-ret_from_smpfork:
- .set at
- mb /* Make the changed data visible before the freed lock. */
- stq $31,scheduler_lock
+.ent ret_from_smp_fork
+ret_from_smp_fork:
lda $26,ret_from_sys_call
+ mov $17,$16
jsr $31,schedule_tail
- .set noat
-.end ret_from_smpfork
+.end ret_from_smp_fork
#endif /* __SMP__ */
.align 3
@@ -715,51 +719,51 @@ reschedule:
ldq $19,0($30)
ldq $20,8($30)
addq $30,16,$30
- br $31,ret_from_reschedule
+ br ret_from_reschedule
.end reschedule
.align 3
.ent sys_sigreturn
sys_sigreturn:
- bis $30,$30,$17
+ mov $30,$17
+ lda $18,-SWITCH_STACK_SIZE($30)
lda $30,-SWITCH_STACK_SIZE($30)
- bis $30,$30,$18
jsr $26,do_sigreturn
br $1,undo_switch_stack
- br $31,ret_from_sys_call
+ br ret_from_sys_call
.end sys_sigreturn
.align 3
.ent sys_rt_sigreturn
sys_rt_sigreturn:
- bis $30,$30,$17
+ mov $30,$17
+ lda $18,-SWITCH_STACK_SIZE($30)
lda $30,-SWITCH_STACK_SIZE($30)
- bis $30,$30,$18
jsr $26,do_rt_sigreturn
br $1,undo_switch_stack
- br $31,ret_from_sys_call
+ br ret_from_sys_call
.end sys_rt_sigreturn
.align 3
.ent sys_sigsuspend
sys_sigsuspend:
- bis $30,$30,$17
+ mov $30,$17
br $1,do_switch_stack
- bis $30,$30,$18
+ mov $30,$18
jsr $26,do_sigsuspend
lda $30,SWITCH_STACK_SIZE($30)
- br $31,ret_from_sys_call
+ br ret_from_sys_call
.end sys_sigsuspend
.align 3
.ent sys_rt_sigsuspend
sys_rt_sigsuspend:
- bis $30,$30,$18
+ mov $30,$18
br $1,do_switch_stack
- bis $30,$30,$19
+ mov $30,$19
jsr $26,do_rt_sigsuspend
lda $30,SWITCH_STACK_SIZE($30)
- br $31,ret_from_sys_call
+ br ret_from_sys_call
.end sys_rt_sigsuspend
.data
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 67c08778d..38bd43947 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -37,6 +37,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/sysinfo.h>
+#include <asm/hwrpb.h>
extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
extern int do_pipe(int *);
@@ -140,6 +141,7 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
struct inode *inode;
struct osf_dirent_callback buf;
+ lock_kernel();
error = -EBADF;
file = fget(fd);
if (!file)
@@ -172,6 +174,7 @@ asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
out_putf:
fput(file);
out:
+ unlock_kernel();
return error;
}
@@ -317,8 +320,8 @@ static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsi
struct super_block * sb = inode->i_sb;
int error;
- error = -ENOSYS;
- if (sb->s_op->statfs) {
+ error = -ENODEV;
+ if (sb && sb->s_op && sb->s_op->statfs) {
set_fs(KERNEL_DS);
error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat));
set_fs(USER_DS);
@@ -762,14 +765,10 @@ asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args)
asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
{
unsigned long usp = rdusp();
- unsigned long oss_sp, oss_os;
+ unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size;
+ unsigned long oss_os = on_sig_stack(usp);
int error;
- if (uoss) {
- oss_sp = current->sas_ss_sp + current->sas_ss_size;
- oss_os = on_sig_stack(usp);
- }
-
if (uss) {
void *ss_sp;
@@ -880,11 +879,27 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
int *start, void *arg)
{
unsigned long w;
+ struct percpu_struct *cpu;
switch (op) {
case GSI_IEEE_FP_CONTROL:
/* Return current software fp control & status bits. */
- w = current->tss.flags & IEEE_SW_MASK;
+ /* Note that DU doesn't verify available space here. */
+
+ /* EV6 implements most of the bits in hardware. If
+ UNDZ is not set, UNFD is maintained in software. */
+ if (implver() == IMPLVER_EV6) {
+ unsigned long fpcr = rdfpcr();
+ w = ieee_fpcr_to_swcr(fpcr);
+ if (!(fpcr & FPCR_UNDZ)) {
+ w &= ~IEEE_TRAP_ENABLE_UNF;
+ w |= current->tss.flags & IEEE_TRAP_ENABLE_UNF;
+ }
+ } else {
+ /* Otherwise we are forced to do everything in sw. */
+ w = current->tss.flags & IEEE_SW_MASK;
+ }
+
if (put_user(w, (unsigned long *) buffer))
return -EFAULT;
return 0;
@@ -898,10 +913,28 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
break;
case GSI_UACPROC:
+ if (nbytes < sizeof(unsigned int))
+ return -EINVAL;
w = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
if (put_user(w, (unsigned int *)buffer))
return -EFAULT;
- return 0;
+ return 1;
+
+ case GSI_PROC_TYPE:
+ if (nbytes < sizeof(unsigned long))
+ return -EINVAL;
+ cpu = (struct percpu_struct*)
+ ((char*)hwrpb + hwrpb->processor_offset);
+ if (put_user(w, (unsigned long *)buffer))
+ return -EFAULT;
+ return 1;
+
+ case GSI_GET_HWRPB:
+ if (nbytes < sizeof(*hwrpb))
+ return -EINVAL;
+ if (copy_to_user(buffer, hwrpb, nbytes) != 0)
+ return -EFAULT;
+ return 1;
default:
break;
@@ -916,7 +949,7 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
{
switch (op) {
case SSI_IEEE_FP_CONTROL: {
- unsigned long swcr, fpcr;
+ unsigned long swcr, fpcr, undz;
/*
* Alpha Architecture Handbook 4.7.7.3:
@@ -931,11 +964,12 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
current->tss.flags &= ~IEEE_SW_MASK;
current->tss.flags |= swcr & IEEE_SW_MASK;
- /* Update the real fpcr. For exceptions that are disabled in
- software but have not been seen, enable the exception in
- hardware so that we can update our software status mask. */
- fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
- fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+ /* Update the real fpcr. Keep UNFD off if not UNDZ. */
+ fpcr = rdfpcr();
+ undz = (fpcr & FPCR_UNDZ);
+ fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ);
+ fpcr |= ieee_swcr_to_fpcr(swcr);
+ fpcr &= ~(undz << 1);
wrfpcr(fpcr);
return 0;
@@ -1390,8 +1424,9 @@ asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) -
offsetof(struct timex32, time)))
return -EFAULT;
-
- if ((ret = do_adjtimex(&txc)))
+
+ ret = do_adjtimex(&txc);
+ if (ret < 0)
return ret;
/* copy back to timex32 */
@@ -1401,5 +1436,5 @@ asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
(put_tv32(&txc_p->time, &txc.time)))
return -EFAULT;
- return 0;
+ return ret;
}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 55e211a23..93d8db602 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -237,10 +237,13 @@ void exit_thread(void)
void flush_thread(void)
{
- /* Arrange for each exec'ed process to start off with a
- clean slate with respect to the FPU. */
+ /* Arrange for each exec'ed process to start off with a clean slate
+ with respect to the FPU. This is all exceptions disabled. Note
+ that EV6 defines UNFD valid only with UNDZ, which we don't want
+ for IEEE conformance -- so that disabled bit remains in software. */
+
current->tss.flags &= ~IEEE_SW_MASK;
- wrfpcr(FPCR_DYN_NORMAL);
+ wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED);
}
void release_thread(struct task_struct *dead_task)
@@ -270,8 +273,6 @@ int alpha_vfork(struct switch_stack * swstack)
(struct pt_regs *) (swstack+1));
}
-extern void ret_from_sys_call(void);
-extern void ret_from_smpfork(void);
/*
* Copy an alpha thread..
*
@@ -282,9 +283,13 @@ extern void ret_from_smpfork(void);
* Use the passed "regs" pointer to determine how much space we need
* for a kernel fork().
*/
+
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
+ extern void ret_from_sys_call(void);
+ extern void ret_from_smp_fork(void);
+
struct pt_regs * childregs;
struct switch_stack * childstack, *stack;
unsigned long stack_offset;
@@ -292,18 +297,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
if (!(regs->ps & 8))
stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
- childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p);
+ childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (long)p);
*childregs = *regs;
childregs->r0 = 0;
childregs->r19 = 0;
- childregs->r20 = 1; /* OSF/1 has some strange fork() semantics.. */
+ childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */
regs->r20 = 0;
stack = ((struct switch_stack *) regs) - 1;
childstack = ((struct switch_stack *) childregs) - 1;
*childstack = *stack;
#ifdef __SMP__
- childstack->r26 = (unsigned long) ret_from_smpfork;
+ childstack->r26 = (unsigned long) ret_from_smp_fork;
#else
childstack->r26 = (unsigned long) ret_from_sys_call;
#endif
@@ -328,10 +333,12 @@ void dump_thread(struct pt_regs * pt, struct user * dump)
dump->start_code = current->mm->start_code;
dump->start_data = current->mm->start_data;
dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
- dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
- dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) >> PAGE_SHIFT;
- dump->u_ssize =
- (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ dump->u_tsize = ((current->mm->end_code - dump->start_code)
+ >> PAGE_SHIFT);
+ dump->u_dsize = ((current->mm->brk + PAGE_SIZE-1 - dump->start_data)
+ >> PAGE_SHIFT);
+ dump->u_ssize = (current->mm->start_stack - dump->start_stack
+ + PAGE_SIZE-1) >> PAGE_SHIFT;
/*
* We store the registers in an order/format that is
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index bee005933..8a0efe52d 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -165,7 +165,7 @@ extern unsigned long est_cycle_freq;
extern void SMC93x_Init(void);
/* smc37c669.c */
-extern void SMC669_Init(void);
+extern void SMC669_Init(int);
/* es1888.c */
extern void es1888_init(void);
@@ -187,6 +187,7 @@ extern void entInt(void);
extern void entMM(void);
extern void entSys(void);
extern void entUna(void);
+extern void entDbg(void);
/* process.c */
extern void generic_kill_arch (int mode, char *reboot_cmd);
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 42821d903..80b4454e1 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -183,6 +183,11 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p,
vec = get_sysvec_byname(p+9);
continue;
}
+
+ if (strncmp(p, "cycle=", 6) == 0) {
+ est_cycle_freq = simple_strtol(p+6, NULL, 0);
+ continue;
+ }
}
/* Replace the command line, not that we've killed it with strtok. */
@@ -721,8 +726,8 @@ int get_cpuinfo(char *buffer)
(char*)cpu->serial_no,
systype_name, sysvariation_name, hwrpb->sys_revision,
(char*)hwrpb->ssn,
- hwrpb->cycle_freq ? : est_cycle_freq,
- hwrpb->cycle_freq ? "" : "est.",
+ est_cycle_freq ? : hwrpb->cycle_freq,
+ est_cycle_freq ? "est." : "",
hwrpb->intr_freq / 4096,
(100 * hwrpb->intr_freq / 4096) % 100,
hwrpb->pagesize,
diff --git a/arch/alpha/kernel/smc37c669.c b/arch/alpha/kernel/smc37c669.c
index 1202b7b90..caab7accc 100644
--- a/arch/alpha/kernel/smc37c669.c
+++ b/arch/alpha/kernel/smc37c669.c
@@ -862,7 +862,7 @@ typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY {
*/
SMC37c669_CONFIG_REGS *SMC37c669_detect(
- void
+ int
);
unsigned int SMC37c669_enable_device(
@@ -1015,6 +1015,29 @@ __initdata =
};
/*
+** The following definition is for the MONET (XP1000) IRQ
+** translation table.
+*/
+static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_monet_irq_table[]
+__initdata =
+ {
+ { SMC37c669_DEVICE_IRQ_A, -1 },
+ { SMC37c669_DEVICE_IRQ_B, -1 },
+ { SMC37c669_DEVICE_IRQ_C, 6 },
+ { SMC37c669_DEVICE_IRQ_D, 7 },
+ { SMC37c669_DEVICE_IRQ_E, 4 },
+ { SMC37c669_DEVICE_IRQ_F, 3 },
+ { SMC37c669_DEVICE_IRQ_H, -1 },
+ { -1, -1 } /* End of table */
+ };
+
+static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_tables[] __initdata =
+ {
+ SMC37c669_default_irq_table,
+ SMC37c669_monet_irq_table
+ };
+
+/*
** DRQ Translation Table
**
** The DRQ translation table is a list of SMC37c669 device and
@@ -1163,7 +1186,7 @@ struct DDB smc_ddb = {
**
**--
*/
-SMC37c669_CONFIG_REGS * __init SMC37c669_detect( void )
+SMC37c669_CONFIG_REGS * __init SMC37c669_detect( int index )
{
int i;
SMC37c669_DEVICE_ID_REGISTER id;
@@ -1196,7 +1219,7 @@ SMC37c669_CONFIG_REGS * __init SMC37c669_detect( void )
/*
** Initialize the IRQ and DRQ translation tables.
*/
- SMC37c669_irq_table = SMC37c669_default_irq_table;
+ SMC37c669_irq_table = SMC37c669_irq_tables[ index ];
SMC37c669_drq_table = SMC37c669_default_drq_table;
/*
** erfix
@@ -2516,13 +2539,13 @@ SMC37c669_dump_registers(void)
* None
*
*/
-void __init SMC669_Init ( void )
+void __init SMC669_Init ( int index )
{
SMC37c669_CONFIG_REGS *SMC_base;
unsigned long flags;
__save_and_cli(flags);
- if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) {
+ if ( ( SMC_base = SMC37c669_detect( index ) ) != NULL ) {
#if SMC_DEBUG
SMC37c669_config_mode( TRUE );
SMC37c669_dump_registers( );
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 25615e43d..aa1eaf363 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -37,7 +37,18 @@
#define DBGS(args)
#endif
-struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
+struct ipi_msg_flush_tb_struct {
+ volatile unsigned int flush_tb_mask;
+ union {
+ struct mm_struct * flush_mm;
+ struct vm_area_struct * flush_vma;
+ } p;
+ unsigned long flush_addr;
+ unsigned long flush_end;
+};
+
+static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
+static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
struct cpuinfo_alpha cpu_data[NR_CPUS];
@@ -499,6 +510,7 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
return;
}
mdelay(1);
+ barrier();
}
DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid));
}
@@ -541,6 +553,7 @@ delay1:
if (!(hwrpb->txrdy & cpumask))
goto ready1;
udelay(100);
+ barrier();
}
goto timeout;
@@ -549,6 +562,7 @@ delay2:
if (!(hwrpb->txrdy & cpumask))
goto ready2;
udelay(100);
+ barrier();
}
goto timeout;
@@ -783,7 +797,7 @@ flush_tlb_all(void)
unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
long timeout = 1000000;
- spin_lock_own(&kernel_flag, "flush_tlb_all");
+ spin_lock(&flush_tb_lock);
ipi_msg_flush_tb.flush_tb_mask = to_whom;
send_ipi_message(to_whom, IPI_TLB_ALL);
@@ -800,6 +814,8 @@ flush_tlb_all(void)
ipi_msg_flush_tb.flush_tb_mask);
ipi_msg_flush_tb.flush_tb_mask = 0;
}
+
+ spin_unlock(&flush_tb_lock);
}
void
@@ -808,7 +824,7 @@ flush_tlb_mm(struct mm_struct *mm)
unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
long timeout = 1000000;
- spin_lock_own(&kernel_flag, "flush_tlb_mm");
+ spin_lock(&flush_tb_lock);
ipi_msg_flush_tb.flush_tb_mask = to_whom;
ipi_msg_flush_tb.p.flush_mm = mm;
@@ -830,6 +846,8 @@ flush_tlb_mm(struct mm_struct *mm)
ipi_msg_flush_tb.flush_tb_mask);
ipi_msg_flush_tb.flush_tb_mask = 0;
}
+
+ spin_unlock(&flush_tb_lock);
}
void
@@ -840,7 +858,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
struct mm_struct * mm = vma->vm_mm;
int timeout = 1000000;
- spin_lock_own(&kernel_flag, "flush_tlb_page");
+ spin_lock(&flush_tb_lock);
ipi_msg_flush_tb.flush_tb_mask = to_whom;
ipi_msg_flush_tb.p.flush_vma = vma;
@@ -863,6 +881,8 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
ipi_msg_flush_tb.flush_tb_mask);
ipi_msg_flush_tb.flush_tb_mask = 0;
}
+
+ spin_unlock(&flush_tb_lock);
}
void
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index 656e5d868..c464c37ec 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -316,7 +316,7 @@ dp264_pci_fixup(void)
{
layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
common_pci_fixup(dp264_map_irq, common_swizzle);
- SMC669_Init();
+ SMC669_Init(0);
}
static void __init
@@ -325,7 +325,7 @@ monet_pci_fixup(void)
layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
common_pci_fixup(monet_map_irq, monet_swizzle);
/* es1888_init(); */ /* later? */
- SMC669_Init();
+ SMC669_Init(1);
}
static void __init
@@ -333,7 +333,7 @@ webbrick_pci_fixup(void)
{
layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
common_pci_fixup(webbrick_map_irq, common_swizzle);
- SMC669_Init();
+ SMC669_Init(0);
}
diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c
index c6f908618..f9c4b64c5 100644
--- a/arch/alpha/kernel/sys_miata.c
+++ b/arch/alpha/kernel/sys_miata.c
@@ -267,7 +267,7 @@ miata_pci_fixup(void)
{
layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
common_pci_fixup(miata_map_irq, miata_swizzle);
- SMC669_Init(); /* it might be a GL (fails harmlessly if not) */
+ SMC669_Init(0); /* it might be a GL (fails harmlessly if not) */
es1888_init();
}
diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c
index a03f451d0..a35fdd219 100644
--- a/arch/alpha/kernel/sys_sx164.c
+++ b/arch/alpha/kernel/sys_sx164.c
@@ -183,7 +183,7 @@ sx164_pci_fixup(void)
{
layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
common_pci_fixup(sx164_map_irq, common_swizzle);
- SMC669_Init();
+ SMC669_Init(0);
}
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 2f9363113..a84378926 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -18,6 +18,9 @@
* fixed tick loss calculation in timer_interrupt
* (round system clock to nearest tick instead of truncating)
* fixed algorithm in time_init for getting time from CMOS clock
+ * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net)
+ * fixed algorithm in do_gettimeofday() for calculating the precise time
+ * from processor cycle counter (now taking lost_ticks into account)
*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -223,7 +226,7 @@ time_init(void)
{
void (*irq_handler)(int, void *, struct pt_regs *);
unsigned int year, mon, day, hour, min, sec, cc1, cc2;
- unsigned long cycle_freq;
+ unsigned long cycle_freq, diff, one_percent;
/*
* The Linux interpretation of the CMOS clock register contents:
@@ -237,19 +240,30 @@ time_init(void)
/* Read cycle counter exactly on falling edge of update flag */
cc1 = rpcc();
- /* If our cycle frequency isn't valid, go another round and give
- a guess at what it should be. */
- cycle_freq = hwrpb->cycle_freq;
- if (cycle_freq == 0) {
- printk("HWRPB cycle frequency bogus. Estimating... ");
-
+ if (!est_cycle_freq) {
+ /* Sometimes the hwrpb->cycle_freq value is bogus.
+ Go another round to check up on it and see. */
do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
cc2 = rpcc();
- est_cycle_freq = cycle_freq = cc2 - cc1;
+ est_cycle_freq = cc2 - cc1;
cc1 = cc2;
+ }
- printk("%lu Hz\n", cycle_freq);
+ /* If the given value is within 1% of what we calculated,
+ accept it. Otherwise, use what we found. */
+ cycle_freq = hwrpb->cycle_freq;
+ one_percent = cycle_freq / 100;
+ diff = cycle_freq - est_cycle_freq;
+ if (diff < 0)
+ diff = -diff;
+ if (diff > one_percent) {
+ cycle_freq = est_cycle_freq;
+ printk("HWRPB cycle frequency bogus. Estimated %lu Hz\n",
+ cycle_freq);
+ }
+ else {
+ est_cycle_freq = 0;
}
/* From John Bowman <bowman@math.ualberta.ca>: allow the values
@@ -314,8 +328,10 @@ time_init(void)
void
do_gettimeofday(struct timeval *tv)
{
- unsigned long flags, now, delta_cycles, delta_usec;
+ unsigned long flags, delta_cycles, delta_usec;
unsigned long sec, usec;
+ __u32 now;
+ extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
now = rpcc();
save_and_cli(flags);
@@ -337,9 +353,15 @@ do_gettimeofday(struct timeval *tv)
* with no clear gain.
*/
- delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625;
+ delta_usec = (delta_cycles * state.scaled_ticks_per_cycle
+ + state.partial_tick
+ + (lost_ticks << FIX_SHIFT) ) * 15625;
delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
+ /* the 'lost_tics' term above implements this:
+ * delta_usec += lost_ticks * (1000000 / HZ);
+ */
+
usec += delta_usec;
if (usec >= 1000000) {
sec += 1;
@@ -357,7 +379,6 @@ do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
sti();
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index e925cf6ff..2548f0914 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -121,17 +121,20 @@ long alpha_fp_emul (unsigned long pc);
#endif
asmlinkage void
-do_entArith(unsigned long summary, unsigned long write_mask, unsigned long a2,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs regs)
+do_entArith(unsigned long summary, unsigned long write_mask,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, struct pt_regs regs)
{
- if ((summary & 1)) {
- /*
- * Software-completion summary bit is set, so try to
- * emulate the instruction.
- */
- if (alpha_fp_emul_imprecise(&regs, write_mask)) {
- return; /* emulation was successful */
+ if (summary & 1) {
+ /* Software-completion summary bit is set, so try to
+ emulate the instruction. */
+ if (implver() == IMPLVER_EV6) {
+ /* Whee! EV6 has precice exceptions. */
+ if (alpha_fp_emul(regs.pc - 4))
+ return;
+ } else {
+ if (alpha_fp_emul_imprecise(&regs, write_mask))
+ return;
}
}
@@ -141,22 +144,26 @@ do_entArith(unsigned long summary, unsigned long write_mask, unsigned long a2,
current->comm, regs.pc, summary, write_mask);
#endif
die_if_kernel("Arithmetic fault", &regs, 0, 0);
- force_sig(SIGFPE, current);
+ send_sig(SIGFPE, current, 1);
unlock_kernel();
}
-asmlinkage void do_entIF(unsigned long type, unsigned long a1,
- unsigned long a2, unsigned long a3, unsigned long a4,
- unsigned long a5, struct pt_regs regs)
+asmlinkage void
+do_entIF(unsigned long type, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, struct pt_regs regs)
{
- lock_kernel();
die_if_kernel("Instruction fault", &regs, type, 0);
switch (type) {
case 0: /* breakpoint */
if (ptrace_cancel_bpt(current)) {
regs.pc -= 4; /* make pc point to former bpt */
}
- force_sig(SIGTRAP, current);
+ send_sig(SIGTRAP, current, 1);
+ break;
+
+ case 1: /* bugcheck */
+ send_sig(SIGTRAP, current, 1);
break;
case 2: /* gentrap */
@@ -170,14 +177,13 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1,
switch ((long) regs.r16) {
case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
- case GEN_FLTINE:
- force_sig(SIGFPE, current);
+ case GEN_FLTINE: case GEN_ROPRAND:
+ send_sig(SIGFPE, current, 1);
break;
case GEN_DECOVF:
case GEN_DECDIV:
case GEN_DECINV:
- case GEN_ROPRAND:
case GEN_ASSERTERR:
case GEN_NULPTRERR:
case GEN_STKOVF:
@@ -192,44 +198,50 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1,
case GEN_SUBRNG5:
case GEN_SUBRNG6:
case GEN_SUBRNG7:
- force_sig(SIGILL, current);
+ send_sig(SIGTRAP, current, 1);
break;
}
break;
- case 1: /* bugcheck */
case 3: /* FEN fault */
- force_sig(SIGILL, current);
+ send_sig(SIGILL, current, 1);
break;
case 4: /* opDEC */
-#ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION
- {
- unsigned int opcode;
-
- /* get opcode of faulting instruction: */
- get_user(opcode, (__u32*)(regs.pc - 4));
- opcode >>= 26;
- if (opcode == 0x16) {
- /*
- * It's a FLTI instruction, emulate it
- * (we don't do no stinkin' VAX fp...)
- */
- if (!alpha_fp_emul(regs.pc - 4))
- force_sig(SIGFPE, current);
- break;
- }
+ if (implver() == IMPLVER_EV4) {
+ /* EV4 does not implement anything except normal
+ rounding. Everything else will come here as
+ an illegal instruction. Emulate them. */
+ if (alpha_fp_emul(regs.pc - 4))
+ return;
}
-#endif
- force_sig(SIGILL, current);
+ send_sig(SIGILL, current, 1);
break;
default:
panic("do_entIF: unexpected instruction-fault type");
}
+}
+
+/* There is an ifdef in the PALcode in MILO that enables a
+ "kernel debugging entry point" as an unprivilaged call_pal.
+
+ We don't want to have anything to do with it, but unfortunately
+ several versions of MILO included in distributions have it enabled,
+ and if we don't put something on the entry point we'll oops. */
+
+asmlinkage void
+do_entDbg(unsigned long type, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, struct pt_regs regs)
+{
+ lock_kernel();
+ die_if_kernel("Instruction fault", &regs, type, 0);
+ force_sig(SIGILL, current);
unlock_kernel();
}
+
/*
* entUna has a different register layout to be reasonably simple. It
* needs access to all the integer registers (the kernel doesn't use
@@ -857,14 +869,14 @@ do_entUnaUser(void * va, unsigned long opcode,
give_sigsegv:
regs->pc -= 4; /* make pc point to faulting insn */
lock_kernel();
- force_sig(SIGSEGV, current);
+ send_sig(SIGSEGV, current, 1);
unlock_kernel();
return;
give_sigbus:
regs->pc -= 4;
lock_kernel();
- force_sig(SIGBUS, current);
+ send_sig(SIGBUS, current, 1);
unlock_kernel();
return;
}
@@ -895,4 +907,5 @@ trap_init(void)
wrent(entIF, 3);
wrent(entUna, 4);
wrent(entSys, 5);
+ wrent(entDbg, 6);
}
diff --git a/arch/alpha/lib/clear_user.S b/arch/alpha/lib/clear_user.S
index 65d7e2f28..21d86eb78 100644
--- a/arch/alpha/lib/clear_user.S
+++ b/arch/alpha/lib/clear_user.S
@@ -80,6 +80,7 @@ $tail:
ret $31, ($28), 1 # .. e1 :
__do_clear_user:
+ ldgp $29,0($27) # we do exceptions -- we need the gp.
and $6, 7, $4 # e0 : find dest misalignment
beq $0, $zerolength # .. e1 :
addq $0, $4, $1 # e0 : bias counter
diff --git a/arch/alpha/lib/copy_user.S b/arch/alpha/lib/copy_user.S
index aa309b9f5..7cc7382ab 100644
--- a/arch/alpha/lib/copy_user.S
+++ b/arch/alpha/lib/copy_user.S
@@ -46,6 +46,8 @@
.globl __copy_user
.ent __copy_user
__copy_user:
+ ldgp $29,0($27) # we do exceptions -- we need the gp.
+ .prologue 1
and $6,7,$3
beq $0,$35
beq $3,$36
@@ -107,7 +109,7 @@ $43:
$66:
EXI( ldq $1,0($7) )
subq $4,8,$4
- stq $1,0($6)
+ EXO( stq $1,0($6) )
addq $7,8,$7
subq $0,8,$0
addq $6,8,$6
diff --git a/arch/alpha/lib/io.c b/arch/alpha/lib/io.c
index 4172216d8..71ba9d4bf 100644
--- a/arch/alpha/lib/io.c
+++ b/arch/alpha/lib/io.c
@@ -405,15 +405,16 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
* Copy data from "real" memory space to IO memory space.
* This needs to be optimized.
*/
-void _memcpy_toio(unsigned long to, void * from, long count)
+void _memcpy_toio(unsigned long to, const void * from, long count)
{
/* Optimize co-aligned transfers. Everything else gets handled
a byte at a time. */
+ /* FIXME -- align FROM. */
if (count >= 8 && (to & 7) == ((long)from & 7)) {
count -= 8;
do {
- writeq(*(u64 *)from, to);
+ writeq(*(const u64 *)from, to);
count -= 8;
to += 8;
from += 8;
@@ -424,7 +425,7 @@ void _memcpy_toio(unsigned long to, void * from, long count)
if (count >= 4 && (to & 3) == ((long)from & 3)) {
count -= 4;
do {
- writel(*(u32 *)from, to);
+ writel(*(const u32 *)from, to);
count -= 4;
to += 4;
from += 4;
@@ -435,7 +436,7 @@ void _memcpy_toio(unsigned long to, void * from, long count)
if (count >= 2 && (to & 1) == ((long)from & 1)) {
count -= 2;
do {
- writew(*(u16 *)from, to);
+ writew(*(const u16 *)from, to);
count -= 2;
to += 2;
from += 2;
@@ -444,7 +445,7 @@ void _memcpy_toio(unsigned long to, void * from, long count)
}
while (count > 0) {
- writeb(*(u8 *) from, to);
+ writeb(*(const u8 *) from, to);
count--;
to++;
from++;
diff --git a/arch/alpha/lib/strlen_user.S b/arch/alpha/lib/strlen_user.S
index cdf71158f..1f4fb07f5 100644
--- a/arch/alpha/lib/strlen_user.S
+++ b/arch/alpha/lib/strlen_user.S
@@ -27,7 +27,8 @@
.align 3
__strlen_user:
- .prologue 0
+ ldgp $29,0($27) # we do exceptions -- we need the gp.
+ .prologue 1
EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned)
lda t1, -1(zero)
diff --git a/arch/alpha/lib/strncpy_from_user.S b/arch/alpha/lib/strncpy_from_user.S
index aff7c1d2b..998450196 100644
--- a/arch/alpha/lib/strncpy_from_user.S
+++ b/arch/alpha/lib/strncpy_from_user.S
@@ -31,6 +31,7 @@
.globl __strncpy_from_user
.ent __strncpy_from_user
.frame $30, 0, $26
+ .prologue 1
.align 3
$aligned:
@@ -99,6 +100,7 @@ $a_eoc:
/*** The Function Entry Point ***/
.align 3
__strncpy_from_user:
+ ldgp $29, 0($27) # we do exceptions -- we need the gp.
mov a0, v0 # save the string start
beq a2, $zerolength
diff --git a/arch/alpha/math-emu/fp-emul.c b/arch/alpha/math-emu/fp-emul.c
index 97f4bc326..122ec85ac 100644
--- a/arch/alpha/math-emu/fp-emul.c
+++ b/arch/alpha/math-emu/fp-emul.c
@@ -13,6 +13,7 @@
#define OPC_INTL 0x11
#define OPC_INTS 0x12
#define OPC_INTM 0x13
+#define OPC_FLTC 0x14
#define OPC_FLTV 0x15
#define OPC_FLTI 0x16
#define OPC_FLTL 0x17
@@ -21,33 +22,37 @@
#define OPC_JSR 0x1a
+#define OP_FUN(OP,FUN) ((OP << 26) | (FUN << 5))
+
/*
- * "Base" function codes for the FLTI-class instructions. These
- * instructions all have opcode 0x16. Note that in most cases these
- * actually correspond to the "chopped" form of the instruction. Not
- * to worry---we extract the qualifier bits separately and deal with
- * them separately. Notice that base function code 0x2c is used for
- * both CVTTS and CVTST. The other bits in the function code are used
- * to distinguish the two.
+ * "Base" function codes for the FLTI-class instructions.
+ * Note that in most cases these actually correspond to the "chopped"
+ * form of the instruction. Not to worry---we extract the qualifier
+ * bits separately and deal with them separately. Notice that base
+ * function code 0x2c is used for both CVTTS and CVTST. The other bits
+ * in the function code are used to distinguish the two.
*/
-#define FLTI_FUNC_ADDS 0x000
-#define FLTI_FUNC_ADDT 0x020
-#define FLTI_FUNC_CMPTEQ 0x025
-#define FLTI_FUNC_CMPTLT 0x026
-#define FLTI_FUNC_CMPTLE 0x027
-#define FLTI_FUNC_CMPTUN 0x024
-#define FLTI_FUNC_CVTTS_or_CVTST 0x02c
-#define FLTI_FUNC_CVTTQ 0x02f
-#define FLTI_FUNC_CVTQS 0x03c
-#define FLTI_FUNC_CVTQT 0x03e
-#define FLTI_FUNC_DIVS 0x003
-#define FLTI_FUNC_DIVT 0x023
-#define FLTI_FUNC_MULS 0x002
-#define FLTI_FUNC_MULT 0x022
-#define FLTI_FUNC_SUBS 0x001
-#define FLTI_FUNC_SUBT 0x021
-
-#define FLTI_FUNC_CVTQL 0x030 /* opcode 0x17 */
+#define FLTI_FUNC_ADDS OP_FUN(OPC_FLTI, 0x000)
+#define FLTI_FUNC_ADDT OP_FUN(OPC_FLTI, 0x020)
+#define FLTI_FUNC_CMPTEQ OP_FUN(OPC_FLTI, 0x025)
+#define FLTI_FUNC_CMPTLT OP_FUN(OPC_FLTI, 0x026)
+#define FLTI_FUNC_CMPTLE OP_FUN(OPC_FLTI, 0x027)
+#define FLTI_FUNC_CMPTUN OP_FUN(OPC_FLTI, 0x024)
+#define FLTI_FUNC_CVTTS_or_CVTST OP_FUN(OPC_FLTI, 0x02c)
+#define FLTI_FUNC_CVTTQ OP_FUN(OPC_FLTI, 0x02f)
+#define FLTI_FUNC_CVTQS OP_FUN(OPC_FLTI, 0x03c)
+#define FLTI_FUNC_CVTQT OP_FUN(OPC_FLTI, 0x03e)
+#define FLTI_FUNC_DIVS OP_FUN(OPC_FLTI, 0x003)
+#define FLTI_FUNC_DIVT OP_FUN(OPC_FLTI, 0x023)
+#define FLTI_FUNC_MULS OP_FUN(OPC_FLTI, 0x002)
+#define FLTI_FUNC_MULT OP_FUN(OPC_FLTI, 0x022)
+#define FLTI_FUNC_SUBS OP_FUN(OPC_FLTI, 0x001)
+#define FLTI_FUNC_SUBT OP_FUN(OPC_FLTI, 0x021)
+
+#define FLTC_FUNC_SQRTS OP_FUN(OPC_FLTC, 0x00B)
+#define FLTC_FUNC_SQRTT OP_FUN(OPC_FLTC, 0x02B)
+
+#define FLTL_FUNC_CVTQL OP_FUN(OPC_FLTL, 0x030)
#define MISC_TRAPB 0x0000
#define MISC_EXCB 0x0400
@@ -101,7 +106,7 @@ void cleanup_module(void)
long
alpha_fp_emul (unsigned long pc)
{
- unsigned long opcode, fa, fb, fc, func, mode;
+ unsigned long op_fun, fa, fb, fc, func, mode;
unsigned long fpcw = current->tss.flags;
unsigned long va, vb, vc, res, fpcr;
__u32 insn;
@@ -110,10 +115,11 @@ alpha_fp_emul (unsigned long pc)
get_user(insn, (__u32*)pc);
fc = (insn >> 0) & 0x1f; /* destination register */
- func = (insn >> 5) & 0x7ff;
fb = (insn >> 16) & 0x1f;
fa = (insn >> 21) & 0x1f;
- opcode = insn >> 26;
+ func = (insn >> 5) & 0x7ff;
+ mode = (insn >> 5) & 0xc0;
+ op_fun = insn & OP_FUN(0x3f, 0x3f);
va = alpha_read_fp_reg(fa);
vb = alpha_read_fp_reg(fb);
@@ -123,7 +129,6 @@ alpha_fp_emul (unsigned long pc)
* Try the operation in software. First, obtain the rounding
* mode...
*/
- mode = func & 0xc0;
if (mode == 0xc0) {
/* dynamic---get rounding mode from fpcr: */
mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT;
@@ -135,8 +140,7 @@ alpha_fp_emul (unsigned long pc)
something_is_wrong();
}
- /* least 6 bits contain operation code: */
- switch (func & 0x3f) {
+ switch (op_fun) {
case FLTI_FUNC_CMPTEQ:
res = ieee_CMPTEQ(va, vb, &vc);
break;
@@ -153,7 +157,7 @@ alpha_fp_emul (unsigned long pc)
res = ieee_CMPTUN(va, vb, &vc);
break;
- case FLTI_FUNC_CVTQL:
+ case FLTL_FUNC_CVTQL:
/*
* Notice: We can get here only due to an integer
* overflow. Such overflows are reported as invalid
@@ -222,6 +226,14 @@ alpha_fp_emul (unsigned long pc)
res = ieee_CVTTQ(mode, vb, &vc);
break;
+ case FLTC_FUNC_SQRTS:
+ res = ieee_SQRTS(mode, vb, &vc);
+ break;
+
+ case FLTC_FUNC_SQRTT:
+ res = ieee_SQRTT(mode, vb, &vc);
+ break;
+
default:
printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
func & 0x3f, pc);
@@ -247,7 +259,7 @@ alpha_fp_emul (unsigned long pc)
/* Update hardware control register */
fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
- fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16);
+ fpcr |= ieee_swcr_to_fpcr(fpcw);
wrfpcr(fpcr);
/* Do we generate a signal? */
@@ -319,6 +331,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
write_mask &= ~(1UL << rc);
break;
+ case OPC_FLTC:
case OPC_FLTV:
case OPC_FLTI:
case OPC_FLTL:
@@ -326,13 +339,11 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
break;
}
if (!write_mask) {
- if ((opcode == OPC_FLTI || opcode == OPC_FLTL)
- && alpha_fp_emul(trigger_pc))
- {
- /* re-execute insns in trap-shadow: */
- regs->pc = trigger_pc + 4;
- MOD_DEC_USE_COUNT;
- return 1;
+ if (alpha_fp_emul(trigger_pc)) {
+ /* re-execute insns in trap-shadow: */
+ regs->pc = trigger_pc + 4;
+ MOD_DEC_USE_COUNT;
+ return 1;
}
break;
}
diff --git a/arch/alpha/math-emu/ieee-math.c b/arch/alpha/math-emu/ieee-math.c
index 4208b742c..224fdd2b7 100644
--- a/arch/alpha/math-emu/ieee-math.c
+++ b/arch/alpha/math-emu/ieee-math.c
@@ -22,6 +22,7 @@
* functions are used on exceptional numbers only (well, assuming you
* don't turn on the "trap on inexact"...).
*/
+#include <linux/sched.h>
#include "ieee-math.h"
#define STICKY_S 0x20000000 /* both in longword 0 of fraction */
@@ -1340,3 +1341,41 @@ ieee_DIVT (int f, unsigned long a, unsigned long b, unsigned long *c)
op_c.e -= 9; /* remove excess exp from original shift */
return round_t_ieee(f, &op_c, c);
}
+
+/*
+ * Sqrt a = b, where a and b are ieee s-floating numbers. "f"
+ * contains the rounding mode etc.
+ */
+unsigned long
+ieee_SQRTS (int f, unsigned long a, unsigned long *b)
+{
+ fpclass_t a_type;
+ EXTENDED op_a, op_b;
+
+ *b = IEEE_QNaN;
+ a_type = extend_ieee(a, &op_a, SINGLE);
+ if (op_a.s == 0) {
+ /* FIXME -- handle positive denormals. */
+ send_sig(SIGFPE, current, 1);
+ }
+ return FPCR_INV;
+}
+
+/*
+ * Sqrt a = b, where a and b are ieee t-floating numbers. "f"
+ * contains the rounding mode etc.
+ */
+unsigned long
+ieee_SQRTT (int f, unsigned long a, unsigned long *b)
+{
+ fpclass_t a_type;
+ EXTENDED op_a, op_b;
+
+ *b = IEEE_QNaN;
+ a_type = extend_ieee(a, &op_a, DOUBLE);
+ if (op_a.s == 0) {
+ /* FIXME -- handle positive denormals. */
+ send_sig(SIGFPE, current, 1);
+ }
+ return FPCR_INV;
+}
diff --git a/arch/alpha/math-emu/ieee-math.h b/arch/alpha/math-emu/ieee-math.h
index 35ce1afb7..1b3cf2694 100644
--- a/arch/alpha/math-emu/ieee-math.h
+++ b/arch/alpha/math-emu/ieee-math.h
@@ -48,5 +48,7 @@ extern unsigned long ieee_DIVS (int rm, unsigned long a, unsigned long b,
unsigned long *c);
extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b,
unsigned long *c);
+extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b);
+extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b);
#endif /* __ieee_math_h__ */
diff --git a/arch/arm/defconfig b/arch/arm/defconfig
index 64fb0d7ab..db89599be 100644
--- a/arch/arm/defconfig
+++ b/arch/arm/defconfig
@@ -80,7 +80,6 @@ CONFIG_BLK_DEV_PART=y
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 5996398f8..d50b90f8d 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -77,12 +77,14 @@ asmlinkage int old_mmap(struct mmap_arg_struct *arg)
goto out;
if (!(a.flags & MAP_ANONYMOUS)) {
error = -EBADF;
- if (a.fd >= current->files->max_fds ||
- !(file = current->files->fd[a.fd]))
+ file = fget(a.fd);
+ if (!file)
goto out;
}
a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+ if (file)
+ fput(file);
out:
unlock_kernel();
return error;
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 22c3639da..b6448e942 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -127,7 +127,6 @@ void do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
sti ();
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index fc9809144..665c7c0b1 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -8,37 +8,30 @@
# Note 2! The CFLAGS definition is now in the main makefile...
all: lib first_rule
-ifeq ($(MACHINE),a5k)
-MMARCH=arc
-else
-MMARCH=$(MACHINE)
-endif
O_TARGET := mm.o
-O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o
+O_OBJS := init.o extable.o fault-$(PROCESSOR).o small_page.o
ifeq ($(PROCESSOR),armo)
O_OBJS += proc-arm2,3.o
endif
ifeq ($(PROCESSOR),armv)
- O_OBJS += small_page.o proc-arm6,7.o proc-sa110.o
+ O_OBJS += mm-$(MACHINE).o proc-arm6,7.o proc-sa110.o ioremap.o
endif
include $(TOPDIR)/Rules.make
-proc-arm2,3.o: ../lib/constants.h
-proc-arm6,7.o: ../lib/constants.h
-proc-sa110.o: ../lib/constants.h
-
%.o: %.S
-ifneq ($(CONFIG_BINUTILS_NEW),y)
- $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s
- $(CC) $(CFLAGS:-pipe=) -c -o $@ ..$@.tmp.s
- $(RM) ..$@.tmp.s
-else
$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
-endif
.PHONY: lib
lib:; @$(MAKE) -C ../lib constants.h
+
+# Special dependencies
+fault-armv.o: fault-common.c
+fault-armo.o: fault-common.c
+proc-arm2,3.o: ../lib/constants.h
+proc-arm6,7.o: ../lib/constants.h
+proc-sa110.o: ../lib/constants.h
+
diff --git a/arch/arm/mm/fault-armo.c b/arch/arm/mm/fault-armo.c
index 6fe1f30ff..c51980771 100644
--- a/arch/arm/mm/fault-armo.c
+++ b/arch/arm/mm/fault-armo.c
@@ -1,11 +1,10 @@
/*
- * linux/arch/arm/mm/fault.c
+ * linux/arch/arm/mm/fault-armo.c
*
* Copyright (C) 1995 Linus Torvalds
- * Modifications for ARM processor (c) 1995, 1996 Russell King
+ * Modifications for ARM processor (c) 1995-1999 Russell King
*/
-#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -15,8 +14,7 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -27,35 +25,32 @@
#define FAULT_CODE_WRITE 0x02
#define FAULT_CODE_USER 0x01
-struct pgtable_cache_struct quicklists;
+#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW))
+#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE))
-void __bad_pmd(pmd_t *pmd)
+#include "fault-common.c"
+
+static void *alloc_table(int size, int prio)
{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+ if (size != 128)
+ printk("invalid table size\n");
+ return (void *)get_page_8k(prio);
}
-void __bad_pmd_kernel(pmd_t *pmd)
+void free_table(void *table)
{
- printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
- __backtrace();
-#endif
- set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+ free_page_8k((unsigned long)table);
}
pgd_t *get_pgd_slow(void)
{
- pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
+ pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
pgd_t *init;
-
+
if (pgd) {
init = pgd_offset(&init_mm, 0);
- memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
- memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+ memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
}
return pgd;
@@ -65,17 +60,17 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
{
pte_t *pte;
- pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
+ pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
set_pmd(pmd, mk_pmd(pte));
return pte + offset;
}
set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
return NULL;
}
- kfree (pte);
+ free_table((void *)pte);
if (pmd_bad(*pmd)) {
__bad_pmd(pmd);
return NULL;
@@ -83,126 +78,22 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
return (pte_t *) pmd_page(*pmd) + offset;
}
-extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
-
-static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
- struct task_struct *tsk, struct mm_struct *mm)
-{
- /*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- pgd_t *pgd;
- if (addr < PAGE_SIZE)
- printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk (KERN_ALERT "Unable to handle kernel paging request");
- printk (" at virtual address %08lx\n", addr);
- printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
- pgd = pgd_offset (mm, addr);
- printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
- if (!pgd_none (*pgd)) {
- pmd_t *pmd;
- pmd = pmd_offset (pgd, addr);
- printk (", *pmd = %08lx", pmd_val (*pmd));
- if (!pmd_none (*pmd))
- printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
- }
- printk ("\n");
- die_if_kernel ("Oops", regs, mode, SIGKILL);
- do_exit (SIGKILL);
-}
-
-static void
-handle_dataabort (unsigned long addr, int mode, struct pt_regs *regs)
-{
- struct task_struct *tsk;
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- unsigned long fixup;
-
- lock_kernel();
- tsk = current;
- mm = tsk->mm;
-
- down(&mm->mmap_sem);
- vma = find_vma (mm, addr);
- if (!vma)
- goto bad_area;
- if (addr >= vma->vm_start)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
- goto bad_area;
-
- /*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- if (!(mode & FAULT_CODE_WRITE)) { /* write? */
- if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- }
- handle_mm_fault (tsk, vma, addr, mode & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW));
- up(&mm->mmap_sem);
- goto out;
-
- /*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
- up(&mm->mmap_sem);
- if (mode & FAULT_CODE_USER) {
-//extern int console_loglevel;
-//cli();
- tsk->tss.error_code = mode;
- tsk->tss.trap_no = 14;
-//console_loglevel = 9;
- printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
- tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
-//#ifdef DEBUG
- show_regs (regs);
- c_backtrace (regs->ARM_fp, 0);
-//#endif
- force_sig(SIGSEGV, tsk);
-//while (1);
- goto out;
- }
-
- /* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
- printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
- tsk->comm, regs->ARM_pc, addr, fixup);
- regs->ARM_pc = fixup;
- goto out;
- }
-
-
- kernel_page_fault (addr, mode, regs, tsk, mm);
-out:
- unlock_kernel();
-}
-
/*
* Handle a data abort. Note that we have to handle a range of addresses
* on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force
- * a copy-on-write
+ * a copy-on-write. However, on the second page, we always force COW.
*/
asmlinkage void
-do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
+do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
{
- handle_dataabort (min_addr, mode, regs);
+ do_page_fault(min_addr, mode, regs);
if ((min_addr ^ max_addr) >> PAGE_SHIFT)
- handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs);
+ do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs);
}
asmlinkage int
-do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs)
+do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
{
#if 0
if (the memc mapping for this page exists - can check now...) {
@@ -210,6 +101,6 @@ do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs)
return 0;
}
#endif
- handle_dataabort (addr, mode, regs);
+ do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs);
return 1;
}
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index f090c5f2c..d57d4fb20 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -1,10 +1,11 @@
/*
- * linux/arch/arm/mm/fault.c
+ * linux/arch/arm/mm/fault-armv.c
*
* Copyright (C) 1995 Linus Torvalds
- * Modifications for ARM processor (c) 1995, 1996 Russell King
+ * Modifications for ARM processor (c) 1995-1999 Russell King
*/
+#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -14,43 +15,37 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
+#include <asm/unaligned.h>
#define FAULT_CODE_READ 0x02
#define FAULT_CODE_USER 0x01
-struct pgtable_cache_struct quicklists;
+#define DO_COW(m) (!((m) & FAULT_CODE_READ))
+#define READ_FAULT(m) ((m) & FAULT_CODE_READ)
-void __bad_pmd(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
-}
-
-void __bad_pmd_kernel(pmd_t *pmd)
-{
- printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
-}
+#include "fault-common.c"
pgd_t *get_pgd_slow(void)
{
/*
* need to get a 16k page for level 1
*/
- pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2);
+ pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
pgd_t *init;
-
+
if (pgd) {
init = pgd_offset(&init_mm, 0);
- memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
- memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+ memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
+ clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR);
}
return pgd;
}
@@ -59,17 +54,19 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
{
pte_t *pte;
- pte = (pte_t *) get_small_page(GFP_KERNEL);
+ pte = (pte_t *)get_page_2k(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
+ clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ pte += PTRS_PER_PTE;
set_pmd(pmd, mk_user_pmd(pte));
return pte + offset;
}
set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
return NULL;
}
- free_small_page ((unsigned long) pte);
+ free_page_2k((unsigned long)pte);
if (pmd_bad(*pmd)) {
__bad_pmd(pmd);
return NULL;
@@ -81,17 +78,19 @@ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
{
pte_t *pte;
- pte = (pte_t *) get_small_page(GFP_KERNEL);
+ pte = (pte_t *)get_page_2k(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (pte) {
- memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
+ clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+ pte += PTRS_PER_PTE;
set_pmd(pmd, mk_kernel_pmd(pte));
return pte + offset;
}
set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
return NULL;
}
- free_small_page ((unsigned long) pte);
+ free_page_2k((unsigned long)pte);
if (pmd_bad(*pmd)) {
__bad_pmd_kernel(pmd);
return NULL;
@@ -99,10 +98,8 @@ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
return (pte_t *) pmd_page(*pmd) + offset;
}
-extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
-
#ifdef DEBUG
-static int sp_valid (unsigned long *sp)
+static int sp_valid(unsigned long *sp)
{
unsigned long addr = (unsigned long) sp;
@@ -114,187 +111,371 @@ static int sp_valid (unsigned long *sp)
}
#endif
-static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
- struct task_struct *tsk, struct mm_struct *mm)
+#ifdef CONFIG_ALIGNMENT_TRAP
+/*
+ * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
+ * /proc/sys/debug/alignment, modified and integrated into
+ * Linux 2.1 by Russell King
+ *
+ * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet. Also,
+ * it seems to give a severe performance impact (1 abort/ms - NW runs at
+ * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS.
+ *
+ * IMHO, I don't think that the trap handler is advantageous on ARM6,7
+ * processors (they'll run like an ARM3). We'll see.
+ */
+#define CODING_BITS(i) (i & 0x0e000000)
+
+#define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */
+#define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */
+#define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */
+#define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */
+#define LDST_L_BIT(i) (i & (1 << 20)) /* Load */
+
+#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */
+#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
+
+#define RN_BITS(i) ((i >> 16) & 15) /* Rn */
+#define RD_BITS(i) ((i >> 12) & 15) /* Rd */
+#define RM_BITS(i) (i & 15) /* Rm */
+
+#define REGMASK_BITS(i) (i & 0xffff)
+#define OFFSET_BITS(i) (i & 0x0fff)
+
+#define IS_SHIFT(i) (i & 0x0ff0)
+#define SHIFT_BITS(i) ((i >> 7) & 0x1f)
+#define SHIFT_TYPE(i) (i & 0x60)
+#define SHIFT_LSL 0x00
+#define SHIFT_LSR 0x20
+#define SHIFT_ASR 0x40
+#define SHIFT_RORRRX 0x60
+
+static unsigned long ai_user;
+static unsigned long ai_sys;
+static unsigned long ai_skipped;
+static unsigned long ai_half;
+static unsigned long ai_word;
+static unsigned long ai_multi;
+
+static int proc_alignment_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
{
- /*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- pgd_t *pgd;
- if (addr < PAGE_SIZE)
- printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk (KERN_ALERT "Unable to handle kernel paging request");
- printk (" at virtual address %08lx\n", addr);
- printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
- pgd = pgd_offset (mm, addr);
- printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
- if (!pgd_none (*pgd)) {
- pmd_t *pmd;
- pmd = pmd_offset (pgd, addr);
- printk (", *pmd = %08lx", pmd_val (*pmd));
- if (!pmd_none (*pmd))
- printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
- }
- printk ("\n");
- die_if_kernel ("Oops", regs, mode, SIGKILL);
- do_exit (SIGKILL);
+ char *p = page;
+ int len;
+
+ p += sprintf(p, "User:\t\t%li\n", ai_user);
+ p += sprintf(p, "System:\t\t%li\n", ai_sys);
+ p += sprintf(p, "Skipped:\t%li\n", ai_skipped);
+ p += sprintf(p, "Half:\t\t%li\n", ai_half);
+ p += sprintf(p, "Word:\t\t%li\n", ai_word);
+ p += sprintf(p, "Multi:\t\t%li\n", ai_multi);
+
+ len = (p - page) - off;
+ if (len < 0)
+ len = 0;
+
+ *eof = (len <= count) ? 1 : 0;
+ *start = page + off;
+
+ return len;
}
-static void page_fault (unsigned long addr, int mode, struct pt_regs *regs)
+/*
+ * This needs to be done after sysctl_init, otherwise sys/
+ * will be overwritten.
+ */
+void __init alignment_init(void)
{
- struct task_struct *tsk;
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- unsigned long fixup;
-
- lock_kernel();
- tsk = current;
- mm = tsk->mm;
-
- down(&mm->mmap_sem);
- vma = find_vma (mm, addr);
- if (!vma)
- goto bad_area;
- if (vma->vm_start <= addr)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
- goto bad_area;
+ struct proc_dir_entry *e;
- /*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- if (mode & FAULT_CODE_READ) { /* read? */
- if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
+ e = create_proc_entry("sys/debug/alignment", S_IFREG | S_IRUGO, NULL);
+
+ if (e)
+ e->read_proc = proc_alignment_read;
+}
+
+static int
+do_alignment_exception(struct pt_regs *regs)
+{
+ unsigned int instr, rd, rn, correction, nr_regs, regbits;
+ unsigned long eaddr;
+ union { unsigned long un; signed long sn; } offset;
+
+ if (user_mode(regs)) {
+ set_cr(cr_no_alignment);
+ ai_user += 1;
+ return 0;
}
- handle_mm_fault (tsk, vma, addr & PAGE_MASK, !(mode & FAULT_CODE_READ));
- up(&mm->mmap_sem);
- goto out;
- /*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
- up(&mm->mmap_sem);
- if (mode & FAULT_CODE_USER) {
- tsk->tss.error_code = mode;
- tsk->tss.trap_no = 14;
- printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
- tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
-#ifdef DEBUG
- {
- unsigned int i, j;
- unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128);
- for (j = 0; j < 20 && sp_valid (sp); j++) {
- printk ("%p: ", sp);
- for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
- printk ("%08lx ", *sp);
- printk ("\n");
+ ai_sys += 1;
+
+ instr = *(unsigned long *)instruction_pointer(regs);
+ correction = 4; /* sometimes 8 on ARMv3 */
+ regs->ARM_pc += correction + 4;
+
+ rd = RD_BITS(instr);
+ rn = RN_BITS(instr);
+ eaddr = regs->uregs[rn];
+
+ switch(CODING_BITS(instr)) {
+ case 0x00000000:
+ if ((instr & 0x0ff00ff0) == 0x01000090) {
+ ai_skipped += 1;
+ printk(KERN_ERR "Unaligned trap: not handling swp instruction\n");
+ return 1;
+ }
+
+ if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) {
+ ai_half += 1;
+ if (LDSTH_I_BIT(instr))
+ offset.un = (instr & 0xf00) >> 4 | (instr & 15);
+ else
+ offset.un = regs->uregs[RM_BITS(instr)];
+
+ if (LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
}
+
+ if (LDST_L_BIT(instr))
+ regs->uregs[rd] = get_unaligned((unsigned short *)eaddr);
+ else
+ put_unaligned(regs->uregs[rd], (unsigned short *)eaddr);
+
+ /* signed half-word? */
+ if (instr & 0x40)
+ regs->uregs[rd] = (long)((short) regs->uregs[rd]);
+
+ if (!LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
+ regs->uregs[rn] = eaddr;
+ } else if (LDST_W_BIT(instr))
+ regs->uregs[rn] = eaddr;
+ break;
}
- show_regs (regs);
- c_backtrace (regs->ARM_fp, regs->ARM_cpsr);
-#endif
- force_sig(SIGSEGV, tsk);
- goto out;
- }
- /* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
- printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
- tsk->comm, regs->ARM_pc, addr, fixup);
- regs->ARM_pc = fixup;
- goto out;
+ default:
+ ai_skipped += 1;
+ panic("Alignment trap: not handling instruction %08X at %08lX",
+ instr, regs->ARM_pc - correction - 4);
+ break;
+
+ case 0x04000000:
+ offset.un = OFFSET_BITS(instr);
+ goto ldr_str;
+
+ case 0x06000000:
+ offset.un = regs->uregs[RM_BITS(instr)];
+
+ if (IS_SHIFT(instr)) {
+ unsigned int shiftval = SHIFT_BITS(instr);
+
+ switch(SHIFT_TYPE(instr)) {
+ case SHIFT_LSL:
+ offset.un <<= shiftval;
+ break;
+
+ case SHIFT_LSR:
+ offset.un >>= shiftval;
+ break;
+
+ case SHIFT_ASR:
+ offset.sn >>= shiftval;
+ break;
+
+ case SHIFT_RORRRX:
+ if (shiftval == 0) {
+ offset.un >>= 1;
+ if (regs->ARM_cpsr & CC_C_BIT)
+ offset.un |= 1 << 31;
+ } else
+ offset.un = offset.un >> shiftval |
+ offset.un << (32 - shiftval);
+ break;
+ }
+ }
+
+ ldr_str:
+ ai_word += 1;
+ if (LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
+ } else {
+ if (LDST_W_BIT(instr)) {
+ printk(KERN_ERR "Not handling ldrt/strt correctly\n");
+ return 1;
+ }
+ }
+
+ if (LDST_L_BIT(instr)) {
+ regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
+ if (rd == 15)
+ correction = 0;
+ } else
+ put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
+
+ if (!LDST_P_BIT(instr)) {
+ if (LDST_U_BIT(instr))
+ eaddr += offset.un;
+ else
+ eaddr -= offset.un;
+
+ regs->uregs[rn] = eaddr;
+ } else if (LDST_W_BIT(instr))
+ regs->uregs[rn] = eaddr;
+ break;
+
+ case 0x08000000:
+ if (LDM_S_BIT(instr))
+ panic("Alignment trap: not handling LDM with s-bit\n");
+ ai_multi += 1;
+
+ for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
+ nr_regs += 4;
+
+ if (!LDST_U_BIT(instr))
+ eaddr -= nr_regs;
+
+ if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
+ (LDST_U_BIT(instr) && LDST_P_BIT(instr)))
+ eaddr += 4;
+
+ for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
+ if (regbits & 1) {
+ if (LDST_L_BIT(instr)) {
+ regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
+ if (rd == 15)
+ correction = 0;
+ } else
+ put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
+ eaddr += 4;
+ }
+
+ if (LDST_W_BIT(instr)) {
+ if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
+ eaddr -= nr_regs;
+ else if (LDST_P_BIT(instr))
+ eaddr -= 4;
+ else if (!LDST_U_BIT(instr))
+ eaddr -= 4 + nr_regs;
+ regs->uregs[rn] = eaddr;
+ }
+ break;
}
- kernel_page_fault (addr, mode, regs, tsk, mm);
-out:
- unlock_kernel();
+ regs->ARM_pc -= correction;
+
+ return 0;
}
-/*
- * Handle a data abort. Note that we have to handle a range of addresses
- * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force
- * a copy-on-write
- */
+#endif
+
asmlinkage void
-do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
+do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
{
if (user_mode(regs))
error_code |= FAULT_CODE_USER;
+
#define DIE(signr,nam)\
force_sig(signr, current);\
- die_if_kernel(nam, regs, fsr, signr);\
- break;
+ die(nam, regs, fsr);\
+ do_exit(signr);\
+ break
switch (fsr & 15) {
- case 2:
- DIE(SIGKILL, "Terminal exception")
+ /*
+ * 0 - vector exception
+ */
case 0:
- DIE(SIGSEGV, "Vector exception")
+ force_sig(SIGSEGV, current);
+ if (!user_mode(regs)) {
+ die("vector exception", regs, fsr);
+ do_exit(SIGSEGV);
+ }
+ break;
+
+ /*
+ * 15 - permission fault on page
+ * 5 - page-table entry descriptor fault
+ * 7 - first-level descriptor fault
+ */
+ case 15: case 5: case 7:
+ do_page_fault(addr, error_code, regs);
+ break;
+
+ /*
+ * 13 - permission fault on section
+ */
+ case 13:
+ force_sig(SIGSEGV, current);
+ if (!user_mode(regs)) {
+ die("section permission fault", regs, fsr);
+ do_exit(SIGSEGV);
+ } else {
+#ifdef CONFIG_DEBUG_USER
+ printk("%s: permission fault on section, "
+ "address=0x%08lx, code %d\n",
+ current->comm, addr, error_code);
+#ifdef DEBUG
+ {
+ unsigned int i, j;
+ unsigned long *sp;
+
+ sp = (unsigned long *) (regs->ARM_sp - 128);
+ for (j = 0; j < 20 && sp_valid(sp); j++) {
+ printk("%p: ", sp);
+ for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++)
+ printk("%08lx ", *sp);
+ printk("\n");
+ }
+ show_regs(regs);
+ c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
+ }
+#endif
+#endif
+ }
+ break;
+
case 1:
case 3:
- DIE(SIGBUS, "Alignment exception")
+#ifdef CONFIG_ALIGNMENT_TRAP
+ if (!do_alignment_exception(regs))
+ break;
+#endif
+ /*
+ * this should never happen
+ */
+ DIE(SIGBUS, "Alignment exception");
+ break;
+
+ case 2:
+ DIE(SIGKILL, "Terminal exception");
case 12:
case 14:
- DIE(SIGBUS, "External abort on translation")
+ DIE(SIGBUS, "External abort on translation");
case 9:
case 11:
- DIE(SIGSEGV, "Domain fault")
- case 13:/* permission fault on section */
-#ifdef DEBUG
- {
- unsigned int i, j;
- unsigned long *sp;
-
- printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n",
- current->comm, addr, error_code);
- sp = (unsigned long *) (regs->ARM_sp - 128);
- for (j = 0; j < 20 && sp_valid (sp); j++) {
- printk ("%p: ", sp);
- for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
- printk ("%08lx ", *sp);
- printk ("\n");
- }
- show_regs (regs);
- c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
- }
-#endif
- DIE(SIGSEGV, "Permission fault")
+ DIE(SIGSEGV, "Domain fault");
- case 15:/* permission fault on page */
- case 5: /* page-table entry descriptor fault */
- case 7: /* first-level descriptor fault */
- page_fault (addr, error_code, regs);
- break;
case 4:
case 6:
- DIE(SIGBUS, "External abort on linefetch")
+ DIE(SIGBUS, "External abort on linefetch");
case 8:
case 10:
- DIE(SIGBUS, "External abort on non-linefetch")
+ DIE(SIGBUS, "External abort on non-linefetch");
}
}
asmlinkage int
-do_PrefetchAbort (unsigned long addr, struct pt_regs *regs)
+do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
{
-#if 0
- /* does this still apply ? */
- if (the memc mapping for this page exists - can check now...) {
- printk ("Page in, but got abort (undefined instruction?)\n");
- return 0;
- }
-#endif
- page_fault (addr, FAULT_CODE_USER|FAULT_CODE_READ, regs);
+ do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs);
return 1;
}
-
diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c
new file mode 100644
index 000000000..810dea699
--- /dev/null
+++ b/arch/arm/mm/fault-common.c
@@ -0,0 +1,188 @@
+/*
+ * linux/arch/arm/mm/fault-common.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Modifications for ARM processor (c) 1995-1999 Russell King
+ */
+#include <linux/config.h>
+
+extern void die(char *msg, struct pt_regs *regs, unsigned int err);
+
+void __bad_pmd(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+#ifdef CONFIG_DEBUG_ERRORS
+ __backtrace();
+#endif
+ set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+}
+
+void __bad_pmd_kernel(pmd_t *pmd)
+{
+ printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+#ifdef CONFIG_DEBUG_ERRORS
+ __backtrace();
+#endif
+ set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+}
+
+static void
+kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
+ struct task_struct *tsk, struct mm_struct *mm)
+{
+ char *reason;
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ pgd_t *pgd;
+
+ if (addr < PAGE_SIZE)
+ reason = "NULL pointer dereference";
+ else
+ reason = "paging request";
+
+ printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
+ reason, addr);
+ printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
+ pgd = pgd_offset(mm, addr);
+ printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd));
+
+ do {
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (pgd_none(*pgd))
+ break;
+
+ if (pgd_bad(*pgd)) {
+ printk("(bad)\n");
+ break;
+ }
+
+ pmd = pmd_offset(pgd, addr);
+ printk(", *pmd = %08lx", pmd_val(*pmd));
+
+ if (pmd_none(*pmd))
+ break;
+
+ if (pmd_bad(*pmd)) {
+ printk("(bad)\n");
+ break;
+ }
+
+ pte = pte_offset(pmd, addr);
+ printk(", *pte = %08lx", pte_val(*pte));
+ printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
+ } while(0);
+
+ printk("\n");
+ die("Oops", regs, mode);
+
+ do_exit(SIGKILL);
+}
+
+static void do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ unsigned long fixup;
+
+ tsk = current;
+ mm = tsk->mm;
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_interrupt() || mm == &init_mm)
+ goto no_context;
+
+ down(&mm->mmap_sem);
+ vma = find_vma(mm, addr);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= addr)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, addr))
+ goto bad_area;
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ if (READ_FAULT(mode)) { /* read? */
+ if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
+ goto bad_area;
+ } else {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ }
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode)))
+ goto do_sigbus;
+
+ up(&mm->mmap_sem);
+ return;
+
+ /*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up(&mm->mmap_sem);
+
+ /* User mode accesses just cause a SIGSEGV */
+ if (mode & FAULT_CODE_USER) {
+ tsk->tss.error_code = mode;
+ tsk->tss.trap_no = 14;
+#ifdef CONFIG_DEBUG_USER
+ printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
+ tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
+#endif
+ force_sig(SIGSEGV, tsk);
+ return;
+ }
+
+no_context:
+ /* Are we prepared to handle this kernel fault? */
+ if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
+ tsk->comm, regs->ARM_pc, addr, fixup);
+#endif
+ regs->ARM_pc = fixup;
+ return;
+ }
+
+ kernel_page_fault(addr, mode, regs, tsk, mm);
+ return;
+
+do_sigbus:
+ /*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+ up(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->tss.error_code = mode;
+ tsk->tss.trap_no = 14;
+ force_sig(SIGBUS, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!(mode & FAULT_CODE_USER))
+ goto no_context;
+}
+
+
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index b3b0ecf56..47a2cfde7 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -29,6 +29,9 @@
#include <asm/proc/mm-init.h>
pgd_t swapper_pg_dir[PTRS_PER_PGD];
+#ifndef CONFIG_NO_PGT_CACHE
+struct pgtable_cache_struct quicklists;
+#endif
extern char _etext, _stext, _edata, __bss_start, _end;
extern char __init_begin, __init_end;
@@ -36,6 +39,7 @@ extern char __init_begin, __init_end;
int do_check_pgt_cache(int low, int high)
{
int freed = 0;
+#ifndef CONFIG_NO_PGT_CACHE
if(pgtable_cache_size > high) {
do {
if(pgd_quicklist)
@@ -46,6 +50,7 @@ int do_check_pgt_cache(int low, int high)
free_pte_slow(get_pte_fast()), freed++;
} while(pgtable_cache_size > low);
}
+#endif
return freed;
}
@@ -63,17 +68,18 @@ int do_check_pgt_cache(int low, int high)
* data and COW.
*/
#if PTRS_PER_PTE != 1
-unsigned long *empty_bad_page_table;
+pte_t *empty_bad_page_table;
pte_t *__bad_pagetable(void)
{
- int i;
pte_t bad_page;
+ int i;
bad_page = BAD_PAGE;
for (i = 0; i < PTRS_PER_PTE; i++)
- empty_bad_page_table[i] = (unsigned long)pte_val(bad_page);
- return (pte_t *) empty_bad_page_table;
+ set_pte(empty_bad_page_table + i, bad_page);
+
+ return empty_bad_page_table;
}
#endif
@@ -128,8 +134,11 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
empty_bad_page = (unsigned long *)start_mem;
start_mem += PAGE_SIZE;
#if PTRS_PER_PTE != 1
- empty_bad_page_table = (unsigned long *)start_mem;
- start_mem += PTRS_PER_PTE * sizeof (void *);
+#ifdef CONFIG_CPU_32
+ start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
+#endif
+ empty_bad_page_table = (pte_t *)start_mem;
+ start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
#endif
memzero (empty_zero_page, PAGE_SIZE);
start_mem = setup_pagetables (start_mem, end_mem);
@@ -137,6 +146,9 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
flush_tlb_all();
update_memc_all();
+ end_mem &= PAGE_MASK;
+ high_memory = (void *)end_mem;
+
return free_area_init(start_mem, end_mem);
}
@@ -161,19 +173,18 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
/* mark usable pages in the mem_map[] */
mark_usable_memory_areas(&start_mem, end_mem);
+#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \
+ (w) < (unsigned long)(max))
+
for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) {
if (PageReserved(mem_map+MAP_NR(tmp))) {
- if (tmp >= KERNTOPHYS(_stext) &&
- tmp < KERNTOPHYS(_edata)) {
- if (tmp < KERNTOPHYS(_etext))
- codepages++;
- else
- datapages++;
- } else if (tmp >= KERNTOPHYS(__init_begin)
- && tmp < KERNTOPHYS(__init_end))
+ if (BETWEEN(tmp, &__init_begin, &__init_end))
initpages++;
- else if (tmp >= KERNTOPHYS(__bss_start)
- && tmp < (unsigned long) start_mem)
+ else if (BETWEEN(tmp, &_stext, &_etext))
+ codepages++;
+ else if (BETWEEN(tmp, &_etext, &_edata))
+ datapages++;
+ else if (BETWEEN(tmp, &__bss_start, start_mem))
datapages++;
else
reservedpages++;
@@ -181,13 +192,16 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
}
atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
#ifdef CONFIG_BLK_DEV_INITRD
- if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
+ if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end))
#endif
free_page(tmp);
}
- printk ("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+
+#undef BETWEEN
+
+ printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
+ max_mapnr >> (20 - PAGE_SHIFT),
codepages << (PAGE_SHIFT-10),
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
@@ -203,17 +217,45 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
#endif
}
-void free_initmem (void)
+static void free_area(unsigned long addr, unsigned long end, char *s)
{
- unsigned long addr;
+ unsigned int size = (end - addr) >> 10;
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ for (; addr < end; addr += PAGE_SIZE) {
mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
atomic_set(&mem_map[MAP_NR(addr)].count, 1);
free_page(addr);
}
- printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+
+ if (size)
+ printk(" %dk %s", size, s);
+}
+
+void free_initmem (void)
+{
+ printk("Freeing unused kernel memory:");
+
+ free_area((unsigned long)(&__init_begin),
+ (unsigned long)(&__init_end),
+ "init");
+
+#ifdef CONFIG_FOOTBRIDGE
+ {
+ extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end;
+
+ if (!machine_is_netwinder())
+ free_area((unsigned long)(&__netwinder_begin),
+ (unsigned long)(&__netwinder_end),
+ "netwinder");
+
+ if (!machine_is_ebsa285() && !machine_is_cats())
+ free_area((unsigned long)(&__ebsa285_begin),
+ (unsigned long)(&__ebsa285_end),
+ "ebsa285/cats");
+ }
+#endif
+
+ printk("\n");
}
void si_meminfo(struct sysinfo *val)
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
new file mode 100644
index 000000000..70d7c77b9
--- /dev/null
+++ b/arch/arm/mm/ioremap.c
@@ -0,0 +1,149 @@
+/*
+ * arch/arm/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ *
+ * Hacked for ARM by Phil Blundell <philb@gnu.org>
+ * Hacked to allow all architectures to build, and various cleanups
+ * by Russell King
+ */
+
+/*
+ * This allows a driver to remap an arbitrary region of bus memory into
+ * virtual space. One should *only* use readl, writel, memcpy_toio and
+ * so on with such remapped areas.
+ *
+ * Because the ARM only has a 32-bit address space we can't address the
+ * whole of the (physical) PCI space at once. PCI huge-mode addressing
+ * allows us to circumvent this restriction by splitting PCI space into
+ * two 2GB chunks and mapping only one at a time into processor memory.
+ * We use MMU protection domains to trap any attempt to access the bank
+ * that is not currently mapped. (This isn't fully implemented yet.)
+ *
+ * DC21285 currently has a bug in that the PCI address extension
+ * register affects the address of any writes waiting in the outbound
+ * FIFO. Unfortunately, it is not possible to tell the DC21285 to
+ * flush this - flushing the area causes the bus to lock.
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+ unsigned long phys_addr, pgprot_t pgprot)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ if (!pte_none(*pte))
+ printk("remap_area_pte: page already exists\n");
+ set_pte(pte, mk_pte_phys(phys_addr, pgprot));
+ address += PAGE_SIZE;
+ phys_addr += PAGE_SIZE;
+ pte++;
+ } while (address < end);
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+ unsigned long phys_addr, unsigned long flags)
+{
+ unsigned long end;
+ pgprot_t pgprot;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+
+ phys_addr -= address;
+ pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
+ do {
+ pte_t * pte = pte_alloc_kernel(pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+ return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+ unsigned long size, unsigned long flags)
+{
+ pgd_t * dir;
+ unsigned long end = address + size;
+
+ phys_addr -= address;
+ dir = pgd_offset(&init_mm, address);
+ flush_cache_all();
+ while (address < end) {
+ pmd_t *pmd = pmd_alloc_kernel(dir, address);
+ if (!pmd)
+ return -ENOMEM;
+ if (remap_area_pmd(pmd, address, end - address,
+ phys_addr + address, flags))
+ return -ENOMEM;
+ set_pgdir(address, *dir);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ }
+ flush_tlb_all();
+ return 0;
+}
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ *
+ * 'flags' are the extra L_PTE_ flags that you want to specify for this
+ * mapping. See include/asm-arm/proc-armv/pgtable.h for more information.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+ void * addr;
+ struct vm_struct * area;
+ unsigned long offset;
+
+ /*
+ * Mappings have to be page-aligned
+ */
+ offset = phys_addr & ~PAGE_MASK;
+ size = PAGE_ALIGN(size + offset);
+
+ /*
+ * Don't allow mappings that wrap..
+ */
+ if (!size || size > phys_addr + size)
+ return NULL;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_vm_area(size);
+ if (!area)
+ return NULL;
+ addr = area->addr;
+ if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+ vfree(addr);
+ return NULL;
+ }
+ return (void *) (offset + (char *)addr);
+}
+
+void iounmap(void *addr)
+{
+ return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
diff --git a/arch/arm/mm/mm-arc.c b/arch/arm/mm/mm-arc.c
deleted file mode 100644
index 6bb92f037..000000000
--- a/arch/arm/mm/mm-arc.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * arch/arm/mm/mm-arc.c
- *
- * Extra MM routines for the Archimedes architecture
- *
- * Copyright (C) 1998 Russell King
- */
-#include <linux/init.h>
-#include <asm/hardware.h>
-#include <asm/pgtable.h>
-
-unsigned long phys_screen_end;
-
-/*
- * This routine needs more work to make it dynamically release/allocate mem!
- */
-__initfunc(unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update))
-{
- static int updated = 0;
-
- if (updated)
- return 0;
-
- updated = update;
-
- if (update) {
- unsigned long address = log_start, offset;
- pgd_t *pgdp;
-
- kmem = (kmem + 3) & ~3;
-
- pgdp = pgd_offset (&init_mm, address); /* +31 */
- offset = SCREEN_START;
- while (address < SCREEN1_END) {
- unsigned long addr_pmd, end_pmd;
- pmd_t *pmdp;
-
- /* if (pgd_none (*pgdp)) alloc pmd */
- pmdp = pmd_offset (pgdp, address); /* +0 */
- addr_pmd = address & ~PGDIR_MASK; /* 088000 */
- end_pmd = addr_pmd + SCREEN1_END - address; /* 100000 */
- if (end_pmd > PGDIR_SIZE)
- end_pmd = PGDIR_SIZE;
-
- do {
- unsigned long addr_pte, end_pte;
- pte_t *ptep;
-
- if (pmd_none (*pmdp)) {
- pte_t *new_pte = (pte_t *)kmem;
- kmem += PTRS_PER_PTE * BYTES_PER_PTR;
- memzero (new_pte, PTRS_PER_PTE * BYTES_PER_PTR);
- set_pmd (pmdp, mk_pmd(new_pte));
- }
-
- ptep = pte_offset (pmdp, addr_pmd); /* +11 */
- addr_pte = addr_pmd & ~PMD_MASK; /* 088000 */
- end_pte = addr_pte + end_pmd - addr_pmd; /* 100000 */
- if (end_pte > PMD_SIZE)
- end_pte = PMD_SIZE;
-
- do {
- set_pte (ptep, mk_pte(offset, PAGE_KERNEL));
- addr_pte += PAGE_SIZE;
- offset += PAGE_SIZE;
- ptep++;
- } while (addr_pte < end_pte);
-
- pmdp++;
- addr_pmd = (addr_pmd + PMD_SIZE) & PMD_MASK;
- } while (addr_pmd < end_pmd);
-
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- pgdp ++;
- }
-
- phys_screen_end = offset;
- flush_tlb_all ();
- update_memc_all ();
- }
- return kmem;
-}
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 8a226526b..4481fc32b 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -37,7 +37,8 @@ __initfunc(unsigned long setup_io_pagetables(unsigned long start_mem))
virtual = mp->virtual;
physical = mp->physical;
length = mp->length;
- prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0);
+ prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
+ | L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
while ((virtual & 1048575 || physical & 1048575) && length >= PAGE_SIZE) {
alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
@@ -56,7 +57,8 @@ __initfunc(unsigned long setup_io_pagetables(unsigned long start_mem))
physical += 1048576;
}
- prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0);
+ prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
+ | L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
while (length >= PAGE_SIZE) {
alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
diff --git a/arch/arm/mm/mm-ebsa285.c b/arch/arm/mm/mm-ebsa285.c
deleted file mode 100644
index a5b17c6b9..000000000
--- a/arch/arm/mm/mm-ebsa285.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * arch/arm/mm/mm-ebsa285.c
- *
- * Extra MM routines for the EBSA285 architecture
- *
- * Copyright (C) 1998 Russell King, Dave Gilbert.
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/proc/mm-init.h>
-#include <asm/dec21285.h>
-
-/*
- * This is to allow us to fiddle with the EEPROM
- * This entry will go away in time, once the fmu
- * can mmap() the flash.
- *
- * These ones are so that we can fiddle
- * with the various cards (eg VGA)
- * until we're happy with them...
- */
-#define MAPPING \
- { 0xd8000000, DC21285_FLASH, 0x00400000, DOMAIN_USER, 1, 1 }, /* EEPROM */ \
- { 0xdc000000, 0x7c000000, 0x00100000, DOMAIN_USER, 1, 1 }, /* VGA */ \
- { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_USER, 1, 1 }, /* VGA */ \
- { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
- { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
- { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
- { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
- { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
- { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
- { 0xfff00000, 0x40000000, 0x00100000, DOMAIN_IO , 0, 1 }, /* X-Bus */
-
-#include "mm-armv.c"
diff --git a/arch/arm/mm/mm-footbridge.c b/arch/arm/mm/mm-footbridge.c
new file mode 100644
index 000000000..ec7e64c90
--- /dev/null
+++ b/arch/arm/mm/mm-footbridge.c
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/mm/mm-ebsa285.c
+ *
+ * Extra MM routines for the EBSA285 architecture
+ *
+ * Copyright (C) 1998 Russell King, Dave Gilbert.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/proc/mm-init.h>
+#include <asm/dec21285.h>
+
+/*
+ * The first entry allows us to fiddle with the EEPROM from user-space.
+ * This entry will go away in time, once the fmu32 can mmap() the
+ * flash. It can't at the moment.
+ *
+ * If you want to fiddle with PCI VGA cards from user space, then
+ * change the '0, 1 }' for the PCI MEM and PCI IO to '1, 1 }'
+ * You can then access the PCI bus at 0xe0000000 and 0xffe00000.
+ */
+
+#ifdef CONFIG_HOST_FOOTBRIDGE
+
+/*
+ * The mapping when the footbridge is in host mode.
+ */
+#define MAPPING \
+ { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \
+ { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 }, \
+ { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1 }, \
+ { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1 }, \
+ { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1 }, \
+ { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \
+ { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \
+ { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \
+ { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 }
+
+#else
+
+/*
+ * These two functions convert virtual addresses to PCI addresses
+ * and PCI addresses to virtual addresses. Note that it is only
+ * legal to use these on memory obtained via get_free_page or
+ * kmalloc.
+ */
+unsigned long __virt_to_bus(unsigned long res)
+{
+#ifdef CONFIG_DEBUG_ERRORS
+ if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
+ printk("__virt_to_phys: invalid virtual address 0x%08lx\n", res);
+ __backtrace();
+ }
+#endif
+ return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0);
+}
+
+unsigned long __bus_to_virt(unsigned long res)
+{
+ res -= (*CSR_PCISDRAMBASE & 0xfffffff0);
+ res += PAGE_OFFSET;
+
+#ifdef CONFIG_DEBUG_ERRORS
+ if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
+ printk("__phys_to_virt: invalid virtual address 0x%08lx\n", res);
+ __backtrace();
+ }
+#endif
+ return res;
+}
+
+/*
+ * The mapping when the footbridge is in add-in mode.
+ */
+#define MAPPING \
+ { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1 }, \
+ { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1 }, \
+ { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1 }, \
+ { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1 }, \
+ { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1 }, \
+ { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1 }
+
+#endif
+
+#include "mm-armv.c"
diff --git a/arch/arm/mm/mm-vnc.c b/arch/arm/mm/mm-vnc.c
deleted file mode 100644
index 94e037485..000000000
--- a/arch/arm/mm/mm-vnc.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mm/mm-vnc.c
- *
- * Extra MM routines for the Corel VNC architecture
- *
- * Copyright (C) 1998 Russell King
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/proc/mm-init.h>
-#include <asm/dec21285.h>
-
-/* Table describing the MMU translation mapping
- * mainly used to set up the I/O mappings.
- */
-#define MAPPING \
- { 0xd0000000, DC21285_FLASH, 0x00800000, DOMAIN_IO , 0, 1 }, /* Flash */ \
- { 0xe0000000, DC21285_PCI_MEM, 0x18000000, DOMAIN_IO , 0, 1 }, /* PCI Mem */ \
- { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 0 Config */ \
- { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG, 0x01000000, DOMAIN_IO , 0, 1 }, /* Type 1 Config */ \
- { PCI_IACK, DC21285_PCI_IACK, 0x01000000, DOMAIN_IO , 0, 1 }, /* PCI IACK */ \
- { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO , 0, 1 }, /* Out wrflsh */ \
- { 0xfe000000, DC21285_ARMCSR_BASE, 0x01000000, DOMAIN_IO , 0, 1 }, /* CSR */ \
- { 0xffe00000, DC21285_PCI_IO, 0x00100000, DOMAIN_IO , 0, 1 }, /* PCI I/O */ \
-
-#include "mm-armv.c"
diff --git a/arch/arm/mm/proc-arm2,3.S b/arch/arm/mm/proc-arm2,3.S
index 86cab564a..263d79708 100644
--- a/arch/arm/mm/proc-arm2,3.S
+++ b/arch/arm/mm/proc-arm2,3.S
@@ -193,7 +193,7 @@ _arm2_3_data_abort:
movs pc, lr
_arm2_3_check_bugs:
- movs pc, lr
+ bics pc, lr, #0x04000000 @ Clear FIQ disable bit
/*
* Processor specific - ARM2
@@ -206,6 +206,8 @@ LC0: .word SYMBOL_NAME(page_nr)
* Params : prev Old task structure
* : next New task structure for process to run
*
+ * Returns : prev
+ *
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
*
@@ -218,15 +220,15 @@ _arm2_switch_to:
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
mov r4, r1
- add r0, r1, #TSS_MEMCMAP @ Remap MEMC
+ add r7, r1, #TSS_MEMCMAP @ Remap MEMC
ldr r1, LC0
ldr r1, [r1]
-1: ldmia r0!, {r2, r3, r5, r6}
+1: ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
strb r6, [r6]
- ldmia r0!, {r2, r3, r5, r6}
+ ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
@@ -318,6 +320,8 @@ _arm2_proc_fin: movs pc, lr
* Params : prev Old task structure
* : next New task structure for process to run
*
+ * Returns : prev
+ *
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
*
@@ -330,22 +334,22 @@ _arm3_switch_to:
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
mov r4, r1
- add r0, r1, #TSS_MEMCMAP @ Remap MEMC
+ add r7, r1, #TSS_MEMCMAP @ Remap MEMC
ldr r1, LC0
ldr r1, [r1]
-1: ldmia r0!, {r2, r3, r5, r6}
+1: ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
strb r6, [r6]
- ldmia r0!, {r2, r3, r5, r6}
+ ldmia r7!, {r2, r3, r5, r6}
strb r2, [r2]
strb r3, [r3]
strb r5, [r5]
strb r6, [r6]
subs r1, r1, #8
bhi 1b
- mcr p15, 0, r0, c1, c0, 0 @ flush cache
+ mcr p15, 0, r7, c1, c0, 0 @ flush cache
ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously
/*
* Function: arm3_remap_memc (struct task_struct *tsk)
diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S
index b7119a330..b817ae2b4 100644
--- a/arch/arm/mm/proc-arm6,7.S
+++ b/arch/arm/mm/proc-arm6,7.S
@@ -52,13 +52,14 @@ _arm6_7_flush_tlb_area:
blt 1b
mov pc, lr
-@LC0: .word _current
/*
* Function: arm6_7_switch_to (struct task_struct *prev, struct task_struct *next)
*
* Params : prev Old task structure
* : next New task structure for process to run
*
+ * Returns : prev
+ *
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
*
@@ -72,15 +73,15 @@ _arm6_7_switch_to:
stmfd sp!, {ip} @ Save cpsr_SVC
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
- ldr r0, [r1, #TSK_ADDR_LIMIT]
- teq r0, #0
- moveq r0, #DOM_KERNELDOMAIN
- movne r0, #DOM_USERDOMAIN
- mcr p15, 0, r0, c3, c0 @ Set domain reg
- ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer
+ ldr r2, [r1, #TSK_ADDR_LIMIT]
+ teq r2, #0
+ moveq r2, #DOM_KERNELDOMAIN
+ movne r2, #DOM_USERDOMAIN
+ mcr p15, 0, r2, c3, c0 @ Set domain reg
+ ldr r2, [r1, #TSS_MEMMAP] @ Page table pointer
mov r1, #0
mcr p15, 0, r1, c7, c0, 0 @ flush cache
- mcr p15, 0, r0, c2, c0, 0 @ update page table ptr
+ mcr p15, 0, r2, c2, c0, 0 @ update page table ptr
mcr p15, 0, r1, c5, c0, 0 @ flush TLBs
ldmfd sp!, {ip}
msr spsr, ip @ Save tasks CPSR into SPSR for this return
@@ -369,6 +370,35 @@ _arm7_set_pmd: tst r1, #3
mov pc, lr
/*
+ * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte)
+ * Params : r0 = Address to set
+ * : r1 = value to set
+ * Purpose : Set a PTE and flush it out of any WB cache
+ */
+ .align 5
+_arm6_7_set_pte:
+ str r1, [r0], #-1024 @ linux version
+
+ bic r2, r1, #0xff0
+ bic r2, r2, #3
+ orr r2, r2, #HPTE_TYPE_SMALL
+
+ tst r1, #LPTE_USER | LPTE_EXEC
+ orrne r2, r2, #HPTE_AP_READ
+
+ tst r1, #LPTE_WRITE
+ tstne r1, #LPTE_DIRTY
+ orrne r2, r2, #HPTE_AP_WRITE
+
+ tst r1, #LPTE_PRESENT
+ tstne r1, #LPTE_YOUNG
+ moveq r2, #0
+
+ str r2, [r0] @ hardware version
+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
+ mov pc, lr
+
+/*
* Function: _arm6_7_reset
*
* Notes : This sets up everything for a reset
@@ -405,8 +435,12 @@ ENTRY(arm6_processor_functions)
.word _arm6_7_flush_tlb_all @ 44
.word _arm6_7_flush_tlb_area @ 48
.word _arm6_set_pmd @ 52
- .word _arm6_7_reset @ 54
- .word _arm6_7_flush_cache @ 58
+ .word _arm6_7_set_pte @ 56
+ .word _arm6_7_reset @ 60
+ .word _arm6_7_flush_cache @ 64
+
+ .word _arm6_7_flush_cache @ 68
+ .word _arm6_7_flush_cache @ 72
/*
* Purpose : Function pointers used to access above functions - all calls
@@ -431,8 +465,9 @@ ENTRY(arm7_processor_functions)
.word _arm6_7_flush_tlb_all @ 44
.word _arm6_7_flush_tlb_area @ 48
.word _arm7_set_pmd @ 52
- .word _arm6_7_reset @ 56
- .word _arm6_7_flush_cache @ 60
-
+ .word _arm6_7_set_pte @ 56
+ .word _arm6_7_reset @ 60
.word _arm6_7_flush_cache @ 64
+
.word _arm6_7_flush_cache @ 68
+ .word _arm6_7_flush_cache @ 72
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index 221797862..ff55c8ffa 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -8,6 +8,7 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/hardware.h>
#include "../lib/constants.h"
/* This is the maximum size of an area which will be flushed. If the area
@@ -21,7 +22,6 @@ Lclean_switch: .long 0
/*
* Function: sa110_flush_cache_all (void)
- *
* Purpose : Flush all cache lines
*/
.align 5
@@ -33,7 +33,7 @@ _sa110_flush_cache_all_r2:
ands r1, r1, #1
eor r1, r1, #1
str r1, [r3]
- ldr ip, =0xdf000000
+ ldr ip, =FLUSH_BASE
addne ip, ip, #32768
add r1, ip, #16384 @ only necessary for 16k
1: ldr r3, [ip], #32
@@ -47,11 +47,9 @@ _sa110_flush_cache_all_r2:
/*
* Function: sa110_flush_cache_area (unsigned long address, int end, int flags)
- *
* Params : address Area start address
* : end Area end address
* : flags b0 = I cache as well
- *
* Purpose : clean & flush all cache lines associated with this area of memory
*/
.align 5
@@ -74,10 +72,8 @@ _sa110_flush_cache_area:
/*
* Function: sa110_cache_wback_area(unsigned long address, unsigned long end)
- *
* Params : address Area start address
* : end Area end address
- *
* Purpose : ensure all dirty cachelines in the specified area have been
* written out to memory (for DMA)
*/
@@ -99,13 +95,10 @@ _sa110_cache_wback_area:
/*
* Function: sa110_cache_purge_area(unsigned long address, unsigned long end)
- *
* Params : address Area start address
* : end Area end address
- *
* Purpose : throw away all D-cached data in specified region without
- * an obligation to write it ack.
- *
+ * an obligation to write it back.
* Note : Must clean the D-cached entries around the boundaries if the
* start and/or end address are not cache aligned.
*/
@@ -124,9 +117,7 @@ _sa110_cache_purge_area:
/*
* Function: sa110_flush_cache_entry (unsigned long address)
- *
* Params : address Address of cache line to flush
- *
* Purpose : clean & flush an entry
*/
.align 5
@@ -138,24 +129,23 @@ _sa110_flush_cache_entry:
mov pc, lr
/*
- * Function: sa110_flush_cache_pte (unsigned long address)
- *
+ * Function: sa110_clean_cache_area(unsigned long start, unsigned long size)
* Params : address Address of cache line to clean
- *
* Purpose : Ensure that physical memory reflects cache at this location
* for page table purposes.
*/
-_sa110_flush_cache_pte:
- mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
+_sa110_clean_cache_area:
+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
+ add r0, r0, #32
+ subs r1, r1, #32
+ bhi 1b
mov pc, lr
/*
* Function: sa110_flush_ram_page (unsigned long page)
- *
* Params : address Area start address
* : size size of area
* : flags b0 = I cache as well
- *
* Purpose : clean & flush all cache lines associated with this area of memory
*/
.align 5
@@ -176,7 +166,6 @@ _sa110_flush_ram_page:
/*
* Function: sa110_flush_tlb_all (void)
- *
* Purpose : flush all TLB entries in all caches
*/
.align 5
@@ -188,11 +177,9 @@ _sa110_flush_tlb_all:
/*
* Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags)
- *
* Params : address Area start address
* : end Area end address
* : flags b0 = I cache as well
- *
* Purpose : flush a TLB entry
*/
.align 5
@@ -212,22 +199,21 @@ _sa110_flush_tlb_area:
.align 5
_sa110_flush_icache_area:
- mov r3, #0
1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry
add r0, r0, #32
- cmp r0, r1
- blt 1b
+ subs r1, r1, #32
+ bhi 1b
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c7, c5, 0 @ flush I cache
mov pc, lr
/*
* Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next)
- *
* Params : prev Old task structure
* : next New task structure for process to run
- *
+ * Returns : prev
* Purpose : Perform a task switch, saving the old processes state, and restoring
* the new.
- *
* Notes : We don't fiddle with the FP registers here - we postpone this until
* the new task actually uses FP. This way, we don't swap FP for tasks
* that do not require it.
@@ -237,20 +223,30 @@ _sa110_switch_to:
stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack
mrs ip, cpsr
stmfd sp!, {ip} @ Save cpsr_SVC
+ ldr r2, [r0, #TSS_MEMMAP] @ Get old page tables
str sp, [r0, #TSS_SAVE] @ Save sp_SVC
ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC
- ldr r0, [r1, #TSK_ADDR_LIMIT]
- teq r0, #0
- moveq r0, #DOM_KERNELDOMAIN
- movne r0, #DOM_USERDOMAIN
- mcr p15, 0, r0, c3, c0 @ Set segment
- ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer
+ ldr r4, [r1, #TSK_ADDR_LIMIT]
+ teq r4, #0
+ moveq r4, #DOM_KERNELDOMAIN
+ movne r4, #DOM_USERDOMAIN
+ mcr p15, 0, r4, c3, c0 @ Set segment
+ ldr r4, [r1, #TSS_MEMMAP] @ Page table pointer
+/*
+ * Flushing the cache is nightmarishly slow, so we take any excuse
+ * to get out of it. If the old page table is the same as the new,
+ * this is a CLONE_VM relative of the old task and there is no need
+ * to flush. The overhead of the tests isn't even on the radar
+ * compared to the cost of the flush itself.
+ */
+ teq r4, r2
+ beq 2f
ldr r3, =Lclean_switch
ldr r2, [r3]
ands r2, r2, #1
eor r2, r2, #1
str r2, [r3]
- ldr r2, =0xdf000000
+ ldr r2, =FLUSH_BASE
addne r2, r2, #32768
add r1, r2, #16384 @ only necessary for 16k
1: ldr r3, [r2], #32
@@ -259,19 +255,16 @@ _sa110_switch_to:
mov r1, #0
mcr p15, 0, r1, c7, c5, 0 @ flush I cache
mcr p15, 0, r1, c7, c10, 4 @ drain WB
- mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
+ mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c8, c7, 0 @ flush TLBs
- ldmfd sp!, {ip}
+2: ldmfd sp!, {ip}
msr spsr, ip @ Save tasks CPSR into SPSR for this return
ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously
/*
* Function: sa110_data_abort ()
- *
* Params : r0 = address of aborted instruction
- *
* Purpose : obtain information about current aborted instruction
- *
* Returns : r0 = address of abort
* : r1 = FSR
* : r2 != 0 if writing
@@ -288,12 +281,10 @@ _sa110_data_abort:
mov pc, lr
/*
- * Function: sa110_set_pmd ()
- *
+ * Function: sa110_set_pmd(pmd_t *pmdp, pmd_t pmd)
* Params : r0 = Address to set
* : r1 = value to set
- *
- * Purpose : Set a PMD and flush it out of any WB cache
+ * Purpose : Set a PMD and flush it out
*/
.align 5
_sa110_set_pmd: str r1, [r0]
@@ -301,23 +292,51 @@ _sa110_set_pmd: str r1, [r0]
mov pc, lr
/*
+ * Function: sa110_set_pte(pte_t *ptep, pte_t pte)
+ * Params : r0 = Address to set
+ * : r1 = value to set
+ * Purpose : Set a PTE and flush it out
+ */
+ .align 5
+_sa110_set_pte: str r1, [r0], #-1024 @ linux version
+
+ eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
+
+ bic r2, r1, #0xff0
+ bic r2, r2, #3
+ orr r2, r2, #HPTE_TYPE_SMALL
+
+ tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec?
+ orrne r2, r2, #HPTE_AP_READ
+
+ tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty?
+ orreq r2, r2, #HPTE_AP_WRITE
+
+ tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young?
+ movne r2, #0
+
+ str r2, [r0] @ hardware version
+ mov r0, r0
+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns)
+ mov pc, lr
+
+/*
* Function: sa110_check_bugs (void)
* : sa110_proc_init (void)
* : sa110_proc_fin (void)
- *
* Notes : This processor does not require these
*/
_sa110_check_bugs:
mrs ip, cpsr
bic ip, ip, #F_BIT
msr cpsr, ip
+
_sa110_proc_init:
_sa110_proc_fin:
mov pc, lr
/*
* Function: sa110_reset
- *
* Notes : This sets up everything for a reset
*/
_sa110_reset: mrs r1, cpsr
@@ -350,14 +369,15 @@ ENTRY(sa110_processor_functions)
.word _sa110_flush_cache_all @ 24
.word _sa110_flush_cache_area @ 28
.word _sa110_flush_cache_entry @ 32
- .word _sa110_flush_cache_pte @ 36
+ .word _sa110_clean_cache_area @ 36
.word _sa110_flush_ram_page @ 40
.word _sa110_flush_tlb_all @ 44
.word _sa110_flush_tlb_area @ 48
.word _sa110_set_pmd @ 52
- .word _sa110_reset @ 56
- .word _sa110_flush_icache_area @ 60
+ .word _sa110_set_pte @ 56
+ .word _sa110_reset @ 60
+ .word _sa110_flush_icache_area @ 64
- .word _sa110_cache_wback_area @ 64
- .word _sa110_cache_purge_area @ 68
+ .word _sa110_cache_wback_area @ 68
+ .word _sa110_cache_purge_area @ 72
diff --git a/arch/arm/mm/small_page.c b/arch/arm/mm/small_page.c
index 2f8cad9a3..6bdc6cfc7 100644
--- a/arch/arm/mm/small_page.c
+++ b/arch/arm/mm/small_page.c
@@ -5,6 +5,8 @@
*
* Changelog:
* 26/01/1996 RMK Cleaned up various areas to make little more generic
+ * 07/02/1999 RMK Support added for 16K and 32K page sizes
+ * containing 8K blocks
*/
#include <linux/signal.h>
@@ -19,21 +21,32 @@
#include <linux/swap.h>
#include <linux/smp.h>
-#define SMALL_ALLOC_SHIFT (10)
+#if PAGE_SIZE == 4096
+/* 2K blocks */
+#define SMALL_ALLOC_SHIFT (11)
+#define NAME(x) x##_2k
+#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384
+/* 8K blocks */
+#define SMALL_ALLOC_SHIFT (13)
+#define NAME(x) x##_8k
+#endif
+
#define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT)
#define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE)
+#define BLOCK_MASK ((1 << NR_BLOCKS) - 1)
-#if NR_BLOCKS != 4
-#error I only support 4 blocks per page!
-#endif
-
-#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & 15)
+#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK)
#define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off)
#define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off))
+#define ALL_USED BLOCK_MASK
#define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off)))
-#define PAGE_PTR(page,block) ((struct free_small_page *)((page) + \
+#define SM_PAGE_PTR(page,block) ((struct free_small_page *)((page) + \
((block) << SMALL_ALLOC_SHIFT)))
+#if NR_BLOCKS != 2 && NR_BLOCKS != 4
+#error I only support 2 or 4 blocks per page
+#endif
+
struct free_small_page {
unsigned long next;
unsigned long prev;
@@ -52,6 +65,7 @@ static unsigned char offsets[1<<NR_BLOCKS] = {
1, /* 0001 */
0, /* 0010 */
2, /* 0011 */
+#if NR_BLOCKS == 4
0, /* 0100 */
1, /* 0101 */
0, /* 0110 */
@@ -64,6 +78,7 @@ static unsigned char offsets[1<<NR_BLOCKS] = {
1, /* 1101 */
0, /* 1110 */
4 /* 1111 */
+#endif
};
static inline void clear_page_links(unsigned long page)
@@ -72,7 +87,7 @@ static inline void clear_page_links(unsigned long page)
int i;
for (i = 0; i < NR_BLOCKS; i++) {
- fsp = PAGE_PTR(page, i);
+ fsp = SM_PAGE_PTR(page, i);
fsp->next = fsp->prev = 0;
}
}
@@ -90,7 +105,7 @@ static inline void set_page_links_prev(unsigned long page, unsigned long prev)
for (i = 0; i < NR_BLOCKS; i++) {
if (mask & (1 << i))
continue;
- fsp = PAGE_PTR(page, i);
+ fsp = SM_PAGE_PTR(page, i);
fsp->prev = prev;
}
}
@@ -108,12 +123,12 @@ static inline void set_page_links_next(unsigned long page, unsigned long next)
for (i = 0; i < NR_BLOCKS; i++) {
if (mask & (1 << i))
continue;
- fsp = PAGE_PTR(page, i);
+ fsp = SM_PAGE_PTR(page, i);
fsp->next = next;
}
}
-unsigned long get_small_page(int priority)
+unsigned long NAME(get_page)(int priority)
{
struct free_small_page *fsp;
unsigned long new_page;
@@ -129,8 +144,8 @@ again:
page = mem_map + MAP_NR(small_page_ptr);
offset = offsets[USED(page)];
SET_USED(page, offset);
- new_page = (unsigned long)PAGE_PTR(small_page_ptr, offset);
- if (USED(page) == 15) {
+ new_page = (unsigned long)SM_PAGE_PTR(small_page_ptr, offset);
+ if (USED(page) == ALL_USED) {
fsp = (struct free_small_page *)new_page;
set_page_links_prev (fsp->next, 0);
small_page_ptr = fsp->next;
@@ -156,30 +171,31 @@ need_new_page:
goto again;
}
-void free_small_page(unsigned long spage)
+void NAME(free_page)(unsigned long spage)
{
struct free_small_page *ofsp, *cfsp;
unsigned long flags;
struct page *page;
int offset, oldoffset;
+ if (!spage)
+ goto none;
+
offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1);
spage -= offset << SMALL_ALLOC_SHIFT;
page = mem_map + MAP_NR(spage);
- if (!PageReserved(page) || !USED(page)) {
- printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
- return;
- }
- if (IS_FREE(page, offset)) {
- printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
- return;
- }
+ if (!PageReserved(page) || !USED(page))
+ goto non_small;
+
+ if (IS_FREE(page, offset))
+ goto free;
+
save_flags_cli (flags);
oldoffset = offsets[USED(page)];
CLEAR_USED(page, offset);
- ofsp = PAGE_PTR(spage, oldoffset);
- cfsp = PAGE_PTR(spage, offset);
+ ofsp = SM_PAGE_PTR(spage, oldoffset);
+ cfsp = SM_PAGE_PTR(spage, offset);
if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */
cfsp->prev = 0;
@@ -197,4 +213,13 @@ void free_small_page(unsigned long spage)
} else
*cfsp = *ofsp;
restore_flags(flags);
+ return;
+
+non_small:
+ printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
+ return;
+free:
+ printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
+none:
+ return;
}
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 3c42052e4..65a3aee0a 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -158,7 +158,7 @@ fi
endmenu
mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
@@ -168,6 +168,8 @@ endmenu
source drivers/char/Config.in
+# source drivers/usb/Config.in
+
source fs/Config.in
if [ "$CONFIG_VT" = "y" ]; then
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 200716f59..5bd7fe5bd 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -104,7 +104,6 @@ CONFIG_PARIDE_PARPORT=y
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -121,7 +120,6 @@ CONFIG_INET=y
# (it is safe to leave these untouched)
#
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
#
@@ -172,20 +170,25 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
@@ -241,7 +244,7 @@ CONFIG_EEXPRESS_PRO100=y
# CONFIG_ISDN is not set
#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
#
# CONFIG_CD_NO_IDESCSI is not set
@@ -281,6 +284,7 @@ CONFIG_82C710_MOUSE=y
# Joystick support
#
# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
#
# Ftape, the floppy tape device driver
diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c
index e7383e55b..91d338b2c 100644
--- a/arch/i386/kernel/bios32.c
+++ b/arch/i386/kernel/bios32.c
@@ -14,7 +14,7 @@
* Hannover, Germany
* hm@ix.de
*
- * Copyright 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * Copyright 1997--1999 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*
* For more information, please consult the following manuals (look at
* http://www.pcisig.com/ for how to get them):
@@ -71,6 +71,10 @@
* a large gallery of common hardware bug workarounds (watch the comments)
* -- the PCI specs themselves are sane, but most implementors should be
* hit hard with \hammer scaled \magstep5. [mj]
+ *
+ * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj]
+ *
+ * Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj]
*/
#include <linux/config.h>
@@ -171,6 +175,7 @@ PCI_STUB(write, dword, u32)
#define PCI_NO_SORT 0x100
#define PCI_BIOS_SORT 0x200
#define PCI_NO_CHECKS 0x400
+#define PCI_NO_PEER_FIXUP 0x800
static unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
@@ -521,6 +526,8 @@ static struct {
unsigned short segment;
} pci_indirect = { 0, __KERNEL_CS };
+static int pci_bios_present;
+
__initfunc(static int check_pcibios(void))
{
u32 signature, eax, ebx, ecx;
@@ -803,7 +810,7 @@ __initfunc(static struct pci_access *pci_find_bios(void))
* which used BIOS ordering, we are bound to do this...
*/
-__initfunc(void pcibios_sort(void))
+static void __init pcibios_sort(void)
{
struct pci_dev *dev = pci_devices;
struct pci_dev **last = &pci_devices;
@@ -856,7 +863,7 @@ __initfunc(void pcibios_sort(void))
static int pci_last_io_addr __initdata = 0x5800;
-__initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx))
+static void __init pcibios_fixup_io_addr(struct pci_dev *dev, int idx)
{
unsigned short cmd;
unsigned int reg = PCI_BASE_ADDRESS_0 + 4*idx;
@@ -868,13 +875,16 @@ __initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx))
printk("PCI: Unassigned I/O space for %02x:%02x\n", bus, devfn);
return;
}
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) {
+ if (((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+ (dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
/*
* In case the BIOS didn't assign an address 0--3 to an IDE
* controller, we don't try to fix it as it means "use default
* addresses" at least with several broken chips and the IDE
* driver needs the original settings to recognize which devices
* correspond to the primary controller.
+ *
+ * We don't assign VGA I/O ranges as well.
*/
return;
}
@@ -914,7 +924,7 @@ __initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx))
* expected to be unique) and remove the ghost devices.
*/
-__initfunc(void pcibios_fixup_ghosts(struct pci_bus *b))
+static void __init pcibios_fixup_ghosts(struct pci_bus *b)
{
struct pci_dev *d, *e, **z;
int mirror = PCI_DEVFN(16,0);
@@ -954,12 +964,17 @@ __initfunc(void pcibios_fixup_ghosts(struct pci_bus *b))
* the reality doesn't pass this test and the bus number is usually
* set by BIOS to the first free value.
*/
-__initfunc(void pcibios_fixup_peer_bridges(void))
+static void __init pcibios_fixup_peer_bridges(void)
{
struct pci_bus *b = &pci_root;
int i, n, cnt=-1;
struct pci_dev *d;
+#ifdef CONFIG_VISWS
+ pci_scan_peer_bridge(1);
+ return;
+#endif
+
#ifdef CONFIG_PCI_DIRECT
/*
* Don't search for peer host bridges if we use config type 2
@@ -969,6 +984,7 @@ __initfunc(void pcibios_fixup_peer_bridges(void))
if (access_pci == &pci_direct_conf2)
return;
#endif
+
for(d=b->devices; d; d=d->sibling)
if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST)
cnt++;
@@ -979,6 +995,20 @@ __initfunc(void pcibios_fixup_peer_bridges(void))
for(i=0; i<256; i += 8)
if (!pcibios_read_config_word(n, i, PCI_VENDOR_ID, &l) &&
l != 0x0000 && l != 0xffff) {
+#ifdef CONFIG_PCI_BIOS
+ if (pci_bios_present) {
+ int err, idx = 0;
+ u8 bios_bus, bios_dfn;
+ u16 d;
+ pcibios_read_config_word(n, i, PCI_DEVICE_ID, &d);
+ DBG("BIOS test for %02x:%02x (%04x:%04x)\n", n, i, l, d);
+ while (!(err = pci_bios_find_device(l, d, idx, &bios_bus, &bios_dfn)) &&
+ (bios_bus != n || bios_dfn != i))
+ idx++;
+ if (err)
+ break;
+ }
+#endif
DBG("Found device at %02x:%02x\n", n, i);
found++;
if (!pcibios_read_config_word(n, i, PCI_CLASS_DEVICE, &l) &&
@@ -989,13 +1019,7 @@ __initfunc(void pcibios_fixup_peer_bridges(void))
break;
if (found) {
printk("PCI: Discovered primary peer bus %02x\n", n);
- b = kmalloc(sizeof(*b), GFP_KERNEL);
- memset(b, 0, sizeof(*b));
- b->next = pci_root.next;
- pci_root.next = b;
- b->number = b->secondary = n;
- b->subordinate = 0xff;
- b->subordinate = pci_scan_bus(b);
+ b = pci_scan_peer_bridge(n);
n = b->subordinate;
}
n++;
@@ -1003,11 +1027,77 @@ __initfunc(void pcibios_fixup_peer_bridges(void))
}
/*
+ * Exceptions for specific devices. Usually work-arounds for fatal design flaws.
+ */
+
+static void __init pci_fixup_i450nx(struct pci_dev *d)
+{
+ /*
+ * i450NX -- Find and scan all secondary buses on all PXB's.
+ */
+ int pxb, reg;
+ u8 busno, suba, subb;
+ reg = 0xd0;
+ for(pxb=0; pxb<2; pxb++) {
+ pci_read_config_byte(d, reg++, &busno);
+ pci_read_config_byte(d, reg++, &suba);
+ pci_read_config_byte(d, reg++, &subb);
+ DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
+ if (busno)
+ pci_scan_peer_bridge(busno); /* Bus A */
+ if (suba < subb)
+ pci_scan_peer_bridge(suba+1); /* Bus B */
+ }
+ pci_probe |= PCI_NO_PEER_FIXUP;
+}
+
+static void __init pci_fixup_umc_ide(struct pci_dev *d)
+{
+ /*
+ * UM8886BF IDE controller sets region type bits incorrectly,
+ * therefore they look like memory despite of them being I/O.
+ */
+ int i;
+
+ for(i=0; i<4; i++)
+ d->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
+}
+
+struct dev_ex {
+ u16 vendor, device;
+ void (*handler)(struct pci_dev *);
+ char *comment;
+};
+
+static struct dev_ex __initdata dev_ex_table[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx, "Scanning peer host bridges" },
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide, "Working around UM8886BF bugs" }
+};
+
+static void __init pcibios_scan_buglist(struct pci_bus *b)
+{
+ struct pci_dev *d;
+ int i;
+
+ for(d=b->devices; d; d=d->sibling)
+ for(i=0; i<sizeof(dev_ex_table)/sizeof(dev_ex_table[0]); i++) {
+ struct dev_ex *e = &dev_ex_table[i];
+ if (e->vendor == d->vendor && e->device == d->device) {
+ printk("PCI: %02x:%02x [%04x/%04x]: %s\n",
+ b->number, d->devfn, d->vendor, d->device, e->comment);
+ e->handler(d);
+ }
+ }
+}
+
+/*
* Fix base addresses, I/O and memory enables and IRQ's (mostly work-arounds
* for buggy PCI BIOS'es :-[).
*/
-__initfunc(void pcibios_fixup_devices(void))
+extern int skip_ioapic_setup;
+
+static void __init pcibios_fixup_devices(void)
{
struct pci_dev *dev;
int i, has_io, has_mem;
@@ -1059,6 +1149,7 @@ __initfunc(void pcibios_fixup_devices(void))
/*
* Recalculate IRQ numbers if we use the I/O APIC
*/
+ if(!skip_ioapic_setup)
{
int irq;
unsigned char pin;
@@ -1099,7 +1190,8 @@ __initfunc(void pcibios_fixup_devices(void))
__initfunc(void pcibios_fixup(void))
{
- pcibios_fixup_peer_bridges();
+ if (!(pci_probe & PCI_NO_PEER_FIXUP))
+ pcibios_fixup_peer_bridges();
pcibios_fixup_devices();
#ifdef CONFIG_PCI_BIOS
@@ -1111,6 +1203,7 @@ __initfunc(void pcibios_fixup(void))
__initfunc(void pcibios_fixup_bus(struct pci_bus *b))
{
pcibios_fixup_ghosts(b);
+ pcibios_scan_buglist(b);
}
/*
@@ -1126,8 +1219,10 @@ __initfunc(void pcibios_init(void))
struct pci_access *dir = NULL;
#ifdef CONFIG_PCI_BIOS
- if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios())))
+ if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
pci_probe |= PCI_BIOS_SORT;
+ pci_bios_present = 1;
+ }
#endif
#ifdef CONFIG_PCI_DIRECT
if (pci_probe & (PCI_PROBE_CONF1 | PCI_PROBE_CONF2))
@@ -1139,10 +1234,6 @@ __initfunc(void pcibios_init(void))
access_pci = bios;
}
-#if !defined(CONFIG_PCI_BIOS) && !defined(CONFIG_PCI_DIRECT)
-#error PCI configured with neither PCI BIOS or PCI direct access support.
-#endif
-
__initfunc(char *pcibios_setup(char *str))
{
if (!strcmp(str, "off")) {
@@ -1178,5 +1269,9 @@ __initfunc(char *pcibios_setup(char *str))
return NULL;
}
#endif
+ else if (!strcmp(str, "nopeer")) {
+ pci_probe |= PCI_NO_PEER_FIXUP;
+ return NULL;
+ }
return str;
}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 0153c4b40..3a5fc93a1 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -154,7 +154,9 @@ ENTRY(lcall7)
.globl ret_from_fork
ret_from_fork:
#ifdef __SMP__
+ pushl %ebx
call SYMBOL_NAME(schedule_tail)
+ addl $4, %esp
#endif /* __SMP__ */
GET_CURRENT(%ebx)
jmp ret_from_sys_call
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index cd9074796..f0d5d3378 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -39,10 +39,12 @@ EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
@@ -74,8 +76,11 @@ EXPORT_SYMBOL(strlen_user);
EXPORT_SYMBOL(cpu_data);
EXPORT_SYMBOL(kernel_flag);
EXPORT_SYMBOL(smp_invalidate_needed);
+EXPORT_SYMBOL(cpu_number_map);
EXPORT_SYMBOL(__cpu_logical_map);
EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(cpu_present_map);
+EXPORT_SYMBOL(cpu_online_map);
/* Global SMP irq stuff */
EXPORT_SYMBOL(synchronize_irq);
@@ -87,7 +92,7 @@ EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(mtrr_hook);
+EXPORT_SYMBOL(smp_call_function);
#endif
#ifdef CONFIG_MCA
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 232abf78d..42ebd9643 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -202,7 +202,7 @@ DO_ACTION( enable, 1, |= 0xff000000, ) /* destination = 0xff */
DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync()) /* mask = 1 */
DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */
-static void __init clear_IO_APIC_pin(unsigned int pin)
+static void clear_IO_APIC_pin(unsigned int pin)
{
struct IO_APIC_route_entry entry;
@@ -215,6 +215,13 @@ static void __init clear_IO_APIC_pin(unsigned int pin)
io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1));
}
+static void clear_IO_APIC (void)
+{
+ int pin;
+
+ for (pin = 0; pin < nr_ioapic_registers; pin++)
+ clear_IO_APIC_pin(pin);
+}
/*
* support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
@@ -286,7 +293,8 @@ static int __init find_timer_pin(int type)
for (i = 0; i < mp_irq_entries; i++) {
int lbus = mp_irqs[i].mpc_srcbus;
- if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA) &&
+ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
+ mp_bus_id_to_type[lbus] == MP_BUS_EISA) &&
(mp_irqs[i].mpc_irqtype == type) &&
(mp_irqs[i].mpc_srcbusirq == 0x00))
@@ -319,20 +327,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
}
/*
- * Unclear documentation on what a "conforming ISA interrupt" means.
- *
- * Should we, or should we not, take the ELCR register into account?
- * It's part of the EISA specification, but maybe it should only be
- * used if the interrupt is actually marked as EISA?
- *
- * Oh, well. Don't do it until somebody tells us what the right thing
- * to do is..
- */
-#undef USE_ELCR_TRIGGER_LEVEL
-#ifdef USE_ELCR_TRIGGER_LEVEL
-
-/*
- * ISA Edge/Level control register, ELCR
+ * EISA Edge/Level control register, ELCR
*/
static int __init EISA_ELCR(unsigned int irq)
{
@@ -342,18 +337,22 @@ static int __init EISA_ELCR(unsigned int irq)
}
printk("Broken MPtable reports ISA irq %d\n", irq);
return 0;
-}
+}
-#define default_ISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_dstirq))
-#define default_ISA_polarity(idx) (0)
+/* EISA interrupts are always polarity zero and can be edge or level
+ * trigger depending on the ELCR value. If an interrupt is listed as
+ * EISA conforming in the MP table, that means its trigger type must
+ * be read in from the ELCR */
-#else
+#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_dstirq))
+#define default_EISA_polarity(idx) (0)
+
+/* ISA interrupts are always polarity zero edge triggered, even when
+ * listed as conforming in the MP table. */
#define default_ISA_trigger(idx) (0)
#define default_ISA_polarity(idx) (0)
-#endif
-
static int __init MPBIOS_polarity(int idx)
{
int bus = mp_irqs[idx].mpc_srcbus;
@@ -373,6 +372,11 @@ static int __init MPBIOS_polarity(int idx)
polarity = default_ISA_polarity(idx);
break;
}
+ case MP_BUS_EISA:
+ {
+ polarity = default_EISA_polarity(idx);
+ break;
+ }
case MP_BUS_PCI: /* PCI pin */
{
polarity = 1;
@@ -432,6 +436,11 @@ static int __init MPBIOS_trigger(int idx)
trigger = default_ISA_trigger(idx);
break;
}
+ case MP_BUS_EISA:
+ {
+ trigger = default_EISA_trigger(idx);
+ break;
+ }
case MP_BUS_PCI: /* PCI pin, level */
{
trigger = 1;
@@ -496,6 +505,7 @@ static int __init pin_2_irq(int idx, int pin)
switch (mp_bus_id_to_type[bus])
{
case MP_BUS_ISA: /* ISA pin */
+ case MP_BUS_EISA:
{
irq = mp_irqs[idx].mpc_srcbusirq;
break;
@@ -562,6 +572,9 @@ static int __init assign_irq_vector(int irq)
printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n",
current_vector);
}
+ if (current_vector == SYSCALL_VECTOR)
+ panic("ran out of interrupt sources!");
+
IO_APIC_VECTOR(irq) = current_vector;
return current_vector;
}
@@ -625,7 +638,7 @@ void __init setup_IO_APIC_irqs(void)
/*
* Set up a certain pin as ExtINT delivered interrupt
*/
-void __init setup_ExtINT_pin(unsigned int pin)
+void __init setup_ExtINT_pin(unsigned int pin, int irq)
{
struct IO_APIC_route_entry entry;
@@ -635,11 +648,16 @@ void __init setup_ExtINT_pin(unsigned int pin)
memset(&entry,0,sizeof(entry));
entry.delivery_mode = dest_ExtINT;
- entry.dest_mode = 1; /* logical delivery */
+ entry.dest_mode = 0; /* physical delivery */
entry.mask = 0; /* unmask IRQ now */
- entry.dest.logical.logical_dest = 0x01; /* logical CPU #0 */
+ /*
+ * We use physical delivery to get the timer IRQ
+ * to the boot CPU. 'boot_cpu_id' is the physical
+ * APIC ID of the boot CPU.
+ */
+ entry.dest.physical.physical_dest = boot_cpu_id;
- entry.vector = 0; /* it's ignored */
+ entry.vector = assign_irq_vector(irq);
entry.polarity = 0;
entry.trigger = 0;
@@ -681,9 +699,11 @@ void __init print_IO_APIC(void)
printk(".... register #01: %08X\n", *(int *)&reg_01);
printk("....... : max redirection entries: %04X\n", reg_01.entries);
- if ( (reg_01.entries != 0x0f) && /* ISA-only Neptune boards */
- (reg_01.entries != 0x17) && /* ISA+PCI boards */
- (reg_01.entries != 0x3F) /* Xeon boards */
+ if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */
+ (reg_01.entries != 0x17) && /* typical ISA+PCI boards */
+ (reg_01.entries != 0x1b) && /* Compaq Proliant boards */
+ (reg_01.entries != 0x1f) && /* dual Xeon boards */
+ (reg_01.entries != 0x3F) /* bigger Xeon boards */
)
UNEXPECTED_IO_APIC();
if (reg_01.entries == 0x0f)
@@ -754,7 +774,7 @@ void __init print_IO_APIC(void)
static void __init init_sym_mode(void)
{
- int i, pin;
+ int i;
for (i = 0; i < PIN_MAP_SIZE; i++) {
irq_2_pin[i].pin = -1;
@@ -784,8 +804,7 @@ static void __init init_sym_mode(void)
/*
* Do not trust the IO-APIC being empty at bootup
*/
- for (pin = 0; pin < nr_ioapic_registers; pin++)
- clear_IO_APIC_pin(pin);
+ clear_IO_APIC();
}
/*
@@ -793,6 +812,15 @@ static void __init init_sym_mode(void)
*/
void init_pic_mode(void)
{
+ /*
+ * Clear the IO-APIC before rebooting:
+ */
+ clear_IO_APIC();
+
+ /*
+ * Put it back into PIC mode (has an effect only on
+ * certain boards)
+ */
printk("disabling symmetric IO mode... ");
outb_p(0x70, 0x22);
outb_p(0x00, 0x23);
@@ -885,6 +913,8 @@ static void __init setup_ioapic_id(void)
static void __init construct_default_ISA_mptable(void)
{
int i, pos = 0;
+ const int bus_type = (mpc_default_type == 2 || mpc_default_type == 3 ||
+ mpc_default_type == 6) ? MP_BUS_EISA : MP_BUS_ISA;
for (i = 0; i < 16; i++) {
if (!IO_APIC_IRQ(i))
@@ -892,14 +922,14 @@ static void __init construct_default_ISA_mptable(void)
mp_irqs[pos].mpc_irqtype = mp_INT;
mp_irqs[pos].mpc_irqflag = 0; /* default */
- mp_irqs[pos].mpc_srcbus = MP_BUS_ISA;
+ mp_irqs[pos].mpc_srcbus = 0;
mp_irqs[pos].mpc_srcbusirq = i;
mp_irqs[pos].mpc_dstapic = 0;
mp_irqs[pos].mpc_dstirq = i;
pos++;
}
mp_irq_entries = pos;
- mp_bus_id_to_type[0] = MP_BUS_ISA;
+ mp_bus_id_to_type[0] = bus_type;
/*
* MP specification 1.4 defines some extra rules for default
@@ -1019,7 +1049,7 @@ static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
* and do not need to be masked.
*/
ack_APIC_irq();
- status = desc->status & ~IRQ_REPLAY;
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
status |= IRQ_PENDING;
/*
@@ -1030,8 +1060,9 @@ static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
action = desc->action;
status &= ~IRQ_PENDING;
+ status |= IRQ_INPROGRESS;
}
- desc->status = status | IRQ_INPROGRESS;
+ desc->status = status;
spin_unlock(&irq_controller_lock);
/*
@@ -1073,7 +1104,7 @@ static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
* So this all has to be within the spinlock.
*/
mask_IO_APIC_irq(irq);
- status = desc->status & ~IRQ_REPLAY;
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
/*
* If the IRQ is disabled for whatever reason, we must
@@ -1082,8 +1113,9 @@ static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs)
action = NULL;
if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
action = desc->action;
+ status |= IRQ_INPROGRESS;
}
- desc->status = status | IRQ_INPROGRESS;
+ desc->status = status;
ack_APIC_irq();
spin_unlock(&irq_controller_lock);
@@ -1143,7 +1175,7 @@ static inline void init_IO_APIC_traps(void)
* 0x80, because int 0x80 is hm, kind of importantish. ;)
*/
for (i = 0; i < NR_IRQS ; i++) {
- if (IO_APIC_IRQ(i)) {
+ if (IO_APIC_VECTOR(i) > 0) {
if (IO_APIC_irq_trigger(i))
irq_desc[i].handler = &ioapic_level_irq_type;
else
@@ -1153,8 +1185,25 @@ static inline void init_IO_APIC_traps(void)
*/
if (i < 16)
disable_8259A_irq(i);
+ } else {
+ if (!IO_APIC_IRQ(i))
+ continue;
+
+ /*
+ * Hmm.. We don't have an entry for this,
+ * so default to an old-fashioned 8259
+ * interrupt if we can..
+ */
+ if (i < 16) {
+ make_8259A_irq(i);
+ continue;
+ }
+
+ /* Strange. Oh, well.. */
+ irq_desc[i].handler = &no_irq_type;
}
}
+ init_IRQ_SMP();
}
/*
@@ -1178,7 +1227,7 @@ static inline void check_timer(void)
if (pin2 != -1) {
printk(".. (found pin %d) ...", pin2);
- setup_ExtINT_pin(pin2);
+ setup_ExtINT_pin(pin2, 0);
make_8259A_irq(0);
}
@@ -1258,14 +1307,12 @@ void __init setup_IO_APIC(void)
construct_default_ISA_mptable();
}
- init_IO_APIC_traps();
-
/*
* Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
* mptable:
*/
setup_IO_APIC_irqs();
- init_IRQ_SMP();
+ init_IO_APIC_traps();
check_timer();
print_IO_APIC();
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 37878f59f..ea218fe45 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -70,11 +70,34 @@ atomic_t nmi_counter;
*/
spinlock_t irq_controller_lock;
-
/*
* Dummy controller type for unused interrupts
*/
-static void do_none(unsigned int irq, struct pt_regs * regs) { }
+static void do_none(unsigned int irq, struct pt_regs * regs)
+{
+ /*
+ * we are careful. While for ISA irqs it's common to happen
+ * outside of any driver (think autodetection), this is not
+ * at all nice for PCI interrupts. So we are stricter and
+ * print a warning when such spurious interrupts happen.
+ * Spurious interrupts can confuse other drivers if the PCI
+ * IRQ line is shared.
+ *
+ * Such spurious interrupts are either driver bugs, or
+ * sometimes hw (chipset) bugs.
+ */
+ printk("unexpected IRQ vector %d on CPU#%d!\n",irq, smp_processor_id());
+
+#ifdef __SMP__
+ /*
+ * [currently unexpected vectors happen only on SMP and APIC.
+ * if we want to have non-APIC and non-8259A controllers
+ * in the future with unexpected vectors, this ack should
+ * probably be made controller-specific.]
+ */
+ ack_APIC_irq();
+#endif
+}
static void enable_none(unsigned int irq) { }
static void disable_none(unsigned int irq) { }
@@ -82,7 +105,7 @@ static void disable_none(unsigned int irq) { }
#define startup_none enable_none
#define shutdown_none disable_none
-static struct hw_interrupt_type no_irq_type = {
+struct hw_interrupt_type no_irq_type = {
"none",
startup_none,
shutdown_none,
@@ -128,10 +151,7 @@ irq_desc_t irq_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
*/
static unsigned int cached_irq_mask = 0xffff;
-#define __byte(x,y) (((unsigned char *)&(y))[x])
-#define __word(x,y) (((unsigned short *)&(y))[x])
-#define __long(x,y) (((unsigned int *)&(y))[x])
-
+#define __byte(x,y) (((unsigned char *)&(y))[x])
#define cached_21 (__byte(0,cached_irq_mask))
#define cached_A1 (__byte(1,cached_irq_mask))
@@ -141,10 +161,10 @@ static unsigned int cached_irq_mask = 0xffff;
* fed to the CPU IRQ line directly.
*
* Any '1' bit in this mask means the IRQ is routed through the IO-APIC.
- * this 'mixed mode' IRQ handling costs us one more branch in do_IRQ,
- * but we have _much_ higher compatibility and robustness this way.
+ * this 'mixed mode' IRQ handling costs nothing because it's only used
+ * at IRQ setup time.
*/
-unsigned long long io_apic_irqs = 0;
+unsigned long io_apic_irqs = 0;
/*
* These have to be protected by the irq controller spinlock
@@ -183,8 +203,8 @@ int i8259A_irq_pending(unsigned int irq)
void make_8259A_irq(unsigned int irq)
{
- disable_irq(irq);
- __long(0,io_apic_irqs) &= ~(1<<irq);
+ disable_irq_nosync(irq);
+ io_apic_irqs &= ~(1<<irq);
irq_desc[irq].handler = &i8259A_irq_type;
enable_irq(irq);
}
@@ -219,11 +239,13 @@ static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
{
unsigned int status;
mask_and_ack_8259A(irq);
- status = desc->status & ~IRQ_REPLAY;
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
action = NULL;
- if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
action = desc->action;
- desc->status = status | IRQ_INPROGRESS;
+ status |= IRQ_INPROGRESS;
+ }
+ desc->status = status;
}
spin_unlock(&irq_controller_lock);
@@ -254,32 +276,43 @@ static void do_8259A_IRQ(unsigned int irq, struct pt_regs * regs)
BUILD_COMMON_IRQ()
+
+#define BI(x,y) \
+ BUILD_IRQ(##x##y)
+
+#define BUILD_16_IRQS(x) \
+ BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
+ BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
+ BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+ BI(x,c) BI(x,d) BI(x,e) BI(x,f)
+
/*
* ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
+ * (these are usually mapped to vectors 0x20-0x30)
*/
-BUILD_IRQ(0) BUILD_IRQ(1) BUILD_IRQ(2) BUILD_IRQ(3)
-BUILD_IRQ(4) BUILD_IRQ(5) BUILD_IRQ(6) BUILD_IRQ(7)
-BUILD_IRQ(8) BUILD_IRQ(9) BUILD_IRQ(10) BUILD_IRQ(11)
-BUILD_IRQ(12) BUILD_IRQ(13) BUILD_IRQ(14) BUILD_IRQ(15)
+BUILD_16_IRQS(0x0)
#ifdef CONFIG_X86_IO_APIC
/*
- * The IO-APIC gives us many more interrupt sources..
+ * The IO-APIC gives us many more interrupt sources. Most of these
+ * are unused but an SMP system is supposed to have enough memory ...
+ * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
+ * across the spectrum, so we really want to be prepared to get all
+ * of these. Plus, more powerful systems might have more than 64
+ * IO-APIC registers.
+ *
+ * (these are usually mapped into the 0x30-0xff vector range)
*/
-BUILD_IRQ(16) BUILD_IRQ(17) BUILD_IRQ(18) BUILD_IRQ(19)
-BUILD_IRQ(20) BUILD_IRQ(21) BUILD_IRQ(22) BUILD_IRQ(23)
-BUILD_IRQ(24) BUILD_IRQ(25) BUILD_IRQ(26) BUILD_IRQ(27)
-BUILD_IRQ(28) BUILD_IRQ(29) BUILD_IRQ(30) BUILD_IRQ(31)
-BUILD_IRQ(32) BUILD_IRQ(33) BUILD_IRQ(34) BUILD_IRQ(35)
-BUILD_IRQ(36) BUILD_IRQ(37) BUILD_IRQ(38) BUILD_IRQ(39)
-BUILD_IRQ(40) BUILD_IRQ(41) BUILD_IRQ(42) BUILD_IRQ(43)
-BUILD_IRQ(44) BUILD_IRQ(45) BUILD_IRQ(46) BUILD_IRQ(47)
-BUILD_IRQ(48) BUILD_IRQ(49) BUILD_IRQ(50) BUILD_IRQ(51)
-BUILD_IRQ(52) BUILD_IRQ(53) BUILD_IRQ(54) BUILD_IRQ(55)
-BUILD_IRQ(56) BUILD_IRQ(57) BUILD_IRQ(58) BUILD_IRQ(59)
-BUILD_IRQ(60) BUILD_IRQ(61) BUILD_IRQ(62) BUILD_IRQ(63)
+ BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
+BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
#endif
+#undef BUILD_16_IRQS
+#undef BI
+
+
#ifdef __SMP__
/*
* The following vectors are part of the Linux architecture, there
@@ -289,7 +322,7 @@ BUILD_IRQ(60) BUILD_IRQ(61) BUILD_IRQ(62) BUILD_IRQ(63)
BUILD_SMP_INTERRUPT(reschedule_interrupt)
BUILD_SMP_INTERRUPT(invalidate_interrupt)
BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
-BUILD_SMP_INTERRUPT(mtrr_interrupt)
+BUILD_SMP_INTERRUPT(call_function_interrupt)
BUILD_SMP_INTERRUPT(spurious_interrupt)
/*
@@ -303,37 +336,35 @@ BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt)
#endif
+#define IRQ(x,y) \
+ IRQ##x##y##_interrupt
+
+#define IRQLIST_16(x) \
+ IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
+ IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
+ IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
+
static void (*interrupt[NR_IRQS])(void) = {
- IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
- IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
- IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
- IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
+ IRQLIST_16(0x0),
+
#ifdef CONFIG_X86_IO_APIC
- ,IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,
- IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,
- IRQ24_interrupt, IRQ25_interrupt, IRQ26_interrupt, IRQ27_interrupt,
- IRQ28_interrupt, IRQ29_interrupt,
- IRQ30_interrupt, IRQ31_interrupt, IRQ32_interrupt, IRQ33_interrupt,
- IRQ34_interrupt, IRQ35_interrupt, IRQ36_interrupt, IRQ37_interrupt,
- IRQ38_interrupt, IRQ39_interrupt,
- IRQ40_interrupt, IRQ41_interrupt, IRQ42_interrupt, IRQ43_interrupt,
- IRQ44_interrupt, IRQ45_interrupt, IRQ46_interrupt, IRQ47_interrupt,
- IRQ48_interrupt, IRQ49_interrupt,
- IRQ50_interrupt, IRQ51_interrupt, IRQ52_interrupt, IRQ53_interrupt,
- IRQ54_interrupt, IRQ55_interrupt, IRQ56_interrupt, IRQ57_interrupt,
- IRQ58_interrupt, IRQ59_interrupt,
- IRQ60_interrupt, IRQ61_interrupt, IRQ62_interrupt, IRQ63_interrupt
+ IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
+ IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
+ IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
+ IRQLIST_16(0xc), IRQLIST_16(0xd)
#endif
};
+#undef IRQ
+#undef IRQLIST_16
+
/*
- * Initial irq handlers.
+ * Special irq handlers.
*/
-void no_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-}
+void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
#ifndef CONFIG_VISWS
/*
@@ -718,7 +749,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction *
* hardware disable after having gotten the irq
* controller lock.
*/
-void disable_irq(unsigned int irq)
+void disable_irq_nosync(unsigned int irq)
{
unsigned long flags;
@@ -728,9 +759,21 @@ void disable_irq(unsigned int irq)
irq_desc[irq].handler->disable(irq);
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
- if (irq_desc[irq].status & IRQ_INPROGRESS)
- synchronize_irq();
+/*
+ * Synchronous version of the above, making sure the IRQ is
+ * no longer running on any other IRQ..
+ */
+void disable_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+
+ if (!local_irq_count[smp_processor_id()]) {
+ do {
+ barrier();
+ } while (irq_desc[irq].status & IRQ_INPROGRESS);
+ }
}
void enable_irq(unsigned int irq)
@@ -740,7 +783,7 @@ void enable_irq(unsigned int irq)
spin_lock_irqsave(&irq_controller_lock, flags);
switch (irq_desc[irq].depth) {
case 1:
- irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
+ irq_desc[irq].status &= ~IRQ_DISABLED;
irq_desc[irq].handler->enable(irq);
/* fall throught */
default:
@@ -770,7 +813,7 @@ asmlinkage void do_IRQ(struct pt_regs regs)
* 0 return value means that this irq is already being
* handled by some other CPU. (or is disabled)
*/
- unsigned int irq = regs.orig_eax & 0xff;
+ int irq = regs.orig_eax & 0xff; /* subtle, see irq.h */
int cpu = smp_processor_id();
kstat.irqs[cpu][irq]++;
@@ -835,7 +878,7 @@ int setup_x86_irq(unsigned int irq, struct irqaction * new)
if (!shared) {
irq_desc[irq].depth = 0;
- irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
+ irq_desc[irq].status &= ~IRQ_DISABLED;
irq_desc[irq].handler->startup(irq);
}
spin_unlock_irqrestore(&irq_controller_lock,flags);
@@ -907,7 +950,7 @@ out:
*
* This depends on the fact that any interrupt that
* comes in on to an unassigned handler will get stuck
- * with "IRQ_INPROGRESS" asserted and the interrupt
+ * with "IRQ_WAITING" cleared and the interrupt
* disabled.
*/
unsigned long probe_irq_on(void)
@@ -921,8 +964,7 @@ unsigned long probe_irq_on(void)
spin_lock_irq(&irq_controller_lock);
for (i = NR_IRQS-1; i > 0; i--) {
if (!irq_desc[i].action) {
- unsigned int status = irq_desc[i].status | IRQ_AUTODETECT;
- irq_desc[i].status = status & ~IRQ_INPROGRESS;
+ irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
irq_desc[i].handler->startup(i);
}
}
@@ -945,7 +987,7 @@ unsigned long probe_irq_on(void)
continue;
/* It triggered already - consider it spurious. */
- if (status & IRQ_INPROGRESS) {
+ if (!(status & IRQ_WAITING)) {
irq_desc[i].status = status & ~IRQ_AUTODETECT;
irq_desc[i].handler->shutdown(i);
}
@@ -971,7 +1013,7 @@ int probe_irq_off(unsigned long unused)
if (!(status & IRQ_AUTODETECT))
continue;
- if (status & IRQ_INPROGRESS) {
+ if (!(status & IRQ_WAITING)) {
if (!nr_irqs)
irq_found = i;
nr_irqs++;
@@ -986,42 +1028,6 @@ int probe_irq_off(unsigned long unused)
return irq_found;
}
-/*
- * Silly, horrible hack
- */
-static char uglybuffer[10*256];
-
-__asm__("\n" __ALIGN_STR"\n"
- "common_unexpected:\n\t"
- SAVE_ALL
- "pushl $ret_from_intr\n\t"
- "jmp strange_interrupt");
-
-void strange_interrupt(int irqnum)
-{
- printk("Unexpected interrupt %d\n", irqnum & 255);
- for (;;);
-}
-
-extern int common_unexpected;
-__initfunc(void init_unexpected_irq(void))
-{
- int i;
- for (i = 0; i < 256; i++) {
- char *code = uglybuffer + 10*i;
- unsigned long jumpto = (unsigned long) &common_unexpected;
-
- jumpto -= (unsigned long)(code+10);
- code[0] = 0x68; /* pushl */
- *(int *)(code+1) = i - 512;
- code[5] = 0xe9; /* jmp */
- *(int *)(code+6) = jumpto;
-
- set_intr_gate(i,code);
- }
-}
-
-
void init_ISA_irqs (void)
{
int i;
@@ -1033,7 +1039,7 @@ void init_ISA_irqs (void)
if (i < 16) {
/*
- * 16 old-style INTA-cycle interrupt gates:
+ * 16 old-style INTA-cycle interrupts:
*/
irq_desc[i].handler = &i8259A_irq_type;
} else {
@@ -1054,9 +1060,16 @@ __initfunc(void init_IRQ(void))
#else
init_VISWS_APIC_irqs();
#endif
-
- for (i = 0; i < 16; i++)
- set_intr_gate(0x20+i,interrupt[i]);
+ /*
+ * Cover the whole vector space, no vector can escape
+ * us. (some of these will be overridden and become
+ * 'special' SMP interrupts)
+ */
+ for (i = 0; i < NR_IRQS; i++) {
+ int vector = FIRST_EXTERNAL_VECTOR + i;
+ if (vector != SYSCALL_VECTOR)
+ set_intr_gate(vector, interrupt[i]);
+ }
#ifdef __SMP__
@@ -1067,13 +1080,9 @@ __initfunc(void init_IRQ(void))
set_intr_gate(IRQ0_TRAP_VECTOR, interrupt[0]);
/*
- * The reschedule interrupt slowly changes it's functionality,
- * while so far it was a kind of broadcasted timer interrupt,
- * in the future it should become a CPU-to-CPU rescheduling IPI,
- * driven by schedule() ?
+ * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+ * IPI, driven by wakeup.
*/
-
- /* IPI for rescheduling */
set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
/* IPI for invalidation */
@@ -1085,8 +1094,8 @@ __initfunc(void init_IRQ(void))
/* self generated IPI for local APIC timer */
set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
- /* IPI for MTRR control */
- set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt);
+ /* IPI for generic function call */
+ set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
/* IPI vector for APIC spurious interrupts */
set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h
index 982ab101e..6a19d9884 100644
--- a/arch/i386/kernel/irq.h
+++ b/arch/i386/kernel/irq.h
@@ -16,6 +16,7 @@ struct hw_interrupt_type {
void (*disable)(unsigned int irq);
};
+extern struct hw_interrupt_type no_irq_type;
/*
* IRQ line status.
@@ -25,6 +26,7 @@ struct hw_interrupt_type {
#define IRQ_PENDING 4 /* IRQ pending - replay on enable */
#define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */
#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */
+#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */
/*
* This is the "IRQ descriptor", which contains various information
@@ -41,6 +43,18 @@ typedef struct {
} irq_desc_t;
/*
+ * IDT vectors usable for external interrupt sources start
+ * at 0x20:
+ */
+#define FIRST_EXTERNAL_VECTOR 0x20
+
+#define SYSCALL_VECTOR 0x80
+
+/*
+ * Vectors 0x20-0x2f are used for ISA interrupts.
+ */
+
+/*
* Special IRQ vectors used by the SMP architecture:
*
* (some of the following vectors are 'rare', they might be merged
@@ -51,10 +65,10 @@ typedef struct {
#define INVALIDATE_TLB_VECTOR 0x31
#define STOP_CPU_VECTOR 0x40
#define LOCAL_TIMER_VECTOR 0x41
-#define MTRR_CHANGE_VECTOR 0x50
+#define CALL_FUNCTION_VECTOR 0x50
/*
- * First vector available to drivers: (vectors 0x51-0xfe)
+ * First APIC vector available to drivers: (vectors 0x51-0xfe)
*/
#define IRQ0_TRAP_VECTOR 0x51
@@ -85,7 +99,6 @@ extern void disable_8259A_irq(unsigned int irq);
extern int i8259A_irq_pending(unsigned int irq);
extern void ack_APIC_irq(void);
extern void FASTCALL(send_IPI_self(int vector));
-extern void smp_send_mtrr(void);
extern void init_VISWS_APIC_irqs(void);
extern void setup_IO_APIC(void);
extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
@@ -94,12 +107,15 @@ extern void send_IPI(int dest, int vector);
extern void init_pic_mode(void);
extern void print_IO_APIC(void);
-extern unsigned long long io_apic_irqs;
+extern unsigned long io_apic_irqs;
+
+extern char _stext, _etext;
#define MAX_IRQ_SOURCES 128
#define MAX_MP_BUSSES 32
enum mp_bustype {
MP_BUS_ISA,
+ MP_BUS_EISA,
MP_BUS_PCI
};
extern int mp_bus_id_to_type [MAX_MP_BUSSES];
@@ -126,7 +142,7 @@ static inline void irq_exit(int cpu, unsigned int irq)
hardirq_exit(cpu);
}
-#define IO_APIC_IRQ(x) ((1<<x) & io_apic_irqs)
+#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
#else
@@ -201,6 +217,13 @@ __asm__( \
"pushl $ret_from_intr\n\t" \
"jmp "SYMBOL_NAME_STR(do_IRQ));
+/*
+ * subtle. orig_eax is used by the signal code to distinct between
+ * system calls and interrupted 'random user-space'. Thus we have
+ * to put a negative value into orig_eax here. (the problem is that
+ * both system calls and IRQs want to have small integer numbers in
+ * orig_eax, and the syscall code has won the optimization conflict ;)
+ */
#define BUILD_IRQ(nr) \
asmlinkage void IRQ_NAME(nr); \
__asm__( \
@@ -216,7 +239,6 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
static inline void x86_do_profile (unsigned long eip)
{
if (prof_buffer && current->pid) {
- extern int _stext;
eip -= (unsigned long) &_stext;
eip >>= prof_shift;
/*
diff --git a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c
index de5a47e72..7c5ad2712 100644
--- a/arch/i386/kernel/mca.c
+++ b/arch/i386/kernel/mca.c
@@ -26,6 +26,9 @@
* - Added the 'driver_loaded' flag in MCA_adapter
* - Added an alternative implemention of ZP Gu's mca_find_unused_adapter
*
+ * David Weinehall March 24th, 1999
+ * - Fixed the output of 'Driver Installed' in /proc/mca/pos
+ * - Made the Integrated Video & SCSI show up even if they have id 0000
*/
#include <linux/types.h>
@@ -49,12 +52,12 @@
* Other miscellaneous information follows.
*/
-typedef enum {
- MCA_ADAPTER_NORMAL = 0,
- MCA_ADAPTER_NONE = 1,
- MCA_ADAPTER_DISABLED = 2,
- MCA_ADAPTER_ERROR = 3
-} MCA_AdapterStatus;
+typedef enum {
+ MCA_ADAPTER_NORMAL = 0,
+ MCA_ADAPTER_NONE = 1,
+ MCA_ADAPTER_DISABLED = 2,
+ MCA_ADAPTER_ERROR = 3
+} MCA_AdapterStatus;
struct MCA_adapter {
MCA_AdapterStatus status; /* is there a valid adapter? */
@@ -69,16 +72,17 @@ struct MCA_adapter {
};
struct MCA_info {
-/* one for each of the 8 possible slots, plus one for integrated SCSI
- and one for integrated video. */
+ /* one for each of the 8 possible slots, plus one for integrated SCSI
+ * and one for integrated video.
+ */
struct MCA_adapter slot[MCA_NUMADAPTERS];
-/* two potential addresses for integrated SCSI adapter - this will
- * track which one we think it is
- */
+ /* two potential addresses for integrated SCSI adapter - this will
+ * track which one we think it is.
+ */
- unsigned char which_scsi;
+ unsigned char which_scsi;
};
/* The mca_info structure pointer. If MCA bus is present, the function
@@ -88,7 +92,7 @@ struct MCA_info {
* is set to zero.
*/
-static struct MCA_info* mca_info = 0;
+static struct MCA_info* mca_info = NULL;
/* MCA registers */
@@ -102,10 +106,10 @@ static struct MCA_info* mca_info = 0;
#ifdef CONFIG_PROC_FS
-static void mca_do_proc_init( void );
-static int mca_default_procfn( char* buf, int slot );
+static void mca_do_proc_init(void);
+static int mca_default_procfn(char* buf, int slot);
-static ssize_t proc_mca_read( struct file*, char*, size_t, loff_t *);
+static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *);
static struct file_operations proc_mca_operations = {
NULL, /* array_lseek */
@@ -146,23 +150,26 @@ static struct inode_operations proc_mca_inode_operations = {
/* Build the status info for the adapter */
-static void mca_configure_adapter_status( int slot ) {
+static void mca_configure_adapter_status(int slot) {
mca_info->slot[slot].status = MCA_ADAPTER_NONE;
mca_info->slot[slot].id = mca_info->slot[slot].pos[0]
+ (mca_info->slot[slot].pos[1] << 8);
- if( !mca_info->slot[slot].id ) {
+ if(!mca_info->slot[slot].id && slot < MCA_MAX_SLOT_NR) {
/* id = 0x0000 usually indicates hardware failure,
* however, ZP Gu (zpg@castle.net> reports that his 9556
- * has 0x0000 as id and everything still works.
+ * has 0x0000 as id and everything still works. There
+ * also seem to be an adapter with id = 0x0000; the
+ * NCR Parallel Bus Memory Card. Until this is confirmed,
+ * however, this code will stay.
*/
mca_info->slot[slot].status = MCA_ADAPTER_ERROR;
return;
- } else if( mca_info->slot[slot].id != 0xffff ) {
+ } else if(mca_info->slot[slot].id != 0xffff) {
/* 0xffff usually indicates that there's no adapter,
* however, some integrated adapters may have 0xffff as
@@ -174,21 +181,21 @@ static void mca_configure_adapter_status( int slot ) {
mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
}
- if( (mca_info->slot[slot].id == 0xffff ||
- mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR ) {
+ if((mca_info->slot[slot].id == 0xffff ||
+ mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR) {
int j;
- for( j = 2; j < 8; j++ ) {
- if( mca_info->slot[slot].pos[j] != 0xff ) {
+ for(j = 2; j < 8; j++) {
+ if(mca_info->slot[slot].pos[j] != 0xff) {
mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
break;
}
}
}
- if( !(mca_info->slot[slot].pos[2] & MCA_ENABLED) ) {
+ if(!(mca_info->slot[slot].pos[2] & MCA_ENABLED)) {
- /* enabled bit is in pos 2 */
+ /* enabled bit is in POS 2 */
mca_info->slot[slot].status = MCA_ADAPTER_DISABLED;
}
@@ -198,94 +205,101 @@ static void mca_configure_adapter_status( int slot ) {
__initfunc(void mca_init(void))
{
- unsigned int i, j;
+ unsigned int i, j;
unsigned long flags;
/* WARNING: Be careful when making changes here. Putting an adapter
- * and the motherboard simultaneously into setup mode may result in
- * damage to chips (according to The Indispensible PC Hardware Book
- * by Hans-Peter Messmer). Also, we disable system interrupts (so
+ * and the motherboard simultaneously into setup mode may result in
+ * damage to chips (according to The Indispensible PC Hardware Book
+ * by Hans-Peter Messmer). Also, we disable system interrupts (so
* that we are not disturbed in the middle of this).
*/
/* Make sure the MCA bus is present */
- if (!MCA_bus)
+ if(!MCA_bus)
return;
- printk( "Micro Channel bus detected.\n" );
- save_flags( flags );
+ printk("Micro Channel bus detected.\n");
+ save_flags(flags);
cli();
/* Allocate MCA_info structure (at address divisible by 8) */
- mca_info = kmalloc(sizeof(struct MCA_info), GFP_ATOMIC);
+ mca_info = kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
+
+ if(mca_info == NULL) {
+ printk("Failed to allocate memory for mca_info!");
+ restore_flags(flags);
+ return;
+ }
/* Make sure adapter setup is off */
outb_p(0, MCA_ADAPTER_SETUP_REG);
/* Put motherboard into video setup mode, read integrated video
- * pos registers, and turn motherboard setup off.
+ * POS registers, and turn motherboard setup off.
*/
outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
mca_info->slot[MCA_INTEGVIDEO].name[0] = 0;
- for (j=0; j<8; j++) {
- mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j));
+ for(j=0; j<8; j++) {
+ mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j));
}
mca_configure_adapter_status(MCA_INTEGVIDEO);
/* Put motherboard into scsi setup mode, read integrated scsi
- * pos registers, and turn motherboard setup off.
+ * POS registers, and turn motherboard setup off.
*
- * It seems there are two possible SCSI registers. Martin says that
+ * It seems there are two possible SCSI registers. Martin says that
* for the 56,57, 0xf7 is the one, but fails on the 76.
* Alfredo (apena@vnet.ibm.com) says
- * 0xfd works on his machine. We'll try both of them. I figure it's
- * a good bet that only one could be valid at a time. This could
+ * 0xfd works on his machine. We'll try both of them. I figure it's
+ * a good bet that only one could be valid at a time. This could
* screw up though if one is used for something else on the other
* machine.
*/
outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG);
mca_info->slot[MCA_INTEGSCSI].name[0] = 0;
- for (j=0; j<8; j++) {
- if( (mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff )
+ for(j=0; j<8; j++) {
+ if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff)
{
- /* 0xff all across means no device. 0x00 means something's
- * broken, but a device is probably there. However, if you get
- * 0x00 from a motherboard register it won't matter what we
- * find. For the record, on the 57SLC, the integrated SCSI
- * adapter has 0xffff for the adapter ID, but nonzero for
- * other registers.
+ /* 0xff all across means no device. 0x00 means
+ * something's broken, but a device is probably there.
+ * However, if you get 0x00 from a motherboard
+ * register it won't matter what we find. For the
+ * record, on the 57SLC, the integrated SCSI
+ * adapter has 0xffff for the adapter ID, but
+ * nonzero for other registers.
*/
mca_info->which_scsi = 0xf7;
}
}
- if( !mca_info->which_scsi ) {
+ if(!mca_info->which_scsi) {
/* Didn't find it at 0xf7, try somewhere else... */
mca_info->which_scsi = 0xfd;
outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG);
- for (j=0; j<8; j++)
- mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j));
+ for(j=0; j<8; j++)
+ mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j));
}
mca_configure_adapter_status(MCA_INTEGSCSI);
- /* turn off motherboard setup */
+ /* Turn off motherboard setup */
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
/* Now loop over MCA slots: put each adapter into setup mode, and
- * read its pos registers. Then put adapter setup off.
+ * read its POS registers. Then put adapter setup off.
*/
- for (i=0; i<MCA_MAX_SLOT_NR; i++) {
+ for(i=0; i<MCA_MAX_SLOT_NR; i++) {
outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
- for (j=0; j<8; j++) {
- mca_info->slot[i].pos[j]=inb_p(MCA_POS_REG(j));
+ for(j=0; j<8; j++) {
+ mca_info->slot[i].pos[j]=inb_p(MCA_POS_REG(j));
}
mca_info->slot[i].name[0] = 0;
mca_info->slot[i].driver_loaded = 0;
@@ -295,7 +309,7 @@ __initfunc(void mca_init(void))
/* Enable interrupts and return memory start */
- restore_flags( flags );
+ restore_flags(flags);
request_region(0x60,0x01,"system control port B (MCA)");
request_region(0x90,0x01,"arbitration (MCA)");
@@ -312,89 +326,90 @@ __initfunc(void mca_init(void))
/*--------------------------------------------------------------------*/
-static void mca_handle_nmi_slot( int slot, int check_flag )
+static void mca_handle_nmi_slot(int slot, int check_flag)
{
- if( slot < MCA_MAX_SLOT_NR ) {
- printk( "NMI: caused by MCA adapter in slot %d (%s)\n", slot+1,
- mca_info->slot[slot].name );
- } else if( slot == MCA_INTEGSCSI ) {
- printk( "NMI: caused by MCA integrated SCSI adapter (%s)\n",
- mca_info->slot[slot].name );
- } else if( slot == MCA_INTEGVIDEO ) {
- printk( "NMI: caused by MCA integrated video adapter (%s)\n",
- mca_info->slot[slot].name );
- }
-
- /* more info available in pos 6 and 7? */
-
- if( check_flag ) {
- unsigned char pos6, pos7;
-
- pos6 = mca_read_pos( slot, 6 );
- pos7 = mca_read_pos( slot, 7 );
-
- printk( "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7 );
- }
-
-} /* mca_handle_nmi_slot */
-
-/*--------------------------------------------------------------------*/
-
-void mca_handle_nmi( void )
+ if(slot < MCA_MAX_SLOT_NR) {
+ printk("NMI: caused by MCA adapter in slot %d (%s)\n", slot+1,
+ mca_info->slot[slot].name);
+ } else if(slot == MCA_INTEGSCSI) {
+ printk("NMI: caused by MCA integrated SCSI adapter (%s)\n",
+ mca_info->slot[slot].name);
+ } else if(slot == MCA_INTEGVIDEO) {
+ printk("NMI: caused by MCA integrated video adapter (%s)\n",
+ mca_info->slot[slot].name);
+ }
+
+ /* More info available in POS 6 and 7? */
+
+ if(check_flag) {
+ unsigned char pos6, pos7;
+
+ pos6 = mca_read_pos(slot, 6);
+ pos7 = mca_read_pos(slot, 7);
+
+ printk("NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
+ }
+
+} /* mca_handle_nmi_slot */
+
+/*--------------------------------------------------------------------*/
+
+void mca_handle_nmi(void)
{
int i;
- unsigned char pos5;
-
- /* First try - scan the various adapters and see if a specific
- * adapter was responsible for the error
- */
-
- for( i = 0; i < MCA_NUMADAPTERS; i += 1 ) {
-
- /* bit 7 of POS 5 is reset when this adapter has a hardware
- * error. bit 7 it reset if there's error information
- * available in pos 6 and 7. */
-
- pos5 = mca_read_pos( i, 5 );
-
- if( !(pos5 & 0x80) ) {
- mca_handle_nmi_slot( i, !(pos5 & 0x40) );
- return;
- }
- }
-
- /* if I recall correctly, there's a whole bunch of other things that
- * we can do to check for NMI problems, but that's all I know about
+ unsigned char pos5;
+
+ /* First try - scan the various adapters and see if a specific
+ * adapter was responsible for the error.
+ */
+
+ for(i = 0; i < MCA_NUMADAPTERS; i++) {
+
+ /* Bit 7 of POS 5 is reset when this adapter has a hardware
+ * error. Bit 7 it reset if there's error information
+ * available in POS 6 and 7.
+ */
+
+ pos5 = mca_read_pos(i, 5);
+
+ if(!(pos5 & 0x80)) {
+ mca_handle_nmi_slot(i, !(pos5 & 0x40));
+ return;
+ }
+ }
+
+ /* If I recall correctly, there's a whole bunch of other things that
+ * we can do to check for NMI problems, but that's all I know about
* at the moment.
- */
+ */
- printk( "NMI generated from unknown source!\n" );
-} /* mca_handle_nmi */
+ printk("NMI generated from unknown source!\n");
+} /* mca_handle_nmi */
/*--------------------------------------------------------------------*/
-int mca_find_adapter( int id, int start )
+int mca_find_adapter(int id, int start)
{
- if( mca_info == 0 || id == 0 || id == 0xffff ) {
+ if(mca_info == NULL || id == 0xffff) {
return MCA_NOTFOUND;
}
- for( ; start >= 0 && start < MCA_NUMADAPTERS; start += 1 ) {
+ for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
- /* not sure about this. There's no point in returning
+ /* Not sure about this. There's no point in returning
* adapters that aren't enabled, since they can't actually
- * be used. However, they might be needed for statistical
+ * be used. However, they might be needed for statistical
* purposes or something... But if that is the case, the
* user is free to write a routine that manually iterates
* through the adapters.
*/
- if( mca_info->slot[start].status == MCA_ADAPTER_DISABLED ) {
+ if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED) {
continue;
}
- if( id == mca_info->slot[start].id ) {
+ if(id == mca_info->slot[start].id) {
return start;
}
}
@@ -404,28 +419,28 @@ int mca_find_adapter( int id, int start )
/*--------------------------------------------------------------------*/
-int mca_find_unused_adapter( int id, int start )
+int mca_find_unused_adapter(int id, int start)
{
- if( mca_info == 0 || id == 0 || id == 0xffff ) {
+ if(mca_info == NULL || id == 0xffff) {
return MCA_NOTFOUND;
}
- for( ; start >= 0 && start < MCA_NUMADAPTERS; start += 1 ) {
+ for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
- /* not sure about this. There's no point in returning
+ /* not sure about this. There's no point in returning
* adapters that aren't enabled, since they can't actually
- * be used. However, they might be needed for statistical
+ * be used. However, they might be needed for statistical
* purposes or something... But if that is the case, the
* user is free to write a routine that manually iterates
* through the adapters.
*/
- if( mca_info->slot[start].status == MCA_ADAPTER_DISABLED ||
- mca_info->slot[start].driver_loaded ) {
+ if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED ||
+ mca_info->slot[start].driver_loaded) {
continue;
}
- if( id == mca_info->slot[start].id ) {
+ if(id == mca_info->slot[start].id) {
return start;
}
}
@@ -435,68 +450,68 @@ int mca_find_unused_adapter( int id, int start )
/*--------------------------------------------------------------------*/
-unsigned char mca_read_stored_pos( int slot, int reg )
+unsigned char mca_read_stored_pos(int slot, int reg)
{
- if( slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0 ) return 0;
- if( reg < 0 || reg >= 8 ) return 0;
+ if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
+ if(reg < 0 || reg >= 8) return 0;
return mca_info->slot[slot].pos[reg];
} /* mca_read_stored_pos() */
/*--------------------------------------------------------------------*/
-unsigned char mca_read_pos( int slot, int reg )
+unsigned char mca_read_pos(int slot, int reg)
{
unsigned int byte = 0;
unsigned long flags;
- if( slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == 0 ) return 0;
- if( reg < 0 || reg >= 8 ) return 0;
+ if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
+ if(reg < 0 || reg >= 8) return 0;
- save_flags( flags );
+ save_flags(flags);
cli();
- /* make sure motherboard setup is off */
+ /* Make sure motherboard setup is off */
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
- /* read in the appropriate register */
+ /* Read in the appropriate register */
- if( slot == MCA_INTEGSCSI && mca_info->which_scsi ) {
+ if(slot == MCA_INTEGSCSI && mca_info->which_scsi) {
- /* disable adapter setup, enable motherboard setup */
+ /* Disable adapter setup, enable motherboard setup */
outb_p(0, MCA_ADAPTER_SETUP_REG);
outb_p(mca_info->which_scsi, MCA_MOTHERBOARD_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
- } else if( slot == MCA_INTEGVIDEO ) {
+ } else if(slot == MCA_INTEGVIDEO) {
- /* disable adapter setup, enable motherboard setup */
+ /* Disable adapter setup, enable motherboard setup */
outb_p(0, MCA_ADAPTER_SETUP_REG);
outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
- } else if( slot < MCA_MAX_SLOT_NR ) {
+ } else if(slot < MCA_MAX_SLOT_NR) {
- /* make sure motherboard setup is off */
+ /* Make sure motherboard setup is off */
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
- /* read the appropriate register */
+ /* Read the appropriate register */
outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
byte = inb_p(MCA_POS_REG(reg));
outb_p(0, MCA_ADAPTER_SETUP_REG);
}
- /* make sure the stored values are consistent, while we're here */
+ /* Make sure the stored values are consistent, while we're here */
mca_info->slot[slot].pos[reg] = byte;
- restore_flags( flags );
+ restore_flags(flags);
return byte;
} /* mca_read_pos() */
@@ -513,44 +528,47 @@ unsigned char mca_read_pos( int slot, int reg )
* screws up.
*/
-void mca_write_pos( int slot, int reg, unsigned char byte )
+void mca_write_pos(int slot, int reg, unsigned char byte)
{
unsigned long flags;
- if( slot < 0 || slot >= MCA_MAX_SLOT_NR ) return;
- if( reg < 0 || reg >= 8 ) return;
- if (mca_info == 0 ) return;
+ if(slot < 0 || slot >= MCA_MAX_SLOT_NR)
+ return;
+ if(reg < 0 || reg >= 8)
+ return;
+ if(mca_info == NULL)
+ return;
- save_flags( flags );
+ save_flags(flags);
cli();
- /* make sure motherboard setup is off */
+ /* Make sure motherboard setup is off */
outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
- /* read in the appropriate register */
+ /* Read in the appropriate register */
outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
- outb_p( byte, MCA_POS_REG(reg) );
+ outb_p(byte, MCA_POS_REG(reg));
outb_p(0, MCA_ADAPTER_SETUP_REG);
- restore_flags( flags );
+ restore_flags(flags);
- /* update the global register list, while we have the byte */
+ /* Update the global register list, while we have the byte */
mca_info->slot[slot].pos[reg] = byte;
} /* mca_write_pos() */
/*--------------------------------------------------------------------*/
-void mca_set_adapter_name( int slot, char* name )
+void mca_set_adapter_name(int slot, char* name)
{
- if( mca_info == 0 ) return;
+ if(mca_info == NULL) return;
- if( slot >= 0 && slot < MCA_NUMADAPTERS ) {
- if( name != NULL ) {
- strncpy( mca_info->slot[slot].name, name,
- sizeof(mca_info->slot[slot].name)-1 );
+ if(slot >= 0 && slot < MCA_NUMADAPTERS) {
+ if(name != NULL) {
+ strncpy(mca_info->slot[slot].name, name,
+ sizeof(mca_info->slot[slot].name)-1);
mca_info->slot[slot].name[
sizeof(mca_info->slot[slot].name)-1] = 0;
} else {
@@ -559,61 +577,61 @@ void mca_set_adapter_name( int slot, char* name )
}
}
-void mca_set_adapter_procfn( int slot, MCA_ProcFn procfn, void* dev)
+void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev)
{
- if( mca_info == 0 ) return;
+ if(mca_info == NULL) return;
- if( slot >= 0 && slot < MCA_NUMADAPTERS ) {
+ if(slot >= 0 && slot < MCA_NUMADAPTERS) {
mca_info->slot[slot].procfn = procfn;
mca_info->slot[slot].dev = dev;
}
}
-int mca_is_adapter_used( int slot )
+int mca_is_adapter_used(int slot)
{
return mca_info->slot[slot].driver_loaded;
}
-int mca_mark_as_used( int slot )
+int mca_mark_as_used(int slot)
{
if(mca_info->slot[slot].driver_loaded) return 1;
mca_info->slot[slot].driver_loaded = 1;
return 0;
}
-void mca_mark_as_unused( int slot )
+void mca_mark_as_unused(int slot)
{
mca_info->slot[slot].driver_loaded = 0;
}
-char *mca_get_adapter_name( int slot )
+char *mca_get_adapter_name(int slot)
{
- if( mca_info == 0 ) return 0;
+ if(mca_info == NULL) return 0;
- if( slot >= 0 && slot < MCA_NUMADAPTERS ) {
+ if(slot >= 0 && slot < MCA_NUMADAPTERS) {
return mca_info->slot[slot].name;
}
return 0;
}
-int mca_isadapter( int slot )
+int mca_isadapter(int slot)
{
- if( mca_info == 0 ) return 0;
+ if(mca_info == NULL) return 0;
- if( slot >= 0 && slot < MCA_NUMADAPTERS ) {
- return (( mca_info->slot[slot].status == MCA_ADAPTER_NORMAL )
- || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED ) );
+ if(slot >= 0 && slot < MCA_NUMADAPTERS) {
+ return ((mca_info->slot[slot].status == MCA_ADAPTER_NORMAL)
+ || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED));
}
return 0;
}
-int mca_isenabled( int slot )
+int mca_isenabled(int slot)
{
- if( mca_info == 0 ) return 0;
+ if(mca_info == NULL) return 0;
- if( slot >= 0 && slot < MCA_NUMADAPTERS ) {
+ if(slot >= 0 && slot < MCA_NUMADAPTERS) {
return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL);
}
@@ -624,39 +642,37 @@ int mca_isenabled( int slot )
#ifdef CONFIG_PROC_FS
-int get_mca_info(char *buf)
+int get_mca_info(char *buf)
{
- int i, j, len = 0;
+ int i, j, len = 0;
- if( MCA_bus && mca_info != 0 )
+ if(MCA_bus && mca_info != NULL)
{
- /* Format pos registers of eight MCA slots */
+ /* Format POS registers of eight MCA slots */
- for (i=0; i<MCA_MAX_SLOT_NR; i++)
+ for(i=0; i<MCA_MAX_SLOT_NR; i++)
{
len += sprintf(buf+len, "Slot %d: ", i+1);
- for (j=0; j<8; j++)
+ for(j=0; j<8; j++)
len += sprintf(buf+len, "%02x ", mca_info->slot[i].pos[j]);
- len += sprintf( buf+len, " %s\n", mca_info->slot[i].name );
- }
+ len += sprintf(buf+len, " %s\n", mca_info->slot[i].name);
+ }
- /* Format pos registers of integrated video subsystem */
+ /* Format POS registers of integrated video subsystem */
len += sprintf(buf+len, "Video : ");
- for (j=0; j<8; j++)
+ for(j=0; j<8; j++)
len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]);
- len += sprintf( buf+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name );
+ len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name);
- /* Format pos registers of integrated SCSI subsystem */
+ /* Format POS registers of integrated SCSI subsystem */
len += sprintf(buf+len, "SCSI : ");
- for (j=0; j<8; j++)
+ for(j=0; j<8; j++)
len += sprintf(buf+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]);
- len += sprintf( buf+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name );
- }
- else
- {
- /* Leave it empty if MCA not detected - this should *never*
+ len += sprintf(buf+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name);
+ } else {
+ /* Leave it empty if MCA not detected - this should *never*
* happen!
*/
}
@@ -667,119 +683,123 @@ int get_mca_info(char *buf)
/*--------------------------------------------------------------------*/
-__initfunc(void mca_do_proc_init( void ))
+__initfunc(void mca_do_proc_init(void))
{
- int i = 0;
- struct proc_dir_entry* node = 0;
+ int i;
+ struct proc_dir_entry* node = NULL;
- if( mca_info == 0 ) return; /* should never happen */
+ if(mca_info == NULL) return; /* Should never happen */
- proc_register( &proc_mca, &(struct proc_dir_entry) {
+ proc_register(&proc_mca, &(struct proc_dir_entry) {
PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO,
- 1, 0, 0, 0, &proc_mca_inode_operations,} );
+ 1, 0, 0, 0, &proc_mca_inode_operations,});
- proc_register( &proc_mca, &(struct proc_dir_entry) {
+ proc_register(&proc_mca, &(struct proc_dir_entry) {
PROC_MCA_MACHINE, 7, "machine", S_IFREG|S_IRUGO,
- 1, 0, 0, 0, &proc_mca_inode_operations,} );
+ 1, 0, 0, 0, &proc_mca_inode_operations,});
- /* initialize /proc/mca entries for existing adapters */
+ /* Initialize /proc/mca entries for existing adapters */
- for( i = 0; i < MCA_NUMADAPTERS; i += 1 ) {
+ for(i = 0; i < MCA_NUMADAPTERS; i++) {
mca_info->slot[i].procfn = 0;
mca_info->slot[i].dev = 0;
- if( ! mca_isadapter( i ) ) continue;
- node = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
+ if(!mca_isadapter(i)) continue;
+ node = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
- if( i < MCA_MAX_SLOT_NR ) {
+ if(node == NULL) {
+ printk("Failed to allocate memory for MCA proc-entries!");
+ return;
+ }
+ if(i < MCA_MAX_SLOT_NR) {
node->low_ino = PROC_MCA_SLOT + i;
- node->namelen = sprintf( mca_info->slot[i].procname,
- "slot%d", i+1 );
- } else if( i == MCA_INTEGVIDEO ) {
+ node->namelen = sprintf(mca_info->slot[i].procname,
+ "slot%d", i+1);
+ } else if(i == MCA_INTEGVIDEO) {
node->low_ino = PROC_MCA_VIDEO;
- node->namelen = sprintf( mca_info->slot[i].procname,
- "video" );
- } else if( i == MCA_INTEGSCSI ) {
+ node->namelen = sprintf(mca_info->slot[i].procname,
+ "video");
+ } else if(i == MCA_INTEGSCSI) {
node->low_ino = PROC_MCA_SCSI;
- node->namelen = sprintf( mca_info->slot[i].procname,
- "scsi" );
+ node->namelen = sprintf(mca_info->slot[i].procname,
+ "scsi");
}
node->name = mca_info->slot[i].procname;
node->mode = S_IFREG | S_IRUGO;
node->ops = &proc_mca_inode_operations;
- proc_register( &proc_mca, node );
+ proc_register(&proc_mca, node);
}
} /* mca_do_proc_init() */
/*--------------------------------------------------------------------*/
-int mca_default_procfn( char* buf, int slot )
+int mca_default_procfn(char* buf, int slot)
{
int len = 0, i;
- /* this really shouldn't happen... */
+ /* This really shouldn't happen... */
- if( mca_info == 0 ) {
+ if(mca_info == NULL) {
*buf = 0;
return 0;
}
- /* print out the basic information */
+ /* Print out the basic information */
- if( slot < MCA_MAX_SLOT_NR ) {
- len += sprintf( buf+len, "Slot: %d\n", slot+1 );
- } else if( slot == MCA_INTEGSCSI ) {
- len += sprintf( buf+len, "Integrated SCSI Adapter\n" );
- } else if( slot == MCA_INTEGVIDEO ) {
- len += sprintf( buf+len, "Integrated Video Adapter\n" );
+ if(slot < MCA_MAX_SLOT_NR) {
+ len += sprintf(buf+len, "Slot: %d\n", slot+1);
+ } else if(slot == MCA_INTEGSCSI) {
+ len += sprintf(buf+len, "Integrated SCSI Adapter\n");
+ } else if(slot == MCA_INTEGVIDEO) {
+ len += sprintf(buf+len, "Integrated Video Adapter\n");
}
- if( mca_info->slot[slot].name[0] ) {
+ if(mca_info->slot[slot].name[0]) {
- /* drivers might register a name without /proc handler... */
+ /* Drivers might register a name without /proc handler... */
- len += sprintf( buf+len, "Adapter Name: %s\n",
- mca_info->slot[slot].name );
+ len += sprintf(buf+len, "Adapter Name: %s\n",
+ mca_info->slot[slot].name);
} else {
- len += sprintf( buf+len, "Adapter Name: Unknown\n" );
+ len += sprintf(buf+len, "Adapter Name: Unknown\n");
}
- len += sprintf( buf+len, "Id: %02x%02x\n",
- mca_info->slot[slot].pos[1], mca_info->slot[slot].pos[0] );
- len += sprintf( buf+len, "Enabled: %s\nPOS: ",
- mca_isenabled(slot) ? "Yes" : "No" );
- len += sprintf( buf+len, "Driver Installed: %s\n",
- mca_is_adapter_used(slot) ? "Yes" : "No" );
- for (i=0; i<8; i++) {
+ len += sprintf(buf+len, "Id: %02x%02x\n",
+ mca_info->slot[slot].pos[1], mca_info->slot[slot].pos[0]);
+ len += sprintf(buf+len, "Enabled: %s\nPOS: ",
+ mca_isenabled(slot) ? "Yes" : "No");
+ for(i=0; i<8; i++) {
len += sprintf(buf+len, "%02x ", mca_info->slot[slot].pos[i]);
}
+ len += sprintf(buf+len, "\nDriver Installed: %s",
+ mca_is_adapter_used(slot) ? "Yes" : "No");
buf[len++] = '\n';
buf[len] = 0;
return len;
} /* mca_default_procfn() */
-static int get_mca_machine_info( char* buf )
+static int get_mca_machine_info(char* buf)
{
int len = 0;
- len += sprintf( buf+len, "Model Id: 0x%x\n", machine_id );
- len += sprintf( buf+len, "Submodel Id: 0x%x\n", machine_submodel_id );
- len += sprintf( buf+len, "BIOS Revision: 0x%x\n", BIOS_revision );
+ len += sprintf(buf+len, "Model Id: 0x%x\n", machine_id);
+ len += sprintf(buf+len, "Submodel Id: 0x%x\n", machine_submodel_id);
+ len += sprintf(buf+len, "BIOS Revision: 0x%x\n", BIOS_revision);
return len;
}
-static int mca_fill( char* page, int pid, int type, char** start,
+static int mca_fill(char* page, int pid, int type, char** start,
loff_t *offset, int length)
{
int len = 0;
int slot = 0;
- switch( type ) {
+ switch(type) {
case PROC_MCA_REGISTERS:
- return get_mca_info( page );
+ return get_mca_info(page);
case PROC_MCA_MACHINE:
- return get_mca_machine_info( page );
+ return get_mca_machine_info(page);
case PROC_MCA_VIDEO:
slot = MCA_INTEGVIDEO;
break;
@@ -787,24 +807,24 @@ static int mca_fill( char* page, int pid, int type, char** start,
slot = MCA_INTEGSCSI;
break;
default:
- if( type < PROC_MCA_SLOT || type >= PROC_MCA_LAST ) {
+ if(type < PROC_MCA_SLOT || type >= PROC_MCA_LAST) {
return -EBADF;
}
slot = type - PROC_MCA_SLOT;
break;
}
- /* if we made it here, we better have a valid slot */
+ /* If we made it here, we better have a valid slot */
- /* get the standard info */
+ /* Get the standard info */
- len = mca_default_procfn( page, slot );
+ len = mca_default_procfn(page, slot);
- /* do any device-specific processing, if there is any */
+ /* Do any device-specific processing, if there is any */
- if( mca_info->slot[slot].procfn ) {
- len += mca_info->slot[slot].procfn( page+len, slot,
- mca_info->slot[slot].dev );
+ if(mca_info->slot[slot].procfn) {
+ len += mca_info->slot[slot].procfn(page+len, slot,
+ mca_info->slot[slot].dev);
}
return len;
@@ -814,7 +834,7 @@ static int mca_fill( char* page, int pid, int type, char** start,
#define PROC_BLOCK_SIZE (3*1024)
-static ssize_t proc_mca_read( struct file* file,
+static ssize_t proc_mca_read(struct file* file,
char* buf, size_t count, loff_t *ppos)
{
unsigned long page;
@@ -825,11 +845,11 @@ static ssize_t proc_mca_read( struct file* file,
struct proc_dir_entry *dp;
struct inode *inode = file->f_dentry->d_inode;
- if (count < 0)
+ if(count < 0)
return -EINVAL;
- if (count > PROC_BLOCK_SIZE)
+ if(count > PROC_BLOCK_SIZE)
count = PROC_BLOCK_SIZE;
- if (!(page = __get_free_page(GFP_KERNEL)))
+ if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
type = inode->i_ino;
pid = type >> 16;
@@ -837,12 +857,12 @@ static ssize_t proc_mca_read( struct file* file,
start = 0;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
length = mca_fill((char *) page, pid, type,
- &start, ppos, count);
- if (length < 0) {
+ &start, ppos, count);
+ if(length < 0) {
free_page(page);
return length;
}
- if (start != 0) {
+ if(start != 0) {
/* We have had block-adjusting processing! */
copy_to_user(buf, start, length);
@@ -851,11 +871,11 @@ static ssize_t proc_mca_read( struct file* file,
} else {
/* Static 4kB (or whatever) block capacity */
- if (*ppos >= length) {
+ if(*ppos >= length) {
free_page(page);
return 0;
}
- if (count + *ppos > length)
+ if(count + *ppos > length)
count = length - *ppos;
end = count + *ppos;
copy_to_user(buf, (char *) page + *ppos, count);
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 16c767b4a..0d71d8bb5 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -132,6 +132,70 @@
Fixed harmless compiler warning in include/asm-i386/mtrr.h
Fixed version numbering and history for v1.23 -> v1.24.
v1.26
+ 19990118 Richard Gooch <rgooch@atnf.csiro.au>
+ PLACEHOLDER.
+ v1.27
+ 19990123 Richard Gooch <rgooch@atnf.csiro.au>
+ Changed locking to spin with reschedule.
+ Made use of new <smp_call_function>.
+ v1.28
+ 19990201 Zoltan Boszormenyi <zboszor@mol.hu>
+ Extended the driver to be able to use Cyrix style ARRs.
+ 19990204 Richard Gooch <rgooch@atnf.csiro.au>
+ Restructured Cyrix support.
+ v1.29
+ 19990204 Zoltan Boszormenyi <zboszor@mol.hu>
+ Refined ARR support: enable MAPEN in set_mtrr_prepare()
+ and disable MAPEN in set_mtrr_done().
+ 19990205 Richard Gooch <rgooch@atnf.csiro.au>
+ Minor cleanups.
+ v1.30
+ 19990208 Zoltan Boszormenyi <zboszor@mol.hu>
+ Protect plain 6x86s (and other processors without the
+ Page Global Enable feature) against accessing CR4 in
+ set_mtrr_prepare() and set_mtrr_done().
+ 19990210 Richard Gooch <rgooch@atnf.csiro.au>
+ Turned <set_mtrr_up> and <get_mtrr> into function pointers.
+ v1.31
+ 19990212 Zoltan Boszormenyi <zboszor@mol.hu>
+ Major rewrite of cyrix_arr_init(): do not touch ARRs,
+ leave them as the BIOS have set them up.
+ Enable usage of all 8 ARRs.
+ Avoid multiplications by 3 everywhere and other
+ code clean ups/speed ups.
+ 19990213 Zoltan Boszormenyi <zboszor@mol.hu>
+ Set up other Cyrix processors identical to the boot cpu.
+ Since Cyrix don't support Intel APIC, this is l'art pour l'art.
+ Weigh ARRs by size:
+ If size <= 32M is given, set up ARR# we were given.
+ If size > 32M is given, set up ARR7 only if it is free,
+ fail otherwise.
+ 19990214 Zoltan Boszormenyi <zboszor@mol.hu>
+ Also check for size >= 256K if we are to set up ARR7,
+ mtrr_add() returns the value it gets from set_mtrr()
+ 19990218 Zoltan Boszormenyi <zboszor@mol.hu>
+ Remove Cyrix "coma bug" workaround from here.
+ Moved to linux/arch/i386/kernel/setup.c and
+ linux/include/asm-i386/bugs.h
+ 19990228 Richard Gooch <rgooch@atnf.csiro.au>
+ Added #ifdef CONFIG_DEVFS_FS
+ Added MTRRIOC_KILL_ENTRY ioctl(2)
+ Trap for counter underflow in <mtrr_file_del>.
+ Trap for 4 MiB aligned regions for PPro, stepping <= 7.
+ 19990301 Richard Gooch <rgooch@atnf.csiro.au>
+ Created <get_free_region> hook.
+ 19990305 Richard Gooch <rgooch@atnf.csiro.au>
+ Temporarily disable AMD support now MTRR capability flag is set.
+ v1.32
+ 19990308 Zoltan Boszormenyi <zboszor@mol.hu>
+ Adjust my changes (19990212-19990218) to Richard Gooch's
+ latest changes. (19990228-19990305)
+ v1.33
+ 19990309 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed typo in <printk> message.
+ 19990310 Richard Gooch <rgooch@atnf.csiro.au>
+ Support K6-II/III based on Alan Cox's <alan@redhat.com> patches.
+ v1.34
*/
#include <linux/types.h>
#include <linux/errno.h>
@@ -163,11 +227,12 @@
#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/atomic.h>
+#include <asm/msr.h>
#include <asm/hardirq.h>
#include "irq.h"
-#define MTRR_VERSION "1.26 (19981001)"
+#define MTRR_VERSION "1.34 (19990310)"
#define TRUE 1
#define FALSE 0
@@ -197,7 +262,7 @@
# define MTRR_CHANGE_MASK_DEFTYPE 0x04
#endif
-/* In the processor's MTRR interface, the MTRR type is always held in
+/* In the Intel processor's MTRR interface, the MTRR type is always held in
an 8 bit field: */
typedef u8 mtrr_type;
@@ -207,9 +272,12 @@ typedef u8 mtrr_type;
#ifdef __SMP__
# define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
#else
-# define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type,TRUE)
+# define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \
+ TRUE)
#endif
+#define spin_lock_reschedule(lock) while (!spin_trylock(lock)) schedule ();
+
#ifndef CONFIG_PROC_FS
# define compute_ascii() while (0)
#endif
@@ -233,49 +301,30 @@ struct set_mtrr_context
unsigned long deftype_lo;
unsigned long deftype_hi;
unsigned long cr4val;
+ unsigned long ccr3;
};
-/*
- * Access to machine-specific registers (available on 586 and better only)
- * Note: the rd* operations modify the parameters directly (without using
- * pointer indirection), this allows gcc to optimize better
- */
-#define rdmsr(msr,val1,val2) \
- __asm__ __volatile__("rdmsr" \
- : "=a" (val1), "=d" (val2) \
- : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
- __asm__ __volatile__("wrmsr" \
- : /* no outputs */ \
- : "c" (msr), "a" (val1), "d" (val2))
-#define rdtsc(low,high) \
- __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdpmc(counter,low,high) \
- __asm__ __volatile__("rdpmc" \
- : "=a" (low), "=d" (high) \
- : "c" (counter))
-
-
-/* Put the processor into a state where MTRRs can be safely set. */
-static void set_mtrr_prepare(struct set_mtrr_context *ctxt)
+/* Put the processor into a state where MTRRs can be safely set */
+static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
{
unsigned long tmp;
- /* disable interrupts locally */
+ /* Disable interrupts locally */
__save_flags (ctxt->flags); __cli ();
- /* save value of CR4 and clear Page Global Enable (bit 7) */
- asm volatile ("movl %%cr4, %0\n\t"
- "movl %0, %1\n\t"
- "andb $0x7f, %b1\n\t"
- "movl %1, %%cr4\n\t"
- : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return;
+
+ /* Save value of CR4 and clear Page Global Enable (bit 7) */
+ if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+ asm volatile ("movl %%cr4, %0\n\t"
+ "movl %0, %1\n\t"
+ "andb $0x7f, %b1\n\t"
+ "movl %1, %%cr4\n\t"
+ : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
- /* disable and flush caches. Note that wbinvd flushes the TLBs as
- a side-effect. */
+ /* Disable and flush caches. Note that wbinvd flushes the TLBs as
+ a side-effect */
asm volatile ("movl %%cr0, %0\n\t"
"orl $0x40000000, %0\n\t"
"wbinvd\n\t"
@@ -283,64 +332,108 @@ static void set_mtrr_prepare(struct set_mtrr_context *ctxt)
"wbinvd\n\t"
: "=r" (tmp) : : "memory");
- /* disable MTRRs, and set the default type to uncached. */
- rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
- wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ /* Disable MTRRs, and set the default type to uncached */
+ rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+ wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+ break;
+ case X86_VENDOR_CYRIX:
+ tmp = getCx86 (CX86_CCR3);
+ setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
+ ctxt->ccr3 = tmp;
+ break;
+ }
} /* End Function set_mtrr_prepare */
-
-/* Restore the processor after a set_mtrr_prepare */
-static void set_mtrr_done(struct set_mtrr_context *ctxt)
+/* Restore the processor after a set_mtrr_prepare */
+static void set_mtrr_done (struct set_mtrr_context *ctxt)
{
unsigned long tmp;
- /* flush caches and TLBs */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+ {
+ __restore_flags (ctxt->flags);
+ return;
+ }
+
+ /* Flush caches and TLBs */
asm volatile ("wbinvd" : : : "memory" );
- /* restore MTRRdefType */
- wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+ /* Restore MTRRdefType */
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+ break;
+ case X86_VENDOR_CYRIX:
+ setCx86 (CX86_CCR3, ctxt->ccr3);
+ break;
+ }
- /* enable caches */
+ /* Enable caches */
asm volatile ("movl %%cr0, %0\n\t"
"andl $0xbfffffff, %0\n\t"
"movl %0, %%cr0\n\t"
: "=r" (tmp) : : "memory");
- /* restore value of CR4 */
- asm volatile ("movl %0, %%cr4"
- : : "r" (ctxt->cr4val) : "memory");
+ /* Restore value of CR4 */
+ if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+ asm volatile ("movl %0, %%cr4"
+ : : "r" (ctxt->cr4val) : "memory");
- /* re-enable interrupts locally (if enabled previously) */
+ /* Re-enable interrupts locally (if enabled previously) */
__restore_flags (ctxt->flags);
} /* End Function set_mtrr_done */
-
-/* this function returns the number of variable MTRRs */
+/* This function returns the number of variable MTRRs */
static unsigned int get_num_var_ranges (void)
{
unsigned long config, dummy;
- rdmsr(MTRRcap_MSR, config, dummy);
- return (config & 0xff);
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ rdmsr (MTRRcap_MSR, config, dummy);
+ return (config & 0xff);
+ /*break;*/
+ case X86_VENDOR_CYRIX:
+ /* Cyrix have 8 ARRs */
+ return 8;
+ /*break;*/
+ case X86_VENDOR_AMD:
+ return 2;
+ /*break;*/
+ }
+ return 0;
} /* End Function get_num_var_ranges */
-
-/* non-zero if we have the write-combining memory type. */
+/* Returns non-zero if we have the write-combining memory type */
static int have_wrcomb (void)
{
unsigned long config, dummy;
- rdmsr(MTRRcap_MSR, config, dummy);
- return (config & (1<<10));
-}
-
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ rdmsr (MTRRcap_MSR, config, dummy);
+ return (config & (1<<10));
+ /*break;*/
+ case X86_VENDOR_CYRIX:
+ case X86_VENDOR_AMD:
+ return 1;
+ /*break;*/
+ }
+ return 0;
+} /* End Function have_wrcomb */
-static void get_mtrr (unsigned int reg, unsigned long *base,
- unsigned long *size, mtrr_type *type)
+static void intel_get_mtrr (unsigned int reg, unsigned long *base,
+ unsigned long *size, mtrr_type *type)
{
unsigned long dummy, mask_lo, base_lo;
- rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy);
+ rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
if ((mask_lo & 0x800) == 0) {
/* Invalid (i.e. free) range. */
*base = 0;
@@ -364,11 +457,104 @@ static void get_mtrr (unsigned int reg, unsigned long *base,
*base = (base_lo & 0xfffff000UL);
*type = (base_lo & 0xff);
-} /* End Function get_mtrr */
+} /* End Function intel_get_mtrr */
+
+static void cyrix_get_arr (unsigned int reg, unsigned long *base,
+ unsigned long *size, mtrr_type *type)
+{
+ unsigned long flags;
+ unsigned char arr, ccr3, rcr, shift;
+
+ arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
+
+ /* Save flags and disable interrupts */
+ __save_flags (flags); __cli ();
+ ccr3 = getCx86 (CX86_CCR3);
+ setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
+ ((unsigned char *) base)[3] = getCx86 (arr);
+ ((unsigned char *) base)[2] = getCx86 (arr+1);
+ ((unsigned char *) base)[1] = getCx86 (arr+2);
+ rcr = getCx86(CX86_RCR_BASE + reg);
+ setCx86 (CX86_CCR3, ccr3); /* disable MAPEN */
+
+ /* Enable interrupts if it was enabled previously */
+ __restore_flags (flags);
+
+ shift = ((unsigned char *) base)[1] & 0x0f;
+ *base &= 0xfffff000UL;
+
+ /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+ * Note: shift==0xf means 4G, this is unsupported.
+ */
+ if (shift)
+ *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+ else
+ *size = 0;
+
+ /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
+ if (reg < 7) {
+ switch (rcr) {
+ case 1: *type = MTRR_TYPE_UNCACHABLE; break;
+ case 8: *type = MTRR_TYPE_WRBACK; break;
+ case 9: *type = MTRR_TYPE_WRCOMB; break;
+ case 24:
+ default: *type = MTRR_TYPE_WRTHROUGH; break;
+ }
+ } else {
+ switch (rcr) {
+ case 0: *type = MTRR_TYPE_UNCACHABLE; break;
+ case 8: *type = MTRR_TYPE_WRCOMB; break;
+ case 9: *type = MTRR_TYPE_WRBACK; break;
+ case 25:
+ default: *type = MTRR_TYPE_WRTHROUGH; break;
+ }
+ }
+} /* End Function cyrix_get_arr */
-static void set_mtrr_up (unsigned int reg, unsigned long base,
- unsigned long size, mtrr_type type, int do_safe)
+static void amd_get_mtrr (unsigned int reg, unsigned long *base,
+ unsigned long *size, mtrr_type *type)
+{
+ unsigned long low, high;
+
+ rdmsr (0xC0000085, low, high);
+ /* Upper dword is region 1, lower is region 0 */
+ if (reg == 1) low = high;
+ /* The base masks off on the right alignment */
+ *base = low & 0xFFFE0000;
+ *type = 0;
+ if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
+ if (low & 2) *type = MTRR_TYPE_WRCOMB;
+ if ( !(low & 3) )
+ {
+ *size = 0;
+ return;
+ }
+ /*
+ * This needs a little explaining. The size is stored as an
+ * inverted mask of bits of 128K granularity 15 bits long offset
+ * 2 bits
+ *
+ * So to get a size we do invert the mask and add 1 to the lowest
+ * mask bit (4 as its 2 bits in). This gives us a size we then shift
+ * to turn into 128K blocks
+ *
+ * eg 111 1111 1111 1100 is 512K
+ *
+ * invert 000 0000 0000 0011
+ * +1 000 0000 0000 0100
+ * *128K ...
+ */
+ low = (~low) & 0x1FFFC;
+ *size = (low + 4) << 15;
+ return;
+} /* End Function amd_get_mtrr */
+
+static void (*get_mtrr) (unsigned int reg, unsigned long *base,
+ unsigned long *size, mtrr_type *type) = NULL;
+
+static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
+ unsigned long size, mtrr_type type, int do_safe)
/* [SUMMARY] Set variable MTRR register on the local CPU.
<reg> The register to set.
<base> The base address of the region.
@@ -376,6 +562,7 @@ static void set_mtrr_up (unsigned int reg, unsigned long base,
<type> The type of the region.
<do_safe> If TRUE, do the change safely. If FALSE, safety measures should
be done externally.
+ [RETURNS] Nothing.
*/
{
struct set_mtrr_context ctxt;
@@ -393,8 +580,92 @@ static void set_mtrr_up (unsigned int reg, unsigned long base,
wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
}
if (do_safe) set_mtrr_done (&ctxt);
-} /* End Function set_mtrr_up */
+} /* End Function intel_set_mtrr_up */
+
+static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
+ unsigned long size, mtrr_type type, int do_safe)
+{
+ struct set_mtrr_context ctxt;
+ unsigned char arr, arr_type, arr_size;
+
+ arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
+
+ /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
+ size >>= (reg < 7 ? 12 : 18);
+ size &= 0x7fff; /* make sure arr_size <= 14 */
+ for(arr_size = 0; size; arr_size++, size >>= 1);
+
+ if (reg<7) {
+ switch (type) {
+ case MTRR_TYPE_UNCACHABLE: arr_type = 1; break;
+ case MTRR_TYPE_WRCOMB: arr_type = 9; break;
+ case MTRR_TYPE_WRTHROUGH: arr_type = 24; break;
+ default: arr_type = 8; break;
+ }
+ } else {
+ switch (type) {
+ case MTRR_TYPE_UNCACHABLE: arr_type = 0; break;
+ case MTRR_TYPE_WRCOMB: arr_type = 8; break;
+ case MTRR_TYPE_WRTHROUGH: arr_type = 25; break;
+ default: arr_type = 9; break;
+ }
+ }
+
+ if (do_safe) set_mtrr_prepare (&ctxt);
+ setCx86(arr, ((unsigned char *) &base)[3]);
+ setCx86(arr+1, ((unsigned char *) &base)[2]);
+ setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
+ setCx86(CX86_RCR_BASE + reg, arr_type);
+ if (do_safe) set_mtrr_done (&ctxt);
+} /* End Function cyrix_set_arr_up */
+
+static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
+ unsigned long size, mtrr_type type, int do_safe)
+/* [SUMMARY] Set variable MTRR register on the local CPU.
+ <reg> The register to set.
+ <base> The base address of the region.
+ <size> The size of the region. If this is 0 the region is disabled.
+ <type> The type of the region.
+ <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+ be done externally.
+ [RETURNS] Nothing.
+*/
+{
+ u32 low, high;
+ struct set_mtrr_context ctxt;
+
+ if (do_safe) set_mtrr_prepare (&ctxt);
+ /*
+ * Low is MTRR0 , High MTRR 1
+ */
+ rdmsr (0xC0000085, low, high);
+ /*
+ * Blank to disable
+ */
+ if (size == 0)
+ *(reg ? &high : &low) = 0;
+ else
+ /* Set the register to the base (already shifted for us), the
+ type (off by one) and an inverted bitmask of the size
+
+ The size is the only odd bit. We are fed say 512K
+ We invert this and we get 111 1111 1111 1011 but
+ if you subtract one and invert you get the desired
+ 111 1111 1111 1100 mask
+ */
+ *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+ /*
+ * The writeback rule is quite specific. See the manual. Its
+ * disable local interrupts, write back the cache, set the mtrr
+ */
+ __asm__ __volatile__ ("wbinvd" : : : "memory");
+ wrmsr (0xC0000085, low, high);
+ if (do_safe) set_mtrr_done (&ctxt);
+} /* End Function amd_set_mtrr_up */
+static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
+ unsigned long size, mtrr_type type,
+ int do_safe) = NULL;
#ifdef __SMP__
@@ -407,7 +678,7 @@ struct mtrr_var_range
};
-/* Get the MSR pair relating to a var range. */
+/* Get the MSR pair relating to a var range */
__initfunc(static void get_mtrr_var_range (unsigned int index,
struct mtrr_var_range *vr))
{
@@ -416,8 +687,8 @@ __initfunc(static void get_mtrr_var_range (unsigned int index,
} /* End Function get_mtrr_var_range */
-/* Set the MSR pair relating to a var range. Returns TRUE if
- changes are made. */
+/* Set the MSR pair relating to a var range. Returns TRUE if
+ changes are made */
__initfunc(static int set_mtrr_var_range_testing (unsigned int index,
struct mtrr_var_range *vr))
{
@@ -441,8 +712,7 @@ __initfunc(static int set_mtrr_var_range_testing (unsigned int index,
}
return changed;
-}
-
+} /* End Function set_mtrr_var_range_testing */
__initfunc(static void get_fixed_ranges(mtrr_type *frs))
{
@@ -456,8 +726,7 @@ __initfunc(static void get_fixed_ranges(mtrr_type *frs))
for (i = 0; i < 8; i++)
rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
-}
-
+} /* End Function get_fixed_ranges */
__initfunc(static int set_fixed_ranges_testing(mtrr_type *frs))
{
@@ -487,10 +756,8 @@ __initfunc(static int set_fixed_ranges_testing(mtrr_type *frs))
changed = TRUE;
}
}
-
return changed;
-}
-
+} /* End Function set_fixed_ranges_testing */
struct mtrr_state
{
@@ -502,7 +769,7 @@ struct mtrr_state
};
-/* Grab all of the MTRR state for this CPU into *state. */
+/* Grab all of the MTRR state for this CPU into *state */
__initfunc(static void get_mtrr_state(struct mtrr_state *state))
{
unsigned int nvrs, i;
@@ -511,22 +778,22 @@ __initfunc(static void get_mtrr_state(struct mtrr_state *state))
nvrs = state->num_var_ranges = get_num_var_ranges();
vrs = state->var_ranges
- = kmalloc(nvrs * sizeof(struct mtrr_var_range), GFP_KERNEL);
+ = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
if (vrs == NULL)
nvrs = state->num_var_ranges = 0;
for (i = 0; i < nvrs; i++)
- get_mtrr_var_range(i, &vrs[i]);
+ get_mtrr_var_range (i, &vrs[i]);
- get_fixed_ranges(state->fixed_ranges);
+ get_fixed_ranges (state->fixed_ranges);
- rdmsr(MTRRdefType_MSR, lo, dummy);
+ rdmsr (MTRRdefType_MSR, lo, dummy);
state->def_type = (lo & 0xff);
state->enabled = (lo & 0xc00) >> 10;
} /* End Function get_mtrr_state */
-/* Free resources associated with a struct mtrr_state */
+/* Free resources associated with a struct mtrr_state */
__initfunc(static void finalize_mtrr_state(struct mtrr_state *state))
{
if (state->var_ranges) kfree (state->var_ranges);
@@ -546,14 +813,14 @@ __initfunc(static unsigned long set_mtrr_state (struct mtrr_state *state,
unsigned long change_mask = 0;
for (i = 0; i < state->num_var_ranges; i++)
- if (set_mtrr_var_range_testing(i, &state->var_ranges[i]))
+ if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) )
change_mask |= MTRR_CHANGE_MASK_VARIABLE;
- if (set_fixed_ranges_testing(state->fixed_ranges))
+ if ( set_fixed_ranges_testing(state->fixed_ranges) )
change_mask |= MTRR_CHANGE_MASK_FIXED;
- /* set_mtrr_restore restores the old value of MTRRdefType,
- so to set it we fiddle with the saved value. */
+ /* Set_mtrr_restore restores the old value of MTRRdefType,
+ so to set it we fiddle with the saved value */
if ((ctxt->deftype_lo & 0xff) != state->def_type
|| ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled)
{
@@ -566,76 +833,63 @@ __initfunc(static unsigned long set_mtrr_state (struct mtrr_state *state,
static atomic_t undone_count;
-static void (*handler_func) (struct set_mtrr_context *ctxt, void *info);
-static void *handler_info;
static volatile int wait_barrier_execute = FALSE;
static volatile int wait_barrier_cache_enable = FALSE;
-static void sync_handler (void)
+struct set_mtrr_data
+{
+ unsigned long smp_base;
+ unsigned long smp_size;
+ unsigned int smp_reg;
+ mtrr_type smp_type;
+};
+
+static void ipi_handler (void *info)
/* [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
[RETURNS] Nothing.
*/
{
+ struct set_mtrr_data *data = info;
struct set_mtrr_context ctxt;
set_mtrr_prepare (&ctxt);
- /* Notify master CPU that I'm at the barrier and then wait */
+ /* Notify master that I've flushed and disabled my cache */
atomic_dec (&undone_count);
while (wait_barrier_execute) barrier ();
/* The master has cleared me to execute */
- (*handler_func) (&ctxt, handler_info);
+ (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
+ data->smp_type, FALSE);
/* Notify master CPU that I've executed the function */
atomic_dec (&undone_count);
/* Wait for master to clear me to enable cache and return */
while (wait_barrier_cache_enable) barrier ();
set_mtrr_done (&ctxt);
-} /* End Function sync_handler */
-
-static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt,
- void *info),
- void *info, int local)
-/* [SUMMARY] Execute a function on all CPUs, with caches flushed and disabled.
- [PURPOSE] This function will synchronise all CPUs, flush and disable caches
- on all CPUs, then call a specified function. When the specified function
- finishes on all CPUs, caches are enabled on all CPUs.
- <handler> The function to execute.
- <info> An arbitrary information pointer which is passed to <<handler>>.
- <local> If TRUE <<handler>> is executed locally.
- [RETURNS] Nothing.
-*/
+} /* End Function ipi_handler */
+
+static void set_mtrr_smp (unsigned int reg, unsigned long base,
+ unsigned long size, mtrr_type type)
{
- unsigned long timeout;
+ struct set_mtrr_data data;
struct set_mtrr_context ctxt;
- mtrr_hook = sync_handler;
- handler_func = handler;
- handler_info = info;
+ data.smp_reg = reg;
+ data.smp_base = base;
+ data.smp_size = size;
+ data.smp_type = type;
wait_barrier_execute = TRUE;
wait_barrier_cache_enable = TRUE;
- /* Send a message to all other CPUs and wait for them to enter the
- barrier */
atomic_set (&undone_count, smp_num_cpus - 1);
- smp_send_mtrr();
- /* Wait for it to be done */
- timeout = jiffies + JIFFIE_TIMEOUT;
- while ( (atomic_read (&undone_count) > 0) &&
- time_before(jiffies, timeout) )
- barrier ();
- if (atomic_read (&undone_count) > 0)
- {
+ /* Flush and disable the local CPU's cache and start the ball rolling on
+ other CPUs */
+ set_mtrr_prepare (&ctxt);
+ if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
panic ("mtrr: timed out waiting for other CPUs\n");
- }
- mtrr_hook = NULL;
- /* All other CPUs should be waiting for the barrier, with their caches
- already flushed and disabled. Prepare for function completion
- notification */
+ /* Wait for all other CPUs to flush and disable their caches */
+ while (atomic_read (&undone_count) > 0) barrier ();
+ /* Set up for completion wait and then release other CPUs to change MTRRs*/
atomic_set (&undone_count, smp_num_cpus - 1);
- /* Flush and disable the local CPU's cache and release the barier, which
- should cause the other CPUs to execute the function. Also execute it
- locally if required */
- set_mtrr_prepare (&ctxt);
wait_barrier_execute = FALSE;
- if (local) (*handler) (&ctxt, info);
+ (*set_mtrr_up) (reg, base, size, type, FALSE);
/* Now wait for other CPUs to complete the function */
while (atomic_read (&undone_count) > 0) barrier ();
/* Now all CPUs should have finished the function. Release the barrier to
@@ -643,41 +897,10 @@ static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt,
then enable the local cache and return */
wait_barrier_cache_enable = FALSE;
set_mtrr_done (&ctxt);
- handler_func = NULL;
- handler_info = NULL;
-} /* End Function do_all_cpus */
-
-
-struct set_mtrr_data
-{
- unsigned long smp_base;
- unsigned long smp_size;
- unsigned int smp_reg;
- mtrr_type smp_type;
-};
-
-static void set_mtrr_handler (struct set_mtrr_context *ctxt, void *info)
-{
- struct set_mtrr_data *data = info;
-
- set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, data->smp_type,
- FALSE);
-} /* End Function set_mtrr_handler */
-
-static void set_mtrr_smp (unsigned int reg, unsigned long base,
- unsigned long size, mtrr_type type)
-{
- struct set_mtrr_data data;
-
- data.smp_reg = reg;
- data.smp_base = base;
- data.smp_size = size;
- data.smp_type = type;
- do_all_cpus (set_mtrr_handler, &data, TRUE);
} /* End Function set_mtrr_smp */
-/* Some BIOS's are fucked and don't set all MTRRs the same! */
+/* Some BIOS's are fucked and don't set all MTRRs the same! */
__initfunc(static void mtrr_state_warn (unsigned long mask))
{
if (!mask) return;
@@ -720,6 +943,58 @@ static void init_table (void)
#endif
} /* End Function init_table */
+static int generic_get_free_region (unsigned long base, unsigned long size)
+/* [SUMMARY] Get a free MTRR.
+ <base> The starting (base) address of the region.
+ <size> The size (in bytes) of the region.
+ [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+ int i, max;
+ mtrr_type ltype;
+ unsigned long lbase, lsize;
+
+ max = get_num_var_ranges ();
+ for (i = 0; i < max; ++i)
+ {
+ (*get_mtrr) (i, &lbase, &lsize, &ltype);
+ if (lsize < 1) return i;
+ }
+ return -ENOSPC;
+} /* End Function generic_get_free_region */
+
+static int cyrix_get_free_region (unsigned long base, unsigned long size)
+/* [SUMMARY] Get a free ARR.
+ <base> The starting (base) address of the region.
+ <size> The size (in bytes) of the region.
+ [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+ int i;
+ mtrr_type ltype;
+ unsigned long lbase, lsize;
+
+ /* If we are to set up a region >32M then look at ARR7 immediately */
+ if (size > 0x2000000UL) {
+ cyrix_get_arr (7, &lbase, &lsize, &ltype);
+ if (lsize < 1) return 7;
+ /* else try ARR0-ARR6 first */
+ } else {
+ for (i = 0; i < 7; i++)
+ {
+ cyrix_get_arr (i, &lbase, &lsize, &ltype);
+ if (lsize < 1) return i;
+ }
+ /* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
+ cyrix_get_arr (i, &lbase, &lsize, &ltype);
+ if ((lsize < 1) && (size >= 0x40000)) return i;
+ }
+ return -ENOSPC;
+} /* End Function cyrix_get_free_region */
+
+static int (*get_free_region) (unsigned long base,
+ unsigned long size) = generic_get_free_region;
+
int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
char increment)
/* [SUMMARY] Add an MTRR entry.
@@ -738,28 +1013,57 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
unsigned long lbase, lsize, last;
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
- if ( (base & 0xfff) || (size & 0xfff) )
+ switch (boot_cpu_data.x86_vendor)
{
- printk ("mtrr: size and base must be multiples of 4kB\n");
- printk ("mtrr: size: %lx base: %lx\n", size, base);
- return -EINVAL;
- }
- if (base + size < 0x100000)
- {
- printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n",
- base, size);
- return -EINVAL;
- }
- /* Check upper bits of base and last are equal and lower bits are 0 for
- base and 1 for last */
- last = base + size - 1;
- for (lbase = base; !(lbase & 1) && (last & 1);
- lbase = lbase >> 1, last = last >> 1);
- if (lbase != last)
- {
- printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
- base, size);
+ case X86_VENDOR_INTEL:
+ /* For Intel PPro stepping <= 7, must be 4 MiB aligned */
+ if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
+ (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) )
+ {
+ printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+ return -EINVAL;
+ }
+ /* Fall through */
+ case X86_VENDOR_CYRIX:
+ if ( (base & 0xfff) || (size & 0xfff) )
+ {
+ printk ("mtrr: size and base must be multiples of 4 kiB\n");
+ printk ("mtrr: size: %lx base: %lx\n", size, base);
+ return -EINVAL;
+ }
+ if (base + size < 0x100000)
+ {
+ printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
+ base, size);
+ return -EINVAL;
+ }
+ /* Check upper bits of base and last are equal and lower bits are 0
+ for base and 1 for last */
+ last = base + size - 1;
+ for (lbase = base; !(lbase & 1) && (last & 1);
+ lbase = lbase >> 1, last = last >> 1);
+ if (lbase != last)
+ {
+ printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+ base, size);
+ return -EINVAL;
+ }
+ break;
+ case X86_VENDOR_AMD:
+ /* Apply the K6 block alignment and size rules
+ In order
+ o Uncached or gathering only
+ o 128K or bigger block
+ o Power of 2 block
+ o base suitably aligned to the power
+ */
+ if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+ (size & ~(size-1))-size || (base & (size-1)))
+ return -EINVAL;
+ break;
+ default:
return -EINVAL;
+ /*break;*/
}
if (type >= MTRR_NUM_TYPES)
{
@@ -775,10 +1079,10 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
increment = increment ? 1 : 0;
max = get_num_var_ranges ();
/* Search for existing MTRR */
- spin_lock (&main_lock);
+ spin_lock_reschedule (&main_lock);
for (i = 0; i < max; ++i)
{
- get_mtrr (i, &lbase, &lsize, &ltype);
+ (*get_mtrr) (i, &lbase, &lsize, &ltype);
if (base >= lbase + lsize) continue;
if ( (base < lbase) && (base + size <= lbase) ) continue;
/* At this point we know there is some kind of overlap/enclosure */
@@ -804,19 +1108,18 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
return i;
}
/* Search for an empty MTRR */
- for (i = 0; i < max; ++i)
+ i = (*get_free_region) (base, size);
+ if (i < 0)
{
- get_mtrr (i, &lbase, &lsize, &ltype);
- if (lsize > 0) continue;
- set_mtrr (i, base, size, type);
- usage_table[i] = 1;
- compute_ascii ();
spin_unlock (&main_lock);
+ printk ("mtrr: no more MTRRs available\n");
return i;
}
+ set_mtrr (i, base, size, type);
+ usage_table[i] = 1;
+ compute_ascii ();
spin_unlock (&main_lock);
- printk ("mtrr: no more MTRRs available\n");
- return -ENOSPC;
+ return i;
} /* End Function mtrr_add */
int mtrr_del (int reg, unsigned long base, unsigned long size)
@@ -836,13 +1139,13 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
max = get_num_var_ranges ();
- spin_lock (&main_lock);
+ spin_lock_reschedule (&main_lock);
if (reg < 0)
{
/* Search for existing MTRR */
for (i = 0; i < max; ++i)
{
- get_mtrr (i, &lbase, &lsize, &ltype);
+ (*get_mtrr) (i, &lbase, &lsize, &ltype);
if ( (lbase == base) && (lsize == size) )
{
reg = i;
@@ -862,7 +1165,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
printk ("mtrr: register: %d too big\n", reg);
return -EINVAL;
}
- get_mtrr (reg, &lbase, &lsize, &ltype);
+ (*get_mtrr) (reg, &lbase, &lsize, &ltype);
if (lsize < 1)
{
spin_unlock (&main_lock);
@@ -913,7 +1216,9 @@ static int mtrr_file_del (unsigned long base, unsigned long size,
reg = mtrr_del (-1, base, size);
if (reg < 0) return reg;
- if (fcount != NULL) --fcount[reg];
+ if (fcount == NULL) return reg;
+ if (fcount[reg] < 1) return -EINVAL;
+ --fcount[reg];
return reg;
} /* End Function mtrr_file_del */
@@ -1019,11 +1324,18 @@ static int mtrr_ioctl (struct inode *inode, struct file *file,
err = mtrr_file_del (sentry.base, sentry.size, file);
if (err < 0) return err;
break;
+ case MTRRIOC_KILL_ENTRY:
+ if ( !suser () ) return -EPERM;
+ if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+ return -EFAULT;
+ err = mtrr_del (-1, sentry.base, sentry.size);
+ if (err < 0) return err;
+ break;
case MTRRIOC_GET_ENTRY:
if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
return -EFAULT;
if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
- get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type);
+ (*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
gentry.type = type;
if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
return -EFAULT;
@@ -1115,7 +1427,7 @@ static void compute_ascii (void)
max = get_num_var_ranges ();
for (i = 0; i < max; i++)
{
- get_mtrr (i, &base, &size, &type);
+ (*get_mtrr) (i, &base, &size, &type);
if (size < 1) usage_table[i] = 0;
else
{
@@ -1148,23 +1460,165 @@ EXPORT_SYMBOL(mtrr_del);
#ifdef __SMP__
+typedef struct {
+ unsigned long base;
+ unsigned long size;
+ mtrr_type type;
+} arr_state_t;
+
+arr_state_t arr_state[8] __initdata = {
+ {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
+ {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
+};
+
+unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
+
+__initfunc(static void cyrix_arr_init_secondary(void))
+{
+ struct set_mtrr_context ctxt;
+ int i;
+
+ set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+ /* the CCRs are not contiguous */
+ for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
+ for( ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]);
+ for(i=0; i<8; i++)
+ cyrix_set_arr_up(i,
+ arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE);
+
+ set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+} /* End Function cyrix_arr_init_secondary */
+
+#endif
+
+/*
+ * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
+ * with the SMM (System Management Mode) mode. So we need the following:
+ * Check whether SMI_LOCK (CCR3 bit 0) is set
+ * if it is set, write a warning message: ARR3 cannot be changed!
+ * (it cannot be changed until the next processor reset)
+ * if it is reset, then we can change it, set all the needed bits:
+ * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
+ * - disable access to SMM memory (CCR1 bit 2 reset)
+ * - disable SMM mode (CCR1 bit 1 reset)
+ * - disable write protection of ARR3 (CCR6 bit 1 reset)
+ * - (maybe) disable ARR3
+ * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
+ */
+__initfunc(static void cyrix_arr_init(void))
+{
+ struct set_mtrr_context ctxt;
+ unsigned char ccr[7];
+ int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
+#ifdef __SMP__
+ int i;
+#endif
+
+ set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+ /* Save all CCRs locally */
+ ccr[0] = getCx86 (CX86_CCR0);
+ ccr[1] = getCx86 (CX86_CCR1);
+ ccr[2] = getCx86 (CX86_CCR2);
+ ccr[3] = ctxt.ccr3;
+ ccr[4] = getCx86 (CX86_CCR4);
+ ccr[5] = getCx86 (CX86_CCR5);
+ ccr[6] = getCx86 (CX86_CCR6);
+
+ if (ccr[3] & 1)
+ ccrc[3] = 1;
+ else {
+ /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+ * access to SMM memory through ARR3 (bit 7).
+ */
+/*
+ if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
+ if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
+ if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
+*/
+ if (ccr[6] & 0x02) {
+ ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */
+ setCx86 (CX86_CCR6, ccr[6]);
+ }
+ /* Disable ARR3. */
+ /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
+ }
+ /* If we changed CCR1 in memory, change it in the processor, too. */
+ if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
+
+ /* Enable ARR usage by the processor */
+ if (!(ccr[5] & 0x20)) {
+ ccr[5] |= 0x20; ccrc[5] = 1;
+ setCx86 (CX86_CCR5, ccr[5]);
+ }
+
+#ifdef __SMP__
+ for(i=0; i<7; i++) ccr_state[i] = ccr[i];
+ for(i=0; i<8; i++)
+ cyrix_get_arr(i,
+ &arr_state[i].base, &arr_state[i].size, &arr_state[i].type);
+#endif
+
+ set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+
+ if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n");
+ if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n");
+/*
+ if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
+ if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
+ if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
+*/
+ if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
+} /* End Function cyrix_arr_init */
+
+__initfunc(static void mtrr_setup (void))
+{
+ printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ get_mtrr = intel_get_mtrr;
+ set_mtrr_up = intel_set_mtrr_up;
+ break;
+ case X86_VENDOR_CYRIX:
+ printk ("mtrr: Using Cyrix style ARRs\n");
+ get_mtrr = cyrix_get_arr;
+ set_mtrr_up = cyrix_set_arr_up;
+ get_free_region = cyrix_get_free_region;
+ break;
+ case X86_VENDOR_AMD:
+ get_mtrr = amd_get_mtrr;
+ set_mtrr_up = amd_set_mtrr_up;
+ break;
+ }
+} /* End Function mtrr_setup */
+
+#ifdef __SMP__
+
static volatile unsigned long smp_changes_mask __initdata = 0;
static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
__initfunc(void mtrr_init_boot_cpu (void))
{
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
- printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-
- get_mtrr_state (&smp_mtrr_state);
+ mtrr_setup ();
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ get_mtrr_state (&smp_mtrr_state);
+ break;
+ case X86_VENDOR_CYRIX:
+ cyrix_arr_init ();
+ break;
+ }
} /* End Function mtrr_init_boot_cpu */
-__initfunc(void mtrr_init_secondary_cpu (void))
+__initfunc(static void intel_mtrr_init_secondary_cpu (void))
{
unsigned long mask, count;
struct set_mtrr_context ctxt;
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
/* Note that this is not ideal, since the cache is only flushed/disabled
for this CPU while the MTRRs are changed, but changing this requires
more invasive changes to the way the kernel boots */
@@ -1177,21 +1631,52 @@ __initfunc(void mtrr_init_secondary_cpu (void))
if (mask & 0x01) set_bit (count, &smp_changes_mask);
mask >>= 1;
}
-} /* End Function mtrr_init_secondary_cpu */
+} /* End Function intel_mtrr_init_secondary_cpu */
+__initfunc(void mtrr_init_secondary_cpu (void))
+{
+ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ intel_mtrr_init_secondary_cpu ();
+ break;
+ case X86_VENDOR_CYRIX:
+ /* This is _completely theoretical_!
+ * I assume here that one day Cyrix will support Intel APIC.
+ * In reality on non-Intel CPUs we won't even get to this routine.
+ * Hopefully no one will plug two Cyrix processors in a dual P5 board.
+ * :-)
+ */
+ cyrix_arr_init_secondary ();
+ break;
+ default:
+ printk ("mtrr: SMP support incomplete for this vendor\n");
+ break;
+ }
+} /* End Function mtrr_init_secondary_cpu */
#endif /* __SMP__ */
__initfunc(int mtrr_init(void))
{
if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
-# ifndef __SMP__
- printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-# endif
-
# ifdef __SMP__
- finalize_mtrr_state (&smp_mtrr_state);
- mtrr_state_warn (smp_changes_mask);
-# endif /* __SMP__ */
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_INTEL:
+ finalize_mtrr_state (&smp_mtrr_state);
+ mtrr_state_warn (smp_changes_mask);
+ break;
+ }
+# else /* __SMP__ */
+ mtrr_setup ();
+ switch (boot_cpu_data.x86_vendor)
+ {
+ case X86_VENDOR_CYRIX:
+ cyrix_arr_init ();
+ break;
+ }
+# endif /* !__SMP__ */
# ifdef CONFIG_PROC_FS
proc_register (&proc_root, &proc_root_mtrr);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 00f7e0ba2..ad745f58a 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -111,6 +111,8 @@ static int cpu_idle(void *unused)
/* endless idle loop with no priority at all */
current->priority = 0;
current->counter = -100;
+ init_idle();
+
for (;;) {
if (work)
start_idle = jiffies;
@@ -139,6 +141,8 @@ int cpu_idle(void *unused)
/* endless idle loop with no priority at all */
current->priority = 0;
current->counter = -100;
+ init_idle();
+
while(1) {
if (current_cpu_data.hlt_works_ok && !hlt_counter &&
!current->need_resched)
@@ -316,7 +320,7 @@ void machine_restart(char * __unused)
/* Make sure the first page is mapped to the start of physical memory.
It is normally not mapped, to trap kernel NULL pointer dereferences. */
- pg0[0] = 7;
+ pg0[0] = _PAGE_RW | _PAGE_PRESENT;
/*
* Use `swapper_pg_dir' as our page directory. We bother with
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index b0eca4345..9f5ce58f1 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -354,6 +354,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
struct user * dummy = NULL;
+ unsigned long flags;
int i, ret;
lock_kernel();
@@ -385,21 +386,22 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
(current->uid != child->uid) ||
(current->gid != child->egid) ||
(current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
(current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
goto out;
/* the same process cannot be attached many times */
if (child->flags & PF_PTRACED)
goto out;
child->flags |= PF_PTRACED;
- if (child->p_pptr != current) {
- unsigned long flags;
- write_lock_irqsave(&tasklist_lock, flags);
+ write_lock_irqsave(&tasklist_lock, flags);
+ if (child->p_pptr != current) {
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
- write_unlock_irqrestore(&tasklist_lock, flags);
}
+ write_unlock_irqrestore(&tasklist_lock, flags);
+
send_sig(SIGSTOP, child, 1);
ret = 0;
goto out;
@@ -559,7 +561,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
case PTRACE_DETACH: { /* detach a process that was attached. */
- unsigned long flags;
long tmp;
ret = -EIO;
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index c3f34270a..af6df1065 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -5,6 +5,10 @@
*
* Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
* and Martin Mares, November 1997.
+ *
+ * Force Cyrix 6x86(MX) and M II processors to report MTRR capability
+ * and fix against Cyrix "coma bug" by
+ * Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
*/
/*
@@ -39,6 +43,7 @@
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/cobalt.h>
+#include <asm/msr.h>
/*
* Machine setup..
@@ -57,6 +62,7 @@ int MCA_bus = 0;
unsigned int machine_id = 0;
unsigned int machine_submodel_id = 0;
unsigned int BIOS_revision = 0;
+unsigned int mca_pentium_flag = 0;
/*
* Setup options
@@ -244,11 +250,6 @@ __initfunc(void setup_arch(char **cmdline_p,
unsigned long memory_start, memory_end;
char c = ' ', *to = command_line, *from = COMMAND_LINE;
int len = 0;
- static unsigned char smptrap=0;
-
- if (smptrap)
- return;
- smptrap=1;
#ifdef CONFIG_VISWS
visws_get_board_type_and_rev();
@@ -381,7 +382,7 @@ __initfunc(void setup_arch(char **cmdline_p,
}
-__initfunc(static int amd_model(struct cpuinfo_x86 *c))
+__initfunc(static int get_model_name(struct cpuinfo_x86 *c))
{
unsigned int n, dummy, *v;
@@ -398,9 +399,87 @@ __initfunc(static int amd_model(struct cpuinfo_x86 *c))
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0;
+ /* Set MTRR capability flag if appropriate */
+ if(boot_cpu_data.x86 !=5)
+ return 1;
+ if((boot_cpu_data.x86_model == 9) ||
+ ((boot_cpu_data.x86_model == 8) &&
+ (boot_cpu_data.x86_mask >= 8)))
+ c->x86_capability |= X86_FEATURE_MTRR;
+
return 1;
}
+__initfunc(static int amd_model(struct cpuinfo_x86 *c))
+{
+ u32 l, h;
+ unsigned long flags;
+ int mbytes = max_mapnr >> (20-PAGE_SHIFT);
+
+ int r=get_model_name(c);
+
+ /*
+ * Now do the cache operations.
+ */
+
+ switch(c->x86)
+ {
+ case 5:
+ if( c->x86_model < 6 )
+ {
+ /* Anyone with a K5 want to fill this in */
+ break;
+ }
+
+ /* K6 with old style WHCR */
+ if( c->x86_model < 8 ||
+ (c->x86_model== 8 && c->x86_mask < 8))
+ {
+ /* We can only write allocate on the low 508Mb */
+ if(mbytes>508)
+ mbytes=508;
+
+ rdmsr(0xC0000082, l, h);
+ if((l&0x0000FFFF)==0)
+ {
+ l=(1<<0)|(mbytes/4);
+ save_flags(flags);
+ __cli();
+ __asm__ __volatile__ ("wbinvd": : :"memory");
+ wrmsr(0xC0000082, l, h);
+ restore_flags(flags);
+ printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
+ mbytes);
+
+ }
+ break;
+ }
+ if (c->x86_model == 8 || c->x86_model == 9)
+ {
+ /* The more serious chips .. */
+
+ if(mbytes>4092)
+ mbytes=4092;
+ rdmsr(0xC0000082, l, h);
+ if((l&0xFFFF0000)==0)
+ {
+ l=((mbytes>>2)<<22)|(1<<16);
+ save_flags(flags);
+ __cli();
+ __asm__ __volatile__ ("wbinvd": : :"memory");
+ wrmsr(0xC0000082, l, h);
+ restore_flags(flags);
+ printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
+ mbytes);
+ }
+ break;
+ }
+ break;
+ }
+ return r;
+}
+
+
/*
* Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
*/
@@ -507,6 +586,10 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
(c->x86_model)++;
} else /* 686 */
p = Cx86_cb+1;
+ /* Emulate MTRRs using Cyrix's ARRs. */
+ c->x86_capability |= X86_FEATURE_MTRR;
+ /* 6x86's contain this bug */
+ c->coma_bug = 1;
break;
case 4: /* MediaGX/GXm */
@@ -517,7 +600,7 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
/* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) {
- amd_model(c); /* get CPU marketing name */
+ get_model_name(c); /* get CPU marketing name */
c->x86_capability&=~X86_FEATURE_TSC;
return;
}
@@ -531,11 +614,14 @@ __initfunc(static void cyrix_model(struct cpuinfo_x86 *c))
case 5: /* 6x86MX/M II */
if (dir1 > 7) dir0_msn++; /* M II */
+ else c->coma_bug = 1; /* 6x86MX, it has the bug. */
tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
p = Cx86_cb+tmp;
if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
(c->x86_model)++;
+ /* Emulate MTRRs using Cyrix's ARRs. */
+ c->x86_capability |= X86_FEATURE_MTRR;
break;
case 0xf: /* Cyrix 486 without DEVID registers */
@@ -642,6 +728,20 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c))
return;
+
+ if (c->cpuid_level > 0 && c->x86_vendor == X86_VENDOR_INTEL)
+ {
+ if(c->x86_capability&(1<<18))
+ {
+ /* Disable processor serial number on Intel Pentium III
+ from code by Phil Karn */
+ unsigned long lo,hi;
+ rdmsr(0x119,lo,hi);
+ lo |= 0x200000;
+ wrmsr(0x119,lo,hi);
+ printk(KERN_INFO "Pentium-III serial number disabled.\n");
+ }
+ }
for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
if (c->cpuid_level > 1) {
@@ -726,15 +826,6 @@ __initfunc(void dodgy_tsc(void))
}
-#define rdmsr(msr,val1,val2) \
- __asm__ __volatile__("rdmsr" \
- : "=a" (val1), "=d" (val2) \
- : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
- __asm__ __volatile__("wrmsr" \
- : /* no outputs */ \
- : "c" (msr), "a" (val1), "d" (val2))
static char *cpu_vendor_names[] __initdata = {
"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" };
@@ -784,9 +875,9 @@ int get_cpuinfo(char * buffer)
int sep_bug;
static char *x86_cap_flags[] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
- "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
- "16", "17", "18", "19", "20", "21", "22", "mmx",
- "24", "25", "26", "27", "28", "29", "30", "31"
+ "cx8", "9", "10", "sep", "mtrr", "pge", "14", "cmov",
+ "16", "17", "psn", "19", "20", "21", "22", "mmx",
+ "24", "kni", "26", "27", "28", "29", "30", "31"
};
struct cpuinfo_x86 *c = cpu_data;
int i, n;
@@ -807,7 +898,7 @@ int get_cpuinfo(char * buffer)
c->x86_model,
c->x86_model_id[0] ? c->x86_model_id : "unknown");
- if (c->x86_mask)
+ if (c->x86_mask || c->cpuid_level >= 0)
p += sprintf(p, "stepping\t: %d\n", c->x86_mask);
else
p += sprintf(p, "stepping\t: unknown\n");
@@ -832,10 +923,10 @@ int get_cpuinfo(char * buffer)
} else if (c->x86_vendor == X86_VENDOR_INTEL) {
x86_cap_flags[6] = "pae";
x86_cap_flags[9] = "apic";
- x86_cap_flags[12] = "mtrr";
x86_cap_flags[14] = "mca";
x86_cap_flags[16] = "pat";
x86_cap_flags[17] = "pse36";
+ x86_cap_flags[18] = "psn";
x86_cap_flags[24] = "osfxsr";
}
@@ -850,6 +941,7 @@ int get_cpuinfo(char * buffer)
"hlt_bug\t\t: %s\n"
"sep_bug\t\t: %s\n"
"f00f_bug\t: %s\n"
+ "coma_bug\t: %s\n"
"fpu\t\t: %s\n"
"fpu_exception\t: %s\n"
"cpuid level\t: %d\n"
@@ -859,6 +951,7 @@ int get_cpuinfo(char * buffer)
c->hlt_works_ok ? "no" : "yes",
sep_bug ? "yes" : "no",
c->f00f_bug ? "yes" : "no",
+ c->coma_bug ? "yes" : "no",
c->hard_math ? "yes" : "no",
(c->hard_math && ignore_irq13) ? "yes" : "no",
c->cpuid_level,
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 2960d521c..4d13635ae 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -29,6 +29,7 @@
* from Jose Renau
* Alan Cox : Added EBDA scanning
* Ingo Molnar : various cleanups and rewrites
+ * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
*/
#include <linux/config.h>
@@ -39,10 +40,12 @@
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/mtrr.h>
+#include <asm/msr.h>
#include "irq.h"
-extern unsigned long start_kernel, _etext;
+#define JIFFIE_TIMEOUT 100
+
extern void update_one_process( struct task_struct *p,
unsigned long ticks, unsigned long user,
unsigned long system, int cpu);
@@ -146,6 +149,8 @@ int skip_ioapic_setup = 0; /* 1 if "noapic" boot option passed */
*/
#define APIC_DEFAULT_PHYS_BASE 0xfee00000
+#define CLEAR_TSC wrmsr(0x10, 0x00001000, 0x00001000)
+
/*
* Setup routine for controlling SMP activation
*
@@ -308,8 +313,17 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
printk("Processor #%d unused. (Max %d processors).\n",m->mpc_apicid, NR_CPUS);
else
{
+ int ver = m->mpc_apicver;
+
cpu_present_map|=(1<<m->mpc_apicid);
- apic_version[m->mpc_apicid]=m->mpc_apicver;
+ /*
+ * Validate version
+ */
+ if (ver == 0x0) {
+ printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid);
+ ver = 0x10;
+ }
+ apic_version[m->mpc_apicid] = ver;
}
}
mpt+=sizeof(*m);
@@ -325,11 +339,13 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
SMP_PRINTK(("Bus #%d is %s\n",
m->mpc_busid,
str));
- if ((strncmp(m->mpc_bustype,"ISA",3) == 0) ||
- (strncmp(m->mpc_bustype,"EISA",4) == 0))
+ if (strncmp(m->mpc_bustype,"ISA",3) == 0)
mp_bus_id_to_type[m->mpc_busid] =
MP_BUS_ISA;
else
+ if (strncmp(m->mpc_bustype,"EISA",4) == 0)
+ mp_bus_id_to_type[m->mpc_busid] =
+ MP_BUS_EISA;
if (strncmp(m->mpc_bustype,"PCI",3) == 0) {
mp_bus_id_to_type[m->mpc_busid] =
MP_BUS_PCI;
@@ -454,7 +470,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length)
*/
cfg=pg0[0];
- pg0[0] = (mp_lapic_addr | 7);
+ pg0[0] = (mp_lapic_addr | _PAGE_RW | _PAGE_PRESENT);
local_flush_tlb();
boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID));
@@ -710,24 +726,19 @@ void __init enable_local_APIC(void)
value |= 0xff; /* Set spurious IRQ vector to 0xff */
apic_write(APIC_SPIV,value);
- value = apic_read(APIC_TASKPRI);
- value &= ~APIC_TPRI_MASK; /* Set Task Priority to 'accept all' */
- apic_write(APIC_TASKPRI,value);
-
/*
- * Set arbitrarion priority to 0
+ * Set Task Priority to 'accept all'
*/
- value = apic_read(APIC_ARBPRI);
- value &= ~APIC_ARBPRI_MASK;
- apic_write(APIC_ARBPRI, value);
+ value = apic_read(APIC_TASKPRI);
+ value &= ~APIC_TPRI_MASK;
+ apic_write(APIC_TASKPRI,value);
/*
- * Set the logical destination ID to 'all', just to be safe.
+ * Clear the logical destination ID, just to be safe.
* also, put the APIC into flat delivery mode.
*/
value = apic_read(APIC_LDR);
value &= ~APIC_LDR_MASK;
- value |= SET_APIC_LOGICAL_ID(0xff);
apic_write(APIC_LDR,value);
value = apic_read(APIC_DFR);
@@ -735,8 +746,6 @@ void __init enable_local_APIC(void)
apic_write(APIC_DFR, value);
udelay(100); /* B safe */
- ack_APIC_irq();
- udelay(100);
}
unsigned long __init init_smp_mappings(unsigned long memory_start)
@@ -883,6 +892,7 @@ int __init start_secondary(void *unused)
* Everything has been set up for the secondary
* CPUs - they just need to reload everything
* from the task structure
+ * This function must not return.
*/
void __init initialize_secondary(void)
{
@@ -924,7 +934,6 @@ static void __init do_boot_cpu(int i)
/*
* We need an idle process for each processor.
*/
-
kernel_thread(start_secondary, NULL, CLONE_PID);
cpucount++;
@@ -935,6 +944,8 @@ static void __init do_boot_cpu(int i)
idle->processor = i;
__cpu_logical_map[cpucount] = i;
cpu_number_map[i] = cpucount;
+ idle->has_cpu = 1; /* we schedule the first task manually */
+ idle->tss.eip = (unsigned long) start_secondary;
/* start_eip had better be page-aligned! */
start_eip = setup_trampoline();
@@ -1167,6 +1178,7 @@ void __init smp_boot_cpus(void)
/* Must be done before other processors booted */
mtrr_init_boot_cpu ();
#endif
+ init_idle();
/*
* Initialize the logical to physical CPU number mapping
* and the per-CPU profiling counter/multiplier
@@ -1316,7 +1328,7 @@ void __init smp_boot_cpus(void)
* Install writable page 0 entry.
*/
cfg = pg0[0];
- pg0[0] = 3; /* writeable, present, addr 0 */
+ pg0[0] = _PAGE_RW | _PAGE_PRESENT; /* writeable, present, addr 0 */
local_flush_tlb();
/*
@@ -1641,15 +1653,84 @@ void smp_send_stop(void)
send_IPI_allbutself(STOP_CPU_VECTOR);
}
+/* Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+struct smp_call_function_struct {
+ void (*func) (void *info);
+ void *info;
+ atomic_t unstarted_count;
+ atomic_t unfinished_count;
+ int wait;
+};
+static volatile struct smp_call_function_struct *smp_call_function_data = NULL;
+
/*
- * this function sends an 'reload MTRR state' IPI to all other CPUs
- * in the system. it goes straight through, completion processing
- * is done on the mttr.c level.
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
*/
-void smp_send_mtrr(void)
+int smp_call_function (void (*func) (void *info), void *info, int retry,
+ int wait)
+/* [SUMMARY] 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 are or have executed.
+*/
{
- send_IPI_allbutself(MTRR_CHANGE_VECTOR);
+ unsigned long timeout;
+ struct smp_call_function_struct data;
+ static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+ if (retry) {
+ while (1) {
+ if (smp_call_function_data) {
+ schedule (); /* Give a mate a go */
+ continue;
+ }
+ spin_lock (&lock);
+ if (smp_call_function_data) {
+ spin_unlock (&lock); /* Bad luck */
+ continue;
+ }
+ /* Mine, all mine! */
+ break;
+ }
+ }
+ else {
+ if (smp_call_function_data) return -EBUSY;
+ spin_lock (&lock);
+ if (smp_call_function_data) {
+ spin_unlock (&lock);
+ return -EBUSY;
+ }
+ }
+ smp_call_function_data = &data;
+ spin_unlock (&lock);
+ data.func = func;
+ data.info = info;
+ atomic_set (&data.unstarted_count, smp_num_cpus - 1);
+ data.wait = wait;
+ if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1);
+ /* Send a message to all other CPUs and wait for them to respond */
+ send_IPI_allbutself (CALL_FUNCTION_VECTOR);
+ /* Wait for response */
+ timeout = jiffies + JIFFIE_TIMEOUT;
+ while ( (atomic_read (&data.unstarted_count) > 0) &&
+ time_before (jiffies, timeout) )
+ barrier ();
+ if (atomic_read (&data.unstarted_count) > 0) {
+ smp_call_function_data = NULL;
+ return -ETIMEDOUT;
+ }
+ if (wait)
+ while (atomic_read (&data.unfinished_count) > 0)
+ barrier ();
+ smp_call_function_data = NULL;
+ return 0;
}
/*
@@ -1692,9 +1773,8 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
system=1;
irq_enter(cpu, 0);
+ update_one_process(p, 1, user, system, cpu);
if (p->pid) {
- update_one_process(p, 1, user, system, cpu);
-
p->counter -= 1;
if (p->counter < 0) {
p->counter = 0;
@@ -1707,7 +1787,6 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
kstat.cpu_user += user;
kstat.per_cpu_user[cpu] += user;
}
-
kstat.cpu_system += system;
kstat.per_cpu_system[cpu] += system;
@@ -1767,6 +1846,7 @@ asmlinkage void smp_invalidate_interrupt(void)
local_flush_tlb();
ack_APIC_irq();
+
}
static void stop_this_cpu (void)
@@ -1789,12 +1869,19 @@ asmlinkage void smp_stop_cpu_interrupt(void)
stop_this_cpu();
}
-void (*mtrr_hook) (void) = NULL;
-
-asmlinkage void smp_mtrr_interrupt(void)
+asmlinkage void smp_call_function_interrupt(void)
{
- ack_APIC_irq();
- if (mtrr_hook) (*mtrr_hook)();
+ void (*func) (void *info) = smp_call_function_data->func;
+ void *info = smp_call_function_data->info;
+ int wait = smp_call_function_data->wait;
+
+ ack_APIC_irq ();
+ /* Notify initiating CPU that I've grabbed the data and am about to
+ execute the function */
+ atomic_dec (&smp_call_function_data->unstarted_count);
+ /* At this point the structure may be out of scope unless wait==1 */
+ (*func) (info);
+ if (wait) atomic_dec (&smp_call_function_data->unfinished_count);
}
/*
@@ -1802,8 +1889,10 @@ asmlinkage void smp_mtrr_interrupt(void)
*/
asmlinkage void smp_spurious_interrupt(void)
{
- /* ack_APIC_irq(); see sw-dev-man vol 3, chapter 7.4.13.5 */
- printk("spurious APIC interrupt, ayiee, should never happen.\n");
+ ack_APIC_irq();
+ /* see sw-dev-man vol 3, chapter 7.4.13.5 */
+ printk("spurious APIC interrupt on CPU#%d, should never happen.\n",
+ smp_processor_id());
}
/*
@@ -1815,10 +1904,6 @@ asmlinkage void smp_spurious_interrupt(void)
* closely follows bus clocks.
*/
-#define RDTSC(x) __asm__ __volatile__ ( "rdtsc" \
- :"=a" (((unsigned long*)&x)[0]), \
- "=d" (((unsigned long*)&x)[1]))
-
/*
* The timer chip is already set up at HZ interrupts per second here,
* but we do not accept timer interrupts yet. We only allow the BP
@@ -1937,7 +2022,7 @@ int __init calibrate_APIC_clock(void)
/*
* We wrapped around just now. Let's start:
*/
- RDTSC(t1);
+ rdtscll(t1);
tt1=apic_read(APIC_TMCCT);
#define LOOPS (HZ/10)
@@ -1948,7 +2033,7 @@ int __init calibrate_APIC_clock(void)
wait_8254_wraparound ();
tt2=apic_read(APIC_TMCCT);
- RDTSC(t2);
+ rdtscll(t2);
/*
* The APIC bus clock counter is 32 bits only, it
@@ -2058,3 +2143,4 @@ int setup_profiling_timer(unsigned int multiplier)
}
#undef APIC_DIVISOR
+
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index ec2ea5d60..2ab29d479 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -30,19 +30,6 @@
* serialize accesses to xtime/lost_ticks).
*/
-/* What about the "updated NTP code" stuff in 2.0 time.c? It's not in
- * 2.1, perhaps it should be ported, too.
- *
- * What about the BUGGY_NEPTUN_TIMER stuff in do_slow_gettimeoffset()?
- * Whatever it fixes, is it also fixed in the new code from the Jumbo
- * patch, so that that code can be used instead?
- *
- * The CPU Hz should probably be displayed in check_bugs() together
- * with the CPU vendor and type. Perhaps even only in MHz, though that
- * takes away some of the fun of the new code :)
- *
- * - Michael Krause */
-
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -60,6 +47,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
+#include <asm/msr.h>
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
@@ -96,8 +84,8 @@ static inline unsigned long do_fast_gettimeoffset(void)
register unsigned long edx asm("dx");
/* Read the Time Stamp Counter */
- __asm__("rdtsc"
- :"=a" (eax), "=d" (edx));
+
+ rdtsc(eax,edx);
/* .. relative to previous jiffy (32 bits is enough) */
eax -= last_tsc_low; /* tsc_low delta */
@@ -292,7 +280,6 @@ void do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
write_unlock_irq(&xtime_lock);
@@ -457,7 +444,8 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/
/* read Pentium cycle counter */
- __asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
+
+ rdtscl(last_tsc_low);
outb_p(0x00, 0x43); /* latch the count ASAP */
@@ -556,70 +544,72 @@ static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NUL
* device.
*/
+#define CALIBRATE_LATCH (5 * LATCH)
+#define CALIBRATE_TIME (5 * 1000020/HZ)
+
__initfunc(static unsigned long calibrate_tsc(void))
{
- unsigned long retval;
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
- __asm__( /* set the Gate high, program CTC channel 2 for mode 0
- * (interrupt on terminal count mode), binary count,
- * load 5 * LATCH count, (LSB and MSB)
- * to begin countdown, read the TSC and busy wait.
- * BTW LATCH is calculated in timex.h from the HZ value
- */
+ /*
+ * Now let's take care of CTC channel 2
+ *
+ * Set the Gate high, program CTC channel 2 for mode 0,
+ * (interrupt on terminal count mode), binary count,
+ * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+ */
+ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
+ outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
+ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
+
+ {
+ unsigned long startlow, starthigh;
+ unsigned long endlow, endhigh;
+ unsigned long count;
+
+ rdtsc(startlow,starthigh);
+ count = 0;
+ do {
+ count++;
+ } while ((inb(0x61) & 0x20) == 0);
+ rdtsc(endlow,endhigh);
+
+ last_tsc_low = endlow;
+
+ /* Error: ECTCNEVERSET */
+ if (count <= 1)
+ goto bad_ctc;
+
+ /* 64-bit subtract - gcc just messes up with long longs */
+ __asm__("subl %2,%0\n\t"
+ "sbbl %3,%1"
+ :"=a" (endlow), "=d" (endhigh)
+ :"g" (startlow), "g" (starthigh),
+ "0" (endlow), "1" (endhigh));
+
+ /* Error: ECPUTOOFAST */
+ if (endhigh)
+ goto bad_ctc;
+
+ /* Error: ECPUTOOSLOW */
+ if (endlow <= CALIBRATE_TIME)
+ goto bad_ctc;
+
+ __asm__("divl %2"
+ :"=a" (endlow), "=d" (endhigh)
+ :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+
+ return endlow;
+ }
- /* Set the Gate high, disable speaker */
- "inb $0x61, %%al\n\t" /* Read port */
- "andb $0xfd, %%al\n\t" /* Turn off speaker Data */
- "orb $0x01, %%al\n\t" /* Set Gate high */
- "outb %%al, $0x61\n\t" /* Write port */
-
- /* Now let's take care of CTC channel 2 */
- "movb $0xb0, %%al\n\t" /* binary, mode 0, LSB/MSB, ch 2*/
- "outb %%al, $0x43\n\t" /* Write to CTC command port */
- "movl %1, %%eax\n\t"
- "outb %%al, $0x42\n\t" /* LSB of count */
- "shrl $8, %%eax\n\t"
- "outb %%al, $0x42\n\t" /* MSB of count */
-
- /* Read the TSC; counting has just started */
- "rdtsc\n\t"
- /* Move the value for safe-keeping. */
- "movl %%eax, %%ebx\n\t"
- "movl %%edx, %%ecx\n\t"
-
- /* Busy wait. Only 50 ms wasted at boot time. */
- "0: inb $0x61, %%al\n\t" /* Read Speaker Output Port */
- "testb $0x20, %%al\n\t" /* Check CTC channel 2 output (bit 5) */
- "jz 0b\n\t"
-
- /* And read the TSC. 5 jiffies (50.00077ms) have elapsed. */
- "rdtsc\n\t"
-
- /* Great. So far so good. Store last TSC reading in
- * last_tsc_low (only 32 lsb bits needed) */
- "movl %%eax, last_tsc_low\n\t"
- /* And now calculate the difference between the readings. */
- "subl %%ebx, %%eax\n\t"
- "sbbl %%ecx, %%edx\n\t" /* 64-bit subtract */
- /* but probably edx = 0 at this point (see below). */
- /* Now we have 5 * (TSC counts per jiffy) in eax. We want
- * to calculate TSC->microsecond conversion factor. */
-
- /* Note that edx (high 32-bits of difference) will now be
- * zero iff CPU clock speed is less than 85 GHz. Moore's
- * law says that this is likely to be true for the next
- * 12 years or so. You will have to change this code to
- * do a real 64-by-64 divide before that time's up. */
- "movl %%eax, %%ecx\n\t"
- "xorl %%eax, %%eax\n\t"
- "movl %2, %%edx\n\t"
- "divl %%ecx\n\t" /* eax= 2^32 / (1 * TSC counts per microsecond) */
- /* Return eax for the use of fast_gettimeoffset */
- "movl %%eax, %0\n\t"
- : "=r" (retval)
- : "r" (5 * LATCH), "r" (5 * 1000020/HZ)
- : /* we clobber: */ "ax", "bx", "cx", "dx", "cc", "memory");
- return retval;
+ /*
+ * The CTC wasn't reliable: we got a hit on the very first read,
+ * or the CPU was so fast/slow that the quotient wouldn't fit in
+ * 32 bits..
+ */
+bad_ctc:
+ return 0;
}
__initfunc(void time_init(void))
@@ -655,23 +645,26 @@ __initfunc(void time_init(void))
dodgy_tsc();
if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+ unsigned long tsc_quotient = calibrate_tsc();
+ if (tsc_quotient) {
+ fast_gettimeoffset_quotient = tsc_quotient;
+ use_tsc = 1;
#ifndef do_gettimeoffset
- do_gettimeoffset = do_fast_gettimeoffset;
+ do_gettimeoffset = do_fast_gettimeoffset;
#endif
- do_get_fast_time = do_gettimeofday;
- use_tsc = 1;
- fast_gettimeoffset_quotient = calibrate_tsc();
-
- /* report CPU clock rate in Hz.
- * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
- * clock/second. Our precision is about 100 ppm.
- */
- { unsigned long eax=0, edx=1000000;
- __asm__("divl %2"
- :"=a" (cpu_hz), "=d" (edx)
- :"r" (fast_gettimeoffset_quotient),
- "0" (eax), "1" (edx));
- printk("Detected %ld Hz processor.\n", cpu_hz);
+ do_get_fast_time = do_gettimeofday;
+
+ /* report CPU clock rate in Hz.
+ * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
+ * clock/second. Our precision is about 100 ppm.
+ */
+ { unsigned long eax=0, edx=1000000;
+ __asm__("divl %2"
+ :"=a" (cpu_hz), "=d" (edx)
+ :"r" (tsc_quotient),
+ "0" (eax), "1" (edx));
+ printk("Detected %ld Hz processor.\n", cpu_hz);
+ }
}
}
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index f0dc06092..cce35ac80 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -42,6 +42,8 @@
#include <asm/lithium.h>
#endif
+#include "irq.h"
+
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
@@ -125,7 +127,6 @@ static void show_registers(struct pt_regs *regs)
unsigned long esp;
unsigned short ss;
unsigned long *stack, addr, module_start, module_end;
- extern char _stext, _etext;
esp = (unsigned long) (1+regs);
ss = __KERNEL_DS;
@@ -669,9 +670,6 @@ cobalt_init(void)
#endif
void __init trap_init(void)
{
- /* Initially up all of the IDT to jump to unexpected */
- init_unexpected_irq();
-
if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
EISA_bus = 1;
set_call_gate(&default_ldt,lcall7);
@@ -693,7 +691,7 @@ void __init trap_init(void)
set_trap_gate(15,&spurious_interrupt_bug);
set_trap_gate(16,&coprocessor_error);
set_trap_gate(17,&alignment_check);
- set_system_gate(0x80,&system_call);
+ set_system_gate(SYSCALL_VECTOR,&system_call);
/* set up GDT task & ldt entries */
set_tss_desc(0, &init_task.tss);
diff --git a/arch/i386/kernel/visws_apic.c b/arch/i386/kernel/visws_apic.c
index f7dabc15d..c12054689 100644
--- a/arch/i386/kernel/visws_apic.c
+++ b/arch/i386/kernel/visws_apic.c
@@ -201,11 +201,13 @@ static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs)
{
unsigned int status;
/* XXX APIC EOI? */
- status = desc->status & ~IRQ_REPLAY;
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
action = NULL;
- if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
action = desc->action;
- desc->status = status | IRQ_INPROGRESS;
+ status |= IRQ_INPROGRESS;
+ }
+ desc->status = status;
}
spin_unlock(&irq_controller_lock);
diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S
index faddbf4ec..3f6e27fcc 100644
--- a/arch/i386/lib/semaphore.S
+++ b/arch/i386/lib/semaphore.S
@@ -31,6 +31,15 @@ ENTRY(__down_failed_interruptible)
popl %edx /* restore %edx */
ret
+/* Don't save/restore %eax, because that will be our return value */
+ENTRY(__down_failed_trylock)
+ pushl %edx /* save %edx */
+ pushl %ecx /* save %ecx (and argument) */
+ call SYMBOL_NAME(__down_trylock)
+ popl %ecx /* restore %ecx (count on __down_trylock not changing it) */
+ popl %edx /* restore %edx */
+ ret
+
ENTRY(__up_wakeup)
pushl %eax /* save %eax */
pushl %edx /* save %edx */
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index cb60ea268..3a5957b09 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -56,6 +56,11 @@ SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib
CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES)
LIBS += arch/m68k/lib/lib.a
+ifdef CONFIG_Q40
+CORE_FILES := $(CORE_FILES) arch/m68k/q40/q40.o
+SUBDIRS := $(SUBDIRS) arch/m68k/q40
+endif
+
ifdef CONFIG_AMIGA
CORE_FILES := $(CORE_FILES) arch/m68k/amiga/amiga.o
SUBDIRS := $(SUBDIRS) arch/m68k/amiga
@@ -81,6 +86,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o
SUBDIRS := $(SUBDIRS) arch/m68k/apollo
endif
+ifdef CONFIG_MVME147
+CORE_FILES := $(CORE_FILES) arch/m68k/mvme147/mvme147.o
+SUBDIRS := $(SUBDIRS) arch/m68k/mvme147
+endif
+
ifdef CONFIG_MVME16x
CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o
SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x
@@ -91,6 +101,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/bvme6000/bvme6000.o
SUBDIRS := $(SUBDIRS) arch/m68k/bvme6000
endif
+ifdef CONFIG_SUN3X
+CORE_FILES := $(CORE_FILES) arch/m68k/sun3x/sun3x.o
+SUBDIRS := $(SUBDIRS) arch/m68k/sun3x
+endif
+
ifdef CONFIG_M68040
CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o
SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index 79ef5f9fd..6de1fd686 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -291,7 +291,7 @@ static void atakeyb_rep( unsigned long ignore )
atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
add_timer( &atakeyb_rep_timer );
- handle_scancode(rep_scancode);
+ handle_scancode(rep_scancode, 1);
}
atari_enable_irq( IRQ_MFP_ACIA );
@@ -448,7 +448,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
add_timer( &atakeyb_rep_timer );
}
- handle_scancode(break_flag | scancode);
+ handle_scancode(scancode, !break_flag);
break;
}
break;
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 543b04c74..fc1b5627f 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -417,10 +417,10 @@ void bvme6000_init_console_port (struct console *co, int cflag)
static void scc_delay (void)
{
int n;
- char i;
+ volatile int trash;
for (n = 0; n < 20; n++)
- i = *(volatile char *)0;
+ trash = n;
}
static void scc_write (char ch)
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index a67227d60..a8dacc904 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -37,6 +37,7 @@ fi
bool 'Apollo support' CONFIG_APOLLO
bool 'VME (Motorola and BVM) support' CONFIG_VME
if [ "$CONFIG_VME" = "y" ]; then
+ bool 'MVME147 support' CONFIG_MVME147
bool 'MVME162, 166 and 167 support' CONFIG_MVME16x
bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000
fi
@@ -44,10 +45,13 @@ bool 'HP9000/300 support' CONFIG_HP300
if [ "$CONFIG_HP300" = "y" ]; then
bool 'DIO bus support' CONFIG_DIO
fi
+bool 'Sun3x support' CONFIG_SUN3X
+
define_bool CONFIG_SUN3 n
if [ "$CONFIG_PCI" = "y" ]; then
bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
fi
+bool 'Q40/Q60 support' CONFIG_Q40
comment 'Processor type'
bool '68020 support' CONFIG_M68020
@@ -94,6 +98,29 @@ else
fi
fi
bool '/proc/hardware support' CONFIG_PROC_HARDWARE
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Parallel port support (EXPERIMENTAL, disables old lp driver!)' CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT" != "n" ]; then
+ if [ "$CONFIG_AMIGA" != "n" ]; then
+ dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+ if [ "$CONFIG_ZORRO" != "n" ]; then
+ dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+ fi
+ fi
+ if [ "$CONFIG_Q40" != "n" ]; then
+ tristate ' Q40 Parallel port' CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT" != "n" ]; then
+ define_bool CONFIG_PARPORT_PC y
+ fi
+ fi
+ fi
+ if [ "$CONFIG_ATARI" == "y" ]; then
+ dep_tristate ' Atari builtin port' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+ fi
+fi
+
+
endmenu
source drivers/block/Config.in
@@ -147,6 +174,7 @@ if [ "$CONFIG_ZORRO" = "y" ]; then
bool 'A4091 SCSI support' CONFIG_A4091_SCSI
bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI
bool 'Blizzard PowerUP 603e+ SCSI' CONFIG_BLZ603EPLUS_SCSI
+ dep_tristate 'BSC Oktagon SCSI support' CONFIG_OKTAGON_SCSI $CONFIG_SCSI
bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI
# bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI
fi
@@ -167,6 +195,10 @@ if [ "$CONFIG_MAC" = "y" ]; then
fi
#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+ bool 'WD33C93 SCSI driver for MVME147' CONFIG_MVME147_SCSI
+fi
+
if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI
fi
@@ -175,6 +207,10 @@ if [ "$CONFIG_VME" = "y" -a "$CONFIG_BVME6000" = "y" ]; then
bool 'NCR53C710 SCSI driver for BVME6000' CONFIG_BVME6000_SCSI
fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+ bool 'ESP SCSI driver' CONFIG_SUN3X_ESP
+fi
+
endmenu
fi
@@ -219,6 +255,9 @@ if [ "$CONFIG_MAC" = "y" ]; then
# bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
fi
+if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME147" = "y" ]; then
+ tristate 'MVME147 (Lance) Ethernet support' CONFIG_MVME147_NET
+fi
if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
fi
@@ -232,9 +271,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then
tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET
fi
fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+ bool 'Sun3x Lance support' CONFIG_SUNLANCE
+fi
if [ "$CONFIG_HP300" = "y" ]; then
bool 'HP on-board LANCE support' CONFIG_HPLANCE
fi
+if [ "$CONFIG_Q40" = "y" ]; then
+ if [ ! "$CONFIG_PARPORT" = "n" ]; then
+ dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
+ fi
+fi
fi
endmenu
@@ -243,6 +290,23 @@ fi
mainmenu_option next_comment
comment 'Character devices'
+if [ "$CONFIG_Q40" = "y" ]; then
+ tristate 'Q40 Standard/generic serial support' CONFIG_SERIAL
+fi
+
+if [ "$CONFIG_SERIAL" = "y" ]; then
+ bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
+ bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
+fi
+
+if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
+ bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
+ bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+# bool ' Autodetect IRQ - do not yet enable !!' CONFIG_SERIAL_DETECT_IRQ
+ bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT
+ bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6
+fi
+
if [ "$CONFIG_VME" = "n" ]; then
define_bool CONFIG_VT y
if [ "$CONFIG_VT" = "y" ]; then
@@ -254,10 +318,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then
define_bool CONFIG_NVRAM y
fi
-tristate 'Parallel printer support' CONFIG_M68K_PRINTER
-if [ "$CONFIG_ZORRO" = "y" ]; then
- dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
-fi
+if [ "$CONFIG_PARPORT" = "n" ]; then
+ tristate 'Parallel printer support' CONFIG_M68K_PRINTER
+ if [ "$CONFIG_ZORRO" = "y" ]; then
+ dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_M68K_PRINTER
+ fi
+else
+ dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
+ if [ "$CONFIG_PRINTER" != "n" ]; then
+ bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+ fi
+fi
if [ "$CONFIG_AMIGA" = "y" ]; then
tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
fi
@@ -280,13 +351,17 @@ if [ "$CONFIG_ATARI" = "y" ]; then
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
- bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
+ if [ "$CONFIG_AMIGA_PCMCIA" = "y" ]; then
+ tristate 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET_SERIAL
+ fi
fi
-if [ "$CONFIG_ZORRO" = "y" ]; then
- tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
- dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
- dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
- tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+if [ "$CONFIG_PARPORT" = "n" ]; then
+ if [ "$CONFIG_ZORRO" = "y" ]; then
+ tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT
+ dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
+ dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
+ tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+ fi
fi
if [ "$CONFIG_MAC" = "y" ]; then
bool 'Mac SCC serial support' CONFIG_MAC_SCC
@@ -294,18 +369,32 @@ fi
if [ "$CONFIG_HP300" = "y" -a "$CONFIG_DIO" = "y" ]; then
tristate 'HP DCA serial support' CONFIG_HPDCA
fi
+if [ "$CONFIG_SUN3X" = "y" ]; then
+ bool 'Sun3x builtin serial support' CONFIG_SUN3X_ZS
+ if [ "$CONFIG_SUN3X_ZS" = "y" ]; then
+ bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD
+ bool 'Sun mouse support' CONFIG_SUN_MOUSE
+ define_bool CONFIG_SBUS y
+ define_bool CONFIG_SBUSCHAR y
+ define_bool CONFIG_SUN_SERIAL y
+ fi
+fi
if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o \
- "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" ]; then
+ "$CONFIG_MAC" = "y" -o "$CONFIG_HP300" = "y" -o \
+ "$CONFIG_SUN3X" = "y" ]; then
if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
"$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_MAC_SCC" = "y" -o \
"$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
"$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" -o \
- "$CONFIG_HPDCA" = "y" ]; then
+ "$CONFIG_HPDCA" = "y" -o "$CONFIG_SUN3X_ZS" = "y" ]; then
bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
fi
fi
if [ "$CONFIG_VME" = "y" ]; then
define_bool CONFIG_SERIAL_CONSOLE y
+ if [ "$CONFIG_MVME147" = "y" ]; then
+ bool 'SCC support for MVME147 serial ports' CONFIG_MVME147_SCC
+ fi
if [ "$CONFIG_MVME16x" = "y" ]; then
bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167
bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC
@@ -346,13 +435,13 @@ endmenu
source fs/Config.in
if [ "$CONFIG_VME" = "n" ]; then
+ mainmenu_option next_comment
+ comment 'Console drivers'
if [ "$CONFIG_HP300" = "y" ]; then
bool 'Frame buffer support' CONFIG_FB
else
define_bool CONFIG_FB y
fi
- mainmenu_option next_comment
- comment 'Console drivers'
source drivers/video/Config.in
endmenu
fi
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
index ab9152f5d..109ce19fa 100644
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -78,7 +78,6 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/m68k/hp300/hil.c b/arch/m68k/hp300/hil.c
index 3be0d488a..d7fe1867c 100644
--- a/arch/m68k/hp300/hil.c
+++ b/arch/m68k/hp300/hil.c
@@ -223,12 +223,13 @@ static void poll_finished(void)
{
case 0x40:
{
- unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0);
+ int down = (poll.data[1] & 1) == 0;
+ unsigned char scode = poll.data[1] >> 1;
#if 0
- if (scode & 0x80)
- printk("[%02x]", scode & 0x7f);
+ if (down)
+ printk("[%02x]", scode);
#endif
- handle_scancode(scode);
+ handle_scancode(scode, down);
}
break;
}
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index e21e4b21c..61482c3a8 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -164,8 +164,17 @@ SYMBOL_NAME_LABEL(inthandler)
movel %sp,%sp@-
movel %d0,%sp@- | put vector # on stack
+#if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD)
+ btstb #4,0xff000000 | Q40 floppy needs very special treatment ...
+ jbeq 1f
+ btstb #3,0xff000004
+ jbeq 1f
+ jbsr SYMBOL_NAME(floppy_hardint)
+ jbra 3f
+1:
+#endif
jbsr SYMBOL_NAME(process_int)| process the IRQ
- addql #8,%sp | pop parameters off stack
+3: addql #8,%sp | pop parameters off stack
SYMBOL_NAME_LABEL(ret_from_interrupt)
subql #1,SYMBOL_NAME(local_irq_count)
@@ -295,6 +304,8 @@ SYMBOL_NAME_LABEL(resume)
2: fmovemx %fp0-%fp7,%a0@(TASK_TSS+TSS_FPREG)
fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_TSS+TSS_FPCNTL)
3:
+ /* Return previous task in %d1 */
+ movel %curptr,%d1
/* switch to new task (a1 contains new task) */
movel %a1,%curptr
@@ -320,8 +331,15 @@ SYMBOL_NAME_LABEL(resume)
movec %d0,%cacr
/* switch the root pointer */
+#ifdef CPU_M68030_ONLY
+ .chip 68030
+ pmovefd %a1@(TASK_TSS+TSS_CRP),%crp
+ .chip 68k
+ pflush #0,#4
+#else
pmove %a1@(TASK_TSS+TSS_CRP),%crp
#endif
+#endif
#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
jra 2f /* skip m68040 stuff */
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 482c15f50..361b10cb6 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -23,6 +23,7 @@
** 98/04/25 Phil Blundell: added HP300 support
** 1998/08/30 David Kilzer: Added support for fbcon_font_desc structures
** for linux-2.1.115
+** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01)
**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file README.legal in the main directory of this archive
@@ -303,6 +304,12 @@
.globl SYMBOL_NAME(availmem)
.globl SYMBOL_NAME(m68k_pgtable_cachemode)
.globl SYMBOL_NAME(m68k_supervisor_cachemode)
+#ifdef CONFIG_MVME16x
+.globl SYMBOL_NAME(mvme_bdid_ptr)
+#endif
+#ifdef CONFIG_Q40
+.globl SYMBOL_NAME(q40_mem_cptr)
+#endif
CPUTYPE_040 = 1 /* indicates an 040 */
CPUTYPE_060 = 2 /* indicates an 060 */
@@ -512,13 +519,15 @@ func_define putn,1
#endif
.endm
-
#define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab
#define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab
#define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab
+#define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab
#define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab
#define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab
#define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab
+#define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab
+#define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab
#define is_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab
#define is_not_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab
@@ -552,9 +561,11 @@ ENTRY(_stext)
.long BOOTINFOV_MAGIC
.long MACH_AMIGA, AMIGA_BOOTI_VERSION
.long MACH_ATARI, ATARI_BOOTI_VERSION
+ .long MACH_MVME147, MVME147_BOOTI_VERSION
.long MACH_MVME16x, MVME16x_BOOTI_VERSION
.long MACH_BVME6000, BVME6000_BOOTI_VERSION
.long MACH_MAC, MAC_BOOTI_VERSION
+ .long MACH_Q40, Q40_BOOTI_VERSION
.long 0
1: jra SYMBOL_NAME(__start)
@@ -859,7 +870,12 @@ L(mmu_init_amiga):
/*
* 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000
*/
- mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+ mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
+ /*
+ * Map the Zorro III I/O space with transparent translation
+ * for frame buffer memory etc.
+ */
+ mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
@@ -867,7 +883,8 @@ L(mmu_init_amiga):
/*
* 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000
*/
- mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+ mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
+ mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030
jbra L(mmu_init_done)
@@ -926,6 +943,25 @@ L(spata68040):
L(mmu_init_not_atari):
#endif
+#ifdef CONFIG_Q40
+ is_not_q40(L(notq40))
+ /*
+ * add transparent mapping for 0xff00 0000 - 0xffff ffff
+ * non-cached serialized etc..
+ * this includes master chip, DAC, RTC and ISA ports
+ * 0xfe000000-0xfeffffff is for screen and ROM
+ */
+
+ putc 'Q'
+
+ mmu_map_tt #0,#0xfe000000,#0x01000000,#_PAGE_CACHE040W
+ mmu_map_tt #1,#0xff000000,#0x01000000,#_PAGE_NOCACHE_S
+
+ jbra L(mmu_init_done)
+
+L(notq40):
+#endif
+
#ifdef CONFIG_HP300
is_not_hp300(L(nothp300))
@@ -940,6 +976,24 @@ L(nothp300):
#endif
+#ifdef CONFIG_MVME147
+
+ is_not_mvme147(L(not147))
+
+ /*
+ * On MVME147 we have already created kernel page tables for
+ * 4MB of RAM at address 0, so now need to do a transparent
+ * mapping of the top of memory space. Make it 0.5GByte for now,
+ * so we can access on-board i/o areas.
+ */
+
+ mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030
+
+ jbra L(mmu_init_done)
+
+L(not147):
+#endif /* CONFIG_MVME147 */
+
#ifdef CONFIG_MVME16x
is_not_mvme16x(L(not16x))
@@ -965,7 +1019,7 @@ L(nothp300):
* 0xffe00000->0xffe1ffff.
*/
- mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+ mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
@@ -985,7 +1039,7 @@ L(not16x):
* clash with User code virtual address space.
*/
- mmu_map_tt 1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
+ mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S
jbra L(mmu_init_done)
@@ -1052,13 +1106,23 @@ L(mmu_init_mac):
mmu_map_eq #0x50000000,#0x02000000,%d3
mmu_map_eq #0x60000000,#0x00400000,%d3
mmu_map_eq #0x9c000000,#0x00400000,%d3
- mmu_map_tt 1,#0xf8000000,#0x08000000,%d3
+ mmu_map_tt #1,#0xf8000000,#0x08000000,%d3
jbra L(mmu_init_done)
L(mmu_init_not_mac):
#endif
+#ifdef CONFIG_SUN3X
+ is_not_sun3x(L(notsun3x))
+
+ /* setup tt1 for I/O */
+ mmu_map_tt #1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S
+
+L(notsun3x):
+ jbra L(mmu_init_done)
+#endif
+
L(mmu_init_done):
putc 'G'
@@ -1214,6 +1278,14 @@ L(mmu_fixup_done):
1:
#endif
+#ifdef CONFIG_SUN3X
+ is_not_sun3x(1f)
+
+ /* enable copro */
+ oriw #0x4000,0x61000000
+1:
+#endif
+
/*
* Fixup the addresses for the kernel pointer table and availmem.
* Convert them from physical addresses to virtual addresses.
@@ -1780,7 +1852,7 @@ func_start mmu_map_tt,%d0/%d1/%a0,4
/* Extract the highest bit set
*/
bfffo ARG3{#0,#32},%d1
- cmpw #8,%d0
+ cmpw #8,%d1
jcc L(do_map)
/* And get the mask
@@ -2155,7 +2227,9 @@ func_start mmu_temp_map,%d0/%d1/%a0/%a1
/* Temporary allocate a page table and insert it into the ptr table
*/
movel %a1@,%d0
- addl #PTR_TABLE_SIZE*4,%a1@
+ /* The 512 should be PAGE_TABLE_SIZE*4, but that violates the
+ alignment restriction for pointer tables on the '0[46]0. */
+ addl #512,%a1@
orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0
movel %d0,%a0@
dputs " (new)"
@@ -2703,6 +2777,31 @@ func_start serial_init,%d0/%d1/%a0/%a1
L(serial_init_not_mac):
#endif /* CONFIG_MAC */
+#ifdef CONFIG_Q40
+ is_not_q40(2f)
+/* debug output goes into SRAM, so we don't do it unless requested
+ - check for '%LX$' signature in SRAM */
+ lea %pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+ move.l #0xff020010,%a1@ /* must be inited - also used by debug=mem */
+ move.l #0xff020000,%a1
+ cmp.b #'%',%a1@
+ bne 2f /*nodbg*/
+ addq.w #4,%a1
+ cmp.b #'L',%a1@
+ bne 2f /*nodbg*/
+ addq.w #4,%a1
+ cmp.b #'X',%a1@
+ bne 2f /*nodbg*/
+ addq.w #4,%a1
+ cmp.b #'$',%a1@
+ bne 2f /*nodbg*/
+ /* signature OK */
+ lea %pc@(L(q40_do_debug)),%a1
+ tas %a1@
+/*nodbg: q40_do_debug is 0 by default*/
+2:
+#endif
+
L(serial_init_done):
func_return serial_init
@@ -2792,6 +2891,15 @@ func_start serial_putc,%d0/%d1/%a0/%a1
4:
#endif /* CONFIG_ATARI */
+#ifdef CONFIG_MVME147
+ is_not_mvme147(2f)
+1: btst #2,M147_SCC_CTRL_A
+ jeq 1b
+ moveb %d0,M147_SCC_DATA_A
+ jbra L(serial_putc_done)
+2:
+#endif
+
#ifdef CONFIG_MVME16x
is_not_mvme16x(2f)
/*
@@ -2805,7 +2913,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1
moveml %sp@+,%d0-%d7/%a2-%a6
jbra L(serial_putc_done)
2:
-#endif CONFIG_MVME162 | CONFIG_MVME167
+#endif CONFIG_MVME16x
#ifdef CONFIG_BVME6000
is_not_bvme6000(2f)
@@ -2819,6 +2927,18 @@ func_start serial_putc,%d0/%d1/%a0/%a1
2:
#endif
+#ifdef CONFIG_Q40
+ is_not_q40(2f)
+ tst.l %pc@(L(q40_do_debug)) /* only debug if requested */
+ beq 2f
+ lea %pc@(SYMBOL_NAME(q40_mem_cptr)),%a1
+ move.l %a1@,%a0
+ move.b %d0,%a0@
+ addq.l #4,%a0
+ move.l %a0,%a1@
+2:
+#endif
+
L(serial_putc_done):
func_return serial_putc
@@ -3472,6 +3592,10 @@ L(kernel_pgdir_ptr):
L(temp_mmap_mem):
.long 0
+#if defined (CONFIG_MVME147)
+M147_SCC_CTRL_A = 0xfffe3002
+M147_SCC_DATA_A = 0xfffe3003
+#endif
#if defined (CONFIG_BVME6000)
BVME_SCC_CTRL_A = 0xffb0000b
@@ -3509,3 +3633,9 @@ SYMBOL_NAME_LABEL(m68k_supervisor_cachemode)
SYMBOL_NAME_LABEL(mvme_bdid_ptr)
.long 0
#endif
+#if defined(CONFIG_Q40)
+SYMBOL_NAME_LABEL(q40_mem_cptr)
+ .long 0
+L(q40_do_debug):
+ .long 0
+#endif
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 20e39f17f..66fc41064 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -38,6 +38,10 @@
#include <asm/page.h>
#include <asm/machdep.h>
+#ifdef CONFIG_Q40
+#include <asm/q40ints.h>
+#endif
+
/* table for system interrupt handlers */
static irq_handler_t irq_list[SYS_IRQS];
@@ -177,14 +181,24 @@ void sys_free_irq(unsigned int irq, void *dev_id)
/*
* Do we need these probe functions on the m68k?
+ *
+ * ... may be usefull with ISA devices
*/
unsigned long probe_irq_on (void)
{
+#ifdef CONFIG_Q40
+ if (MACH_IS_Q40)
+ return q40_probe_irq_on();
+#endif
return 0;
}
int probe_irq_off (unsigned long irqs)
{
+#ifdef CONFIG_Q40
+ if (MACH_IS_Q40)
+ return q40_probe_irq_off(irqs);
+#endif
return 0;
}
diff --git a/arch/m68k/kernel/m68k_defs.h b/arch/m68k/kernel/m68k_defs.h
index b32e6a1c9..4926a6dad 100644
--- a/arch/m68k/kernel/m68k_defs.h
+++ b/arch/m68k/kernel/m68k_defs.h
@@ -3,6 +3,47 @@
*/
#define TS_MAGICKEY 0x5a5a5a5a
-#define TS_TSS 482
-#define TS_ESP0 502
-#define TS_FPU 506
+#define TASK_STATE 0
+#define TASK_FLAGS 4
+#define TASK_SIGPENDING 8
+#define TASK_NEEDRESCHED 20
+#define TASK_TSS 470
+#define TASK_MM 622
+#define TSS_KSP 0
+#define TSS_USP 4
+#define TSS_SR 8
+#define TSS_FS 10
+#define TSS_CRP 12
+#define TSS_ESP0 20
+#define TSS_FPREG 24
+#define TSS_FPCNTL 120
+#define TSS_FPSTATE 132
+#define PT_D0 32
+#define PT_ORIG_D0 36
+#define PT_SR 44
+#define PT_VECTOR 50
+#define IRQ_HANDLER 0
+#define IRQ_DEVID 8
+#define IRQ_NEXT 16
+#define STAT_IRQ 120
+#define BIR_TAG 0
+#define BIR_SIZE 2
+#define BIR_DATA 4
+#define FBCON_FONT_DESC_IDX 0
+#define FBCON_FONT_DESC_NAME 4
+#define FBCON_FONT_DESC_WIDTH 8
+#define FBCON_FONT_DESC_HEIGHT 12
+#define FBCON_FONT_DESC_DATA 16
+#define FBCON_FONT_DESC_PREF 20
+#define CUSTOMBASE -2132807680
+#define C_INTENAR 28
+#define C_INTREQR 30
+#define C_INTENA 154
+#define C_INTREQ 156
+#define C_SERDATR 24
+#define C_SERDAT 48
+#define C_SERPER 50
+#define CIAABASE -2134908927
+#define CIABBASE -2134913024
+#define C_PRA 0
+#define ZTWOBASE -2147483648
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 793ca6ec7..5aae5953c 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -18,6 +18,7 @@
#include <asm/checksum.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#include <asm/m68kserial.h>
asmlinkage long long __ashrdi3 (long long, int);
extern char m68k_debug_device[];
@@ -54,6 +55,8 @@ EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_set_cachemode);
EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
@@ -69,4 +72,5 @@ EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
+EXPORT_SYMBOL_NOVERS(__down_failed_trylock);
EXPORT_SYMBOL_NOVERS(__up_wakeup);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index c7c3f458e..97f3bd151 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -169,15 +169,7 @@ asmlinkage int m68k_fork(struct pt_regs *regs)
asmlinkage int m68k_vfork(struct pt_regs *regs)
{
- int child;
- struct semaphore sem = MUTEX_LOCKED;
-
- child = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
-
- if (child > 0)
- down(&sem);
-
- return child;
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs);
}
asmlinkage int m68k_clone(struct pt_regs *regs)
@@ -190,7 +182,7 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
newsp = regs->d2;
if (!newsp)
newsp = rdusp();
- return do_fork(clone_flags & ~CLONE_VFORK, newsp, regs);
+ return do_fork(clone_flags, newsp, regs);
}
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 5aeb2534b..e9254cfa7 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -312,6 +312,7 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
+ unsigned long flags;
int ret;
lock_kernel();
@@ -343,21 +344,22 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
(current->uid != child->uid) ||
(current->gid != child->egid) ||
(current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
(current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
goto out;
/* the same process cannot be attached many times */
if (child->flags & PF_PTRACED)
goto out;
child->flags |= PF_PTRACED;
- if (child->p_pptr != current) {
- unsigned long flags;
- write_lock_irqsave(&tasklist_lock, flags);
+ write_lock_irqsave(&tasklist_lock, flags);
+ if (child->p_pptr != current) {
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
- write_unlock_irqrestore(&tasklist_lock, flags);
}
+ write_unlock_irqrestore(&tasklist_lock, flags);
+
send_sig(SIGSTOP, child, 1);
ret = 0;
goto out;
@@ -502,7 +504,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
case PTRACE_DETACH: { /* detach a process that was attached. */
- unsigned long flags;
long tmp;
ret = -EIO;
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index ade12c46d..39dcd9c15 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -77,10 +77,26 @@ int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
int (*mach_set_clock_mmss) (unsigned long) = NULL;
void (*mach_reset)( void );
long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
void (*mach_floppy_eject) (void) = NULL;
#endif
+struct serial_struct;
+#ifdef CONFIG_SERIAL
+long serial_rs_init(void);
+int serial_register_serial(struct serial_struct *);
+void serial_unregister_serial(int);
+long ser_console_init(long, long );
+#endif
+#if defined(CONFIG_USERIAL)||defined(CONFIG_BVME6000_SCC)||defined(CONFIG_MVME162_SCC)||defined(CONFIG_HPDCA)||defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL)||defined(CONFIG_MAC_SCC)||defined(CONFIG_ATARI_MIDI)||defined(CONFIG_ATARI_SCC)||defined(CONFIG_ATARI_MFPSER)
+#define M68K_SERIAL
+#endif
+#ifdef M68K_SERIAL
+long m68k_rs_init(void);
+int m68k_register_serial(struct serial_struct *);
+void m68k_unregister_serial(int);
+long m68k_serial_console_init(long, long );
+#endif
#ifdef CONFIG_HEARTBEAT
void (*mach_heartbeat) (int) = NULL;
#endif
@@ -97,15 +113,19 @@ char *mach_sysrq_xlate = NULL;
extern int amiga_parse_bootinfo(const struct bi_record *);
extern int atari_parse_bootinfo(const struct bi_record *);
extern int mac_parse_bootinfo(const struct bi_record *);
+extern int q40_parse_bootinfo(const struct bi_record *);
extern void config_amiga(void);
extern void config_atari(void);
extern void config_mac(void);
extern void config_sun3(void);
extern void config_apollo(void);
+extern void config_mvme147(void);
extern void config_mvme16x(void);
extern void config_bvme6000(void);
extern void config_hp300(void);
+extern void config_q40(void);
+extern void config_sun3x(void);
#define MASK_256K 0xfffc0000
@@ -149,6 +169,8 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
unknown = atari_parse_bootinfo(record);
else if (MACH_IS_MAC)
unknown = mac_parse_bootinfo(record);
+ else if (MACH_IS_Q40)
+ unknown = q40_parse_bootinfo(record);
else
unknown = 1;
}
@@ -258,6 +280,11 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
config_apollo();
break;
#endif
+#ifdef CONFIG_MVME147
+ case MACH_MVME147:
+ config_mvme147();
+ break;
+#endif
#ifdef CONFIG_MVME16x
case MACH_MVME16x:
config_mvme16x();
@@ -273,6 +300,16 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
config_hp300();
break;
#endif
+#ifdef CONFIG_Q40
+ case MACH_Q40:
+ config_q40();
+ break;
+#endif
+#ifdef CONFIG_SUN3X
+ case MACH_SUN3X:
+ config_sun3x();
+ break;
+#endif
default:
panic ("No configuration setup");
}
@@ -384,7 +421,52 @@ int get_hardware_list(char *buffer)
return(len);
}
-#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
+#if defined(CONFIG_SERIAL) || defined(M68K_SERIAL)
+int rs_init(void)
+{
+#ifdef CONFIG_SERIAL
+ if (MACH_IS_Q40)
+ return serial_rs_init();
+#endif
+#ifdef M68K_SERIAL
+ return m68k_rs_init();
+#endif
+}
+int register_serial(struct serial_struct *p)
+{
+#ifdef CONFIG_SERIAL
+ if (MACH_IS_Q40)
+ return serial_register_serial(p);
+#endif
+#ifdef M68K_SERIAL
+ return m68k_register_serial(p);
+#endif
+}
+void unregister_serial(int i)
+{
+#ifdef CONFIG_SERIAL
+ if (MACH_IS_Q40)
+ serial_unregister_serial(i);
+#endif
+#ifdef M68K_SERIAL
+ m68k_unregister_serial(i);
+#endif
+}
+#ifdef CONFIG_SERIAL_CONSOLE
+long serial_console_init(long kmem_start, long kmem_end)
+{
+#ifdef CONFIG_SERIAL
+ if (MACH_IS_Q40)
+ return ser_console_init(kmem_start, kmem_end);
+#endif
+#if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE)
+ return m68k_serial_console_init(kmem_start, kmem_end);
+#endif
+}
+#endif
+#endif
+
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
__initfunc(void floppy_setup(char *str, int *ints))
{
if (mach_floppy_setup)
@@ -399,7 +481,7 @@ void floppy_eject(void)
#endif
/* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+__initfunc(void kbd_reset_setup(char *str, int *ints))
{
}
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 107d0de7f..9b98fdb75 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -198,8 +198,7 @@ void do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
+ write_unlock_irq(&xtime_lock);
}
diff --git a/arch/m68k/lib/semaphore.S b/arch/m68k/lib/semaphore.S
index 8e4141149..842f83f64 100644
--- a/arch/m68k/lib/semaphore.S
+++ b/arch/m68k/lib/semaphore.S
@@ -32,6 +32,16 @@ ENTRY(__down_failed_interruptible)
movel (%sp)+,%a0
rts
+ENTRY(__down_failed_trylock)
+ movel %a0,-(%sp)
+ movel %d1,-(%sp)
+ movel %a1,-(%sp)
+ jbsr SYMBOL_NAME(__down_trylock)
+ movel (%sp)+,%a1
+ movel (%sp)+,%d1
+ movel (%sp)+,%a0
+ rts
+
ENTRY(__up_wakeup)
moveml %a0/%d0/%d1,-(%sp)
movel %a1,-(%sp)
diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c
index 5a6ae7c75..a128a6314 100644
--- a/arch/m68k/mac/mackeyb.c
+++ b/arch/m68k/mac/mackeyb.c
@@ -60,7 +60,7 @@ static void input_keycode(int, int);
extern struct kbd_struct kbd_table[];
extern void adb_bus_init(void);
-extern void handle_scancode(unsigned char);
+extern void handle_scancode(unsigned char, int);
extern void put_queue(int);
/* keyb */
@@ -387,7 +387,7 @@ input_keycode(int keycode, int repeat)
*/
switch (keycode) {
case 0x39:
- handle_scancode(keycode); /* down */
+ handle_scancode(keycode, 1); /* down */
up_flag = 0x80; /* see below ... */
mark_bh(KEYBOARD_BH);
break;
@@ -397,7 +397,7 @@ input_keycode(int keycode, int repeat)
}
}
- handle_scancode(keycode + up_flag);
+ handle_scancode(keycode, !up_flag);
}
static void
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 8e520702f..9a41dc279 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -123,7 +123,7 @@ void show_mem(void)
unsigned long mm_cachebits = 0;
#endif
-static pte_t *__init kernel_page_table(unsigned long *memavailp)
+__initfunc(static pte_t * kernel_page_table(unsigned long *memavailp))
{
pte_t *ptablep;
@@ -140,15 +140,19 @@ static pte_t *__init kernel_page_table(unsigned long *memavailp)
static pmd_t *last_pgtable __initdata = NULL;
-static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
+__initfunc(static pmd_t * kernel_ptr_table(unsigned long *memavailp))
{
if (!last_pgtable) {
unsigned long pmd, last;
int i;
+ /* Find the last ptr table that was used in head.S and
+ * reuse the remaining space in that page for further
+ * ptr tables.
+ */
last = (unsigned long)kernel_pg_dir;
for (i = 0; i < PTRS_PER_PGD; i++) {
- if (!pgd_val(kernel_pg_dir[i]))
+ if (!pgd_present(kernel_pg_dir[i]))
continue;
pmd = pgd_page(kernel_pg_dir[i]);
if (pmd > last)
@@ -175,8 +179,8 @@ static pmd_t *__init kernel_ptr_table(unsigned long *memavailp)
return last_pgtable;
}
-static unsigned long __init
-map_chunk (unsigned long addr, long size, unsigned long *memavailp)
+__initfunc(static unsigned long
+map_chunk (unsigned long addr, long size, unsigned long *memavailp))
{
#define PTRTREESIZE (256*1024)
#define ROOTTREESIZE (32*1024*1024)
@@ -282,8 +286,8 @@ extern char __init_begin, __init_end;
* paging_init() continues the virtual memory environment setup which
* was begun by the code in arch/head.S.
*/
-unsigned long __init paging_init(unsigned long start_mem,
- unsigned long end_mem)
+__initfunc(unsigned long paging_init(unsigned long start_mem,
+ unsigned long end_mem))
{
int chunk;
unsigned long mem_avail = 0;
@@ -392,7 +396,7 @@ unsigned long __init paging_init(unsigned long start_mem,
return PAGE_ALIGN(free_area_init(start_mem, end_mem));
}
-void __init mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
{
int codepages = 0;
int datapages = 0;
@@ -443,7 +447,7 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem)
/* insert pointer tables allocated so far into the tablelist */
init_pointer_table((unsigned long)kernel_pg_dir);
for (i = 0; i < PTRS_PER_PGD; i++) {
- if (pgd_val(kernel_pg_dir[i]))
+ if (pgd_present(kernel_pg_dir[i]))
init_pointer_table(pgd_page(kernel_pg_dir[i]));
}
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index d2cd29011..3fefe4e03 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -116,6 +116,14 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
if (!size || size > physaddr + size)
return NULL;
+#ifdef CONFIG_AMIGA
+ if (MACH_IS_AMIGA) {
+ if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+ && (cacheflag == IOMAP_NOCACHE_SER))
+ return (void *)physaddr;
+ }
+#endif
+
#ifdef DEBUG
printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
#endif
@@ -174,7 +182,7 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
}
}
- while (size > 0) {
+ while ((long)size > 0) {
#ifdef DEBUG
if (!(virtaddr & (PTRTREESIZE-1)))
printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
@@ -187,7 +195,7 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
}
if (CPU_IS_020_OR_030) {
- pmd_dir->pmd[(virtaddr/PTRTREESIZE)&-16] = physaddr;
+ pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
physaddr += PTRTREESIZE;
virtaddr += PTRTREESIZE;
size -= PTRTREESIZE;
@@ -217,7 +225,14 @@ void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
*/
void iounmap(void *addr)
{
+#ifdef CONFIG_AMIGA
+ if ((!MACH_IS_AMIGA) ||
+ (((unsigned long)addr < 0x40000000) ||
+ ((unsigned long)addr > 0x60000000)))
+ free_io_area(addr);
+#else
free_io_area(addr);
+#endif
}
/*
@@ -232,7 +247,7 @@ void __iounmap(void *addr, unsigned long size)
pmd_t *pmd_dir;
pte_t *pte_dir;
- while (size > 0) {
+ while ((long)size > 0) {
pgd_dir = pgd_offset_k(virtaddr);
if (pgd_bad(*pgd_dir)) {
printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -242,7 +257,7 @@ void __iounmap(void *addr, unsigned long size)
pmd_dir = pmd_offset(pgd_dir, virtaddr);
if (CPU_IS_020_OR_030) {
- int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+ int pmd_off = (virtaddr/PTRTREESIZE) & 15;
if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
pmd_dir->pmd[pmd_off] = 0;
@@ -308,7 +323,7 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
}
}
- while (size > 0) {
+ while ((long)size > 0) {
pgd_dir = pgd_offset_k(virtaddr);
if (pgd_bad(*pgd_dir)) {
printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
@@ -318,7 +333,7 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
pmd_dir = pmd_offset(pgd_dir, virtaddr);
if (CPU_IS_020_OR_030) {
- int pmd_off = (virtaddr/PTRTREESIZE) & -16;
+ int pmd_off = (virtaddr/PTRTREESIZE) & 15;
if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index a97578ec2..a6d496571 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/pagemap.h>
#include <asm/setup.h>
#include <asm/segment.h>
@@ -93,12 +94,11 @@ typedef struct page ptable_desc;
static ptable_desc ptable_list = { &ptable_list, &ptable_list };
#define PD_MARKBITS(dp) (*(unsigned char *)&(dp)->offset)
-#define PD_PAGE(dp) (PAGE_OFFSET + ((dp)->map_nr << PAGE_SHIFT))
#define PAGE_PD(page) ((ptable_desc *)&mem_map[MAP_NR(page)])
#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
-void __init init_pointer_table(unsigned long ptable)
+__initfunc(void init_pointer_table(unsigned long ptable))
{
ptable_desc *dp;
unsigned long page = ptable & PAGE_MASK;
@@ -166,7 +166,7 @@ pmd_t *get_pointer_table (void)
(dp->next = last->next)->prev = dp;
(dp->prev = last)->next = dp;
}
- return (pmd_t *) (PD_PAGE(dp) + off);
+ return (pmd_t *) (page_address(dp) + off);
}
int free_pointer_table (pmd_t *ptable)
@@ -215,8 +215,8 @@ static unsigned long transp_transl_matches( unsigned long regval,
/* function code match? */
base = (regval >> 4) & 7;
mask = ~(regval & 7);
- if ((SUPER_DATA & mask) != (base & mask))
- return( 0 );
+ if (((SUPER_DATA ^ base) & mask) != 0)
+ return 0;
}
else {
/* must not be user-only */
@@ -226,8 +226,8 @@ static unsigned long transp_transl_matches( unsigned long regval,
/* address match? */
base = regval & 0xff000000;
- mask = ~((regval << 8) & 0xff000000);
- return( (vaddr & mask) == (base & mask) );
+ mask = ~(regval << 8) & 0xff000000;
+ return ((vaddr ^ base) & mask) == 0;
}
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
diff --git a/arch/m68k/mvme147/147ints.c b/arch/m68k/mvme147/147ints.c
new file mode 100644
index 000000000..3121ad94f
--- /dev/null
+++ b/arch/m68k/mvme147/147ints.c
@@ -0,0 +1,142 @@
+/*
+ * arch/m68k/mvme147/147ints.c
+ *
+ * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * based on amiints.c -- Amiga Linux interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+static struct {
+ void (*handler)(int, void *, struct pt_regs *);
+ unsigned long flags;
+ void *dev_id;
+ const char *devname;
+ unsigned count;
+} irq_tab[256];
+
+/*
+ * void mvme147_init_IRQ (void)
+ *
+ * Parameters: None
+ *
+ * Returns: Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the mvme147 IRQ handling routines.
+ */
+
+void mvme147_init_IRQ (void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ irq_tab[i].handler = mvme147_defhand;
+ irq_tab[i].flags = IRQ_FLG_STD;
+ irq_tab[i].dev_id = NULL;
+ irq_tab[i].devname = NULL;
+ irq_tab[i].count = 0;
+ }
+}
+
+int mvme147_request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags, const char *devname, void *dev_id)
+{
+ if (irq > 255) {
+ printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+ return -ENXIO;
+ }
+ if (!(irq_tab[irq].flags & IRQ_FLG_STD)) {
+ if (irq_tab[irq].flags & IRQ_FLG_LOCK) {
+ printk("%s: IRQ %d from %s is not replaceable\n",
+ __FUNCTION__, irq, irq_tab[irq].devname);
+ return -EBUSY;
+ }
+ if (flags & IRQ_FLG_REPLACE) {
+ printk("%s: %s can't replace IRQ %d from %s\n",
+ __FUNCTION__, devname, irq, irq_tab[irq].devname);
+ return -EBUSY;
+ }
+ }
+ irq_tab[irq].handler = handler;
+ irq_tab[irq].flags = flags;
+ irq_tab[irq].dev_id = dev_id;
+ irq_tab[irq].devname = devname;
+ return 0;
+}
+
+void mvme147_free_irq(unsigned int irq, void *dev_id)
+{
+ if (irq > 255) {
+ printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+ return;
+ }
+ if (irq_tab[irq].dev_id != dev_id)
+ printk("%s: Removing probably wrong IRQ %d from %s\n",
+ __FUNCTION__, irq, irq_tab[irq].devname);
+
+ irq_tab[irq].handler = mvme147_defhand;
+ irq_tab[irq].flags = IRQ_FLG_STD;
+ irq_tab[irq].dev_id = NULL;
+ irq_tab[irq].devname = NULL;
+}
+
+void mvme147_process_int (unsigned long vec, struct pt_regs *fp)
+{
+ if (vec > 255)
+ printk ("mvme147_process_int: Illegal vector %ld\n", vec);
+ else
+ {
+ irq_tab[vec].count++;
+ irq_tab[vec].handler(vec, irq_tab[vec].dev_id, fp);
+ }
+}
+
+int mvme147_get_irq_list (char *buf)
+{
+ int i, len = 0;
+
+ for (i = 0; i < 256; i++) {
+ if (irq_tab[i].count)
+ len += sprintf (buf+len, "Vec 0x%02x: %8d %s\n",
+ i, irq_tab[i].count,
+ irq_tab[i].devname ? irq_tab[i].devname : "free");
+ }
+ return len;
+}
+
+
+static void mvme147_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+ printk ("Unknown interrupt 0x%02x\n", irq);
+}
+
+void mvme147_enable_irq (unsigned int irq)
+{
+}
+
+
+void mvme147_disable_irq (unsigned int irq)
+{
+}
+
diff --git a/arch/m68k/mvme147/Makefile b/arch/m68k/mvme147/Makefile
new file mode 100644
index 000000000..c0f064118
--- /dev/null
+++ b/arch/m68k/mvme147/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/mvme147 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+O_TARGET := mvme147.o
+O_OBJS := config.o 147ints.o
+
+
+include $(TOPDIR)/Rules.make
+
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
new file mode 100644
index 000000000..639d5f640
--- /dev/null
+++ b/arch/m68k/mvme147/config.c
@@ -0,0 +1,240 @@
+/*
+ * arch/m68k/mvme147/config.c
+ *
+ * Copyright (C) 1996 Dave Frascone [chaos@mindspring.com]
+ * Cloned from Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * Based on:
+ *
+ * Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/mvme147hw.h>
+
+
+extern void mvme147_process_int (int level, struct pt_regs *regs);
+extern void mvme147_init_IRQ (void);
+extern void mvme147_free_irq (unsigned int, void *);
+extern int mvme147_get_irq_list (char *);
+extern void mvme147_enable_irq (unsigned int);
+extern void mvme147_disable_irq (unsigned int);
+static void mvme147_get_model(char *model);
+static int mvme147_get_hardware_list(char *buffer);
+extern int mvme147_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void mvme147_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int mvme147_keyb_init(void);
+extern int mvme147_kbdrate (struct kbd_repeat *);
+extern unsigned long mvme147_gettimeoffset (void);
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+ int *min, int *sec);
+extern int mvme147_hwclk (int, struct hwclk_time *);
+extern int mvme147_set_clock_mmss (unsigned long);
+extern void mvme147_check_partition (struct gendisk *hd, unsigned int dev);
+extern void mvme147_reset (void);
+extern void mvme147_waitbut(void);
+
+
+static int bcd2int (unsigned char b);
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c, called via mvme147_process_int() */
+
+void (*tick_handler)(int, void *, struct pt_regs *);
+
+
+int mvme147_kbdrate (struct kbd_repeat *k)
+{
+ return 0;
+}
+
+void mvme147_reset()
+{
+ printk ("\r\n\nCalled mvme147_reset\r\n");
+ m147_pcc->watchdog = 0x0a; /* Clear timer */
+ m147_pcc->watchdog = 0xa5; /* Enable watchdog - 100ms to reset */
+ while (1)
+ ;
+}
+
+static void mvme147_get_model(char *model)
+{
+ sprintf(model, "Motorola MVME147");
+}
+
+
+static int mvme147_get_hardware_list(char *buffer)
+{
+ *buffer = '\0';
+
+ return 0;
+}
+
+
+__initfunc(void config_mvme147(void))
+{
+ mach_sched_init = mvme147_sched_init;
+ mach_keyb_init = mvme147_keyb_init;
+ mach_kbdrate = mvme147_kbdrate;
+ mach_init_IRQ = mvme147_init_IRQ;
+ mach_gettimeoffset = mvme147_gettimeoffset;
+ mach_gettod = mvme147_gettod;
+ mach_hwclk = mvme147_hwclk;
+ mach_set_clock_mmss = mvme147_set_clock_mmss;
+ mach_reset = mvme147_reset;
+ mach_free_irq = mvme147_free_irq;
+ mach_process_int = mvme147_process_int;
+ mach_get_irq_list = mvme147_get_irq_list;
+ mach_request_irq = mvme147_request_irq;
+ enable_irq = mvme147_enable_irq;
+ disable_irq = mvme147_disable_irq;
+ mach_get_model = mvme147_get_model;
+ mach_get_hardware_list = mvme147_get_hardware_list;
+}
+
+
+/* Using pcc tick timer 1 */
+
+static void mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+ m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
+ m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+ tick_handler(irq, dev_id, fp);
+}
+
+
+void mvme147_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+ tick_handler = timer_routine;
+ request_irq (PCC_IRQ_TIMER1, mvme147_timer_int,
+ IRQ_FLG_REPLACE, "timer 1", NULL);
+
+ /* Init the clock with a value */
+ /* our clock goes off every 6.25us */
+ m147_pcc->t1_preload = PCC_TIMER_PRELOAD;
+ m147_pcc->t1_cntrl = 0x0; /* clear timer */
+ m147_pcc->t1_cntrl = 0x3; /* start timer */
+ m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; /* clear pending ints */
+ m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
+}
+
+/* This is always executed with interrupts disabled. */
+/* XXX There are race hazards in this code XXX */
+unsigned long mvme147_gettimeoffset (void)
+{
+ volatile unsigned short *cp = (volatile unsigned short *)0xfffe1012;
+ unsigned short n;
+
+ n = *cp;
+ while (n != *cp)
+ n = *cp;
+
+ n -= PCC_TIMER_PRELOAD;
+ return (unsigned long)n * 25 / 4;
+}
+
+extern void mvme147_gettod (int *year, int *mon, int *day, int *hour,
+ int *min, int *sec)
+{
+ m147_rtc->ctrl = RTC_READ;
+ *year = bcd2int (m147_rtc->bcd_year);
+ *mon = bcd2int (m147_rtc->bcd_mth);
+ *day = bcd2int (m147_rtc->bcd_dom);
+ *hour = bcd2int (m147_rtc->bcd_hr);
+ *min = bcd2int (m147_rtc->bcd_min);
+ *sec = bcd2int (m147_rtc->bcd_sec);
+ m147_rtc->ctrl = 0;
+}
+
+static int bcd2int (unsigned char b)
+{
+ return ((b>>4)*10 + (b&15));
+}
+
+int mvme147_hwclk(int op, struct hwclk_time *t)
+{
+ return 0;
+}
+
+int mvme147_set_clock_mmss (unsigned long nowtime)
+{
+ return 0;
+}
+
+int mvme147_keyb_init (void)
+{
+ return 0;
+}
+
+/*------------------- Serial console stuff ------------------------*/
+
+void m147_scc_write(struct console *co, const char *str, unsigned cnt);
+
+
+void mvme147_init_console_port (struct console *co, int cflag)
+{
+ co->write = m147_scc_write;
+}
+
+
+static void scc_delay (void)
+{
+ int n;
+ volatile int trash;
+
+ for (n = 0; n < 20; n++)
+ trash = n;
+}
+
+static void scc_write (char ch)
+{
+ volatile char *p = (volatile char *)M147_SCC_A_ADDR;
+
+ do {
+ scc_delay();
+ }
+ while (!(*p & 4));
+ scc_delay();
+ *p = 8;
+ scc_delay();
+ *p = ch;
+}
+
+
+void m147_scc_write (struct console *co, const char *str, unsigned count)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ while (count--)
+ {
+ if (*str == '\n')
+ scc_write ('\r');
+ scc_write (*str++);
+ }
+ restore_flags(flags);
+}
+
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index 838c3bbac..db7eb3137 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -335,10 +335,10 @@ void mvme16x_init_console_port (struct console *co, int cflag)
static void scc_delay (void)
{
int n;
- char i;
+ volatile int trash;
for (n = 0; n < 20; n++)
- i = *(volatile char *)0;
+ trash = n;
}
static void scc_write (char ch)
diff --git a/arch/m68k/q40/Makefile b/arch/m68k/q40/Makefile
new file mode 100644
index 000000000..90858884f
--- /dev/null
+++ b/arch/m68k/q40/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/q40 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := q40.o
+O_OBJS := config.o q40ints.o
+
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/q40/README b/arch/m68k/q40/README
new file mode 100644
index 000000000..5433796cb
--- /dev/null
+++ b/arch/m68k/q40/README
@@ -0,0 +1,121 @@
+Linux for the Q40
+=================
+
+You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
+some up to date information. Booter and other tools will be also
+available from this place and ftp.uni-erlangen.de/linux/680x0/q40/
+and mirrors.
+
+Hints to documentation usually refer to the linux source tree in
+/usr/src/linux unless URL given.
+
+It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is
+not yet implemented - do not try it! (See below)
+
+For a list of kernel commandline options read the documentation for the
+particular device drivers.
+
+The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
+When something blocks interrupts (HD) it will loose some of them, so far
+this is not known to have caused any data loss. On hihgly loaded systems
+it can make the floppy very slow. Other Q40 OS' simply poll the floppy
+for this reason - something that can't be done in Linux.
+Only possible cure is getting a 82072 contoler with fifo instead of
+the 8272A
+
+drivers used by the Q40, appart from the very obvious (console etc.):
+ drivers/char/q40_keyb.c # use PC keymaps for national keyboards
+ serial.c # normal PC driver - any speed
+ lp.c # printer driver
+ char/joystick/* # most of this should work
+ block/q40ide.c # startup for ide
+ ide* # see Documentation/ide.txt
+ floppy.c # normal PC driver, DMA emu in asm/floppy.h
+ # and arch/m68k/kernel/entry.S
+ # see drivers/block/README.fd
+ video/q40fb.c
+ misc/parport_pc.c
+
+Various other PC drivers can be enabled simply by adding them to
+arch/m68k/config.in, especially 8 bit devices should be without any
+problems. For cards using 16bit io/mem more care is required, like
+checking byteorder issues, hacking memcpy_*_io etc.
+
+
+Debugging
+=========
+
+Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM,
+preceded by the booter signature. This is a trace just in case something
+went wrong during earliest setup stages.
+*Changed* to preserve SRAM contents by default, this is only done when
+requested - SRAM must start with '%LX$' signature to do this. '-d' option
+to 'lxx' loader enables this.
+
+SRAM can also be used as additional console device, use debug=mem.
+This will save kernel startup msgs into SRAM, the screen will display
+only the penguin - and shell prompt if it gets that far..
+
+Serial console works and can also be used for debugging, provided serial
+initialisation works.
+
+Most problems seem to be caused by fawlty or badly configured io-cards or
+harddrives anyway..there are so many things that can go wrong here.
+Make sure to configure the parallel port as SPP for first testing..the
+Q40 may have trouble with parallel interrupts.
+
+
+Q40 Hardware Description
+========================
+
+This is just an overview, see asm-m68k/* for details ask if you have any
+questions.
+
+The Q40 consists of a 68040@40 MHz, 1MB video RAM, up to 32MB RAM, AT-style
+keyboard interface, 1 Programmable LED, 2 8bit DACs and up to 1MB ROM, 1MB
+shadow ROM.
+
+Most interfacing like floppy, hd, serial, parallel ports is done via ISA
+slots. The ISA io and mem range is mapped (sparse&byteswapped!) into separate
+regions of the memory.
+The main interrupt register IIRQ_REG will indicate whether an IRQ was internal
+or from some ISA devices, EIRQ_REG can distinguish up to 8 ISA IRQs.
+
+The Q40 custom chip is programmable to provide 2 periodic timers:
+ - 50 or 200 Hz - level 2, !!THIS CANT BE DISABLED!!
+ - 10 or 20 KHz - level 4 (and possibly 6 - hardware decoding..)
+
+Linux uses the 200 Hz interrupt for timer and beep by default.
+
+
+Interrupts
+==========
+
+q40 master chip handles only level triggered interrupts :-((
+further limitation is no disabling etc. Unless someone finds
+some ingenious clue this means autoprobing will never work.
+Parallel port interrupts cause most trouble..
+
+IRQ sharing is not yet implemented.
+
+
+Keyboard
+========
+
+q40 receives AT make/break codes from the keyboard, these are translated to
+the PC scancodes x86 Linux uses. So by theory every national keyboard should
+work just by loading the apropriate x86 keytable - see any national-HOWTO.
+
+Unfortunately the AT->PC translation isn't quite trivial and even worse, my
+documentation of it is absolutely minimal - thus some exotic keys may not
+behave exactly as expected.
+
+There is still hope that it can be fixed completely though. If you encounter
+problems, email me idealy this:
+ - exact keypress/release sequence
+ - 'showkey -s' run on q40, non-X session
+ - 'showkey -s' run on a PC, non-X session
+ - AT codes as displayed by the q40 debuging ROM
+btw if the showkey output from PC and Q40 doesn't differ then you have some
+classic configuration problem - don't send me anything in this case
+
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
new file mode 100644
index 000000000..e3c35c60c
--- /dev/null
+++ b/arch/m68k/q40/config.c
@@ -0,0 +1,425 @@
+/*
+ * arch/m68k/q40/config.c
+ *
+ * originally based on:
+ *
+ * linux/bvme/config.c
+ *
+ * Copyright (C) 1993 Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/q40_master.h>
+#include <asm/keyboard.h>
+
+extern void fd_floppy_eject(void);
+extern void fd_floppy_setup(char *str, int *ints);
+
+extern void q40_process_int (int level, struct pt_regs *regs);
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */
+extern void q40_init_IRQ (void);
+extern void q40_free_irq (unsigned int, void *);
+extern int q40_get_irq_list (char *);
+extern void q40_enable_irq (unsigned int);
+extern void q40_disable_irq (unsigned int);
+static void q40_get_model(char *model);
+static int q40_get_hardware_list(char *buffer);
+extern int q40_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
+extern void q40_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern int q40_keyb_init(void);
+extern int q40_kbdrate (struct kbd_repeat *);
+extern unsigned long q40_gettimeoffset (void);
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+ int *min, int *sec);
+extern int q40_hwclk (int, struct hwclk_time *);
+extern int q40_set_clock_mmss (unsigned long);
+extern void q40_reset (void);
+extern void q40_waitbut(void);
+void q40_set_vectors (void);
+extern void (*kd_mksound)(unsigned int, unsigned int);
+void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
+
+extern char *saved_command_line;
+extern char m68k_debug_device[];
+static void q40_mem_console_write(struct console *co, const char *b,
+ unsigned int count);
+
+static int ql_ticks=0;
+static int sound_ticks=0;
+
+static unsigned char bcd2bin (unsigned char b);
+static unsigned char bin2bcd (unsigned char b);
+
+static int q40_wait_key(struct console *co){return 0;}
+static struct console q40_console_driver = {
+ "debug",
+ NULL, /* write */
+ NULL, /* read */
+ NULL, /* device */
+ q40_wait_key, /* wait_key */
+ NULL, /* unblank */
+ NULL, /* setup */
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+
+/* Save tick handler routine pointer, will point to do_timer() in
+ * kernel/sched.c */
+
+/* static void (*tick_handler)(int, void *, struct pt_regs *); */
+
+
+/* early debugging function:*/
+extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
+static int _cpleft;
+
+static void q40_mem_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ char *p=(char *)s;
+
+ if (count<_cpleft)
+ while (count-- >0){
+ *q40_mem_cptr=*p++;
+ q40_mem_cptr+=4;
+ _cpleft--;
+ }
+}
+#if 0
+void printq40(char *str)
+{
+ int l=strlen(str);
+ char *p=q40_mem_cptr;
+
+ while (l-- >0 && _cpleft-- >0)
+ {
+ *p=*str++;
+ p+=4;
+ }
+ q40_mem_cptr=p;
+}
+#endif
+
+#if 0
+int q40_kbdrate (struct kbd_repeat *k)
+{
+ return 0;
+}
+#endif
+
+void q40_reset()
+{
+
+ printk ("\n\n*******************************************\n"
+ "Called q40_reset : press the RESET button!! \n");
+ printk( "*******************************************\n");
+
+ while(1)
+ ;
+}
+
+static void q40_get_model(char *model)
+{
+ sprintf(model, "Q40");
+}
+
+
+/* No hardware options on Q40? */
+
+static int q40_get_hardware_list(char *buffer)
+{
+ *buffer = '\0';
+ return 0;
+}
+
+
+__initfunc(void config_q40(void))
+{
+ mach_sched_init = q40_sched_init; /* ok */
+ /*mach_kbdrate = q40_kbdrate;*/ /* unneeded ?*/
+ mach_keyb_init = q40_keyb_init; /* OK */
+ mach_init_IRQ = q40_init_IRQ;
+ mach_gettimeoffset = q40_gettimeoffset;
+ mach_gettod = q40_gettod;
+ mach_hwclk = q40_hwclk;
+ mach_set_clock_mmss = q40_set_clock_mmss;
+/* mach_mksound = q40_mksound; */
+ mach_reset = q40_reset; /* use reset button instead !*/
+ mach_free_irq = q40_free_irq;
+ mach_process_int = q40_process_int;
+ mach_get_irq_list = q40_get_irq_list;
+ mach_request_irq = q40_request_irq;
+ enable_irq = q40_enable_irq;
+ disable_irq = q40_disable_irq;
+ mach_default_handler = &q40_sys_default_handler;
+ mach_get_model = q40_get_model; /* no use..*/
+ mach_get_hardware_list = q40_get_hardware_list; /* no use */
+ kd_mksound = q40_mksound;
+ /*mach_kbd_leds = q40kbd_leds;*/
+#ifdef CONFIG_MAGIC_SYSRQ
+ mach_sysrq_key = 0x54;
+#endif
+ conswitchp = &dummy_con;
+#ifdef CONFIG_BLK_DEV_FD
+ mach_floppy_setup = fd_floppy_setup;
+ mach_floppy_eject = fd_floppy_eject;
+ /**/
+#endif
+
+ mach_max_dma_address = 0; /* no DMA at all */
+
+
+/* userfull for early debuging stages writes kernel messages into SRAM */
+
+ if (!strncmp( m68k_debug_device,"mem",3 ))
+ {
+ /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+ _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
+ q40_console_driver.write = q40_mem_console_write;
+ register_console(&q40_console_driver);
+ }
+}
+
+
+int q40_parse_bootinfo(const struct bi_record *rec)
+{
+ return 1; /* unknown */
+}
+
+#define DAC_LEFT ((unsigned char *)0xff008000)
+#define DAC_RIGHT ((unsigned char *)0xff008004)
+void q40_mksound(unsigned int hz, unsigned int ticks)
+{
+ /* for now ignore hz, except that hz==0 switches off sound */
+ /* simply alternate the ampl 0-255-0-.. at 200Hz */
+ if (hz==0)
+ {
+ if (sound_ticks)
+ sound_ticks=1; /* atomic - no irq spinlock used */
+
+ *DAC_LEFT=0;
+ *DAC_RIGHT=0;
+
+ return;
+ }
+ /* sound itself is done in q40_timer_int */
+ if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */
+ sound_ticks=ticks<<1;
+}
+
+static void (*q40_timer_routine)(int, void *, struct pt_regs *);
+
+static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if (HZ==10000)
+ master_outb(-1,SAMPLE_CLEAR_REG);
+#else /* must be 50 or 100 */
+ master_outb(-1,FRAME_CLEAR_REG);
+#endif
+
+#if (HZ==100)
+ ql_ticks = ql_ticks ? 0 : 1;
+ if (sound_ticks)
+ {
+ unsigned char sval=(sound_ticks & 1) ? 0 : 255;
+ sound_ticks--;
+ *DAC_LEFT=sval;
+ *DAC_RIGHT=sval;
+ }
+ if (ql_ticks) return;
+#endif
+ q40_timer_routine(irq, dev_id, fp);
+}
+
+
+void q40_sched_init (void (*timer_routine)(int, void *, struct pt_regs *))
+{
+ int timer_irq;
+
+ q40_timer_routine = timer_routine;
+
+#if (HZ==10000)
+ timer_irq=Q40_IRQ_TIMER;
+#else
+ timer_irq=Q40_IRQ_FRAME;
+#endif
+
+ /*printk("registering sched/timer IRQ %d\n", timer_irq);*/
+
+ if (request_irq(timer_irq, q40_timer_int, 0,
+ "timer", q40_timer_int))
+ panic ("Couldn't register timer int");
+
+#if (HZ==10000)
+ master_outb(SAMPLE_LOW,SAMPLE_RATE_REG);
+ master_outb(-1,SAMPLE_CLEAR_REG);
+ master_outb(1,SAMPLE_ENABLE_REG);
+#else
+ master_outb(-1,FRAME_CLEAR_REG); /* not necessary ? */
+#if (HZ==100)
+ master_outb( 1,FRAME_RATE_REG);
+#endif
+#endif
+}
+
+
+unsigned long q40_gettimeoffset (void)
+{
+#if (HZ==100)
+ return 5000*(ql_ticks!=0);
+#else
+ return 0;
+#endif
+}
+
+extern void q40_gettod (int *year, int *mon, int *day, int *hour,
+ int *min, int *sec)
+{
+ RTC_CTRL |= RTC_READ;
+ *year = bcd2bin (RTC_YEAR);
+ *mon = bcd2bin (RTC_MNTH)-1;
+ *day = bcd2bin (RTC_DATE);
+ *hour = bcd2bin (RTC_HOUR);
+ *min = bcd2bin (RTC_MINS);
+ *sec = bcd2bin (RTC_SECS);
+ RTC_CTRL &= ~(RTC_READ);
+
+}
+
+static unsigned char bcd2bin (unsigned char b)
+{
+ return ((b>>4)*10 + (b&15));
+}
+
+static unsigned char bin2bcd (unsigned char b)
+{
+ return (((b/10)*16) + (b%10));
+}
+
+
+/*
+ * Looks like op is non-zero for setting the clock, and zero for
+ * reading the clock.
+ *
+ * struct hwclk_time {
+ * unsigned sec; 0..59
+ * unsigned min; 0..59
+ * unsigned hour; 0..23
+ * unsigned day; 1..31
+ * unsigned mon; 0..11
+ * unsigned year; 00...
+ * int wday; 0..6, 0 is Sunday, -1 means unknown/don't set
+ * };
+ */
+
+int q40_hwclk(int op, struct hwclk_time *t)
+{
+ if (op)
+ { /* Write.... */
+ RTC_CTRL |= RTC_WRITE;
+
+ RTC_SECS = bin2bcd(t->sec);
+ RTC_MINS = bin2bcd(t->min);
+ RTC_HOUR = bin2bcd(t->hour);
+ RTC_DATE = bin2bcd(t->day);
+ RTC_MNTH = bin2bcd(t->mon + 1);
+ RTC_YEAR = bin2bcd(t->year%100);
+ if (t->wday >= 0)
+ RTC_DOW = bin2bcd(t->wday+1);
+
+ RTC_CTRL &= ~(RTC_WRITE);
+ }
+ else
+ { /* Read.... */
+ RTC_CTRL |= RTC_READ;
+
+ t->year = bcd2bin (RTC_YEAR);
+ t->mon = bcd2bin (RTC_MNTH)-1;
+ t->day = bcd2bin (RTC_DATE);
+ t->hour = bcd2bin (RTC_HOUR);
+ t->min = bcd2bin (RTC_MINS);
+ t->sec = bcd2bin (RTC_SECS);
+
+ RTC_CTRL &= ~(RTC_READ);
+
+ if (t->year < 70)
+ t->year += 100;
+ t->wday = bcd2bin(RTC_DOW)-1;
+
+ }
+
+ return 0;
+}
+
+/*
+ * Set the minutes and seconds from seconds value 'nowtime'. Fail if
+ * clock is out by > 30 minutes. Logic lifted from atari code.
+ * Algorithm is to wait for the 10ms register to change, and then to
+ * wait a short while, and then set it.
+ */
+
+int q40_set_clock_mmss (unsigned long nowtime)
+{
+ int retval = 0;
+ short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+ int rtc_minutes;
+
+
+ rtc_minutes = bcd2bin (RTC_MINS);
+
+ if ((rtc_minutes < real_minutes
+ ? real_minutes - rtc_minutes
+ : rtc_minutes - real_minutes) < 30)
+ {
+ RTC_CTRL |= RTC_WRITE;
+ RTC_MINS = bin2bcd(real_minutes);
+ RTC_SECS = bin2bcd(real_seconds);
+ RTC_CTRL &= ~(RTC_WRITE);
+ }
+ else
+ retval = -1;
+
+
+ return retval;
+}
+
+extern void q40kbd_init_hw(void);
+
+int q40_keyb_init (void)
+{
+ q40kbd_init_hw();
+ return 0;
+}
+
+#if 0
+/* dummy to cause */
+void q40_slow_io()
+{
+ return;
+}
+#endif
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
new file mode 100644
index 000000000..e9b5a5b1f
--- /dev/null
+++ b/arch/m68k/q40/q40ints.c
@@ -0,0 +1,347 @@
+/*
+ * arch/m68k/q40/q40ints.c
+ *
+ * Copyright (C) 1999 Richard Zidlicky
+ *
+ * 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.
+ *
+ * losely based on bvme6000ints.c
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+#include <asm/q40_master.h>
+#include <asm/q40ints.h>
+
+/*
+ * Q40 IRQs are defined as follows:
+ * 3,4,5,6,7,10,11,14,15 : ISA dev IRQs
+ * 16-31: reserved
+ * 32 : keyboard int
+ * 33 : frame int (50 Hz periodic timer)
+ * 34 : sample int (10/20 KHz periodic timer)
+ *
+*/
+
+extern int ints_inited;
+
+
+void q40_irq2_handler (int, void *, struct pt_regs *fp);
+
+
+extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
+
+/*
+ * This should ideally be 4 elements only, for speed.
+ */
+
+#define DEVNAME_SIZE 24
+
+static struct {
+ void (*handler)(int, void *, struct pt_regs *);
+ unsigned long flags;
+ void *dev_id;
+ char devname[DEVNAME_SIZE];
+ unsigned count;
+} irq_tab[Q40_IRQ_MAX+1];
+
+/*
+ * void q40_init_IRQ (void)
+ *
+ * Parameters: None
+ *
+ * Returns: Nothing
+ *
+ * This function is called during kernel startup to initialize
+ * the q40 IRQ handling routines.
+ */
+
+void q40_init_IRQ (void)
+{
+ int i;
+
+ for (i = 0; i <= Q40_IRQ_MAX; i++) {
+ irq_tab[i].handler = q40_defhand;
+ irq_tab[i].flags = IRQ_FLG_STD;
+ irq_tab[i].dev_id = NULL;
+ irq_tab[i].devname[0] = 0;
+ irq_tab[i].count = 0;
+ }
+
+ /* setup handler for ISA ints */
+ sys_request_irq(IRQ2,q40_irq2_handler, IRQ_FLG_LOCK, "q40 ISA and master chip", NULL);
+
+ /* now enable some ints.. */
+
+#if 0 /* has been abandoned */
+ master_outb(1,SER_ENABLE_REG);
+#endif
+ master_outb(1,EXT_ENABLE_REG);
+
+ /* would be spurious ints by now, q40kbd_init_hw() does that */
+ master_outb(0,KEY_IRQ_ENABLE_REG);
+}
+
+int q40_request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags, const char *devname, void *dev_id)
+{
+ /*printk("q40_request_irq %d, %s\n",irq,devname);*/
+
+ if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+ printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname);
+ return -ENXIO;
+ }
+
+ /* test for ISA ints not implemented by HW */
+ if (irq<15)
+ {
+ switch (irq){
+ case 1: case 2: case 8: case 9:
+ case 12: case 13:
+ printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
+ return -ENXIO;
+ default:
+ }
+ }
+
+ if (irq<Q40_IRQ_TIMER)
+ {
+ if (irq==11) {
+ printk("warning IRQ 10 and 11 not distinguishable\n");
+ irq=10;
+ }
+ if (!(irq_tab[irq].flags & IRQ_FLG_STD))
+ {
+ if (irq_tab[irq].flags & IRQ_FLG_LOCK)
+ {
+ printk("%s: IRQ %d from %s is not replaceable\n",
+ __FUNCTION__, irq, irq_tab[irq].devname);
+ return -EBUSY;
+ }
+ if (flags & IRQ_FLG_REPLACE)
+ {
+ printk("%s: %s can't replace IRQ %d from %s\n",
+ __FUNCTION__, devname, irq, irq_tab[irq].devname);
+ return -EBUSY;
+ }
+ }
+ /*printk("IRQ %d set to handler %p\n",irq,handler);*/
+ irq_tab[irq].handler = handler;
+ irq_tab[irq].flags = flags;
+ irq_tab[irq].dev_id = dev_id;
+ strncpy(irq_tab[irq].devname,devname,DEVNAME_SIZE);
+ return 0;
+ }
+ else {
+ /* Q40_IRQ_TIMER :somewhat special actions required here ..*/
+ sys_request_irq(4,handler,flags,devname,dev_id);
+ sys_request_irq(6,handler,flags,devname,dev_id);
+ return 0;
+ }
+}
+
+void q40_free_irq(unsigned int irq, void *dev_id)
+{
+ if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) {
+ printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id);
+ return;
+ }
+
+ /* test for ISA ints not implemented by HW */
+ if (irq<15) {
+ switch (irq){
+ case 1: case 2: case 8: case 9:
+ case 12: case 13:
+ printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+ return;
+ default:
+ }
+ }
+
+ if (irq<Q40_IRQ_TIMER){
+ if (irq==11) irq=10;
+ if (irq_tab[irq].dev_id != dev_id)
+ printk("%s: Removing probably wrong IRQ %d from %s\n",
+ __FUNCTION__, irq, irq_tab[irq].devname);
+
+ irq_tab[irq].handler = q40_defhand;
+ irq_tab[irq].flags = IRQ_FLG_STD;
+ irq_tab[irq].dev_id = NULL;
+ /* irq_tab[irq].devname = NULL; */
+ } else { /* == Q40_IRQ_TIMER */
+ sys_free_irq(4,dev_id);
+ sys_free_irq(6,dev_id);
+ }
+}
+
+#if 1
+void q40_process_int (int level, struct pt_regs *fp)
+{
+ printk("unexpected interrupt %x\n",level);
+}
+#endif
+
+/*
+ * tables to translate bits into IRQ numbers
+ * it is a good idea to order the entries by priority
+ *
+*/
+
+struct IRQ_TABLE{ unsigned mask; int irq ;};
+
+static struct IRQ_TABLE iirqs[]={
+ {IRQ_FRAME_MASK,Q40_IRQ_FRAME},
+ {IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
+ {0,0}};
+static struct IRQ_TABLE eirqs[]={
+ {IRQ3_MASK,3}, /* ser 1 */
+ {IRQ4_MASK,4}, /* ser 2 */
+ {IRQ14_MASK,14}, /* IDE 1 */
+ {IRQ15_MASK,15}, /* IDE 2 */
+ {IRQ6_MASK,6}, /* floppy */
+ {IRQ7_MASK,7}, /* par */
+
+ {IRQ5_MASK,5},
+ {IRQ10_MASK,10},
+
+
+
+
+ {0,0}};
+
+/* complaiun only this many times about spurious ints : */
+static int ccleirq=60; /* ISA dev IRQ's*/
+static int cclirq=60; /* internal */
+
+/* FIX: add IRQ_INPROGRESS,mask,unmask,probing.... */
+
+void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
+{
+ /* got level 2 interrupt, dispatch to ISA or keyboard IRQs */
+
+ unsigned mir=master_inb(IIRQ_REG);
+ unsigned mer;
+ int irq,i;
+
+ /*
+ * more than 1 bit might be set, must handle atmost 1 int source,
+ * - handle only those with explicitly set handler
+ */
+
+ if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK))
+ {
+
+ /* some ISA dev caused the int */
+
+ mer=master_inb(EIRQ_REG);
+
+ for (i=0; eirqs[i].mask; i++)
+ {
+ if (mer&(eirqs[i].mask))
+ {
+ irq=eirqs[i].irq;
+ irq_tab[irq].count++;
+ if (irq_tab[irq].handler == q40_defhand )
+ continue; /* ignore uninited INTs :-( */
+
+ irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+ return;
+ }
+ }
+ if (ccleirq>0)
+ printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--;
+ }
+ else
+ {
+ /* internal */
+
+ for (i=0; iirqs[i].mask; i++)
+ {
+ if (mir&(iirqs[i].mask))
+ {
+ irq=iirqs[i].irq;
+ irq_tab[irq].count++;
+ if (irq_tab[irq].handler == q40_defhand )
+ continue; /* ignore uninited INTs :-( */
+
+ irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+ return;
+ }
+ }
+ if (cclirq>0)
+ printk("internal level 2 interrupt from unknown source ? IIRQ_REG=%x\n",mir),cclirq--;
+ }
+}
+
+int q40_get_irq_list (char *buf)
+{
+ int i, len = 0;
+
+ for (i = 0; i <= Q40_IRQ_MAX; i++) {
+ if (irq_tab[i].count)
+ len += sprintf (buf+len, "Vec 0x%02x: %8d %s%s\n",
+ i, irq_tab[i].count,
+ irq_tab[i].devname[0] ? irq_tab[i].devname : "?",
+ irq_tab[i].handler == q40_defhand ?
+ " (now unassigned)" : "");
+ }
+ return len;
+}
+
+
+static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp)
+{
+#if 0
+ printk ("Unknown q40 interrupt 0x%02x\n", irq);
+#endif
+}
+static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
+{
+#if 0
+ if (ints_inited)
+#endif
+ printk ("Uninitialised interrupt level %d\n", lev);
+#if 0
+ else
+ printk ("Interrupt before interrupt initialisation\n");
+#endif
+}
+
+ void (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = {
+ sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler,
+ sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
+ };
+
+void q40_enable_irq (unsigned int irq)
+{
+}
+
+
+void q40_disable_irq (unsigned int irq)
+{
+}
+
+unsigned long q40_probe_irq_on (void)
+{
+ printk("sorry, irq probing not yet implemented - reconfigure the driver to avoid this\n");
+ return 0;
+}
+int q40_probe_irq_off (unsigned long irqs)
+{
+ return -1;
+}
diff --git a/arch/m68k/sun3x/Makefile b/arch/m68k/sun3x/Makefile
new file mode 100644
index 000000000..ba1f2bbd5
--- /dev/null
+++ b/arch/m68k/sun3x/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for Linux arch/m68k/sun3x source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := sun3x.o
+O_OBJS := config.o time.o dvma.o sbus.o
+OX_OBJS :=
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/sun3x/config.c b/arch/m68k/sun3x/config.c
new file mode 100644
index 000000000..5054cd888
--- /dev/null
+++ b/arch/m68k/sun3x/config.c
@@ -0,0 +1,128 @@
+/*
+ * Setup kernel for a Sun3x machine
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * based on code from Oliver Jowett <oliver@jowett.manawatu.gen.nz>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+static volatile unsigned char *sun3x_intreg = (unsigned char *)SUN3X_INTREG;
+extern int serial_console;
+
+void sun3x_halt(void)
+{
+ /* Disable interrupts */
+ cli();
+
+ /* we can't drop back to PROM, so we loop here */
+ for (;;);
+}
+
+void sun3x_reboot(void)
+{
+ /* This never returns, don't bother saving things */
+ cli();
+
+ /* no idea, whether this works */
+ asm ("reset");
+}
+
+__initfunc(int sun3x_keyb_init(void))
+{
+ return 0;
+}
+
+int sun3x_kbdrate(struct kbd_repeat *r)
+{
+ return 0;
+}
+
+void sun3x_kbd_leds(unsigned int i)
+{
+
+}
+
+static void sun3x_badint (int irq, void *dev_id, struct pt_regs *fp)
+{
+ printk ("received spurious interrupt %d\n",irq);
+ num_spurious += 1;
+}
+
+void (*sun3x_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+ sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint,
+ sun3x_badint, sun3x_badint, sun3x_badint, sun3x_badint
+};
+
+void sun3x_enable_irq(unsigned int irq)
+{
+ *sun3x_intreg |= (1 << irq);
+}
+
+void sun3x_disable_irq(unsigned int irq)
+{
+ *sun3x_intreg &= ~(1 << irq);
+}
+
+__initfunc(void sun3x_init_IRQ(void))
+{
+ /* disable all interrupts initially */
+ *sun3x_intreg = 1; /* master enable only */
+}
+
+int sun3x_get_irq_list(char *buf)
+{
+ return 0;
+}
+
+/*
+ * Setup the sun3x configuration info
+ */
+__initfunc(void config_sun3x(void))
+{
+ mach_get_irq_list = sun3x_get_irq_list;
+ mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */
+
+ mach_keyb_init = sun3x_keyb_init;
+ mach_kbdrate = sun3x_kbdrate;
+ mach_kbd_leds = sun3x_kbd_leds;
+
+ mach_sched_init = sun3x_sched_init;
+ mach_init_IRQ = sun3x_init_IRQ;
+ enable_irq = sun3x_enable_irq;
+ disable_irq = sun3x_disable_irq;
+ mach_request_irq = sys_request_irq;
+ mach_free_irq = sys_free_irq;
+ mach_default_handler = &sun3x_default_handler;
+ mach_gettimeoffset = sun3x_gettimeoffset;
+ mach_reset = sun3x_reboot;
+
+ mach_gettod = sun3x_gettod;
+
+ switch (*(unsigned char *)SUN3X_EEPROM_CONS) {
+ case 0x10:
+ serial_console = 1;
+ conswitchp = NULL;
+ break;
+ case 0x11:
+ serial_console = 2;
+ conswitchp = NULL;
+ break;
+ default:
+ serial_console = 0;
+ conswitchp = &dummy_con;
+ break;
+ }
+
+}
diff --git a/arch/m68k/sun3x/dvma.c b/arch/m68k/sun3x/dvma.c
new file mode 100644
index 000000000..9ef3471a2
--- /dev/null
+++ b/arch/m68k/sun3x/dvma.c
@@ -0,0 +1,162 @@
+/*
+ * Virtual DMA allocation
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+
+#include <asm/sun3x.h>
+#include <asm/dvma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+/* IOMMU support */
+
+#define IOMMU_ENTRIES 2048
+#define IOMMU_ADDR_MASK 0x03ffe000
+#define IOMMU_CACHE_INHIBIT 0x00000040
+#define IOMMU_FULL_BLOCK 0x00000020
+#define IOMMU_MODIFIED 0x00000010
+#define IOMMU_USED 0x00000008
+#define IOMMU_WRITE_PROTECT 0x00000004
+#define IOMMU_DT_MASK 0x00000003
+#define IOMMU_DT_INVALID 0x00000000
+#define IOMMU_DT_VALID 0x00000001
+#define IOMMU_DT_BAD 0x00000002
+
+#define DVMA_PAGE_SHIFT 13
+#define DVMA_PAGE_SIZE (1UL << DVMA_PAGE_SHIFT)
+#define DVMA_PAGE_MASK (~(DVMA_PAGE_SIZE-1))
+
+
+static volatile unsigned long *iommu_pte = (unsigned long *)SUN3X_IOMMU;
+static unsigned long iommu_use[IOMMU_ENTRIES];
+static unsigned long iommu_bitmap[IOMMU_ENTRIES/32];
+
+
+#define dvma_entry_paddr(index) (iommu_pte[index] & IOMMU_ADDR_MASK)
+#define dvma_entry_vaddr(index,paddr) ((index << DVMA_PAGE_SHIFT) | \
+ (paddr & (DVMA_PAGE_SIZE-1)))
+#define dvma_entry_set(index,addr) (iommu_pte[index] = \
+ (addr & IOMMU_ADDR_MASK) | \
+ IOMMU_DT_VALID)
+#define dvma_entry_clr(index) (iommu_pte[index] = IOMMU_DT_INVALID)
+#define dvma_entry_use(index) (iommu_use[index])
+#define dvma_entry_inc(index) (iommu_use[index]++)
+#define dvma_entry_dec(index) (iommu_use[index]--)
+#define dvma_entry_hash(addr) ((addr >> DVMA_PAGE_SHIFT) ^ \
+ ((addr & 0x03c00000) >> \
+ (DVMA_PAGE_SHIFT+4)))
+#define dvma_map iommu_bitmap
+#define dvma_map_size (IOMMU_ENTRIES/2)
+#define dvma_slow_offset (IOMMU_ENTRIES/2)
+#define dvma_is_slow(addr) ((addr) & \
+ (dvma_slow_offset << DVMA_PAGE_SHIFT))
+
+static int fixed_dvma;
+
+void __init dvma_init(void)
+{
+ unsigned long tmp;
+
+ if ((unsigned long)high_memory < (IOMMU_ENTRIES << DVMA_PAGE_SHIFT)) {
+ printk ("Sun3x fixed DVMA mapping\n");
+ fixed_dvma = 1;
+ for (tmp = 0; tmp < (unsigned long)high_memory; tmp += DVMA_PAGE_SIZE)
+ dvma_entry_set (tmp >> DVMA_PAGE_SHIFT, virt_to_phys((void *)tmp));
+ fixed_dvma = 1;
+ } else {
+ printk ("Sun3x variable DVMA mapping\n");
+ for (tmp = 0; tmp < IOMMU_ENTRIES; tmp++)
+ dvma_entry_clr (tmp);
+ fixed_dvma = 0;
+ }
+}
+
+unsigned long dvma_slow_alloc (unsigned long paddr, int npages)
+{
+ int scan, base;
+
+ scan = 0;
+ for (;;) {
+ scan = find_next_zero_bit(dvma_map, dvma_map_size, scan);
+ if ((base = scan) + npages > dvma_map_size) {
+ printk ("dvma_slow_alloc failed for %d pages\n",npages);
+ return 0;
+ }
+ for (;;) {
+ if (scan >= base + npages) goto found;
+ if (test_bit(scan, dvma_map)) break;
+ scan++;
+ }
+ }
+
+found:
+ for (scan = base; scan < base+npages; scan++) {
+ dvma_entry_set(scan+dvma_slow_offset, paddr);
+ paddr += DVMA_PAGE_SIZE;
+ set_bit(scan, dvma_map);
+ }
+ return (dvma_entry_vaddr((base+dvma_slow_offset),paddr));
+}
+
+unsigned long dvma_alloc (unsigned long paddr, unsigned long size)
+{
+ int index;
+ int pages = ((paddr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+ DVMA_PAGE_SHIFT;
+
+ if (fixed_dvma)
+ return ((unsigned long)phys_to_virt (paddr));
+
+ if (pages > 1) /* multi page, allocate from slow pool */
+ return dvma_slow_alloc (paddr, pages);
+
+ index = dvma_entry_hash (paddr);
+
+ if (dvma_entry_use(index)) {
+ if (dvma_entry_paddr(index) == (paddr & DVMA_PAGE_MASK)) {
+ dvma_entry_inc(index);
+ return dvma_entry_vaddr(index,paddr);
+ }
+ /* collision, allocate from slow pool */
+ return dvma_slow_alloc (paddr, pages);
+ }
+
+ dvma_entry_set(index,paddr);
+ dvma_entry_inc(index);
+ return dvma_entry_vaddr(index,paddr);
+}
+
+void dvma_free (unsigned long dvma_addr, unsigned long size)
+{
+ int npages;
+ int index;
+
+ if (fixed_dvma)
+ return;
+
+ if (!dvma_is_slow(dvma_addr)) {
+ index = (dvma_addr >> DVMA_PAGE_SHIFT);
+ if (dvma_entry_use(index) == 0) {
+ printk ("dvma_free: %lx entry already free\n",dvma_addr);
+ return;
+ }
+ dvma_entry_dec(index);
+ if (dvma_entry_use(index) == 0)
+ dvma_entry_clr(index);
+ return;
+ }
+
+ /* free in slow pool */
+ npages = ((dvma_addr & ~DVMA_PAGE_MASK) + size + (DVMA_PAGE_SIZE-1)) >>
+ DVMA_PAGE_SHIFT;
+ for (index = (dvma_addr >> DVMA_PAGE_SHIFT); npages--; index++) {
+ dvma_entry_clr(index);
+ clear_bit (index,dvma_map);
+ }
+}
diff --git a/arch/m68k/sun3x/sbus.c b/arch/m68k/sun3x/sbus.c
new file mode 100644
index 000000000..f1a89df65
--- /dev/null
+++ b/arch/m68k/sun3x/sbus.c
@@ -0,0 +1,44 @@
+/*
+ * SBus helper functions
+ *
+ * Sun3x don't have a sbus, but many of the used devices are also
+ * used on Sparc machines with sbus. To avoid having a lot of
+ * duplicate code, we provide necessary glue stuff to make using
+ * of the sbus driver code possible.
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+__initfunc(void sbus_init(void))
+{
+
+}
+
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+ u32 bus_type, int rdonly)
+{
+ return (void *)address;
+}
+
+int prom_getintdefault(int node, char *property, int deflt)
+{
+ return deflt;
+}
+
+int prom_getbool (int node, char *prop)
+{
+ return 1;
+}
+
+void prom_printf(char *fmt, ...)
+{
+
+}
+
+void prom_halt (void)
+{
+
+}
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
new file mode 100644
index 000000000..39fa5f696
--- /dev/null
+++ b/arch/m68k/sun3x/time.c
@@ -0,0 +1,83 @@
+/*
+ * linux/arch/m68k/sun3x/time.c
+ *
+ * Sun3x-specific time handling
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/sun3x.h>
+
+#include "time.h"
+
+#define M_CONTROL 0xf8
+#define M_SEC 0xf9
+#define M_MIN 0xfa
+#define M_HOUR 0xfb
+#define M_DAY 0xfc
+#define M_DATE 0xfd
+#define M_MONTH 0xfe
+#define M_YEAR 0xff
+
+#define C_WRITE 0x80
+#define C_READ 0x40
+#define C_SIGN 0x20
+#define C_CALIB 0x1f
+
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+
+/* Read the Mostek */
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+ int *hourp, int *minp, int *secp)
+{
+ volatile unsigned char *eeprom = (unsigned char *)SUN3X_EEPROM;
+
+ /* Stop updates */
+ *(eeprom + M_CONTROL) |= C_READ;
+
+ /* Read values */
+ *yearp = BCD_TO_BIN(*(eeprom + M_YEAR));
+ *monp = BCD_TO_BIN(*(eeprom + M_MONTH));
+ *dayp = BCD_TO_BIN(*(eeprom + M_DATE));
+ *hourp = BCD_TO_BIN(*(eeprom + M_HOUR));
+ *minp = BCD_TO_BIN(*(eeprom + M_MIN));
+ *secp = BCD_TO_BIN(*(eeprom + M_SEC));
+
+ /* Restart updates */
+ *(eeprom + M_CONTROL) &= ~C_READ;
+}
+
+/* Not much we can do here */
+unsigned long sun3x_gettimeoffset (void)
+{
+ return 0L;
+}
+
+static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
+{
+ void (*vector)(int, void *, struct pt_regs *) = dev_id;
+
+ /* Clear the pending interrupt - pulse the enable line low */
+ disable_irq(5);
+ enable_irq(5);
+
+ vector(irq, NULL, regs);
+}
+
+__initfunc(void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *)))
+{
+ sys_request_irq(5, sun3x_timer_tick, IRQ_FLG_STD, "timer tick", vector);
+
+ /* Pulse enable low to get the clock started */
+ disable_irq(5);
+ enable_irq(5);
+}
diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
new file mode 100644
index 000000000..873742d70
--- /dev/null
+++ b/arch/m68k/sun3x/time.h
@@ -0,0 +1,9 @@
+#ifndef SUN3X_TIME_H
+#define SUN3X_TIME_H
+
+void sun3x_gettod (int *yearp, int *monp, int *dayp,
+ int *hourp, int *minp, int *secp);
+unsigned long sun3x_gettimeoffset (void);
+void sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *));
+
+#endif
diff --git a/arch/mips/config.in b/arch/mips/config.in
index b1a6310b6..aa1aba32f 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -217,7 +217,7 @@ if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS"
mainmenu_option next_comment
- comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+ comment comment 'Old CD-ROM drivers (not SCSI, not IDE)'
bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
@@ -257,6 +257,8 @@ else
endmenu
fi
+# source drivers/usb/Config.in
+
source fs/Config.in
if [ "$CONFIG_VT" = "y" ]; then
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 0b3de2ffe..a24fa46f5 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -11,7 +11,6 @@
# Machine selection
#
# CONFIG_ACER_PICA_61 is not set
-# CONFIG_COBALT_MICRO_SERVER is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI is not set
@@ -35,8 +34,8 @@ CONFIG_CPU_R4X00=y
#
CONFIG_PCI_QUIRKS=y
CONFIG_PCI_OLD_PROC=y
-CONFIG_ELF_KERNEL=y
CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_ELF_KERNEL=y
# CONFIG_BINFMT_AOUT is not set
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
@@ -91,7 +90,6 @@ CONFIG_PARIDE_PARPORT=y
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -108,7 +106,6 @@ CONFIG_INET=y
# (it is safe to leave these untouched)
#
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
# CONFIG_SKB_LARGE is not set
#
@@ -160,9 +157,12 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_NCR53C7xx is not set
CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
CONFIG_SCSI_NCR53C8XX_SYNC=20
@@ -174,6 +174,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
@@ -239,7 +240,7 @@ CONFIG_PCNET32=y
# CONFIG_ISDN is not set
#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# comment
#
# CONFIG_CD_NO_IDESCSI is not set
@@ -267,6 +268,7 @@ CONFIG_RTC=y
# Joystick support
#
# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
#
# Ftape, the floppy tape device driver
@@ -311,6 +313,7 @@ CONFIG_LOCKD=m
#
# CONFIG_BSD_DISKLABEL is not set
# CONFIG_MAC_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
CONFIG_NLS=y
@@ -351,6 +354,10 @@ CONFIG_NLS_KOI8_R=m
#
CONFIG_VGA_CONSOLE=y
# CONFIG_FB is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
#
# Sound
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index a0e141759..38fab1e16 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -1,4 +1,4 @@
-/* $Id: irixelf.c,v 1.16 1998/10/28 12:38:11 ralf Exp $
+/* $Id: irixelf.c,v 1.15 1999/01/04 16:03:48 ralf Exp $
*
* irixelf.c: Code to load IRIX ELF executables which conform to
* the MIPS ABI.
@@ -1123,7 +1123,7 @@ static int writenote(struct memelfnote *men, struct file *file)
static int irix_core_dump(long signr, struct pt_regs * regs)
{
int has_dumped = 0;
- struct file file;
+ struct file *file;
struct dentry *dentry;
struct inode *inode;
mm_segment_t fs;
@@ -1192,30 +1192,28 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
fs = get_fs();
set_fs(KERNEL_DS);
+
memcpy(corefile,"core.", 5);
#if 0
memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
corefile[4] = '\0';
#endif
- dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
- if (IS_ERR(dentry)) {
- inode = NULL;
+ file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
+ if (IS_ERR(file))
goto end_coredump;
- }
+ dentry = file->f_dentry;
inode = dentry->d_inode;
-
- if(inode->i_nlink > 1)
- goto end_coredump; /* multiple links - don't dump */
+ if (inode->i_nlink > 1)
+ goto close_coredump; /* multiple links - don't dump */
if (!S_ISREG(inode->i_mode))
- goto end_coredump;
+ goto close_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
- goto end_coredump;
- if (init_private_file(&file, dentry, 3))
- goto end_coredump;
- if (!file.f_op->write)
goto close_coredump;
+ if (!file->f_op->write)
+ goto close_coredump;
+
has_dumped = 1;
current->flags |= PF_DUMPCORE;
@@ -1351,7 +1349,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
}
for(i = 0; i < numnote; i++)
- if (!writenote(&notes[i], &file))
+ if (!writenote(&notes[i], file))
goto close_coredump;
set_fs(fs);
@@ -1373,19 +1371,17 @@ static int irix_core_dump(long signr, struct pt_regs * regs)
DUMP_WRITE((void *)addr, len);
}
- if ((off_t) file.f_pos != offset) {
+ if ((off_t) file->f_pos != offset) {
/* Sanity check. */
- printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
- (off_t) file.f_pos, offset);
+ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
+ (off_t) file->f_pos, offset);
}
close_coredump:
- if (file.f_op->release)
- file.f_op->release(inode, &file);
+ filp_close(file, NULL);
end_coredump:
set_fs(fs);
- dput(dentry);
#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
#endif
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 6fb6735fd..71dd05e75 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -1,4 +1,4 @@
-/* $Id: ptrace.c,v 1.10 1999/01/03 17:50:52 ralf Exp $
+/* $Id: ptrace.c,v 1.11 1999/02/15 02:16:51 ralf Exp $
*
* 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
@@ -259,6 +259,7 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
+ unsigned int flags;
int res;
lock_kernel();
@@ -297,22 +298,26 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
(current->uid != child->uid) ||
(current->gid != child->egid) ||
(current->gid != child->sgid) ||
- (current->gid != child->gid)) &&
- !capable(CAP_SYS_PTRACE)) {
+ (current->gid != child->gid) ||
+ (!cap_issubset(child->cap_permitted,
+ current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)){
res = -EPERM;
goto out;
}
/* the same process cannot be attached many times */
- if (child->flags & PF_PTRACED) {
- res = -EPERM;
+ if (child->flags & PF_PTRACED)
goto out;
- }
child->flags |= PF_PTRACED;
+
+ write_lock_irqsave(&tasklist_lock, flags);
if (child->p_pptr != current) {
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
}
+ write_unlock_irqrestore(&tasklist_lock, flags);
+
send_sig(SIGSTOP, child, 1);
res = 0;
goto out;
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 4b8698d3b..faac180d1 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -1,7 +1,9 @@
-/* $Id: $
+/* $Id: r2300_switch.S,v 1.5 1999/04/11 17:13:56 harald Exp $
+ *
* r2300_switch.S: R2300 specific task switching code.
*
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
+ * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996 by Andreas Busse
*
* Multi-cpu abstraction and macros for easier reading:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -28,19 +30,23 @@
.set mips1
.align 5
+/*
+ * task_struct *r4xx0_resume(task_struct *prev,
+ * task_struct *next)
+ */
LEAF(r2300_resume)
.set reorder
mfc0 t1, CP0_STATUS
.set noreorder
- sw t1, THREAD_STATUS($28)
- CPU_SAVE_NONSCRATCH($28)
- sw ra, THREAD_REG31($28)
+ sw t1, THREAD_STATUS(a0)
+ CPU_SAVE_NONSCRATCH(a0)
+ sw ra, THREAD_REG31(a0)
/*
* The order of restoring the registers takes care of the race
* updating $28, $29 and kernelsp without disabling ints.
*/
- move $28, a0
+ move $28, a1
CPU_RESTORE_NONSCRATCH($28)
addiu t0, $28, KERNEL_STACK_SIZE-32
sw t0, kernelsp
@@ -55,8 +61,9 @@ LEAF(r2300_resume)
lw a3, MM_CONTEXT(a3)
mtc0 a2, CP0_STATUS
andi a3, 0xfc0
+ mtc0 a3, CP0_ENTRYHI
jr ra
- mtc0 a3, CP0_ENTRYHI
+ move v0, a0
END(r2300_resume)
/*
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index afc1591f5..3ba84bb9a 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -1,10 +1,10 @@
-/* $Id: r4k_switch.S,v 1.5 1999/05/01 10:08:18 harald Exp $
+/* $Id: r4k_switch.S,v 1.6 1999/05/01 22:40:37 ralf Exp $
*
* 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) 1994, 1995, 1996, 1998 by Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996, 1998, 1999 by Ralf Baechle
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* Copyright (C) 1994, 1995, 1996, by Andreas Busse
*/
@@ -24,20 +24,24 @@
#include <asm/asmmacro.h>
+/*
+ * task_struct *r4xx0_resume(task_struct *prev,
+ * task_struct *next)
+ */
.set noreorder
.set mips3
.align 5
LEAF(r4xx0_resume)
mfc0 t1, CP0_STATUS
- sw t1, THREAD_STATUS($28)
- CPU_SAVE_NONSCRATCH($28)
- sw ra, THREAD_REG31($28)
+ sw t1, THREAD_STATUS(a0)
+ CPU_SAVE_NONSCRATCH(a0)
+ sw ra, THREAD_REG31(a0)
/*
* The order of restoring the registers takes care of the race
* updating $28, $29 and kernelsp without disabling ints.
*/
- move $28, a0
+ move $28, a1
CPU_RESTORE_NONSCRATCH($28)
addiu t0, $28, KERNEL_STACK_SIZE-32
sw t0, kernelsp
@@ -52,8 +56,9 @@
lw a3, MM_CONTEXT(a3)
mtc0 a2, CP0_STATUS
andi a3, a3, 0xff
+ mtc0 a3, CP0_ENTRYHI
jr ra
- mtc0 a3, CP0_ENTRYHI
+ move v0, a0
END(r4xx0_resume)
/*
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index b3336d864..5464524f6 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.17 1999/05/01 21:54:19 ralf Exp $
+/* $Id: sysirix.c,v 1.18 1999/05/01 22:40:38 ralf Exp $
*
* sysirix.c: IRIX system call emulation.
*
@@ -628,7 +628,6 @@ asmlinkage int irix_stime(int value)
cli();
xtime.tv_sec = value;
xtime.tv_usec = 0;
- time_state = TIME_ERROR;
time_maxerror = MAXPHASE;
time_esterror = MAXPHASE;
sti();
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 1491da82d..ecb89b755 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.10 1999/02/01 01:26:32 ralf Exp $
+/* $Id: time.c,v 1.11 1999/02/15 02:16:53 ralf Exp $
*
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
* Copyright (C) 1996, 1997, 1998 Ralf Baechle
@@ -255,7 +255,6 @@ void do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
sti();
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 1d2cd9647..b6c219169 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.18 1999/04/12 19:13:21 harald Exp $
+/* $Id: traps.c,v 1.19 1999/05/01 22:40:38 ralf Exp $
*
* 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
@@ -464,8 +464,8 @@ extern asmlinkage void r4k_restore_fp_context(struct sigcontext *sc);
extern asmlinkage void r2300_restore_fp_context(struct sigcontext *sc);
extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc);
-extern asmlinkage void r4xx0_resume(void *tsk);
-extern asmlinkage void r2300_resume(void *tsk);
+extern asmlinkage void *r4xx0_resume(void *last, void *next);
+extern asmlinkage void *r2300_resume(void *last, void *next);
__initfunc(void trap_init(void))
{
diff --git a/arch/mips/mm/loadmmu.c b/arch/mips/mm/loadmmu.c
index 82f6793c1..6142d82c5 100644
--- a/arch/mips/mm/loadmmu.c
+++ b/arch/mips/mm/loadmmu.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: loadmmu.c,v 1.7 1998/04/05 11:23:55 ralf Exp $
+ * $Id: loadmmu.c,v 1.8 1999/04/11 17:13:56 harald Exp $
*/
#include <linux/init.h>
#include <linux/kernel.h>
@@ -53,7 +53,7 @@ void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1,
int (*user_mode)(struct pt_regs *);
-asmlinkage void (*resume)(void *tsk);
+asmlinkage void *(*resume)(void *last, void *next);
extern void ld_mmu_r2300(void);
extern void ld_mmu_r4xx0(void);
diff --git a/arch/mips/sgi/kernel/indy_timer.c b/arch/mips/sgi/kernel/indy_timer.c
index 0920b9d2c..11980d75a 100644
--- a/arch/mips/sgi/kernel/indy_timer.c
+++ b/arch/mips/sgi/kernel/indy_timer.c
@@ -1,4 +1,4 @@
-/* $Id: indy_timer.c,v 1.10 1998/08/25 09:14:49 ralf Exp $
+/* $Id: indy_timer.c,v 1.11 1999/01/04 16:03:56 ralf Exp $
*
* indy_timer.c: Setting up the clock on the INDY 8254 controller.
*
@@ -104,9 +104,10 @@ void indy_timer_interrupt(struct pt_regs *regs)
* absolutely sure we do this update within 500ms before the
* next second starts, thus the following code.
*/
- if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - (tick >> 1) &&
+ xtime.tv_usec <= 500000 + (tick >> 1))
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
index b1ea955ed..707f3c97c 100644
--- a/arch/ppc/8xx_io/commproc.c
+++ b/arch/ppc/8xx_io/commproc.c
@@ -111,7 +111,12 @@ m8xx_cpm_reset(uint host_page_addr)
*/
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr =
(CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
- ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
+ (((5)/2) << 13) | CICR_HP_MASK;
+ /* I hard coded the CPM interrupt to 5 above
+ * since the CPM_INTERRUPT define is relative to
+ * the linux irq structure not what the hardware
+ * belives. -- Cort
+ */
((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0;
/* Set our interrupt handler with the core CPU.
*/
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 126b724be..1c71f473f 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -1,5 +1,4 @@
/*
- * $Id: enet.c,v 1.8 1998/11/15 19:58:07 cort Exp $
* Ethernet driver for Motorola MPC8xx.
* Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
*
@@ -22,6 +21,7 @@
* small packets.
*
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -39,7 +39,7 @@
#include <asm/8xx_immap.h>
#include <asm/pgtable.h>
-#include <asm/mbx.h>
+#include <asm/fads.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include "commproc.h"
@@ -49,7 +49,7 @@
*
* The MPC8xx CPM performs the Ethernet processing on SCC1. It can use
* an aribtrary number of buffers on byte boundaries, but must have at
- * least two receive buffers to prevent constand overrun conditions.
+ * least two receive buffers to prevent constant overrun conditions.
*
* The buffer descriptors are allocated from the CPM dual port memory
* with the data buffers allocated from host memory, just like all other
@@ -94,6 +94,17 @@
* Port C, 15 - SCC1 Ethernet Tx Enable
* Port C, 11 - SCC1 Ethernet Collision
* Port C, 10 - SCC1 Ethernet Rx Enable
+ *
+ * The RPX-Lite (that I had :-), was the MPC850SAR. It has a control
+ * register to enable Ethernet functions in the 68160, and the Ethernet
+ * was controlled by SCC2. So, the pin I/O was like this:
+ * Port A, 13 - SCC2 Ethernet Rx
+ * Port A, 12 - SCC2 Ethernet Tx
+ * Port A, 6 (CLK2) - Ethernet Tx Clk
+ * Port A, 4 (CLK4) - Ethernet Rx Clk
+ * Port B, 18 (RTS2) - Ethernet Tx Enable
+ * Port C, 8 (CD2) - Ethernet Rx Enable
+ * Port C, 9 (CTS2) - SCC Ethernet Collision
*/
/* The number of Tx and Rx buffers. These are allocated from the page
@@ -149,10 +160,26 @@ static int cpm_enet_close(struct device *dev);
static struct net_device_stats *cpm_enet_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev);
-/* GET THIS FROM THE VPD!!!!
+/* Get this from various configuration locations (depends on board).
*/
/*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/
+/* Right now, only the boards with an 860 use SCC1 for the Ethernet.
+ * All others use SCC2. We may need to make this board specific someday.
+ */
+#ifndef CONFIG_MPC860
+/*static ushort my_enet_addr[] = { 0x2700, 0x00ec, 0x1000 };*/
+#define CPM_CR_ENET CPM_CR_CH_SCC2
+#define PROFF_ENET PROFF_SCC2
+#define SCC_ENET 1 /* Index, not number! */
+#define CPMVEC_ENET CPMVEC_SCC2
+#else
+#define CPM_CR_ENET CPM_CR_CH_SCC1
+#define PROFF_ENET PROFF_SCC1
+#define SCC_ENET 0
+#define CPMVEC_ENET CPMVEC_SCC1
+#endif
+
static int
cpm_enet_open(struct device *dev)
{
@@ -178,7 +205,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
/* Transmitter timeout, serious problems. */
if (dev->tbusy) {
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 20)
+ if (tickssofar < 200)
return 1;
printk("%s: transmit timed out.\n", dev->name);
cep->stats.tx_errors++;
@@ -186,17 +213,17 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
{
int i;
cbd_t *bdp;
- printk(" Ring data dump: cur_tx %x%s cur_rx %x.\n",
+ printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
cep->cur_tx, cep->tx_full ? " (full)" : "",
cep->cur_rx);
bdp = cep->tx_bd_base;
- for (i = 0 ; i < TX_RING_SIZE; i++)
+ for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
printk("%04x %04x %08x\n",
bdp->cbd_sc,
bdp->cbd_datlen,
bdp->cbd_bufaddr);
bdp = cep->rx_bd_base;
- for (i = 0 ; i < RX_RING_SIZE; i++)
+ for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
printk("%04x %04x %08x\n",
bdp->cbd_sc,
bdp->cbd_datlen,
@@ -263,7 +290,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
/* Push the data cache so the CPM does not get stale memory
* data.
*/
- /*flush_dcache_range(skb->data, skb->data + skb->len);*/
+ flush_dcache_range(skb->data, skb->data + skb->len);
/* Send it on its way. Tell CPM its ready, interrupt when done,
* its the last BD of the frame, and to put the CRC on the end.
@@ -300,7 +327,7 @@ static void
cpm_enet_interrupt(void *dev_id)
{
struct device *dev = dev_id;
- struct cpm_enet_private *cep;
+ volatile struct cpm_enet_private *cep;
volatile cbd_t *bdp;
ushort int_events;
int must_restart;
@@ -314,6 +341,7 @@ cpm_enet_interrupt(void *dev_id)
/* Get the interrupt events that caused us to be here.
*/
int_events = cep->sccp->scc_scce;
+ cep->sccp->scc_scce = int_events;
must_restart = 0;
/* Handle receive event in its own function.
@@ -329,6 +357,7 @@ cpm_enet_interrupt(void *dev_id)
* I don't know if "normally" implies TXB is set when the buffer
* descriptor is closed.....trial and error :-).
*/
+#if 0
if (int_events & SCCE_ENET_TXE) {
/* Transmission errors.
@@ -359,16 +388,46 @@ cpm_enet_interrupt(void *dev_id)
(BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN))
must_restart = 1;
}
+#endif
/* Transmit OK, or non-fatal error. Update the buffer descriptors.
*/
if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
+#if 1
+ bdp = cep->dirty_tx;
+ while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
+ if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
+ break;
+
+ if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */
+ cep->stats.tx_heartbeat_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */
+ cep->stats.tx_window_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */
+ cep->stats.tx_aborted_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */
+ cep->stats.tx_fifo_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
+ cep->stats.tx_carrier_errors++;
+
+
+ /* No heartbeat or Lost carrier are not really bad errors.
+ * The others require a restart transmit command.
+ */
+ if (bdp->cbd_sc &
+ (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {
+ must_restart = 1;
+ cep->stats.tx_errors++;
+ }
+
cep->stats.tx_packets++;
+#else
bdp = cep->dirty_tx;
-#ifndef final_version
+#if 1
if (bdp->cbd_sc & BD_ENET_TX_READY)
printk("HEY! Enet xmit interrupt and TX_READY.\n");
#endif
+#endif
/* Deferred means some collisions occurred during transmit,
* but we eventually sent the packet OK.
*/
@@ -406,9 +465,9 @@ cpm_enet_interrupt(void *dev_id)
}
cep->dirty_tx = (cbd_t *)bdp;
- }
+ }
- if (must_restart) {
+ if (must_restart) {
volatile cpm8xx_t *cp;
/* Some transmit errors cause the transmitter to shut
@@ -419,8 +478,9 @@ cpm_enet_interrupt(void *dev_id)
*/
cp = cpmp;
cp->cp_cpcr =
- mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+ mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
+ }
}
/* Check for receive busy, i.e. packets coming but no place to
@@ -432,11 +492,6 @@ cpm_enet_interrupt(void *dev_id)
printk("CPM ENET: BSY can't happen.\n");
}
- /* Write the SCC event register with the events we have handled
- * to clear them. Maybe we should do this sooner?
- */
- cep->sccp->scc_scce = int_events;
-
dev->interrupt = 0;
return;
@@ -576,7 +631,7 @@ static void set_multicast_list(struct device *dev)
int i, j;
cep = (struct cpm_enet_private *)dev->priv;
- /* Get pointer to SCC1 area in parameter RAM.
+ /* Get pointer to SCC area in parameter RAM.
*/
ep = (scc_enet_t *)dev->base_addr;
@@ -627,7 +682,7 @@ static void set_multicast_list(struct device *dev)
/* Ask CPM to run CRC and set bit in
* filter mask.
*/
- cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_SET_GADDR) | CPM_CR_FLG;
+ cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_SET_GADDR) | CPM_CR_FLG;
/* this delay is necessary here -- Cort */
udelay(10);
while (cpmp->cp_cpcr & CPM_CR_FLG);
@@ -636,13 +691,15 @@ static void set_multicast_list(struct device *dev)
}
}
-/* Initialize the CPM Ethernet on SCC1. If EPPC-Bug loaded us, or performed
+/* Initialize the CPM Ethernet on SCC. If EPPC-Bug loaded us, or performed
* some other network I/O, a whole bunch of this has already been set up.
* It is no big deal if we do it again, we just have to disable the
* transmit and receive to make sure we don't catch the CPM with some
* inconsistent control information.
*/
-__initfunc(int cpm_enet_init(void))
+/* until this gets cleared up -- Cort */
+int __init cpm_enet_init() { m8xx_enet_init(); }
+int __init m8xx_enet_init(void)
{
struct device *dev;
struct cpm_enet_private *cep;
@@ -650,6 +707,7 @@ __initfunc(int cpm_enet_init(void))
unsigned char *eap;
unsigned long mem_addr;
pte_t *pte;
+ bd_t *bd;
volatile cbd_t *bdp;
volatile cpm8xx_t *cp;
volatile scc_t *sccp;
@@ -660,6 +718,8 @@ __initfunc(int cpm_enet_init(void))
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
+ bd = (bd_t *)res;
+
/* Allocate some private information.
*/
cep = (struct cpm_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
@@ -670,13 +730,13 @@ __initfunc(int cpm_enet_init(void))
*/
dev = init_etherdev(0, 0);
- /* Get pointer to SCC1 area in parameter RAM.
+ /* Get pointer to SCC area in parameter RAM.
*/
- ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_SCC1]);
+ ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_ENET]);
/* And another to the SCC register area.
*/
- sccp = (volatile scc_t *)(&cp->cp_scc[0]);
+ sccp = (volatile scc_t *)(&cp->cp_scc[SCC_ENET]);
cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */
/* Disable receive and transmit in case EPPC-Bug started it.
@@ -686,6 +746,9 @@ __initfunc(int cpm_enet_init(void))
/* Cookbook style from the MPC860 manual.....
* Not all of this is necessary if EPPC-Bug has initialized
* the network.
+ * So far we are lucky, all board configurations use the same
+ * pins, or at least the same I/O Port for these functions.....
+ * It can't last though......
*/
/* Configure port A pins for Txd and Rxd.
@@ -706,7 +769,7 @@ __initfunc(int cpm_enet_init(void))
immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
/* Configure Serial Interface clock routing.
- * First, clear all SCC1 bits to zero, then set the ones we want.
+ * First, clear all SCC bits to zero, then set the ones we want.
*/
cp->cp_sicr &= ~SICR_ENET_MASK;
cp->cp_sicr |= SICR_ENET_CLKRT;
@@ -731,13 +794,13 @@ __initfunc(int cpm_enet_init(void))
cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
cep->cur_rx = cep->rx_bd_base;
- /* Issue init Rx BD command for SCC1.
+ /* Issue init Rx BD command for SCC.
* Manual says to perform an Init Rx parameters here. We have
* to perform both Rx and Tx because the SCC may have been
* already running.
* In addition, we have to do it later because we don't yet have
* all of the BD control/status set properly.
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_RX) | CPM_CR_FLG;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
*/
@@ -781,20 +844,17 @@ __initfunc(int cpm_enet_init(void))
ep->sen_iaddr3 = 0;
ep->sen_iaddr4 = 0;
- /* Set Ethernet station address. This must come from the
- * Vital Product Data (VPD) EEPROM.....as soon as I get the
- * I2C interface working.....
+ /* Set Ethernet station address.
*
- * Since we performed a diskless boot, the Ethernet controller
+ * If we performed a MBX diskless boot, the Ethernet controller
* has been initialized and we copy the address out into our
* own structure.
*/
-#ifdef notdef
- ep->sen_paddrh = my_enet_addr[0];
- ep->sen_paddrm = my_enet_addr[1];
- ep->sen_paddrl = my_enet_addr[2];
-#else
eap = (unsigned char *)&(ep->sen_paddrh);
+#ifndef CONFIG_MBX
+ for (i=5; i>=0; i--)
+ *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
+#else
for (i=5; i>=0; i--)
dev->dev_addr[i] = *eap++;
#endif
@@ -854,7 +914,7 @@ __initfunc(int cpm_enet_init(void))
* than the manual describes because we have just now finished
* the BD initialization.
*/
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
cep->skb_cur = cep->skb_dirty = 0;
@@ -869,7 +929,7 @@ __initfunc(int cpm_enet_init(void))
/* Install our interrupt handler.
*/
- cpm_install_handler(CPMVEC_SCC1, cpm_enet_interrupt, dev);
+ cpm_install_handler(CPMVEC_ENET, cpm_enet_interrupt, dev);
/* Set GSMR_H to enable all normal operating modes.
* Set GSMR_L to enable Ethernet to MC68160.
@@ -884,12 +944,42 @@ __initfunc(int cpm_enet_init(void))
/* Set processing mode. Use Ethernet CRC, catch broadcast, and
* start frame search 22 bit times after RENA.
*/
- sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_BRO | SCC_PMSR_NIB22);
+ sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_NIB22);
/* It is now OK to enable the Ethernet transmitter.
- */
+ * Unfortunately, there are board implementation differences here.
+ */
+#ifdef CONFIG_MBX
immap->im_ioport.iop_pcpar |= PC_ENET_TENA;
immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
+#endif
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+ cp->cp_pbpar |= PB_ENET_TENA;
+ cp->cp_pbdir |= PB_ENET_TENA;
+
+ /* And while we are here, set the configuration to enable ethernet.
+ */
+ *((volatile uint *)RPX_CSR_ADDR) &= ~BCSR0_ETHLPBK;
+ *((volatile uint *)RPX_CSR_ADDR) |=
+ (BCSR0_ETHEN | BCSR0_COLTESTDIS | BCSR0_FULLDPLXDIS);
+#endif
+
+#ifdef CONFIG_BSEIP
+ cp->cp_pbpar |= PB_ENET_TENA;
+ cp->cp_pbdir |= PB_ENET_TENA;
+
+ /* BSE uses port B and C for PHY control.
+ */
+ cp->cp_pbpar &= ~(PB_BSE_POWERUP | PB_BSE_FDXDIS);
+ cp->cp_pbdir |= (PB_BSE_POWERUP | PB_BSE_FDXDIS);
+ cp->cp_pbdat |= (PB_BSE_POWERUP | PB_BSE_FDXDIS);
+
+ immap->im_ioport.iop_pcpar &= ~PC_BSE_LOOPBACK;
+ immap->im_ioport.iop_pcdir |= PC_BSE_LOOPBACK;
+ immap->im_ioport.iop_pcso &= ~PC_BSE_LOOPBACK;
+ immap->im_ioport.iop_pcdat &= ~PC_BSE_LOOPBACK;
+#endif
dev->base_addr = (unsigned long)ep;
dev->priv = cep;
@@ -913,3 +1003,4 @@ __initfunc(int cpm_enet_init(void))
return 0;
}
+
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 990b24b84..d865053c4 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -45,6 +45,7 @@ endif
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
MAKECOFFBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
MAKECHRPBOOT = $(MAKE) -C arch/$(ARCH)/chrpboot
+MAKEMBXBOOT = $(MAKE) -C arch/$(ARCH)/mbxboot
ifdef CONFIG_8xx
SUBDIRS += arch/ppc/8xx_io
@@ -63,10 +64,16 @@ checks:
BOOT_TARGETS = netboot znetboot zImage floppy install \
vmlinux.coff znetboot.initrd zImage.initrd vmlinux.coff.initrd
+ifdef CONFIG_MBX
+$(BOOT_TARGETS): $(CHECKS) vmlinux
+ @$(MAKECOFFBOOT) $@
+ @$(MAKEMBXBOOT) $@
+else
$(BOOT_TARGETS): $(CHECKS) vmlinux
@$(MAKECOFFBOOT) $@
@$(MAKEBOOT) $@
@$(MAKECHRPBOOT) $@
+endif
pmac_config:
rm -f .config arch/ppc/defconfig
@@ -100,10 +107,10 @@ archclean:
@$(MAKECOFFBOOT) clean
@$(MAKEBOOT) clean
@$(MAKECHRPBOOT) clean
+ @$(MAKEMBXBOOT) clean
archmrproper:
archdep:
$(MAKEBOOT) fastdep
$(MAKECHRPBOOT) fastdep
-
diff --git a/arch/ppc/apus_defconfig b/arch/ppc/apus_defconfig
index c9f900cfe..5e75d496a 100644
--- a/arch/ppc/apus_defconfig
+++ b/arch/ppc/apus_defconfig
@@ -100,7 +100,6 @@ CONFIG_NETLINK=y
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index da4945fd7..5a83e79ee 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -14,7 +14,7 @@
.s.o:
$(AS) -o $*.o $<
.c.o:
- $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
+ $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
.S.s:
$(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
.S.o:
@@ -25,17 +25,14 @@ ZSZ = 0
IOFF = 0
ISZ = 0
-ifeq ($(CONFIG_ALL_PPC),y)
-# yes, we want to build prep stuff
-CONFIG_PREP = y
-endif
-
-ifeq ($(CONFIG_MBX),y)
-ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
+ifeq ($(CONFIG_SMP),y)
+TFTPIMAGE=/tftpboot/zImage.prep.smp
else
-ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00600000
+TFTPIMAGE=/tftpboot/zImage.prep
endif
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
+
GZIP_FLAGS = -v9
OBJECTS := head.o misc.o ../coffboot/zlib.o
@@ -43,19 +40,13 @@ CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O elf32-powerpc
-ifeq ($(CONFIG_MBX),y)
-OBJECTS += mbxtty.o
-CFLAGS += -DCONFIG_MBX
-else
-OBJECTS += vreset.o kbd.o
+OBJECTS += vreset.o kbd.o of1275.o
ifeq ($(CONFIG_SERIAL_CONSOLE),y)
OBJECTS += ns16550.o
endif
-endif
all: zImage
-ifeq ($(CONFIG_PREP),y)
zvmlinux.initrd: zvmlinux
$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
@@ -66,54 +57,19 @@ zvmlinux.initrd: zvmlinux
-DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \
-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \
-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \
- -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
- $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
- $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
- --add-section=initrd=ramdisk.image.gz \
- --add-section=image=../coffboot/vmlinux.gz \
- zvmlinux.initrd.tmp $@
- rm zvmlinux.initrd.tmp
-endif
-ifeq ($(CONFIG_MBX),y)
-zvmlinux.initrd: zvmlinux
- $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
- $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
- --add-section=initrd=ramdisk.image.gz \
- --add-section=image=../coffboot/vmlinux.gz \
- zvmlinux.initrd.tmp zvmlinux.initrd
- $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \
- -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \
- -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \
- -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \
- -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
+ -c -o misc.o misc.c
$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
--add-section=initrd=ramdisk.image.gz \
--add-section=image=../coffboot/vmlinux.gz \
zvmlinux.initrd.tmp $@
rm zvmlinux.initrd.tmp
-endif
-ifeq ($(CONFIG_PREP),y)
zImage: zvmlinux mkprep
./mkprep -pbp zvmlinux zImage
-else
-ifeq ($(CONFIG_MBX),y)
-zImage: zvmlinux
- ln -sf zvmlinux zImage
-else
-zImage:
-endif
-endif
-ifeq ($(CONFIG_PREP),y)
zImage.initrd: zvmlinux.initrd mkprep
./mkprep -pbp zvmlinux.initrd zImage.initrd
-endif
-ifeq ($(CONFIG_MBX),y)
-zImage.initrd: zvmlinux.initrd
- ln -sf zvmlinux.initrd zImage.initrd
-endif
zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
#
@@ -128,7 +84,7 @@ zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
#
$(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \
- -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
+ -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \
-c -o misc.o misc.c
$(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
@@ -136,34 +92,16 @@ zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
rm zvmlinux.tmp
floppy: $(TOPDIR)/vmlinux zImage
-ifeq ($(CONFIG_PREP),y)
dd if=zImage of=/dev/fd0H1440 bs=64b
-endif
-ifeq ($(CONFIG_PREP),y)
mkprep : mkprep.c
- $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c
-endif
+ $(HOSTCC) -o mkprep mkprep.c
-ifeq ($(CONFIG_PREP),y)
znetboot : zImage
- cp zImage /tftpboot/zImage.prep
-else
-ifeq ($(CONFIG_MBX),y)
-znetboot : zImage
- cp zImage /tftpboot/zImage.mbx
-else
-znetboot :
-endif
-endif
+ cp zImage $(TFTPIMAGE)
znetboot.initrd : zImage.initrd
-ifeq ($(CONFIG_PREP),y)
- cp zImage.initrd /tftpboot/zImage.prep
-endif
-ifeq ($(CONFIG_MBX),y)
- cp zImage.initrd /tftpboot/zImage.mbx
-endif
+ cp zImage.initrd $(TFTPIMAGE)
clean:
rm -f vmlinux* zvmlinux* mkprep zImage*
diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S
index 43facf7e2..552e82fa1 100644
--- a/arch/ppc/boot/head.S
+++ b/arch/ppc/boot/head.S
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include "../kernel/ppc_defs.h"
#include "../kernel/ppc_asm.tmpl"
#include <asm/processor.h>
@@ -7,43 +6,24 @@
.text
/*
- * $Id: head.S,v 1.26 1998/09/19 01:21:20 cort Exp $
+ * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $
*
- * This code is loaded by the ROM loader at some arbitrary location.
- * Move it to high memory so that it can load the kernel at 0x0000.
- *
- * The MBX EPPC-Bug understands ELF, so it loads us into the location
- * specified in the header. This is a two step process. First, EPPC-Bug
- * loads the file into the intermediate buffer memory location specified
- * by the environment parameters. When it discovers this is an ELF
- * binary, it relocates to the link address for us. Unfortunately, the
- * header does not move with the file, so we have to find the
- * intermediate load location and read the header from there. From
- * information provided by Motorola (thank you), we know this intermediate
- * location can be found from the NVRAM environment.
- * All of these addresses must be somewhat carefully chosen to make sure
- * we don't overlap the regions. I chose to load the kernel at 0, the
- * compressed image loads at 0x00100000, and the MBX intermediate buffer
- * was set to 0x00200000. Provided the loaded kernel image never grows
- * over one megabyte (which I am going to ensure never happens :-), these
- * will work fine. When we get called from EPPC-Bug, registers are:
- * R1 - Stack pointer at a high memory address.
- * R3 - Pointer to Board Information Block.
- * R4 - Pointer to argument string.
- * Interrupts masked, cache and MMU disabled.
+ * Boot loader philosophy:
+ * ROM loads us to some arbitrary location
+ * Move the boot code to the link address (8M)
+ * Call decompress_kernel()
+ * Relocate the initrd, zimage and residual data to 8M
+ * Decompress the kernel to 0
+ * Jump to the kernel entry
+ * -- Cort
*/
-
.globl start
start:
bl start_
start_:
mr r11,r3 /* Save pointer to residual/board data */
-
-#ifndef CONFIG_MBX
- mfmsr r3 /* Turn off interrupts */
- li r4,0
- ori r4,r4,MSR_EE
- andc r3,r3,r4
+ mr r25,r5 /* Save OFW pointer */
+ li r3,MSR_IP /* Establish default MSR value */
mtmsr r3
/* check if we need to relocate ourselves to the link addr or were we
@@ -68,25 +48,6 @@ start_:
mr r7,r5
b start_ldr
1010:
-#if 0
-/* Copy relocation code down to location 0x0100 (where we hope it's safe!) */
- mflr r3
- addi r5,r3,start_ldr-start_
- addi r3,r3,relocate-start_
- li r4,0x0100
- mtctr r4
- subi r3,r3,4
- subi r4,r4,4
-00: lwzu r6,4(r3)
- stwu r6,4(r4)
- cmp 0,r3,r5
- bne 00b
- mflr r21
- mfctr r22
- mtlr r21
- mtctr r22
- bctr /* Jump to code */
-#endif
/*
* no matter where we're loaded, move ourselves to -Ttext address
*/
@@ -96,13 +57,8 @@ relocate:
mr r8,r3
lis r4,start@h
ori r4,r4,start@l
-#if 0
- lis r5,edata@h
- ori r5,r5,edata@l
-#else
lis r5,end@h
ori r5,r5,end@l
-#endif
addi r5,r5,3 /* Round up - just in case */
sub r5,r5,r4 /* Compute # longwords to move */
srwi r5,r5,2
@@ -120,7 +76,6 @@ relocate:
mtlr r3 /* Easiest way to do an absolute jump */
blr
start_ldr:
-#endif /* ndef CONFIG_MBX */
/* Clear all of BSS */
lis r3,edata@h
ori r3,r3,edata@l
@@ -140,31 +95,11 @@ start_ldr:
li r2,0x000F /* Mask pointer to 16-byte boundary */
andc r1,r1,r2
/* Run loader */
-#ifdef CONFIG_MBX
- mr r3, r11
- mr r21, r11
- bl serial_init /* Init MBX serial port */
-
- lis r8, 0xfa200000@h /* Disable Ethernet SCC */
- li r0, 0
- stw r0, 0x0a00(r8)
-
- mr r11, r21
- lis r8,start@h
- ori r8,r8,start@l
- li r9,end@h
- ori r9,r9,end@l
- sub r7,r8,r9
- srwi r7,r7,2
-#define ILAP_ADDRESS 0xfa000020
- lis r8, ILAP_ADDRESS@h
- lwz r8, ILAP_ADDRESS@l(r8)
- addis r8, r8, 1 /* Add 64K */
-#endif
mr r3,r8 /* Load point */
mr r4,r7 /* Program length */
mr r5,r6 /* Checksum */
mr r6,r11 /* Residual data */
+ mr r7,r25 /* OFW interfaces */
bl decompress_kernel
/* changed to use r3 (as firmware does) for kernel
@@ -193,12 +128,24 @@ start_ldr:
li r9,0x0
lwz r9,0(r9)
mtlr r9
-#ifndef CONFIG_MBX
li r9,0
lis r10,0xdeadc0de@h
ori r10,r10,0xdeadc0de@l
stw r10,0(r9)
-#endif
+/*
+ * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2
+ * so disable BATs before setting this to avoid a clash
+ */
+ li r8,0
+ mtspr DBAT0U,r8
+ mtspr DBAT1U,r8
+ mtspr DBAT2U,r8
+ mtspr DBAT3U,r8
+ mtspr IBAT0U,r8
+ mtspr IBAT1U,r8
+ mtspr IBAT2U,r8
+ mtspr IBAT3U,r8
+
blr
hang:
b hang
@@ -269,7 +216,6 @@ _put_MSR:
_GLOBAL(flush_instruction_cache)
mflr r5
bl flush_data_cache
-#ifndef CONFIG_MBX
mfspr r3,HID0 /* Caches are controlled by this register */
li r4,0
ori r4,r4,(HID0_ICE|HID0_ICFI)
@@ -278,18 +224,12 @@ _GLOBAL(flush_instruction_cache)
andc r3,r3,r4
ori r3,r3,HID0_ICE /* Enable cache */
mtspr HID0,r3
-#endif
mtlr r5
blr
#define NUM_CACHE_LINES 128*8
#define CACHE_LINE_SIZE 32
-#if 0
-cache_flush_buffer:
- .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
-#else
#define cache_flush_buffer 0x1000
-#endif
/*
* Flush data cache
@@ -300,11 +240,7 @@ _GLOBAL(flush_data_cache)
ori r3,r3,cache_flush_buffer@l
li r4,NUM_CACHE_LINES
mtctr r4
-#if 0
-00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
-#else
00: lwz r4,0(r3)
-#endif
addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
bdnz 00b
10: blr
diff --git a/arch/ppc/boot/kbd.c b/arch/ppc/boot/kbd.c
index 9f5cd330b..49a102e9c 100644
--- a/arch/ppc/boot/kbd.c
+++ b/arch/ppc/boot/kbd.c
@@ -1,7 +1,6 @@
-
#include <linux/keyboard.h>
-#include <../drivers/char/defkeymap.c> /* yeah I know it's bad */
+#include <../drivers/char/defkeymap.c> /* yeah I know it's bad -- Cort */
unsigned char shfts, ctls, alts, caps;
@@ -119,7 +118,7 @@ enter: /* Wait for key up */
}
break;
}
- if (brk) return (0); /* Ignore initial 'key up' codes */
+ if (brk) return (-1); /* Ignore initial 'key up' codes */
goto loop;
}
@@ -128,6 +127,11 @@ static void kbdreset(void)
unsigned char c;
int i;
+ /* flush input queue */
+ while ((inb(KBSTATP) & KBINRDY))
+ {
+ (void)inb(KBDATAP);
+ }
/* Send self-test */
while (inb(KBSTATP) & KBOUTRDY) ;
outb(KBSTATP,0xAA);
@@ -144,22 +148,63 @@ static void kbdreset(void)
while (inb(KBSTATP) & KBOUTRDY) ;
outb(KBDATAP,0x45);
for (i = 0; i < 10000; i++) udelay(1);
+
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBSTATP,0x20);
+ while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */
+ if (! (inb(KBDATAP) & 0x40)) {
+ /*
+ * Quote from PS/2 System Reference Manual:
+ *
+ * "Address hex 0060 and address hex 0064 should be
+ * written only when the input-buffer-full bit and
+ * output-buffer-full bit in the Controller Status
+ * register are set 0." (KBINRDY and KBOUTRDY)
+ */
+
+ while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ;
+ outb(KBDATAP,0xF0);
+ while (inb(KBSTATP) & (KBINRDY | KBOUTRDY)) ;
+ outb(KBDATAP,0x01);
+ }
+
while (inb(KBSTATP) & KBOUTRDY) ;
outb(KBSTATP,0xAE);
}
+/* We have to actually read the keyboard when CRT_tstc is called,
+ * since the pending data might be a key release code, and therefore
+ * not valid data. In this case, kbd() will return -1, even though there's
+ * data to be read. Of course, we might actually read a valid key press,
+ * in which case it gets queued into key_pending for use by CRT_getc.
+ */
+
static int kbd_reset = 0;
+static int key_pending = -1;
+
int CRT_getc(void)
{
int c;
if (!kbd_reset) {kbdreset(); kbd_reset++; }
+
+ if (key_pending != -1) {
+ c = key_pending;
+ key_pending = -1;
+ return c;
+ } else {
while ((c = kbd(0)) == 0) ;
- return(c);
+ return c;
+ }
}
int CRT_tstc(void)
{
if (!kbd_reset) {kbdreset(); kbd_reset++; }
- return ((inb(KBSTATP) & KBINRDY) != 0);
+
+ while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
+ key_pending = kbd(1);
+ }
+
+ return (key_pending != -1);
}
diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c
index 470e1e4a9..15d347df5 100644
--- a/arch/ppc/boot/misc.c
+++ b/arch/ppc/boot/misc.c
@@ -1,7 +1,7 @@
/*
* misc.c
*
- * $Id: misc.c,v 1.53 1998/12/15 17:40:15 cort Exp $
+ * $Id: misc.c,v 1.64 1999/04/30 05:52:46 cort Exp $
*
* Adapted for PowerPC by Gary Thomas
*
@@ -17,13 +17,7 @@
#include <asm/page.h>
#include <asm/processor.h>
#include <asm/mmu.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
-#ifdef CONFIG_FADS
-#include <asm/fads.h>
-#endif
-#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+#if defined(CONFIG_SERIAL_CONSOLE)
#include "ns16550.h"
struct NS16550 *com_port;
#endif /* CONFIG_SERIAL_CONSOLE */
@@ -37,30 +31,18 @@ struct NS16550 *com_port;
*/
char *avail_ram;
char *end_avail;
+extern char _end[];
-/* Because of the limited amount of memory on the MBX, it presents
- * loading problems. The biggest is that we load this boot program
- * into a relatively low memory address, and the Linux kernel Bss often
- * extends into this space when it get loaded. When the kernel starts
- * and zeros the BSS space, it also writes over the information we
- * save here and pass to the kernel (command line and board info).
- * On the MBX we grab some known memory holes to hold this information.
- */
-char cmd_preset[] = "console=tty0 console=ttyS0,9600n8";
-char cmd_buf[256];
-char *cmd_line = cmd_buf;
-
-#if defined(CONFIG_MBX) || defined(CONFIG_FADS)
-char *root_string = "root=/dev/nfs";
-char *nfsaddrs_string = "nfsaddrs=";
-char *nfsroot_string = "nfsroot=";
-char *defroot_string = "/sys/mbxroot";
-int do_ipaddrs(char **cmd_cp, int echo);
-void do_nfsroot(char **cmd_cp, char *dp);
-int strncmp(const char * cs,const char * ct,size_t count);
-char *strrchr(const char * s, int c);
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
+#else
+#define CMDLINE "";
#endif
+char cmd_preset[] = CMDLINE;
+char cmd_buf[256];
+char *cmd_line = cmd_buf;
+int keyb_present = 1; /* keyboard controller is present by default */
RESIDUAL hold_resid_buf;
RESIDUAL *hold_residual = &hold_resid_buf;
unsigned long initrd_start = 0, initrd_end = 0;
@@ -78,6 +60,8 @@ void _bcopy(char *src, char *dst, int len);
void * memcpy(void * __dest, __const void * __src,
int __n);
void gunzip(void *, int, unsigned char *, int *);
+static int _cvt(unsigned long val, char *buf, long radix, char *digits);
+unsigned char inb(int);
void pause()
{
@@ -90,7 +74,6 @@ void exit()
while(1);
}
-#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS)
static void clear_screen()
{
int i, j;
@@ -113,8 +96,11 @@ static void scroll()
tstc(void)
{
-#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
- return (CRT_tstc() || NS16550_tstc(com_port));
+#if defined(CONFIG_SERIAL_CONSOLE)
+ if (keyb_present)
+ return (CRT_tstc() || NS16550_tstc(com_port));
+ else
+ NS16550_tstc(com_port);
#else
return (CRT_tstc() );
#endif /* CONFIG_SERIAL_CONSOLE */
@@ -123,10 +109,11 @@ tstc(void)
getc(void)
{
while (1) {
-#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+#if defined(CONFIG_SERIAL_CONSOLE)
if (NS16550_tstc(com_port)) return (NS16550_getc(com_port));
#endif /* CONFIG_SERIAL_CONSOLE */
- if (CRT_tstc()) return (CRT_getc());
+ if (keyb_present)
+ if (CRT_tstc()) return (CRT_getc());
}
}
@@ -135,7 +122,7 @@ putc(const char c)
{
int x,y;
-#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+#if defined(CONFIG_SERIAL_CONSOLE)
NS16550_putc(com_port, c);
if ( c == '\n' ) NS16550_putc(com_port, '\r');
#endif /* CONFIG_SERIAL_CONSOLE */
@@ -149,6 +136,8 @@ putc(const char c)
scroll();
y--;
}
+ } else if (c == '\r') {
+ x = 0;
} else if (c == '\b') {
if (x > 0) {
x--;
@@ -179,7 +168,7 @@ void puts(const char *s)
y = orig_y;
while ( ( c = *s++ ) != '\0' ) {
-#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+#if defined(CONFIG_SERIAL_CONSOLE)
NS16550_putc(com_port, c);
if ( c == '\n' ) NS16550_putc(com_port, '\r');
#endif /* CONFIG_SERIAL_CONSOLE */
@@ -206,42 +195,11 @@ void puts(const char *s)
}
}
+ cursor(x, y);
+
orig_x = x;
orig_y = y;
}
-#else
-/* The MBX is just the serial port.
-*/
-tstc(void)
-{
- return (serial_tstc());
-}
-
-getc(void)
-{
- while (1) {
- if (serial_tstc()) return (serial_getc());
- }
-}
-
-void
-putc(const char c)
-{
- serial_putchar(c);
-}
-
-void puts(const char *s)
-{
- char c;
-
- while ( ( c = *s++ ) != '\0' ) {
- serial_putchar(c);
- if ( c == '\n' )
- serial_putchar('\r');
- }
-}
-
-#endif /* CONFIG_MBX */
void * memcpy(void * __dest, __const void * __src,
int __n)
@@ -354,7 +312,8 @@ void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
unsigned char sanity[0x2000];
unsigned long
-decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
+decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+ RESIDUAL *residual, void *OFW_interface)
{
int timer;
extern unsigned long start;
@@ -362,9 +321,13 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
unsigned long i;
BATU *u;
BATL *l;
-#if defined(CONFIG_MBX) || defined(CONFIG_KB)
- char *dp;
-#endif
+ unsigned long TotalMemory;
+ unsigned long orig_MSR;
+ int dev_handle;
+ int mem_info[2];
+ int res, size;
+ unsigned char board_type;
+ unsigned char base_mod;
lines = 25;
cols = 80;
@@ -372,7 +335,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
orig_y = 24;
-#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS)
/*
* IBM's have the MMU on, so we have to disable it or
* things get really unhappy in the kernel when
@@ -381,42 +343,79 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
*/
flush_instruction_cache();
_put_HID0(_get_HID0() & ~0x0000C000);
- _put_MSR(_get_MSR() & ~0x0030);
- vga_init(0xC0000000);
+ _put_MSR((orig_MSR = _get_MSR()) & ~0x0030);
-#if defined(CONFIG_SERIAL_CONSOLE) && !defined(CONFIG_MBX)
+#if defined(CONFIG_SERIAL_CONSOLE)
com_port = (struct NS16550 *)NS16550_init(0);
#endif /* CONFIG_SERIAL_CONSOLE */
+ vga_init(0xC0000000);
if (residual)
- memcpy(hold_residual,residual,sizeof(RESIDUAL));
-#else /* CONFIG_MBX */
-
- /* Grab some space for the command line and board info. Since
- * we no longer use the ELF header, but it was loaded, grab
- * that space.
- */
- cmd_line = (char *)(load_addr - 0x10000);
- hold_residual = (RESIDUAL *)(cmd_line + sizeof(cmd_buf));
- /* copy board data */
- if (residual)
- memcpy(hold_residual,residual,sizeof(bd_t));
-#endif /* CONFIG_MBX */
+ {
+ /* Is this Motorola PPCBug? */
+ if ((1 & residual->VitalProductData.FirmwareSupports) &&
+ (1 == residual->VitalProductData.FirmwareSupplier)) {
+ board_type = inb(0x800) & 0xF0;
- /* MBX/prep sometimes put the residual/board info at the end of mem
- * assume 16M for now -- Cort
- * To boot on standard MBX boards with 4M, we can't use initrd,
- * and we have to assume less memory. -- Dan
- */
- if ( INITRD_OFFSET )
- end_avail = (char *)0x01000000;
- else
- end_avail = (char *)0x00400000;
+ /* If this is genesis 2 board then check for no
+ * keyboard controller and more than one processor.
+ */
+ if (board_type == 0xe0) {
+ base_mod = inb(0x803);
+ /* if a MVME2300/2400 or a Sitka then no keyboard */
+ if((base_mod == 0x9) || (base_mod == 0xF9) ||
+ (base_mod == 0xE1)) {
+ keyb_present = 0; /* no keyboard */
+ }
+ }
+ }
+ memcpy(hold_residual,residual,sizeof(RESIDUAL));
+ } else {
+ /* Assume 32M in the absence of more info... */
+ TotalMemory = 0x02000000;
+ /*
+ * This is a 'best guess' check. We want to make sure
+ * we don't try this on a PReP box without OF
+ * -- Cort
+ */
+ while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) )
+ {
+ /* The MMU needs to be on when we call OFW */
+ _put_MSR(orig_MSR);
+ of_init(OFW_interface);
+
+ /* get handle to memory description */
+ res = of_finddevice("/memory@0",
+ &dev_handle);
+ // puthex(res); puts("\n");
+ if (res) break;
+
+ /* get the info */
+ // puts("get info = ");
+ res = of_getprop(dev_handle,
+ "reg",
+ mem_info,
+ sizeof(mem_info),
+ &size);
+ // puthex(res); puts(", info = "); puthex(mem_info[0]);
+ // puts(" "); puthex(mem_info[1]); puts("\n");
+ if (res) break;
+
+ TotalMemory = mem_info[1];
+ break;
+ }
+ hold_residual->TotalMemory = TotalMemory;
+ residual = hold_residual;
+ /* Turn MMU back off */
+ _put_MSR(orig_MSR & ~0x0030);
+ }
- /* let residual data tell us it's higher */
- if ( (unsigned long)residual > 0x00800000 )
- end_avail = (char *)PAGE_ALIGN((unsigned long)residual);
+ /* assume the chunk below 8M is free */
+ end_avail = (char *)0x00800000;
+ /* tell the user where we were loaded at and where we
+ * were relocated to for debugging this process
+ */
puts("loaded at: "); puthex(load_addr);
puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
if ( (unsigned long)load_addr != (unsigned long)&start )
@@ -431,20 +430,12 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
{
puts("board data at: "); puthex((unsigned long)residual);
puts(" ");
-#if defined(CONFIG_MBX) || defined(CONFIG_FADS)
- puthex((unsigned long)((unsigned long)residual + sizeof(bd_t)));
-#else
puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL)));
-#endif
puts("\n");
puts("relocated to: ");
puthex((unsigned long)hold_residual);
puts(" ");
-#if defined(CONFIG_MBX) || defined(CONFIG_FADS)
- puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t)));
-#else
puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL)));
-#endif
puts("\n");
}
@@ -460,33 +451,16 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
initrd_end = INITRD_SIZE + initrd_start;
/*
- * setup avail_ram - this is the first part of ram usable
- * by the uncompress code. -- Cort
+ * Find a place to stick the zimage and initrd and
+ * relocate them if we have to. -- Cort
*/
- avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size);
- if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram)
- && (load_addr <= 0x01000000) )
- avail_ram = (char *)(load_addr+(num_words*4));
- if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram)
- && (load_addr <= 0x01000000) )
- avail_ram = (char *)((unsigned long)&start+(num_words*4));
-
- /* relocate zimage */
+ avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
puts("zimage at: "); puthex((unsigned long)zimage_start);
puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
- /*
- * don't relocate the zimage if it was loaded above 16M since
- * things get weird if we try to relocate -- Cort
- * We don't relocate zimage on a base MBX board because of
- * insufficient memory. In this case we don't have initrd either,
- * so use that as an indicator. -- Dan
- */
- if (( (unsigned long)zimage_start <= 0x01000000 ) && initrd_start)
+ if ( (unsigned long)zimage_start <= 0x00800000 )
{
- memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size),
- (void *)zimage_start, zimage_size );
- zimage_start = (char *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size);
- end_avail = (char *)zimage_start;
+ memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size );
+ zimage_start = (char *)avail_ram;
puts("relocated to: "); puthex((unsigned long)zimage_start);
puts(" ");
puthex((unsigned long)zimage_size+(unsigned long)zimage_start);
@@ -498,44 +472,24 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
{
puts("initrd at: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
- /*
- * Memory is really tight on the MBX (we can assume 4M)
- * so put the initrd at the TOP of ram, and set end_avail
- * to right after that.
- *
- * I should do something like this for prep, too and keep
- * a variable end_of_DRAM to keep track of what we think the
- * max ram is.
- * -- Cort
- */
-#if 0
- memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE),
- (void *)initrd_start,
- INITRD_SIZE );
- initrd_start = PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE);
+#ifdef OMIT
+ avail_ram = (char *)PAGE_ALIGN(
+ (unsigned long)zimage_size+(unsigned long)zimage_start);
+ memcpy ((void *)avail_ram, (void *)initrd_start, INITRD_SIZE );
+ initrd_start = (unsigned long)avail_ram;
initrd_end = initrd_start + INITRD_SIZE;
- end_avail = (char *)initrd_start;
puts("relocated to: "); puthex(initrd_start);
puts(" "); puthex(initrd_end); puts("\n");
-#endif
+#endif
}
-#ifndef CONFIG_MBX
- /* this is safe, just use it */
- /* I don't know why it didn't work for me on the MBX with 20 MB
- * memory. I guess something was saved up there, but I can't
- * figure it out......we are running on luck. -- Dan.
- */
avail_ram = (char *)0x00400000;
- end_avail = (char *)0x00600000;
-#endif
+ end_avail = (char *)0x00800000;
puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" ");
puthex((unsigned long)end_avail); puts("\n");
-
-#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS)
- CRT_tstc(); /* Forces keyboard to be initialized */
-#endif
+ if (keyb_present)
+ CRT_tstc(); /* Forces keyboard to be initialized */
puts("\nLinux/PPC load: ");
timer = 0;
@@ -550,13 +504,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
cp--;
puts("\b \b");
}
-#ifdef CONFIG_MBX
- } else if (ch == '?') {
- if (!do_ipaddrs(&cp, 1)) {
- *cp++ = ch;
- putc(ch);
- }
-#endif
} else {
*cp++ = ch;
putc(ch);
@@ -567,32 +514,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
udelay(1000); /* 1 msec */
}
*cp = 0;
-#ifdef CONFIG_MBX
- /* The MBX does not currently have any default boot strategy.
- * If the command line is not filled in, we will automatically
- * create the default network boot.
- */
- if (cmd_line[0] == 0) {
- dp = root_string;
- while (*dp != 0)
- *cp++ = *dp++;
- *cp++ = ' ';
-
- dp = nfsaddrs_string;
- while (*dp != 0)
- *cp++ = *dp++;
- dp = cp;
- do_ipaddrs(&cp, 0);
- *cp++ = ' ';
-
- /* Add the server address to the root file system path.
- */
- dp = strrchr(dp, ':');
- dp++;
- do_nfsroot(&cp, dp);
- *cp = 0;
- }
-#endif
puts("\n");
/* mappings on early boot can only handle 16M */
@@ -611,150 +532,6 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
return (unsigned long)hold_residual;
}
-#ifdef CONFIG_MBX
-int
-do_ipaddrs(char **cmd_cp, int echo)
-{
- char *cp, *ip, ch;
- unsigned char ipd;
- int i, j, retval;
-
- /* We need to create the string:
- * <my_ip>:<serv_ip>
- */
- cp = *cmd_cp;
- retval = 0;
-
- if ((cp - 9) >= cmd_line) {
- if (strncmp(cp - 9, "nfsaddrs=", 9) == 0) {
- ip = (char *)0xfa000060;
- retval = 1;
- for (j=0; j<2; j++) {
- for (i=0; i<4; i++) {
- ipd = *ip++;
-
- ch = ipd/100;
- if (ch) {
- ch += '0';
- if (echo)
- putc(ch);
- *cp++ = ch;
- ipd -= 100 * (ch - '0');
- }
-
- ch = ipd/10;
- if (ch) {
- ch += '0';
- if (echo)
- putc(ch);
- *cp++ = ch;
- ipd -= 10 * (ch - '0');
- }
-
- ch = ipd + '0';
- if (echo)
- putc(ch);
- *cp++ = ch;
-
- ch = '.';
- if (echo)
- putc(ch);
- *cp++ = ch;
- }
-
- /* At the end of the string, remove the
- * '.' and replace it with a ':'.
- */
- *(cp - 1) = ':';
- if (echo) {
- putc('\b'); putc(':');
- }
- }
-
- /* At the end of the second string, remove the
- * '.' from both the command line and the
- * screen.
- */
- --cp;
- putc('\b'); putc(' '); putc('\b');
- }
- }
- *cmd_cp = cp;
- return(retval);
-}
-
-void
-do_nfsroot(char **cmd_cp, char *dp)
-{
- char *cp, *rp, *ep;
-
- /* The boot argument (i.e /sys/mbxroot/zImage) is stored
- * at offset 0x0078 in NVRAM. We use this path name to
- * construct the root file system path.
- */
- cp = *cmd_cp;
-
- /* build command string.
- */
- rp = nfsroot_string;
- while (*rp != 0)
- *cp++ = *rp++;
-
- /* Add the server address to the path.
- */
- while (*dp != ' ')
- *cp++ = *dp++;
- *cp++ = ':';
-
- rp = (char *)0xfa000078;
- ep = strrchr(rp, '/');
-
- if (ep != 0) {
- while (rp < ep)
- *cp++ = *rp++;
- }
- else {
- rp = defroot_string;
- while (*rp != 0)
- *cp++ = *rp++;
- }
-
- *cmd_cp = cp;
-}
-
-size_t strlen(const char * s)
-{
- const char *sc;
-
- for (sc = s; *sc != '\0'; ++sc)
- /* nothing */;
- return sc - s;
-}
-
-int strncmp(const char * cs,const char * ct,size_t count)
-{
- register signed char __res = 0;
-
- while (count) {
- if ((__res = *cs - *ct++) != 0 || !*cs++)
- break;
- count--;
- }
-
- return __res;
-}
-
-char * strrchr(const char * s, int c)
-{
- const char *p = s + strlen(s);
- do {
- if (*p == (char)c)
- return (char *)p;
- } while (--p >= s);
- return NULL;
-}
-#endif
-
void puthex(unsigned long val)
{
unsigned char buf[10];
@@ -802,3 +579,243 @@ _bcopy(char *src, char *dst, int len)
{
while (len--) *dst++ = *src++;
}
+
+
+#define FALSE 0
+#define TRUE 1
+#include <stdarg.h>
+
+int
+strlen(char *s)
+{
+ int len = 0;
+ while (*s++) len++;
+ return len;
+}
+
+_printk(char const *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = _vprintk(putc, fmt, ap);
+ va_end(ap);
+ return (ret);
+}
+
+#define is_digit(c) ((c >= '0') && (c <= '9'))
+
+int
+_vprintk(putc, fmt0, ap)
+int (*putc)();
+const char *fmt0;
+va_list ap;
+{
+ char c, sign, *cp;
+ int left_prec, right_prec, zero_fill, length, pad, pad_on_right;
+ char buf[32];
+ long val;
+ while (c = *fmt0++)
+ {
+ if (c == '%')
+ {
+ c = *fmt0++;
+ left_prec = right_prec = pad_on_right = 0;
+ if (c == '-')
+ {
+ c = *fmt0++;
+ pad_on_right++;
+ }
+ if (c == '0')
+ {
+ zero_fill = TRUE;
+ c = *fmt0++;
+ } else
+ {
+ zero_fill = FALSE;
+ }
+ while (is_digit(c))
+ {
+ left_prec = (left_prec * 10) + (c - '0');
+ c = *fmt0++;
+ }
+ if (c == '.')
+ {
+ c = *fmt0++;
+ zero_fill++;
+ while (is_digit(c))
+ {
+ right_prec = (right_prec * 10) + (c - '0');
+ c = *fmt0++;
+ }
+ } else
+ {
+ right_prec = left_prec;
+ }
+ sign = '\0';
+ switch (c)
+ {
+ case 'd':
+ case 'x':
+ case 'X':
+ val = va_arg(ap, long);
+ switch (c)
+ {
+ case 'd':
+ if (val < 0)
+ {
+ sign = '-';
+ val = -val;
+ }
+ length = _cvt(val, buf, 10, "0123456789");
+ break;
+ case 'x':
+ length = _cvt(val, buf, 16, "0123456789abcdef");
+ break;
+ case 'X':
+ length = _cvt(val, buf, 16, "0123456789ABCDEF");
+ break;
+ }
+ cp = buf;
+ break;
+ case 's':
+ cp = va_arg(ap, char *);
+ length = strlen(cp);
+ break;
+ case 'c':
+ c = va_arg(ap, long /*char*/);
+ (*putc)(c);
+ continue;
+ default:
+ (*putc)('?');
+ }
+ pad = left_prec - length;
+ if (sign != '\0')
+ {
+ pad--;
+ }
+ if (zero_fill)
+ {
+ c = '0';
+ if (sign != '\0')
+ {
+ (*putc)(sign);
+ sign = '\0';
+ }
+ } else
+ {
+ c = ' ';
+ }
+ if (!pad_on_right)
+ {
+ while (pad-- > 0)
+ {
+ (*putc)(c);
+ }
+ }
+ if (sign != '\0')
+ {
+ (*putc)(sign);
+ }
+ while (length-- > 0)
+ {
+ (*putc)(c = *cp++);
+ if (c == '\n')
+ {
+ (*putc)('\r');
+ }
+ }
+ if (pad_on_right)
+ {
+ while (pad-- > 0)
+ {
+ (*putc)(c);
+ }
+ }
+ } else
+ {
+ (*putc)(c);
+ if (c == '\n')
+ {
+ (*putc)('\r');
+ }
+ }
+ }
+}
+
+int _cvt(unsigned long val, char *buf, long radix, char *digits)
+{
+ char temp[80];
+ char *cp = temp;
+ int length = 0;
+ if (val == 0)
+ { /* Special case */
+ *cp++ = '0';
+ } else
+ while (val)
+ {
+ *cp++ = digits[val % radix];
+ val /= radix;
+ }
+ while (cp != temp)
+ {
+ *buf++ = *--cp;
+ length++;
+ }
+ *buf = '\0';
+ return (length);
+}
+
+_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
+{
+ int i, c;
+ if ((unsigned int)s > (unsigned int)p)
+ {
+ s = (unsigned int)s - (unsigned int)p;
+ }
+ while (s > 0)
+ {
+ if (base)
+ {
+ _printk("%06X: ", (int)p - (int)base);
+ } else
+ {
+ _printk("%06X: ", p);
+ }
+ for (i = 0; i < 16; i++)
+ {
+ if (i < s)
+ {
+ _printk("%02X", p[i] & 0xFF);
+ } else
+ {
+ _printk(" ");
+ }
+ if ((i % 2) == 1) _printk(" ");
+ if ((i % 8) == 7) _printk(" ");
+ }
+ _printk(" |");
+ for (i = 0; i < 16; i++)
+ {
+ if (i < s)
+ {
+ c = p[i] & 0xFF;
+ if ((c < 0x20) || (c >= 0x7F)) c = '.';
+ } else
+ {
+ c = ' ';
+ }
+ _printk("%c", c);
+ }
+ _printk("|\n");
+ s -= 16;
+ p += 16;
+ }
+}
+
+_dump_buf(unsigned char *p, int s)
+{
+ _printk("\n");
+ _dump_buf_with_offset(p, s, 0);
+}
diff --git a/arch/ppc/boot/mkprep.c b/arch/ppc/boot/mkprep.c
index 7799c9acc..0a596b0ff 100644
--- a/arch/ppc/boot/mkprep.c
+++ b/arch/ppc/boot/mkprep.c
@@ -14,15 +14,8 @@
* Modified for x86 hosted builds by Matt Porter <porter@neta.com>
*/
-#ifdef linux
-#include <linux/types.h>
-/*#include <asm/stat.h>*/
-/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
-#else
#include <unistd.h>
-#endif
#include <sys/stat.h>
-
#include <stdio.h>
#include <errno.h>
@@ -168,10 +161,10 @@ void write_prep_partition(int in, int out)
/* set entry point and boot image size skipping over elf header */
#ifdef __i386__
*entry = 0x400/*+65536*/;
- *length = info.st_size+0x400;
+ *length = info.st_size-elfhdr_size+0x400;
#else
*entry = cpu_to_le32(0x400/*+65536*/);
- *length = cpu_to_le32(info.st_size+0x400);
+ *length = cpu_to_le32(info.st_size-elfhdr_size+0x400);
#endif /* __i386__ */
/* sets magic number for msdos partition (used by linux) */
diff --git a/arch/ppc/boot/of1275.c b/arch/ppc/boot/of1275.c
new file mode 100644
index 000000000..b82fa7a46
--- /dev/null
+++ b/arch/ppc/boot/of1275.c
@@ -0,0 +1,427 @@
+/* Open Firmware Client Interface */
+
+
+#include "of1275.h"
+
+
+static int (*of_server)(void *) = (int(*)(void*))-1;
+
+void
+of_init(void *handler)
+{
+ of_server = (int(*)(void*))handler;
+}
+
+
+/* 6.3.2.1 Client interface */
+
+
+int
+of_test(const char *name, int *missing)
+{
+ int result;
+ static of_test_service s;
+ s.service = "test";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.name = name;
+ result = of_server(&s);
+ *missing = s.missing;
+ return result;
+}
+
+
+/* 6.3.2.2 Device tree */
+
+
+int
+of_peer(int phandle, int *sibling_phandle)
+{
+ int result;
+ static of_peer_service s;
+ s.service = "peer";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ result = of_server(&s);
+ *sibling_phandle = s.sibling_phandle;
+ return result;
+}
+
+int
+of_child(int phandle, int *child_phandle)
+{
+ int result;
+ static of_child_service s;
+ s.service = "child";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ result = of_server(&s);
+ *child_phandle = s.child_phandle;
+ return result;
+}
+
+int
+of_parent(int phandle, int *parent_phandle)
+{
+ int result;
+ static of_parent_service s;
+ s.service = "parent";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ result = of_server(&s);
+ *parent_phandle = s.parent_phandle;
+ return result;
+}
+
+int
+of_instance_to_package(int ihandle, int *phandle)
+{
+ int result;
+ static of_instance_to_package_service s;
+ s.service = "instance-to-package";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.ihandle = ihandle;
+ result = of_server(&s);
+ *phandle = s.phandle;
+ return result;
+}
+
+int
+of_getproplen(int phandle, const char *name, int *proplen)
+{
+ int result;
+ static of_getproplen_service s;
+ s.service = "getproplen";
+ s.n_args = 2;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ s.name = name;
+ result = of_server(&s);
+ *proplen = s.proplen;
+ return result;
+}
+
+int
+of_getprop(int phandle, const char *name, void *buf, int buflen, int *size)
+{
+ int result;
+ static of_getprop_service s;
+ s.service = "getprop";
+ s.n_args = 4;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ s.name = name;
+ s.buf = buf;
+ s.buflen = buflen;
+ result = of_server(&s);
+ *size = s.size;
+ return result;
+}
+
+int
+of_nextprop(int phandle, const char *previous, void *buf, int *flag)
+{
+ int result;
+ static of_nextprop_service s;
+ s.service = "nextprop";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ s.previous = previous;
+ s.buf = buf;
+ result = of_server(&s);
+ *flag = s.flag;
+ return result;
+}
+
+int
+of_setprop(int phandle, const char *name, void *buf, int len, int *size)
+{
+ int result;
+ static of_setprop_service s;
+ s.service = "setprop";
+ s.n_args = 4;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ s.name = name;
+ s.buf = buf;
+ s.len = len;
+ result = of_server(&s);
+ *size = s.size;
+ return result;
+}
+
+int
+of_canon(const char *device_specifier, void *buf, int buflen, int *length)
+{
+ int result;
+ static of_canon_service s;
+ s.service = "canon";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.device_specifier = device_specifier;
+ s.buf = buf;
+ s.buflen = buflen;
+ result = of_server(&s);
+ *length = s.length;
+ return result;
+}
+
+int
+of_finddevice(const char *device_specifier, int *phandle)
+{
+ int result;
+ static of_finddevice_service s;
+ s.service = "finddevice";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.device_specifier = device_specifier;
+ result = of_server(&s);
+ *phandle = s.phandle;
+ return result;
+}
+
+int
+of_instance_to_path(int ihandle, void *buf, int buflen, int *length)
+{
+ int result;
+ static of_instance_to_path_service s;
+ s.service = "instance-to-path";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.ihandle = ihandle;
+ s.buf = buf;
+ s.buflen = buflen;
+ result = of_server(&s);
+ *length = s.length;
+ return result;
+}
+
+int
+of_package_to_path(int phandle, void *buf, int buflen, int *length)
+{
+ int result;
+ static of_package_to_path_service s;
+ s.service = "package-to-path";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.phandle = phandle;
+ s.buf = buf;
+ s.buflen = buflen;
+ result = of_server(&s);
+ *length = s.length;
+ return result;
+}
+
+/* int of_call_method(const char *method, int ihandle, ...); */
+
+
+/* 6.3.2.3 Device I/O */
+
+
+int
+of_open(const char *device_specifier, int *ihandle)
+{
+ int result;
+ static of_open_service s;
+ s.service = "open";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.device_specifier = device_specifier;
+ result = of_server(&s);
+ *ihandle = s.ihandle;
+ return result;
+}
+
+int
+of_close(int ihandle)
+{
+ int result;
+ static of_close_service s;
+ s.service = "close";
+ s.n_args = 1;
+ s.n_returns = 0;
+ s.ihandle = ihandle;
+ result = of_server(&s);
+ return result;
+}
+
+int
+of_read(int ihandle, void *addr, int len, int *actual)
+{
+ int result;
+ static of_read_service s;
+ s.service = "read";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.ihandle = ihandle;
+ s.addr = addr;
+ s.len = len;
+ result = of_server(&s);
+ *actual = s.actual;
+ return result;
+}
+
+int
+of_write(int ihandle, void *addr, int len, int *actual)
+{
+ int result;
+ static of_write_service s;
+ s.service = "write";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.ihandle = ihandle;
+ s.addr = addr;
+ s.len = len;
+ result = of_server(&s);
+ *actual = s.actual;
+ return result;
+}
+
+int
+of_seek(int ihandle, int pos_hi, int pos_lo, int *status)
+{
+ int result;
+ static of_seek_service s;
+ s.service = "seek";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.ihandle = ihandle;
+ s.pos_hi = pos_hi;
+ s.pos_lo = pos_lo;
+ result = of_server(&s);
+ *status = s.status;
+ return result;
+}
+
+
+/* 6.3.2.4 Memory */
+
+
+int
+of_claim(void *virt, int size, int align, void **baseaddr)
+{
+ int result;
+ static of_claim_service s;
+ s.service = "claim";
+ s.n_args = 3;
+ s.n_returns = 1;
+ s.virt = virt;
+ s.size = size;
+ s.align = align;
+ result = of_server(&s);
+ *baseaddr = s.baseaddr;
+ return result;
+}
+
+int
+of_release(void *virt, int size)
+{
+ int result;
+ static of_release_service s;
+ s.service = "release";
+ s.n_args = 2;
+ s.n_returns = 0;
+ s.virt = virt;
+ s.size = size;
+ result = of_server(&s);
+ return result;
+}
+
+
+/* 6.3.2.5 Control transfer */
+
+
+int
+of_boot(const char *bootspec)
+{
+ int result;
+ static of_boot_service s;
+ s.service = "boot";
+ s.n_args = 1;
+ s.n_returns = 0;
+ s.bootspec = bootspec;
+ result = of_server(&s);
+ return result;
+}
+
+int
+of_enter(void)
+{
+ int result;
+ static of_enter_service s;
+ s.service = "enter";
+ s.n_args = 0;
+ s.n_returns = 0;
+ result = of_server(&s);
+ return result;
+}
+
+int
+of_exit(void)
+{
+ int result;
+ static of_exit_service s;
+ s.service = "exit";
+ s.n_args = 0;
+ s.n_returns = 0;
+ result = of_server(&s);
+ return result;
+}
+
+/* int of_chain(void *virt, int size, void *entry, void *args, int len); */
+
+
+/* 6.3.2.6 User interface */
+
+
+/* int of_interpret(const char *arg, ...); */
+
+int
+of_set_callback(void *newfunc, void **oldfunc)
+{
+ int result;
+ static of_set_callback_service s;
+ s.service = "set-callback";
+ s.n_args = 1;
+ s.n_returns = 1;
+ s.newfunc = newfunc;
+ result = of_server(&s);
+ *oldfunc = s.oldfunc;
+ return result;
+}
+
+int
+of_set_symbol_lookup(void *sym_to_value, void *value_to_sym)
+{
+ int result;
+ static of_set_symbol_lookup_service s;
+ s.service = "set-symbol-lookup";
+ s.n_args = 2;
+ s.n_returns = 0;
+ s.sym_to_value = sym_to_value;
+ s.value_to_sym = s.value_to_sym;
+ result = of_server(&s);
+ return result;
+}
+
+
+/* 6.3.2.7 Time */
+
+
+int
+of_milliseconds(int *ms)
+{
+ int result;
+ static of_milliseconds_service s;
+ s.service = "milliseconds";
+ s.n_args = 0;
+ s.n_returns = 1;
+ result = of_server(&s);
+ *ms = s.ms;
+ return result;
+}
diff --git a/arch/ppc/boot/of1275.h b/arch/ppc/boot/of1275.h
new file mode 100644
index 000000000..bc050d32b
--- /dev/null
+++ b/arch/ppc/boot/of1275.h
@@ -0,0 +1,421 @@
+/* 6.3.2.1 Client interface */
+
+
+typedef struct _of_test_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ const char *name;
+ /*out*/
+ int missing;
+} of_test_service;
+
+int of_test(const char *name, int *missing);
+
+
+/* 6.3.2.2 Device tree */
+
+
+typedef struct _of_peer_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ /*out*/
+ int sibling_phandle;
+} of_peer_service;
+
+int of_peer(int phandle, int *sibling_phandle);
+
+
+typedef struct _of_child_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ /*out*/
+ int child_phandle;
+} of_child_service;
+
+int of_child(int phandle, int *child_phandle);
+
+
+typedef struct _of_parent_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ /*out*/
+ int parent_phandle;
+} of_parent_service;
+
+int of_child(int phandle, int *parent_phandle);
+
+
+typedef struct _of_instance_to_package_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int ihandle;
+ /*out*/
+ int phandle;
+} of_instance_to_package_service;
+
+int of_instance_to_package(int ihandle, int *phandle);
+
+
+typedef struct _of_getproplen_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ const char *name;
+ /*out*/
+ int proplen;
+} of_getproplen_service;
+
+int of_getproplen(int phandle, const char *name, int *proplen);
+
+
+typedef struct _of_getprop_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ const char *name;
+ void *buf;
+ int buflen;
+ /*out*/
+ int size;
+} of_getprop_service;
+
+int of_getprop(int phandle, const char *name, void *buf, int buflen,
+ int *size);
+
+
+typedef struct _of_nextprop_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ const char *previous;
+ void *buf;
+ /*out*/
+ int flag;
+} of_nextprop_service;
+
+int of_nextprop(int phandle, const char *previous, void *buf, int *flag);
+
+
+typedef struct _of_setprop_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ const char *name;
+ void *buf;
+ int len;
+ /*out*/
+ int size;
+} of_setprop_service;
+
+int of_setprop(int phandle, const char *name, void *buf, int len, int *size);
+
+
+typedef struct _of_canon_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ const char *device_specifier;
+ void *buf;
+ int buflen;
+ /*out*/
+ int length;
+} of_canon_service;
+
+int of_canon(const char *device_specifier, void *buf, int buflen, int *length);
+
+
+typedef struct _of_finddevice_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ const char *device_specifier;
+ /*out*/
+ int phandle;
+} of_finddevice_service;
+
+int of_finddevice(const char *device_specifier, int *phandle);
+
+
+typedef struct _of_instance_to_path_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int ihandle;
+ void *buf;
+ int buflen;
+ /*out*/
+ int length;
+} of_instance_to_path_service;
+
+int of_instance_to_path(int ihandle, void *buf, int buflen, int *length);
+
+
+typedef struct _of_package_to_path_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int phandle;
+ void *buf;
+ int buflen;
+ /*out*/
+ int length;
+} of_package_to_path_service;
+
+int of_package_to_path(int phandle, void *buf, int buflen, int *length);
+
+
+typedef struct _of_call_method_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ const char *method;
+ int ihandle;
+ /*...*/
+ int args[0];
+} of_call_method_service;
+
+int of_call_method(const char *method, int ihandle, ...);
+
+
+/* 6.3.2.3 Device I/O */
+
+
+typedef struct _of_open_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ const char *device_specifier;
+ /*out*/
+ int ihandle;
+} of_open_service;
+
+int of_open(const char *device_specifier,
+ int *ihandle);
+
+
+typedef struct _of_close_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int ihandle;
+ /*out*/
+} of_close_service;
+
+int of_close(int ihandle);
+
+
+typedef struct _of_read_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int ihandle;
+ void *addr;
+ int len;
+ /*out*/
+ int actual;
+} of_read_service;
+
+int of_read(int ihandle, void *addr, int len, int *actual);
+
+
+typedef struct _of_write_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int ihandle;
+ void *addr;
+ int len;
+ /*out*/
+ int actual;
+} of_write_service;
+
+int of_write(int ihandle, void *addr, int len, int *actual);
+
+
+typedef struct _of_seek_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ int ihandle;
+ int pos_hi;
+ int pos_lo;
+ /*out*/
+ int status;
+} of_seek_service;
+
+int of_seek(int ihandle, int pos_hi, int pos_lo, int *status);
+
+
+/* 6.3.2.4 Memory */
+
+
+typedef struct _of_claim_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ void *virt;
+ int size;
+ int align;
+ /*out*/
+ void *baseaddr;
+} of_claim_service;
+
+int of_claim(void *virt, int size, int align, void **baseaddr);
+
+
+typedef struct _of_release_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ void *virt;
+ int size;
+ int align;
+ /*out*/
+} of_release_service;
+
+int of_release(void *virt, int size);
+
+
+/* 6.3.2.5 Control transfer */
+
+
+typedef struct _of_boot_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ const char *bootspec;
+ /*out*/
+} of_boot_service;
+
+int of_boot(const char *bootspec);
+
+
+typedef struct _of_enter_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ /*out*/
+} of_enter_service;
+
+int of_enter(void);
+
+
+typedef struct _of_exit_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ /*out*/
+} of_exit_service;
+
+int of_exit(void);
+
+
+typedef struct _of_chain_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ void *virt;
+ int size;
+ void *entry;
+ void *args;
+ int len;
+ /*out*/
+} of_chain_service;
+
+int of_chain(void *virt, int size, void *entry, void *args, int len);
+
+
+/* 6.3.2.6 User interface */
+
+
+typedef struct _of_interpret_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ const char *cmd;
+ int args[0];
+ /*...*/
+ /*out*/
+ /*...*/
+} of_interpret_service;
+
+int of_interpret(const char *arg, ...);
+
+
+typedef struct _of_set_callback_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ void *newfunc;
+ /*out*/
+ void *oldfunc;
+} of_set_callback_service;
+
+int of_set_callback(void *newfunc, void **oldfunc);
+
+
+typedef struct _of_set_symbol_lookup_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ void *sym_to_value;
+ void *value_to_sym;
+ /*out*/
+} of_set_symbol_lookup_service;
+
+int of_set_symbol_lookup(void *sym_to_value, void *value_to_sym);
+
+
+/* 6.3.2.7 Time */
+
+
+typedef struct _of_milliseconds_service {
+ const char *service;
+ int n_args;
+ int n_returns;
+ /*in*/
+ /*out*/
+ int ms;
+} of_milliseconds_service;
+
+int of_milliseconds(int *ms);
diff --git a/arch/ppc/boot/piggyback.c b/arch/ppc/boot/piggyback.c
deleted file mode 100644
index ca9fc2957..000000000
--- a/arch/ppc/boot/piggyback.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include <stdio.h>
-
-extern long ce_exec_config[];
-
-main(int argc, char *argv[])
-{
- int i, cnt, pos, len;
- unsigned int cksum, val;
- unsigned char *lp;
- unsigned char buf[8192];
- if (argc != 1)
- {
- fprintf(stderr, "usage: %s <in-file >out-file\n", argv[0]);
- exit(1);
- }
- fprintf(stdout, "#\n");
- fprintf(stdout, "# Miscellaneous data structures:\n");
- fprintf(stdout, "# WARNING - this file is automatically generated!\n");
- fprintf(stdout, "#\n");
- fprintf(stdout, "\n");
- fprintf(stdout, "\t.data\n");
- fprintf(stdout, "\t.globl input_data\n");
- fprintf(stdout, "input_data:\n");
- pos = 0;
- cksum = 0;
- while ((len = read(0, buf, sizeof(buf))) > 0)
- {
- cnt = 0;
- lp = (unsigned char *)buf;
- len = (len + 3) & ~3; /* Round up to longwords */
- for (i = 0; i < len; i += 4)
- {
- if (cnt == 0)
- {
- fprintf(stdout, "\t.long\t");
- }
- fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
- val = *(unsigned long *)lp;
- cksum ^= val;
- lp += 4;
- if (++cnt == 4)
- {
- cnt = 0;
- fprintf(stdout, " # %x \n", pos+i-12);
- fflush(stdout);
- } else
- {
- fprintf(stdout, ",");
- }
- }
- if (cnt)
- {
- fprintf(stdout, "0\n");
- }
- pos += len;
- }
- fprintf(stdout, "\t.globl input_len\n");
- fprintf(stdout, "input_len:\t.long\t0x%x\n", pos);
- fflush(stdout);
- fclose(stdout);
- fprintf(stderr, "cksum = %x\n", cksum);
- exit(0);
-}
-
diff --git a/arch/ppc/chrp_defconfig b/arch/ppc/chrp_defconfig
index 9141b2d90..48e305f44 100644
--- a/arch/ppc/chrp_defconfig
+++ b/arch/ppc/chrp_defconfig
@@ -85,7 +85,6 @@ CONFIG_PARIDE_PARPORT=y
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile
index 946845a5d..cd0336bc9 100644
--- a/arch/ppc/chrpboot/Makefile
+++ b/arch/ppc/chrpboot/Makefile
@@ -28,6 +28,12 @@ ifeq ($(CONFIG_ALL_PPC),y)
CONFIG_CHRP = y
endif
+ifeq ($(CONFIG_SMP),y)
+TFTPIMAGE=/tftpboot/zImage.chrp.smp
+else
+TFTPIMAGE=/tftpboot/zImage.chrp
+endif
+
all: $(TOPDIR)/zImage
#
@@ -36,10 +42,10 @@ all: $(TOPDIR)/zImage
#
ifeq ($(CONFIG_CHRP),y)
znetboot: zImage
- cp zImage /tftpboot/zImage.chrp
+ cp zImage $(TFTPIMAGE)
znetboot.initrd: zImage.initrd
- cp zImage.initrd /tftpboot/zImage.chrp
+ cp zImage.initrd $(TFTPIMAGE)
floppy: zImage
mcopy zImage a:zImage
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
index 4669d2228..9ca967785 100644
--- a/arch/ppc/coffboot/Makefile
+++ b/arch/ppc/coffboot/Makefile
@@ -23,6 +23,12 @@ ifeq ($(CONFIG_ALL_PPC),y)
CONFIG_PMAC = y
endif
+ifeq ($(CONFIG_SMP),y)
+TFTPIMAGE=/tftpboot/zImage.pmac.smp
+else
+TFTPIMAGE=/tftpboot/zImage.pmac
+endif
+
ifeq ($(CONFIG_PMAC),y)
hack-coff: hack-coff.c
$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
@@ -33,10 +39,10 @@ floppy: zImage
# umount /mnt
znetboot: vmlinux.coff
- cp vmlinux.coff /tftpboot/zImage.pmac
+ cp vmlinux.coff $(TFTPIMAGE)
znetboot.initrd: vmlinux.coff.initrd
- cp vmlinux.coff.initrd /tftpboot/zImage.pmac
+ cp vmlinux.coff.initrd $(TFTPIMAGE)
coffboot: $(OBJS) ld.script
$(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig
index f58965709..131244790 100644
--- a/arch/ppc/common_defconfig
+++ b/arch/ppc/common_defconfig
@@ -1,5 +1,5 @@
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
#
@@ -21,7 +21,7 @@ CONFIG_ALL_PPC=y
#
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
CONFIG_PCI=y
# CONFIG_PCI_QUIRKS is not set
@@ -32,23 +32,23 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
+CONFIG_BINFMT_MISC=m
# CONFIG_BINFMT_JAVA is not set
# CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
CONFIG_MAC_KEYBOARD=y
CONFIG_MAC_FLOPPY=y
CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
CONFIG_ADBMOUSE=y
-CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
# CONFIG_TOTALMP is not set
CONFIG_BOOTX_TEXT=y
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
#
# Plug and Play support
@@ -60,18 +60,28 @@ CONFIG_BOOTX_TEXT=y
#
# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
# CONFIG_IDE_CHIPSETS is not set
-CONFIG_BLK_DEV_LOOP=m
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
@@ -84,27 +94,36 @@ CONFIG_PARIDE_PARPORT=y
#
# Networking options
#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_PACKET=y
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_RARP is not set
-# CONFIG_IP_NOSR is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+CONFIG_INET_RARP=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
+
+#
+#
+#
# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
+CONFIG_ATALK=m
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
@@ -124,13 +143,21 @@ CONFIG_SKB_LARGE=y
# SCSI support
#
CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
#
@@ -141,7 +168,10 @@ CONFIG_BLK_DEV_SR_VENDOR=y
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
+CONFIG_SCSI_AIC7XXX=y
+# CONFIG_OVERRIDE_CMDS is not set
+CONFIG_AIC7XXX_PROC_STATS=y
+CONFIG_AIC7XXX_RESET_DELAY=15
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
@@ -154,15 +184,20 @@ CONFIG_BLK_DEV_SR_VENDOR=y
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_NCR53C7xx is not set
CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
-CONFIG_SCSI_NCR53C8XX_SYNC=5
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
@@ -170,6 +205,7 @@ CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
@@ -187,6 +223,7 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
CONFIG_NET_ETHERNET=y
CONFIG_MACE=y
CONFIG_BMAC=y
@@ -199,7 +236,7 @@ CONFIG_BMAC=y
# CONFIG_ACENIC is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
-CONFIG_PCNET32=m
+CONFIG_PCNET32=y
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
@@ -219,16 +256,21 @@ CONFIG_DE4X5=y
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_DLCI is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_IPDDP is not set
CONFIG_PPP=y
-CONFIG_SLIP=m
-# CONFIG_SLIP_COMPRESSED is not set
-# CONFIG_SLIP_SMART is not set
-# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_SLIP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
# CONFIG_SHAPER is not set
# CONFIG_HOSTESS_SV11 is not set
# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
#
# Amateur Radio support
@@ -241,7 +283,7 @@ CONFIG_SLIP=m
# CONFIG_ISDN is not set
#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
#
# CONFIG_CD_NO_IDESCSI is not set
@@ -249,27 +291,42 @@ CONFIG_SLIP=m
# Console drivers
#
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
CONFIG_FB_OF=y
CONFIG_FB_CONTROL=y
CONFIG_FB_PLATINUM=y
CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
CONFIG_FBCON_CFB8=y
CONFIG_FBCON_CFB16=y
CONFIG_FBCON_CFB24=y
CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x8 is not set
CONFIG_FONT_8x16=y
-# CONFIG_FONT_SUN8x16 is not set
+CONFIG_FONT_SUN8x16=y
CONFIG_FONT_SUN12x22=y
# CONFIG_FONT_6x11 is not set
# CONFIG_FONT_PEARL_8x8 is not set
@@ -283,7 +340,8 @@ CONFIG_VT_CONSOLE=y
CONFIG_SERIAL=m
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_UNIX98_PTYS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
CONFIG_MOUSE=y
#
@@ -309,30 +367,40 @@ CONFIG_PSMOUSE=y
# Joystick support
#
# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
#
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS_FS=y
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
CONFIG_HFS_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_VFAT_FS=m
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
@@ -344,7 +412,7 @@ CONFIG_EXT2_FS=y
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
-CONFIG_NFSD=m
+CONFIG_NFSD=y
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
@@ -364,7 +432,7 @@ CONFIG_NLS=y
#
# Native Language Support
#
-# CONFIG_NLS_CODEPAGE_437 is not set
+CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
@@ -402,30 +470,11 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_SONICVIBES is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
-CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_PAS is not set
-# CONFIG_SOUND_SB is not set
-# CONFIG_SOUND_ADLIB is not set
-# CONFIG_SOUND_GUS is not set
-# CONFIG_SOUND_MPU401 is not set
-# CONFIG_SOUND_PSS is not set
-# CONFIG_SOUND_MSS is not set
-# CONFIG_SOUND_SSCAPE is not set
-# CONFIG_SOUND_TRIX is not set
-# CONFIG_SOUND_MAD16 is not set
-# CONFIG_SOUND_WAVEFRONT is not set
-# CONFIG_SOUND_CS4232 is not set
-# CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_MAUI is not set
-# CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_AD1816 is not set
-# CONFIG_SOUND_OPL3SA1 is not set
-# CONFIG_SOUND_SOFTOSS is not set
-# CONFIG_SOUND_YM3812 is not set
-# CONFIG_SOUND_VMIDI is not set
-# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_OSS is not set
#
-# Additional low level sound drivers
+# Kernel hacking
#
-# CONFIG_LOWLEVEL_SOUND is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index b15e90afd..e10cc51bb 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -19,12 +19,10 @@ choice 'Machine Type' \
APUS CONFIG_APUS \
MBX CONFIG_MBX" PowerMac
+bool 'Symmetric multi-processing support' CONFIG_SMP
if [ "$CONFIG_ALL_PPC" != "y" ];then
define_bool CONFIG_MACH_SPECIFIC y
fi
-
-bool 'Symmetric multi-processing support' CONFIG_SMP
-
endmenu
if [ "$CONFIG_MBX" = "y" ];then
@@ -82,13 +80,20 @@ bool 'Power management support for PowerBook 3400/2400' CONFIG_PMAC_PBOOK
bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
+if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
+ bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
+fi
bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
-bool 'Support for PowerMac IDE devices (must also enable IDE)' CONFIG_BLK_DEV_IDE_PMAC
bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
-bool 'Include kgdb kernel debugger' CONFIG_KGDB
-bool 'Include xmon kernel debugger' CONFIG_XMON
bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
+bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
+if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+ bool 'PReP bootloader kernel arguments' CONFIG_CMDLINE_BOOL y
+ if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
+ string 'Initial kernel command string' CONFIG_CMDLINE console=ttyS0,9600 console=tty0 root=/dev/sda2
+ fi
+fi
if [ "$CONFIG_APUS" = "y" ]; then
define_bool CONFIG_FB_CONSOLE y
@@ -152,7 +157,7 @@ fi
endmenu
mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
@@ -172,8 +177,16 @@ mainmenu_option next_comment
comment 'Sound'
tristate 'Sound card support' CONFIG_SOUND
if [ "$CONFIG_SOUND" != "n" ]; then
- tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND
+ dep_tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND $CONFIG_SOUND
source drivers/sound/Config.in
fi
endmenu
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Include kgdb kernel debugger' CONFIG_KGDB
+bool 'Include xmon kernel debugger' CONFIG_XMON
+endmenu
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index 811d599c0..131244790 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -8,13 +8,12 @@
CONFIG_PPC=y
CONFIG_6xx=y
# CONFIG_8xx is not set
-CONFIG_PMAC=y
+# CONFIG_PMAC is not set
# CONFIG_PREP is not set
# CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
# CONFIG_APUS is not set
# CONFIG_MBX is not set
-CONFIG_MACH_SPECIFIC=y
# CONFIG_SMP is not set
#
@@ -36,20 +35,20 @@ CONFIG_KERNEL_ELF=y
CONFIG_BINFMT_MISC=m
# CONFIG_BINFMT_JAVA is not set
# CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
CONFIG_MAC_KEYBOARD=y
CONFIG_MAC_FLOPPY=y
CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
CONFIG_ADBMOUSE=y
-CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
# CONFIG_TOTALMP is not set
CONFIG_BOOTX_TEXT=y
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
#
# Plug and Play support
@@ -76,15 +75,13 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
# CONFIG_BLK_DEV_IDEPCI is not set
# CONFIG_BLK_DEV_SL82C105 is not set
CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
# CONFIG_IDE_CHIPSETS is not set
#
# Additional Block Devices
#
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
@@ -102,7 +99,6 @@ CONFIG_NETLINK=y
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -120,7 +116,6 @@ CONFIG_IP_ALIAS=y
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
@@ -156,12 +151,12 @@ CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=y
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
@@ -189,16 +184,28 @@ CONFIG_AIC7XXX_RESET_DELAY=15
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
@@ -229,7 +236,7 @@ CONFIG_BMAC=y
# CONFIG_ACENIC is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
@@ -263,6 +270,7 @@ CONFIG_PPP=y
# CONFIG_SHAPER is not set
# CONFIG_HOSTESS_SV11 is not set
# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
#
# Amateur Radio support
@@ -275,7 +283,7 @@ CONFIG_PPP=y
# CONFIG_ISDN is not set
#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
#
# CONFIG_CD_NO_IDESCSI is not set
@@ -283,22 +291,37 @@ CONFIG_PPP=y
# Console drivers
#
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
CONFIG_FB_OF=y
CONFIG_FB_CONTROL=y
CONFIG_FB_PLATINUM=y
CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
CONFIG_FBCON_CFB8=y
CONFIG_FBCON_CFB16=y
CONFIG_FBCON_CFB24=y
CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
CONFIG_FBCON_FONTS=y
# CONFIG_FONT_8x8 is not set
@@ -314,15 +337,25 @@ CONFIG_FONT_SUN12x22=y
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
+CONFIG_SERIAL=m
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
+# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
#
@@ -334,11 +367,20 @@ CONFIG_NVRAM=y
# Joystick support
#
# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
#
# Filesystems
@@ -429,3 +471,10 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
# CONFIG_SOUND_OSS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index d047c2086..5c8b44a90 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -27,7 +27,7 @@ O_OBJS += totalmp.o
endif
ifeq ($(CONFIG_MBX),y)
-O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o
+O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o
else
ifeq ($(CONFIG_APUS),y)
O_OBJS += apus_setup.o prom.o openpic.o
@@ -36,7 +36,8 @@ ifneq ($(CONFIG_MBX),y)
O_OBJS += prep_time.o pmac_time.o chrp_time.o \
pmac_setup.o pmac_support.o \
prep_pci.o pmac_pci.o chrp_pci.o \
- residual.o prom.o openpic.o feature.o
+ residual.o prom.o openpic.o feature.o \
+ prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o
OX_OBJS += chrp_setup.o prep_setup.o
endif
endif
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
index 83ee7756d..cf5fcffd3 100644
--- a/arch/ppc/kernel/align.c
+++ b/arch/ppc/kernel/align.c
@@ -194,13 +194,8 @@ fix_alignment(struct pt_regs *regs)
return -EFAULT; /* bad address */
}
-#ifdef __SMP__
- if ((flags & F) && (regs->msr & MSR_FP) )
- smp_giveup_fpu(current);
-#else
- if ((flags & F) && last_task_used_math == current)
- giveup_fpu();
-#endif
+ if ((flags & F) && (regs->msr & MSR_FP))
+ giveup_fpu(current);
if (flags & M)
return 0; /* too hard for now */
@@ -254,27 +249,16 @@ fix_alignment(struct pt_regs *regs)
data.d = current->tss.fpr[reg];
break;
/* these require some floating point conversions... */
- /* note that giveup_fpu enables the FPU for the kernel */
/* we'd like to use the assignment, but we have to compile
* the kernel with -msoft-float so it doesn't use the
* fp regs for copying 8-byte objects. */
case LD+F+S:
-#ifdef __SMP__
- if (regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- giveup_fpu();
-#endif
+ enable_kernel_fp();
cvt_fd(&data.f, &current->tss.fpr[reg], &current->tss.fpscr);
/* current->tss.fpr[reg] = data.f; */
break;
case ST+F+S:
-#ifdef __SMP__
- if (regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- giveup_fpu();
-#endif
+ enable_kernel_fp();
cvt_df(&current->tss.fpr[reg], &data.f, &current->tss.fpscr);
/* data.f = current->tss.fpr[reg]; */
break;
diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c
index c3a81ad3e..55e57fc5b 100644
--- a/arch/ppc/kernel/apus_setup.c
+++ b/arch/ppc/kernel/apus_setup.c
@@ -14,12 +14,50 @@
#include <linux/sched.h>
#include <linux/kd.h>
#include <linux/init.h>
+#include <linux/hdreg.h>
+
+/* Get the IDE stuff from the 68k file */
+#define ide_init_hwif_ports m68k_ide_init_hwif_ports
+#define ide_default_irq m68k_ide_default_irq
+#define ide_default_io_base m68k_ide_default_io_base
+#define ide_check_region m68k_ide_check_region
+#define ide_request_region m68k_ide_request_region
+#define ide_release_region m68k_ide_release_region
+#define ide_fix_driveid m68k_ide_fix_driveid
+#include <asm-m68k/ide.h>
+#undef ide_init_hwif_ports
+#define ide_default_irq
+#define ide_default_io_base
+#define ide_check_region
+#define ide_request_region
+#define ide_release_region
+#define ide_fix_driveid
+
#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/amigappc.h>
#include <asm/pgtable.h>
#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+unsigned long apus_get_rtc_time(void);
+int apus_set_rtc_time(unsigned long nowtime);
+
+/* APUS defs */
+extern int parse_bootinfo(const struct bi_record *);
+extern char _end[];
+#ifdef CONFIG_APUS
+struct mem_info ramdisk;
+unsigned long isa_io_base;
+unsigned long isa_mem_base;
+unsigned long pci_dram_offset;
+#endif
+/* END APUS defs */
unsigned long m68k_machtype;
char debug_device[6] = "";
@@ -72,6 +110,8 @@ __initfunc(void apus_setup_arch(unsigned long * memory_start_p,
int i;
char *p, *q;
+ m68k_machtype = MACH_AMIGA;
+
/* Parse the command line for arch-specific options.
* For the m68k, this is currently only "debug=xxx" to enable printing
* certain kernel messages to some machine-specific device. */
@@ -409,3 +449,194 @@ void cache_clear(__u32 addr, int length)
"isync \n\t"
: : "r" (addr));
}
+
+void
+apus_restart(char *cmd)
+{
+ cli();
+
+ APUS_WRITE(APUS_REG_LOCK,
+ REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
+ APUS_WRITE(APUS_REG_LOCK,
+ REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
+ APUS_WRITE(APUS_REG_LOCK,
+ REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
+ APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+ APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
+ for(;;);
+}
+
+void
+apus_power_off(void)
+{
+ for (;;);
+}
+
+void
+apus_halt(void)
+{
+ apus_restart(NULL);
+}
+
+void
+apus_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ int old_level, new_level;
+
+ /* I don't think we need SMP code here - Corey */
+
+ old_level = ~(regs->mq) & IPLEMU_IPLMASK;
+ new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
+ if (new_level != 0)
+ {
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+ APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+ | (~(new_level) & IPLEMU_IPLMASK)));
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+
+ process_int (VEC_SPUR+new_level, regs);
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+ APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+ | (~(old_level) & IPLEMU_IPLMASK)));
+ }
+ APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+apus_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port, buf, ns);
+}
+
+void
+apus_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port, buf, ns);
+}
+
+int
+apus_ide_default_irq(ide_ioreg_t base)
+{
+ m68k_ide_default_irq(base);
+}
+
+ide_ioreg_t
+apus_ide_default_io_base(int index)
+{
+ m68k_ide_default_io_base(index);
+}
+
+int
+apus_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return m68k_ide_check_region(from, extent);
+}
+
+void
+apus_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+ m68k_ide_request_region(from, extent, name);
+}
+
+void
+apus_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+ m68k_ide_release_region(from, extent);
+}
+
+void
+apus_ide_fix_driveid(struct hd_driveid *id)
+{
+ m68k_ide_fix_driveid(id);
+}
+
+__initfunc(void
+apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+{
+ m68k_ide_init_hwif_ports(p, base, irq);
+}
+#endif
+
+__initfunc(void
+apus_local_init_IRQ(void))
+{
+ ppc_md.mask_irq = amiga_disable_irq;
+ ppc_md.unmask_irq = amiga_enable_irq;
+ apus_init_IRQ();
+}
+
+__initfunc(void
+apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ /* Parse bootinfo. The bootinfo is located right after
+ the kernel bss */
+ parse_bootinfo((const struct bi_record *)&_end);
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* Take care of initrd if we have one. Use data from
+ bootinfo to avoid the need to initialize PPC
+ registers when kernel is booted via a PPC reset. */
+ if ( ramdisk.addr ) {
+ initrd_start = (unsigned long) __va(ramdisk.addr);
+ initrd_end = (unsigned long)
+ __va(ramdisk.size + ramdisk.addr);
+ }
+ /* Make sure code below is not executed. */
+ r4 = 0;
+ r6 = 0;
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+
+ ppc_md.setup_arch = apus_setup_arch;
+ ppc_md.setup_residual = NULL;
+ ppc_md.get_cpuinfo = apus_get_cpuinfo;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = apus_init_IRQ;
+ ppc_md.do_IRQ = apus_do_IRQ;
+ ppc_md.get_irq_source = NULL;
+ ppc_md.init = NULL;
+
+ ppc_md.restart = apus_restart;
+ ppc_md.power_off = apus_power_off;
+ ppc_md.halt = apus_halt;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = apus_set_rtc_time;
+ ppc_md.get_rtc_time = apus_get_rtc_time;
+ ppc_md.calibrate_decr = apus_calibrate_decr;
+
+ /* These should not be used for the APUS yet, since it uses
+ the M68K keyboard now. */
+ ppc_md.kbd_setkeycode = NULL;
+ ppc_md.kbd_getkeycode = NULL;
+ ppc_md.kbd_translate = NULL;
+ ppc_md.kbd_unexpected_up = NULL;
+ ppc_md.kbd_leds = NULL;
+ ppc_md.kbd_init_hw = NULL;
+ ppc_md.kbd_sysrq_xlate = NULL;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = apus_ide_insw;
+ ppc_ide_md.outsw = apus_ide_outsw;
+ ppc_ide_md.default_irq = apus_ide_default_irq;
+ ppc_ide_md.default_io_base = apus_ide_default_io_base;
+ ppc_ide_md.check_region = apus_ide_check_region;
+ ppc_ide_md.request_region = apus_ide_request_region;
+ ppc_ide_md.release_region = apus_ide_release_region;
+ ppc_ide_md.fix_driveid = apus_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = _IO_BASE;
+#endif
+}
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
index 98a3e182e..fa4dda10b 100644
--- a/arch/ppc/kernel/chrp_pci.c
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -15,10 +15,14 @@
#include <asm/hydra.h>
#include <asm/prom.h>
#include <asm/gg2.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
/* LongTrail */
#define pci_config_addr(bus, dev, offset) \
- (GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
+(GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
volatile struct Hydra *Hydra = NULL;
@@ -30,144 +34,136 @@ volatile struct Hydra *Hydra = NULL;
int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
{
- if (bus > 7) {
- *val = 0xff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short *val)
{
- if (bus > 7) {
- *val = 0xffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int *val)
{
- if (bus > 7) {
- *val = 0xffffffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
- *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char val)
{
- if (bus > 7)
- return PCIBIOS_DEVICE_NOT_FOUND;
- out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val)
{
- if (bus > 7)
- return PCIBIOS_DEVICE_NOT_FOUND;
- out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
}
int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val)
{
- if (bus > 7)
- return PCIBIOS_DEVICE_NOT_FOUND;
- out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
}
-extern volatile unsigned int *pci_config_address;
-extern volatile unsigned char *pci_config_data;
-
-#define DEV_FN_MAX (31<<3)
+#define python_config_address(bus) (unsigned *)((0xfef00000+0xf8000)-(bus*0x100000))
+#define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000))
+#define PYTHON_CFA(b, d, o) (0x80 | ((b<<6) << 8) | ((d) << 16) \
+ | (((o) & ~3) << 24))
+unsigned int python_busnr = 1;
-int raven_pcibios_read_config_byte(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned char *val)
+int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- *val = in_8(pci_config_data+(offset&3));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ *val = in_8((unsigned char *)python_config_data(bus) + (offset&3));
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_read_config_word(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned short *val)
+int python_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- *val = in_le16((volatile unsigned short *)
- (pci_config_data+(offset&3)));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ *val = in_le16((unsigned short *)(python_config_data(bus) + (offset&3)));
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_read_config_dword(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned int *val)
+
+int python_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
- *val = in_le32((volatile unsigned int *)(pci_config_data));
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ *val = in_le32((unsigned *)python_config_data(bus));
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_write_config_byte(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned char val)
+int python_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- out_8(pci_config_data+(offset&3),val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ out_8((volatile unsigned char *)python_config_data(bus) + (offset&3), val);
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_write_config_word(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned short val)
+int python_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
- out_le16((volatile unsigned short *)(pci_config_data+(offset&3)),val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ out_le16((volatile unsigned short *)python_config_data(bus) + (offset&3),
+ val);
+ return PCIBIOS_SUCCESSFUL;
}
-int raven_pcibios_write_config_dword(unsigned char bus,
- unsigned char dev_fn,
- unsigned char offset,
- unsigned int val)
+int python_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
{
- if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
- if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
- out_be32(pci_config_address,
- 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
- out_le32((volatile unsigned int *)pci_config_data,val);
- return PCIBIOS_SUCCESSFUL;
+ if (bus > python_busnr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
+ out_le32((unsigned *)python_config_data(bus) + (offset&3), val);
+ return PCIBIOS_SUCCESSFUL;
}
/*
@@ -191,7 +187,8 @@ static u_char hydra_openpic_initsenses[] __initdata = {
/* all others are 1 (= default) */
};
-__initfunc(int hydra_init(void))
+int __init
+hydra_init(void)
{
struct device_node *np;
@@ -216,75 +213,95 @@ __initfunc(int hydra_init(void))
return 1;
}
-
-extern int chrp_ide_irq;
-
-__initfunc(int w83c553f_init(void))
+void __init
+chrp_pcibios_fixup(void)
{
- u_char bus, dev;
-#if 0
- unsigned char t8;
- unsigned short t16;
-#endif
- unsigned int t32;
- struct pci_dev *pdev;
- if ((pdev = pci_find_device(PCI_VENDOR_ID_WINBOND,
- PCI_DEVICE_ID_WINBOND_83C553, NULL))) {
- bus = pdev->bus->number;
- dev = pdev->devfn + 1;
- pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
- if (t32 == (PCI_DEVICE_ID_WINBOND_82C105<<16) + PCI_VENDOR_ID_WINBOND) {
-#if 0
- printk("Enabling SL82C105 IDE on W83C553F\n");
- /*
- * FIXME: this doesn't help :-(
- */
-
- /* I/O mapping */
- pcibios_read_config_word(bus, dev, PCI_COMMAND, &t16);
- t16 |= PCI_COMMAND_IO;
- pcibios_write_config_word(bus, dev, PCI_COMMAND, t16);
-
- /* Standard IDE registers */
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
- 0x000001f0 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_1,
- 0x000003f4 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_2, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_2,
- 0x00000170 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_3, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_3,
- 0x00000374 | 1);
+ struct pci_dev *dev;
+
+ /* some of IBM chrps have > 1 bus */
+ if ( !strncmp("IBM", get_property(find_path_device("/"),
+ "name", NULL),3) )
+ {
+ pci_scan_peer_bridge(1);
+ pci_scan_peer_bridge(2);
+ }
+
+ /* PCI interrupts are controlled by the OpenPIC */
+ for( dev=pci_devices ; dev; dev=dev->next )
+ {
+ if ( dev->irq )
+ dev->irq = openpic_to_irq( dev->irq );
+ /* adjust the io_port for the NCR cards for busses other than 0 -- Cort */
+ if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) )
+ dev->base_address[0] += (dev->bus->number*0x08000000);
+ /* these need to be absolute addrs for OF and Matrox FB -- Cort */
+ if ( dev->vendor == PCI_VENDOR_ID_MATROX )
+ {
+ if ( dev->base_address[0] < isa_mem_base )
+ dev->base_address[0] += isa_mem_base;
+ if ( dev->base_address[1] < isa_mem_base )
+ dev->base_address[1] += isa_mem_base;
+ }
+ /* the F50 identifies the amd as a trident */
+ if ( (dev->vendor == PCI_VENDOR_ID_TRIDENT) &&
+ (dev->class == PCI_CLASS_NETWORK_ETHERNET) )
+ {
+ dev->vendor = PCI_VENDOR_ID_AMD;
+ pcibios_write_config_word(dev->bus->number, dev->devfn,
+ PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
+ }
+ }
+}
- /* IDE Bus Master Control */
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_4, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_4,
- 0x1000 | 1);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5,
- 0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_5, &t32);
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_5,
- 0x1010 | 1);
+decl_config_access_method(grackle);
+decl_config_access_method(indirect);
- /* IDE Interrupt */
- pcibios_read_config_byte(bus, dev, PCI_INTERRUPT_LINE, &t8);
- chrp_ide_irq = t8;
-#endif
- return 1;
- }
- }
- return 0;
+void __init
+chrp_setup_pci_ptrs(void)
+{
+ struct device_node *py;
+
+ if ( !strncmp("MOT",
+ get_property(find_path_device("/"), "model", NULL),3) )
+ {
+ pci_dram_offset = 0;
+ isa_mem_base = 0xf7000000;
+ isa_io_base = 0xfe000000;
+ set_config_access_method(grackle);
+ }
+ else
+ {
+ if ( (py = find_compatible_devices( "pci", "IBM,python" )) )
+ {
+ /* find out how many pythons */
+ while ( (py = py->next) ) python_busnr++;
+ set_config_access_method(python);
+ /*
+ * We base these values on the machine type but should
+ * try to read them from the python controller itself.
+ * -- Cort
+ */
+ if ( !strncmp("IBM,7025-F50", get_property(find_path_device("/"), "name", NULL),12) )
+ {
+ pci_dram_offset = 0x80000000;
+ isa_mem_base = 0xa0000000;
+ isa_io_base = 0x88000000;
+ } else if ( !strncmp("IBM,7043-260",
+ get_property(find_path_device("/"), "name", NULL),12) )
+ {
+ pci_dram_offset = 0x80000000;
+ isa_mem_base = 0xc0000000;
+ isa_io_base = 0xf8000000;
+ }
+ }
+ else
+ {
+ pci_dram_offset = 0;
+ isa_mem_base = 0xf7000000;
+ isa_io_base = 0xf8000000;
+ set_config_access_method(gg2);
+ }
+ }
+
+ ppc_md.pcibios_fixup = chrp_pcibios_fixup;
}
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index 5b373c876..2c652f049 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -31,6 +31,7 @@
#include <linux/ioport.h>
#include <linux/console.h>
#include <linux/pci.h>
+#include <linux/openpic.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -40,9 +41,50 @@
#include <asm/prom.h>
#include <asm/gg2.h>
#include <asm/pci-bridge.h>
-
-extern void hydra_init(void);
-extern void w83c553f_init(void);
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/adb.h>
+#include <asm/hydra.h>
+
+#include "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
+
+/* Fixme - need to move these into their own .c and .h file */
+extern void i8259_mask_and_ack_irq(unsigned int irq_nr);
+extern void i8259_set_irq_mask(unsigned int irq_nr);
+extern void i8259_mask_irq(unsigned int irq_nr);
+extern void i8259_unmask_irq(unsigned int irq_nr);
+extern void i8259_init(void);
+
+/* Fixme - remove this when it is fixed. - Corey */
+extern volatile unsigned char *chrp_int_ack_special;
+
+unsigned long chrp_get_rtc_time(void);
+int chrp_set_rtc_time(unsigned long nowtime);
+void chrp_calibrate_decr(void);
+void chrp_time_init(void);
+
+void chrp_setup_pci_ptrs(void);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+extern unsigned char mackbd_sysrq_xlate[128];
/* for the mac fs */
kdev_t boot_dev;
@@ -53,7 +95,6 @@ extern int probingmem;
extern unsigned long loops_per_sec;
unsigned long empty_zero_page[1024];
-extern unsigned char aux_device_present;
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
@@ -62,17 +103,17 @@ extern int rd_image_start; /* starting block # of image */
#endif
static const char *gg2_memtypes[4] = {
- "FPM", "SDRAM", "EDO", "BEDO"
+ "FPM", "SDRAM", "EDO", "BEDO"
};
static const char *gg2_cachesizes[4] = {
- "256 KB", "512 KB", "1 MB", "Reserved"
+ "256 KB", "512 KB", "1 MB", "Reserved"
};
static const char *gg2_cachetypes[4] = {
- "Asynchronous", "Reserved", "Flow-Through Synchronous",
- "Pipelined Synchronous"
+ "Asynchronous", "Reserved", "Flow-Through Synchronous",
+ "Pipelined Synchronous"
};
static const char *gg2_cachemodes[4] = {
- "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+ "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
};
int
@@ -85,53 +126,60 @@ chrp_get_cpuinfo(char *buffer)
root = find_path_device("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = get_property(root, "model", NULL);
len = sprintf(buffer,"machine\t\t: CHRP %s\n", model);
- /* VLSI VAS96011/12 `Golden Gate 2' */
- /* Memory banks */
- sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_CTRL))
- >>31) & 1;
- for (i = 0; i < (sdramen ? 4 : 6); i++) {
- t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_DRAM_BANK0+
- i*4));
- if (!(t & 1))
- continue;
- switch ((t>>8) & 0x1f) {
- case 0x1f:
- model = "4 MB";
- break;
- case 0x1e:
- model = "8 MB";
- break;
- case 0x1c:
- model = "16 MB";
- break;
- case 0x18:
- model = "32 MB";
- break;
- case 0x10:
- model = "64 MB";
- break;
- case 0x00:
- model = "128 MB";
- break;
- default:
- model = "Reserved";
- break;
- }
- len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model,
- gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
+ /* longtrail (goldengate) stuff */
+ if ( !strncmp( model, "IBM,LongTrail", 9 ) )
+ {
+ /* VLSI VAS96011/12 `Golden Gate 2' */
+ /* Memory banks */
+ sdramen = (in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
+ GG2_PCI_DRAM_CTRL))
+ >>31) & 1;
+ for (i = 0; i < (sdramen ? 4 : 6); i++) {
+ t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+
+ GG2_PCI_DRAM_BANK0+
+ i*4));
+ if (!(t & 1))
+ continue;
+ switch ((t>>8) & 0x1f) {
+ case 0x1f:
+ model = "4 MB";
+ break;
+ case 0x1e:
+ model = "8 MB";
+ break;
+ case 0x1c:
+ model = "16 MB";
+ break;
+ case 0x18:
+ model = "32 MB";
+ break;
+ case 0x10:
+ model = "64 MB";
+ break;
+ case 0x00:
+ model = "128 MB";
+ break;
+ default:
+ model = "Reserved";
+ break;
+ }
+ len += sprintf(buffer+len, "memory bank %d\t: %s %s\n", i, model,
+ gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]);
+ }
+ /* L2 cache */
+ t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
+ len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n",
+ gg2_cachesizes[(t>>7) & 3],
+ gg2_cachetypes[(t>>2) & 3],
+ gg2_cachemodes[t & 3]);
}
- /* L2 cache */
- t = in_le32((unsigned *)(GG2_PCI_CONFIG_BASE+GG2_PCI_CC_CTRL));
- len += sprintf(buffer+len, "board l2\t: %s %s (%s)\n",
- gg2_cachesizes[(t>>7) & 3], gg2_cachetypes[(t>>2) & 3],
- gg2_cachemodes[t & 3]);
return len;
}
- /*
+/*
* Fixes for the National Semiconductor PC78308VUL SuperI/O
*
* Some versions of Open Firmware incorrectly initialize the IRQ settings
@@ -140,57 +188,55 @@ chrp_get_cpuinfo(char *buffer)
__initfunc(static inline void sio_write(u8 val, u8 index))
{
- outb(index, 0x15c);
- outb(val, 0x15d);
+ outb(index, 0x15c);
+ outb(val, 0x15d);
}
__initfunc(static inline u8 sio_read(u8 index))
{
- outb(index, 0x15c);
- return inb(0x15d);
+ outb(index, 0x15c);
+ return inb(0x15d);
}
__initfunc(static void sio_fixup_irq(const char *name, u8 device, u8 level,
u8 type))
{
- u8 level0, type0, active;
-
- /* select logical device */
- sio_write(device, 0x07);
- active = sio_read(0x30);
- level0 = sio_read(0x70);
- type0 = sio_read(0x71);
- printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
- !active ? "in" : "");
- if (level0 == level && type0 == type && active)
- printk("OK\n");
- else {
- printk("remapping to level %d, type %d, active\n", level, type);
- sio_write(0x01, 0x30);
- sio_write(level, 0x70);
- sio_write(type, 0x71);
- }
+ u8 level0, type0, active;
+
+ /* select logical device */
+ sio_write(device, 0x07);
+ active = sio_read(0x30);
+ level0 = sio_read(0x70);
+ type0 = sio_read(0x71);
+ printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
+ !active ? "in" : "");
+ if (level0 == level && type0 == type && active)
+ printk("OK\n");
+ else {
+ printk("remapping to level %d, type %d, active\n", level, type);
+ sio_write(0x01, 0x30);
+ sio_write(level, 0x70);
+ sio_write(type, 0x71);
+ }
}
__initfunc(static void sio_init(void))
{
- /* logical device 0 (KBC/Keyboard) */
- sio_fixup_irq("keyboard", 0, 1, 2);
- /* select logical device 1 (KBC/Mouse) */
- sio_fixup_irq("mouse", 1, 12, 2);
+ /* logical device 0 (KBC/Keyboard) */
+ sio_fixup_irq("keyboard", 0, 1, 2);
+ /* select logical device 1 (KBC/Mouse) */
+ sio_fixup_irq("mouse", 1, 12, 2);
}
__initfunc(void
-chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
+ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
extern char cmd_line[];
/* init to some ~sane value until calibrate_delay() runs */
loops_per_sec = 50000000;
-
- aux_device_present = 0xaa;
#ifdef CONFIG_BLK_DEV_INITRD
/* this is fine for chrp */
@@ -219,8 +265,15 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
* -- Geert
*/
hydra_init(); /* Mac I/O */
- w83c553f_init(); /* PCI-ISA bridge and IDE */
+ /* Some IBM machines don't have the hydra -- Cort */
+ if ( !OpenPIC )
+ {
+ OpenPIC = (struct OpenPIC *)*(unsigned long *)get_property(
+ find_path_device("/"), "platform-open-pic", NULL);
+ OpenPIC = ioremap((unsigned long)OpenPIC, sizeof(struct OpenPIC));
+ }
+
/*
* Fix the Super I/O configuration
*/
@@ -232,27 +285,210 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
if ( !strncmp("MOT", get_property(find_path_device("/"),
"model", NULL),3) )
*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+ /*
+ * The f50 has a lot of IO space - we need to map some in that
+ * isn't covered by the BAT mappings in MMU_init() -- Cort
+ */
+ if ( !strncmp("F5", get_property(find_path_device("/"),
+ "ibm,model-class", NULL),2) )
+ {
+#if 0
+ /*
+ * This ugly hack allows us to force ioremap() to
+ * create a 1-to-1 mapping for us, even though
+ * the address is < ioremap_base. This is necessary
+ * since we want our PCI IO space to have contiguous
+ * virtual addresses and I think it's worse to have
+ * calls to map_page() here.
+ * -- Cort
+ */
+ unsigned long hold = ioremap_base;
+ ioremap_base = 0;
+ __ioremap(0x90000000, 0x10000000, _PAGE_NO_CACHE);
+ ioremap_base = hold;
+#endif
+ }
}
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+void
+chrp_restart(char *cmd)
+{
+#if 0
+ extern unsigned int rtas_entry, rtas_data, rtas_size;
+ printk("RTAS system-reboot returned %d\n",
+ call_rtas("system-reboot", 0, 1, NULL));
+ printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+ rtas_entry,rtas_data,rtas_size);
+ for (;;);
+#else
+ printk("System Halted\n");
+ while(1);
+#endif
+}
-unsigned int chrp_ide_irq = 0;
-int chrp_ide_ports_known = 0;
-ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
-ide_ioreg_t chrp_idedma_regbase;
+void
+chrp_power_off(void)
+{
+ /* RTAS doesn't seem to work on Longtrail.
+ For now, do it the same way as the PReP. */
+#if 0
+ extern unsigned int rtas_entry, rtas_data, rtas_size;
+ printk("RTAS power-off returned %d\n",
+ call_rtas("power-off", 2, 1, NULL, 0, 0));
+ printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+ rtas_entry,rtas_data,rtas_size);
+ for (;;);
+#else
+ chrp_restart(NULL);
+#endif
+}
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+chrp_halt(void)
{
- ide_ioreg_t port = base;
- int i = 8;
+ chrp_restart(NULL);
+}
- while (i--)
- *p++ = port++;
- *p++ = port;
- if (irq != NULL)
- *irq = chrp_ide_irq;
+u_int
+chrp_irq_cannonicalize(u_int irq)
+{
+ if (irq == 2)
+ {
+ return 9;
+ }
+ else
+ {
+ return irq;
+ }
+}
+
+void
+chrp_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ int irq;
+ unsigned long bits = 0;
+ int openpic_eoi_done = 0;
+
+#ifdef __SMP__
+ {
+ unsigned int loops = 1000000;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
+#endif /* __SMP__ */
+
+ irq = openpic_irq(0);
+ if (irq == IRQ_8259_CASCADE)
+ {
+ /*
+ * This magic address generates a PCI IACK cycle.
+ *
+ * This should go in the above mask/ack code soon. -- Cort
+ */
+ if ( chrp_int_ack_special )
+ irq = *chrp_int_ack_special;
+ else
+ irq = i8259_irq(0);
+ /*
+ * Acknowledge as soon as possible to allow i8259
+ * interrupt nesting */
+ openpic_eoi(0);
+ openpic_eoi_done = 1;
+ }
+ if (irq == OPENPIC_VEC_SPURIOUS)
+ {
+ /*
+ * Spurious interrupts should never be
+ * acknowledged
+ */
+ ppc_spurious_interrupts++;
+ openpic_eoi_done = 1;
+ goto out;
+ }
+ bits = 1UL << irq;
+
+ if (irq < 0)
+ {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ ppc_spurious_interrupts++;
+ }
+ else
+ {
+ ppc_irq_dispatch_handler( regs, irq );
+ }
+out:
+ if (!openpic_eoi_done)
+ openpic_eoi(0);
}
+__initfunc(void
+ chrp_init_IRQ(void))
+{
+ struct device_node *np;
+ int i;
+
+ if ( !(np = find_devices("pci") ) )
+ printk("Cannot find pci to get ack address\n");
+ else
+ {
+ chrp_int_ack_special = (volatile unsigned char *)
+ (*(unsigned long *)get_property(np,
+ "8259-interrupt-acknowledge", NULL));
+ }
+ for ( i = 16 ; i < NR_IRQS ; i++ )
+ irq_desc[i].ctl = &open_pic;
+ /* openpic knows that it's at irq 16 offset
+ * so we don't need to set it in the pic structure
+ * -- Cort
+ */
+ openpic_init(1);
+ for ( i = 0 ; i < 16 ; i++ )
+ irq_desc[i].ctl = &i8259_pic;
+ i8259_init();
+#ifdef CONFIG_XMON
+ request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
+ xmon_irq, 0, "NMI", 0);
+#endif /* CONFIG_XMON */
+#ifdef __SMP__
+ request_irq(openpic_to_irq(OPENPIC_VEC_IPI),
+ openpic_ipi_action, 0, "IPI0", 0);
+#endif /* __SMP__ */
+}
+
+__initfunc(void
+ chrp_init2(void))
+{
+ adb_init();
+
+ /* Should this be here? - Corey */
+ pmac_nvram_init();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+unsigned int chrp_ide_irq = 0;
+int chrp_ide_ports_known = 0;
+ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
+ide_ioreg_t chrp_idedma_regbase;
+
void chrp_ide_probe(void) {
struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
@@ -270,9 +506,167 @@ void chrp_ide_probe(void) {
}
}
+void
+chrp_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port+_IO_BASE, buf, ns);
+}
+
+void
+chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+chrp_ide_default_irq(ide_ioreg_t base)
+{
+ if (chrp_ide_ports_known == 0)
+ chrp_ide_probe();
+ return chrp_ide_irq;
+}
+
+ide_ioreg_t
+chrp_ide_default_io_base(int index)
+{
+ if (chrp_ide_ports_known == 0)
+ chrp_ide_probe();
+ return chrp_ide_regbase[index];
+}
+
+int
+chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return check_region(from, extent);
+}
+
+void
+chrp_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+ request_region(from, extent, name);
+}
+
+void
+chrp_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+ release_region(from, extent);
+}
+
+void
+chrp_ide_fix_driveid(struct hd_driveid *id)
+{
+ ppc_generic_ide_fix_driveid(id);
+}
+
+void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = port;
+ if (irq != NULL)
+ *irq = chrp_ide_irq;
+}
+
EXPORT_SYMBOL(chrp_ide_irq);
EXPORT_SYMBOL(chrp_ide_ports_known);
EXPORT_SYMBOL(chrp_ide_regbase);
EXPORT_SYMBOL(chrp_ide_probe);
#endif
+
+__initfunc(void
+ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ chrp_setup_pci_ptrs();
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if ( r3 )
+ {
+ initrd_start = r3 + KERNELBASE;
+ initrd_end = r3 + r4 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ ppc_md.setup_arch = chrp_setup_arch;
+ ppc_md.setup_residual = NULL;
+ ppc_md.get_cpuinfo = chrp_get_cpuinfo;
+ ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
+ ppc_md.init_IRQ = chrp_init_IRQ;
+ ppc_md.do_IRQ = chrp_do_IRQ;
+
+ ppc_md.init = chrp_init2;
+
+ ppc_md.restart = chrp_restart;
+ ppc_md.power_off = chrp_power_off;
+ ppc_md.halt = chrp_halt;
+
+ ppc_md.time_init = chrp_time_init;
+ ppc_md.set_rtc_time = chrp_set_rtc_time;
+ ppc_md.get_rtc_time = chrp_get_rtc_time;
+ ppc_md.calibrate_decr = chrp_calibrate_decr;
+
+#ifdef CONFIG_VT
+#ifdef CONFIG_MAC_KEYBOAD
+ if ( adb_hardware == ADB_NONE )
+ {
+ ppc_md.kbd_setkeycode = pckbd_setkeycode;
+ ppc_md.kbd_getkeycode = pckbd_getkeycode;
+ ppc_md.kbd_translate = pckbd_translate;
+ ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+ ppc_md.kbd_leds = pckbd_leds;
+ ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+ }
+ else
+ {
+ ppc_md.kbd_setkeycode = mackbd_setkeycode;
+ ppc_md.kbd_getkeycode = mackbd_getkeycode;
+ ppc_md.kbd_translate = mackbd_translate;
+ ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
+ ppc_md.kbd_leds = mackbd_leds;
+ ppc_md.kbd_init_hw = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate;
+#endif
+ }
+#else
+ ppc_md.kbd_setkeycode = pckbd_setkeycode;
+ ppc_md.kbd_getkeycode = pckbd_getkeycode;
+ ppc_md.kbd_translate = pckbd_translate;
+ ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+ ppc_md.kbd_leds = pckbd_leds;
+ ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = chrp_ide_insw;
+ ppc_ide_md.outsw = chrp_ide_outsw;
+ ppc_ide_md.default_irq = chrp_ide_default_irq;
+ ppc_ide_md.default_io_base = chrp_ide_default_io_base;
+ ppc_ide_md.check_region = chrp_ide_check_region;
+ ppc_ide_md.request_region = chrp_ide_request_region;
+ ppc_ide_md.release_region = chrp_ide_release_region;
+ ppc_ide_md.fix_driveid = chrp_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = _IO_BASE;
+#endif
+}
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
index 7a2ea7b26..c374c9bd1 100644
--- a/arch/ppc/kernel/chrp_time.c
+++ b/arch/ppc/kernel/chrp_time.c
@@ -154,7 +154,8 @@ unsigned long chrp_get_rtc_time(void)
__initfunc(void chrp_calibrate_decr(void))
{
struct device_node *cpu;
- int freq, *fp, divisor;
+ int *fp, divisor;
+ unsigned long freq;
if (via_calibrate_decr())
return;
@@ -170,10 +171,9 @@ __initfunc(void chrp_calibrate_decr(void))
if (fp != 0)
freq = *fp;
}
-
freq *= 60; /* try to make freq/1e6 an integer */
divisor = 60;
- printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ printk("time_init: decrementer frequency = %lu/%d\n", freq, divisor);
decrementer_count = freq / HZ / divisor;
count_period_num = divisor;
count_period_den = freq / 1000000;
diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c
index 48d8bcb39..25ee3424b 100644
--- a/arch/ppc/kernel/feature.c
+++ b/arch/ppc/kernel/feature.c
@@ -41,7 +41,6 @@ static u32 feature_bits_pbook[] = {
OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
0, /* FEATURE_BMac_reset */
0, /* FEATURE_BMac_IO_enable */
- 0, /* FEATURE_Modem_PowerOn -> guess...*/
0 /* FEATURE_Modem_Reset -> guess...*/
};
@@ -64,8 +63,7 @@ static u32 feature_bits_heathrow[] = {
OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
0x80000000, /* FEATURE_BMac_reset */
0x60000000, /* FEATURE_BMac_IO_enable */
- 0x02000000, /* FEATURE_Modem_PowerOn -> guess...*/
- 0x07000000 /* FEATURE_Modem_Reset -> guess...*/
+ 0x02000000 /* FEATURE_Modem_Reset -> guess...*/
};
/* definition of a feature controller object */
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index d7b791387..b9ecc2dcc 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -1,7 +1,7 @@
/*
* arch/ppc/kernel/head.S
*
- * $Id: head.S,v 1.114 1998/12/28 10:28:45 paulus Exp $
+ * $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -44,8 +44,13 @@
/* optimization for 603 to load the tlb directly from the linux table */
#define NO_RELOAD_HTAB 1
+#ifndef CONFIG_8xx
CACHE_LINE_SIZE = 32
LG_CACHE_LINE_SIZE = 5
+#else
+CACHE_LINE_SIZE = 16
+LG_CACHE_LINE_SIZE = 4
+#endif
#define TOPHYS(x) (x - KERNELBASE)
@@ -81,13 +86,12 @@ LG_CACHE_LINE_SIZE = 5
sync; \
isync
-/* This instruction is not implemented on the PPC 603 or 601 */
#ifndef CONFIG_8xx
/* This instruction is not implemented on the PPC 603 or 601 */
#define tlbia \
li r4,128; \
mtctr r4; \
- lis r4,0xC000; \
+ lis r4,KERNELBASE@h; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
@@ -212,6 +216,7 @@ __start:
mr r29,r5
mr r28,r6
mr r27,r7
+ li r24,0 /* cpu # */
#ifndef CONFIG_8xx
bl prom_init
.globl __secondary_start
@@ -236,15 +241,33 @@ __secondary_start:
mtspr IBAT1L,r10
b 5f
4:
-#ifndef CONFIG_APUS
- ori r11,r11,0x1fe /* set up BAT registers for 604 */
- li r8,2 /* R/W access */
-#else
+#ifdef CONFIG_APUS
+ ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */
ori r11,r11,0xfe /* set up an 8MB mapping */
lis r8,CYBERBASEp@h
lwz r8,0(r8)
addis r8,r8,KERNELBASE@h
addi r8,r8,2
+#else
+ ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */
+ li r8,2 /* R/W access */
+ /*
+ * allow secondary cpus to get at all of ram in early bootup
+ * since their init_task may be up there -- Cort
+ */
+ oris r18,r8,0x10000000@h
+ oris r21,r11,(KERNELBASE+0x10000000)@h
+ mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT1U,r21 /* bit in upper BAT register */
+ mtspr IBAT1L,r18
+ mtspr IBAT1U,r21
+
+ oris r18,r8,0x20000000@h
+ oris r21,r11,(KERNELBASE+0x20000000)@h
+ mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT2U,r21 /* bit in upper BAT register */
+ mtspr IBAT2L,r28
+ mtspr IBAT2U,r21
#endif
mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
mtspr DBAT0U,r11 /* bit in upper BAT register */
@@ -327,20 +350,28 @@ __secondary_start:
lis r8, MI_Kp@h /* Set the protection mode */
mtspr MI_AP, r8
mtspr MD_AP, r8
-#ifdef CONFIG_MBX
+
+/* We will get these from a configuration file as soon as I verify
+ * the extraneous bits don't cause problems in the TLB.
+ */
+#if defined(CONFIG_MBX) || defined(CONFIG_RPXLITE)
+#define BOOT_IMMR 0xfa000000
+#endif
+#ifdef CONFIG_BSEIP
+#define BOOT_IMMR 0xff000000
+#endif
/* Map another 8 MByte at 0xfa000000 to get the processor
* internal registers (among other things).
*/
- lis r8, 0xfa000000@h /* Create vaddr for TLB */
+ lis r8, BOOT_IMMR@h /* Create vaddr for TLB */
ori r8, r8, MD_EVALID /* Mark it valid */
mtspr MD_EPN, r8
li r8, MD_PS8MEG /* Set 8M byte page */
ori r8, r8, MD_SVALID /* Make it valid */
mtspr MD_TWC, r8
- lis r8, 0xfa000000@h /* Create paddr for TLB */
+ lis r8, BOOT_IMMR@h /* Create paddr for TLB */
ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */
mtspr MD_RPN, r8
-#endif
/* Since the cache is enabled according to the information we
* just loaded into the TLB, invalidate and enable the caches here.
@@ -354,9 +385,8 @@ __secondary_start:
#if 0
mtspr DC_CST, r8
#else
- /* I still have a bug somewhere because the Ethernet driver
- * does not want to work with copyback enabled. For now,
- * at least enable write through.
+ /* For a debug option, I left this here to easily enable
+ * the write through cache mode
*/
lis r8, DC_SFWT@h
mtspr DC_CST, r8
@@ -385,7 +415,7 @@ turn_on_mmu:
* this, we leave this much untouched space on the stack on exception
* entry.
*/
-#define STACK_UNDERHEAD 64
+#define STACK_UNDERHEAD 0
/*
* Exception entry code. This code runs with address translation
@@ -442,7 +472,11 @@ label: \
.long int_return
/* System reset */
+#ifdef CONFIG_SMP /* MVME/MTX start the secondary here */
+ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
+#else
STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -1148,6 +1182,8 @@ transfer_to_handler:
mflr r23
andi. r24,r23,0x3f00 /* get vector offset */
stw r24,TRAP(r21)
+ li r22,RESULT
+ stwcx. r22,r22,r21 /* to clear the reservation */
li r22,0
stw r22,RESULT(r21)
mtspr SPRG2,r22 /* r1 is now kernel sp */
@@ -1155,7 +1191,7 @@ transfer_to_handler:
cmplw 0,r1,r2
cmplw 1,r1,r24
crand 1,1,4
- bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
+ bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
lwz r24,0(r23) /* virtual address of handler */
lwz r23,4(r23) /* where to go when done */
mtspr SRR0,r24
@@ -1204,13 +1240,10 @@ Hash_base = 0x180000
Hash_bits = 12 /* e.g. 256kB hash table */
Hash_msk = (((1 << Hash_bits) - 1) * 64)
- .globl hash_table_lock
-hash_table_lock:
-.long 0
-
.globl hash_page
hash_page:
#ifdef __SMP__
+ eieio
lis r2,hash_table_lock@h
ori r2,r2,hash_table_lock@l
tophys(r2,r2,r6)
@@ -1226,7 +1259,7 @@ hash_page:
12: cmpw r6,r0
bdnzf 2,10b
tw 31,31,31
-11:
+11: eieio
#endif
/* Get PTE (linux-style) and check access */
lwz r5,PG_TABLES(r5)
@@ -1234,13 +1267,25 @@ hash_page:
rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
lwz r5,0(r5) /* get pmd entry */
rlwinm. r5,r5,0,0,19 /* extract address of pte page */
+#ifdef __SMP__
beq- hash_page_out /* return if no mapping */
+#else
+ /* XXX it seems like the 601 will give a machine fault on the
+ rfi if its alignment is wrong (bottom 4 bits of address are
+ 8 or 0xc) and we have had a not-taken conditional branch
+ to the address following the rfi. */
+ beqlr-
+#endif
tophys(r2,r5,r2)
rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
lwz r6,0(r2) /* get linux-style pte */
ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
andc. r0,r4,r6 /* check access & ~permission */
+#ifdef __SMP__
bne- hash_page_out /* return if access not permitted */
+#else
+ bnelr-
+#endif
ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */
rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
@@ -1257,7 +1302,9 @@ hash_page:
/* Construct the high word of the PPC-style PTE */
mfsrin r5,r3 /* get segment reg for segment */
rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */
+#ifndef __SMP__ /* do this later for SMP */
oris r5,r5,0x8000 /* set V (valid) bit */
+#endif
rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */
/* Get the address of the primary PTE group in the hash table */
@@ -1274,9 +1321,6 @@ hash_page_patch_A:
li r2,8 /* PTEs/group */
bne 10f /* no PTE: go look for an empty slot */
tlbie r3 /* invalidate TLB entry */
-#ifdef __SMP__
- tlbsync
-#endif
/* Search the primary PTEG for a PTE whose 1st word matches r5 */
mtctr r2
@@ -1345,18 +1389,43 @@ hash_page_patch_C:
addi r4,r4,1
stw r4,0(r2)
+#ifndef __SMP__
/* Store PTE in PTEG */
found_empty:
stw r5,0(r3)
found_slot:
stw r6,4(r3)
- SYNC
+ sync
+
+#else /* __SMP__ */
/*
- * These nop's seem to be necessary to avoid getting a machine
- * check on the rfi on 601 processors.
+ * Between the tlbie above and updating the hash table entry below,
+ * another CPU could read the hash table entry and put it in its TLB.
+ * There are 3 cases:
+ * 1. using an empty slot
+ * 2. updating an earlier entry to change permissions (i.e. enable write)
+ * 3. taking over the PTE for an unrelated address
+ *
+ * In each case it doesn't really matter if the other CPUs have the old
+ * PTE in their TLB. So we don't need to bother with another tlbie here,
+ * which is convenient as we've overwritten the register that had the
+ * address. :-) The tlbie above is mainly to make sure that this CPU comes
+ * and gets the new PTE from the hash table.
+ *
+ * We do however have to make sure that the PTE is never in an invalid
+ * state with the V bit set.
*/
- nop
- nop
+found_empty:
+found_slot:
+ stw r5,0(r3) /* clear V (valid) bit in PTE */
+ sync
+ tlbsync
+ sync
+ stw r6,4(r3) /* put in correct RPN, WIMG, PP bits */
+ sync
+ oris r5,r5,0x8000
+ stw r5,0(r3) /* finally set V bit in PTE */
+#endif /* __SMP__ */
/*
* Update the hash table miss count. We only want misses here
@@ -1380,6 +1449,7 @@ found_slot:
tophys(r2,r2,r6)
li r0,0
stw r0,hash_table_lock@l(r2)
+ eieio
#endif
/* Return from the exception */
@@ -1398,17 +1468,22 @@ found_slot:
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
- SYNC
rfi
-hash_page_out:
#ifdef __SMP__
+hash_page_out:
lis r2,hash_table_lock@ha
tophys(r2,r2,r6)
li r0,0
stw r0,hash_table_lock@l(r2)
-#endif
+ eieio
blr
+
+ .globl hash_table_lock
+hash_table_lock:
+ .long 0
+#endif
+
next_slot:
.long 0
@@ -1420,27 +1495,25 @@ load_up_fpu:
* On SMP we know the fpu is free, since we give it up every
* switch. -- Cort
*/
+ mfmsr r5
+ ori r5,r5,MSR_FP
+ SYNC
+ mtmsr r5 /* enable use of fpu now */
+ SYNC
+/*
+ * For SMP, we don't do lazy FPU switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another. Instead we call giveup_fpu in switch_to.
+ */
+#ifndef __SMP__
#ifndef CONFIG_APUS
lis r6,-KERNELBASE@h
#else
lis r6,CYBERBASEp@h
lwz r6,0(r6)
#endif
-
addis r3,r6,last_task_used_math@ha
lwz r4,last_task_used_math@l(r3)
- mfmsr r5
- ori r5,r5,MSR_FP
- SYNC
- mtmsr r5 /* enable use of fpu now */
-/*
- * All the saving of last_task_used_math is handled
- * by a switch_to() call to smp_giveup_fpu() in SMP so
- * last_task_used_math is not used.
- * -- Cort
- */
-#ifndef __SMP__
- SYNC
cmpi 0,r4,0
beq 1f
add r4,r4,r6
@@ -1454,15 +1527,17 @@ load_up_fpu:
li r20,MSR_FP|MSR_FE0|MSR_FE1
andc r4,r4,r20 /* disable FP for previous task */
stw r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
#endif /* __SMP__ */
-1: ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 /* enable use of FP after return */
+ /* enable use of FP after return */
+ ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1
mfspr r5,SPRG3 /* current task's TSS (phys) */
lfd fr0,TSS_FPSCR-4(r5)
mtfsf 0xff,fr0
REST_32FPRS(0, r5)
+#ifndef __SMP__
subi r4,r5,TSS
sub r4,r4,r6
-#ifndef __SMP__
stw r4,last_task_used_math@l(r3)
#endif /* __SMP__ */
/* restore registers and return */
@@ -1499,48 +1574,44 @@ KernelFP:
.align 4
/*
- * Disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
+ * giveup_fpu(tsk)
+ * Disable FP for the task given as the argument,
+ * and save the floating-point registers in its thread_struct.
* Enables the FPU for use in the kernel on return.
*/
-/* smp_giveup_fpu() takes an arg to tell it where to save the fpu
- * regs since last_task_used_math can't be trusted (many many race
- * conditions). -- Cort
- */
- .globl smp_giveup_fpu
-smp_giveup_fpu:
- mr r4,r3
- b 12f
.globl giveup_fpu
giveup_fpu:
- lis r3,last_task_used_math@ha
- lwz r4,last_task_used_math@l(r3)
-12:
mfmsr r5
ori r5,r5,MSR_FP
SYNC
mtmsr r5 /* enable use of fpu now */
SYNC
- cmpi 0,r4,0
+ cmpi 0,r3,0
beqlr- /* if no previous owner, done */
- addi r4,r4,TSS /* want TSS of last_task_used_math */
+ addi r3,r3,TSS /* want TSS of task */
+ lwz r5,PT_REGS(r3)
+ cmpi 0,r5,0
+ SAVE_32FPRS(0, r3)
+ mffs fr0
+ stfd fr0,TSS_FPSCR-4(r3)
+ beq 1f
+ lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+ li r3,MSR_FP|MSR_FE0|MSR_FE1
+ andc r4,r4,r3 /* disable FP for previous task */
+ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
#ifndef __SMP__
li r5,0
- stw r5,last_task_used_math@l(r3)
+ lis r4,last_task_used_math@ha
+ stw r5,last_task_used_math@l(r4)
#endif /* __SMP__ */
- SAVE_32FPRS(0, r4)
- mffs fr0
- stfd fr0,TSS_FPSCR-4(r4)
- lwz r5,PT_REGS(r4)
- lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
- li r4,MSR_FP|MSR_FE0|MSR_FE1
- andc r3,r3,r4 /* disable FP for previous task */
- stw r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+ blr
+
#else /* CONFIG_8xx */
.globl giveup_fpu
giveup_fpu:
-#endif /* CONFIG_8xx */
blr
+#endif /* CONFIG_8xx */
/*
* This code is jumped to from the startup code to copy
@@ -1600,10 +1671,38 @@ copy_and_flush:
. = 0x4000
#endif
+#ifdef CONFIG_SMP
+ .globl __secondary_start_psurge
+__secondary_start_psurge:
+ li r24,1 /* cpu # */
+ b __secondary_start
+
+ .globl __secondary_hold
+__secondary_hold:
+ /* tell the master we're here */
+ lis r5,0x4@h
+ ori r5,r5,0x4@l
+ stw r3,0(r5)
+ dcbf 0,r5
+100:
+ lis r5,0
+ dcbi 0,r5
+ lwz r4,0(r5)
+ /* wait until we're told to start */
+ cmp 0,r4,r3
+ bne 100b
+ /* our cpu # was at addr 0 - go */
+ lis r5,__secondary_start@h
+ ori r5,r5,__secondary_start@l
+ tophys(r5,r5,r4)
+ mtlr r5
+ mr r24,r3 /* cpu # */
+ blr
+#endif /* CONFIG_SMP */
+
/*
* This is where the main kernel code starts.
*/
-
start_here:
#ifndef CONFIG_8xx
/*
@@ -1650,9 +1749,9 @@ start_here:
/* get current */
lis r2,current_set@h
ori r2,r2,current_set@l
- addi r2,r2,4
+ slwi r24,r24,2 /* cpu # to current_set[cpu#] */
+ add r2,r2,r24
lwz r2,0(r2)
-
b 10f
99:
#endif /* __SMP__ */
@@ -1677,12 +1776,10 @@ start_here:
#ifdef __SMP__
10:
#endif /* __SMP__ */
-
/* stack */
addi r1,r2,TASK_UNION_SIZE
li r0,0
stwu r0,-STACK_FRAME_OVERHEAD(r1)
-
/*
* Decide what sort of machine this is and initialize the MMU.
*/
@@ -1693,7 +1790,6 @@ start_here:
mr r7,r27
bl identify_machine
bl MMU_init
-
/*
* Go back to running unmapped so we can load up new values
* for SDR1 (hash table pointer) and the segment registers
@@ -1725,8 +1821,10 @@ start_here:
2:
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
+ sync /* wait for tlbia/tlbie to finish */
#ifdef __SMP__
- tlbsync
+ tlbsync /* ... on all CPUs */
+ sync
#endif
#ifndef CONFIG_8xx
mtspr SDR1,r6
@@ -1947,8 +2045,9 @@ _GLOBAL(_switch)
stw r0,GPR0(r1)
lwz r0,0(r1)
stw r0,GPR1(r1)
- SAVE_10GPRS(2, r1)
- SAVE_10GPRS(12, r1)
+ /* r3-r13 are caller saved -- Cort */
+ SAVE_GPR(2, r1)
+ SAVE_8GPRS(14, r1)
SAVE_10GPRS(22, r1)
mflr r20 /* Return to switch caller */
mfmsr r22
@@ -1971,46 +2070,71 @@ _GLOBAL(_switch)
mtspr SPRG3,r0 /* Update current TSS phys addr */
SYNC
lwz r1,KSP(r4) /* Load new stack pointer */
+ /* save the old current 'last' for return value */
+ mr r3,r2
addi r2,r4,-TSS /* Update current */
#ifndef CONFIG_8xx
/* Set up segment registers for new task */
rlwinm r5,r5,4,8,27 /* VSID = context << 4 */
addis r5,r5,0x6000 /* Set Ks, Ku bits */
- li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */
mtctr r0
- li r3,0
-3: mtsrin r5,r3
+ li r9,0
+3: mtsrin r5,r9
addi r5,r5,1 /* next VSID */
- addis r3,r3,0x1000 /* address of next segment */
+ addis r9,r9,0x1000 /* address of next segment */
bdnz 3b
#else
/* On the MPC8xx, we place the physical address of the new task
* page directory loaded into the MMU base register, and set the
* ASID compare register with the new "context".
*/
- lwz r3,MM-TSS(r4) /* Get virtual address of mm */
- lwz r3,PGD(r3) /* get new->mm->pgd */
- addis r3,r3,-KERNELBASE@h /* convert to phys addr */
- mtspr M_TWB, r3 /* Update MMU base address */
+ lwz r9,MM-TSS(r4) /* Get virtual address of mm */
+ lwz r9,PGD(r9) /* get new->mm->pgd */
+ addis r9,r9,-KERNELBASE@h /* convert to phys addr */
+ mtspr M_TWB, r9 /* Update MMU base address */
mtspr M_CASID, r5 /* Update context */
tlbia
#endif
SYNC
-
-/* FALL THROUGH into int_return */
-#ifdef __SMP__
- /* call schedule_tail if this is the first time for a child process */
- lwz r5,TSS_SMP_FORK_RET(r4)
- cmpi 0,r5,0
- beq+ int_return
- li r3,0
- stw r3,TSS_SMP_FORK_RET(r4)
- bl schedule_tail
-#endif /* __SMP__ */
+2: lwz r9,_MSR(r1) /* Returning to user mode? */
+ andi. r9,r9,MSR_PR
+ beq+ 10f /* if not, don't adjust kernel stack */
+8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */
+ stw r4,TSS+KSP(r2) /* save kernel stack pointer */
+ tophys(r9,r1,r9)
+ mtspr SPRG2,r9 /* phys exception stack pointer */
+10: lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ /* r3-r13 are destroyed -- Cort */
+ REST_GPR(14, r1)
+ REST_8GPRS(15, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
/*
* Trap exit.
*/
+#ifdef __SMP__
+ .globl ret_from_smpfork
+ret_from_smpfork:
+ bl schedule_tail
+#endif
.globl ret_from_syscall
ret_from_syscall:
.globl int_return
@@ -2025,8 +2149,8 @@ int_return:
lwz r5,_MSR(r1)
and. r5,r5,r4
beq 2f
-3: lis r4,n_lost_interrupts@ha
- lwz r4,n_lost_interrupts@l(r4)
+3: lis r4,ppc_n_lost_interrupts@ha
+ lwz r4,ppc_n_lost_interrupts@l(r4)
cmpi 0,r4,0
beq+ 1f
addi r3,r1,STACK_FRAME_OVERHEAD
@@ -2118,7 +2242,7 @@ _GLOBAL(fake_interrupt)
_GLOBAL(set_context)
rlwinm r3,r3,4,8,27 /* VSID = context << 4 */
addis r3,r3,0x6000 /* Set Ks, Ku bits */
- li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ li r0,12 /* TASK_SIZE / SEGMENT_SIZE */
mtctr r0
li r4,0
3: mtsrin r3,r4
@@ -2177,6 +2301,27 @@ _GLOBAL(flush_icache_range)
blr
/*
+ * Like above, but only do the D-cache. This is used by the 8xx
+ * to push the cache so the CPM doesn't get stale data.
+ *
+ * flush_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(flush_dcache_range)
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ blr
+
+/*
* Flush a particular page from the DATA cache
* Note: this is necessary because the instruction cache does *not*
* snoop from the data cache.
@@ -2207,25 +2352,35 @@ _GLOBAL(flush_page_to_ram)
blr
/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced). This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+ li r0,4096/CACHE_LINE_SIZE
+ mtctr r0
+1: dcbz 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ blr
+
+/*
* Flush entries from the hash table with VSIDs in the range
* given.
*/
#ifndef CONFIG_8xx
_GLOBAL(flush_hash_segments)
+ lis r5,Hash@ha
+ lwz r5,Hash@l(r5) /* base of hash table */
#ifdef NO_RELOAD_HTAB
-/*
- * Bitmask of PVR numbers of 603-like chips,
- * for which we don't use the hash table at all.
- */
-#define PVR_603_LIKE 0x13000000 /* bits 3, 6, 7 set */
-
- mfspr r0,PVR
- rlwinm r0,r0,16,27,31
- lis r9,PVR_603_LIKE@h
- rlwnm. r0,r9,r0,0,0
- beq+ 99f
+ cmpwi 0,r5,0
+ bne+ 99f
tlbia
- isync
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
99:
#endif /* NO_RELOAD_HTAB */
@@ -2247,14 +2402,13 @@ _GLOBAL(flush_hash_segments)
bne- 10b
stwcx. r8,0,r9
bne- 10b
+ eieio
#endif
rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
oris r3,r3,0x8000 /* set V bit */
rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
oris r4,r4,0x8000
ori r4,r4,0x7f
- lis r5,Hash@ha
- lwz r5,Hash@l(r5) /* base of hash table */
lis r6,Hash_size@ha
lwz r6,Hash_size@l(r6) /* size in bytes */
srwi r6,r6,3 /* # PTEs */
@@ -2270,11 +2424,11 @@ _GLOBAL(flush_hash_segments)
2: bdnz 1b /* continue with loop */
sync
tlbia
- isync
+ sync
#ifdef __SMP__
tlbsync
+ sync
lis r3,hash_table_lock@ha
- li r0,0
stw r0,hash_table_lock@l(r3)
mtmsr r10
SYNC
@@ -2287,14 +2441,17 @@ _GLOBAL(flush_hash_segments)
* flush_hash_page(unsigned context, unsigned long va)
*/
_GLOBAL(flush_hash_page)
+ lis r6,Hash@ha
+ lwz r6,Hash@l(r6) /* hash table base */
#ifdef NO_RELOAD_HTAB
- mfspr r0,PVR
- rlwinm r0,r0,16,27,31
- lis r9,PVR_603_LIKE@h
- rlwnm. r0,r9,r0,0,0
- beq+ 99f
+ cmpwi 0,r6,0 /* hash table in use? */
+ bne+ 99f
tlbie r4 /* in hw tlb too */
- isync
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
99:
#endif /* NO_RELOAD_HTAB */
@@ -2311,11 +2468,12 @@ _GLOBAL(flush_hash_page)
ori r9,r9,hash_table_lock@l
lwz r8,PROCESSOR(r2)
oris r8,r8,9
-10: lwarx r6,0,r9
- cmpi 0,r6,0
+10: lwarx r7,0,r9
+ cmpi 0,r7,0
bne- 10b
stwcx. r8,0,r9
bne- 10b
+ eieio
#endif
rlwinm r3,r3,11,1,20 /* put context into vsid */
rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
@@ -2328,8 +2486,6 @@ _GLOBAL(flush_hash_page)
lwz r5,Hash_mask@l(r5) /* hash mask */
slwi r5,r5,6 /* << 6 */
and r7,r7,r5
- lis r6,Hash@ha
- lwz r6,Hash@l(r6) /* hash table base */
add r6,r6,r7 /* address of primary PTEG */
li r8,8
mtctr r8
@@ -2350,9 +2506,10 @@ _GLOBAL(flush_hash_page)
stw r0,0(r7) /* invalidate entry */
4: sync
tlbie r4 /* in hw tlb too */
- isync
+ sync
#ifdef __SMP__
tlbsync
+ sync
lis r3,hash_table_lock@h
li r0,0
stw r0,hash_table_lock@l(r3)
@@ -2418,30 +2575,27 @@ enter_rtas:
rfi /* return to caller */
#endif /* CONFIG_8xx */
-#ifdef CONFIG_MBX
-/* Jump into the system reset for the MBX rom.
+#ifdef CONFIG_8xx
+/* Jump into the system reset for the rom.
* We first disable the MMU, and then jump to the ROM reset address.
*
- * This does not work, don't bother trying. There is no place in
- * the ROM we can jump to cause a reset. We will have to program
- * a watchdog of some type that we don't service to cause a processor
- * reset.
+ * r3 is the board info structure, r4 is the location for starting.
+ * I use this for building a small kernel that can load other kernels,
+ * rather than trying to write or rely on a rom monitor that can tftp load.
*/
- .globl MBX_gorom
-MBX_gorom:
- li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
- lis r4,2f@h
- addis r4,r4,-KERNELBASE@h
- ori r4,r4,2f@l
- mtspr SRR0,r4
- mtspr SRR1,r3
- rfi
+ .globl m8xx_gorom
+m8xx_gorom:
+ li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ lis r6,2f@h
+ addis r6,r6,-KERNELBASE@h
+ ori r6,r6,2f@l
+ mtspr SRR0,r6
+ mtspr SRR1,r5
+ rfi
2:
- lis r4, 0xfe000000@h
- addi r4, r4, 0xfe000000@l
- mtlr r4
- blr
-#endif /* CONFIG_MBX */
+ mtlr r4
+ blr
+#endif /* CONFIG_8xx */
/*
* We put a few things here that have to be page-aligned.
diff --git a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c
new file mode 100644
index 000000000..4ec6d3e11
--- /dev/null
+++ b/arch/ppc/kernel/i8259.c
@@ -0,0 +1,130 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include "i8259.h"
+
+unsigned char cached_8259[2] = { 0xff, 0xff };
+#define cached_A1 (cached_8259[0])
+#define cached_21 (cached_8259[1])
+
+int i8259_irq(int cpu)
+{
+ int irq;
+
+ /*
+ * Perform an interrupt acknowledge cycle on controller 1
+ */
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+ /*
+ * Interrupt is cascaded so perform interrupt
+ * acknowledge on controller 2
+ */
+ outb(0x0C, 0xA0);
+ irq = (inb(0xA0) & 7) + 8;
+ }
+ else if (irq==7)
+ {
+ /*
+ * This may be a spurious interrupt
+ *
+ * Read the interrupt status register. If the most
+ * significant bit is not set then there is no valid
+ * interrupt
+ */
+ outb(0x0b, 0x20);
+ if(~inb(0x20)&0x80)
+ return -1;
+ }
+ return irq;
+}
+
+static void i8259_mask_and_ack_irq(unsigned int irq_nr)
+{
+ if ( irq_nr >= i8259_pic.irq_offset )
+ irq_nr -= i8259_pic.irq_offset;
+
+ if (irq_nr > 7) {
+ cached_A1 |= 1 << (irq_nr-8);
+ inb(0xA1); /* DUMMY */
+ outb(cached_A1,0xA1);
+ outb(0x20,0xA0); /* Non-specific EOI */
+ outb(0x20,0x20); /* Non-specific EOI to cascade */
+ } else {
+ cached_21 |= 1 << irq_nr;
+ inb(0x21); /* DUMMY */
+ outb(cached_21,0x21);
+ outb(0x20,0x20); /* Non-specific EOI */
+ }
+}
+
+static void i8259_set_irq_mask(int irq_nr)
+{
+ outb(cached_A1,0xA1);
+ outb(cached_21,0x21);
+}
+
+static void i8259_mask_irq(unsigned int irq_nr)
+{
+ if ( irq_nr >= i8259_pic.irq_offset )
+ irq_nr -= i8259_pic.irq_offset;
+ if ( irq_nr < 8 )
+ cached_21 |= 1 << irq_nr;
+ else
+ cached_A1 |= 1 << (irq_nr-8);
+ i8259_set_irq_mask(irq_nr);
+}
+
+static void i8259_unmask_irq(unsigned int irq_nr)
+{
+
+ if ( irq_nr >= i8259_pic.irq_offset )
+ irq_nr -= i8259_pic.irq_offset;
+ if ( irq_nr < 8 )
+ cached_21 &= ~(1 << irq_nr);
+ else
+ cached_A1 &= ~(1 << (irq_nr-8));
+ i8259_set_irq_mask(irq_nr);
+}
+
+struct hw_interrupt_type i8259_pic = {
+ " i8259 ",
+ NULL,
+ NULL,
+ NULL,
+ i8259_unmask_irq,
+ i8259_mask_irq,
+ i8259_mask_and_ack_irq,
+ 0
+};
+
+static void
+no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+void __init i8259_init(void)
+{
+ /* init master interrupt controller */
+ outb(0x11, 0x20); /* Start init sequence */
+ outb(0x00, 0x21); /* Vector base */
+ outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0x21); /* Select 8086 mode */
+ outb(0xFF, 0x21); /* Mask all */
+ /* init slave interrupt controller */
+ outb(0x11, 0xA0); /* Start init sequence */
+ outb(0x08, 0xA1); /* Vector base */
+ outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+ outb(0x01, 0xA1); /* Select 8086 mode */
+ outb(0xFF, 0xA1); /* Mask all */
+ outb(cached_A1, 0xA1);
+ outb(cached_21, 0x21);
+ request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT,
+ "82c59 secondary cascade", NULL );
+ enable_irq(i8259_pic.irq_offset + 2); /* Enable cascade interrupt */
+}
diff --git a/arch/ppc/kernel/i8259.h b/arch/ppc/kernel/i8259.h
new file mode 100644
index 000000000..a1d6df0a1
--- /dev/null
+++ b/arch/ppc/kernel/i8259.h
@@ -0,0 +1,12 @@
+
+#ifndef _PPC_KERNEL_i8259_H
+#define _PPC_KERNEL_i8259_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type i8259_pic;
+
+void i8259_init(void);
+int i8259_irq(int);
+
+#endif /* _PPC_KERNEL_i8259_H */
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index af163699b..c68d1e63e 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -1,5 +1,5 @@
/*
- * $Id: idle.c,v 1.57 1998/12/28 10:28:46 paulus Exp $
+ * $Id: idle.c,v 1.61 1999/03/18 04:15:45 cort Exp $
*
* Idle daemon for PowerPC. Idle daemon will handle any action
* that needs to be taken when the system becomes idle.
@@ -39,6 +39,12 @@ unsigned long htab_reclaim_on = 0;
unsigned long zero_paged_on = 0;
unsigned long powersave_nap = 0;
+unsigned long *zero_cache; /* head linked list of pre-zero'd pages */
+unsigned long zero_sz; /* # currently pre-zero'd pages */
+unsigned long zeropage_hits; /* # zero'd pages request that we've done */
+unsigned long zeropage_calls; /* # zero'd pages request that've been made */
+unsigned long zerototal; /* # pages zero'd over time */
+
int idled(void *unused)
{
/* endless loop with no priority at all */
@@ -108,8 +114,6 @@ void inline htab_reclaim(void)
/* if we don't have a htab */
if ( Hash_size == 0 )
return;
- lock_dcache(1);
-
#if 0
/* find a random place in the htab to start each time */
start = &Hash[jiffies%(Hash_size/sizeof(PTE))];
@@ -147,7 +151,6 @@ void inline htab_reclaim(void)
}
out:
if ( current->need_resched ) printk("need_resched: %lx\n", current->need_resched);
- unlock_dcache();
#endif /* CONFIG_8xx */
}
@@ -159,7 +162,7 @@ unsigned long get_zero_page_fast(void)
{
unsigned long page = 0;
- atomic_inc((atomic_t *)&quicklists.zeropage_calls);
+ atomic_inc((atomic_t *)&zero_cache_calls);
if ( zero_quicklist )
{
/* atomically remove this page from the list */
@@ -177,10 +180,10 @@ unsigned long get_zero_page_fast(void)
#endif /* __SMP__ */
/* we can update zerocount after the fact since it is not
* used for anything but control of a loop which doesn't
- * matter since it won't affect anything if it zero's one
+ * matter since it won't affect anything if it zeros one
* less page -- Cort
*/
- atomic_inc((atomic_t *)&quicklists.zeropage_hits);
+ atomic_inc((atomic_t *)&zero_cache_hits);
atomic_dec((atomic_t *)&zero_cache_sz);
/* zero out the pointer to next in the page */
@@ -222,7 +225,6 @@ void zero_paged(void)
/*
* Make the page no cache so we don't blow our cache with 0's
- * We should just turn off the cache instead. -- Cort
*/
pte = find_pte(init_task.mm, pageptr);
if ( !pte )
@@ -254,8 +256,8 @@ void zero_paged(void)
* So we update the list atomically without locking it.
* -- Cort
*/
+
/* turn cache on for this page */
-
pte_cache(*pte);
flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
/* atomically add this page to the list */
@@ -280,7 +282,7 @@ void zero_paged(void)
* reads it. -- Cort
*/
atomic_inc((atomic_t *)&zero_cache_sz);
- atomic_inc((atomic_t *)&quicklists.zerototal);
+ atomic_inc((atomic_t *)&zero_cache_total);
}
}
@@ -301,11 +303,17 @@ void power_save(void)
hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
asm("mtspr 1008,%0" : : "r" (hid0));
- msr |= MSR_POW;
+
+ /* set the POW bit in the MSR, and enable interrupts
+ * so we wake up sometime! */
+ _nmask_and_or_msr(0, MSR_POW | MSR_EE);
+
+ /* Disable interrupts again so restore_flags will
+ * work. */
+ _nmask_and_or_msr(MSR_EE, 0);
}
restore_flags(msr);
default:
return;
}
-
}
diff --git a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c
new file mode 100644
index 000000000..641d77a52
--- /dev/null
+++ b/arch/ppc/kernel/indirect_pci.c
@@ -0,0 +1,121 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * 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.
+ */
+
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+unsigned int * pci_config_address;
+unsigned char * pci_config_data;
+
+int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ unsigned flags;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ *val= in_8(pci_config_data + (offset&3));
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ unsigned flags;
+
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ *val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ unsigned flags;
+
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ *val= in_le32((unsigned *)pci_config_data);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ unsigned flags;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ out_8(pci_config_data + (offset&3), val);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ unsigned flags;
+
+ if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ unsigned flags;
+
+ if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ save_flags(flags); cli();
+
+ out_be32(pci_config_address,
+ ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+ out_le32((unsigned *)pci_config_data, val);
+
+ restore_flags(flags);
+ return PCIBIOS_SUCCESSFUL;
+}
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index f4a7c7143..461e51aa1 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,5 +1,5 @@
/*
- * $Id: irq.c,v 1.91 1998/12/28 10:28:47 paulus Exp $
+ * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
*
* arch/ppc/kernel/irq.c
*
@@ -42,6 +42,7 @@
#include <linux/malloc.h>
#include <linux/openpic.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/hydra.h>
@@ -56,101 +57,46 @@
#include <asm/amigaints.h>
#include <asm/amigahw.h>
#include <asm/amigappc.h>
-#ifdef CONFIG_8xx
-#include <asm/8xx_immap.h>
-#include <asm/mbx.h>
-#endif
+#include <asm/ptrace.h>
+
+#include "local_irq.h"
-extern void process_int(unsigned long vec, struct pt_regs *fp);
-extern void apus_init_IRQ(void);
-extern void amiga_disable_irq(unsigned int irq);
-extern void amiga_enable_irq(unsigned int irq);
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
-static volatile unsigned char *chrp_int_ack_special;
extern volatile unsigned long ipi_count;
-static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base);
+void enable_irq(unsigned int irq_nr);
+void disable_irq(unsigned int irq_nr);
+
+/* Fixme - Need to figure out a way to get rid of this - Corey */
+volatile unsigned char *chrp_int_ack_special;
#ifdef CONFIG_APUS
/* Rename a few functions. Requires the CONFIG_APUS protection. */
#define request_irq nop_ppc_request_irq
#define free_irq nop_ppc_free_irq
#define get_irq_list nop_get_irq_list
-#endif
-#ifndef CONFIG_8xx
-void (*mask_and_ack_irq)(int irq_nr);
-void (*mask_irq)(unsigned int irq_nr);
-void (*unmask_irq)(unsigned int irq_nr);
-#else /* CONFIG_8xx */
-/* init_IRQ() happens too late for the MBX because we initialize the
- * CPM early and it calls request_irq() before we have these function
- * pointers initialized.
- */
-#define mask_and_ack_irq(irq) mbx_mask_irq(irq)
-#define mask_irq(irq) mbx_mask_irq(irq)
-#define unmask_irq(irq) mbx_unmask_irq(irq)
-#endif /* CONFIG_8xx */
-
#define VEC_SPUR (24)
-#undef SHOW_IRQ
-#undef SHOW_GATWICK_IRQS
-#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-#define cached_21 (((char *)(cached_irq_mask))[3])
-#define cached_A1 (((char *)(cached_irq_mask))[2])
-#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-int max_irqs;
-int max_real_irqs;
-static struct irqaction *irq_action[NR_IRQS];
-static int spurious_interrupts = 0;
-static unsigned int cached_irq_mask[NR_MASK_WORDS];
-unsigned int lost_interrupts[NR_MASK_WORDS];
-atomic_t n_lost_interrupts;
-
-/* pmac */
-struct pmac_irq_hw {
- unsigned int flag;
- unsigned int enable;
- unsigned int ack;
- unsigned int level;
-};
+#endif
-/* XXX these addresses should be obtained from the device tree */
-volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
- (struct pmac_irq_hw *) 0xf3000020,
- (struct pmac_irq_hw *) 0xf3000010,
- (struct pmac_irq_hw *) 0xf4000020,
- (struct pmac_irq_hw *) 0xf4000010,
-};
+#define MAXCOUNT 10000000
-/* This is the interrupt used on the main controller for the secondary
- controller. Happens on PowerBooks G3 Series (a second mac-io)
- -- BenH
- */
-static int second_irq = -999;
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-/* Returns the number of 0's to the left of the most significant 1 bit */
-static inline int cntlzw(int bits)
-{
- int lz;
+int ppc_spurious_interrupts = 0;
- asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits));
- return lz;
-}
+unsigned int ppc_local_bh_count[NR_CPUS];
+unsigned int ppc_local_irq_count[NR_CPUS];
+struct irqaction *ppc_irq_action[NR_IRQS];
+unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+atomic_t ppc_n_lost_interrupts;
-static inline void sync(void)
-{
- asm volatile ("sync");
-}
/* nasty hack for shared irq's since we need to do kmalloc calls but
- * can't very very early in the boot when we need to do a request irq.
+ * can't very early in the boot when we need to do a request irq.
* this needs to be removed.
* -- Cort
*/
static char cache_bitmask = 0;
-static struct irqaction malloc_cache[4];
+static struct irqaction malloc_cache[8];
extern int mem_init_done;
void *irq_kmalloc(size_t size, int pri)
@@ -179,168 +125,80 @@ void irq_kfree(void *ptr)
kfree(ptr);
}
-#ifndef CONFIG_8xx
-void i8259_mask_and_ack_irq(int irq_nr)
-{
- /* spin_lock(&irq_controller_lock);*/
- cached_irq_mask[0] |= 1 << irq_nr;
- if (irq_nr > 7) {
- inb(0xA1); /* DUMMY */
- outb(cached_A1,0xA1);
- outb(0x62,0x20); /* Specific EOI to cascade */
- /*outb(0x20,0xA0);*/
- outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
- } else {
- inb(0x21); /* DUMMY */
- outb(cached_21,0x21);
- /*outb(0x20,0x20);*/
- outb(0x60|irq_nr,0x20); /* specific eoi */
-
- }
- /* spin_unlock(&irq_controller_lock);*/
-}
-
-void __pmac pmac_mask_and_ack_irq(int irq_nr)
-{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
-
- if ((unsigned)irq_nr >= max_irqs)
- return;
- /*spin_lock(&irq_controller_lock);*/
-
- clear_bit(irq_nr, cached_irq_mask);
- if (test_and_clear_bit(irq_nr, lost_interrupts))
- atomic_dec(&n_lost_interrupts);
- out_le32(&pmac_irq_hw[i]->ack, bit);
- out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
- out_le32(&pmac_irq_hw[i]->ack, bit);
- /* make sure ack gets to controller before we enable interrupts */
- sync();
-
- /*spin_unlock(&irq_controller_lock);*/
- /*if ( irq_controller_lock.lock )
- panic("irq controller lock still held in mask and ack\n");*/
-}
+struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
-void __openfirmware chrp_mask_and_ack_irq(int irq_nr)
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
{
- /* spinlocks are done by i8259_mask_and_ack() - Cort */
- if (is_8259_irq(irq_nr))
- i8259_mask_and_ack_irq(irq_nr);
-}
-
+ struct irqaction *old, **p, *action;
+ unsigned long flags;
-static void i8259_set_irq_mask(int irq_nr)
-{
- if (irq_nr > 7) {
- outb(cached_A1,0xA1);
- } else {
- outb(cached_21,0x21);
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+ if (!handler)
+ {
+ /* Free */
+ for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
+ {
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ restore_flags(flags);
+ irq_kfree(action);
+ return 0;
+ }
+ return -ENOENT;
}
-}
-
-static void __pmac pmac_set_irq_mask(int irq_nr)
-{
- unsigned long bit = 1UL << (irq_nr & 0x1f);
- int i = irq_nr >> 5;
-
- if ((unsigned)irq_nr >= max_irqs)
- return;
-
- /* enable unmasked interrupts */
- out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
-
- /*
- * Unfortunately, setting the bit in the enable register
- * when the device interrupt is already on *doesn't* set
- * the bit in the flag register or request another interrupt.
- */
- if ((bit & cached_irq_mask[i])
- && (ld_le32(&pmac_irq_hw[i]->level) & bit)
- && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
- if (!test_and_set_bit(irq_nr, lost_interrupts))
- atomic_inc(&n_lost_interrupts);
+
+ action = (struct irqaction *)
+ irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ save_flags(flags);
+ cli();
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = NULL;
+ enable_irq(irq);
+
+ p = &irq_desc[irq].action;
+
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & action->flags & SA_SHIRQ))
+ return -EBUSY;
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
}
-}
-
-/*
- * These have to be protected by the spinlock
- * before being called.
- */
-static void i8259_mask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] |= 1 << irq_nr;
- i8259_set_irq_mask(irq_nr);
-}
-
-static void i8259_unmask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] &= ~(1 << irq_nr);
- i8259_set_irq_mask(irq_nr);
-}
-
-static void __pmac pmac_mask_irq(unsigned int irq_nr)
-{
- clear_bit(irq_nr, cached_irq_mask);
- pmac_set_irq_mask(irq_nr);
- sync();
-}
-
-static void __pmac pmac_unmask_irq(unsigned int irq_nr)
-{
- set_bit(irq_nr, cached_irq_mask);
- pmac_set_irq_mask(irq_nr);
-}
-
-static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
-{
- if (is_8259_irq(irq_nr))
- i8259_mask_irq(irq_nr);
- else
- openpic_disable_irq(irq_to_openpic(irq_nr));
-}
+ *p = action;
-static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
-{
- if (is_8259_irq(irq_nr))
- i8259_unmask_irq(irq_nr);
- else
- openpic_enable_irq(irq_to_openpic(irq_nr));
-}
-#else /* CONFIG_8xx */
-static void mbx_mask_irq(unsigned int irq_nr)
-{
- cached_irq_mask[0] &= ~(1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
- cached_irq_mask[0];
+ restore_flags(flags);
+ return 0;
}
-static void mbx_unmask_irq(unsigned int irq_nr)
+void free_irq(unsigned int irq, void *dev_id)
{
- cached_irq_mask[0] |= (1 << (31-irq_nr));
- ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
- cached_irq_mask[0];
+ request_irq(irq, NULL, 0, NULL, dev_id);
}
-#endif /* CONFIG_8xx */
void disable_irq(unsigned int irq_nr)
{
- /*unsigned long flags;*/
-
- /* spin_lock_irqsave(&irq_controller_lock, flags);*/
mask_irq(irq_nr);
- /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
synchronize_irq();
}
void enable_irq(unsigned int irq_nr)
{
- /*unsigned long flags;*/
-
- /* spin_lock_irqsave(&irq_controller_lock, flags);*/
unmask_irq(irq_nr);
- /* spin_unlock_irqrestore(&irq_controller_lock, flags);*/
}
int get_irq_list(char *buf)
@@ -354,8 +212,8 @@ int get_irq_list(char *buf)
*(char *)(buf+len++) = '\n';
for (i = 0 ; i < NR_IRQS ; i++) {
- action = irq_action[i];
- if ((!action || !action->handler) && (i != second_irq))
+ action = irq_desc[i].action;
+ if ( !action || !action->handler )
continue;
len += sprintf(buf+len, "%3d: ", i);
#ifdef __SMP__
@@ -365,56 +223,83 @@ int get_irq_list(char *buf)
#else
len += sprintf(buf+len, "%10u ", kstat_irqs(i));
#endif /* __SMP__ */
- switch( _machine )
- {
- case _MACH_prep:
- len += sprintf(buf+len, " 82c59 ");
- break;
- case _MACH_Pmac:
- if (i < 64)
- len += sprintf(buf+len, " PMAC-PIC ");
- else
- len += sprintf(buf+len, " GATWICK ");
- break;
- case _MACH_chrp:
- if ( is_8259_irq(i) )
- len += sprintf(buf+len, " 82c59 ");
- else
- len += sprintf(buf+len, " OpenPIC ");
- break;
- case _MACH_mbx:
- len += sprintf(buf+len, " MPC8xx ");
- break;
+ if ( irq_desc[i].ctl )
+ len += sprintf(buf+len, " %s ", irq_desc[i].ctl->typename );
+ len += sprintf(buf+len, " %s",action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ", %s", action->name);
}
-
- if (i != second_irq) {
- len += sprintf(buf+len, " %s",action->name);
- for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ", %s", action->name);
- }
- len += sprintf(buf+len, "\n");
- } else
- len += sprintf(buf+len, " Gatwick secondary IRQ controller\n");
+ len += sprintf(buf+len, "\n");
}
#ifdef __SMP__
/* should this be per processor send/receive? */
- len += sprintf(buf+len, "IPI: %10lu", ipi_count);
- for ( i = 0 ; i <= smp_num_cpus-1; i++ )
- len += sprintf(buf+len," ");
- len += sprintf(buf+len, " interprocessor messages received\n");
+ len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
#endif
- len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
- for ( i = 0 ; i <= smp_num_cpus-1; i++ )
- len += sprintf(buf+len," ");
- len += sprintf(buf+len, " spurious or short\n");
+ len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
return len;
}
-
/*
- * Global interrupt locks for SMP. Allow interrupts to come in on any
- * CPU, yet make cli/sti act globally to protect critical regions..
+ * Eventually, this should take an array of interrupts and an array size
+ * so it can dispatch multiple interrupts.
*/
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
+{
+ int status;
+ struct irqaction *action;
+ int cpu = smp_processor_id();
+
+ mask_and_ack_irq(irq);
+ status = 0;
+ action = irq_desc[irq].action;
+ kstat.irqs[cpu][irq]++;
+ if (action && action->handler) {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ do {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while ( action );
+ __cli();
+ unmask_irq(irq);
+ } else {
+ ppc_spurious_interrupts++;
+ disable_irq( irq );
+ }
+}
+
+asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
+{
+ int cpu = smp_processor_id();
+
+ hardirq_enter(cpu);
+ ppc_md.do_IRQ(regs, cpu, isfake);
+ hardirq_exit(cpu);
+}
+
+unsigned long probe_irq_on (void)
+{
+ return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+ return 0;
+}
+
+void __init init_IRQ(void)
+{
+ static int once = 0;
+
+ if ( once )
+ return;
+ else
+ once++;
+
+ ppc_md.init_IRQ();
+}
+
#ifdef __SMP__
unsigned char global_irq_holder = NO_PROC_ID;
unsigned volatile int global_irq_lock;
@@ -431,9 +316,13 @@ static void show(char * str)
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d %d]\n",
- atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
+ atomic_read(&global_irq_count),
+ ppc_local_irq_count[0],
+ ppc_local_irq_count[1]);
printk("bh: %d [%d %d]\n",
- atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
+ atomic_read(&global_bh_count),
+ ppc_local_bh_count[0],
+ ppc_local_bh_count[1]);
stack = (unsigned long *) &str;
for (i = 40; i ; i--) {
unsigned long x = *++stack;
@@ -443,7 +332,6 @@ static void show(char * str)
}
}
-#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
{
int count = MAXCOUNT;
@@ -469,7 +357,8 @@ static inline void wait_on_irq(int cpu)
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
- if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+ if (ppc_local_bh_count[cpu]
+ || !atomic_read(&global_bh_count))
break;
}
@@ -490,7 +379,8 @@ static inline void wait_on_irq(int cpu)
continue;
if (global_irq_lock)
continue;
- if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+ if (!ppc_local_bh_count[cpu]
+ && atomic_read(&global_bh_count))
continue;
if (!test_and_set_bit(0,&global_irq_lock))
break;
@@ -512,7 +402,6 @@ void synchronize_bh(void)
wait_on_bh();
}
-
/*
* This is called when we want to synchronize with
* interrupts. We may for example tell a device to
@@ -581,7 +470,7 @@ void __global_cli(void)
if (flags & (1 << 15)) {
int cpu = smp_processor_id();
__cli();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
get_irqlock(cpu);
}
}
@@ -590,7 +479,7 @@ void __global_sti(void)
{
int cpu = smp_processor_id();
- if (!local_irq_count[cpu])
+ if (!ppc_local_irq_count[cpu])
release_irqlock(cpu);
__sti();
}
@@ -614,7 +503,7 @@ unsigned long __global_save_flags(void)
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
- if (!local_irq_count[smp_processor_id()]) {
+ if (!ppc_local_irq_count[smp_processor_id()]) {
if (local_enabled)
retval = 1;
if (global_irq_holder == (unsigned char) smp_processor_id())
@@ -623,6 +512,31 @@ unsigned long __global_save_flags(void)
return retval;
}
+int
+tb(long vals[],
+ int max_size)
+{
+ register unsigned long *orig_sp __asm__ ("r1");
+ register unsigned long lr __asm__ ("r3");
+ unsigned long *sp;
+ int i;
+
+ asm volatile ("mflr 3");
+ vals[0] = lr;
+ sp = (unsigned long *) *orig_sp;
+ sp = (unsigned long *) *sp;
+ for (i=1; i<max_size; i++) {
+ if (sp == 0) {
+ break;
+ }
+
+ vals[i] = *(sp+1);
+ sp = (unsigned long *) *sp;
+ }
+
+ return i;
+}
+
void __global_restore_flags(unsigned long flags)
{
switch (flags) {
@@ -639,559 +553,21 @@ void __global_restore_flags(unsigned long flags)
__sti();
break;
default:
- printk("global_restore_flags: %08lx (%08lx)\n",
- flags, (&flags)[-1]);
- }
-}
-
-#endif /* __SMP__ */
-
-asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
-{
- int irq;
- unsigned long bits;
- struct irqaction *action;
- int cpu = smp_processor_id();
- int status;
- int openpic_eoi_done = 0;
-
- /* save the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- unsigned dcache_locked;
-
- dcache_locked = unlock_dcache();
- hardirq_enter(cpu);
-#ifndef CONFIG_8xx
-#ifdef __SMP__
- if ( cpu != 0 )
- {
- if (!isfake)
- {
- extern void smp_message_recv(void);
-#ifdef CONFIG_XMON
- static int xmon_2nd;
- if (xmon_2nd)
- xmon(regs);
-#endif
- smp_message_recv();
- goto out;
- }
- /* could be here due to a do_fake_interrupt call but we don't
- mess with the controller from the second cpu -- Cort */
- goto out;
- }
-
- {
- unsigned int loops = MAXCOUNT;
- while (test_bit(0, &global_irq_lock)) {
- if (smp_processor_id() == global_irq_holder) {
- printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- break;
- }
- if (loops-- == 0) {
- printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- }
- }
- }
-#endif /* __SMP__ */
-
- switch ( _machine )
- {
- case _MACH_Pmac:
- for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
-
- /* Here, we handle interrupts coming from Gatwick,
- * normal interrupt code will take care of acking and
- * masking the irq on Gatwick itself but we ack&mask
- * the Gatwick main interrupt on Heathrow now. It's
- * unmasked later, after interrupt handling. -- BenH
- */
- if (irq == second_irq) {
- mask_and_ack_irq(second_irq);
- for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
- int i = irq >> 5;
- bits = ld_le32(&pmac_irq_hw[i]->flag)
- | lost_interrupts[i];
- if (bits == 0)
- continue;
- irq -= cntlzw(bits);
- break;
- }
- /* If not found, on exit, irq is 63 (128-1-32-32).
- * We set it to -1 and revalidate second controller
- */
- if (irq < max_real_irqs) {
- irq = -1;
- unmask_irq(second_irq);
- }
-#ifdef SHOW_GATWICK_IRQS
- printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits);
-#endif
- }
-
- break;
- case _MACH_chrp:
- irq = openpic_irq(0);
- if (irq == IRQ_8259_CASCADE)
- {
- /*
- * This magic address generates a PCI IACK cycle.
- *
- * This should go in the above mask/ack code soon. -- Cort
- */
- irq = *chrp_int_ack_special;
- /*
- * Acknowledge as soon as possible to allow i8259
- * interrupt nesting
- */
- openpic_eoi(0);
- openpic_eoi_done = 1;
- }
- else if (irq >= OPENPIC_VEC_TIMER)
- {
- /*
- * OpenPIC interrupts >64 will be used for other purposes
- * like interprocessor interrupts and hardware errors
- */
- if (irq == OPENPIC_VEC_SPURIOUS) {
- /*
- * Spurious interrupts should never be
- * acknowledged
- */
- spurious_interrupts++;
- openpic_eoi_done = 1;
- } else {
- /*
- * Here we should process IPI timer
- * for now the interrupt is dismissed.
- */
- }
- goto out;
- }
- break;
- case _MACH_prep:
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
- {
-retry_cascade:
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- /* if no intr left */
- if ( !(irq & 128 ) )
- goto out;
- irq = (irq&7) + 8;
- }
- bits = 1UL << irq;
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
{
- int old_level, new_level;
-
- old_level = ~(regs->mq) & IPLEMU_IPLMASK;
- new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
-
- if (new_level == 0)
- {
- goto apus_out;
- }
-
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
- | (~(new_level) & IPLEMU_IPLMASK)));
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-
- process_int (VEC_SPUR+new_level, regs);
-
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
- APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
- | (~(old_level) & IPLEMU_IPLMASK)));
-
-apus_out:
- hardirq_exit(cpu);
- APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
- goto out2;
- }
-#endif
- }
-
- if (irq < 0) {
- /* we get here with Gatwick but the 'bogus' isn't correct in that case -- Cort */
- if ( irq != second_irq )
- {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- spurious_interrupts++;
- }
- goto out;
- }
-
-#else /* CONFIG_8xx */
- /* For MPC8xx, read the SIVEC register and shift the bits down
- * to get the irq number.
- */
- bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
- irq = bits >> 26;
-#endif /* CONFIG_8xx */
- mask_and_ack_irq(irq);
- status = 0;
- action = irq_action[irq];
- kstat.irqs[cpu][irq]++;
- if (action && action->handler) {
- if (!(action->flags & SA_INTERRUPT))
- __sti();
- do {
- status |= action->flags;
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while ( action );
- __cli();
- unmask_irq(irq);
- } else {
-#ifndef CONFIG_8xx
- if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
-#endif
- spurious_interrupts++;
- disable_irq( irq );
- }
-
- /* This was a gatwick sub-interrupt, we re-enable them on Heathrow
- now */
- if (_machine == _MACH_Pmac && irq >= max_real_irqs)
- unmask_irq(second_irq);
-
- /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
-#ifndef CONFIG_8xx
- if ( is_prep && (irq > 7) )
- goto retry_cascade;
- /* do_bottom_half is called if necessary from int_return in head.S */
-out:
- if (_machine == _MACH_chrp && !openpic_eoi_done)
- openpic_eoi(0);
-#endif /* CONFIG_8xx */
- hardirq_exit(cpu);
-
-#ifdef CONFIG_APUS
-out2:
-#endif
- /* restore the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- lock_dcache(dcache_locked);
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
-{
- struct irqaction *old, **p, *action;
- unsigned long flags;
-
-#ifdef SHOW_IRQ
- printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
- irq,(int)handler,devname,(int)dev_id);
-#endif /* SHOW_IRQ */
-
- if (irq >= NR_IRQS)
- return -EINVAL;
-
- /* Cannot allocate second controller IRQ */
- if (irq == second_irq)
- return -EBUSY;
+ unsigned long trace[5];
+ int count;
+ int i;
- if (!handler)
- {
- /* Free */
- for (p = irq + irq_action; (action = *p) != NULL; p = &action->next)
- {
- /* Found it - now free it */
- save_flags(flags);
- cli();
- *p = action->next;
- restore_flags(flags);
- irq_kfree(action);
- return 0;
- }
- return -ENOENT;
- }
-
- action = (struct irqaction *)
- irq_kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- if (!action)
- return -ENOMEM;
- save_flags(flags);
- cli();
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->dev_id = dev_id;
- action->next = NULL;
- enable_irq(irq);
- p = irq_action + irq;
-
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & action->flags & SA_SHIRQ))
- return -EBUSY;
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- }
- *p = action;
-
- restore_flags(flags);
- return 0;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- request_irq(irq, NULL, 0, NULL, dev_id);
-}
-
-unsigned long probe_irq_on (void)
-{
- return 0;
-}
-
-int probe_irq_off (unsigned long irqs)
-{
- return 0;
-}
-
-#ifndef CONFIG_8xx
-__initfunc(static void i8259_init(void))
-{
- /* init master interrupt controller */
- outb(0x11, 0x20); /* Start init sequence */
- outb(0x00, 0x21); /* Vector base */
- outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
- outb(0x01, 0x21); /* Select 8086 mode */
- outb(0xFF, 0x21); /* Mask all */
-
- /* init slave interrupt controller */
- outb(0x11, 0xA0); /* Start init sequence */
- outb(0x08, 0xA1); /* Vector base */
- outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
- outb(0x01, 0xA1); /* Select 8086 mode */
- outb(0xFF, 0xA1); /* Mask all */
- outb(cached_A1, 0xA1);
- outb(cached_21, 0x21);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
- panic("Could not allocate cascade IRQ!");
- enable_irq(2); /* Enable cascade interrupt */
-}
-#endif /* CONFIG_8xx */
-
-/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External
- * interrupts can be either edge or level triggered, but there is no
- * reason for us to change the EPPC-bug values (it would not work if we did).
- */
-__initfunc(void init_IRQ(void))
-{
- extern void xmon_irq(int, void *, struct pt_regs *);
- int i;
- struct device_node *irqctrler;
- unsigned long addr;
- struct device_node *np;
-
-#ifndef CONFIG_8xx
- switch (_machine)
- {
- case _MACH_Pmac:
- mask_and_ack_irq = pmac_mask_and_ack_irq;
- mask_irq = pmac_mask_irq;
- unmask_irq = pmac_unmask_irq;
-
- /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128,
- others have 32 */
- max_irqs = max_real_irqs = 32;
- irqctrler = find_devices("mac-io");
- if (irqctrler)
- {
- max_real_irqs = 64;
- if (irqctrler->next)
- max_irqs = 128;
- else
- max_irqs = 64;
- }
-
- /* get addresses of first controller */
- if (irqctrler) {
- if (irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 0; i < 2; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (2 - i) * 0x10);
- }
-
- /* get addresses of second controller */
- irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
- if (irqctrler && irqctrler->n_addrs > 0) {
- addr = (unsigned long)
- ioremap(irqctrler->addrs[0].address, 0x40);
- for (i = 2; i < 4; ++i)
- pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
- (addr + (4 - i) * 0x10);
- }
- }
-
- /* disable all interrupts in all controllers */
- for (i = 0; i * 32 < max_irqs; ++i)
- out_le32(&pmac_irq_hw[i]->enable, 0);
-
-
- /* get interrupt line of secondary interrupt controller */
- if (irqctrler) {
- second_irq = irqctrler->intrs[0].line;
- printk(KERN_INFO "irq: secondary controller on irq %d\n",
- (int)second_irq);
- if (device_is_compatible(irqctrler, "gatwick"))
- pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
- enable_irq(second_irq);
- }
- printk("System has %d possible interrupts\n", max_irqs);
- if (max_irqs != max_real_irqs)
- printk(KERN_DEBUG "%d interrupts on main controller\n",
- max_real_irqs);
-
-#ifdef CONFIG_XMON
- request_irq(20, xmon_irq, 0, "NMI", 0);
-#endif /* CONFIG_XMON */
- break;
- case _MACH_chrp:
- mask_and_ack_irq = chrp_mask_and_ack_irq;
- mask_irq = chrp_mask_irq;
- unmask_irq = chrp_unmask_irq;
-
- if ( !(np = find_devices("pci") ) )
- printk("Cannot find pci to get ack address\n");
- else
- {
- chrp_int_ack_special = (volatile unsigned char *)
- (*(unsigned long *)get_property(np,
- "8259-interrupt-acknowledge", NULL));
- }
- openpic_init(1);
- i8259_init();
- cached_irq_mask[0] = cached_irq_mask[1] = ~0UL;
-#ifdef CONFIG_XMON
- request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
- xmon_irq, 0, "NMI", 0);
-#endif /* CONFIG_XMON */
- break;
- case _MACH_prep:
- mask_and_ack_irq = i8259_mask_and_ack_irq;
- mask_irq = i8259_mask_irq;
- unmask_irq = i8259_unmask_irq;
- cached_irq_mask[0] = ~0UL;
-
- i8259_init();
- /*
- * According to the Carolina spec from ibm irqs 0,1,2, and 8
- * must be edge triggered. Also, the pci intrs must be level
- * triggered and _only_ isa intrs can be level sensitive
- * which are 3-7,9-12,14-15. 13 is special - it can be level.
- *
- * power on default is 0's in both regs - all edge.
- *
- * These edge/level control regs allow edge/level status
- * to be decided on a irq basis instead of on a PIC basis.
- * It's still pretty ugly.
- * - Cort
- */
- {
- unsigned char irq_mode1 = 0, irq_mode2 = 0;
- irq_mode1 = 0; /* to get rid of compiler warnings */
- /*
- * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
- */
- if ( _prep_type == _PREP_IBM )
- irq_mode2 |= 0xa0;
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
+ count = tb(trace, 5);
+ printk("tb:");
+ for(i=0; i<count; i++) {
+ printk(" %8.8lx", trace[i]);
}
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- mask_irq = amiga_disable_irq;
- unmask_irq = amiga_enable_irq;
- apus_init_IRQ();
- break;
-#endif
+ printk("\n");
}
-#endif /* CONFIG_8xx */
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
- struct device_node *node;
- static struct interrupt_info int_pool[4];
-
- memset(int_pool, 0, sizeof(int_pool));
- node = gw->child;
- while(node)
- {
- /* Fix SCC */
- if (strcasecmp(node->name, "escc") == 0)
- if (node->child && node->child->n_intrs == 0)
- {
- node->child->n_intrs = 1;
- node->child->intrs = &int_pool[0];
- int_pool[0].line = 15+irq_base;
- printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n",
- int_pool[0].line);
- }
- /* Fix media-bay & left SWIM */
- if (strcasecmp(node->name, "media-bay") == 0)
- {
- struct device_node* ya_node;
-
- if (node->n_intrs == 0)
- {
- node->n_intrs = 1;
- node->intrs = &int_pool[1];
- int_pool[1].line = 29+irq_base;
- printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
- int_pool[1].line);
- }
- ya_node = node->child;
- while(ya_node)
- {
- if ((strcasecmp(ya_node->name, "floppy") == 0) &&
- ya_node->n_intrs == 0)
- {
- ya_node->n_intrs = 2;
- ya_node->intrs = &int_pool[2];
- int_pool[2].line = 19+irq_base;
- int_pool[3].line = 1+irq_base;
- printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
- int_pool[2].line, int_pool[3].line);
- }
- ya_node = ya_node->sibling;
- }
- }
- node = node->sibling;
}
-
}
+#endif /* __SMP__ */
diff --git a/arch/ppc/kernel/local_irq.h b/arch/ppc/kernel/local_irq.h
new file mode 100644
index 000000000..5149c291a
--- /dev/null
+++ b/arch/ppc/kernel/local_irq.h
@@ -0,0 +1,45 @@
+
+#ifndef _PPC_KERNEL_LOCAL_IRQ_H
+#define _PPC_KERNEL_LOCAL_IRQ_H
+
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
+
+/* Structure describing interrupts */
+struct hw_interrupt_type {
+ const char * typename;
+ void (*startup)(unsigned int irq);
+ void (*shutdown)(unsigned int irq);
+ void (*handle)(unsigned int irq, struct pt_regs * regs);
+ void (*enable)(unsigned int irq);
+ void (*disable)(unsigned int irq);
+ void (*mask_and_ack)(unsigned int irq);
+ int irq_offset;
+};
+
+#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
+#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
+#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
+
+struct irqdesc {
+ struct irqaction *action;
+ struct hw_interrupt_type *ctl;
+};
+
+extern struct irqdesc irq_desc[NR_IRQS];
+
+
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
+
+extern int ppc_spurious_interrupts;
+extern int ppc_second_irq;
+extern struct irqaction *ppc_irq_action[NR_IRQS];
+extern unsigned int ppc_local_bh_count[NR_CPUS];
+extern unsigned int ppc_local_irq_count[NR_CPUS];
+extern unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+extern unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+extern atomic_t ppc_n_lost_interrupts;
+
+#endif /* _PPC_KERNEL_LOCAL_IRQ_H */
diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c
index 30b7b1184..5114c3cfb 100644
--- a/arch/ppc/kernel/mbx_pci.c
+++ b/arch/ppc/kernel/mbx_pci.c
@@ -252,3 +252,20 @@ int mbx_pcibios_find_class(unsigned int class_code, unsigned short index,
}
return PCIBIOS_DEVICE_NOT_FOUND;
}
+
+__initfunc(
+void
+mbx_pcibios_fixup(void))
+{
+ /* Nothing to do here? */
+}
+
+__initfunc(
+void
+mbx_setup_pci_ptrs(void))
+{
+ set_config_access_method(mbx);
+
+ ppc_md.pcibios_fixup = mbx_pcibios_fixup;
+}
+
diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c
index 90647dcd9..0f1eb3eb5 100644
--- a/arch/ppc/kernel/mbx_setup.c
+++ b/arch/ppc/kernel/mbx_setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $
+ * $Id: mbx_setup.c,v 1.9 1999/04/28 11:54:09 davem Exp $
*
* linux/arch/ppc/kernel/setup.c
*
@@ -39,6 +39,22 @@
#include <asm/pgtable.h>
#include <asm/ide.h>
#include <asm/mbx.h>
+#include <asm/machdep.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+static int mbx_set_rtc_time(unsigned long time);
+unsigned long mbx_get_rtc_time(void);
+void mbx_calibrate_decr(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
extern unsigned long loops_per_sec;
@@ -55,35 +71,10 @@ extern char saved_command_line[256];
extern unsigned long find_available_memory(void);
extern void m8xx_cpm_reset(uint);
-/* this really does make things cleaner -- Cort */
-void __init powermac_init(void)
-{
-}
-
void __init adbdev_init(void)
{
}
-void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
-{
- ide_ioreg_t port = base;
- int i = 8;
-
- while (i--)
- *p++ = port++;
- *p++ = base + 0x206;
- if (irq != NULL)
- *irq = 0;
-#ifdef ATA_FLASH
- base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
- for (i = 0; i < 8; ++i)
- *p++ = base++;
- *p = ++base; /* Does not matter */
- if (irq)
- *irq = 13;
-#endif
-}
-
__initfunc(void
mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
@@ -145,3 +136,337 @@ abort(void)
#endif
machine_restart(NULL);
}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four. Currently, we only
+ * support the MBX, which is system clock divided by sixteen.
+ */
+__initfunc(void mbx_calibrate_decr(void))
+{
+ bd_t *binfo = (bd_t *)&res;
+ int freq, fp, divisor;
+
+ if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+ printk("WARNING: Wrong decrementer source clock.\n");
+
+ /* The manual says the frequency is in Hz, but it is really
+ * as MHz. The value 'fp' is the number of decrementer ticks
+ * per second.
+ */
+ fp = (binfo->bi_intfreq * 1000000) / 16;
+ freq = fp*60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+/* A place holder for time base interrupts, if they are ever enabled.
+*/
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+ printk("timebase_interrupt()\n");
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+mbx_set_rtc_time(unsigned long time)
+{
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+ return(0);
+}
+
+initfunc(unsigned long
+mbx_get_rtc_time(void)
+{
+ /* First, unlock all of the registers we are going to modify.
+ * To protect them from corruption during power down, registers
+ * that are maintained by keep alive power are "locked". To
+ * modify these registers we have to write the key value to
+ * the key location associated with the register.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+ ((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+
+
+ /* Disable the RTC one second and alarm interrupts.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+ ~(RTCSC_SIE | RTCSC_ALE);
+
+ /* Enabling the decrementer also enables the timebase interrupts
+ * (or from the other point of view, to get decrementer interrupts
+ * we have to enable the timebase). The decrementer interrupt
+ * is wired into the vector table, nothing to do here for that.
+ */
+ ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+ ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+ (TBSCR_TBF | TBSCR_TBE));
+ if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+
+ /* Get time from the RTC.
+ */
+ return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
+}
+
+void
+mbx_restart(char *cmd)
+{
+ extern void MBX_gorom(void);
+
+ MBX_gorom();
+}
+
+void
+mbx_power_off(void)
+{
+ mbx_restart(NULL);
+}
+
+void
+mbx_halt(void)
+{
+ mbx_restart(NULL)
+}
+
+
+int mbx_setup_residual(char *buffer)
+{
+ int len = 0;
+ bd_t *bp;
+ extern RESIDUAL *res;
+
+ bp = (bd_t *)res;
+
+ len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
+ "bus clock\t: %dMHz\n",
+ bp->bi_intfreq /*/ 1000000*/,
+ bp->bi_busfreq /*/ 1000000*/);
+
+ return len;
+}
+
+void
+mbx_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ int irq;
+ unsigned long bits = 0;
+
+ /* For MPC8xx, read the SIVEC register and shift the bits down
+ * to get the irq number. */
+ bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+ irq = bits >> 26;
+ irq += ppc8xx_pic.irq_offset;
+ bits = 1UL << irq;
+
+ if (irq < 0) {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ spurious_interrupts++;
+ }
+ else {
+ ppc_irq_dispatch_handler( regs, irq );
+ }
+
+}
+
+static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ int bits, irq;
+
+ /* A bug in the QSpan chip causes it to give us 0xff always
+ * when doing a character read. So read 32 bits and shift.
+ * This doesn't seem to return useful values anyway, but
+ * read it to make sure things are acked.
+ * -- Cort
+ */
+ irq = (inl(0x508) >> 24)&0xff;
+ if ( irq != 0xff ) printk("iack %d\n", irq);
+
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+ outb(0x0C, 0xA0);
+ irq = inb(0xA0);
+ irq = (irq&7) + 8;
+ }
+ bits = 1UL << irq;
+ irq += i8259_pic.irq_offset;
+ ppc_irq_dispatch_handler( regs, irq );
+}
+
+
+/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug. External
+ * interrupts can be either edge or level triggered, but there is no
+ * reason for us to change the EPPC-bug values (it would not work if we did).
+ */
+__initfunc(void
+mbx_init_IRQ(void))
+{
+ int i;
+
+ ppc8xx_pic.irq_offset = 16;
+ for ( i = 16 ; i < 32 ; i++ )
+ irq_desc[i].ctl = &ppc8xx_pic;
+ unmask_irq(CPM_INTERRUPT);
+
+ for ( i = 0 ; i < 16 ; i++ )
+ irq_desc[i].ctl = &i8259_pic;
+ i8259_init();
+ request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
+ enable_irq(ISA_BRIDGE_INT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+mbx_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port+_IO_BASE), buf, ns);
+}
+
+void
+mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+mbx_ide_default_irq(ide_ioreg_t base)
+{
+ return 14;
+}
+
+ide_ioreg_t
+mbx_ide_default_io_base(int index)
+{
+ return index;
+}
+
+int
+mbx_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return 0
+}
+
+void
+mbx_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+}
+
+void
+mbx_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+}
+
+void
+mbx_ide_fix_driveid(struct hd_driveid *id)
+{
+ ppc_generic_ide_fix_driveid(id);
+}
+
+void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ ide_ioreg_t port = base;
+ int i = 8;
+
+ while (i--)
+ *p++ = port++;
+ *p++ = base + 0x206;
+ if (irq != NULL)
+ *irq = 0;
+#ifdef ATA_FLASH
+ base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+ for (i = 0; i < 8; ++i)
+ *p++ = base++;
+ *p = ++base; /* Does not matter */
+ if (irq)
+ *irq = 13;
+#endif
+}
+#endif
+
+__initfunc(void
+mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+
+ if ( r3 )
+ memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+
+#ifdef CONFIG_PCI
+ mbx_setup_pci_ptrs();
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+ /* take care of cmd line */
+ if ( r6 )
+ {
+
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+
+ ppc_md.setup_arch = mbx_setup_arch;
+ ppc_md.setup_residual = mbx_setup_residual;
+ ppc_md.get_cpuinfo = NULL;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = mbx_init_IRQ;
+ ppc_md.do_IRQ = mbx_do_IRQ;
+ ppc_md.init = NULL;
+
+ ppc_md.restart = mbx_restart;
+ ppc_md.power_off = mbx_power_off;
+ ppc_md.halt = mbx_halt;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = mbx_set_rtc_time;
+ ppc_md.get_rtc_time = mbx_get_rtc_time;
+ ppc_md.calibrate_decr = mbx_calibrate_decr;
+
+ ppc_md.kbd_setkeycode = pckbd_setkeycode;
+ ppc_md.kbd_getkeycode = pckbd_getkeycode;
+ ppc_md.kbd_translate = pckbd_translate;
+ ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+ ppc_md.kbd_leds = pckbd_leds;
+ ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = mbx_ide_insw;
+ ppc_ide_md.outsw = mbx_ide_outsw;
+ ppc_ide_md.default_irq = mbx_ide_default_irq;
+ ppc_ide_md.default_io_base = mbx_ide_default_io_base;
+ ppc_ide_md.check_region = mbx_ide_check_region;
+ ppc_ide_md.request_region = mbx_ide_request_region;
+ ppc_ide_md.release_region = mbx_ide_release_region;
+ ppc_ide_md.fix_driveid = mbx_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = _IO_BASE;
+#endif
+}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index e4589b1e0..cbeb4ffce 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -36,6 +36,7 @@
* Returns (address we're running at) - (address we were linked at)
* for use before the text and data are mapped to KERNELBASE.
*/
+
_GLOBAL(reloc_offset)
mflr r0
bl 1f
@@ -72,8 +73,8 @@ _GLOBAL(_enable_interrupts)
beqlr /* nothing to do if state == 0 */
_GLOBAL(__sti)
_GLOBAL(_hard_sti)
- lis r4,n_lost_interrupts@ha
- lwz r4,n_lost_interrupts@l(r4)
+ lis r4,ppc_n_lost_interrupts@ha
+ lwz r4,ppc_n_lost_interrupts@l(r4)
mfmsr r3 /* Get current state */
ori r3,r3,MSR_EE /* Turn on 'EE' bit */
cmpi 0,r4,0 /* lost interrupts to process first? */
@@ -93,8 +94,8 @@ do_lost_interrupts:
stw r0,20(r1)
stw r3,8(r1)
1: bl fake_interrupt
- lis r4,n_lost_interrupts@ha
- lwz r4,n_lost_interrupts@l(r4)
+ lis r4,ppc_n_lost_interrupts@ha
+ lwz r4,ppc_n_lost_interrupts@l(r4)
cmpi 0,r4,0
bne- 1b
lwz r3,8(r1)
@@ -105,11 +106,31 @@ do_lost_interrupts:
addi r1,r1,16
blr
+
+/*
+ * complement mask on the msr then "or" some values on.
+ * _nmask_and_or_msr(nmask, value_to_or)
+ */
+ _GLOBAL(_nmask_and_or_msr)
+ mfmsr r0 /* Get current msr */
+ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */
+ or r0,r0,r4 /* Or on the bits in r4 (second parm) */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0 /* Update machine state */
+ blr /* Done */
+
+
/*
* Flush MMU TLB
*/
_GLOBAL(_tlbia)
+ sync
tlbia
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
/*
@@ -117,11 +138,17 @@ _GLOBAL(_tlbia)
*/
_GLOBAL(_tlbie)
tlbie r3
+ sync
+#ifdef __SMP__
+ tlbsync
+ sync
+#endif
blr
+
/*
* Atomic [test&set] exchange
*
- * void *xchg_u32(void *ptr, unsigned long val)
+ * unsigned long xchg_u32(void *ptr, unsigned long val)
* Changes the memory location '*ptr' to be val and returns
* the previous value stored there.
*/
@@ -133,6 +160,27 @@ _GLOBAL(xchg_u32)
blr
/*
+ * Try to acquire a spinlock.
+ * Only does the stwcx. if the load returned 0 - the Programming
+ * Environments Manual suggests not doing unnecessary stcwx.'s
+ * since they may inhibit forward progress by other CPUs in getting
+ * a lock.
+ */
+_GLOBAL(__spin_trylock)
+ mr r4,r3
+ eieio /* prevent reordering of stores */
+ li r5,-1
+ lwarx r3,0,r4 /* fetch old value, establish reservation */
+ cmpwi 0,r3,0 /* is it 0? */
+ bnelr- /* return failure if not */
+ stwcx. r5,0,r4 /* try to update with new value */
+ bne- 1f /* if we failed */
+ eieio /* prevent reordering of stores */
+ blr
+1: li r3,1 /* return non-zero for failure */
+ blr
+
+/*
* Atomic add/sub/inc/dec operations
*
* void atomic_add(int c, int *v)
@@ -590,6 +638,16 @@ cvt_df:
stfd 0,-4(r5)
blr
+ .globl __clear_msr_me
+__clear_msr_me:
+ mfmsr r0 /* Get current interrupt state */
+ lis r3,0
+ ori r3,r3,MSR_ME
+ andc r0,r0,r3 /* Clears bit in (r4) */
+ sync /* Some chip revs have problems here */
+ mtmsr r0 /* Update machine state */
+ blr
+
/*
* Fetch the current SR register
* get_SR(int index)
@@ -608,6 +666,8 @@ _GLOBAL(__kernel_thread)
sc
cmpi 0,r3,0 /* parent or child? */
bnelr /* return if parent */
+ li r0,0 /* clear out p->tss.regs */
+ stw r0,TSS+PT_REGS(r2) /* since we don't have user ctx */
mtlr r4 /* fn addr in lr */
mr r3,r5 /* load arg and call fn */
blrl
@@ -836,4 +896,5 @@ sys_call_table:
.long sys_sendfile
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
+ .long sys_vfork
.space (NR_syscalls-183)*4
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 9b51a6cc1..b66ccffa8 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -29,7 +29,7 @@
int
main(void)
{
- DEFINE(KERNELBASE, KERNELBASE);
+ /*DEFINE(KERNELBASE, KERNELBASE);*/
DEFINE(STATE, offsetof(struct task_struct, state));
DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
DEFINE(COUNTER, offsetof(struct task_struct, counter));
@@ -48,7 +48,6 @@ main(void)
DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
- DEFINE(TSS_SMP_FORK_RET, offsetof(struct thread_struct, smp_fork_ret));
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
new file mode 100644
index 000000000..2ca879dd8
--- /dev/null
+++ b/arch/ppc/kernel/open_pic.c
@@ -0,0 +1,48 @@
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/openpic.h>
+#include <asm/irq.h>
+#include "open_pic.h"
+#include "i8259.h"
+
+#ifdef __SMP__
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ smp_message_recv();
+}
+#endif /* __SMP__ */
+
+void chrp_mask_and_ack_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_pic.mask_and_ack(irq_nr);
+}
+
+static void chrp_mask_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_pic.disable(irq_nr);
+ else
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+}
+
+static void chrp_unmask_irq(unsigned int irq_nr)
+{
+ if (is_8259_irq(irq_nr))
+ i8259_pic.enable(irq_nr);
+ else
+ openpic_enable_irq(irq_to_openpic(irq_nr));
+}
+
+struct hw_interrupt_type open_pic = {
+ " OpenPIC ",
+ NULL,
+ NULL,
+ NULL,
+ chrp_unmask_irq,
+ chrp_mask_irq,
+ chrp_mask_and_ack_irq,
+ 0
+};
diff --git a/arch/ppc/kernel/open_pic.h b/arch/ppc/kernel/open_pic.h
new file mode 100644
index 000000000..77b8a46d0
--- /dev/null
+++ b/arch/ppc/kernel/open_pic.h
@@ -0,0 +1,11 @@
+
+#ifndef _PPC_KERNEL_OPEN_PIC_H
+#define _PPC_KERNEL_OPEN_PIC_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type open_pic;
+
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+
+#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c
index ec60ca5a6..f7893dd79 100644
--- a/arch/ppc/kernel/openpic.c
+++ b/arch/ppc/kernel/openpic.c
@@ -107,7 +107,7 @@ static inline void out_le32(volatile u_int *addr, u_int val)
}
#endif
-static inline u_int openpic_read(volatile u_int *addr)
+u_int openpic_read(volatile u_int *addr)
{
u_int val;
@@ -176,8 +176,8 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
__initfunc(void openpic_init(int main_pic))
{
u_int t, i;
- u_int vendorid, devid, stepping, timerfreq;
- const char *version, *vendor, *device;
+ u_int timerfreq;
+ const char *version;
if (!OpenPIC)
panic("No OpenPIC found");
@@ -190,6 +190,9 @@ __initfunc(void openpic_init(int main_pic))
case 2:
version = "1.2";
break;
+ case 3:
+ version = "1.3";
+ break;
default:
version = "?";
break;
@@ -200,32 +203,6 @@ __initfunc(void openpic_init(int main_pic))
OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
NumProcessors, NumSources, OpenPIC);
-
- t = openpic_read(&OpenPIC->Global.Vendor_Identification);
- vendorid = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
- devid = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
- OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
- stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
- OPENPIC_VENDOR_ID_STEPPING_SHIFT;
- switch (vendorid) {
- case OPENPIC_VENDOR_ID_APPLE:
- vendor = "Apple";
- break;
- default:
- vendor = "Unknown";
- break;
- }
- switch (devid) {
- case OPENPIC_DEVICE_ID_APPLE_HYDRA:
- device = "Hydra";
- break;
- default:
- device = "Unknown";
- break;
- }
- printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", vendorid,
- vendor, devid, device, stepping);
-
timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
printk("OpenPIC timer frequency is ");
if (timerfreq)
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 1dfa3a6c8..ccef5f36a 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: pci.c,v 1.43 1998/12/29 18:55:11 cort Exp $
+ * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $
* Common pmac/prep/chrp pci routines. -- Cort
*/
@@ -21,94 +21,41 @@
#include <asm/irq.h>
#include <asm/gg2.h>
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
+#include "pci.h"
-unsigned int * pci_config_address;
-unsigned char * pci_config_data;
-
-/*
- * It would be nice if we could create a include/asm/pci.h and have just
- * function ptrs for all these in there, but that isn't the case.
- * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
- * which has been setup by pcibios_init(). This is all to avoid a check
- * for pmac/prep every time we call one of these. It should also make the move
- * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
- * and create pci.h
- * -- Cort
- */
-int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char *val);
-int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short *val);
-int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int *val);
-int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned char val);
-int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned short val);
-int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
- unsigned char offset, unsigned int val);
-
-#define decl_config_access_method(name) \
-extern int name##_pcibios_read_config_byte(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned char *val); \
-extern int name##_pcibios_read_config_word(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned short *val); \
-extern int name##_pcibios_read_config_dword(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned int *val); \
-extern int name##_pcibios_write_config_byte(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned char val); \
-extern int name##_pcibios_write_config_word(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned short val); \
-extern int name##_pcibios_write_config_dword(unsigned char bus, \
- unsigned char dev_fn, unsigned char offset, unsigned int val)
-
-#define set_config_access_method(name) \
- ptr_pcibios_read_config_byte = name##_pcibios_read_config_byte; \
- ptr_pcibios_read_config_word = name##_pcibios_read_config_word; \
- ptr_pcibios_read_config_dword = name##_pcibios_read_config_dword; \
- ptr_pcibios_write_config_byte = name##_pcibios_write_config_byte; \
- ptr_pcibios_write_config_word = name##_pcibios_write_config_word; \
- ptr_pcibios_write_config_dword = name##_pcibios_write_config_dword
-
-decl_config_access_method(pmac);
-decl_config_access_method(grackle);
-decl_config_access_method(gg2);
-decl_config_access_method(raven);
-decl_config_access_method(prep);
-decl_config_access_method(mbx);
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+unsigned long pci_dram_offset = 0;
int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char *val)
{
- return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_read_config_byte(bus,dev_fn,offset,val);
}
int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short *val)
{
- return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_read_config_word(bus,dev_fn,offset,val);
}
int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int *val)
{
- return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_read_config_dword(bus,dev_fn,offset,val);
}
int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned char val)
{
- return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_write_config_byte(bus,dev_fn,offset,val);
}
int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val)
{
- return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_write_config_word(bus,dev_fn,offset,val);
}
int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned int val)
{
- return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
+ return ppc_md.pcibios_write_config_dword(bus,dev_fn,offset,val);
}
int pcibios_present(void)
@@ -116,167 +63,46 @@ int pcibios_present(void)
return 1;
}
-__initfunc(void pcibios_init(void))
+void __init pcibios_init(void)
{
}
-__initfunc(void
- setup_pci_ptrs(void))
+
+void __init pcibios_fixup(void)
{
-#ifndef CONFIG_MBX
- PPC_DEVICE *hostbridge;
- switch (_machine) {
- case _MACH_prep:
- hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
- BridgeController, PCIBridge,
- -1, 0);
- if (hostbridge &&
- hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
- PnP_TAG_PACKET * pkt;
- set_config_access_method(raven);
- pkt=PnP_find_large_vendor_packet(
- res->DevicePnPHeap+hostbridge->AllocatedOffset,
- 3, 0);
- if(pkt) {
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
- pci_config_address= (unsigned *)
- ld_le32((unsigned *) p.PPCData);
- pci_config_data= (unsigned char *)
- ld_le32((unsigned *) (p.PPCData+8));
- } else {/* default values */
- pci_config_address= (unsigned *) 0x80000cf8;
- pci_config_data= (unsigned char *) 0x80000cfc;
- }
- } else {
- set_config_access_method(prep);
- }
- break;
- case _MACH_Pmac:
- if (find_devices("pci") != 0) {
- /* looks like a G3 powermac */
- set_config_access_method(grackle);
- } else {
- set_config_access_method(pmac);
- }
- break;
- case _MACH_chrp:
- if ( !strncmp("MOT",
- get_property(find_path_device("/"), "model", NULL),3) )
- {
- isa_io_base = 0xfe000000;
- set_config_access_method(grackle);
- }
- else
- {
- isa_io_base = GG2_ISA_IO_BASE;
- set_config_access_method(gg2);
- }
- break;
- default:
- printk("setup_pci_ptrs(): unknown machine type!\n");
- }
-#else /* CONFIG_MBX */
- set_config_access_method(mbx);
-#endif /* CONFIG_MBX */
-#undef set_config_access_method
+ ppc_md.pcibios_fixup();
}
-__initfunc(void pcibios_fixup(void))
+void __init pcibios_fixup_bus(struct pci_bus *bus)
{
- extern unsigned long route_pci_interrupts(void);
- struct pci_dev *dev;
- extern struct bridge_data **bridges;
- extern unsigned char *Motherboard_map;
- extern unsigned char *Motherboard_routes;
- unsigned char i;
-#ifndef CONFIG_MBX
- switch (_machine )
- {
- case _MACH_prep:
- route_pci_interrupts();
- for(dev=pci_devices; dev; dev=dev->next)
- {
- /*
- * Use our old hard-coded kludge to figure out what
- * irq this device uses. This is necessary on things
- * without residual data. -- Cort
- */
- unsigned char d = PCI_SLOT(dev->devfn);
- dev->irq = Motherboard_routes[Motherboard_map[d]];
- for ( i = 0 ; i <= 5 ; i++ )
- {
- if ( dev->base_address[i] > 0x10000000 )
- {
- printk("Relocating PCI address %x -> %x\n",
- dev->base_address[i],
- (dev->base_address[i] & 0x00FFFFFF)
- | 0x01000000);
- dev->base_address[i] =
- (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
- pci_write_config_dword(dev,
- PCI_BASE_ADDRESS_0+(i*0x4),
- dev->base_address[i] );
- }
- }
-#if 0
- /*
- * If we have residual data and if it knows about this
- * device ask it what the irq is.
- * -- Cort
- */
- ppcd = residual_find_device_id( ~0L, dev->device,
- -1,-1,-1, 0);
-#endif
- }
- break;
- case _MACH_chrp:
- /* PCI interrupts are controlled by the OpenPIC */
- for(dev=pci_devices; dev; dev=dev->next)
- if (dev->irq)
- dev->irq = openpic_to_irq(dev->irq);
- break;
- case _MACH_Pmac:
- for(dev=pci_devices; dev; dev=dev->next)
- {
- /*
- * Open Firmware often doesn't initialize the,
- * PCI_INTERRUPT_LINE config register properly, so we
- * should find the device node and se if it has an
- * AAPL,interrupts property.
- */
- struct bridge_data *bp = bridges[dev->bus->number];
- struct device_node *node;
- unsigned int *reg;
- unsigned char pin;
-
- if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
- !pin)
- continue; /* No interrupt generated -> no fixup */
- for (node = bp->node->child; node != 0;
- node = node->sibling) {
- reg = (unsigned int *) get_property(node, "reg", 0);
- if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
- continue;
- /* this is the node, see if it has interrupts */
- if (node->n_intrs > 0)
- dev->irq = node->intrs[0].line;
- break;
- }
- }
- break;
- }
-#else /* CONFIG_MBX */
- for(dev=pci_devices; dev; dev=dev->next)
- {
- }
-#endif /* CONFIG_MBX */
}
-__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+char __init *pcibios_setup(char *str)
{
+ return str;
}
-__initfunc(char *pcibios_setup(char *str))
+#ifndef CONFIG_MBX
+/* Recursively searches any node that is of type PCI-PCI bridge. Without
+ * this, the old code would miss children of P2P bridges and hence not
+ * fix IRQ's for cards located behind P2P bridges.
+ * - Ranjit Deshpande, 01/20/99
+ */
+void __init fix_intr(struct device_node *node, struct pci_dev *dev)
{
- return str;
+ unsigned int *reg, *class_code;
+
+ for (; node != 0;node = node->sibling) {
+ class_code = (unsigned int *) get_property(node, "class-code", 0);
+ if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI)
+ fix_intr(node->child, dev);
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ dev->irq = node->intrs[0].line;
+ break;
+ }
}
+#endif
diff --git a/arch/ppc/kernel/pci.h b/arch/ppc/kernel/pci.h
new file mode 100644
index 000000000..231f1d952
--- /dev/null
+++ b/arch/ppc/kernel/pci.h
@@ -0,0 +1,36 @@
+
+#ifndef __PPC_KERNEL_PCI_H__
+#define __PPC_KERNEL_PCI_H__
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_dram_offset;
+
+extern unsigned int *pci_config_address;
+extern unsigned char *pci_config_data;
+
+void fix_intr(struct device_node *node, struct pci_dev *dev);
+
+#define decl_config_access_method(name) \
+extern int name##_pcibios_read_config_byte(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned char *val); \
+extern int name##_pcibios_read_config_word(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned short *val); \
+extern int name##_pcibios_read_config_dword(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned int *val); \
+extern int name##_pcibios_write_config_byte(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned char val); \
+extern int name##_pcibios_write_config_word(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned short val); \
+extern int name##_pcibios_write_config_dword(unsigned char bus, \
+ unsigned char dev_fn, unsigned char offset, unsigned int val)
+
+#define set_config_access_method(name) \
+ ppc_md.pcibios_read_config_byte = name##_pcibios_read_config_byte; \
+ ppc_md.pcibios_read_config_word = name##_pcibios_read_config_word; \
+ ppc_md.pcibios_read_config_dword = name##_pcibios_read_config_dword; \
+ ppc_md.pcibios_write_config_byte = name##_pcibios_write_config_byte; \
+ ppc_md.pcibios_write_config_word = name##_pcibios_write_config_word; \
+ ppc_md.pcibios_write_config_dword = name##_pcibios_write_config_dword
+
+#endif /* __PPC_KERNEL_PCI_H__ */
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
index 7763059f7..089169e37 100644
--- a/arch/ppc/kernel/pmac_pci.c
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -21,6 +21,9 @@
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
struct bridge_data **bridges, *bridge_list;
static int max_bus;
@@ -84,7 +87,12 @@ int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* Bus number once again taken into consideration.
+ * Change applied from 2.1.24. This makes devices located
+ * behind PCI-PCI bridges visible.
+ * -Ranjit Deshpande, 01/20/99
+ */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
*val = in_8(bp->cfg_data + (offset & 3));
@@ -109,7 +117,8 @@ int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
*val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
@@ -134,7 +143,8 @@ int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ offset);
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + offset + 1);
}
udelay(2);
*val = in_le32((volatile unsigned int *)bp->cfg_data);
@@ -156,7 +166,8 @@ int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_8(bp->cfg_data + (offset & 3), val);
@@ -180,7 +191,8 @@ int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ (offset & ~3));
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
@@ -204,7 +216,8 @@ int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
(1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ offset);
} else {
- out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ /* See pci_read_config_byte */
+ out_le32(bp->cfg_addr, (bus << 16) + (dev_fn << 8) + (offset & ~3) + 1);
}
udelay(2);
out_le32((volatile unsigned int *)bp->cfg_data, val);
@@ -429,3 +442,47 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p
}
}
+__initfunc(
+void
+pmac_pcibios_fixup(void))
+{
+ struct pci_dev *dev;
+
+ /*
+ * FIXME: This is broken: We should not assign IRQ's to IRQless
+ * devices (look at PCI_INTERRUPT_PIN) and we also should
+ * honor the existence of multi-function devices where
+ * different functions have different interrupt pins. [mj]
+ */
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ /*
+ * Open Firmware often doesn't initialize the,
+ * PCI_INTERRUPT_LINE config register properly, so we
+ * should find the device node and se if it has an
+ * AAPL,interrupts property.
+ */
+ struct bridge_data *bp = bridges[dev->bus->number];
+ unsigned char pin;
+
+ if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
+ !pin)
+ continue; /* No interrupt generated -> no fixup */
+ fix_intr(bp->node->child, dev);
+ }
+}
+
+__initfunc(
+void
+pmac_setup_pci_ptrs(void))
+{
+ if (find_devices("pci") != 0) {
+ /* looks like a G3 powermac */
+ set_config_access_method(grackle);
+ } else {
+ set_config_access_method(pmac);
+ }
+
+ ppc_md.pcibios_fixup = pmac_pcibios_fixup;
+}
+
diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c
new file mode 100644
index 000000000..6a49f1405
--- /dev/null
+++ b/arch/ppc/kernel/pmac_pic.c
@@ -0,0 +1,362 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include "pmac_pic.h"
+
+/* pmac */struct pmac_irq_hw {
+ unsigned int flag;
+ unsigned int enable;
+ unsigned int ack;
+ unsigned int level;
+};
+
+/* XXX these addresses should be obtained from the device tree */
+static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
+ (struct pmac_irq_hw *) 0xf3000020,
+ (struct pmac_irq_hw *) 0xf3000010,
+ (struct pmac_irq_hw *) 0xf4000020,
+ (struct pmac_irq_hw *) 0xf4000010,
+};
+
+static int max_irqs;
+static int max_real_irqs;
+
+#define MAXCOUNT 10000000
+
+#define GATWICK_IRQ_POOL_SIZE 10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
+
+static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+
+ if ((unsigned)irq_nr >= max_irqs)
+ return;
+
+ clear_bit(irq_nr, ppc_cached_irq_mask);
+ if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+ atomic_dec(&ppc_n_lost_interrupts);
+ out_le32(&pmac_irq_hw[i]->ack, bit);
+ out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+ out_le32(&pmac_irq_hw[i]->ack, bit);
+ do {
+ /* make sure ack gets to controller before we enable
+ interrupts */
+ mb();
+ } while(in_le32(&pmac_irq_hw[i]->flag) & bit);
+}
+
+static void __pmac pmac_set_irq_mask(unsigned int irq_nr)
+{
+ unsigned long bit = 1UL << (irq_nr & 0x1f);
+ int i = irq_nr >> 5;
+
+ if ((unsigned)irq_nr >= max_irqs)
+ return;
+
+ /* enable unmasked interrupts */
+ out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+
+ do {
+ /* make sure mask gets to controller before we
+ return to user */
+ mb();
+ } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+ != (ppc_cached_irq_mask[i] & bit));
+
+ /*
+ * Unfortunately, setting the bit in the enable register
+ * when the device interrupt is already on *doesn't* set
+ * the bit in the flag register or request another interrupt.
+ */
+ if ((bit & ppc_cached_irq_mask[i])
+ && (ld_le32(&pmac_irq_hw[i]->level) & bit)
+ && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
+ if (!test_and_set_bit(irq_nr, ppc_lost_interrupts))
+ atomic_inc(&ppc_n_lost_interrupts);
+ }
+}
+
+static void __pmac pmac_mask_irq(unsigned int irq_nr)
+{
+ clear_bit(irq_nr, ppc_cached_irq_mask);
+ pmac_set_irq_mask(irq_nr);
+ mb();
+}
+
+static void __pmac pmac_unmask_irq(unsigned int irq_nr)
+{
+ set_bit(irq_nr, ppc_cached_irq_mask);
+ pmac_set_irq_mask(irq_nr);
+}
+
+struct hw_interrupt_type pmac_pic = {
+ " PMAC-PIC ",
+ NULL,
+ NULL,
+ NULL,
+ pmac_unmask_irq,
+ pmac_mask_irq,
+ pmac_mask_and_ack_irq,
+ 0
+};
+
+struct hw_interrupt_type gatwick_pic = {
+ " GATWICK ",
+ NULL,
+ NULL,
+ NULL,
+ pmac_unmask_irq,
+ pmac_mask_irq,
+ pmac_mask_and_ack_irq,
+ 0
+};
+
+static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ int irq, bits;
+
+ for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
+ int i = irq >> 5;
+ bits = ld_le32(&pmac_irq_hw[i]->flag)
+ | ppc_lost_interrupts[i];
+ if (bits == 0)
+ continue;
+ irq -= cntlzw(bits);
+ break;
+ }
+ /* The previous version of this code allowed for this case, we
+ * don't. Put this here to check for it.
+ * -- Cort
+ */
+ if ( irq_desc[irq].ctl != &gatwick_pic )
+ printk("gatwick irq not from gatwick pic\n");
+ else
+ ppc_irq_dispatch_handler( regs, irq );
+}
+
+void
+pmac_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake)
+{
+ int irq;
+ unsigned long bits = 0;
+
+#ifdef __SMP__
+ /* IPI's are a hack on the powersurge -- Cort */
+ if ( cpu != 0 )
+ {
+ if (!isfake)
+ {
+#ifdef CONFIG_XMON
+ static int xmon_2nd;
+ if (xmon_2nd)
+ xmon(regs);
+#endif
+ smp_message_recv();
+ goto out;
+ }
+ /* could be here due to a do_fake_interrupt call but we don't
+ mess with the controller from the second cpu -- Cort */
+ goto out;
+ }
+
+ {
+ unsigned int loops = MAXCOUNT;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
+#endif /* __SMP__ */
+
+ for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+ int i = irq >> 5;
+ bits = ld_le32(&pmac_irq_hw[i]->flag)
+ | ppc_lost_interrupts[i];
+ if (bits == 0)
+ continue;
+ irq -= cntlzw(bits);
+ break;
+ }
+
+ if (irq < 0)
+ {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ ppc_spurious_interrupts++;
+ }
+ else
+ {
+ ppc_irq_dispatch_handler( regs, irq );
+ }
+#ifdef CONFIG_SMP
+out:
+#endif /* CONFIG_SMP */
+}
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+ struct device_node *node;
+ int count;
+
+ memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
+ node = gw->child;
+ count = 0;
+ while(node)
+ {
+ /* Fix SCC */
+ if (strcasecmp(node->name, "escc") == 0)
+ if (node->child) {
+ if (node->child->n_intrs < 3) {
+ node->child->intrs = &gatwick_int_pool[count];
+ count += 3;
+ }
+ node->child->n_intrs = 3;
+ node->child->intrs[0].line = 15+irq_base;
+ node->child->intrs[1].line = 4+irq_base;
+ node->child->intrs[2].line = 5+irq_base;
+ printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
+ node->child->intrs[0].line,
+ node->child->intrs[1].line,
+ node->child->intrs[2].line);
+ }
+ /* Fix media-bay & left SWIM */
+ if (strcasecmp(node->name, "media-bay") == 0) {
+ struct device_node* ya_node;
+
+ if (node->n_intrs == 0)
+ node->intrs = &gatwick_int_pool[count++];
+ node->n_intrs = 1;
+ node->intrs[0].line = 29+irq_base;
+ printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+ node->intrs[0].line);
+
+ ya_node = node->child;
+ while(ya_node)
+ {
+ if (strcasecmp(ya_node->name, "floppy") == 0) {
+ if (ya_node->n_intrs < 2) {
+ ya_node->intrs = &gatwick_int_pool[count];
+ count += 2;
+ }
+ ya_node->n_intrs = 2;
+ ya_node->intrs[0].line = 19+irq_base;
+ ya_node->intrs[1].line = 1+irq_base;
+ printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+ ya_node->intrs[0].line, ya_node->intrs[1].line);
+ }
+ if (strcasecmp(ya_node->name, "ata4") == 0) {
+ if (ya_node->n_intrs < 2) {
+ ya_node->intrs = &gatwick_int_pool[count];
+ count += 2;
+ }
+ ya_node->n_intrs = 2;
+ ya_node->intrs[0].line = 14+irq_base;
+ ya_node->intrs[1].line = 3+irq_base;
+ printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
+ ya_node->intrs[0].line, ya_node->intrs[1].line);
+ }
+ ya_node = ya_node->sibling;
+ }
+ }
+ node = node->sibling;
+ }
+ if (count > 10) {
+ printk("WARNING !! Gatwick interrupt pool overflow\n");
+ printk(" GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
+ printk(" requested = %d\n", count);
+ }
+}
+
+__initfunc(void
+pmac_pic_init(void))
+{
+ int i;
+ struct device_node *irqctrler;
+ unsigned long addr;
+ int second_irq = -999;
+
+
+ /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128,
+ others have 32 */
+ max_irqs = max_real_irqs = 32;
+ irqctrler = find_devices("mac-io");
+ if (irqctrler)
+ {
+ max_real_irqs = 64;
+ if (irqctrler->next)
+ max_irqs = 128;
+ else
+ max_irqs = 64;
+ }
+ for ( i = 0; i < max_real_irqs ; i++ )
+ irq_desc[i].ctl = &pmac_pic;
+
+ /* get addresses of first controller */
+ if (irqctrler) {
+ if (irqctrler->n_addrs > 0) {
+ addr = (unsigned long)
+ ioremap(irqctrler->addrs[0].address, 0x40);
+ for (i = 0; i < 2; ++i)
+ pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+ (addr + (2 - i) * 0x10);
+ }
+
+ /* get addresses of second controller */
+ irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
+ if (irqctrler && irqctrler->n_addrs > 0) {
+ addr = (unsigned long)
+ ioremap(irqctrler->addrs[0].address, 0x40);
+ for (i = 2; i < 4; ++i)
+ pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+ (addr + (4 - i) * 0x10);
+ }
+ }
+
+ /* disable all interrupts in all controllers */
+ for (i = 0; i * 32 < max_irqs; ++i)
+ out_le32(&pmac_irq_hw[i]->enable, 0);
+
+ /* get interrupt line of secondary interrupt controller */
+ if (irqctrler) {
+ second_irq = irqctrler->intrs[0].line;
+ printk(KERN_INFO "irq: secondary controller on irq %d\n",
+ (int)second_irq);
+ if (device_is_compatible(irqctrler, "gatwick"))
+ pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+ for ( i = max_real_irqs ; i < max_irqs ; i++ )
+ irq_desc[i].ctl = &gatwick_pic;
+ request_irq( second_irq, gatwick_action, SA_INTERRUPT,
+ "gatwick cascade", 0 );
+ }
+ printk("System has %d possible interrupts\n", max_irqs);
+ if (max_irqs != max_real_irqs)
+ printk(KERN_DEBUG "%d interrupts on main controller\n",
+ max_real_irqs);
+
+#ifdef CONFIG_XMON
+ request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
+#endif /* CONFIG_XMON */
+}
diff --git a/arch/ppc/kernel/pmac_pic.h b/arch/ppc/kernel/pmac_pic.h
new file mode 100644
index 000000000..335a9ef69
--- /dev/null
+++ b/arch/ppc/kernel/pmac_pic.h
@@ -0,0 +1,15 @@
+#ifndef _PPC_KERNEL_PMAC_PIC_H
+#define _PPC_KERNEL_PMAC_PIC_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type pmac_pic;
+
+void pmac_pic_init(void);
+void pmac_do_IRQ(struct pt_regs *regs,
+ int cpu,
+ int isfake);
+
+
+#endif /* _PPC_KERNEL_PMAC_PIC_H */
+
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index 499e8b6a5..9f8638021 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -44,6 +44,7 @@
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/pgtable.h>
+#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/pci-bridge.h>
#include <asm/adb.h>
@@ -52,10 +53,44 @@
#include <asm/ohare.h>
#include <asm/mediabay.h>
#include <asm/feature.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
#include "time.h"
+#include "local_irq.h"
+#include "pmac_pic.h"
+
+#undef SHOW_GATWICK_IRQS
+
+unsigned long pmac_get_rtc_time(void);
+int pmac_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+void pmac_calibrate_decr(void);
+void pmac_setup_pci_ptrs(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128];
+#endif /* CONFIG_MAGIC_SYSRQ */
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
unsigned char drive_info;
+int ppc_override_l2cr = 0;
+int ppc_override_l2cr_value;
+
extern char saved_command_line[];
#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
@@ -132,6 +167,16 @@ pmac_get_cpuinfo(char *buffer)
}
}
+ /* Checks "l2cr-value" property in the registry */
+ np = find_devices("cpus");
+ if (np != 0) {
+ unsigned int *l2cr = (unsigned int *)
+ get_property(np, "l2cr-value", NULL);
+ if (l2cr != 0) {
+ len += sprintf(buffer+len, "l2cr override\t: 0x%x\n", *l2cr);
+ }
+ }
+
return len;
}
@@ -210,6 +255,26 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p))
*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+ /* Checks "l2cr-value" property in the registry */
+ if ( (_get_PVR() >> 16) == 8) {
+ struct device_node *np = find_devices("cpus");
+ if (np != 0) {
+ unsigned int *l2cr = (unsigned int *)
+ get_property(np, "l2cr-value", NULL);
+ if (l2cr != 0) {
+ ppc_override_l2cr = 1;
+ ppc_override_l2cr_value = *l2cr;
+ _set_L2CR(0);
+ _set_L2CR(ppc_override_l2cr_value);
+ }
+ }
+ }
+
+ if (ppc_override_l2cr)
+ printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
+ ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
+ ? "enabled" : "disabled");
+
feature_init();
#ifdef CONFIG_KGDB
@@ -258,15 +323,12 @@ int boot_target;
int boot_part;
kdev_t boot_dev;
-void __init powermac_init(void)
+__initfunc(void
+pmac_init2(void))
{
- if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return;
adb_init();
pmac_nvram_init();
- if (_machine == _MACH_Pmac) {
- media_bay_init();
- }
+ media_bay_init();
}
#ifdef CONFIG_SCSI
@@ -371,3 +433,174 @@ void note_bootable_part(kdev_t dev, int part)
}
}
+void
+pmac_restart(char *cmd)
+{
+ struct adb_request req;
+
+ switch (adb_hardware) {
+ case ADB_VIACUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+ break;
+
+ case ADB_VIAPMU:
+ pmu_restart();
+ break;
+ default:
+ }
+}
+
+void
+pmac_power_off(void)
+{
+ struct adb_request req;
+
+ switch (adb_hardware) {
+ case ADB_VIACUDA:
+ cuda_request(&req, NULL, 2, CUDA_PACKET,
+ CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+ break;
+
+ case ADB_VIAPMU:
+ pmu_shutdown();
+ break;
+ default:
+ }
+}
+
+void
+pmac_halt(void)
+{
+ pmac_power_off();
+}
+
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+pmac_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_insw(port, buf, ns);
+}
+
+void
+pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ ide_outsw(port, buf, ns);
+}
+
+int
+pmac_ide_default_irq(ide_ioreg_t base)
+{
+ return 0;
+}
+
+ide_ioreg_t
+pmac_ide_default_io_base(int index)
+{
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+ return pmac_ide_regbase[index];
+#else
+ return 0;
+#endif
+}
+
+int
+pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return 0;
+}
+
+void
+pmac_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+}
+
+void
+pmac_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+}
+
+/* Convert the shorts/longs in hd_driveid from little to big endian;
+ * chars are endian independant, of course, but strings need to be flipped.
+ * (Despite what it says in drivers/block/ide.h, they come up as little
+ * endian...)
+ *
+ * Changes to linux/hdreg.h may require changes here. */
+void
+pmac_ide_fix_driveid(struct hd_driveid *id)
+{
+ ppc_generic_ide_fix_driveid(id);
+}
+
+/* This is declared in drivers/block/ide-pmac.c */
+void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+#endif
+
+__initfunc(void
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ pmac_setup_pci_ptrs();
+
+ /* isa_io_base gets set in pmac_find_bridges */
+ isa_mem_base = PMAC_ISA_MEM_BASE;
+ pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = ~0L;
+ DMA_MODE_READ = 1;
+ DMA_MODE_WRITE = 2;
+
+ ppc_md.setup_arch = pmac_setup_arch;
+ ppc_md.setup_residual = NULL;
+ ppc_md.get_cpuinfo = pmac_get_cpuinfo;
+ ppc_md.irq_cannonicalize = NULL;
+ ppc_md.init_IRQ = pmac_pic_init;
+ ppc_md.do_IRQ = pmac_do_IRQ;
+ ppc_md.init = pmac_init2;
+
+ ppc_md.restart = pmac_restart;
+ ppc_md.power_off = pmac_power_off;
+ ppc_md.halt = pmac_halt;
+
+ ppc_md.time_init = NULL;
+ ppc_md.set_rtc_time = pmac_set_rtc_time;
+ ppc_md.get_rtc_time = pmac_get_rtc_time;
+ ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD)
+ ppc_md.kbd_setkeycode = mackbd_setkeycode;
+ ppc_md.kbd_getkeycode = mackbd_getkeycode;
+ ppc_md.kbd_translate = mackbd_translate;
+ ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
+ ppc_md.kbd_leds = mackbd_leds;
+ ppc_md.kbd_init_hw = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate;
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+ ppc_ide_md.insw = pmac_ide_insw;
+ ppc_ide_md.outsw = pmac_ide_outsw;
+ ppc_ide_md.default_irq = pmac_ide_default_irq;
+ ppc_ide_md.default_io_base = pmac_ide_default_io_base;
+ ppc_ide_md.check_region = pmac_ide_check_region;
+ ppc_ide_md.request_region = pmac_ide_request_region;
+ ppc_ide_md.release_region = pmac_ide_release_region;
+ ppc_ide_md.fix_driveid = pmac_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
+
+ ppc_ide_md.io_base = 0;
+#endif
+}
+
diff --git a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c
new file mode 100644
index 000000000..87bc6d0f8
--- /dev/null
+++ b/arch/ppc/kernel/ppc8xx_pic.c
@@ -0,0 +1,49 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/irq.h>
+#include <asm/8xx_immap.h>
+#include <asm/mbx.h>
+#include "ppc8xx_pic.h"
+
+
+static void mbx_mask_irq(unsigned int irq_nr)
+{
+ if ( irq_nr == ISA_BRIDGE_INT ) return;
+ if ( irq_nr >= ppc8xx_pic.irq_offset )
+ irq_nr -= ppc8xx_pic.irq_offset;
+ ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr));
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0];
+}
+
+static void mbx_unmask_irq(unsigned int irq_nr)
+{
+ if ( irq_nr >= ppc8xx_pic.irq_offset )
+ irq_nr -= ppc8xx_pic.irq_offset;
+ ppc_cached_irq_mask[0] |= (1 << (31-irq_nr));
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = ppc_cached_irq_mask[0];
+}
+
+static void mbx_mask_and_ack(unsigned int irq_nr)
+{
+ /* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
+ if ( irq_nr != ISA_BRIDGE_INT )
+ mbx_mask_irq(irq_nr);
+ if ( irq_nr >= ppc8xx_pic.irq_offset )
+ irq_nr -= ppc8xx_pic.irq_offset;
+ /* clear the pending bits */
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
+}
+
+struct hw_interrupt_type ppc8xx_pic = {
+ " 8xx SIU ",
+ NULL,
+ NULL,
+ NULL,
+ mbx_unmask_irq,
+ mbx_mask_irq,
+ mbx_mask_and_ack,
+ 0
+};
diff --git a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h
new file mode 100644
index 000000000..d6b424fec
--- /dev/null
+++ b/arch/ppc/kernel/ppc8xx_pic.h
@@ -0,0 +1,9 @@
+
+#ifndef _PPC_KERNEL_PPC8xx_H
+#define _PPC_KERNEL_PPC8xx_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type ppc8xx_pic;
+
+#endif /* _PPC_KERNEL_PPC8xx_H */
diff --git a/arch/ppc/kernel/ppc_defs.h b/arch/ppc/kernel/ppc_defs.h
deleted file mode 100644
index 83315a2ae..000000000
--- a/arch/ppc/kernel/ppc_defs.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
-#define KERNELBASE -1073741824
-#define STATE 0
-#define NEXT_TASK 48
-#define COUNTER 24
-#define PROCESSOR 36
-#define SIGPENDING 8
-#define TSS 568
-#define MM 872
-#define TASK_STRUCT_SIZE 912
-#define KSP 0
-#define PG_TABLES 4
-#define PGD 8
-#define LAST_SYSCALL 20
-#define PT_REGS 12
-#define PF_TRACESYS 32
-#define TASK_FLAGS 4
-#define NEED_RESCHED 20
-#define TSS_FPR0 24
-#define TSS_FPSCR 284
-#define TSS_SMP_FORK_RET 288
-#define TASK_UNION_SIZE 8192
-#define STACK_FRAME_OVERHEAD 16
-#define INT_FRAME_SIZE 192
-#define GPR0 16
-#define GPR1 20
-#define GPR2 24
-#define GPR3 28
-#define GPR4 32
-#define GPR5 36
-#define GPR6 40
-#define GPR7 44
-#define GPR8 48
-#define GPR9 52
-#define GPR10 56
-#define GPR11 60
-#define GPR12 64
-#define GPR13 68
-#define GPR14 72
-#define GPR15 76
-#define GPR16 80
-#define GPR17 84
-#define GPR18 88
-#define GPR19 92
-#define GPR20 96
-#define GPR21 100
-#define GPR22 104
-#define GPR23 108
-#define GPR24 112
-#define GPR25 116
-#define GPR26 120
-#define GPR27 124
-#define GPR28 128
-#define GPR29 132
-#define GPR30 136
-#define GPR31 140
-#define _NIP 144
-#define _MSR 148
-#define _CTR 156
-#define _LINK 160
-#define _CCR 168
-#define _XER 164
-#define _DAR 180
-#define _DSISR 184
-#define ORIG_GPR3 152
-#define RESULT 188
-#define TRAP 176
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 1b7753dd0..834bdf102 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -8,11 +8,12 @@
#include <linux/vt_kern.h>
#include <linux/nvram.h>
+#include <asm/page.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
-#include <asm/ide.h>
#include <asm/io.h>
+#include <asm/ide.h>
#include <asm/atomic.h>
#include <asm/bitops.h>
#include <asm/checksum.h>
@@ -26,6 +27,8 @@
#include <asm/irq.h>
#include <asm/feature.h>
#include <asm/spinlock.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -39,13 +42,14 @@ extern void AlignmentException(struct pt_regs *regs);
extern void ProgramCheckException(struct pt_regs *regs);
extern void SingleStepException(struct pt_regs *regs);
extern int sys_sigreturn(struct pt_regs *regs);
-extern atomic_t n_lost_interrupts;
+extern atomic_t ppc_n_lost_interrupts;
extern void do_lost_interrupts(unsigned long);
extern int do_signal(sigset_t *, struct pt_regs *);
asmlinkage long long __ashrdi3(long long, int);
asmlinkage int abs(int);
+EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(syscall_trace);
EXPORT_SYMBOL(transfer_to_handler);
@@ -57,16 +61,21 @@ EXPORT_SYMBOL(AlignmentException);
EXPORT_SYMBOL(ProgramCheckException);
EXPORT_SYMBOL(SingleStepException);
EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(n_lost_interrupts);
+EXPORT_SYMBOL(ppc_n_lost_interrupts);
EXPORT_SYMBOL(do_lost_interrupts);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(local_irq_count);
-EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(ppc_local_irq_count);
+EXPORT_SYMBOL(ppc_local_bh_count);
EXPORT_SYMBOL(isa_io_base);
EXPORT_SYMBOL(isa_mem_base);
EXPORT_SYMBOL(pci_dram_offset);
+EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
+EXPORT_SYMBOL(DMA_MODE_READ);
+EXPORT_SYMBOL(DMA_MODE_WRITE);
+EXPORT_SYMBOL(_prep_type);
+EXPORT_SYMBOL(ucSystemType);
EXPORT_SYMBOL(atomic_add);
EXPORT_SYMBOL(atomic_sub);
@@ -155,6 +164,7 @@ EXPORT_SYMBOL(_enable_interrupts);
EXPORT_SYMBOL(flush_instruction_cache);
EXPORT_SYMBOL(_get_PVR);
EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(enable_kernel_fp);
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(xchg_u32);
#ifdef __SMP__
@@ -171,18 +181,14 @@ EXPORT_SYMBOL(_write_lock);
EXPORT_SYMBOL(_write_unlock);
#endif
-#ifndef CONFIG_MACH_SPECIFIC
EXPORT_SYMBOL(_machine);
-#endif
+EXPORT_SYMBOL(ppc_md);
EXPORT_SYMBOL(adb_request);
-EXPORT_SYMBOL(adb_autopoll);
EXPORT_SYMBOL(adb_register);
EXPORT_SYMBOL(cuda_request);
-EXPORT_SYMBOL(cuda_send_request);
EXPORT_SYMBOL(cuda_poll);
EXPORT_SYMBOL(pmu_request);
-EXPORT_SYMBOL(pmu_send_request);
EXPORT_SYMBOL(pmu_poll);
#ifdef CONFIG_PMAC_PBOOK
EXPORT_SYMBOL(sleep_notifier_list);
@@ -194,7 +200,6 @@ EXPORT_SYMBOL(find_compatible_devices);
EXPORT_SYMBOL(find_path_device);
EXPORT_SYMBOL(find_phandle);
EXPORT_SYMBOL(get_property);
-EXPORT_SYMBOL(device_is_compatible);
EXPORT_SYMBOL(pci_io_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
@@ -209,9 +214,8 @@ EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
#endif /* CONFIG_PMAC */
-#ifdef CONFIG_SOUND_MODULE
EXPORT_SYMBOL(abs);
-#endif
+EXPORT_SYMBOL(device_is_compatible);
/* The following are special because they're not called
explicitly (the C compiler generates them). Fortunately,
diff --git a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c
new file mode 100644
index 000000000..e69563c8a
--- /dev/null
+++ b/arch/ppc/kernel/prep_nvram.c
@@ -0,0 +1,173 @@
+/*
+ * linux/arch/ppc/kernel/prep_nvram.c
+ *
+ * Copyright (C) 1998 Corey Minyard
+ *
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+
+/*
+ * Allow for a maximum of 32K of PReP NvRAM data
+ */
+#define MAX_PREP_NVRAM 0x8000
+static char nvramData[MAX_PREP_NVRAM];
+static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0];
+
+#define PREP_NVRAM_AS0 0x74
+#define PREP_NVRAM_AS1 0x75
+#define PREP_NVRAM_DATA 0x77
+
+unsigned char *rs_pcNvRAM;
+
+unsigned char prep_nvram_read_val(int addr)
+{
+ outb(addr, PREP_NVRAM_AS0);
+ outb(addr>>8, PREP_NVRAM_AS1);
+ return inb(PREP_NVRAM_DATA);
+}
+
+void prep_nvram_write_val(int addr,
+ unsigned char val)
+{
+ outb(addr, PREP_NVRAM_AS0);
+ outb(addr>>8, PREP_NVRAM_AS1);
+ outb(val, PREP_NVRAM_DATA);
+}
+
+/*
+ * Most Radstone boards have NvRAM memory mapped at offset 8M in ISA space
+ */
+unsigned char rs_nvram_read_val(int addr)
+{
+ return rs_pcNvRAM[addr];
+}
+
+void rs_nvram_write_val(int addr,
+ unsigned char val)
+{
+ rs_pcNvRAM[addr]=val;
+}
+
+__initfunc(void init_prep_nvram(void))
+{
+ unsigned char *nvp;
+ int i;
+ int nvramSize;
+
+ /*
+ * I'm making the assumption that 32k will always cover the
+ * nvramsize. If this isn't the case please let me know and we can
+ * map the header, then get the size from the header, then map
+ * the whole size. -- Cort
+ */
+ if ( _prep_type == _PREP_Radstone )
+ rs_pcNvRAM = (unsigned char *)ioremap(_ISA_MEM_BASE+0x00800000,
+ 32<<10);
+ request_region(PREP_NVRAM_AS0, 0x8, "PReP NVRAM");
+ /*
+ * The following could fail if the NvRAM were corrupt but
+ * we expect the boot firmware to have checked its checksum
+ * before boot
+ */
+ nvp = (char *) &nvram->Header;
+ for (i=0; i<sizeof(HEADER); i++)
+ {
+ *nvp = ppc_md.nvram_read_val(i);
+ nvp++;
+ }
+
+ /*
+ * The PReP NvRAM may be any size so read in the header to
+ * determine how much we must read in order to get the complete
+ * GE area
+ */
+ nvramSize=(int)nvram->Header.GEAddress+nvram->Header.GELength;
+ if(nvramSize>MAX_PREP_NVRAM)
+ {
+ /*
+ * NvRAM is too large
+ */
+ nvram->Header.GELength=0;
+ return;
+ }
+
+ /*
+ * Read the remainder of the PReP NvRAM
+ */
+ nvp = (char *) &nvram->GEArea[0];
+ for (i=sizeof(HEADER); i<nvramSize; i++)
+ {
+ *nvp = ppc_md.nvram_read_val(i);
+ nvp++;
+ }
+}
+
+__prep
+char *prep_nvram_get_var(const char *name)
+{
+ char *cp;
+ int namelen;
+
+ namelen = strlen(name);
+ cp = prep_nvram_first_var();
+ while (cp != NULL) {
+ if ((strncmp(name, cp, namelen) == 0)
+ && (cp[namelen] == '='))
+ {
+ return cp+namelen+1;
+ }
+ cp = prep_nvram_next_var(cp);
+ }
+
+ return NULL;
+}
+
+__prep
+char *prep_nvram_first_var(void)
+{
+ if (nvram->Header.GELength == 0) {
+ return NULL;
+ } else {
+ return (((char *)nvram)
+ + ((unsigned int) nvram->Header.GEAddress));
+ }
+}
+
+__prep
+char *prep_nvram_next_var(char *name)
+{
+ char *cp;
+
+
+ cp = name;
+ while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+ && (*cp != '\0'))
+ {
+ cp++;
+ }
+
+ /* Skip over any null characters. */
+ while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+ && (*cp == '\0'))
+ {
+ cp++;
+ }
+
+ if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) {
+ return cp;
+ } else {
+ return NULL;
+ }
+}
+
+
+
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
index b48f7a1fc..dd7f1eee1 100644
--- a/arch/ppc/kernel/prep_pci.c
+++ b/arch/ppc/kernel/prep_pci.c
@@ -1,5 +1,5 @@
/*
- * $Id: prep_pci.c,v 1.24 1998/12/10 02:39:51 cort Exp $
+ * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $
* PReP pci functions.
* Originally by Gary Thomas
* rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -11,11 +11,19 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/openpic.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/ptrace.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/residual.h>
#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
#define MAX_DEVNR 22
@@ -27,6 +35,9 @@ unsigned char *Motherboard_map_name;
/* How is the 82378 PIRQ mapping setup? */
unsigned char *Motherboard_routes;
+/* Used for Motorola to store system config register */
+static unsigned long *ProcInfo;
+
/* Tables for known hardware */
/* Motorola PowerStackII - Utah */
@@ -34,38 +45,39 @@ static char Utah_pci_IRQ_map[23] __prepdata =
{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
- 4, /* Slot 2 - SCSI - NCR825A */
+ 5, /* Slot 2 - SCSI - NCR825A */
0, /* Slot 3 - unused */
1, /* Slot 4 - Ethernet - DEC2114x */
0, /* Slot 5 - unused */
- 2, /* Slot 6 - PCI Card slot #1 */
- 3, /* Slot 7 - PCI Card slot #2 */
- 4, /* Slot 8 - PCI Card slot #3 */
- 4, /* Slot 9 - PCI Bridge */
+ 3, /* Slot 6 - PCI Card slot #1 */
+ 4, /* Slot 7 - PCI Card slot #2 */
+ 5, /* Slot 8 - PCI Card slot #3 */
+ 5, /* Slot 9 - PCI Bridge */
/* added here in case we ever support PCI bridges */
/* Secondary PCI bus cards are at slot-9,6 & slot-9,7 */
0, /* Slot 10 - unused */
0, /* Slot 11 - unused */
- 4, /* Slot 12 - SCSI - NCR825A */
+ 5, /* Slot 12 - SCSI - NCR825A */
0, /* Slot 13 - unused */
- 2, /* Slot 14 - enet */
+ 3, /* Slot 14 - enet */
0, /* Slot 15 - unused */
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ 2, /* Slot 16 - unused */
+ 3, /* Slot 17 - unused */
+ 5, /* Slot 18 - unused */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
};
static char Utah_pci_IRQ_routes[] __prepdata =
{
0, /* Line 0 - Unused */
9, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15, /* Line 4 */
+ 10, /* Line 2 */
+ 11, /* Line 3 */
+ 14, /* Line 4 */
+ 15, /* Line 5 */
};
/* Motorola PowerStackII - Omaha */
@@ -125,9 +137,9 @@ static char Blackhawk_pci_IRQ_map[19] __prepdata =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- 1, /* Slot P7 */
- 2, /* Slot P6 */
- 3, /* Slot P5 */
+ 1, /* Slot P7 */
+ 2, /* Slot P6 */
+ 3, /* Slot P5 */
};
static char Blackhawk_pci_IRQ_routes[] __prepdata =
@@ -139,6 +151,122 @@ static char Blackhawk_pci_IRQ_routes[] __prepdata =
15 /* Line 4 */
};
+/* Motorola Mesquite */
+static char Mesquite_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unxued */
+ 0, /* Slot 11 - unused */
+ 0, /* Slot 12 - unused */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 3, /* Slot 16 - PMC */
+ 0, /* Slot 17 - unused */
+ 0, /* Slot 18 - unused */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+/* Motorola Sitka */
+static char Sitka_pci_IRQ_map[21] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unxued */
+ 0, /* Slot 11 - unused */
+ 0, /* Slot 12 - unused */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 9, /* Slot 16 - PMC 1 */
+ 12, /* Slot 17 - PMC 2 */
+ 0, /* Slot 18 - unused */
+ 0, /* Slot 19 - unused */
+ 4, /* Slot 20 - NT P2P bridge */
+};
+
+/* Motorola MTX */
+static char MTX_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+ 9, /* Slot 16 - PCI/PMC slot 1 */
+ 10, /* Slot 17 - PCI/PMC slot 2 */
+ 11, /* Slot 18 - PCI slot 3 */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static char MTXplus_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - Ethernet 1 */
+ 0, /* Slot 15 - unused */
+ 9, /* Slot 16 - PCI slot 1P */
+ 10, /* Slot 17 - PCI slot 2P */
+ 11, /* Slot 18 - PCI slot 3P */
+ 10, /* Slot 19 - Ethernet 2 */
+ 0, /* Slot 20 - P2P Bridge */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
+static char Raven_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* This is a dummy structure */
+};
+
/* Motorola MVME16xx */
static char Genesis_pci_IRQ_map[16] __prepdata =
{
@@ -169,8 +297,35 @@ static char Genesis_pci_IRQ_routes[] __prepdata =
15 /* Line 4 */
};
+static char Genesis2_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - Ethernet */
+ 0, /* Slot 11 - Universe PCI - VME Bridge */
+ 3, /* Slot 12 - unused */
+ 0, /* Slot 13 - unused */
+ 2, /* Slot 14 - SCSI */
+ 0, /* Slot 15 - graphics on 3600 */
+ 9, /* Slot 16 - PMC */
+ 12, /* Slot 17 - pci */
+ 11, /* Slot 18 - pci */
+ 10, /* Slot 19 - pci */
+ 0, /* Slot 20 - pci */
+ 0, /* Slot 21 - unused */
+ 0, /* Slot 22 - unused */
+};
+
/* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] __prepdata =
+static char Comet_pci_IRQ_map[23] __prepdata =
{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
@@ -188,6 +343,13 @@ static char Comet_pci_IRQ_map[16] __prepdata =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
+ 1, /* Slot 16 - PCI slot 1 */
+ 2, /* Slot 17 - PCI slot 2 */
+ 3, /* Slot 18 - PCI slot 3 */
+ 4, /* Slot 19 - PCI bridge */
+ 0,
+ 0,
+ 0,
};
static char Comet_pci_IRQ_routes[] __prepdata =
@@ -199,6 +361,43 @@ static char Comet_pci_IRQ_routes[] __prepdata =
15 /* Line 4 */
};
+/* Motorola Series-EX */
+static char Comet2_pci_IRQ_map[23] __prepdata =
+{
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 3, /* Slot 2 - SCSI - NCR825A */
+ 0, /* Slot 3 - unused */
+ 1, /* Slot 4 - Ethernet - DEC2104X */
+ 0, /* Slot 5 - unused */
+ 1, /* Slot 6 - PCI slot 1 */
+ 2, /* Slot 7 - PCI slot 2 */
+ 3, /* Slot 8 - PCI slot 3 */
+ 4, /* Slot 9 - PCI bridge */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - unused */
+ 3, /* Slot 12 - SCSI - NCR825A */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet - DEC2104X */
+ 0, /* Slot 15 - unused */
+ 1, /* Slot 16 - PCI slot 1 */
+ 2, /* Slot 17 - PCI slot 2 */
+ 3, /* Slot 18 - PCI slot 3 */
+ 4, /* Slot 19 - PCI bridge */
+ 0,
+ 0,
+ 0,
+};
+
+static char Comet2_pci_IRQ_routes[] __prepdata =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15, /* Line 4 */
+};
+
/*
* ibm 830 (and 850?).
* This is actually based on the Carolina motherboard
@@ -312,22 +511,40 @@ static char Nobis_pci_IRQ_routes[] __prepdata = {
#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
+/*
+ * 8259 edge/level control definitions
+ */
+#define ISA8259_M_ELCR 0x4d0
+#define ISA8259_S_ELCR 0x4d1
+
+#define ELCRS_INT15_LVL 0x80
+#define ELCRS_INT14_LVL 0x40
+#define ELCRS_INT12_LVL 0x10
+#define ELCRS_INT11_LVL 0x08
+#define ELCRS_INT10_LVL 0x04
+#define ELCRS_INT9_LVL 0x02
+#define ELCRS_INT8_LVL 0x01
+#define ELCRM_INT7_LVL 0x80
+#define ELCRM_INT5_LVL 0x20
+
+#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
+#define DEVNO(dev) (dev>>3)
+
__prep
int
prep_pcibios_read_config_dword (unsigned char bus,
unsigned char dev, unsigned char offset, unsigned int *val)
{
- unsigned long _val;
+ unsigned long _val;
unsigned long *ptr;
- dev >>= 3;
-
- if ((bus != 0) || (dev > MAX_DEVNR))
- {
+
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+ {
*val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
{
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned long *)CFGPTR(dev);
_val = le32_to_cpu(*ptr);
}
*val = _val;
@@ -339,16 +556,16 @@ int
prep_pcibios_read_config_word (unsigned char bus,
unsigned char dev, unsigned char offset, unsigned short *val)
{
- unsigned short _val;
+ unsigned short _val;
unsigned short *ptr;
- dev >>= 3;
- if ((bus != 0) || (dev > MAX_DEVNR))
- {
- *val = (unsigned short)0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
+
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+ {
+ *val = 0xFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
{
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned short *)CFGPTR(dev);
_val = le16_to_cpu(*ptr);
}
*val = _val;
@@ -360,16 +577,16 @@ int
prep_pcibios_read_config_byte (unsigned char bus,
unsigned char dev, unsigned char offset, unsigned char *val)
{
- unsigned char _val;
- volatile unsigned char *ptr;
- dev >>= 3;
- if ((bus != 0) || (dev > MAX_DEVNR))
- {
- *(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
+ unsigned char _val;
+ unsigned char *ptr;
+
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+ {
+ *val = 0xFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
{
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1));
+ ptr = (unsigned char *)CFGPTR(dev);
_val = *ptr;
}
*val = _val;
@@ -383,14 +600,14 @@ prep_pcibios_write_config_dword (unsigned char bus,
{
unsigned long _val;
unsigned long *ptr;
- dev >>= 3;
+
_val = le32_to_cpu(val);
- if ((bus != 0) || (dev > MAX_DEVNR))
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
{
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned long *)CFGPTR(dev);
*ptr = _val;
}
return PCIBIOS_SUCCESSFUL;
@@ -403,14 +620,14 @@ prep_pcibios_write_config_word (unsigned char bus,
{
unsigned short _val;
unsigned short *ptr;
- dev >>= 3;
+
_val = le16_to_cpu(val);
- if ((bus != 0) || (dev > MAX_DEVNR))
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
{
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ ptr = (unsigned short *)CFGPTR(dev);
*ptr = _val;
}
return PCIBIOS_SUCCESSFUL;
@@ -423,20 +640,151 @@ prep_pcibios_write_config_byte (unsigned char bus,
{
unsigned char _val;
unsigned char *ptr;
- dev >>= 3;
+
_val = val;
- if ((bus != 0) || (dev > MAX_DEVNR))
+ if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
{
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset^1));
+ ptr = (unsigned char *)CFGPTR(dev);
*ptr = _val;
}
return PCIBIOS_SUCCESSFUL;
}
-__initfunc(unsigned long route_pci_interrupts(void))
+#define MOTOROLA_CPUTYPE_REG 0x800
+#define MOTOROLA_BASETYPE_REG 0x803
+#define MPIC_RAVEN_ID 0x48010000
+#define MPIC_HAWK_ID 0x48030000
+#define MOT_PROC2_BIT 0x800
+
+static u_char mvme2600_openpic_initsenses[] __initdata = {
+ 1, /* MVME2600_INT_SIO */
+ 0, /* MVME2600_INT_FALCN_ECC_ERR */
+ 1, /* MVME2600_INT_PCI_ETHERNET */
+ 1, /* MVME2600_INT_PCI_SCSI */
+ 1, /* MVME2600_INT_PCI_GRAPHICS */
+ 1, /* MVME2600_INT_PCI_VME0 */
+ 1, /* MVME2600_INT_PCI_VME1 */
+ 1, /* MVME2600_INT_PCI_VME2 */
+ 1, /* MVME2600_INT_PCI_VME3 */
+ 1, /* MVME2600_INT_PCI_INTA */
+ 1, /* MVME2600_INT_PCI_INTB */
+ 1, /* MVME2600_INT_PCI_INTC */
+ 1, /* MVME2600_INT_PCI_INTD */
+ 1, /* MVME2600_INT_LM_SIG0 */
+ 1, /* MVME2600_INT_LM_SIG1 */
+};
+
+#define MOT_RAVEN_PRESENT 0x1
+#define MOT_HAWK_PRESENT 0x2
+
+int prep_keybd_present = 1;
+int MotMPIC = 0;
+
+__initfunc(int raven_init(void))
+{
+ unsigned int devid;
+ unsigned int pci_membase;
+ unsigned char base_mod;
+
+ /* Check to see if the Raven chip exists. */
+ if ( _prep_type != _PREP_Motorola) {
+ OpenPIC = NULL;
+ return 0;
+ }
+
+ /* Check to see if this board is a type that might have a Raven. */
+ if ((inb(MOTOROLA_CPUTYPE_REG) & 0xF0) != 0xE0) {
+ OpenPIC = NULL;
+ return 0;
+ }
+
+ /* Check the first PCI device to see if it is a Raven. */
+ pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &devid);
+
+ switch (devid & 0xffff0000) {
+ case MPIC_RAVEN_ID:
+ MotMPIC = MOT_RAVEN_PRESENT;
+ break;
+ case MPIC_HAWK_ID:
+ MotMPIC = MOT_HAWK_PRESENT;
+ break;
+ default:
+ OpenPIC = NULL;
+ return 0;
+ }
+
+
+ /* Read the memory base register. */
+ pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+ if (pci_membase == 0) {
+ OpenPIC = NULL;
+ return 0;
+ }
+
+ /* Map the Raven MPIC registers to virtual memory. */
+ OpenPIC = (struct OpenPIC *)ioremap(pci_membase+0xC0000000, 0x22000);
+
+ OpenPIC_InitSenses = mvme2600_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+
+ /* If raven is present on Motorola store the system config register
+ * for later use.
+ */
+ ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
+
+ /* This is a hack. If this is a 2300 or 2400 mot board then there is
+ * no keyboard controller and we have to indicate that.
+ */
+ base_mod = inb(MOTOROLA_BASETYPE_REG);
+ if ((MotMPIC == MOT_HAWK_PRESENT) || (base_mod == 0xF9) ||
+ (base_mod == 0xFA) || (base_mod == 0xE1))
+ prep_keybd_present = 0;
+
+ return 1;
+}
+
+struct mot_info {
+ int cpu_type; /* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
+ /* 0x200 if this board has a Hawk chip. */
+ int base_type;
+ int max_cpu; /* ored with 0x80 if this board should be checked for multi CPU */
+ const char *name;
+ unsigned char *map;
+ unsigned char *routes;
+} mot_info[] = {
+ {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes},
+ {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes},
+ {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes},
+ {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes},
+ {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes},
+ {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes},
+ {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes},
+ {0x000, 0x00, 0x00, "", NULL, NULL}
+};
+
+__initfunc(unsigned long prep_route_pci_interrupts(void))
{
unsigned char *ibc_pirq = (unsigned char *)0x80800860;
unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
@@ -445,49 +793,66 @@ __initfunc(unsigned long route_pci_interrupts(void))
if ( _prep_type == _PREP_Motorola)
{
unsigned short irq_mode;
+ unsigned char cpu_type;
+ unsigned char base_mod;
+ int entry;
+ int mot_entry = -1;
- switch (inb(0x800) & 0xF0)
- {
- case 0x10: /* MVME16xx */
- Motherboard_map_name = "Genesis";
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x20: /* Series E */
- Motherboard_map_name = "Powerstack (Series E)";
- Motherboard_map = Comet_pci_IRQ_map;
- Motherboard_routes = Comet_pci_IRQ_routes;
- break;
- case 0x50: /* PowerStackII Pro3000 */
- Motherboard_map_name = "Omaha (PowerStack II Pro3000)";
- Motherboard_map = Omaha_pci_IRQ_map;
- Motherboard_routes = Omaha_pci_IRQ_routes;
- break;
- case 0x60: /* PowerStackII Pro4000 */
- Motherboard_map_name = "Utah (Powerstack II Pro4000)";
- Motherboard_map = Utah_pci_IRQ_map;
- Motherboard_routes = Utah_pci_IRQ_routes;
- break;
- case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */
- Motherboard_map_name = "Motorola MTX";
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x40: /* PowerStack */
- default: /* Can't hurt, can it? */
- Motherboard_map_name = "Blackhawk (Powerstack)";
- Motherboard_map = Blackhawk_pci_IRQ_map;
- Motherboard_routes = Blackhawk_pci_IRQ_routes;
- break;
+ cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+ base_mod = inb(MOTOROLA_BASETYPE_REG);
+
+ for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+ if (mot_info[entry].cpu_type & 0x200) { /* Check for Hawk chip */
+ if (!(MotMPIC & MOT_HAWK_PRESENT))
+ continue;
+ } else { /* Check non hawk boards */
+ if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+ continue;
+
+ if (mot_info[entry].base_type == 0) {
+ mot_entry = entry;
+ break;
+ }
+
+ if (mot_info[entry].base_type != base_mod)
+ continue;
+ }
+
+ if (!(mot_info[entry].max_cpu & 0x80)) {
+ mot_entry = entry;
+ break;
+ }
+
+ /* processor 1 not present and max processor zero indicated */
+ if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
+ mot_entry = entry;
+ break;
+ }
+
+ /* processor 1 present and max processor zero indicated */
+ if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
+ mot_entry = entry;
+ break;
+ }
}
- /* AJF adjust level/edge control according to routes */
- irq_mode = 0;
- for (i = 1; i <= 4; i++)
- {
- irq_mode |= ( 1 << Motherboard_routes[i] );
+
+ if (mot_entry == -1) /* No particular cpu type found - assume Blackhawk */
+ mot_entry = 3;
+
+ Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+ Motherboard_map = mot_info[mot_entry].map;
+ Motherboard_routes = mot_info[mot_entry].routes;
+
+ if (!(mot_info[entry].cpu_type & 0x100)) {
+ /* AJF adjust level/edge control according to routes */
+ irq_mode = 0;
+ for (i = 1; i <= 4; i++)
+ {
+ irq_mode |= ( 1 << Motherboard_routes[i] );
+ }
+ outb( irq_mode & 0xff, 0x4d0 );
+ outb( (irq_mode >> 8) & 0xff, 0x4d1 );
}
- outb( irq_mode & 0xff, 0x4d0 );
- outb( (irq_mode >> 8) & 0xff, 0x4d1 );
} else if ( _prep_type == _PREP_IBM )
{
unsigned char pl_id;
@@ -526,6 +891,71 @@ __initfunc(unsigned long route_pci_interrupts(void))
outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
pl_id=inb(0x04d1);
/*printk("Hi mask now %#0x\n", pl_id);*/
+ } else if ( _prep_type == _PREP_Radstone )
+ {
+ unsigned char ucElcrM, ucElcrS;
+
+ /*
+ * Set up edge/level
+ */
+ switch(ucSystemType)
+ {
+ case RS_SYS_TYPE_PPC1:
+ {
+ if(ucBoardRevMaj<5)
+ {
+ ucElcrS=ELCRS_INT15_LVL;
+ }
+ else
+ {
+ ucElcrS=ELCRS_INT9_LVL |
+ ELCRS_INT11_LVL |
+ ELCRS_INT14_LVL |
+ ELCRS_INT15_LVL;
+ }
+ ucElcrM=ELCRM_INT5_LVL | ELCRM_INT7_LVL;
+ break;
+ }
+
+ case RS_SYS_TYPE_PPC1a:
+ {
+ ucElcrS=ELCRS_INT9_LVL |
+ ELCRS_INT11_LVL |
+ ELCRS_INT14_LVL |
+ ELCRS_INT15_LVL;
+ ucElcrM=ELCRM_INT5_LVL;
+ break;
+ }
+
+ case RS_SYS_TYPE_PPC2:
+ case RS_SYS_TYPE_PPC2a:
+ case RS_SYS_TYPE_PPC2ep:
+ case RS_SYS_TYPE_PPC4:
+ case RS_SYS_TYPE_PPC4a:
+ default:
+ {
+ ucElcrS=ELCRS_INT9_LVL |
+ ELCRS_INT10_LVL |
+ ELCRS_INT11_LVL |
+ ELCRS_INT14_LVL |
+ ELCRS_INT15_LVL;
+ ucElcrM=ELCRM_INT5_LVL |
+ ELCRM_INT7_LVL;
+ break;
+ }
+ }
+
+ /*
+ * Write edge/level selection
+ */
+ outb(ucElcrS, ISA8259_S_ELCR);
+ outb(ucElcrM, ISA8259_M_ELCR);
+
+ /*
+ * Radstone boards have PCI interrupts all set up
+ * so leave well alone
+ */
+ return 0;
} else
{
printk("No known machine pci routing!\n");
@@ -542,3 +972,117 @@ __initfunc(unsigned long route_pci_interrupts(void))
return 0;
}
+__initfunc(
+void
+prep_pcibios_fixup(void))
+{
+ struct pci_dev *dev;
+ extern unsigned char *Motherboard_map;
+ extern unsigned char *Motherboard_routes;
+ unsigned char i;
+
+ if ( _prep_type == _PREP_Radstone )
+ {
+ printk("Radstone boards require no PCI fixups\n");
+ return;
+ }
+
+ prep_route_pci_interrupts();
+
+ printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
+ if (OpenPIC) {
+ /* PCI interrupts are controlled by the OpenPIC */
+ for(dev=pci_devices; dev; dev=dev->next) {
+ if (dev->bus->number == 0) {
+ dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
+ pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
+ }
+ }
+ return;
+ }
+
+ for(dev=pci_devices; dev; dev=dev->next)
+ {
+ /*
+ * Use our old hard-coded kludge to figure out what
+ * irq this device uses. This is necessary on things
+ * without residual data. -- Cort
+ */
+ unsigned char d = PCI_SLOT(dev->devfn);
+ dev->irq = Motherboard_routes[Motherboard_map[d]];
+
+ for ( i = 0 ; i <= 5 ; i++ )
+ {
+ if ( dev->base_address[i] > 0x10000000 )
+ {
+ printk("Relocating PCI address %lx -> %lx\n",
+ dev->base_address[i],
+ (dev->base_address[i] & 0x00FFFFFF)
+ | 0x01000000);
+ dev->base_address[i] =
+ (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+ pci_write_config_dword(dev,
+ PCI_BASE_ADDRESS_0+(i*0x4),
+ dev->base_address[i] );
+ }
+ }
+#if 0
+ /*
+ * If we have residual data and if it knows about this
+ * device ask it what the irq is.
+ * -- Cort
+ */
+ ppcd = residual_find_device_id( ~0L, dev->device,
+ -1,-1,-1, 0);
+#endif
+ }
+}
+
+decl_config_access_method(indirect);
+
+__initfunc(
+void
+prep_setup_pci_ptrs(void))
+{
+ PPC_DEVICE *hostbridge;
+
+ printk("PReP architecture\n");
+ if ( _prep_type == _PREP_Radstone )
+ {
+ pci_config_address = (unsigned *)0x80000cf8;
+ pci_config_data = (char *)0x80000cfc;
+ set_config_access_method(indirect);
+ }
+ else
+ {
+ hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
+ BridgeController, PCIBridge, -1, 0);
+ if (hostbridge &&
+ hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
+ PnP_TAG_PACKET * pkt;
+ set_config_access_method(indirect);
+ pkt = PnP_find_large_vendor_packet(
+ res->DevicePnPHeap+hostbridge->AllocatedOffset,
+ 3, 0);
+ if(pkt)
+ {
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+ pci_config_address= (unsigned *)ld_le32((unsigned *) p.PPCData);
+ pci_config_data= (unsigned char *)ld_le32((unsigned *) (p.PPCData+8));
+ }
+ else
+ {
+ pci_config_address= (unsigned *) 0x80000cf8;
+ pci_config_data= (unsigned char *) 0x80000cfc;
+ }
+ }
+ else
+ {
+ set_config_access_method(prep);
+ }
+
+ }
+
+ ppc_md.pcibios_fixup = prep_pcibios_fixup;
+}
+
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index 72752e11f..de18f465a 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -30,6 +30,9 @@
#include <linux/blk.h>
#include <linux/ioport.h>
#include <linux/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/openpic.h>
#include <asm/mmu.h>
#include <asm/processor.h>
@@ -38,12 +41,57 @@
#include <asm/pgtable.h>
#include <asm/ide.h>
#include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/mk48t59.h>
+#include <asm/prep_nvram.h>
+#include <asm/raven.h>
+
+
+#include "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
#include <../drivers/sound/sound_config.h>
#include <../drivers/sound/dev_table.h>
#endif
+unsigned char ucSystemType;
+unsigned char ucBoardRev;
+unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+extern unsigned long mc146818_get_rtc_time(void);
+extern int mc146818_set_rtc_time(unsigned long nowtime);
+extern unsigned long mk48t59_get_rtc_time(void);
+extern int mk48t59_set_rtc_time(unsigned long nowtime);
+
+extern unsigned char prep_nvram_read_val(int addr);
+extern void prep_nvram_write_val(int addr,
+ unsigned char val);
+extern unsigned char rs_nvram_read_val(int addr);
+extern void rs_nvram_write_val(int addr,
+ unsigned char val);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
+extern void prep_setup_pci_ptrs(void);
+extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
+extern char saved_command_line[256];
+
+int _prep_type;
+
+#define cached_21 (((char *)(ppc_cached_irq_mask))[3])
+#define cached_A1 (((char *)(ppc_cached_irq_mask))[2])
+
/* for the mac fs */
kdev_t boot_dev;
/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
@@ -54,13 +102,15 @@ extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern int probingmem;
extern unsigned long loops_per_sec;
-extern unsigned char aux_device_present;
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
extern int rd_image_start; /* starting block # of image */
#endif
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
__prep
int
@@ -136,6 +186,8 @@ prep_get_cpuinfo(char *buffer)
break;
}
break;
+ default:
+ break;
}
@@ -163,11 +215,12 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
{
extern char cmd_line[];
unsigned char reg;
+ unsigned char ucMothMemType;
+ unsigned char ucEquipPres1;
/* init to some ~sane value until calibrate_delay() runs */
loops_per_sec = 50000000;
- aux_device_present = 0xaa;
/* Set up floppy in PS/2 mode */
outb(0x09, SIO_CONFIG_RA);
reg = inb(SIO_CONFIG_RD);
@@ -175,20 +228,78 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
outb(reg, SIO_CONFIG_RD);
outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
+ /*
+ * We need to set up the NvRAM access routines early as prep_init
+ * has yet to be called
+ */
+ ppc_md.nvram_read_val = prep_nvram_read_val;
+ ppc_md.nvram_write_val = prep_nvram_write_val;
+
/* we should determine this according to what we find! -- Cort */
switch ( _prep_type )
{
case _PREP_IBM:
+ /* Enable L2. Assume we don't need to flush -- Cort*/
+ *(unsigned char *)(0x8000081c) |= 3;
ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
break;
case _PREP_Motorola:
+ /* Enable L2. Assume we don't need to flush -- Cort*/
+ *(unsigned char *)(0x8000081c) |= 3;
ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
break;
+ case _PREP_Radstone:
+ ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+
+ /*
+ * Determine system type
+ */
+ ucMothMemType=inb(0x866);
+ ucEquipPres1=inb(0x80c);
+
+ ucSystemType=((ucMothMemType&0x03)<<1) |
+ ((ucEquipPres1&0x80)>>7);
+ ucSystemType^=7;
+
+ /*
+ * Determine board revision for use by
+ * rev. specific code
+ */
+ ucBoardRev=inb(0x854);
+ ucBoardRevMaj=ucBoardRev>>5;
+ ucBoardRevMin=ucBoardRev&0x1f;
+
+ /*
+ * Most Radstone boards have memory mapped NvRAM
+ */
+ if((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj<5))
+ {
+ ppc_md.nvram_read_val = prep_nvram_read_val;
+ ppc_md.nvram_write_val = prep_nvram_write_val;
+ }
+ else
+ {
+ ppc_md.nvram_read_val = rs_nvram_read_val;
+ ppc_md.nvram_write_val = rs_nvram_write_val;
+ }
+ break;
}
- /* Enable L2. Assume we don't need to flush -- Cort*/
- *(unsigned char *)(0x8000081c) = *(unsigned char *)(0x8000081c)|3;
-
+ /* Read in NVRAM data */
+ init_prep_nvram();
+
+ /* if no bootargs, look in NVRAM */
+ if ( cmd_line[0] == '\0' ) {
+ char *bootargs;
+ bootargs = prep_nvram_get_var("bootargs");
+ if (bootargs != NULL) {
+ strcpy(cmd_line, bootargs);
+
+ /* again.. */
+ strcpy(saved_command_line, cmd_line);
+ }
+ }
+
printk("Boot arguments: %s\n", cmd_line);
#ifdef CONFIG_SOUND_CS4232
@@ -238,12 +349,349 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
request_region(0x80,0x10,"dma page reg");
request_region(0xc0,0x20,"dma2");
+ raven_init();
+
#ifdef CONFIG_VGA_CONSOLE
+ /* remap the VGA memory */
+ vgacon_remap_base = 0xf0000000;
+ /*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
conswitchp = &vga_con;
#endif
}
-__initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+/*
+ * Determine the decrementer frequency from the residual data
+ * This allows for a faster boot as we do not need to calibrate the
+ * decrementer against another clock. This is important for embedded systems.
+ */
+__initfunc(void prep_res_calibrate_decr(void))
+{
+ int freq, divisor;
+
+ freq = res->VitalProductData.ProcessorBusHz;
+ divisor = 4;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems. On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+
+__initfunc(void
+prep_calibrate_decr_handler(int irq,
+ void *dev,
+ struct pt_regs *regs))
+{
+ unsigned long freq, divisor;
+ static unsigned long t1 = 0, t2 = 0;
+
+ if ( !t1 )
+ t1 = get_dec();
+ else if (!t2)
+ {
+ t2 = get_dec();
+ t2 = t1-t2; /* decr's in 1/HZ */
+ t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+ *done_ptr = 1;
+ }
+}
+
+__initfunc(void prep_calibrate_decr(void))
+{
+ unsigned long flags;
+
+
+ save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set timer to periodic mode */
+ outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+ /* set the clock to ~100 Hz */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+
+ if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+ __sti();
+ while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+ restore_flags(flags);
+ free_irq( 0, NULL);
+}
+
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer. */
+__initfunc(void mk48t59_calibrate_decr(void))
+{
+ unsigned long freq, divisor;
+ unsigned long t1, t2;
+ unsigned char save_control;
+ long i;
+ unsigned char sec;
+
+
+ /* Make sure the time is not stopped. */
+ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+ (save_control & (~MK48T59_RTC_CB_STOP)));
+
+ /* Now make sure the read bit is off so the value will change. */
+ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+ save_control &= ~MK48T59_RTC_CA_READ;
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+
+ /* Read the seconds value to see when it changes. */
+ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+ break;
+ }
+ }
+ t1 = get_dec();
+
+ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+ for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+ break;
+ }
+ }
+
+ t2 = t1 - get_dec();
+
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+void
+prep_restart(char *cmd)
+{
+ unsigned long i = 10000;
+
+
+ _disable_interrupts();
+
+ /* set exception prefix high - to the prom */
+ _nmask_and_or_msr(0, MSR_IP);
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(0x92) & ~1L , 0x92 );
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(0x92) | 1 , 0x92 );
+
+ while ( i != 0 ) i++;
+ panic("restart failed\n");
+}
+
+/*
+ * This function will restart a board regardless of port 92 functionality
+ */
+void
+prep_direct_restart(char *cmd)
+{
+ u32 jumpaddr=0xfff00100;
+ u32 defaultmsr=MSR_IP;
+
+ /*
+ * This will ALWAYS work regardless of port 92
+ * functionality
+ */
+ _disable_interrupts();
+
+ __asm__ __volatile__("\n\
+ mtspr 26, %1 /* SRR0 */
+ mtspr 27, %0 /* SRR1 */
+ rfi"
+ :
+ : "r" (defaultmsr), "r" (jumpaddr));
+ /*
+ * Not reached
+ */
+}
+
+void
+prep_halt(void)
+{
+ unsigned long flags;
+ _disable_interrupts();
+ /* set exception prefix high - to the prom */
+ save_flags( flags );
+ restore_flags( flags|MSR_IP );
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(0x92) & ~1L , 0x92 );
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(0x92) | 1 , 0x92 );
+
+ while ( 1 ) ;
+ /*
+ * Not reached
+ */
+}
+
+void
+prep_power_off(void)
+{
+ prep_halt();
+}
+
+int prep_setup_residual(char *buffer)
+{
+ int len = 0;
+
+
+ /* PREP's without residual data will give incorrect values here */
+ len += sprintf(len+buffer, "clock\t\t: ");
+ if ( res->ResidualLength )
+ len += sprintf(len+buffer, "%ldMHz\n",
+ (res->VitalProductData.ProcessorHz > 1024) ?
+ res->VitalProductData.ProcessorHz>>20 :
+ res->VitalProductData.ProcessorHz);
+ else
+ len += sprintf(len+buffer, "???\n");
+
+ return len;
+}
+
+u_int
+prep_irq_cannonicalize(u_int irq)
+{
+ if (irq == 2)
+ {
+ return 9;
+ }
+ else
+ {
+ return irq;
+ }
+}
+
+void
+prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
+{
+ int irq;
+
+ if ( (irq = i8259_irq(0)) < 0 )
+ {
+ printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
+ regs->nip);
+ ppc_spurious_interrupts++;
+ return;
+ }
+ ppc_irq_dispatch_handler( regs, irq );
+}
+
+__initfunc(void
+prep_init_IRQ(void))
+{
+ int i;
+
+ if (OpenPIC != NULL) {
+ for ( i = 16 ; i < 36 ; i++ )
+ irq_desc[i].ctl = &open_pic;
+ openpic_init(1);
+ }
+
+ for ( i = 0 ; i < 16 ; i++ )
+ irq_desc[i].ctl = &i8259_pic;
+ i8259_init();
+#ifdef __SMP__
+ request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+ 0, "IPI0", 0);
+#endif /* __SMP__ */
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+ _insw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+void
+prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+ _outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+int
+prep_ide_default_irq(ide_ioreg_t base)
+{
+ switch (base) {
+ case 0x1f0: return 13;
+ case 0x170: return 13;
+ case 0x1e8: return 11;
+ case 0x168: return 10;
+ default:
+ return 0;
+ }
+}
+
+ide_ioreg_t
+prep_ide_default_io_base(int index)
+{
+ switch (index) {
+ case 0: return 0x1f0;
+ case 1: return 0x170;
+ case 2: return 0x1e8;
+ case 3: return 0x168;
+ default:
+ return 0;
+ }
+}
+
+int
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+ return check_region(from, extent);
+}
+
+void
+prep_ide_request_region(ide_ioreg_t from,
+ unsigned int extent,
+ const char *name)
+{
+ request_region(from, extent, name);
+}
+
+void
+prep_ide_release_region(ide_ioreg_t from,
+ unsigned int extent)
+{
+ release_region(from, extent);
+}
+
+void
+prep_ide_fix_driveid(struct hd_driveid *id)
+{
+}
+
+__initfunc(void
+prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
{
ide_ioreg_t port = base;
int i = 8;
@@ -254,6 +702,143 @@ __initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int
if (irq != NULL)
*irq = 0;
}
+#endif
+
+__initfunc(void
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7))
+{
+ /* make a copy of residual data */
+ if ( r3 )
+ {
+ memcpy((void *)res,(void *)(r3+KERNELBASE),
+ sizeof(RESIDUAL));
+ }
+
+ isa_io_base = PREP_ISA_IO_BASE;
+ isa_mem_base = PREP_ISA_MEM_BASE;
+ pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+ ISA_DMA_THRESHOLD = 0x00ffffff;
+ DMA_MODE_READ = 0x44;
+ DMA_MODE_WRITE = 0x48;
+
+ /* figure out what kind of prep workstation we are */
+ if ( res->ResidualLength != 0 )
+ {
+ if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+ _prep_type = _PREP_IBM;
+ else if (!strncmp(res->VitalProductData.PrintableModel,
+ "Radstone",8))
+ {
+ extern char *Motherboard_map_name;
+
+ _prep_type = _PREP_Radstone;
+ Motherboard_map_name=
+ res->VitalProductData.PrintableModel;
+ }
+ else
+ _prep_type = _PREP_Motorola;
+ }
+ else /* assume motorola if no residual (netboot?) */
+ {
+ _prep_type = _PREP_Motorola;
+ }
+
+ prep_setup_pci_ptrs();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ /* take care of cmd line */
+ if ( r6 && (((char *) r6) != '\0'))
+ {
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+
+ ppc_md.setup_arch = prep_setup_arch;
+ ppc_md.setup_residual = prep_setup_residual;
+ ppc_md.get_cpuinfo = prep_get_cpuinfo;
+ ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+ ppc_md.init_IRQ = prep_init_IRQ;
+ if ( !OpenPIC )
+ ppc_md.do_IRQ = prep_do_IRQ;
+ else
+ ppc_md.do_IRQ = chrp_do_IRQ;
+ ppc_md.init = NULL;
+
+ ppc_md.restart = prep_restart;
+ ppc_md.power_off = prep_power_off;
+ ppc_md.halt = prep_halt;
+
+ ppc_md.time_init = NULL;
+ if (_prep_type == _PREP_Radstone) {
+ /*
+ * We require a direct restart as port 92 does not work on
+ * all Radstone boards
+ */
+ ppc_md.restart = prep_direct_restart;
+ /*
+ * The RTC device used varies according to board type
+ */
+ if(((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj>=5)) ||
+ (ucSystemType==RS_SYS_TYPE_PPC1a))
+ {
+ ppc_md.set_rtc_time = mk48t59_set_rtc_time;
+ ppc_md.get_rtc_time = mk48t59_get_rtc_time;
+ }
+ else
+ {
+ ppc_md.set_rtc_time = mc146818_set_rtc_time;
+ ppc_md.get_rtc_time = mc146818_get_rtc_time;
+ }
+ /*
+ * Determine the decrementer rate from the residual data
+ */
+ ppc_md.calibrate_decr = prep_res_calibrate_decr;
+ }
+ else if (_prep_type == _PREP_IBM) {
+ ppc_md.set_rtc_time = mc146818_set_rtc_time;
+ ppc_md.get_rtc_time = mc146818_get_rtc_time;
+ ppc_md.calibrate_decr = prep_calibrate_decr;
+ }
+ else {
+ ppc_md.set_rtc_time = mk48t59_set_rtc_time;
+ ppc_md.get_rtc_time = mk48t59_get_rtc_time;
+ ppc_md.calibrate_decr = mk48t59_calibrate_decr;
+ }
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+ ppc_ide_md.insw = prep_ide_insw;
+ ppc_ide_md.outsw = prep_ide_outsw;
+ ppc_ide_md.default_irq = prep_ide_default_irq;
+ ppc_ide_md.default_io_base = prep_ide_default_io_base;
+ ppc_ide_md.check_region = prep_ide_check_region;
+ ppc_ide_md.request_region = prep_ide_request_region;
+ ppc_ide_md.release_region = prep_ide_release_region;
+ ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
+ ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+#endif
+ ppc_ide_md.io_base = _IO_BASE;
+
+#ifdef CONFIG_VT
+ ppc_md.kbd_setkeycode = pckbd_setkeycode;
+ ppc_md.kbd_getkeycode = pckbd_getkeycode;
+ ppc_md.kbd_translate = pckbd_translate;
+ ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+ ppc_md.kbd_leds = pckbd_leds;
+ ppc_md.kbd_init_hw = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+#endif
+#endif
+}
#ifdef CONFIG_SOUND_MODULE
EXPORT_SYMBOL(ppc_cs4232_dma);
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
index f1dff8f13..5b8873d79 100644
--- a/arch/ppc/kernel/prep_time.c
+++ b/arch/ppc/kernel/prep_time.c
@@ -22,7 +22,9 @@
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/processor.h>
-#include <asm/nvram.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/mk48t59.h>
#include "time.h"
@@ -41,73 +43,29 @@
* is setup at boot time to use the correct addresses.
* -- Cort
*/
-/*
- * translate from mc146818 to m48t18 addresses
- */
-unsigned int clock_transl[] __prepdata = { MOTO_RTC_SECONDS,0 /* alarm */,
- MOTO_RTC_MINUTES,0 /* alarm */,
- MOTO_RTC_HOURS,0 /* alarm */, /* 4,5 */
- MOTO_RTC_DAY_OF_WEEK,
- MOTO_RTC_DAY_OF_MONTH,
- MOTO_RTC_MONTH,
- MOTO_RTC_YEAR, /* 9 */
- MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
-};
-
-__prep
-int prep_cmos_clock_read(int addr)
-{
- if ( _prep_type == _PREP_IBM )
- return CMOS_READ(addr);
- else if ( _prep_type == _PREP_Motorola )
- {
- outb(clock_transl[addr]>>8, NVRAM_AS1);
- outb(clock_transl[addr], NVRAM_AS0);
- return (inb(NVRAM_DATA));
- }
-
- printk("Unknown machine in prep_cmos_clock_read()!\n");
- return -1;
-}
-
-__prep
-void prep_cmos_clock_write(unsigned long val, int addr)
-{
- if ( _prep_type == _PREP_IBM )
- {
- CMOS_WRITE(val,addr);
- return;
- }
- else if ( _prep_type == _PREP_Motorola )
- {
- outb(clock_transl[addr]>>8, NVRAM_AS1);
- outb(clock_transl[addr], NVRAM_AS0);
- outb(val,NVRAM_DATA);
- return;
- }
- printk("Unknown machine in prep_cmos_clock_write()!\n");
-}
/*
* Set the hardware clock. -- Cort
*/
__prep
-int prep_set_rtc_time(unsigned long nowtime)
+int mc146818_set_rtc_time(unsigned long nowtime)
{
unsigned char save_control, save_freq_select;
struct rtc_time tm;
to_tm(nowtime, &tm);
- save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
- prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
- save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ /* tell the clock it's being set */
+ save_control = CMOS_READ(RTC_CONTROL);
- prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
- tm.tm_year -= 1900;
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ /* stop and reset prescaler */
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ tm.tm_year = (tm.tm_year - 1900) % 100;
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BIN_TO_BCD(tm.tm_sec);
BIN_TO_BCD(tm.tm_min);
@@ -116,12 +74,12 @@ int prep_set_rtc_time(unsigned long nowtime)
BIN_TO_BCD(tm.tm_mday);
BIN_TO_BCD(tm.tm_year);
}
- prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
- prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
- prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
- prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
- prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
- prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
+ CMOS_WRITE(tm.tm_sec, RTC_SECONDS);
+ CMOS_WRITE(tm.tm_min, RTC_MINUTES);
+ CMOS_WRITE(tm.tm_hour, RTC_HOURS);
+ CMOS_WRITE(tm.tm_mon, RTC_MONTH);
+ CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH);
+ CMOS_WRITE(tm.tm_year, RTC_YEAR);
/* The following flags have to be released exactly in this order,
* otherwise the DS12887 (popular MC146818A clone with integrated
@@ -130,16 +88,14 @@ int prep_set_rtc_time(unsigned long nowtime)
* the Dallas Semiconductor data sheets, but who believes data
* sheets anyway ... -- Markus Kuhn
*/
- prep_cmos_clock_write(save_control, RTC_CONTROL);
- prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
- if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
- time_state = TIME_OK;
return 0;
}
__prep
-unsigned long prep_get_rtc_time(void)
+unsigned long mc146818_get_rtc_time(void)
{
unsigned int year, mon, day, hour, min, sec;
int i;
@@ -151,29 +107,123 @@ unsigned long prep_get_rtc_time(void)
*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
- if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
break;
for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
- if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = prep_cmos_clock_read(RTC_SECONDS);
- min = prep_cmos_clock_read(RTC_MINUTES);
- hour = prep_cmos_clock_read(RTC_HOURS);
- day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
- mon = prep_cmos_clock_read(RTC_MONTH);
- year = prep_cmos_clock_read(RTC_YEAR);
- } while (sec != prep_cmos_clock_read(RTC_SECONDS));
- if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- {
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- }
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+ || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
if ((year += 1900) < 1970)
year += 100;
return mktime(year, mon, day, hour, min, sec);
}
+
+__prep
+int mk48t59_set_rtc_time(unsigned long nowtime)
+{
+ unsigned char save_control;
+ struct rtc_time tm;
+
+
+ to_tm(nowtime, &tm);
+
+ /* tell the clock it's being written */
+ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+ (save_control | MK48T59_RTC_CA_WRITE));
+
+ tm.tm_year = (tm.tm_year - 1900) % 100;
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+
+ ppc_md.nvram_write_val(MK48T59_RTC_SECONDS, tm.tm_sec);
+ ppc_md.nvram_write_val(MK48T59_RTC_MINUTES, tm.tm_min);
+ ppc_md.nvram_write_val(MK48T59_RTC_HOURS, tm.tm_hour);
+ ppc_md.nvram_write_val(MK48T59_RTC_MONTH, tm.tm_mon);
+ ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
+ ppc_md.nvram_write_val(MK48T59_RTC_YEAR, tm.tm_year);
+
+ /* Turn off the write bit. */
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+ return 0;
+}
+
+__prep
+unsigned long mk48t59_get_rtc_time(void)
+{
+ unsigned char save_control;
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* Make sure the time is not stopped. */
+ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+ (save_control & (~MK48T59_RTC_CB_STOP)));
+
+ /* Now make sure the read bit is off so the value will change. */
+ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+ save_control &= ~MK48T59_RTC_CA_READ;
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+ /* Read the seconds value to see when it changes. */
+ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+
+ /* Wait until the seconds value changes, then read the value. */
+ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */
+ if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+ break;
+ }
+ }
+
+ /* Set the register to read the value. */
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+ (save_control | MK48T59_RTC_CA_READ));
+
+ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+ min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
+ hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
+ day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
+ mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
+ year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
+
+ /* Let the time values change again. */
+ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+
+ year = year + 1900;
+ if (year < 1970) {
+ year += 100;
+ }
+
+ return mktime(year, mon, day, hour, min, sec);
+}
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index ebe64a429..db87c2384 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -1,5 +1,5 @@
/*
- * $Id: process.c,v 1.70 1999/01/07 16:28:59 cort Exp $
+ * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $
*
* linux/arch/ppc/kernel/process.c
*
@@ -43,12 +43,18 @@
#include <asm/prom.h>
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
-void switch_to(struct task_struct *, struct task_struct *);
-
extern unsigned long _get_SP(void);
-extern spinlock_t scheduler_lock;
struct task_struct *last_task_used_math = NULL;
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM;
+union task_union init_task_union = { INIT_TASK };
+/* only used to get secondary processor up */
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
@@ -65,32 +71,28 @@ task_top(struct task_struct *tsk)
return ((unsigned long)tsk) + sizeof(struct task_struct);
}
-static struct vm_area_struct init_mmap = INIT_MMAP;
-static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
-static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
-
-struct mm_struct init_mm = INIT_MM;
-union task_union init_task_union = { INIT_TASK };
-
-/* only used to get secondary processor up */
-struct task_struct *current_set[NR_CPUS] = {&init_task, };
-
int
dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
return 1;
}
+void
+enable_kernel_fp(void)
+{
+#ifdef __SMP__
+ if (current->tss.regs && (current->tss.regs->msr & MSR_FP))
+ giveup_fpu(current);
+ else
+ giveup_fpu(NULL); /* just enables FP for kernel */
+#else
+ giveup_fpu(last_task_used_math);
+#endif /* __SMP__ */
+}
+
/* check to make sure the kernel stack is healthy */
int check_stack(struct task_struct *tsk)
{
@@ -155,7 +157,8 @@ int check_stack(struct task_struct *tsk)
}
void
-switch_to(struct task_struct *prev, struct task_struct *new)
+_switch_to(struct task_struct *prev, struct task_struct *new,
+ struct task_struct **last)
{
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
@@ -165,10 +168,10 @@ switch_to(struct task_struct *prev, struct task_struct *new)
#endif
#ifdef SHOW_TASK_SWITCHES
- printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n",
+ printk("%s/%d -> %s/%d NIP %08lx cpu %d root %x/%x\n",
prev->comm,prev->pid,
new->comm,new->pid,new->tss.regs->nip,new->processor,
- scheduler_lock.lock,new->fs->root,prev->fs->root);
+ new->fs->root,prev->fs->root);
#endif
#ifdef __SMP__
/* avoid complexity of lazy save/restore of fpu
@@ -176,18 +179,19 @@ switch_to(struct task_struct *prev, struct task_struct *new)
* this task used the fpu during the last quantum.
*
* If it tries to use the fpu again, it'll trap and
- * reload its fp regs.
+ * reload its fp regs. So we don't have to do a restore
+ * every switch, just a save.
* -- Cort
*/
- if ( prev->tss.regs->msr & MSR_FP )
- smp_giveup_fpu(prev);
+ if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP))
+ giveup_fpu(prev);
prev->last_processor = prev->processor;
current_set[smp_processor_id()] = new;
#endif /* __SMP__ */
new_tss = &new->tss;
old_tss = &current->tss;
- _switch(old_tss, new_tss, new->mm->context);
+ *last = _switch(old_tss, new_tss, new->mm->context);
_enable_interrupts(s);
}
@@ -240,7 +244,12 @@ void instruction_dump (unsigned long *pc)
printk("Instruction DUMP:");
for(i = -3; i < 6; i++)
- printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+ {
+ unsigned long p;
+ if (__get_user( p, &pc[i] ))
+ break;
+ printk("%c%08lx%c",i?' ':'<',p,i?' ':'>');
+ }
printk("\n");
}
@@ -268,8 +277,12 @@ int
copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
- struct pt_regs * childregs;
-
+ struct pt_regs * childregs, *kregs;
+#ifdef __SMP__
+ extern void ret_from_smpfork(void);
+#else
+ extern void ret_from_syscall(void);
+#endif
/* Copy registers */
childregs = ((struct pt_regs *)
((unsigned long)p + sizeof(union task_union)
@@ -278,8 +291,19 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
if ((childregs->msr & MSR_PR) == 0)
childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
+ p->tss.regs = childregs;
p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
- p->tss.regs = childregs;
+ p->tss.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
+ kregs = (struct pt_regs *)(p->tss.ksp + STACK_FRAME_OVERHEAD);
+#ifdef __SMP__
+ kregs->nip = (unsigned long)ret_from_smpfork;
+#else
+ kregs->nip = (unsigned long)ret_from_syscall;
+#endif
+ kregs->msr = MSR_KERNEL;
+ kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
+ kregs->gpr[2] = (unsigned long)p;
+
if (usp >= (unsigned long) regs) {
/* Stack is in kernel space - must adjust */
childregs->gpr[1] = (unsigned long)(childregs + 1);
@@ -293,21 +317,14 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
* copy fpu info - assume lazy fpu switch now always
* -- Cort
*/
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if ( last_task_used_math == current )
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
p->tss.fpscr = current->tss.fpscr;
childregs->msr &= ~MSR_FP;
#ifdef __SMP__
- if ( (p->pid != 0) || !(clone_flags & CLONE_PID) )
- p->tss.smp_fork_ret = 1;
p->last_processor = NO_PROC_ID;
#endif /* __SMP__ */
return 0;
@@ -374,11 +391,6 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
int res;
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
- /*
- * only parent returns here, child returns to either
- * syscall_ret_1() or kernel_thread()
- * -- Cort
- */
#ifdef __SMP__
/* When we clone the idle task we keep the same pid but
* the return value of 0 for both causes problems.
@@ -397,9 +409,7 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
int res;
- lock_kernel();
res = do_fork(SIGCHLD, regs->gpr[1], regs);
- /* only parent returns here */
#ifdef __SMP__
/* When we clone the idle task we keep the same pid but
* the return value of 0 for both causes problems.
@@ -408,10 +418,15 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
if ((current->pid == 0) && (current == &init_task))
res = 1;
#endif /* __SMP__ */
- unlock_kernel();
return res;
}
+asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs);
+}
+
asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs *regs)
@@ -423,13 +438,8 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if ( last_task_used_math == current )
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
error = do_execve(filename, (char **) a1, (char **) a2, regs);
putname(filename);
out:
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index da9d7a04c..b2221481a 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -1,5 +1,5 @@
/*
- * $Id: prom.c,v 1.46 1998/11/11 03:55:09 paulus Exp $
+ * $Id: prom.c,v 1.54 1999/05/10 04:43:46 cort Exp $
*
* Procedures for interfacing to the Open Firmware PROM on
* Power Macintosh computers.
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/version.h>
+#include <asm/spinlock.h>
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/processor.h>
@@ -99,10 +100,12 @@ unsigned int old_rtas = 0;
static struct device_node *allnodes = 0;
static void clearscreen(void);
+static void flushscreen(void);
#ifdef CONFIG_BOOTX_TEXT
static void drawchar(char c);
+static void drawhex(unsigned long v);
static void drawstring(const char *c);
static void scrollscreen(void);
@@ -167,6 +170,11 @@ boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */
#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+/* Is boot-info compatible ? */
+#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION)
+#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2)
+#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4)
+
__init
static void
prom_exit()
@@ -256,6 +264,11 @@ __init
void
prom_init(int r3, int r4, prom_entry pp)
{
+#ifdef CONFIG_SMP
+ int cpu = 0, i;
+ phandle node;
+ char type[16], *path;
+#endif
unsigned long mem;
ihandle prom_rtas;
unsigned long offset = reloc_offset();
@@ -273,6 +286,9 @@ prom_init(int r3, int r4, prom_entry pp)
unsigned long space;
unsigned long ptr, x;
char *model;
+#ifdef CONFIG_BOOTX_TEXT
+ unsigned long flags;
+#endif
RELOC(boot_infos) = PTRUNRELOC(bi);
@@ -283,32 +299,72 @@ prom_init(int r3, int r4, prom_entry pp)
RELOC(g_loc_Y) = 0;
RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
- prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE " booting...\n"));
+
+ /* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since
+ there is nothing much we can do with an incompatible version, except display
+ a message and eventually hang the processor...
+
+ I'll try to keep enough of boot-info compatible in the future to always allow
+ display of this message;
+ */
+ if (!BOOT_INFO_IS_COMPATIBLE(bi))
+ prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
+
+ prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
+ prom_print(RELOC("\nstarted at : 0x"));
+ drawhex(reloc_offset() + KERNELBASE);
+ prom_print(RELOC("\nlinked at : 0x"));
+ drawhex(KERNELBASE);
+ prom_print(RELOC("\nframe buffer at : 0x"));
+ drawhex((unsigned long)bi->dispDeviceBase);
+ prom_print(RELOC(" (phys), 0x"));
+ drawhex((unsigned long)bi->logicalDisplayBase);
+ prom_print(RELOC(" (log)"));
+ prom_print(RELOC("\nMSR : 0x"));
+ __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory");
+ drawhex(flags);
+ prom_print(RELOC("\n\n"));
#endif
-
- /*
- * XXX If this is an iMac, turn off the USB controller.
+ /* Out of the #if/#endif since it flushes the clearscreen too */
+ flushscreen();
+
+ /* New BootX enters kernel with MMU off, i/os are not allowed
+ here. This hack will have been done by the boostrap anyway.
*/
- model = (char *) early_get_property
- (r4 + bi->deviceTreeOffset, 4, RELOC("model"));
- if (model && strcmp(model, RELOC("iMac,1")) == 0) {
- out_le32((unsigned *)0x80880008, 1); /* XXX */
+ if (bi->version < 4) {
+ /*
+ * XXX If this is an iMac, turn off the USB controller.
+ */
+ model = (char *) early_get_property
+ (r4 + bi->deviceTreeOffset, 4, RELOC("model"));
+ if (model && strcmp(model, RELOC("iMac,1")) == 0) {
+ out_le32((unsigned *)0x80880008, 1); /* XXX */
+ }
}
-
+
space = bi->deviceTreeOffset + bi->deviceTreeSize;
if (bi->ramDisk)
space = bi->ramDisk + bi->ramDiskSize;
RELOC(klimit) = PTRUNRELOC((char *) bi + space);
- /*
- * Touch each page to make sure the PTEs for them
- * are in the hash table - the aim is to try to avoid
- * getting DSI exceptions while copying the kernel image.
+ /* New BootX will have flushed all TLBs and enters kernel with
+ MMU switched OFF, so this should not be useful anymore.
*/
- for (ptr = (KERNELBASE + offset) & PAGE_MASK;
- ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
- x = *(volatile unsigned long *)ptr;
-
+ if (bi->version < 4) {
+ /*
+ * Touch each page to make sure the PTEs for them
+ * are in the hash table - the aim is to try to avoid
+ * getting DSI exceptions while copying the kernel image.
+ */
+ for (ptr = (KERNELBASE + offset) & PAGE_MASK;
+ ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
+ x = *(volatile unsigned long *)ptr;
+ }
+
+#ifdef CONFIG_BOOTX_TEXT
+ prom_print(RELOC("booting...\n"));
+ flushscreen();
+#endif
return;
}
@@ -379,7 +435,7 @@ prom_init(int r3, int r4, prom_entry pp)
prom_args.nret = 2;
prom_args.args[0] = RELOC("instantiate-rtas");
prom_args.args[1] = prom_rtas;
- prom_args.args[2] = ((void *)RELOC(rtas_data)-KERNELBASE-offset);
+ prom_args.args[2] = ((void *)(RELOC(rtas_data)-KERNELBASE));
RELOC(prom)(&prom_args);
if (prom_args.args[nargs] != 0)
i = 0;
@@ -393,6 +449,81 @@ prom_init(int r3, int r4, prom_entry pp)
prom_print(RELOC(" done\n"));
}
RELOC(klimit) = (char *) (mem - offset);
+#ifdef CONFIG_SMP
+ /*
+ * With CHRP SMP we need to use the OF to start the other
+ * processors so we can't wait until smp_boot_cpus (the OF is
+ * trashed by then) so we have to put the processors into
+ * a holding pattern controlled by the kernel (not OF) before
+ * we destroy the OF.
+ *
+ * This uses a chunk of high memory, puts some holding pattern
+ * code there and sends the other processors off to there until
+ * smp_boot_cpus tells them to do something. We do that by using
+ * physical address 0x0. The holding pattern checks that address
+ * until its cpu # is there, when it is that cpu jumps to
+ * __secondary_start(). smp_boot_cpus() takes care of setting those
+ * values.
+ *
+ * We also use physical address 0x4 here to tell when a cpu
+ * is in its holding pattern code.
+ *
+ * -- Cort
+ */
+ {
+ extern void __secondary_hold(void);
+ unsigned long i;
+ char type[16];
+
+
+ /*
+ * XXX: hack to make sure we're chrp, assume that if we're
+ * chrp we have a device_type property -- Cort
+ */
+ node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
+ if ( (int)call_prom(RELOC("getprop"), 4, 1, node,
+ RELOC("device_type"),type, sizeof(type)) <= 0)
+ return;
+
+ /* copy the holding pattern code to someplace safe (8M) */
+ memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x10000 );
+ for (i = 8<<20; i < ((8<<20)+0x10000); i += 32)
+ {
+ asm volatile("dcbf 0,%0" : : "r" (i) : "memory");
+ asm volatile("icbi 0,%0" : : "r" (i) : "memory");
+ }
+ }
+
+ /* look for cpus */
+ for (node = 0; prom_next_node(&node);)
+ {
+ type[0] = 0;
+ call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+ type, sizeof(type));
+ if (strcmp(type, RELOC("cpu")) != 0)
+ continue;
+ path = (char *) mem;
+ memset(path, 0, 256);
+ if ((int) call_prom(RELOC("package-to-path"), 3, 1,
+ node, path, 255) < 0)
+ continue;
+ /* XXX: hack - don't start cpu 0, this cpu -- Cort */
+ if ( cpu++ == 0 )
+ continue;
+ prom_print(RELOC("starting cpu "));
+ prom_print(path);
+ *(unsigned long *)(0x4) = 0;
+ asm volatile("dcbf 0,%0": : "r" (0x4) : "memory");
+ call_prom(RELOC("start-cpu"), 3, 0, node, 8<<20, cpu-1);
+ for ( i = 0 ; (i < 10000) &&
+ (*(ulong *)(0x4) == (ulong)0); i++ )
+ ;
+ if (*(ulong *)(0x4) == (ulong)cpu-1 )
+ prom_print(RELOC("...ok\n"));
+ else
+ prom_print(RELOC("...failed\n"));
+ }
+#endif
}
/*
@@ -631,6 +762,12 @@ finish_node(struct device_node *np, unsigned long mem_start,
mem_start = ifunc(np, mem_start);
}
+ /* the f50 sets the name to 'display' and 'compatible' to what we
+ * expect for the name -- Cort
+ */
+ if (!strcmp(np->name, "display"))
+ np->name = get_property(np, "compatible", 0);
+
if (!strcmp(np->name, "device-tree"))
ifunc = interpret_root_props;
else if (np->type == 0)
@@ -1007,7 +1144,7 @@ device_is_compatible(struct device_node *device, const char *compat)
if (cp == NULL)
return 0;
while (cplen > 0) {
- if (strcasecmp(cp, compat) == 0)
+ if (strncasecmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
@@ -1143,6 +1280,8 @@ print_properties(struct device_node *np)
}
#endif
+spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED;
+
/* this can be called after setup -- Cort */
__openfirmware
int
@@ -1173,7 +1312,9 @@ call_rtas(const char *service, int nargs, int nret,
for (i = 0; i < nargs; ++i)
u.words[i+3] = va_arg(list, unsigned long);
va_end(list);
+ spin_lock(&rtas_lock);
enter_rtas((void *)__pa(&u));
+ spin_unlock(&rtas_lock);
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret-1; ++i)
outputs[i] = u.words[i+nargs+4];
@@ -1191,8 +1332,11 @@ abort()
prom_exit();
}
-#define CALC_BASE(y) (bi->dispDeviceBase + bi->dispDeviceRect[0] * \
- (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * (y))
+/* Calc the base address of a given point (x,y) */
+#define CALC_BASE(x,y) ((BOOT_INFO_IS_V2_COMPATIBLE(bi) ? bi->logicalDisplayBase : \
+ bi->dispDeviceBase) + (bi->dispDeviceRect[0] + (x)) * \
+ (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * \
+ ((y) + bi->dispDeviceRect[1]))
__init
static void
@@ -1200,7 +1344,7 @@ clearscreen(void)
{
unsigned long offset = reloc_offset();
boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
- unsigned long *base = (unsigned long *)CALC_BASE(0);
+ unsigned long *base = (unsigned long *)CALC_BASE(0,0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
int i,j;
@@ -1214,6 +1358,33 @@ clearscreen(void)
}
}
+__inline__ void dcbst(const void* addr)
+{
+ __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
+}
+
+__init
+static void
+flushscreen(void)
+{
+ unsigned long offset = reloc_offset();
+ boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ unsigned long *base = (unsigned long *)CALC_BASE(0,0);
+ unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+ (bi->dispDeviceDepth >> 3)) >> 2;
+ int i,j;
+
+ for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+ {
+ unsigned long *ptr = base;
+ for(j=width; j>0; j-=8) {
+ dcbst(ptr);
+ ptr += 8;
+ }
+ base += (bi->dispDeviceRowBytes >> 2);
+ }
+}
+
#ifdef CONFIG_BOOTX_TEXT
__init
@@ -1222,8 +1393,8 @@ scrollscreen(void)
{
unsigned long offset = reloc_offset();
boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
- unsigned long *src = (unsigned long *)CALC_BASE(16);
- unsigned long *dst = (unsigned long *)CALC_BASE(0);
+ unsigned long *src = (unsigned long *)CALC_BASE(0,16);
+ unsigned long *dst = (unsigned long *)CALC_BASE(0,0);
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
int i,j;
@@ -1252,20 +1423,17 @@ drawchar(char c)
{
unsigned long offset = reloc_offset();
- switch(c)
- {
- case '\r': RELOC(g_loc_X) = 0; break;
- case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break;
+ switch(c) {
+ case '\r': RELOC(g_loc_X) = 0; break;
+ case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break;
default:
draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
- if (RELOC(g_loc_X) >= RELOC(g_max_loc_X))
- {
+ if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) {
RELOC(g_loc_X) = 0;
RELOC(g_loc_Y)++;
}
}
- while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y))
- {
+ while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) {
scrollscreen();
RELOC(g_loc_Y)--;
}
@@ -1281,17 +1449,32 @@ drawstring(const char *c)
__init
static void
+drawhex(unsigned long v)
+{
+ static char hex_table[] = "0123456789abcdef";
+ unsigned long offset = reloc_offset();
+
+ drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 8) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 4) & 0x0000000FUL]);
+ drawchar(RELOC(hex_table)[(v >> 0) & 0x0000000FUL]);
+}
+
+
+__init
+static void
draw_byte(unsigned char c, long locX, long locY)
{
unsigned long offset = reloc_offset();
- boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
- unsigned char *base = bi->dispDeviceBase
- + (bi->dispDeviceRowBytes * ((locY * 16) + bi->dispDeviceRect[1]))
- + (bi->dispDeviceDepth >> 3) * ((locX * 8) + bi->dispDeviceRect[0]);
- unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16];
+ boot_infos_t* bi = PTRRELOC(RELOC(boot_infos));
+ unsigned char *base = CALC_BASE(locX << 3, locY << 4);
+ unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16];
- switch(bi->dispDeviceDepth)
- {
+ switch(bi->dispDeviceDepth) {
case 32:
draw_byte_32(font, (unsigned long *)base);
break;
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index e2c6b13a0..b3a25fd2b 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -392,14 +392,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
tmp = get_reg(child, addr);
}
else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
-#ifdef __SMP__
- if (child->tss.regs->msr & MSR_FP )
- smp_giveup_fpu(child);
-#else
- /* only current can be last task to use math on SMP */
- if (last_task_used_math == child)
- giveup_fpu();
-#endif
+ if (child->tss.regs->msr & MSR_FP)
+ giveup_fpu(child);
tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
}
else
@@ -433,13 +427,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
}
if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
-#ifndef __SMP__
- if (last_task_used_math == child)
- giveup_fpu();
-#else
- if (child->tss.regs->msr & MSR_FP )
- smp_giveup_fpu(child);
-#endif
+ if (child->tss.regs->msr & MSR_FP)
+ giveup_fpu(child);
((long *)child->tss.fpr)[addr - PT_FPR0] = data;
ret = 0;
goto out;
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 50cd70889..2d38f3adc 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,5 +1,5 @@
/*
- * $Id: setup.c,v 1.122 1998/12/31 20:51:19 cort Exp $
+ * $Id: setup.c,v 1.132 1999/03/24 00:32:19 cort Exp $
* Common prep/pmac/chrp boot and setup code.
*/
@@ -27,40 +27,74 @@
#include <asm/smp.h>
#ifdef CONFIG_MBX
#include <asm/mbx.h>
+#include <asm/8xx_immap.h>
#endif
#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
-/* APUS defs */
-extern unsigned long m68k_machtype;
-extern int parse_bootinfo(const struct bi_record *);
-extern char _end[];
-#ifdef CONFIG_APUS
-extern struct mem_info ramdisk;
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
-#endif
-/* END APUS defs */
+extern void pmac_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void chrp_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void prep_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void mbx_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+
+extern void apus_init(unsigned long r3,
+ unsigned long r4,
+ unsigned long r5,
+ unsigned long r6,
+ unsigned long r7);
+extern boot_infos_t *boot_infos;
extern char cmd_line[512];
char saved_command_line[256];
unsigned char aux_device_present;
-#if !defined(CONFIG_MACH_SPECIFIC)
+struct ide_machdep_calls ppc_ide_md;
+
unsigned long ISA_DMA_THRESHOLD;
unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
-int _machine;
-/* if we have openfirmware */
-unsigned long have_of;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+
+/* Temporary hacks until machdep.h is fully done. */
+int _machine = 0;
+/* do we have OF? */
+int have_of = 0;
+int is_prep = 0;
+int is_chrp = 0;
+/* For MTX/MVME boards.. with Raven/Falcon Chipset
+ Real close to CHRP, but boot like PReP (via PPCbug)
+ There's probably a nicer way to do this.. --Troy */
+int is_powerplus = 0;
+
+struct machdep_calls ppc_md;
+
/* copy of the residual data */
+#ifndef CONFIG_MBX
unsigned char __res[sizeof(RESIDUAL)] __prepdata = {0,};
-RESIDUAL *res = (RESIDUAL *)&__res;
-
-int _prep_type;
+#else
+unsigned char __res[sizeof(bd_t)] = {0,};
+#endif
-extern boot_infos_t *boot_infos;
+RESIDUAL *res = (RESIDUAL *)&__res;
/*
* Perhaps we can put the pmac screen_info[] here
@@ -110,160 +144,28 @@ struct screen_info screen_info = {
};
#endif /* CONFIG_MBX */
-/* cmd is ignored for now... */
void machine_restart(char *cmd)
{
-#ifndef CONFIG_MBX
- struct adb_request req;
- unsigned long flags;
- unsigned long i = 10000;
-#if 0
- int err;
-#endif
-
- switch(_machine)
- {
- case _MACH_Pmac:
- switch (adb_hardware) {
- case ADB_VIACUDA:
- cuda_request(&req, NULL, 2, CUDA_PACKET,
- CUDA_RESET_SYSTEM);
- for (;;)
- cuda_poll();
- break;
- case ADB_VIAPMU:
- pmu_restart();
- break;
- default:
- }
- break;
-
- case _MACH_chrp:
-#if 0 /* RTAS doesn't seem to work on Longtrail.
- For now, do it the same way as the PReP. */
- /*err = call_rtas("system-reboot", 0, 1, NULL);
- printk("RTAS system-reboot returned %d\n", err);
- for (;;);*/
-
- {
- extern unsigned int rtas_entry, rtas_data, rtas_size;
- unsigned long status, value;
- printk("rtas_entry: %08x rtas_data: %08x rtas_size: %08x\n",
- rtas_entry,rtas_data,rtas_size);
- }
-#endif
- case _MACH_prep:
- _disable_interrupts();
-
- /* set exception prefix high - to the prom */
- save_flags( flags );
- restore_flags( flags|MSR_IP );
-
- /* make sure bit 0 (reset) is a 0 */
- outb( inb(0x92) & ~1L , 0x92 );
- /* signal a reset to system control port A - soft reset */
- outb( inb(0x92) | 1 , 0x92 );
-
- while ( i != 0 ) i++;
- panic("restart failed\n");
- break;
- case _MACH_apus:
- cli();
-
- APUS_WRITE(APUS_REG_LOCK,
- REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
- APUS_WRITE(APUS_REG_LOCK,
- REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
- APUS_WRITE(APUS_REG_LOCK,
- REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
- APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
- APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
- for(;;);
- break;
- }
-#else /* CONFIG_MBX */
- extern void MBX_gorom(void);
- MBX_gorom();
-#endif /* CONFIG_MBX */
+ ppc_md.restart(cmd);
}
-
+
void machine_power_off(void)
{
-#ifndef CONFIG_MBX
- struct adb_request req;
-#if 0
- int err;
-#endif
-
- switch (_machine) {
- case _MACH_Pmac:
- switch (adb_hardware) {
- case ADB_VIACUDA:
- cuda_request(&req, NULL, 2, CUDA_PACKET,
- CUDA_POWERDOWN);
- for (;;)
- cuda_poll();
- break;
- case ADB_VIAPMU:
- pmu_shutdown();
- break;
- default:
- }
- break;
-
- case _MACH_chrp:
-#if 0 /* RTAS doesn't seem to work on Longtrail.
- For now, do it the same way as the PReP. */
- err = call_rtas("power-off", 2, 1, NULL, 0, 0);
- printk("RTAS system-reboot returned %d\n", err);
- for (;;);
-#endif
-
- case _MACH_prep:
- machine_restart(NULL);
- case _MACH_apus:
- for (;;);
- }
- for (;;);
-#else /* CONFIG_MBX */
- machine_restart(NULL);
-#endif /* CONFIG_MBX */
+ ppc_md.power_off();
}
-
+
void machine_halt(void)
{
- if ( _machine == _MACH_Pmac )
- {
- machine_power_off();
- }
- else /* prep, chrp or apus */
- machine_restart(NULL);
-
+ ppc_md.halt();
}
-
+
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
{
-#if !defined(CONFIG_MBX) && !defined(CONFIG_APUS)
- switch (_machine) {
-#if defined(CONFIG_BLK_DEV_IDE_PMAC)
- case _MACH_Pmac:
- pmac_ide_init_hwif_ports(p,base,irq);
- break;
-#endif
- case _MACH_chrp:
- chrp_ide_init_hwif_ports(p,base,irq);
- break;
- case _MACH_prep:
- prep_ide_init_hwif_ports(p,base,irq);
- break;
+ if (ppc_ide_md.ide_init_hwif != NULL) {
+ ppc_ide_md.ide_init_hwif(p, base, irq);
}
-#endif
-#if defined(CONFIG_MBX)
- mbx_ide_init_hwif_ports(p,base,irq);
-#endif
}
-EXPORT_SYMBOL(ide_init_hwif_ports);
#endif
unsigned long cpu_temp(void)
@@ -297,10 +199,6 @@ unsigned long cpu_temp(void)
int get_cpuinfo(char *buffer)
{
- extern int pmac_get_cpuinfo(char *);
- extern int chrp_get_cpuinfo(char *);
- extern int prep_get_cpuinfo(char *);
- extern int apus_get_cpuinfo(char *);
unsigned long len = 0;
unsigned long bogosum = 0;
unsigned long i;
@@ -364,7 +262,6 @@ int get_cpuinfo(char *buffer)
break;
}
-#ifndef CONFIG_MBX
/*
* Assume here that all clock rates are the same in a
* smp system. -- Cort
@@ -381,33 +278,11 @@ int get_cpuinfo(char *buffer)
len += sprintf(len+buffer, "clock\t\t: %dMHz\n",
*fp / 1000000);
}
-
- /* PREP's without residual data for some reason will give
- incorrect values here */
- if ( is_prep )
- {
- len += sprintf(len+buffer, "clock\t\t: ");
- if ( res->ResidualLength )
- len += sprintf(len+buffer, "%ldMHz\n",
- (res->VitalProductData.ProcessorHz > 1024) ?
- res->VitalProductData.ProcessorHz>>20 :
- res->VitalProductData.ProcessorHz);
- else
- len += sprintf(len+buffer, "???\n");
- }
-#else /* CONFIG_MBX */
+
+ if (ppc_md.setup_residual != NULL)
{
- bd_t *bp;
- extern RESIDUAL *res;
-
- bp = (bd_t *)res;
-
- len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
- "bus clock\t: %dMHz\n",
- bp->bi_intfreq /*/ 1000000*/,
- bp->bi_busfreq /*/ 1000000*/);
+ len += ppc_md.setup_residual(buffer + len);
}
-#endif /* CONFIG_MBX */
len += sprintf(len+buffer, "revision\t: %ld.%ld\n",
(GET_PVR & 0xff00) >> 8, GET_PVR & 0xff);
@@ -422,8 +297,8 @@ int get_cpuinfo(char *buffer)
if ( i )
len += sprintf(buffer+len, "\n");
len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
- (bogosum+2500)/500000,
- (bogosum+2500)/5000 % 100);
+ (bogosum+2500)/500000,
+ (bogosum+2500)/5000 % 100);
#endif /* __SMP__ */
/*
@@ -432,34 +307,21 @@ int get_cpuinfo(char *buffer)
{
len += sprintf(buffer+len,"zero pages\t: total %lu (%luKb) "
"current: %lu (%luKb) hits: %lu/%lu (%lu%%)\n",
- quicklists.zerototal,
- (quicklists.zerototal*PAGE_SIZE)>>10,
- quicklists.zero_sz,
- (quicklists.zero_sz*PAGE_SIZE)>>10,
- quicklists.zeropage_hits,quicklists.zeropage_calls,
+ zero_cache_total,
+ (zero_cache_total*PAGE_SIZE)>>10,
+ zero_cache_sz,
+ (zero_cache_sz*PAGE_SIZE)>>10,
+ zero_cache_hits,zero_cache_calls,
/* : 1 below is so we don't div by zero */
- (quicklists.zeropage_hits*100) /
- ((quicklists.zeropage_calls)?quicklists.zeropage_calls:1));
+ (zero_cache_hits*100) /
+ ((zero_cache_calls)?zero_cache_calls:1));
}
-#ifndef CONFIG_MBX
- switch (_machine)
+ if (ppc_md.get_cpuinfo != NULL)
{
- case _MACH_Pmac:
- len += pmac_get_cpuinfo(buffer+len);
- break;
- case _MACH_prep:
- len += prep_get_cpuinfo(buffer+len);
- break;
- case _MACH_chrp:
- len += chrp_get_cpuinfo(buffer+len);
- break;
- case _MACH_apus:
- /* Not much point in printing m68k info when it is not
- used. */
- break;
+ len += ppc_md.get_cpuinfo(buffer+len);
}
-#endif /* ndef CONFIG_MBX */
+
return len;
}
@@ -471,25 +333,22 @@ unsigned long __init
identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
- extern void setup_pci_ptrs(void);
#ifdef __SMP__
if ( first_cpu_booted ) return 0;
#endif /* __SMP__ */
-#ifndef CONFIG_MBX
#ifndef CONFIG_MACH_SPECIFIC
/* boot loader will tell us if we're APUS */
if ( r3 == 0x61707573 )
{
_machine = _MACH_apus;
- have_of = 0;
r3 = 0;
}
/* prep boot loader tells us if we're prep or not */
else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) {
_machine = _MACH_prep;
- have_of = 0;
+ is_prep = 1;
} else {
char *model;
@@ -500,19 +359,49 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
/* ask the OF info if we're a chrp or pmac */
model = get_property(find_path_device("/"), "device_type", NULL);
if ( model && !strncmp("chrp",model,4) )
+ {
_machine = _MACH_chrp;
+ is_chrp = 1;
+ }
else
{
model = get_property(find_path_device("/"),
"model", NULL);
if ( model && !strncmp(model, "IBM", 3))
+ {
_machine = _MACH_chrp;
+ is_chrp = 1;
+ }
else
+ {
_machine = _MACH_Pmac;
+ is_prep = 1;
+ }
}
}
-#endif /* CONFIG_MACH_SPECIFIC */
+#else /* CONFIG_MACH_SPECIFIC */
+
+#ifdef CONFIG_PREP
+ _machine = _MACH_prep;
+ is_prep = 1;
+#elif defined(CONFIG_CHRP)
+ _machine = _MACH_chrp;
+ is_chrp = 1;
+ have_of = 1;
+#elif defined(CONFIG_PMAC)
+ _machine = _MACH_Pmac;
+ have_of = 1;
+#elif defined(CONFIG_MBX)
+ _machine = _MACH_mbx;
+#elif defined(CONFIG_FADS)
+ _machine = _MACH_fads;
+#elif defined(CONFIG_APUS)
+ _machine = _MACH_apus;
+#else
+#error "Machine not defined correctly"
+#endif /* CONFIG_APUS */
+#endif /* CONFIG_MACH_SPECIFIC */
if ( have_of )
{
@@ -571,131 +460,31 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
cmd_line[sizeof(cmd_line) - 1] = 0;
}
-
switch (_machine)
{
case _MACH_Pmac:
- setup_pci_ptrs();
- /* isa_io_base gets set in pmac_find_bridges */
- isa_mem_base = PMAC_ISA_MEM_BASE;
- pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = ~0L;
- DMA_MODE_READ = 1;
- DMA_MODE_WRITE = 2;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+ pmac_init(r3, r4, r5, r6, r7);
break;
case _MACH_prep:
- /* make a copy of residual data */
- if ( r3 )
- memcpy((void *)res,(void *)(r3+KERNELBASE),
- sizeof(RESIDUAL));
- setup_pci_ptrs();
- isa_io_base = PREP_ISA_IO_BASE;
- isa_mem_base = PREP_ISA_MEM_BASE;
- pci_dram_offset = PREP_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = 0x00ffffff;
- DMA_MODE_READ = 0x44;
- DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
- /* figure out what kind of prep workstation we are */
- if ( res->ResidualLength != 0 )
- {
- if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
- _prep_type = _PREP_IBM;
- else
- _prep_type = _PREP_Motorola;
- }
- else /* assume motorola if no residual (netboot?) */
- _prep_type = _PREP_Motorola;
-#ifdef CONFIG_BLK_DEV_INITRD
- /* take care of initrd if we have one */
- if ( r4 )
- {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
- /* take care of cmd line */
- if ( r6 )
- {
- *(char *)(r7+KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6+KERNELBASE));
- }
+ prep_init(r3, r4, r5, r6, r7);
break;
case _MACH_chrp:
- setup_pci_ptrs();
-#ifdef CONFIG_BLK_DEV_INITRD
- /* take care of initrd if we have one */
- if ( r3 )
- {
- initrd_start = r3 + KERNELBASE;
- initrd_end = r3 + r4 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
- /* isa_io_base set by setup_pci_ptrs() */
- isa_mem_base = CHRP_ISA_MEM_BASE;
- pci_dram_offset = CHRP_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = ~0L;
- DMA_MODE_READ = 0x44;
- DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+ chrp_init(r3, r4, r5, r6, r7);
break;
-#ifdef CONFIG_APUS
+#ifdef CONFIG_APUS
case _MACH_apus:
- /* Parse bootinfo. The bootinfo is located right after
- the kernel bss */
- parse_bootinfo((const struct bi_record *)&_end);
-#ifdef CONFIG_BLK_DEV_INITRD
- /* Take care of initrd if we have one. Use data from
- bootinfo to avoid the need to initialize PPC
- registers when kernel is booted via a PPC reset. */
- if ( ramdisk.addr ) {
- initrd_start = (unsigned long) __va(ramdisk.addr);
- initrd_end = (unsigned long)
- __va(ramdisk.size + ramdisk.addr);
- }
- /* Make sure code below is not executed. */
- r4 = 0;
- r6 = 0;
-#endif /* CONFIG_BLK_DEV_INITRD */
-#if !defined(CONFIG_MACH_SPECIFIC)
- ISA_DMA_THRESHOLD = 0x00ffffff;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+ apus_init(r3, r4, r5, r6, r7);
break;
#endif
+#ifdef CONFIG_MBX
+ case _MACH_mbx:
+ mbx_init(r3, r4, r5, r6, r7);
+ break;
+#endif
default:
printk("Unknown machine type in identify_machine!\n");
}
-#else /* CONFIG_MBX */
-
- if ( r3 )
- memcpy( (void *)res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-
-#ifdef CONFIG_PCI
- setup_pci_ptrs();
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
- /* take care of initrd if we have one */
- if ( r4 )
- {
- initrd_start = r4 + KERNELBASE;
- initrd_end = r5 + KERNELBASE;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
- /* take care of cmd line */
- if ( r6 )
- {
-
- *(char *)(r7+KERNELBASE) = 0;
- strcpy(cmd_line, (char *)(r6+KERNELBASE));
- }
-#endif /* CONFIG_MBX */
-
/* Check for nobats option (used in mapin_ram). */
if (strstr(cmd_line, "nobats")) {
extern int __map_without_bats;
@@ -717,14 +506,17 @@ void ppc_setup_l2cr(char *str, int *ints)
}
}
+__initfunc(void
+ ppc_init(void))
+{
+ if (ppc_md.init != NULL) {
+ ppc_md.init();
+ }
+}
+
__initfunc(void setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p))
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
{
- extern void pmac_setup_arch(unsigned long *, unsigned long *);
- extern void chrp_setup_arch(unsigned long *, unsigned long *);
- extern void prep_setup_arch(unsigned long *, unsigned long *);
- extern void mbx_setup_arch(unsigned long *, unsigned long *);
- extern void apus_setup_arch(unsigned long *, unsigned long *);
extern int panic_timeout;
extern char _etext[], _edata[];
extern char *klimit;
@@ -737,7 +529,7 @@ __initfunc(void setup_arch(char **cmdline_p,
if (strstr(cmd_line, "xmon"))
xmon(0);
#endif /* CONFIG_XMON */
-
+
/* reboot on panic */
panic_timeout = 180;
@@ -753,27 +545,113 @@ __initfunc(void setup_arch(char **cmdline_p,
*memory_start_p = find_available_memory();
*memory_end_p = (unsigned long) end_of_DRAM;
-#ifdef CONFIG_MBX
- mbx_setup_arch(memory_start_p,memory_end_p);
-#else /* CONFIG_MBX */
- switch (_machine) {
- case _MACH_Pmac:
- pmac_setup_arch(memory_start_p, memory_end_p);
- break;
- case _MACH_prep:
- prep_setup_arch(memory_start_p, memory_end_p);
- break;
- case _MACH_chrp:
- chrp_setup_arch(memory_start_p, memory_end_p);
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- m68k_machtype = MACH_AMIGA;
- apus_setup_arch(memory_start_p,memory_end_p);
- break;
-#endif
- default:
- printk("Unknown machine %d in setup_arch()\n", _machine);
- }
-#endif /* CONFIG_MBX */
+ ppc_md.setup_arch(memory_start_p, memory_end_p);
+}
+
+void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
+{
+ int i;
+ unsigned short *stringcast;
+
+
+ id->config = __le16_to_cpu(id->config);
+ id->cyls = __le16_to_cpu(id->cyls);
+ id->reserved2 = __le16_to_cpu(id->reserved2);
+ id->heads = __le16_to_cpu(id->heads);
+ id->track_bytes = __le16_to_cpu(id->track_bytes);
+ id->sector_bytes = __le16_to_cpu(id->sector_bytes);
+ id->sectors = __le16_to_cpu(id->sectors);
+ id->vendor0 = __le16_to_cpu(id->vendor0);
+ id->vendor1 = __le16_to_cpu(id->vendor1);
+ id->vendor2 = __le16_to_cpu(id->vendor2);
+ stringcast = (unsigned short *)&id->serial_no[0];
+ for (i=0; i<(20/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->buf_type = __le16_to_cpu(id->buf_type);
+ id->buf_size = __le16_to_cpu(id->buf_size);
+ id->ecc_bytes = __le16_to_cpu(id->ecc_bytes);
+ stringcast = (unsigned short *)&id->fw_rev[0];
+ for (i=0; i<(8/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ stringcast = (unsigned short *)&id->model[0];
+ for (i=0; i<(40/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->dword_io = __le16_to_cpu(id->dword_io);
+ id->reserved50 = __le16_to_cpu(id->reserved50);
+ id->field_valid = __le16_to_cpu(id->field_valid);
+ id->cur_cyls = __le16_to_cpu(id->cur_cyls);
+ id->cur_heads = __le16_to_cpu(id->cur_heads);
+ id->cur_sectors = __le16_to_cpu(id->cur_sectors);
+ id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0);
+ id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1);
+ id->lba_capacity = __le32_to_cpu(id->lba_capacity);
+ id->dma_1word = __le16_to_cpu(id->dma_1word);
+ id->dma_mword = __le16_to_cpu(id->dma_mword);
+ id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+ id->eide_dma_min = __le16_to_cpu(id->eide_dma_min);
+ id->eide_dma_time = __le16_to_cpu(id->eide_dma_time);
+ id->eide_pio = __le16_to_cpu(id->eide_pio);
+ id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+ id->word69 = __le16_to_cpu(id->word69);
+ id->word70 = __le16_to_cpu(id->word70);
+ id->word71 = __le16_to_cpu(id->word71);
+ id->word72 = __le16_to_cpu(id->word72);
+ id->word73 = __le16_to_cpu(id->word73);
+ id->word74 = __le16_to_cpu(id->word74);
+ id->word75 = __le16_to_cpu(id->word75);
+ id->word76 = __le16_to_cpu(id->word76);
+ id->word77 = __le16_to_cpu(id->word77);
+ id->word78 = __le16_to_cpu(id->word78);
+ id->word79 = __le16_to_cpu(id->word79);
+ id->word80 = __le16_to_cpu(id->word80);
+ id->word81 = __le16_to_cpu(id->word81);
+ id->command_sets = __le16_to_cpu(id->command_sets);
+ id->word83 = __le16_to_cpu(id->word83);
+ id->word84 = __le16_to_cpu(id->word84);
+ id->word85 = __le16_to_cpu(id->word85);
+ id->word86 = __le16_to_cpu(id->word86);
+ id->word87 = __le16_to_cpu(id->word87);
+ id->dma_ultra = __le16_to_cpu(id->dma_ultra);
+ id->word89 = __le16_to_cpu(id->word89);
+ id->word90 = __le16_to_cpu(id->word90);
+ id->word91 = __le16_to_cpu(id->word91);
+ id->word92 = __le16_to_cpu(id->word92);
+ id->word93 = __le16_to_cpu(id->word93);
+ id->word94 = __le16_to_cpu(id->word94);
+ id->word95 = __le16_to_cpu(id->word95);
+ id->word96 = __le16_to_cpu(id->word96);
+ id->word97 = __le16_to_cpu(id->word97);
+ id->word98 = __le16_to_cpu(id->word98);
+ id->word99 = __le16_to_cpu(id->word99);
+ id->word100 = __le16_to_cpu(id->word100);
+ id->word101 = __le16_to_cpu(id->word101);
+ id->word102 = __le16_to_cpu(id->word102);
+ id->word103 = __le16_to_cpu(id->word103);
+ id->word104 = __le16_to_cpu(id->word104);
+ id->word105 = __le16_to_cpu(id->word105);
+ id->word106 = __le16_to_cpu(id->word106);
+ id->word107 = __le16_to_cpu(id->word107);
+ id->word108 = __le16_to_cpu(id->word108);
+ id->word109 = __le16_to_cpu(id->word109);
+ id->word110 = __le16_to_cpu(id->word110);
+ id->word111 = __le16_to_cpu(id->word111);
+ id->word112 = __le16_to_cpu(id->word112);
+ id->word113 = __le16_to_cpu(id->word113);
+ id->word114 = __le16_to_cpu(id->word114);
+ id->word115 = __le16_to_cpu(id->word115);
+ id->word116 = __le16_to_cpu(id->word116);
+ id->word117 = __le16_to_cpu(id->word117);
+ id->word118 = __le16_to_cpu(id->word118);
+ id->word119 = __le16_to_cpu(id->word119);
+ id->word120 = __le16_to_cpu(id->word120);
+ id->word121 = __le16_to_cpu(id->word121);
+ id->word122 = __le16_to_cpu(id->word122);
+ id->word123 = __le16_to_cpu(id->word123);
+ id->word124 = __le16_to_cpu(id->word124);
+ id->word125 = __le16_to_cpu(id->word125);
+ id->word126 = __le16_to_cpu(id->word126);
+ id->word127 = __le16_to_cpu(id->word127);
+ id->security = __le16_to_cpu(id->security);
+ for (i=0; i<127; i++)
+ id->reserved[i] = __le16_to_cpu(id->reserved[i]);
}
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 3ffb7981e..17c0f55d1 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -1,7 +1,7 @@
/*
* linux/arch/ppc/kernel/signal.c
*
- * $Id: signal.c,v 1.21 1998/10/22 19:37:49 paulus Exp $
+ * $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -218,13 +218,8 @@ int sys_sigreturn(struct pt_regs *regs)
if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
/* Last stacked signal - restore registers */
sr = (struct sigregs *) sigctx.regs;
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP )
+ giveup_fpu(current);
if (copy_from_user(saved_regs, &sr->gp_regs,
sizeof(sr->gp_regs)))
goto badframe;
@@ -271,13 +266,8 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame,
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto badframe;
-#ifdef __SMP__
- if ( regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
|| __copy_to_user(&frame->fp_regs, current->tss.fpr,
ELF_NFPREG * sizeof(double))
@@ -374,7 +364,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (!oldset)
oldset = &current->blocked;
- newsp = frame = regs->gpr[1] - sizeof(struct sigregs);
+ newsp = frame = 0;
for (;;) {
unsigned long signr;
@@ -471,6 +461,13 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
}
}
+ if ( (ka->sa.sa_flags & SA_ONSTACK)
+ && (! on_sig_stack(regs->gpr[1])))
+ newsp = (current->sas_ss_sp + current->sas_ss_size);
+ else
+ newsp = regs->gpr[1];
+ newsp = frame = newsp - sizeof(struct sigregs);
+
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
}
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index ba505e133..c38fc3108 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -1,10 +1,13 @@
/*
- * $Id: smp.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
+ * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $
*
* Smp support for ppc.
*
* Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
* deal of code from the sparc and intel versions.
+ *
+ * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
+ * (troy@microux.com, hozer@drgw.net)
*/
#include <linux/kernel.h>
@@ -18,6 +21,7 @@
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <linux/init.h>
+#include <linux/openpic.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
@@ -29,9 +33,10 @@
#include <asm/softirq.h>
#include <asm/init.h>
#include <asm/io.h>
+#include <asm/prom.h>
#include "time.h"
-
+int first_cpu_booted = 0;
int smp_threads_ready = 0;
volatile int smp_commenced = 0;
int smp_num_cpus = 1;
@@ -42,7 +47,6 @@ volatile unsigned long ipi_count;
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
-int first_cpu_booted = 0;
cycles_t cacheflush_time;
/* all cpu mappings are 1-1 -- Cort */
@@ -51,6 +55,10 @@ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
int start_secondary(void *);
extern int cpu_idle(void *unused);
+u_int openpic_read(volatile u_int *addr);
+
+/* register for interrupting the secondary processor on the powersurge */
+#define PSURGE_INTR ((volatile unsigned *)0xf80000c0)
void smp_local_timer_interrupt(struct pt_regs * regs)
{
@@ -99,29 +107,33 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
/*
* Dirty hack to get smp message passing working.
- * Right now it only works for stop cpu's but will be setup
- * later for more general message passing.
*
* As it is now, if we're sending two message at the same time
- * we have race conditions. I avoided doing locks here since
- * all that works right now is the stop cpu message.
+ * we have race conditions. The PowerSurge doesn't easily
+ * allow us to send IPI messages so we put the messages in
+ * smp_message[].
*
+ * This is because don't have several IPI's on the PowerSurge even though
+ * we do on the chrp. It would be nice to use the actual IPI's on the chrp
+ * rather than this but having two methods of doing IPI isn't a good idea
+ * right now.
* -- Cort
*/
int smp_message[NR_CPUS];
void smp_message_recv(void)
{
int msg = smp_message[smp_processor_id()];
-
- /* clear interrupt */
- *(volatile unsigned long *)(0xf80000c0) = ~0L;
- eieio();
+
+ if ( _machine == _MACH_Pmac )
+ {
+ /* clear interrupt */
+ out_be32(PSURGE_INTR, ~0);
+ }
/* make sure msg is for us */
if ( msg == -1 ) return;
ipi_count++;
- /*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/
switch( msg )
{
@@ -158,12 +170,17 @@ void smp_send_stop(void)
spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED;
void smp_message_pass(int target, int msg, unsigned long data, int wait)
{
- if ( _machine != _MACH_Pmac )
+ int i;
+ if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) )
return;
-printk("SMP %d: sending smp message %x\n", current->processor, msg);
-if (smp_processor_id() ) printk("pass from cpu 1\n");
+
spin_lock(&mesg_pass_lock);
-#define OTHER (~smp_processor_id() & 1)
+
+ /*
+ * We assume here that the msg is not -1. If it is,
+ * the recipient won't know the message was destined
+ * for it. -- Cort
+ */
switch( target )
{
@@ -171,105 +188,180 @@ if (smp_processor_id() ) printk("pass from cpu 1\n");
smp_message[smp_processor_id()] = msg;
/* fall through */
case MSG_ALL_BUT_SELF:
- smp_message[OTHER] = msg;
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ if ( i != smp_processor_id () )
+ smp_message[i] = msg;
break;
default:
smp_message[target] = msg;
break;
}
- /* interrupt secondary processor */
- *(volatile unsigned long *)(0xf80000c0) = ~0L;
- eieio();
- *(volatile unsigned long *)(0xf80000c0) = 0L;
- eieio();
- /* interrupt primary */
- /**(volatile unsigned long *)(0xf3019000);*/
- spin_unlock(&mesg_pass_lock);
+
+ if ( _machine == _MACH_Pmac )
+ {
+ /* interrupt secondary processor */
+ out_be32(PSURGE_INTR, ~0);
+ out_be32(PSURGE_INTR, 0);
+ /*
+ * Assume for now that the secondary doesn't send
+ * IPI's -- Cort
+ */
+ /* interrupt primary */
+ /**(volatile unsigned long *)(0xf3019000);*/
+ }
+
+ if ( _machine == _MACH_chrp )
+ {
+ /*
+ * There has to be some way of doing this better -
+ * perhaps a sent-to-all or send-to-all-but-self
+ * in the openpic. This gets us going for now, though.
+ * -- Cort
+ */
+ switch ( target )
+ {
+ case MSG_ALL:
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ openpic_cause_IPI(i, 0, 0xffffffff );
+ break;
+ case MSG_ALL_BUT_SELF:
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ if ( i != smp_processor_id () )
+ openpic_cause_IPI(i, 0,
+ 0xffffffff & ~(1 << smp_processor_id()));
+ break;
+ default:
+ openpic_cause_IPI(target, 0, 1U << target);
+ break;
+ }
+ }
+
+ spin_unlock(&mesg_pass_lock);
}
void __init smp_boot_cpus(void)
{
extern struct task_struct *current_set[NR_CPUS];
- extern void __secondary_start(void);
+ extern void __secondary_start_psurge(void);
int i;
struct task_struct *p;
unsigned long a;
printk("Entering SMP Mode...\n");
-
+ /* let other processors know to not do certain initialization */
first_cpu_booted = 1;
- /*dcbf(&first_cpu_booted);*/
+
+ /*
+ * assume for now that the first cpu booted is
+ * cpu 0, the master -- Cort
+ */
+ cpu_callin_map[0] = 1;
+ cpu_callin_map[1] = 0;
+ smp_store_cpu_info(0);
+ active_kernel_processor = 0;
+ current->processor = 0;
for (i = 0; i < NR_CPUS; i++) {
prof_counter[i] = 1;
prof_multiplier[i] = 1;
}
- cpu_callin_map[0] = 1;
- smp_store_cpu_info(0);
- active_kernel_processor = 0;
- current->processor = 0;
-
/*
* XXX very rough, assumes 20 bus cycles to read a cache line,
* timebase increments every 4 bus cycles, 32kB L1 data cache.
*/
cacheflush_time = 5 * 1024;
- if ( _machine != _MACH_Pmac )
+ if ( !(_machine & (_MACH_Pmac|_MACH_chrp)) )
{
printk("SMP not supported on this machine.\n");
return;
}
- /* create a process for second processor */
- kernel_thread(start_secondary, NULL, CLONE_PID);
- p = task[1];
- if ( !p )
- panic("No idle task for secondary processor\n");
- p->processor = 1;
- p->has_cpu = 1;
- current_set[1] = p;
-
- /* need to flush here since secondary bat's aren't setup */
- /* XXX ??? */
- for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
- asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
- asm volatile("sync");
-
- /*dcbf((void *)&current_set[1]);*/
- /* setup entry point of secondary processor */
- *(volatile unsigned long *)(0xf2800000) =
- (unsigned long)__secondary_start-KERNELBASE;
- eieio();
- /* interrupt secondary to begin executing code */
- *(volatile unsigned long *)(0xf80000c0) = ~0L;
- eieio();
- *(volatile unsigned long *)(0xf80000c0) = 0L;
- eieio();
+ switch ( _machine )
+ {
+ case _MACH_Pmac:
+ /* assume powersurge board - 2 processors -- Cort */
+ smp_num_cpus = 2;
+ break;
+ case _MACH_chrp:
+ smp_num_cpus = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
+ & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+ OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1;
+ /* get our processor # - we may not be cpu 0 */
+ printk("SMP %d processors, boot CPU is %d (should be 0)\n",
+ smp_num_cpus,
+ 10/*openpic_read(&OpenPIC->Processor[0]._Who_Am_I)*/);
+ break;
+ }
+
/*
- * wait to see if the secondary made a callin (is actually up).
- * udelay() isn't accurate here since we haven't yet called
- * calibrate_delay() so use this value that I found through
- * experimentation. -- Cort
+ * only check for cpus we know exist. We keep the callin map
+ * with cpus at the bottom -- Cort
*/
- for ( i = 1000; i && !cpu_callin_map[1] ; i-- )
- udelay(100);
+ for ( i = 1 ; i < smp_num_cpus; i++ )
+ {
+ int c;
+
+ /* create a process for the processor */
+ kernel_thread(start_secondary, NULL, CLONE_PID);
+ p = task[i];
+ if ( !p )
+ panic("No idle task for secondary processor\n");
+ p->processor = i;
+ p->has_cpu = 1;
+ current_set[i] = p;
+
+ /* need to flush here since secondary bats aren't setup */
+ for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+ asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+ asm volatile("sync");
+
+ /* wake up cpus */
+ switch ( _machine )
+ {
+ case _MACH_Pmac:
+ /* setup entry point of secondary processor */
+ *(volatile unsigned long *)(0xf2800000) =
+ (unsigned long)__secondary_start_psurge-KERNELBASE;
+ eieio();
+ /* interrupt secondary to begin executing code */
+ out_be32(PSURGE_INTR, ~0);
+ out_be32(PSURGE_INTR, 0);
+ break;
+ case _MACH_chrp:
+ *(unsigned long *)KERNELBASE = i;
+ asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+ break;
+ }
+
+ /*
+ * wait to see if the cpu made a callin (is actually up).
+ * use this value that I found through experimentation.
+ * -- Cort
+ */
+ for ( c = 1000; c && !cpu_callin_map[i] ; c-- )
+ udelay(100);
+
+ if ( cpu_callin_map[i] )
+ {
+ printk("Processor %d found.\n", i);
+ /* this sync's the decr's -- Cort */
+ if ( _machine == _MACH_Pmac )
+ set_dec(decrementer_count);
+ } else {
+ printk("Processor %d is stuck.\n", i);
+ }
+ }
- if(cpu_callin_map[1]) {
- printk("Processor %d found.\n", smp_num_cpus);
- smp_num_cpus++;
-#if 1 /* this sync's the decr's, but we don't want this now -- Cort */
- set_dec(decrementer_count);
-#endif
- } else {
- printk("Processor %d is stuck. \n", smp_num_cpus);
+ if ( _machine == _MACH_Pmac )
+ {
+ /* reset the entry point so if we get another intr we won't
+ * try to startup again */
+ *(volatile unsigned long *)(0xf2800000) = 0x100;
+ /* send interrupt to other processors to start decr's on all cpus */
+ smp_message_pass(1,0xf0f0, 0, 0);
}
- /* reset the entry point so if we get another intr we won't
- * try to startup again */
- *(volatile unsigned long *)(0xf2800000) = 0x100;
- /* send interrupt to other processors to start decr's on all cpus */
- smp_message_pass(1,0xf0f0, 0, 0);
}
void __init smp_commence(void)
@@ -308,7 +400,6 @@ void __init smp_callin(void)
while(!smp_commenced)
barrier();
__sti();
- printk("SMP %d: smp_callin done\n", current->processor);
}
void __init smp_setup(char *str, int *ints)
diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c
index ae44266f7..b90760d7e 100644
--- a/arch/ppc/kernel/softemu8xx.c
+++ b/arch/ppc/kernel/softemu8xx.c
@@ -38,6 +38,7 @@
#define LFDU 51
#define STFD 54
#define STFDU 55
+#define FMR 63
/*
* We return 0 on success, 1 on unimplemented instruction, and EFAULT
@@ -49,6 +50,7 @@ Soft_emulate_8xx(struct pt_regs *regs)
uint inst, instword;
uint flreg, idxreg, disp;
uint retval;
+ signed short sdisp;
uint *ea, *ip;
retval = 0;
@@ -66,6 +68,11 @@ Soft_emulate_8xx(struct pt_regs *regs)
switch ( inst )
{
case LFD:
+ /* this is a 16 bit quantity that is sign extended
+ * so use a signed short here -- Cort
+ */
+ sdisp = (instword & 0xffff);
+ ea = (uint *)(regs->gpr[idxreg] + sdisp);
if (copy_from_user(ip, ea, sizeof(double)))
retval = EFAULT;
break;
@@ -77,6 +84,11 @@ Soft_emulate_8xx(struct pt_regs *regs)
regs->gpr[idxreg] = (uint)ea;
break;
case STFD:
+ /* this is a 16 bit quantity that is sign extended
+ * so use a signed short here -- Cort
+ */
+ sdisp = (instword & 0xffff);
+ ea = (uint *)(regs->gpr[idxreg] + sdisp);
if (copy_to_user(ea, ip, sizeof(double)))
retval = EFAULT;
break;
@@ -87,6 +99,11 @@ Soft_emulate_8xx(struct pt_regs *regs)
else
regs->gpr[idxreg] = (uint)ea;
break;
+ case FMR:
+ /* assume this is a fp move -- Cort */
+ memcpy( ip, &current->tss.fpr[(instword>>11)&0x1f],
+ sizeof(double) );
+ break;
default:
retval = 1;
printk("Bad emulation %s/%d\n"
@@ -98,7 +115,7 @@ Soft_emulate_8xx(struct pt_regs *regs)
(instword>>16)&0x1f,
(instword>>11)&0x1f,
(instword>>6)&0x1f,
- (instword>>1)&0x1f,
+ (instword>>1)&0x3ff,
instword&1);
{
int pa;
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index b97456226..4d96a6f0a 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -205,12 +205,15 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ file = fget(fd);
+ if (!file)
goto out;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
ret = do_mmap(file, addr, len, prot, flags, offset);
+ if (file)
+ fput(file);
out:
unlock_kernel();
return ret;
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 32f60a236..6f0eb798b 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -1,5 +1,5 @@
/*
- * $Id: time.c,v 1.39 1998/12/28 10:28:51 paulus Exp $
+ * $Id: time.c,v 1.47 1999/03/18 05:11:11 cort Exp $
* Common time routines among all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -18,8 +18,8 @@
* Since it is not possible to get a nice 100 Hz clock out of this, without
* creating a software PLL, I have set HZ to 128. -- Dan
*
- * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
- * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h>
@@ -41,18 +41,14 @@
#include <asm/processor.h>
#include <asm/nvram.h>
#include <asm/cache.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
+/* Fixme - Why is this here? - Corey */
#ifdef CONFIG_8xx
#include <asm/8xx_immap.h>
#endif
+#include <asm/machdep.h>
#include "time.h"
-/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
-int (*set_rtc_time)(unsigned long);
-
void smp_local_timer_interrupt(struct pt_regs *);
/* keep track of when we need to update the rtc */
@@ -76,9 +72,6 @@ void timer_interrupt(struct pt_regs * regs)
{
int dval, d;
unsigned long cpu = smp_processor_id();
- /* save the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- unsigned dcache_locked = unlock_dcache();
hardirq_enter(cpu);
#ifdef __SMP__
@@ -119,16 +112,21 @@ void timer_interrupt(struct pt_regs * regs)
*/
if ( xtime.tv_sec > last_rtc_update + 660 )
{
- if (set_rtc_time(xtime.tv_sec) == 0)
+ if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) {
last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+ else {
+ /* do it again in 60 s */
+ last_rtc_update = xtime.tv_sec - 60;
+ }
}
}
}
#ifdef __SMP__
smp_local_timer_interrupt(regs);
#endif
+
+ /* Fixme - make this more generic - Corey */
#ifdef CONFIG_APUS
{
extern void apus_heartbeat (void);
@@ -136,33 +134,8 @@ void timer_interrupt(struct pt_regs * regs)
}
#endif
hardirq_exit(cpu);
- /* restore the HID0 in case dcache was off - see idle.c
- * this hack should leave for a better solution -- Cort */
- lock_dcache(dcache_locked);
}
-#ifdef CONFIG_MBX
-/* A place holder for time base interrupts, if they are ever enabled.
-*/
-void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
- printk("timebase_interrupt()\n");
-}
-
-/* The RTC on the MPC8xx is an internal register.
- * We want to protect this during power down, so we need to unlock,
- * modify, and re-lock.
- */
-static int
-mbx_set_rtc_time(unsigned long time)
-{
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
- ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
- return(0);
-}
-#endif /* CONFIG_MBX */
-
/*
* This version of gettimeofday has microsecond resolution.
*/
@@ -198,9 +171,9 @@ void do_settimeofday(struct timeval *tv)
xtime.tv_sec = tv->tv_sec;
xtime.tv_usec = tv->tv_usec - frac_tick;
set_dec(frac_tick * count_period_den / count_period_num);
- time_adjust = 0; /* stop active adjtime() */
+ time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
+ time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
restore_flags(flags);
@@ -209,81 +182,23 @@ void do_settimeofday(struct timeval *tv)
__initfunc(void time_init(void))
{
-#ifndef CONFIG_MBX
+ if (ppc_md.time_init != NULL)
+ {
+ ppc_md.time_init();
+ }
+
if ((_get_PVR() >> 16) == 1) {
/* 601 processor: dec counts down by 128 every 128ns */
decrementer_count = DECREMENTER_COUNT_601;
count_period_num = COUNT_PERIOD_NUM_601;
count_period_den = COUNT_PERIOD_DEN_601;
+ } else if (!smp_processor_id()) {
+ ppc_md.calibrate_decr();
}
- switch (_machine) {
- case _MACH_Pmac:
- xtime.tv_sec = pmac_get_rtc_time();
- if ( (_get_PVR() >> 16) != 1 && (!smp_processor_id()) )
- pmac_calibrate_decr();
- if ( !smp_processor_id() )
- set_rtc_time = pmac_set_rtc_time;
- break;
- case _MACH_chrp:
- chrp_time_init();
- xtime.tv_sec = chrp_get_rtc_time();
- if ((_get_PVR() >> 16) != 1)
- chrp_calibrate_decr();
- set_rtc_time = chrp_set_rtc_time;
- break;
- case _MACH_prep:
- xtime.tv_sec = prep_get_rtc_time();
- prep_calibrate_decr();
- set_rtc_time = prep_set_rtc_time;
- break;
-#ifdef CONFIG_APUS
- case _MACH_apus:
- {
- xtime.tv_sec = apus_get_rtc_time();
- apus_calibrate_decr();
- set_rtc_time = apus_set_rtc_time;
- break;
- }
-#endif
- }
- xtime.tv_usec = 0;
-#else /* CONFIG_MBX */
- mbx_calibrate_decr();
- set_rtc_time = mbx_set_rtc_time;
-
- /* First, unlock all of the registers we are going to modify.
- * To protect them from corruption during power down, registers
- * that are maintained by keep alive power are "locked". To
- * modify these registers we have to write the key value to
- * the key location associated with the register.
- */
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
- ((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
-
+ xtime.tv_sec = ppc_md.get_rtc_time();
+ xtime.tv_usec = 0;
- /* Disable the RTC one second and alarm interrupts.
- */
- ((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
- ~(RTCSC_SIE | RTCSC_ALE);
-
- /* Enabling the decrementer also enables the timebase interrupts
- * (or from the other point of view, to get decrementer interrupts
- * we have to enable the timebase). The decrementer interrupt
- * is wired into the vector table, nothing to do here for that.
- */
- ((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
- ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
- (TBSCR_TBF | TBSCR_TBE));
- if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
- panic("Could not allocate timer IRQ!");
-
- /* Get time from the RTC.
- */
- xtime.tv_sec = ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc;
- xtime.tv_usec = 0;
-
-#endif /* CONFIG_MBX */
set_dec(decrementer_count);
/* mark the rtc/on-chip timer as in sync
* so we don't update right away
@@ -291,109 +206,6 @@ __initfunc(void time_init(void))
last_rtc_update = xtime.tv_sec;
}
-#ifndef CONFIG_MBX
-/*
- * Uses the on-board timer to calibrate the on-chip decrementer register
- * for prep systems. On the pmac the OF tells us what the frequency is
- * but on prep we have to figure it out.
- * -- Cort
- */
-int calibrate_done = 0;
-volatile int *done_ptr = &calibrate_done;
-__initfunc(void prep_calibrate_decr(void))
-{
- unsigned long flags;
-
- /* the Powerstack II's have trouble with the timer so
- * we use a default value -- Cort
- */
- if ( (_prep_type == _PREP_Motorola) &&
- ((inb(0x800) & 0xF0) & 0x40) )
- {
- unsigned long freq, divisor;
- static unsigned long t2 = 0;
-
- t2 = 998700000/60;
- freq = t2 * 60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
- freq, divisor,t2>>20);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
- return;
- }
-
-
- save_flags(flags);
-
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
- /* set timer to periodic mode */
- outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
- /* set the clock to ~100 Hz */
- outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
- outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
-
- if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
- panic("Could not allocate timer IRQ!");
- __sti();
- while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
- restore_flags(flags);
- free_irq( 0, NULL);
-}
-
-__initfunc(void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs))
-{
- unsigned long freq, divisor;
- static unsigned long t1 = 0, t2 = 0;
-
- if ( !t1 )
- t1 = get_dec();
- else if (!t2)
- {
- t2 = get_dec();
- t2 = t1-t2; /* decr's in 1/HZ */
- t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
- freq = t2 * 60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
- freq, divisor,t2>>20);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
- *done_ptr = 1;
- }
-}
-
-#else /* CONFIG_MBX */
-
-/* The decrementer counts at the system (internal) clock frequency divided by
- * sixteen, or external oscillator divided by four. Currently, we only
- * support the MBX, which is system clock divided by sixteen.
- */
-__initfunc(void mbx_calibrate_decr(void))
-{
- bd_t *binfo = (bd_t *)res;
- int freq, fp, divisor;
-
- if ((((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
- printk("WARNING: Wrong decrementer source clock.\n");
-
- /* The manual says the frequency is in Hz, but it is really
- * as MHz. The value 'fp' is the number of decrementer ticks
- * per second.
- */
- fp = (binfo->bi_intfreq * 1000000) / 16;
- freq = fp*60; /* try to make freq/1e6 an integer */
- divisor = 60;
- printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
- decrementer_count = freq / HZ / divisor;
- count_period_num = divisor;
- count_period_den = freq / 1000000;
-}
-#endif /* CONFIG_MBX */
-
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
@@ -439,6 +251,49 @@ static int month_days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
+/*
+ * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
+ */
+void GregorianDay(struct rtc_time * tm)
+{
+ int leapsToDate;
+ int lastYear;
+ int day;
+ int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+ lastYear=tm->tm_year-1;
+
+ /*
+ * Number of leap corrections to apply up to end of last year
+ */
+ leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
+
+ /*
+ * This year is a leap year if it is divisible by 4 except when it is
+ * divisible by 100 unless it is divisible by 400
+ *
+ * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
+ */
+ if((tm->tm_year%4==0) &&
+ ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
+ (tm->tm_mon>2))
+ {
+ /*
+ * We are past Feb. 29 in a leap year
+ */
+ day=1;
+ }
+ else
+ {
+ day=0;
+ }
+
+ day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
+ tm->tm_mday;
+
+ tm->tm_wday=day%7;
+}
+
void to_tm(int tim, struct rtc_time * tm)
{
register int i;
@@ -467,6 +322,11 @@ void to_tm(int tim, struct rtc_time * tm)
/* Days are what is left over (+1) from all that. */
tm->tm_mday = day + 1;
+
+ /*
+ * Determine the day of week
+ */
+ GregorianDay(tm);
}
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
index 64a07250c..a1c912308 100644
--- a/arch/ppc/kernel/time.h
+++ b/arch/ppc/kernel/time.h
@@ -1,5 +1,5 @@
/*
- * $Id: time.h,v 1.10 1998/04/01 07:46:03 geert Exp $
+ * $Id: time.h,v 1.11 1999/03/18 04:16:34 cort Exp $
* Common time prototypes and such for all ppc machines.
*
* Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -9,32 +9,15 @@
#include <linux/mc146818rtc.h>
/* time.c */
-void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
-void prep_calibrate_decr(void);
-void pmac_calibrate_decr(void);
-extern void apus_calibrate_decr(void);
extern unsigned decrementer_count;
extern unsigned count_period_num;
extern unsigned count_period_den;
-extern unsigned long mktime(unsigned int, unsigned int,unsigned int,
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int);
extern void to_tm(int tim, struct rtc_time * tm);
extern unsigned long last_rtc_update;
-/* pmac/prep/chrp_time.c */
-unsigned long prep_get_rtc_time(void);
-unsigned long pmac_get_rtc_time(void);
-unsigned long chrp_get_rtc_time(void);
-unsigned long apus_get_rtc_time(void);
-int prep_set_rtc_time(unsigned long nowtime);
-int pmac_set_rtc_time(unsigned long nowtime);
-int chrp_set_rtc_time(unsigned long nowtime);
-int apus_set_rtc_time(unsigned long nowtime);
-void pmac_read_rtc_time(void);
-void chrp_calibrate_decr(void);
-void chrp_time_init(void);
int via_calibrate_decr(void);
-void mbx_calibrate_decr(void);
/* Accessor functions for the decrementer register. */
static __inline__ unsigned int get_dec(void)
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index fa5184af2..87cc2bd68 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -191,13 +191,8 @@ AlignmentException(struct pt_regs *regs)
{
int fixed;
-#ifdef __SMP__
- if (regs->msr & MSR_FP )
- smp_giveup_fpu(current);
-#else
- if (last_task_used_math == current)
- giveup_fpu();
-#endif
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
fixed = fix_alignment(regs);
if (fixed == 1) {
regs->nip += 4; /* skip over emulated instruction */
diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c
index 2d2a2d8c0..699c13fad 100644
--- a/arch/ppc/lib/locks.c
+++ b/arch/ppc/lib/locks.c
@@ -1,5 +1,5 @@
/*
- * $Id: locks.c,v 1.21 1998/12/28 10:28:53 paulus Exp $
+ * $Id: locks.c,v 1.23 1999/02/12 07:06:32 cort Exp $
*
* Locks for smp ppc
*
@@ -26,24 +26,18 @@ void _spin_lock(spinlock_t *lock)
#ifdef DEBUG_LOCKS
unsigned int stuck = INIT_STUCK;
#endif /* DEBUG_LOCKS */
- /* try expensive atomic load/store to get lock */
- while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) {
- /* try cheap load until it's free */
- while(lock->lock) {
+ while (__spin_trylock(&lock->lock)) {
#ifdef DEBUG_LOCKS
- if(!--stuck)
- {
- printk("_spin_lock(%p) CPU#%d NIP %p"
- " holder: cpu %ld pc %08lX\n",
- lock, cpu, __builtin_return_address(0),
- lock->owner_cpu,lock->owner_pc);
- stuck = INIT_STUCK;
- /* steal the lock */
- /*xchg_u32((void *)&lock->lock,0);*/
- }
-#endif /* DEBUG_LOCKS */
- barrier();
+ if(!--stuck) {
+ printk("_spin_lock(%p) CPU#%d NIP %p"
+ " holder: cpu %ld pc %08lX\n",
+ lock, cpu, __builtin_return_address(0),
+ lock->owner_cpu,lock->owner_pc);
+ stuck = INIT_STUCK;
+ /* steal the lock */
+ /*xchg_u32((void *)&lock->lock,0);*/
}
+#endif /* DEBUG_LOCKS */
}
lock->owner_pc = (unsigned long)__builtin_return_address(0);
lock->owner_cpu = cpu;
@@ -51,15 +45,11 @@ void _spin_lock(spinlock_t *lock)
int spin_trylock(spinlock_t *lock)
{
- unsigned long result;
-
- result = (unsigned long )xchg_u32((void *)&lock->lock,0xffffffff);
- if ( !result )
- {
- lock->owner_cpu = smp_processor_id();
- lock->owner_pc = (unsigned long)__builtin_return_address(0);
- }
- return (result == 0);
+ if (__spin_trylock(&lock->lock))
+ return 0;
+ lock->owner_cpu = smp_processor_id();
+ lock->owner_pc = (unsigned long)__builtin_return_address(0);
+ return 1;
}
@@ -76,11 +66,11 @@ void _spin_unlock(spinlock_t *lp)
lp->owner_pc,lp->lock);
#endif /* DEBUG_LOCKS */
lp->owner_pc = lp->owner_cpu = 0;
- eieio(); /* actually I believe eieio only orders */
- lp->lock = 0; /* non-cacheable accesses (on 604 at least) */
- eieio(); /* - paulus. */
+ wmb();
+ lp->lock = 0;
+ wmb();
}
-
+
/*
* Just like x86, implement read-write locks as a 32-bit counter
* with the high bit (sign) being the "write" bit.
@@ -95,6 +85,7 @@ void _read_lock(rwlock_t *rw)
again:
/* get our read lock in there */
+ wmb();
atomic_inc((atomic_t *) &(rw)->lock);
if ( (signed long)((rw)->lock) < 0) /* someone has a write lock */
{
@@ -114,6 +105,7 @@ again:
/* try to get the read lock again */
goto again;
}
+ wmb();
}
void _read_unlock(rwlock_t *rw)
@@ -124,7 +116,9 @@ void _read_unlock(rwlock_t *rw)
current->comm,current->pid,current->tss.regs->nip,
rw->lock);
#endif /* DEBUG_LOCKS */
+ wmb();
atomic_dec((atomic_t *) &(rw)->lock);
+ wmb();
}
void _write_lock(rwlock_t *rw)
@@ -134,7 +128,8 @@ void _write_lock(rwlock_t *rw)
int cpu = smp_processor_id();
#endif /* DEBUG_LOCKS */
-again:
+again:
+ wmb();
if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
{
while ( (rw)->lock & (1<<31) ) /* wait for write lock */
@@ -170,6 +165,7 @@ again:
}
goto again;
}
+ wmb();
}
void _write_unlock(rwlock_t *rw)
@@ -180,7 +176,9 @@ void _write_unlock(rwlock_t *rw)
current->comm,current->pid,current->tss.regs->nip,
rw->lock);
#endif /* DEBUG_LOCKS */
+ wmb();
clear_bit(31,&(rw)->lock);
+ wmb();
}
void __lock_kernel(struct task_struct *task)
@@ -196,24 +194,18 @@ void __lock_kernel(struct task_struct *task)
}
#endif /* DEBUG_LOCKS */
- if ( atomic_inc_return((atomic_t *) &task->lock_depth) != 1 )
+ if (atomic_inc_return((atomic_t *) &task->lock_depth) != 1)
return;
/* mine! */
- while ( xchg_u32( (void *)&klock_info.kernel_flag, KLOCK_HELD) )
- {
- /* try cheap load until it's free */
- while(klock_info.kernel_flag) {
+ while (__spin_trylock(&klock_info.kernel_flag)) {
#ifdef DEBUG_LOCKS
- if(!--stuck)
- {
- printk("_lock_kernel() CPU#%d NIP %p\n",
- smp_processor_id(),
- __builtin_return_address(0));
- stuck = INIT_STUCK;
- }
-#endif /* DEBUG_LOCKS */
- barrier();
+ if(!--stuck) {
+ printk("_lock_kernel() CPU#%d NIP %p\n",
+ smp_processor_id(),
+ __builtin_return_address(0));
+ stuck = INIT_STUCK;
}
+#endif /* DEBUG_LOCKS */
}
klock_info.akp = smp_processor_id();
@@ -223,7 +215,7 @@ void __lock_kernel(struct task_struct *task)
void __unlock_kernel(struct task_struct *task)
{
#ifdef DEBUG_LOCKS
- if ( (task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD) )
+ if ((task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD))
{
printk("__unlock_kernel(): %s/%d (nip %08lX) "
"lock depth %x flags %lx\n",
@@ -234,10 +226,13 @@ void __unlock_kernel(struct task_struct *task)
return;
}
#endif /* DEBUG_LOCKS */
- if ( atomic_dec_and_test((atomic_t *) &task->lock_depth) )
+ if (atomic_dec_and_test((atomic_t *) &task->lock_depth))
{
+ wmb();
klock_info.akp = NO_PROC_ID;
+ wmb();
klock_info.kernel_flag = KLOCK_CLEAR;
+ wmb();
}
}
@@ -249,5 +244,5 @@ void reacquire_kernel_lock(struct task_struct *task, int cpu,int depth)
__lock_kernel(task);
task->lock_depth = depth;
__sti();
- }
+ }
}
diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
index a9e40bce9..36b521091 100644
--- a/arch/ppc/lib/strcase.c
+++ b/arch/ppc/lib/strcase.c
@@ -10,3 +10,14 @@ int strcasecmp(const char *s1, const char *s2)
} while (c1 == c2 && c1 != 0);
return c1 - c2;
}
+
+int strncasecmp(const char *s1, const char *s2, int n)
+{
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while ((--n > 0) && c1 == c2 && c1 != 0);
+ return c1 - c2;
+}
diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
index 2ff171ee3..be5504940 100644
--- a/arch/ppc/lib/string.S
+++ b/arch/ppc/lib/string.S
@@ -8,7 +8,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include "../kernel/ppc_asm.tmpl"
#include <asm/processor.h>
#include <asm/errno.h>
@@ -321,8 +320,6 @@ __copy_tofrom_user:
.long 75b,76b
.text
-#undef CLEAR_USE_DCBZ 1
-#undef CLEAR_NO_CACHE 1
.globl __clear_user
__clear_user:
addi r6,r3,-4
@@ -333,15 +330,6 @@ __clear_user:
/* clear a single word */
11: stwu r5,4(r6)
beqlr
-#if defined(CLEAR_NO_CACHE) && defined (CONFIG_6xx)
- /*
- * no reason to turn off the cache for a single word
- * or a few bytes -- Cort
- */
- mfspr r7,HID0
- ori r8,r7,HID0_DLOCK
- mtspr HID0,r8
-#endif /* CLEAR_NO_CACHE */
/* clear word sized chunks */
andi. r0,r6,3
add r4,r0,r4
@@ -353,10 +341,6 @@ __clear_user:
1: stwu r5,4(r6)
bdnz 1b
6: andi. r4,r4,3
-#if defined(CLEAR_NO_CACHE) && defined (CONFIG_6xx)
- /* restore the original state of HID0 in case cache was off -- Cort */
- mtspr HID0,r7
-#endif /* CLEAR_NO_CACHE */
/* clear byte sized chunks */
7: cmpwi 0,r4,0
beqlr
@@ -371,9 +355,6 @@ __clear_user:
.align 2
.long 11b,99b
.long 1b,99b
-#ifdef CLEAR_USE_DCBZ
- /*.long 66b,99b*/
-#endif
.long 8b,99b
.text
diff --git a/arch/ppc/mbx_defconfig b/arch/ppc/mbx_defconfig
index 54035b866..ddb420383 100644
--- a/arch/ppc/mbx_defconfig
+++ b/arch/ppc/mbx_defconfig
@@ -14,8 +14,8 @@ CONFIG_8xx=y
# CONFIG_ALL_PPC is not set
# CONFIG_APUS is not set
CONFIG_MBX=y
-CONFIG_SMP=n
CONFIG_MACH_SPECIFIC=y
+# CONFIG_SMP is not set
CONFIG_SERIAL_CONSOLE=y
#
@@ -58,8 +58,26 @@ CONFIG_KERNEL_ELF=y
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_IDE is not set
-# CONFIG_BLK_DEV_HD_ONLY is not set
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_CMD646 is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_IDE_CHIPSETS is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
@@ -75,7 +93,6 @@ CONFIG_PARIDE_PARPORT=y
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -91,7 +108,7 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_RARP is not set
CONFIG_IP_NOSR=y
-# CONFIG_SKB_LARGE is not set
+CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
@@ -103,7 +120,11 @@ CONFIG_IP_NOSR=y
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
-# CONFIG_CPU_IS_SLOW is not set
+CONFIG_CPU_IS_SLOW=y
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
#
@@ -127,6 +148,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_RTL8139 is not set
# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_EISA is not set
# CONFIG_NET_POCKET is not set
@@ -139,6 +161,8 @@ CONFIG_NET_ETHERNET=y
# CONFIG_TR is not set
# CONFIG_SHAPER is not set
# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
#
# Amateur Radio support
@@ -162,7 +186,8 @@ CONFIG_NET_ETHERNET=y
#
# Character devices
#
-# CONFIG_VT is not set
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
CONFIG_SERIAL=y
CONFIG_SERIAL_CONSOLE=y
# CONFIG_SERIAL_EXTENDED is not set
@@ -171,9 +196,17 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_MOUSE is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
# CONFIG_JOYSTICK is not set
#
@@ -185,35 +218,46 @@ CONFIG_SERIAL_CONSOLE=y
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_EXT2_FS is not set
-# CONFIG_ISO9660_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
# CONFIG_NFSD is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MAC_PARTITION is not set
# CONFIG_SMD_DISKLABEL is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_MAC_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_NLS is not set
#
diff --git a/arch/ppc/mbxboot/Makefile b/arch/ppc/mbxboot/Makefile
new file mode 100644
index 000000000..235a79e7a
--- /dev/null
+++ b/arch/ppc/mbxboot/Makefile
@@ -0,0 +1,101 @@
+#
+# arch/ppc/boot/Makefile
+#
+# 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) 1994 by Linus Torvalds
+# Adapted for PowerPC by Gary Thomas
+# modified by Cort (cort@cs.nmt.edu)
+#
+.c.s:
+ $(CC) $(CFLAGS) -S -o $*.s $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
+.S.s:
+ $(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
+.S.o:
+ $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
+
+ZOFF = 0
+ZSZ = 0
+IOFF = 0
+ISZ = 0
+
+TFTPIMAGE=/tftpboot/zImage.mbx
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
+GZIP_FLAGS = -v9
+
+OBJECTS := head.o misc.o ../coffboot/zlib.o mbxtty.o
+CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include -DCONFIG_MBX
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O elf32-powerpc
+
+all: zImage
+
+zvmlinux.initrd: zvmlinux
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+ --add-section=initrd=ramdisk.image.gz \
+ --add-section=image=../coffboot/vmlinux.gz \
+ zvmlinux.initrd.tmp zvmlinux.initrd
+ $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \
+ -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \
+ -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \
+ -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \
+ -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+ --add-section=initrd=ramdisk.image.gz \
+ --add-section=image=../coffboot/vmlinux.gz \
+ zvmlinux.initrd.tmp $@
+ rm zvmlinux.initrd.tmp
+
+zImage: zvmlinux
+ ln -sf zvmlinux zImage
+
+zImage.initrd: zvmlinux.initrd
+ ln -sf zvmlinux.initrd zImage.initrd
+
+zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz
+#
+# build the boot loader image and then compute the offset into it
+# for the kernel image
+#
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
+ zvmlinux.tmp $@
+#
+# then with the offset rebuild the bootloader so we know where the kernel is
+#
+ $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
+ -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \
+ -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
+ -c -o misc.o misc.c
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
+ zvmlinux.tmp $@
+ rm zvmlinux.tmp
+
+znetboot : zImage
+ cp zImage $(TFTPIMAGE)
+
+znetboot.initrd : zImage.initrd
+ cp zImage.initrd $(TFTPIMAGE)
+
+clean:
+ rm -f vmlinux* zvmlinux* zImage*
+
+fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+ $(CPP) -M *.S *.c > .depend
+
+# just here to match coffboot/Makefile
+vmlinux.coff:
+
+vmlinux.coff.initrd:
diff --git a/arch/ppc/mbxboot/head.S b/arch/ppc/mbxboot/head.S
new file mode 100644
index 000000000..a7b3f4ffc
--- /dev/null
+++ b/arch/ppc/mbxboot/head.S
@@ -0,0 +1,200 @@
+#include "../kernel/ppc_defs.h"
+#include "../kernel/ppc_asm.tmpl"
+#include <asm/processor.h>
+#include <asm/cache.h>
+
+ .text
+
+/*
+ * $Id: head.S,v 1.4 1999/04/22 06:32:09 davem Exp $
+ *
+ * This code is loaded by the ROM loader at some arbitrary location.
+ * Move it to high memory so that it can load the kernel at 0x0000.
+ *
+ * The MBX EPPC-Bug understands ELF, so it loads us into the location
+ * specified in the header. This is a two step process. First, EPPC-Bug
+ * loads the file into the intermediate buffer memory location specified
+ * by the environment parameters. When it discovers this is an ELF
+ * binary, it relocates to the link address for us. Unfortunately, the
+ * header does not move with the file, so we have to find the
+ * intermediate load location and read the header from there. From
+ * information provided by Motorola (thank you), we know this intermediate
+ * location can be found from the NVRAM environment.
+ * All of these addresses must be somewhat carefully chosen to make sure
+ * we don't overlap the regions. I chose to load the kernel at 0, the
+ * compressed image loads at 0x00100000, and the MBX intermediate buffer
+ * was set to 0x00200000. Provided the loaded kernel image never grows
+ * over one megabyte (which I am going to ensure never happens :-), these
+ * will work fine. When we get called from EPPC-Bug, registers are:
+ * R1 - Stack pointer at a high memory address.
+ * R3 - Pointer to Board Information Block.
+ * R4 - Pointer to argument string.
+ * Interrupts masked, cache and MMU disabled.
+ */
+
+ .globl start
+start:
+ bl start_
+start_:
+ mr r11,r3 /* Save pointer to residual/board data */
+/* Clear all of BSS */
+ lis r3,edata@h
+ ori r3,r3,edata@l
+ lis r4,end@h
+ ori r4,r4,end@l
+ subi r3,r3,4
+ subi r4,r4,4
+ li r0,0
+50: stwu r0,4(r3)
+ cmp 0,r3,r4
+ bne 50b
+90: mr r9,r1 /* Save old stack pointer (in case it matters) */
+ lis r1,.stack@h
+ ori r1,r1,.stack@l
+ addi r1,r1,4096*2
+ subi r1,r1,256
+ li r2,0x000F /* Mask pointer to 16-byte boundary */
+ andc r1,r1,r2
+/* Run loader */
+ mr r3, r11
+ mr r21, r11
+ bl serial_init /* Init MBX serial port */
+
+ lis r8, 0xfa200000@h /* Disable Ethernet SCC */
+ li r0, 0
+ stw r0, 0x0a00(r8)
+
+ mr r11, r21
+ lis r8,start@h
+ ori r8,r8,start@l
+ lis r9,end@h
+ ori r9,r9,end@l
+ sub r7,r8,r9
+ srwi r7,r7,2
+#define ILAP_ADDRESS 0xfa000020
+ lis r8, ILAP_ADDRESS@h
+ lwz r8, ILAP_ADDRESS@l(r8)
+ addis r8, r8, 1 /* Add 64K */
+ mr r3,r8 /* Load point */
+ mr r4,r7 /* Program length */
+ mr r5,r6 /* Checksum */
+ mr r6,r11 /* Residual data */
+ bl decompress_kernel
+
+ /* changed to use r3 (as firmware does) for kernel
+ as ptr to residual -- Cort*/
+ lis r6,cmd_line@h
+ ori r6,r6,cmd_line@l
+ lwz r6, 0(r6)
+ subi r7,r6,1
+00: lbzu r2,1(r7)
+ cmpi 0,r2,0
+ bne 00b
+
+ /* r4,r5 have initrd_start, size */
+ lis r2,initrd_start@h
+ ori r2,r2,initrd_start@l
+ lwz r4,0(r2)
+ lis r2,initrd_end@h
+ ori r2,r2,initrd_end@l
+ lwz r5,0(r2)
+
+ /* tell kernel we're prep */
+ /*
+ * get start address of kernel code which is stored as a coff
+ * entry. see boot/head.S -- Cort
+ */
+ li r9,0x0
+ lwz r9,0(r9)
+ mtlr r9
+ blr
+hang:
+ b hang
+
+/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 66MHz)
+ */
+ .globl udelay
+udelay:
+ mfspr r4,PVR
+ srwi r4,r4,16
+ cmpi 0,r4,1 /* 601 ? */
+ bne .udelay_not_601
+00: li r0,86 /* Instructions / microsecond? */
+ mtctr r0
+10: addi r0,r0,0 /* NOP */
+ bdnz 10b
+ subic. r3,r3,1
+ bne 00b
+ blr
+
+.udelay_not_601:
+ mulli r4,r3,1000 /* nanoseconds */
+ addi r4,r4,59
+ li r5,60
+ divw r4,r4,r5 /* BUS ticks */
+1: mftbu r5
+ mftb r6
+ mftbu r7
+ cmp 0,r5,r7
+ bne 1b /* Get [synced] base time */
+ addc r9,r6,r4 /* Compute end time */
+ addze r8,r5
+2: mftbu r5
+ cmp 0,r5,r8
+ blt 2b
+ bgt 3f
+ mftb r6
+ cmp 0,r6,r9
+ blt 2b
+3: blr
+
+.globl _get_HID0
+_get_HID0:
+ mfspr r3,HID0
+ blr
+
+.globl _put_HID0
+_put_HID0:
+ mtspr HID0,r3
+ blr
+
+.globl _get_MSR
+_get_MSR:
+ mfmsr r3
+ blr
+
+.globl _put_MSR
+_put_MSR:
+ mtmsr r3
+ blr
+
+/*
+ * Flush instruction cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_instruction_cache)
+ mflr r5
+ bl flush_data_cache
+ mtlr r5
+ blr
+
+#define NUM_CACHE_LINES 128*8
+#define CACHE_LINE_SIZE 32
+#define cache_flush_buffer 0x1000
+
+/*
+ * Flush data cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_data_cache)
+ lis r3,cache_flush_buffer@h
+ ori r3,r3,cache_flush_buffer@l
+ li r4,NUM_CACHE_LINES
+ mtctr r4
+00: lwz r4,0(r3)
+ addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
+ bdnz 00b
+10: blr
+ .comm .stack,4096*2,4
diff --git a/arch/ppc/boot/mbxtty.c b/arch/ppc/mbxboot/mbxtty.c
index e5566dc32..e5566dc32 100644
--- a/arch/ppc/boot/mbxtty.c
+++ b/arch/ppc/mbxboot/mbxtty.c
diff --git a/arch/ppc/mbxboot/misc.c b/arch/ppc/mbxboot/misc.c
new file mode 100644
index 000000000..15bff41dd
--- /dev/null
+++ b/arch/ppc/mbxboot/misc.c
@@ -0,0 +1,637 @@
+/*
+ * misc.c
+ *
+ * $Id: misc.c,v 1.1 1999/02/17 05:00:06 cort Exp $
+ *
+ * Adapted for PowerPC by Gary Thomas
+ *
+ * Rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
+ */
+
+#include <linux/types.h>
+#include "../coffboot/zlib.h"
+#include "asm/residual.h"
+#include <linux/elf.h>
+#include <linux/config.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#ifdef CONFIG_MBX
+#include <asm/mbx.h>
+#endif
+#ifdef CONFIG_FADS
+#include <asm/fads.h>
+#endif
+
+/*
+ * Please send me load/board info and such data for hardware not
+ * listed here so I can keep track since things are getting tricky
+ * with the different load addrs with different firmware. This will
+ * help to avoid breaking the load/boot process.
+ * -- Cort
+ */
+char *avail_ram;
+char *end_avail;
+
+/* Because of the limited amount of memory on the MBX, it presents
+ * loading problems. The biggest is that we load this boot program
+ * into a relatively low memory address, and the Linux kernel Bss often
+ * extends into this space when it get loaded. When the kernel starts
+ * and zeros the BSS space, it also writes over the information we
+ * save here and pass to the kernel (command line and board info).
+ * On the MBX we grab some known memory holes to hold this information.
+ */
+#if defined(CONFIG_SERIAL_CONSOLE)
+char cmd_preset[] = "console=ttyS0,9600n8";
+#else
+char cmd_preset[] = "";
+#endif
+char cmd_buf[256];
+char *cmd_line = cmd_buf;
+
+char *root_string = "root=/dev/nfs";
+char *nfsaddrs_string = "nfsaddrs=";
+char *nfsroot_string = "nfsroot=";
+char *defroot_string = "/sys/mbxroot";
+int do_ipaddrs(char **cmd_cp, int echo);
+void do_nfsroot(char **cmd_cp, char *dp);
+int strncmp(const char * cs,const char * ct,size_t count);
+char *strrchr(const char * s, int c);
+
+RESIDUAL hold_resid_buf;
+RESIDUAL *hold_residual = &hold_resid_buf;
+unsigned long initrd_start = 0, initrd_end = 0;
+char *zimage_start;
+int zimage_size;
+
+char *vidmem = (char *)0xC00B8000;
+int lines, cols;
+int orig_x, orig_y;
+
+void puts(const char *);
+void putc(const char c);
+void puthex(unsigned long val);
+void _bcopy(char *src, char *dst, int len);
+void * memcpy(void * __dest, __const void * __src,
+ int __n);
+void gunzip(void *, int, unsigned char *, int *);
+
+void pause()
+{
+ puts("pause\n");
+}
+
+void exit()
+{
+ puts("exit\n");
+ while(1);
+}
+
+/* The MBX is just the serial port.
+*/
+tstc(void)
+{
+ return (serial_tstc());
+}
+
+getc(void)
+{
+ while (1) {
+ if (serial_tstc()) return (serial_getc());
+ }
+}
+
+void
+putc(const char c)
+{
+ serial_putchar(c);
+}
+
+void puts(const char *s)
+{
+ char c;
+
+ while ( ( c = *s++ ) != '\0' ) {
+ serial_putchar(c);
+ if ( c == '\n' )
+ serial_putchar('\r');
+ }
+}
+
+
+void * memcpy(void * __dest, __const void * __src,
+ int __n)
+{
+ int i;
+ char *d = (char *)__dest, *s = (char *)__src;
+
+ for (i=0;i<__n;i++) d[i] = s[i];
+}
+
+int memcmp(__const void * __dest, __const void * __src,
+ int __n)
+{
+ int i;
+ char *d = (char *)__dest, *s = (char *)__src;
+
+ for (i=0;i<__n;i++, d++, s++)
+ {
+ if (*d != *s)
+ {
+ return (*s - *d);
+ }
+ }
+ return (0);
+}
+
+void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while(1); /* Halt */
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ puts("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ puts("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ puts("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ puts("inflateInit2 returned %d\n");
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ puts("inflate returned %d\n");
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
+
+unsigned char sanity[0x2000];
+
+unsigned long
+decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
+{
+ int timer;
+ extern unsigned long start;
+ char *cp, ch;
+ unsigned long i, motorola_id = 0;
+ char needs_reloc = 0;
+ BATU *u;
+ BATL *l;
+ char *dp;
+
+ lines = 25;
+ cols = 80;
+ orig_x = 0;
+ orig_y = 24;
+
+ /* Grab some space for the command line and board info. Since
+ * we no longer use the ELF header, but it was loaded, grab
+ * that space.
+ */
+ cmd_line = (char *)(load_addr - 0x10000);
+ hold_residual = (RESIDUAL *)(cmd_line + sizeof(cmd_buf));
+ /* copy board data */
+ if (residual)
+ memcpy(hold_residual,residual,sizeof(bd_t));
+
+ /* MBX/prep sometimes put the residual/board info at the end of mem
+ * assume 16M for now -- Cort
+ * To boot on standard MBX boards with 4M, we can't use initrd,
+ * and we have to assume less memory. -- Dan
+ */
+ if ( INITRD_OFFSET )
+ end_avail = (char *)0x01000000;
+ else
+ end_avail = (char *)0x00400000;
+
+ /* let residual data tell us it's higher */
+ if ( (unsigned long)residual > 0x00800000 )
+ end_avail = (char *)PAGE_ALIGN((unsigned long)residual);
+
+ puts("loaded at: "); puthex(load_addr);
+ puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
+ if ( (unsigned long)load_addr != (unsigned long)&start )
+ {
+ puts("relocated to: "); puthex((unsigned long)&start);
+ puts(" ");
+ puthex((unsigned long)((unsigned long)&start + (4*num_words)));
+ puts("\n");
+ }
+
+ if ( residual )
+ {
+ puts("board data at: "); puthex((unsigned long)residual);
+ puts(" ");
+ puthex((unsigned long)((unsigned long)residual + sizeof(bd_t)));
+ puts("\n");
+ puts("relocated to: ");
+ puthex((unsigned long)hold_residual);
+ puts(" ");
+ puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t)));
+ puts("\n");
+ }
+
+ /* we have to subtract 0x10000 here to correct for objdump including the
+ size of the elf header which we strip -- Cort */
+ zimage_start = (char *)(load_addr - 0x10000 + ZIMAGE_OFFSET);
+ zimage_size = ZIMAGE_SIZE;
+
+ if ( INITRD_OFFSET )
+ initrd_start = load_addr - 0x10000 + INITRD_OFFSET;
+ else
+ initrd_start = 0;
+ initrd_end = INITRD_SIZE + initrd_start;
+
+ /*
+ * setup avail_ram - this is the first part of ram usable
+ * by the uncompress code. -- Cort
+ */
+ avail_ram = (char *)PAGE_ALIGN((unsigned long)zimage_start+zimage_size);
+ if ( ((load_addr+(num_words*4)) > (unsigned long) avail_ram)
+ && (load_addr <= 0x01000000) )
+ avail_ram = (char *)(load_addr+(num_words*4));
+ if ( (((unsigned long)&start+(num_words*4)) > (unsigned long) avail_ram)
+ && (load_addr <= 0x01000000) )
+ avail_ram = (char *)((unsigned long)&start+(num_words*4));
+
+ /* relocate zimage */
+ puts("zimage at: "); puthex((unsigned long)zimage_start);
+ puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
+ /*
+ * don't relocate the zimage if it was loaded above 16M since
+ * things get weird if we try to relocate -- Cort
+ * We don't relocate zimage on a base MBX board because of
+ * insufficient memory. In this case we don't have initrd either,
+ * so use that as an indicator. -- Dan
+ */
+
+ /* Determine if we have a Motorola board */
+ needs_reloc = 0;
+ if ( (( (unsigned long)zimage_start <= 0x01000000 ) && initrd_start)
+ || needs_reloc)
+ {
+ memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size),
+ (void *)zimage_start, zimage_size );
+ zimage_start = (char *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size);
+ end_avail = (char *)zimage_start;
+ puts("relocated to: "); puthex((unsigned long)zimage_start);
+ puts(" ");
+ puthex((unsigned long)zimage_size+(unsigned long)zimage_start);
+ puts("\n");
+ }
+
+ /* relocate initrd */
+ if ( initrd_start )
+ {
+ puts("initrd at: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end); puts("\n");
+ /*
+ * Memory is really tight on the MBX (we can assume 4M)
+ * so put the initrd at the TOP of ram, and set end_avail
+ * to right after that.
+ *
+ * I should do something like this for prep, too and keep
+ * a variable end_of_DRAM to keep track of what we think the
+ * max ram is.
+ * -- Cort
+ */
+ if (needs_reloc)
+ {
+ memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+
+ (unsigned long)end_avail-INITRD_SIZE),
+ (void *)initrd_start,
+ INITRD_SIZE );
+ initrd_start = PAGE_ALIGN(-PAGE_SIZE+
+ (unsigned long)end_avail-INITRD_SIZE);
+ initrd_end = initrd_start + INITRD_SIZE;
+ end_avail = (char *)initrd_start;
+ puts("relocated to: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end); puts("\n");
+ }
+ }
+
+ puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" ");
+ puthex((unsigned long)end_avail); puts("\n");
+
+ puts("\nLinux/PPC load: ");
+ timer = 0;
+ cp = cmd_line;
+ memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
+ while ( *cp ) putc(*cp++);
+ while (timer++ < 5*1000) {
+ if (tstc()) {
+ while ((ch = getc()) != '\n' && ch != '\r') {
+ if (ch == '\b') {
+ if (cp != cmd_line) {
+ cp--;
+ puts("\b \b");
+ }
+ } else if (ch == '?') {
+ if (!do_ipaddrs(&cp, 1)) {
+ *cp++ = ch;
+ putc(ch);
+ }
+ } else {
+ *cp++ = ch;
+ putc(ch);
+ }
+ }
+ break; /* Exit 'timer' loop */
+ }
+ udelay(1000); /* 1 msec */
+ }
+ *cp = 0;
+ /* The MBX does not currently have any default boot strategy.
+ * If the command line is not filled in, we will automatically
+ * create the default network boot.
+ */
+ if (cmd_line[0] == 0) {
+ dp = root_string;
+ while (*dp != 0)
+ *cp++ = *dp++;
+ *cp++ = ' ';
+
+ dp = nfsaddrs_string;
+ while (*dp != 0)
+ *cp++ = *dp++;
+ dp = cp;
+ do_ipaddrs(&cp, 0);
+ *cp++ = ' ';
+
+ /* Add the server address to the root file system path.
+ */
+ dp = strrchr(dp, ':');
+ dp++;
+ do_nfsroot(&cp, dp);
+ *cp = 0;
+ }
+ puts("\n");
+
+ /* mappings on early boot can only handle 16M */
+ if ( (int)(cmd_line[0]) > (16<<20))
+ puts("cmd_line located > 16M\n");
+ if ( (int)hold_residual > (16<<20))
+ puts("hold_residual located > 16M\n");
+ if ( initrd_start > (16<<20))
+ puts("initrd_start located > 16M\n");
+
+ puts("Uncompressing Linux...");
+
+ gunzip(0, 0x400000, zimage_start, &zimage_size);
+ puts("done.\n");
+ puts("Now booting the kernel\n");
+ return (unsigned long)hold_residual;
+}
+
+int
+do_ipaddrs(char **cmd_cp, int echo)
+{
+ char *cp, *ip, ch;
+ unsigned char ipd;
+ int i, j, retval;
+
+ /* We need to create the string:
+ * <my_ip>:<serv_ip>
+ */
+ cp = *cmd_cp;
+ retval = 0;
+
+ if ((cp - 9) >= cmd_line) {
+ if (strncmp(cp - 9, "nfsaddrs=", 9) == 0) {
+ ip = (char *)0xfa000060;
+ retval = 1;
+ for (j=0; j<2; j++) {
+ for (i=0; i<4; i++) {
+ ipd = *ip++;
+
+ ch = ipd/100;
+ if (ch) {
+ ch += '0';
+ if (echo)
+ putc(ch);
+ *cp++ = ch;
+ ipd -= 100 * (ch - '0');
+ }
+
+ ch = ipd/10;
+ if (ch) {
+ ch += '0';
+ if (echo)
+ putc(ch);
+ *cp++ = ch;
+ ipd -= 10 * (ch - '0');
+ }
+
+ ch = ipd + '0';
+ if (echo)
+ putc(ch);
+ *cp++ = ch;
+
+ ch = '.';
+ if (echo)
+ putc(ch);
+ *cp++ = ch;
+ }
+
+ /* At the end of the string, remove the
+ * '.' and replace it with a ':'.
+ */
+ *(cp - 1) = ':';
+ if (echo) {
+ putc('\b'); putc(':');
+ }
+ }
+
+ /* At the end of the second string, remove the
+ * '.' from both the command line and the
+ * screen.
+ */
+ --cp;
+ putc('\b'); putc(' '); putc('\b');
+ }
+ }
+ *cmd_cp = cp;
+ return(retval);
+}
+
+void
+do_nfsroot(char **cmd_cp, char *dp)
+{
+ char *cp, *rp, *ep;
+
+ /* The boot argument (i.e /sys/mbxroot/zImage) is stored
+ * at offset 0x0078 in NVRAM. We use this path name to
+ * construct the root file system path.
+ */
+ cp = *cmd_cp;
+
+ /* build command string.
+ */
+ rp = nfsroot_string;
+ while (*rp != 0)
+ *cp++ = *rp++;
+
+ /* Add the server address to the path.
+ */
+ while (*dp != ' ')
+ *cp++ = *dp++;
+ *cp++ = ':';
+
+ rp = (char *)0xfa000078;
+ ep = strrchr(rp, '/');
+
+ if (ep != 0) {
+ while (rp < ep)
+ *cp++ = *rp++;
+ }
+ else {
+ rp = defroot_string;
+ while (*rp != 0)
+ *cp++ = *rp++;
+ }
+
+ *cmd_cp = cp;
+}
+
+size_t strlen(const char * s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
+
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+ register signed char __res = 0;
+
+ while (count) {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ count--;
+ }
+
+ return __res;
+}
+
+char * strrchr(const char * s, int c)
+{
+ const char *p = s + strlen(s);
+ do {
+ if (*p == (char)c)
+ return (char *)p;
+ } while (--p >= s);
+ return NULL;
+}
+
+void puthex(unsigned long val)
+{
+ unsigned char buf[10];
+ int i;
+ for (i = 7; i >= 0; i--)
+ {
+ buf[i] = "0123456789ABCDEF"[val & 0x0F];
+ val >>= 4;
+ }
+ buf[8] = '\0';
+ puts(buf);
+}
+
+/*
+ * PCI/ISA I/O support
+ */
+
+volatile unsigned char *ISA_io = (unsigned char *)0x80000000;
+volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000;
+
+void
+outb(int port, char val)
+{
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ ISA_io[port] = val;
+}
+
+unsigned char
+inb(int port)
+{
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ return (ISA_io[port]);
+}
+
+unsigned long
+local_to_PCI(unsigned long addr)
+{
+ return ((addr & 0x7FFFFFFF) | 0x80000000);
+}
+
+void
+_bcopy(char *src, char *dst, int len)
+{
+ while (len--) *dst++ = *src++;
+}
diff --git a/arch/ppc/mbxboot/offset b/arch/ppc/mbxboot/offset
new file mode 100644
index 000000000..52a1b5546
--- /dev/null
+++ b/arch/ppc/mbxboot/offset
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'`
+echo "0x"$OFFSET
diff --git a/arch/ppc/mbxboot/size b/arch/ppc/mbxboot/size
new file mode 100644
index 000000000..6c48f8d14
--- /dev/null
+++ b/arch/ppc/mbxboot/size
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'`
+echo "0x"$OFFSET
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 42e2918b1..92299e825 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -140,7 +140,8 @@ good_area:
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- handle_mm_fault(current, vma, address, error_code & 0x02000000);
+ if (!handle_mm_fault(current, vma, address, error_code & 0x02000000))
+ goto bad_area;
up(&mm->mmap_sem);
/*
* keep track of tlb+htab misses that are good addrs but
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index b80d4c21c..eac750568 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -1,5 +1,5 @@
/*
- * $Id: init.c,v 1.139 1998/12/29 19:53:49 cort Exp $
+ * $Id: init.c,v 1.164 1999/05/05 17:33:55 cort Exp $
*
* PowerPC version
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -34,6 +34,7 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/openpic.h>
#ifdef CONFIG_BLK_DEV_INITRD
#include <linux/blk.h> /* for initrd_* */
#endif
@@ -70,10 +71,12 @@ struct device_node *memory_node;
unsigned long ioremap_base;
unsigned long ioremap_bot;
unsigned long avail_start;
-struct pgtable_cache_struct quicklists;
extern int num_memory;
extern struct mem_info memory[NUM_MEMINFO];
extern boot_infos_t *boot_infos;
+#ifndef __SMP__
+struct pgtable_cache_struct quicklists;
+#endif
void MMU_init(void);
static void *MMU_get_page(void);
@@ -116,12 +119,19 @@ extern struct task_struct *current_set[NR_CPUS];
PTE *Hash, *Hash_end;
unsigned long Hash_size, Hash_mask;
#ifndef CONFIG_8xx
+#ifdef CONFIG_PPC64
+unsigned long long _SDR1;
+#else
unsigned long _SDR1;
+#endif
static void hash_init(void);
union ubat { /* BAT register values to be loaded */
BAT bat;
- P601_BAT bat_601;
+#ifdef CONFIG_PPC64
+ u64 word[2];
+#else
u32 word[2];
+#endif
} BATS[4][2]; /* 4 pairs of IBAT, DBAT */
struct batrange { /* stores address ranges mapped by BATs */
@@ -129,6 +139,8 @@ struct batrange { /* stores address ranges mapped by BATs */
unsigned long limit;
unsigned long phys;
} bat_addrs[4];
+unsigned long inline v_mapped_by_bats(unsigned long);
+unsigned long inline p_mapped_by_bats(unsigned long);
#endif /* CONFIG_8xx */
/*
@@ -329,15 +341,40 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags)
* virt == phys; for addresses below this we use
* space going down from ioremap_base (ioremap_bot
* records where we're up to).
- *
- * We should also look out for a frame buffer and
- * map it with a free BAT register, if there is one.
*/
p = addr & PAGE_MASK;
size = PAGE_ALIGN(addr + size) - p;
+
+ /*
+ * Don't allow anybody to remap normal RAM that we're using.
+ * mem_init() sets high_memory so only do the check after that.
+ */
+ if ( mem_init_done && (p < virt_to_phys(high_memory)) )
+ {
+ printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p,
+ __builtin_return_address(0));
+ return NULL;
+ }
+
if (size == 0)
return NULL;
+#ifndef CONFIG_8xx
+ /*
+ * Is it already mapped? Perhaps overlapped by a previous
+ * BAT mapping. If the whole area is mapped then we're done,
+ * otherwise remap it since we want to keep the virt addrs for
+ * each request contiguous.
+ *
+ * We make the assumption here that if the bottom and top
+ * of the range we want are mapped then it's mapped to the
+ * same virt address (and this is contiguous).
+ * -- Cort
+ */
+ if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
+ goto out;
+#endif /* CONFIG_8xx */
+
if (mem_init_done) {
struct vm_struct *area;
area = get_vm_area(size);
@@ -355,10 +392,17 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags)
flags |= pgprot_val(PAGE_KERNEL);
if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
flags |= _PAGE_GUARDED;
+
+#ifndef CONFIG_8xx
+ /*
+ * Is it a candidate for a BAT mapping?
+ */
+#endif /* CONFIG_8xx */
+
for (i = 0; i < size; i += PAGE_SIZE)
map_page(&init_task, v+i, p+i, flags);
-
- return (void *) (v + (addr & ~PAGE_MASK));
+out:
+ return (void *) (v + (p & ~PAGE_MASK));
}
void iounmap(void *addr)
@@ -409,9 +453,7 @@ map_page(struct task_struct *tsk, unsigned long va,
{
pmd_t *pd;
pte_t *pg;
-#ifndef CONFIG_8xx
- int b;
-#endif
+
if (tsk->mm->pgd == NULL) {
/* Allocate upper level page map */
tsk->mm->pgd = (pgd_t *) MMU_get_page();
@@ -419,20 +461,8 @@ map_page(struct task_struct *tsk, unsigned long va,
/* Use upper 10 bits of VA to index the first level map */
pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
if (pmd_none(*pd)) {
-#ifndef CONFIG_8xx
- /*
- * Need to allocate second-level table, but first
- * check whether this address is already mapped by
- * the BATs; if so, don't bother allocating the page.
- */
- for (b = 0; b < 4; ++b) {
- if (va >= bat_addrs[b].start
- && va <= bat_addrs[b].limit) {
- /* XXX should check the phys address matches */
- return;
- }
- }
-#endif /* CONFIG_8xx */
+ if ( v_mapped_by_bats(va) )
+ return;
pg = (pte_t *) MMU_get_page();
pmd_val(*pd) = (unsigned long) pg;
}
@@ -677,6 +707,33 @@ static void get_mem_prop(char *, struct mem_pieces *);
static void sort_mem_pieces(struct mem_pieces *);
static void coalesce_mem_pieces(struct mem_pieces *);
+/*
+ * Return 1 if this VA is mapped by BATs
+ */
+unsigned long inline v_mapped_by_bats(unsigned long va)
+{
+ int b;
+ for (b = 0; b < 4; ++b)
+ if (va >= bat_addrs[b].start
+ && va < bat_addrs[b].limit)
+ return 1;
+ return 0;
+}
+
+/*
+ * Return VA for a given PA or 0 if not mapped
+ */
+unsigned long inline p_mapped_by_bats(unsigned long pa)
+{
+ int b;
+ for (b = 0; b < 4; ++b)
+ if (pa >= bat_addrs[b].phys
+ && pa < (bat_addrs[b].limit-bat_addrs[b].start)
+ +bat_addrs[b].phys)
+ return bat_addrs[b].start+(pa-bat_addrs[b].phys);
+ return 0;
+}
+
__initfunc(static void sort_mem_pieces(struct mem_pieces *mp))
{
unsigned long a, s;
@@ -833,7 +890,7 @@ __initfunc(static void mapin_ram(void))
setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE);
done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
- if (done < tot) {
+ if ((done < tot) && !bat_addrs[3].limit) {
/* use BAT3 to cover a bit more */
tot -= done;
for (bl = 128<<10; bl < max_size; bl <<= 1)
@@ -883,7 +940,8 @@ __initfunc(static void mapin_ram(void))
}
}
-__initfunc(static void *MMU_get_page(void))
+/* This can get called from ioremap, so don't make it an initfunc, OK? */
+static void *MMU_get_page(void)
{
void *p;
@@ -926,14 +984,16 @@ __initfunc(void free_initmem(void))
break;
case _MACH_prep:
FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
- FREESEC(__openfirmware_begin,__openfirmware_end,num_openfirmware_pages);
break;
case _MACH_mbx:
FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
- FREESEC(__openfirmware_begin,__openfirmware_end,num_openfirmware_pages);
FREESEC(__prep_begin,__prep_end,num_prep_pages);
break;
}
+
+ if ( !have_of )
+ FREESEC( __openfirmware_begin, __openfirmware_end,
+ num_openfirmware_pages );
printk ("Freeing unused kernel memory: %ldk init",
(num_freed_pages * PAGE_SIZE) >> 10);
@@ -955,7 +1015,6 @@ __initfunc(void free_initmem(void))
*/
__initfunc(void MMU_init(void))
{
-
#ifdef __SMP__
if ( first_cpu_booted ) return;
#endif /* __SMP__ */
@@ -985,10 +1044,13 @@ __initfunc(void MMU_init(void))
switch (_machine) {
case _MACH_prep:
setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
- setbat(1, 0xd0000000, 0xc0000000, 0x10000000, IO_PAGE);
+ setbat(1, 0xf0000000, 0xc0000000, 0x08000000, IO_PAGE);
+ ioremap_base = 0xf0000000;
break;
case _MACH_chrp:
setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE);
+ setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+ setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
break;
case _MACH_Pmac:
{
@@ -1029,6 +1091,7 @@ __initfunc(void MMU_init(void))
ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
/* ide needs to be able to get at PCI space -- Cort */
ioremap(0x80000000, 0x4000);
+ ioremap(0x81000000, 0x4000);
#endif /* CONFIG_8xx */
}
@@ -1236,6 +1299,9 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
unsigned long a, total;
unsigned long kstart, ksize;
int i;
+
+ /* max amount of RAM we allow -- Cort */
+#define RAM_LIMIT (768<<20)
memory_node = find_devices("memory");
if (memory_node == NULL) {
@@ -1260,7 +1326,18 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
a = phys_mem.regions[0].address;
if (a != 0)
panic("RAM doesn't start at physical address 0");
+ /*
+ * XXX:
+ * Make sure ram mappings don't stomp on IO space
+ * This is a temporary hack to keep this from happening
+ * until we move the KERNELBASE and can allocate RAM up
+ * to our nearest IO area.
+ * -- Cort
+ */
+ if ( phys_mem.regions[0].size >= RAM_LIMIT )
+ phys_mem.regions[0].size = RAM_LIMIT;
total = phys_mem.regions[0].size;
+
if (phys_mem.n_regions > 1) {
printk("RAM starting at 0x%x is not contiguous\n",
phys_mem.regions[1].address);
@@ -1277,8 +1354,15 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
}
prom_mem = phys_mem;
for (i = 0; i < phys_avail.n_regions; ++i)
+ {
+ if ( phys_avail.regions[i].address >= RAM_LIMIT )
+ continue;
+ if ( (phys_avail.regions[i].address+phys_avail.regions[i].size)
+ >= RAM_LIMIT )
+ phys_avail.regions[i].size = RAM_LIMIT - phys_avail.regions[i].address;
remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
phys_avail.regions[i].size, 1);
+ }
/*
* phys_avail records memory we can use now.
@@ -1292,7 +1376,7 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void))
remove_mem_piece(&prom_mem, kstart, ksize, 0);
remove_mem_piece(&phys_avail, 0, 0x4000, 0);
remove_mem_piece(&prom_mem, 0, 0x4000, 0);
-
+#undef RAM_LIMIT
return __va(total);
}
@@ -1421,10 +1505,18 @@ __initfunc(static void hash_init(void))
* up to a maximum of 2MB.
*/
ramsize = (ulong)end_of_DRAM - KERNELBASE;
+#ifdef CONFIG_PPC64
+ Hash_mask = 0;
+ for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++)
+ ;
+ Hash_size = h;
+ Hash_mask << 10; /* so setting _SDR1 works the same -- Cort */
+#else
for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
;
Hash_size = h;
Hash_mask = (h >> 6) - 1;
+#endif
#ifdef NO_RELOAD_HTAB
/* shrink the htab since we don't use it on 603's -- Cort */
@@ -1502,4 +1594,3 @@ __initfunc(static void hash_init(void))
}
}
#endif /* ndef CONFIG_8xx */
-
diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig
index 811d599c0..274f6c679 100644
--- a/arch/ppc/pmac_defconfig
+++ b/arch/ppc/pmac_defconfig
@@ -102,7 +102,6 @@ CONFIG_NETLINK=y
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_FIREWALL is not set
-CONFIG_NET_ALIAS=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -263,6 +262,7 @@ CONFIG_PPP=y
# CONFIG_SHAPER is not set
# CONFIG_HOSTESS_SV11 is not set
# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
#
# Amateur Radio support
diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig
index 14b4ea4a0..01c314cb3 100644
--- a/arch/ppc/prep_defconfig
+++ b/arch/ppc/prep_defconfig
@@ -84,7 +84,6 @@ CONFIG_PARIDE_PARPORT=y
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
diff --git a/arch/sparc/boot/piggyback.c b/arch/sparc/boot/piggyback.c
index 21a32932a..b75edb418 100644
--- a/arch/sparc/boot/piggyback.c
+++ b/arch/sparc/boot/piggyback.c
@@ -1,4 +1,4 @@
-/* $Id: piggyback.c,v 1.1 1997/07/18 06:26:14 ralf Exp $
+/* $Id: piggyback.c,v 1.2 1998/12/15 12:24:43 jj Exp $
Simple utility to make a single-image install kernel with initial ramdisk
for Sparc tftpbooting without need to set up nfs.
@@ -46,16 +46,21 @@ int main(int argc,char **argv)
struct stat s;
int image, tail;
+ start = end = 0;
if (stat (argv[3], &s) < 0) die (argv[3]);
map = fopen (argv[2], "r");
if (!map) die(argv[2]);
while (fgets (buffer, 1024, map)) {
- if (!strcmp (buffer + 11, "start\n"))
+ if (!strcmp (buffer + 8, " T start\n") || !strcmp (buffer + 16, " T start\n"))
start = strtoul (buffer, NULL, 16);
- else if (!strcmp (buffer + 11, "end\n"))
+ else if (!strcmp (buffer + 8, " A end\n") || !strcmp (buffer + 16, " A end\n"))
end = strtoul (buffer, NULL, 16);
}
fclose (map);
+ if (!start || !end) {
+ fprintf (stderr, "Could not determine start and end from System.map\n");
+ exit(1);
+ }
if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]);
if (read(image,buffer,512) != 512) die(argv[1]);
if (!memcmp (buffer, "\177ELF", 4)) {
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index 6220b2085..1fc89b977 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.63 1998/09/21 05:05:56 jj Exp $
+# $Id: config.in,v 1.68 1999/03/14 03:12:42 anton Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -25,7 +25,7 @@ define_bool CONFIG_VT y
define_bool CONFIG_VT_CONSOLE y
bool 'Support for AP1000 multicomputer' CONFIG_AP1000
-bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP
if [ "$CONFIG_AP1000" = "y" ]; then
define_bool CONFIG_NO_KEYBOARD y
@@ -165,6 +165,9 @@ if [ "$CONFIG_NET" = "y" ]; then
fi
tristate 'Sun LANCE support' CONFIG_SUNLANCE
tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Sun BigMAC 10/100baseT support' CONFIG_SUNBMAC
+ fi
tristate 'Sun QuadEthernet support' CONFIG_SUNQE
tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
# bool 'FDDI driver support' CONFIG_FDDI
@@ -174,6 +177,15 @@ if [ "$CONFIG_NET" = "y" ]; then
endmenu
fi
+# This one must be before the filesystem configs. -DaveM
+mainmenu_option next_comment
+comment 'Unix98 PTY support'
+bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+fi
+endmenu
+
source fs/Config.in
mainmenu_option next_comment
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 8e6d9e2f5..102ba924f 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -101,7 +101,6 @@ CONFIG_BLK_DEV_NBD=m
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -118,7 +117,6 @@ CONFIG_INET=y
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=m
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
CONFIG_IPV6=m
# CONFIG_IPV6_EUI64 is not set
@@ -139,6 +137,10 @@ CONFIG_ATALK=m
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
#
@@ -181,11 +183,13 @@ CONFIG_FC4=m
# FC4 drivers
#
CONFIG_FC4_SOC=m
+CONFIG_FC4_SOCAL=m
#
# FC4 targets
#
CONFIG_SCSI_PLUTO=m
+CONFIG_SCSI_FCAL=m
#
# Network device support
@@ -203,28 +207,51 @@ CONFIG_SLIP_SMART=y
# CONFIG_SLIP_MODE_SLIP6 is not set
CONFIG_SUNLANCE=y
CONFIG_HAPPYMEAL=m
+CONFIG_SUNBMAC=m
CONFIG_SUNQE=m
CONFIG_MYRI_SBUS=m
#
+# Unix98 PTY support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
# Filesystems
#
# CONFIG_QUOTA is not set
-CONFIG_MINIX_FS=m
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=m
-# CONFIG_JOLIET is not set
+CONFIG_AUTOFS_FS=m
+# CONFIG_ADFS_FS is not set
+CONFIG_AFFS_FS=m
+# CONFIG_HFS_FS is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+CONFIG_MINIX_FS=m
+# CONFIG_NTFS_FS is not set
+CONFIG_HPFS_FS=m
CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_EXT2_FS=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_UFS_FS_WRITE=y
+
+#
+# Network File Systems
+#
+CONFIG_CODA_FS=m
CONFIG_NFS_FS=y
CONFIG_NFSD=m
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-CONFIG_CODA_FS=m
CONFIG_SMB_FS=m
CONFIG_SMB_WIN95=y
CONFIG_NCP_FS=m
@@ -234,21 +261,18 @@ CONFIG_NCP_FS=m
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-CONFIG_HPFS_FS=m
-# CONFIG_NTFS_FS is not set
-CONFIG_SYSV_FS=m
-CONFIG_AFFS_FS=m
-# CONFIG_HFS_FS is not set
-CONFIG_ROMFS_FS=m
-CONFIG_AUTOFS_FS=m
-CONFIG_AMIGA_PARTITION=y
-CONFIG_UFS_FS=m
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
CONFIG_BSD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
CONFIG_SMD_DISKLABEL=y
CONFIG_SOLARIS_X86_PARTITION=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_MAC_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_AMIGA_PARTITION=y
CONFIG_NLS=y
#
@@ -279,6 +303,7 @@ CONFIG_NLS=y
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
#
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index d5f65dda3..f4d5e3f67 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.48 1998/09/21 05:04:46 jj Exp $
+# $Id: Makefile,v 1.49 1999/01/02 16:45:37 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index 69f3070e5..11f1587dd 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -29,24 +29,25 @@ device_scan(unsigned long mem_start))
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+ prom_printf("Booting Linux...\n");
if(strcmp(node_str, "cpu") == 0) {
linux_num_cpus++;
} else {
int scan;
scan = prom_getchild(prom_root_node);
- prom_printf("root child is %08lx\n", (unsigned long) scan);
+ /* One can look it up in PROM instead */
+ /* prom_printf("root child is %08lx\n", (unsigned long) scan); */
while((scan = prom_getsibling(scan)) != 0) {
prom_getstring(scan, "device_type", node_str, sizeof(node_str));
if(strcmp(node_str, "cpu") == 0) {
linux_cpus[linux_num_cpus].prom_node = scan;
prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
linux_cpus[linux_num_cpus].mid = thismid;
- prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
- linux_num_cpus, (unsigned long) scan,
- thismid);
+ /* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid); */
+ printk("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid);
linux_num_cpus++;
}
- };
+ }
if(linux_num_cpus == 0) {
if (sparc_cpu_model == sun4d) {
scan = prom_getchild(prom_root_node);
@@ -59,9 +60,10 @@ device_scan(unsigned long mem_start))
prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
linux_cpus[linux_num_cpus].prom_node = node;
linux_cpus[linux_num_cpus].mid = thismid;
- prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
- linux_num_cpus, (unsigned long) node,
- thismid);
+ /* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n",
+ linux_num_cpus, (unsigned long) node, thismid); */
+ printk("Found CPU %d <node=%08lx,mid=%d>\n",
+ linux_num_cpus, (unsigned long) node, thismid);
linux_num_cpus++;
}
}
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index d628c0c8d..8eeac72b0 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1,10 +1,10 @@
-/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $
+/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $
* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
@@ -874,7 +874,7 @@ C_LABEL(vac_hwflush_patch2_on): sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG
! We want error in %l5, vaddr in %l6
sun4c_fault:
#ifdef CONFIG_SUN4
- sethi C_LABEL(sun4c_memerr_reg), %l4
+ sethi %hi(C_LABEL(sun4c_memerr_reg)), %l4
ld [%l4+%lo(C_LABEL(sun4c_memerr_reg))], %l4 ! memerr ctrl reg addr
ld [%l4], %l6 ! memerr ctrl reg
ld [%l4 + 4], %l5 ! memerr vaddr reg
@@ -956,7 +956,7 @@ sun4c_fault:
sll %l6, 2, %l6
ld [%l4 + %l6], %l4
#ifdef CONFIG_SUN4
- sethi PAGE_MASK, %l6
+ sethi %hi(PAGE_MASK), %l6
andcc %l4, %l6, %g0
#else
andcc %l4, PAGE_MASK, %g0
@@ -1117,7 +1117,7 @@ C_LABEL(num_context_patch2):
#ifndef CONFIG_SUN4
and %l4, PAGE_MASK, %l4
#else
- sethi PAGE_MASK, %l6
+ sethi %hi(PAGE_MASK), %l6
and %l4, %l6, %l4
#endif
@@ -1380,11 +1380,13 @@ C_LABEL(sys_rt_sigreturn):
/* Now that we have a real sys_clone, sys_fork() is
* implemented in terms of it. Our _real_ implementation
- * of SunOS vfork() will use sys_clone() instead.
+ * of SunOS vfork() will use sys_vfork().
+ *
+ * XXX These three should be consolidated into mostly shared
+ * XXX code just like on sparc64... -DaveM
*/
.align 4
- .globl C_LABEL(sys_fork), C_LABEL(sys_vfork), flush_patch_two
-C_LABEL(sys_vfork):
+ .globl C_LABEL(sys_fork), flush_patch_two
C_LABEL(sys_fork):
mov %o7, %l5
flush_patch_two:
@@ -1422,6 +1424,23 @@ flush_patch_three:
call C_LABEL(do_fork)
mov %l5, %o7
+ /* Whee, real vfork! */
+ .globl C_LABEL(sys_vfork), flush_patch_four
+C_LABEL(sys_vfork):
+flush_patch_four:
+ FLUSH_ALL_KERNEL_WINDOWS;
+ rd %psr, %g4
+ WRITE_PAUSE
+ rd %wim, %g5
+ WRITE_PAUSE
+ std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr]
+ sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
+ mov %fp, %o1
+ or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
+ sethi %hi(C_LABEL(do_fork)), %l1
+ jmpl %l1 + %lo(C_LABEL(do_fork)), %g0
+ add %sp, REGWIN_SZ, %o2
+
.align 4
linux_sparc_ni_syscall:
sethi %hi(C_LABEL(sys_ni_syscall)), %l7
@@ -1454,11 +1473,10 @@ C_LABEL(ret_from_syscall):
#ifdef __SMP__
.globl C_LABEL(ret_from_smpfork)
C_LABEL(ret_from_smpfork):
- /* Nowadays all we need to do is drop the scheduler lock. */
- sethi %hi(C_LABEL(scheduler_lock)), %o4
- stb %g0, [%o4 + %lo(C_LABEL(scheduler_lock))]
wr %l0, PSR_ET, %psr
WRITE_PAUSE
+ call schedule_tail
+ mov %g3, %o0
b C_LABEL(ret_sys_call)
ld [%sp + REGWIN_SZ + PT_I0], %o0
#endif
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 9c396c928..0020770e0 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.92 1998/06/10 07:21:55 davem Exp $
+/* $Id: head.S,v 1.95 1999/04/13 07:40:34 anton Exp $
* head.S: The initial boot code for the Sparc port of Linux.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -408,13 +408,11 @@ C_LABEL(trapbase_cpu3):
/* This was the only reasonable way I could think of to properly align
* these page-table data structures.
*/
- .globl C_LABEL(bootup_user_stack)
.globl C_LABEL(pg0), C_LABEL(pg1), C_LABEL(pg2), C_LABEL(pg3)
.globl C_LABEL(empty_bad_page)
.globl C_LABEL(empty_bad_page_table)
.globl C_LABEL(empty_zero_page)
.globl C_LABEL(swapper_pg_dir)
-C_LABEL(bootup_user_stack): .skip 0x2000
C_LABEL(swapper_pg_dir): .skip PAGE_SIZE
C_LABEL(pg0): .skip PAGE_SIZE
C_LABEL(pg1): .skip PAGE_SIZE
@@ -427,8 +425,8 @@ C_LABEL(empty_zero_page): .skip PAGE_SIZE
.global C_LABEL(root_flags)
.global C_LABEL(ram_flags)
.global C_LABEL(root_dev)
- .global C_LABEL(ramdisk_image)
- .global C_LABEL(ramdisk_size)
+ .global C_LABEL(sparc_ramdisk_image)
+ .global C_LABEL(sparc_ramdisk_size)
/* This stuff has to be in sync with SILO and other potential boot loaders
* Fields should be kept upward compatible and whenever any change is made,
@@ -443,9 +441,9 @@ C_LABEL(root_dev):
.half 0
C_LABEL(ram_flags):
.half 0
-C_LABEL(ramdisk_image):
+C_LABEL(sparc_ramdisk_image):
.word 0
-C_LABEL(ramdisk_size):
+C_LABEL(sparc_ramdisk_size):
.word 0
.word C_LABEL(reboot_command)
@@ -1005,8 +1003,8 @@ sun4c_continue_boot:
WRITE_PAUSE
/* I want a kernel stack NOW! */
- set C_LABEL(bootup_user_stack), %g1
- set (0x2000 - REGWIN_SZ), %g2
+ set C_LABEL(init_task_union), %g1
+ set (TASK_UNION_SIZE - REGWIN_SZ), %g2
add %g1, %g2, %sp
mov 0, %fp /* And for good luck */
@@ -1110,6 +1108,9 @@ sun4c_continue_boot:
set flush_patch_three, %g5
st %g4, [%g5 + 0x18]
st %g4, [%g5 + 0x1c]
+ set flush_patch_four, %g5
+ st %g4, [%g5 + 0x18]
+ st %g4, [%g5 + 0x1c]
set flush_patch_exception, %g5
st %g4, [%g5 + 0x18]
st %g4, [%g5 + 0x1c]
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 4c8f78c8a..26f3194bd 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj Exp $
+/* $Id: irq.c,v 1.93 1999/04/21 06:15:45 anton Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -8,7 +8,7 @@
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
* Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
#include <linux/config.h>
@@ -24,6 +24,8 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/tasks.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -192,12 +194,18 @@ void free_irq(unsigned int irq, void *dev_id)
restore_flags(flags);
}
-/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */
+#ifndef __SMP__
+unsigned int local_bh_count;
+unsigned int local_irq_count;
+
+#else
+/* SMP interrupt locking on Sparc. */
+
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
-#ifdef __SMP__
-/* SMP interrupt locking on Sparc. */
+atomic_t global_bh_lock = ATOMIC_INIT(0);
+spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED;
/* Who has global_irq_lock. */
unsigned char global_irq_holder = NO_PROC_ID;
@@ -208,58 +216,71 @@ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
/* Global IRQ locking depth. */
atomic_t global_irq_count = ATOMIC_INIT(0);
-atomic_t global_bh_count = ATOMIC_INIT(0);
-atomic_t global_bh_lock = ATOMIC_INIT(0);
-
/* This protects BH software state (masks, things like that). */
spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED;
-#ifdef DEBUG_IRQLOCK
+void smp_show_backtrace_all_cpus(void);
+void show_backtrace(void);
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+#define MAXCOUNT 100000000
+#define VERBOSE_DEBUG_IRQLOCK
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; }
-
-static inline void wait_on_bh(int cpu, unsigned long where)
+static void show(char * str)
{
- int stuck = INIT_STUCK;
- do {
- STUCK;
- /* nothing .. wait for the other bh's to go away */
- } while (atomic_read(&global_bh_count) != 0);
-}
+ int i;
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [ ", atomic_read(&global_irq_count));
-static unsigned long previous_irqholder;
+ for (i = 0; i < NR_CPUS; i++) {
+ printk("%d ", local_irq_count[i]);
+ }
+ printk("]\n");
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+ printk("bh: %d [ ", (spin_is_locked(&global_bh_count) ? 1 : 0));
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+ for (i = 0; i < NR_CPUS; i++) {
+ printk("%d ", local_bh_count[cpu]);
+ }
+ printk("]\n");
+
+#ifdef VERBOSE_DEBUG_IRQLOCK
+ smp_show_backtrace_all_cpus();
+#else
+ show_backtrace();
+#endif
+}
+
+static inline void wait_on_bh(void)
+{
+ int count = MAXCOUNT;
+ do {
+ if(!--count) {
+ show("wait_on_bh");
+ count = 0;
+ }
+ barrier();
+ } while(spin_is_locked(&global_bh_count));
+}
/*
* We have to allow irqs to arrive between __sti and __cli
*/
-#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+#define SYNC_OTHER_CORES(x) udelay(x+1)
-static inline void wait_on_irq(int cpu, unsigned long where)
+static inline void wait_on_irq(int cpu)
{
- int stuck = INIT_STUCK;
- int local_count = local_irq_count[cpu];
+ int count = MAXCOUNT;
for (;;) {
-
/*
* Wait until all interrupts are gone. Wait
* for bottom half handlers unless we're
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
- if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+ if (local_bh_count[cpu] || !spin_is_locked(&global_bh_count))
break;
}
@@ -267,17 +288,18 @@ static inline void wait_on_irq(int cpu, unsigned long where)
spin_unlock(&global_irq_lock);
for (;;) {
- STUCK;
-
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
__sti();
SYNC_OTHER_CORES(cpu);
__cli();
-
if (atomic_read(&global_irq_count))
continue;
- if (*((unsigned char *)&global_irq_lock))
+ if (spin_is_locked (&global_irq_lock))
continue;
- if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+ if (!local_bh_count[cpu] && spin_is_locked(&global_bh_count))
continue;
if (spin_trylock(&global_irq_lock))
break;
@@ -295,14 +317,8 @@ static inline void wait_on_irq(int cpu, unsigned long where)
*/
void synchronize_bh(void)
{
- unsigned long where;
-
- __asm__("mov %%i7, %0" : "=r" (where));
-
- if (atomic_read(&global_bh_count) && !in_interrupt()) {
- int cpu = smp_processor_id();
- wait_on_bh(cpu, where);
- }
+ if (spin_is_locked (&global_bh_count) && !in_interrupt())
+ wait_on_bh();
}
/*
@@ -321,16 +337,9 @@ void synchronize_irq(void)
}
}
-#undef INIT_STUCK
-#define INIT_STUCK 10000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
-
-static inline void get_irqlock(int cpu, unsigned long where)
+static inline void get_irqlock(int cpu)
{
- int stuck = INIT_STUCK;
+ int count = MAXCOUNT;
if (!spin_trylock(&global_irq_lock)) {
/* do we already hold the lock? */
@@ -338,23 +347,25 @@ static inline void get_irqlock(int cpu, unsigned long where)
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
- do {
- STUCK;
+ while (spin_is_locked(&global_irq_lock)) {
+ if (!--count) {
+ show("get_irqlock");
+ count = ~0;
+ }
barrier();
- } while (*((volatile unsigned char *)&global_irq_lock));
+ }
} while (!spin_trylock(&global_irq_lock));
}
/*
* We also to make sure that nobody else is running
* in an interrupt context.
*/
- wait_on_irq(cpu, where);
+ wait_on_irq(cpu);
/*
* Ok, finally..
*/
global_irq_holder = cpu;
- previous_irqholder = where;
}
/*
@@ -372,9 +383,6 @@ static inline void get_irqlock(int cpu, unsigned long where)
void __global_cli(void)
{
unsigned int flags;
- unsigned long where;
-
- __asm__("mov %%i7, %0" : "=r" (where));
__save_flags(flags);
@@ -382,7 +390,7 @@ void __global_cli(void)
int cpu = smp_processor_id();
__cli();
if (!local_irq_count[cpu])
- get_irqlock(cpu, where);
+ get_irqlock(cpu);
}
}
@@ -442,65 +450,14 @@ void __global_restore_flags(unsigned long flags)
__sti();
break;
default:
- printk("global_restore_flags: %08lx (%08lx)\n",
- flags, (&flags)[-1]);
+ {
+ unsigned long pc;
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (pc));
+ printk("global_restore_flags: Bogon flags(%08lx) caller %08lx\n", flags, pc);
}
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 200000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
-
-#define VERBOSE_IRQLOCK_DEBUGGING
-
-void irq_enter(int cpu, int irq, void *_opaque)
-{
-#ifdef VERBOSE_IRQLOCK_DEBUGGING
- extern void smp_show_backtrace_all_cpus(void);
-#endif
- int stuck = INIT_STUCK;
-
- hardirq_enter(cpu);
- barrier();
- while (*((volatile unsigned char *)&global_irq_lock)) {
- if ((unsigned char) cpu == global_irq_holder) {
- struct pt_regs *regs = _opaque;
- int sbh_cnt = atomic_read(&global_bh_count);
- int globl_locked = *((unsigned char *)&global_irq_lock);
- int globl_icount = atomic_read(&global_irq_count);
- int local_count = local_irq_count[cpu];
- unsigned long pc = regs->pc;
-
- /* It is very important that we load the state variables
- * before we do the first call to printk() as printk()
- * could end up changing them...
- */
-
- printk("CPU[%d]: BAD! Local IRQ's enabled, global disabled "
- "interrupt at PC[%08lx]\n", cpu, pc);
- printk("CPU[%d]: bhcnt[%d] glocked[%d] gicnt[%d] licnt[%d]\n",
- cpu, sbh_cnt, globl_locked, globl_icount, local_count);
-#ifdef VERBOSE_IRQLOCK_DEBUGGING
- printk("Performing backtrace on all cpus, write this down!\n");
- smp_show_backtrace_all_cpus();
-#endif
- break;
- }
- STUCK;
- barrier();
}
}
-void irq_exit(int cpu, int irq)
-{
- hardirq_exit(cpu);
- release_irqlock(cpu);
-}
-
-#endif /* DEBUG_IRQLOCK */
#endif /* __SMP__ */
void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
@@ -542,7 +499,7 @@ void handler_irq(int irq, struct pt_regs * regs)
smp4m_irq_rotate(cpu);
#endif
#endif
- irq_enter(cpu, irq, regs);
+ irq_enter(cpu, irq);
action = *(irq + irq_action);
kstat.irqs[cpu][irq]++;
do {
@@ -563,7 +520,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
int cpu = smp_processor_id();
disable_pil_irq(irq);
- irq_enter(cpu, irq, regs);
+ irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
floppy_interrupt(irq, dev_id, regs);
irq_exit(cpu, irq);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index aae13c515..a2beedbf1 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $
+/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
@@ -498,9 +498,10 @@ static void pci_do_settimeofday(struct timeval *tv)
tv->tv_sec--;
}
xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = 0x70000000;
- time_esterror = 0x70000000;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
sti();
}
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 3aeee6f6b..301747c22 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.126 1998/09/21 05:05:18 jj Exp $
+/* $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -62,7 +62,9 @@ asmlinkage int sys_idle(void)
/* endless idle loop with no priority at all */
current->priority = 0;
- current->counter = 0;
+ current->counter = -100;
+ init_idle();
+
for (;;) {
if (ARCH_SUN4C_SUN4) {
static int count = HZ;
@@ -108,13 +110,17 @@ out:
/* This is being executed in task 0 'user space'. */
int cpu_idle(void *unused)
{
+ /* endless idle loop with no priority at all */
current->priority = 0;
+ current->counter = -100;
+ init_idle();
+
while(1) {
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
- /* endless idle loop with no priority at all */
- current->counter = 0;
- schedule();
+ if(current->need_resched) {
+ schedule();
+ check_pgt_cache();
+ }
+ barrier(); /* or else gcc optimizes... */
}
}
@@ -203,8 +209,10 @@ void __show_backtrace(unsigned long fp)
int cpu = smp_processor_id();
spin_lock_irqsave(&sparc_backtrace_lock, flags);
- rw = (struct reg_window *) fp;
- while(rw) {
+
+ rw = (struct reg_window *)fp;
+ while(rw && (((unsigned long) rw) >= PAGE_OFFSET) &&
+ !(((unsigned long) rw) & 0x7)) {
printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] "
"FP[%08lx] CALLER[%08lx]\n", cpu,
rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
@@ -216,28 +224,21 @@ void __show_backtrace(unsigned long fp)
spin_unlock_irqrestore(&sparc_backtrace_lock, flags);
}
+#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
+#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
+#define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp))
+
void show_backtrace(void)
{
unsigned long fp;
- __asm__ __volatile__(
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "save %%sp, -64, %%sp\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "mov %%i6, %0" : "=r" (fp));
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+
+ __GET_FP(fp);
+
__show_backtrace(fp);
}
@@ -379,8 +380,21 @@ void flush_thread(void)
current->tss.current_ds = USER_DS;
if (current->tss.flags & SPARC_FLAG_KTHREAD) {
current->tss.flags &= ~SPARC_FLAG_KTHREAD;
- switch_to_context(current);
+
+ /* We must fixup kregs as well. */
+ current->tss.kregs = (struct pt_regs *)
+ (((unsigned long)current) +
+ (TASK_UNION_SIZE - TRACEREG_SZ));
}
+
+ /* Exec'ing out of a vfork() shared address space is
+ * tricky on sparc32. exec_mmap will not set the mmu
+ * context because it sets the new current->mm after
+ * calling init_new_context and activate_context is
+ * a nop on sparc32, so we gotta catch it here. And
+ * clone()'s had the same problem. -DaveM
+ */
+ switch_to_context(current);
}
static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src)
@@ -440,10 +454,17 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src)
size = ((unsigned long)src->fp) - ((unsigned long)src);
sp = (struct sparc_stackf *)(((unsigned long)dst) - size);
+ /* do_fork() grabs the parent semaphore, we must release it
+ * temporarily so we can build the child clone stack frame
+ * without deadlocking.
+ */
+ up(&current->mm->mmap_sem);
if (copy_to_user(sp, src, size))
- return 0;
- if (put_user(dst, &sp->fp))
- return 0;
+ sp = (struct sparc_stackf *) 0;
+ else if (put_user(dst, &sp->fp))
+ sp = (struct sparc_stackf *) 0;
+ down(&current->mm->mmap_sem);
+
return sp;
}
@@ -505,14 +526,24 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.kpsr = current->tss.fork_kpsr;
#endif
p->tss.kwim = current->tss.fork_kwim;
- p->tss.kregs = childregs;
if(regs->psr & PSR_PS) {
- childregs->u_regs[UREG_FP] = p->tss.ksp;
+ extern struct pt_regs fake_swapper_regs;
+
+ p->tss.kregs = &fake_swapper_regs;
+ new_stack = (struct reg_window *)
+ ((((unsigned long)p) +
+ (TASK_UNION_SIZE)) -
+ (REGWIN_SZ));
+ childregs->u_regs[UREG_FP] = (unsigned long) new_stack;
p->tss.flags |= SPARC_FLAG_KTHREAD;
p->tss.current_ds = KERNEL_DS;
+ memcpy((void *)new_stack,
+ (void *)regs->u_regs[UREG_FP],
+ sizeof(struct reg_window));
childregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
+ p->tss.kregs = childregs;
childregs->u_regs[UREG_FP] = sp;
p->tss.flags &= ~SPARC_FLAG_KTHREAD;
p->tss.current_ds = USER_DS;
@@ -658,3 +689,37 @@ out:
unlock_kernel();
return error;
}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ long retval;
+
+ __asm__ __volatile("mov %4, %%g2\n\t" /* Set aside fn ptr... */
+ "mov %5, %%g3\n\t" /* and arg. */
+ "mov %1, %%g1\n\t"
+ "mov %2, %%o0\n\t" /* Clone flags. */
+ "mov 0, %%o1\n\t" /* usp arg == 0 */
+ "t 0x10\n\t" /* Linux/Sparc clone(). */
+ "cmp %%o1, 0\n\t"
+ "be 1f\n\t" /* The parent, just return. */
+ " nop\n\t" /* Delay slot. */
+ "jmpl %%g2, %%o7\n\t" /* Call the function. */
+ " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
+ "mov %3, %%g1\n\t"
+ "t 0x10\n\t" /* Linux/Sparc exit(). */
+ /* Notreached by child. */
+ "1: mov %%o0, %0\n\t" :
+ "=r" (retval) :
+ "i" (__NR_clone), "r" (flags | CLONE_VM),
+ "i" (__NR_exit), "r" (fn), "r" (arg) :
+ "g1", "g2", "g3", "o0", "o1", "memory", "cc");
+ return retval;
+}
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index ed8fe6a25..7f6ec54f9 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -528,6 +528,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH))
|| (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) {
+ unsigned long flags;
+
if(child == current) {
/* Try this under SunOS/Solaris, bwa haha
* You'll never be able to kill the process. ;-)
@@ -539,8 +541,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
(current->uid != child->euid) ||
(current->uid != child->uid) ||
(current->gid != child->egid) ||
- (current->gid != child->gid)) &&
- !capable(CAP_SYS_PTRACE)) {
+ (current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
pt_error_return(regs, EPERM);
goto out;
}
@@ -550,14 +553,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
child->flags |= PF_PTRACED;
+ write_lock_irqsave(&tasklist_lock, flags);
if(child->p_pptr != current) {
- unsigned long flags;
- write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
- write_unlock_irqrestore(&tasklist_lock, flags);
}
+ write_unlock_irqrestore(&tasklist_lock, flags);
send_sig(SIGSTOP, child, 1);
pt_succ_return(regs, 0);
goto out;
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 84190cf5a..d29c1cb66 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.103 1998/09/21 05:05:23 jj Exp $
+/* $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -271,8 +271,8 @@ extern unsigned long sun_serial_setup(unsigned long);
extern unsigned short root_flags;
extern unsigned short root_dev;
extern unsigned short ram_flags;
-extern unsigned ramdisk_image;
-extern unsigned ramdisk_size;
+extern unsigned sparc_ramdisk_image;
+extern unsigned sparc_ramdisk_size;
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
@@ -285,7 +285,7 @@ enum sparc_cpu sparc_cpu_model;
struct tt_entry *sparc_ttable;
-static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
+struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
static void prom_cons_write(struct console *con, const char *str, unsigned count)
{
@@ -375,7 +375,7 @@ __initfunc(void setup_arch(char **cmdline_p,
sun4c_probe_vac();
load_mmu();
total = prom_probe_memory();
- *memory_start_p = (((unsigned long) &end));
+ *memory_start_p = PAGE_ALIGN(((unsigned long) &end));
if(!packed) {
for(i=0; sp_banks[i].num_bytes != 0; i++) {
@@ -404,10 +404,10 @@ __initfunc(void setup_arch(char **cmdline_p,
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
#endif
#ifdef CONFIG_BLK_DEV_INITRD
- if (ramdisk_image) {
- initrd_start = ramdisk_image;
+ if (sparc_ramdisk_image) {
+ initrd_start = sparc_ramdisk_image;
if (initrd_start < KERNBASE) initrd_start += KERNBASE;
- initrd_end = initrd_start + ramdisk_size;
+ initrd_end = initrd_start + sparc_ramdisk_size;
if (initrd_end > *memory_end_p) {
printk(KERN_CRIT "initrd extends beyond end of memory "
"(0x%08lx > 0x%08lx)\ndisabling initrd\n",
@@ -417,6 +417,14 @@ __initfunc(void setup_arch(char **cmdline_p,
if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
initrd_below_start_ok = 1;
*memory_start_p = PAGE_ALIGN (initrd_end);
+ } else if (initrd_start && sparc_ramdisk_image < KERNBASE) {
+ switch (sparc_cpu_model) {
+ case sun4m:
+ case sun4d:
+ initrd_start -= KERNBASE;
+ initrd_end -= KERNBASE;
+ break;
+ }
}
}
#endif
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index 287ed6cdc..e6023f43b 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $
+/* $Id: signal.c,v 1.91 1999/01/26 11:00:44 jj Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -38,6 +38,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
/* This turned off for production... */
/* #define DEBUG_SIGNALS 1 */
+/* #define DEBUG_SIGNALS_TRACE 1 */
+/* #define DEBUG_SIGNALS_MAPS 1 */
/* Signal frames: the original one (compatible with SunOS):
*
@@ -1004,6 +1006,59 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
}
}
+#ifdef DEBUG_SIGNALS_MAPS
+
+#define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %s %lu "
+
+static inline void read_maps (void)
+{
+ struct vm_area_struct * map, * next;
+ char * buffer;
+ ssize_t i;
+
+ buffer = (char*)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ return;
+
+ for (map = current->mm->mmap ; map ; map = next ) {
+ /* produce the next line */
+ char *line;
+ char str[5], *cp = str;
+ int flags;
+ kdev_t dev;
+ unsigned long ino;
+
+ /*
+ * Get the next vma now (but it won't be used if we sleep).
+ */
+ next = map->vm_next;
+ flags = map->vm_flags;
+
+ *cp++ = flags & VM_READ ? 'r' : '-';
+ *cp++ = flags & VM_WRITE ? 'w' : '-';
+ *cp++ = flags & VM_EXEC ? 'x' : '-';
+ *cp++ = flags & VM_MAYSHARE ? 's' : 'p';
+ *cp++ = 0;
+
+ dev = 0;
+ ino = 0;
+ if (map->vm_file != NULL) {
+ dev = map->vm_file->f_dentry->d_inode->i_dev;
+ ino = map->vm_file->f_dentry->d_inode->i_ino;
+ line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+ }
+ printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_offset,
+ kdevname(dev), ino);
+ if (map->vm_file != NULL)
+ printk("%s\n", line);
+ else
+ printk("\n");
+ }
+ free_page((unsigned long)buffer);
+ return;
+}
+#endif
+
/* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
@@ -1115,8 +1170,25 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
}
#ifdef DEBUG_SIGNALS
/* Very useful to debug dynamic linker problems */
- printk ("Sig ILL going...\n");
+ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
show_regs (regs);
+#ifdef DEBUG_SIGNALS_TRACE
+ {
+ struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
+ unsigned int ins[8];
+
+ while(rw &&
+ !(((unsigned long) rw) & 0x3)) {
+ copy_from_user(ins, &rw->ins[0], sizeof(ins));
+ printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
+ rw = (struct reg_window *)(unsigned long)ins[6];
+ }
+ }
+#endif
+#ifdef DEBUG_SIGNALS_MAPS
+ printk("Maps:\n");
+ read_maps();
+#endif
#endif
/* fall through */
default:
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index f77d823aa..fb55c1ffa 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -52,6 +52,7 @@ unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
int smp_activated = 0;
volatile int cpu_number_map[NR_CPUS];
volatile int __cpu_logical_map[NR_CPUS];
+cycles_t cacheflush_time = 0; /* XXX */
/* The only guaranteed locking primitive available on all Sparc
* processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 43f963217..b043d647d 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.77 1999/03/21 06:37:43 davem Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -66,6 +66,7 @@ extern char saved_command_line[];
extern void bcopy (const char *, char *, int);
extern int __ashrdi3(int, int);
+extern int __lshrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
@@ -91,6 +92,7 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
EXPORT_SYMBOL(sparc_cpu_model);
EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
+EXPORT_SYMBOL(kernel_thread);
#ifdef SPIN_LOCK_DEBUG
EXPORT_SYMBOL(_do_spin_lock);
EXPORT_SYMBOL(_do_spin_unlock);
@@ -118,6 +120,7 @@ EXPORT_SYMBOL_PRIVATE(_global_cli);
#endif
EXPORT_SYMBOL(page_offset);
+EXPORT_SYMBOL(sparc_valid_addr_bitmap);
#ifndef CONFIG_SUN4
EXPORT_SYMBOL(stack_top);
@@ -211,6 +214,7 @@ EXPORT_SYMBOL(saved_command_line);
EXPORT_SYMBOL(prom_apply_obio_ranges);
EXPORT_SYMBOL(prom_getname);
EXPORT_SYMBOL(prom_feval);
+EXPORT_SYMBOL(prom_getbool);
EXPORT_SYMBOL(prom_getstring);
EXPORT_SYMBOL(prom_apply_sbus_ranges);
EXPORT_SYMBOL(prom_getint);
@@ -268,6 +272,7 @@ EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memmove);
EXPORT_SYMBOL_NOVERS(__ashrdi3);
+EXPORT_SYMBOL_NOVERS(__lshrdi3);
EXPORT_SYMBOL_DOT(rem);
EXPORT_SYMBOL_DOT(urem);
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 93474714a..1d0de8d23 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -1,4 +1,4 @@
-/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $
+/* $Id: sun4d_irq.c,v 1.18 1999/04/20 13:22:30 anton Exp $
* arch/sparc/kernel/sun4d_irq.c:
* SS1000/SC2000 interrupt handling.
*
@@ -193,7 +193,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
cc_set_iclr(1 << irq);
- irq_enter(cpu, irq, regs);
+ irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
if (!sbusl) {
action = *(irq + irq_action);
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index af0aaf58d..edd736b41 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -190,6 +190,7 @@ __initfunc(void smp4d_boot_cpus(void))
current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
smp_setup_percpu_timer();
+ init_idle();
local_flush_cache_all();
if(linux_num_cpus == 1)
return; /* Not an MP box. */
@@ -211,6 +212,7 @@ __initfunc(void smp4d_boot_cpus(void))
p = task[++cpucount];
p->processor = i;
+ p->has_cpu = 1; /* we schedule the first task manually */
current_set[i] = p;
for (no = 0; no < linux_num_cpus; no++)
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index bd6fc8e20..4d7177dac 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -253,7 +253,7 @@ __initfunc(static void sun4m_init_timers(void (*counter_fn)(int, void *, struct
/* Map the per-cpu Counter registers. */
sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0,
- PAGE_SIZE*NCPUS, "counters_percpu",
+ PAGE_SIZE*SUN4M_NCPUS, "counters_percpu",
cnt_regs[0].which_io, 0x0);
/* Map the system Counter register. */
@@ -334,7 +334,7 @@ __initfunc(void sun4m_init_IRQ(void))
/* Map the interrupt registers for all possible cpus. */
sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
- PAGE_SIZE*NCPUS, "interrupts_percpu",
+ PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu",
int_regs[0].which_io, 0x0);
/* Map the system interrupt control registers. */
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 183ea7323..c9acf609c 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -161,6 +161,7 @@ __initfunc(void smp4m_boot_cpus(void))
smp_store_cpu_info(boot_cpu_id);
set_irq_udt(mid_xlate[boot_cpu_id]);
smp_setup_percpu_timer();
+ init_idle();
local_flush_cache_all();
if(linux_num_cpus == 1)
return; /* Not an MP box. */
@@ -180,6 +181,7 @@ __initfunc(void smp4m_boot_cpus(void))
p = task[++cpucount];
p->processor = i;
+ p->has_cpu = 1; /* we schedule the first task manually */
current_set[i] = p;
/* See trampoline.S for details... */
@@ -448,6 +450,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
if(!--prof_counter[cpu]) {
int user = user_mode(regs);
+ irq_enter(cpu, 0);
if(current->pid) {
update_one_process(current, 1, user, !user, cpu);
@@ -456,7 +459,6 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
current->need_resched = 1;
}
- spin_lock(&ticker_lock);
if(user) {
if(current->priority < DEF_PRIORITY) {
kstat.cpu_nice++;
@@ -469,9 +471,9 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
kstat.cpu_system++;
kstat.per_cpu_system[cpu]++;
}
- spin_unlock(&ticker_lock);
}
prof_counter[cpu] = prof_multiplier[cpu];
+ irq_exit(cpu, 0);
}
}
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index e5ea2e9b3..ed3918c10 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $
+/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $
* linux/arch/sparc/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -25,6 +25,8 @@
#include <asm/uaccess.h>
#include <asm/ipc.h>
+/* #define DEBUG_UNIMP_SYSCALL */
+
/* XXX Make this per-binary type, this way we can detect the type of
* XXX a binary. Every Sparc executable calls this very early on.
*/
@@ -189,6 +191,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
goto out;
}
retval = -ENOMEM;
+ len = PAGE_ALIGN(len);
if(!(flags & MAP_FIXED) && !addr) {
addr = get_unmapped_area(addr, len);
if(!addr)
@@ -202,6 +205,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
if(ARCH_SUN4C_SUN4) {
if(((addr >= 0x20000000) && (addr < 0xe0000000))) {
+ /* VM hole */
retval = current->mm->brk;
goto out_putf;
}
@@ -223,9 +227,14 @@ out:
asmlinkage unsigned long
c_sys_nis_syscall (struct pt_regs *regs)
{
+ static int count = 0;
+
+ if (count++ > 5) return -ENOSYS;
lock_kernel();
- printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]);
+ printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]);
+#ifdef DEBUG_UNIMP_SYSCALL
show_regs (regs);
+#endif
unlock_kernel();
return -ENOSYS;
}
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 5508f850a..4d0dfff5f 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.80 1998/09/21 05:04:59 jj Exp $
+/* $Id: systbls.S,v 1.83 1999/04/07 17:14:06 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -25,7 +25,7 @@ sys_call_table:
/*30*/ .long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
/*35*/ .long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile
/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
-/*45*/ .long sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*45*/ .long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
/*55*/ .long sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
@@ -47,7 +47,7 @@ sys_call_table:
/*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
/*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
-/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
/*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
/*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
/*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
@@ -129,7 +129,7 @@ sunos_sys_table:
/*150*/ .long sys_getsockname, sunos_nosys, sunos_nosys
.long sys_poll, sunos_nosys, sunos_nosys
.long sunos_getdirentries, sys_statfs, sys_fstatfs
- .long sys_umount, sunos_nosys, sunos_nosys
+ .long sys_oldumount, sunos_nosys, sunos_nosys
.long sys_getdomainname, sys_setdomainname
.long sunos_nosys, sys_quotactl, sunos_nosys
.long sunos_mount, sys_ustat, sunos_semsys
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 9e5afcfcf..633ef2adb 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.39 1998/09/29 09:46:15 davem Exp $
+/* $Id: time.c,v 1.43 1999/03/15 22:13:31 davem Exp $
* linux/arch/sparc/kernel/time.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -39,6 +39,8 @@
#include <asm/sun4paddr.h>
#include <asm/page.h>
+extern rwlock_t xtime_lock;
+
enum sparc_clock_type sp_clock_typ;
struct mostek48t02 *mstk48t02_regs = 0;
struct mostek48t08 *mstk48t08_regs = 0;
@@ -80,7 +82,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifdef CONFIG_SUN4
if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
- (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
+ (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
int temp;
intersil_read_intr(intersil_clock, temp);
/* re-enable the irq */
@@ -89,6 +91,8 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#endif
clear_clock_irq();
+ write_lock(&xtime_lock);
+
do_timer(regs);
/* Determine when to update the Mostek clock. */
@@ -101,6 +105,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
}
+ write_unlock(&xtime_lock);
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -436,6 +441,9 @@ extern __inline__ unsigned long do_gettimeoffset(void)
return offset + count;
}
+/* This need not obtain the xtime_lock as it is coded in
+ * an implicitly SMP safe way already.
+ */
void do_gettimeofday(struct timeval *tv)
{
#if CONFIG_AP1000
@@ -485,12 +493,13 @@ void do_gettimeofday(struct timeval *tv)
void do_settimeofday(struct timeval *tv)
{
+ write_lock_irq(&xtime_lock);
bus_do_settimeofday(tv);
+ write_unlock_irq(&xtime_lock);
}
static void sbus_do_settimeofday(struct timeval *tv)
{
- cli();
#if !CONFIG_AP1000
tv->tv_usec -= do_gettimeoffset();
if(tv->tv_usec < 0) {
@@ -501,10 +510,8 @@ static void sbus_do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
}
/*
@@ -544,7 +551,7 @@ static int set_rtc_mmss(unsigned long nowtime)
} else {
printk(KERN_WARNING
"set_rtc_mmss: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
+ mostek_minutes, real_minutes);
return -1;
}
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 86d632409..b9afa02f7 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.57 1998/09/17 11:04:51 jj Exp $
+/* $Id: traps.c,v 1.59 1999/03/06 12:07:31 anton Exp $
* arch/sparc/kernel/traps.c
*
* Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -82,8 +82,13 @@ void instruction_dump (unsigned long *pc)
printk("\n");
}
+#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
+#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
+
void die_if_kernel(char *str, struct pt_regs *regs)
{
+ int count = 0;
+
/* Amuse the user. */
printk(
" \\|/ ____ \\|/\n"
@@ -93,6 +98,27 @@ void die_if_kernel(char *str, struct pt_regs *regs)
printk("%s(%d): %s\n", current->comm, current->pid, str);
show_regs(regs);
+
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __SAVE; __SAVE; __SAVE; __SAVE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+ __RESTORE; __RESTORE; __RESTORE; __RESTORE;
+
+ {
+ struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
+
+ /* Stop the back trace when we hit userland or we
+ * find some badly aligned kernel stack. Set an upper
+ * bound in case our stack is trashed and we loop.
+ */
+ while(rw &&
+ count++ < 30 &&
+ (((unsigned long) rw) >= PAGE_OFFSET) &&
+ !(((unsigned long) rw) & 0x7)) {
+ printk("Caller[%08lx]\n", rw->ins[7]);
+ rw = (struct reg_window *)rw->ins[6];
+ }
+ }
printk("Instruction DUMP:");
instruction_dump ((unsigned long *) regs->pc);
if(regs->psr & PSR_PS)
diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c
index 1fb434b49..a683efb3e 100644
--- a/arch/sparc/kernel/unaligned.c
+++ b/arch/sparc/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.17 1997/04/11 00:42:08 davem Exp $
+/* $Id: unaligned.c,v 1.18 1999/04/03 11:36:17 anton Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -332,7 +332,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
- lock_kernel();
if(!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n",
regs->pc);
@@ -380,7 +379,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
}
advance(regs);
}
- unlock_kernel();
}
static inline int ok_for_user(struct pt_regs *regs, unsigned int insn,
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 0670ff273..d5b475480 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -1,11 +1,11 @@
-# $Id: Makefile,v 1.26 1998/07/26 03:02:43 davem Exp $
+# $Id: Makefile,v 1.28 1999/03/21 06:37:44 davem Exp $
# Makefile for Sparc library files..
#
OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
- copy_user.o locks.o atomic.o bitops.o debuglocks.o
+ copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o
ifdef CONFIG_SMP
OBJS += irqlock.o
@@ -89,6 +89,9 @@ urem.o: urem.S
ashrdi3.o: ashrdi3.S
$(CC) -D__ASSEMBLY__ -c -o ashrdi3.o ashrdi3.S
+lshrdi3.o: lshrdi3.S
+ $(CC) -D__ASSEMBLY__ -c -o lshrdi3.o lshrdi3.S
+
dep:
include $(TOPDIR)/Rules.make
diff --git a/arch/sparc/lib/atomic.S b/arch/sparc/lib/atomic.S
index 4e4aa0646..c57e61574 100644
--- a/arch/sparc/lib/atomic.S
+++ b/arch/sparc/lib/atomic.S
@@ -44,6 +44,7 @@ ___xchg32_sun4md:
.globl ___atomic_add
___atomic_add:
rd %psr, %g3 ! Keep the code small, old way was stupid
+ nop; nop; nop; ! Let the bits set
or %g3, PSR_PIL, %g7 ! Disable interrupts
wr %g7, 0x0, %psr ! Set %psr
nop; nop; nop; ! Let the bits set
@@ -51,12 +52,16 @@ ___atomic_add:
1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP.
orcc %g7, 0x0, %g0 ! Did we get it?
bne 1b ! Nope...
-#endif
ld [%g1], %g7 ! Load locked atomic_t
sra %g7, 8, %g7 ! Get signed 24-bit integer
add %g7, %g2, %g2 ! Add in argument
sll %g2, 8, %g7 ! Transpose back to atomic_t
st %g7, [%g1] ! Clever: This releases the lock as well.
+#else
+ ld [%g1], %g7 ! Load locked atomic_t
+ add %g7, %g2, %g2 ! Add in argument
+ st %g2, [%g1] ! Store it back
+#endif
wr %g3, 0x0, %psr ! Restore original PSR_PIL
nop; nop; nop; ! Let the bits set
jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h
@@ -65,6 +70,7 @@ ___atomic_add:
.globl ___atomic_sub
___atomic_sub:
rd %psr, %g3 ! Keep the code small, old way was stupid
+ nop; nop; nop; ! Let the bits set
or %g3, PSR_PIL, %g7 ! Disable interrupts
wr %g7, 0x0, %psr ! Set %psr
nop; nop; nop; ! Let the bits set
@@ -72,12 +78,16 @@ ___atomic_sub:
1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP.
orcc %g7, 0x0, %g0 ! Did we get it?
bne 1b ! Nope...
-#endif
ld [%g1], %g7 ! Load locked atomic_t
sra %g7, 8, %g7 ! Get signed 24-bit integer
sub %g7, %g2, %g2 ! Subtract argument
sll %g2, 8, %g7 ! Transpose back to atomic_t
st %g7, [%g1] ! Clever: This releases the lock as well
+#else
+ ld [%g1], %g7 ! Load locked atomic_t
+ sub %g7, %g2, %g2 ! Subtract argument
+ st %g2, [%g1] ! Store it back
+#endif
wr %g3, 0x0, %psr ! Restore original PSR_PIL
nop; nop; nop; ! Let the bits set
jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h
diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S
index 253c358fe..ea9ed5a6c 100644
--- a/arch/sparc/lib/bitops.S
+++ b/arch/sparc/lib/bitops.S
@@ -20,12 +20,10 @@
.globl ___set_bit
___set_bit:
rd %psr, %g3
- andcc %g3, PSR_PIL, %g0
- bne 1f
- nop
- wr %g3, PSR_PIL, %psr
+ nop; nop; nop;
+ or %g3, PSR_PIL, %g5
+ wr %g5, 0x0, %psr
nop; nop; nop
-1:
#ifdef __SMP__
set C_LABEL(bitops_spinlock), %g5
2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
@@ -38,17 +36,12 @@ ___set_bit:
#ifdef __SMP__
st %g5, [%g1]
set C_LABEL(bitops_spinlock), %g5
- andcc %g3, PSR_PIL, %g0
- bne 1f
- stb %g0, [%g5]
+ stb %g0, [%g5]
#else
- andcc %g3, PSR_PIL, %g0
- bne 1f
- st %g5, [%g1]
+ st %g5, [%g1]
#endif
wr %g3, 0x0, %psr
nop; nop; nop
-1:
jmpl %o7, %g0
mov %g4, %o7
@@ -56,12 +49,10 @@ ___set_bit:
.globl ___clear_bit
___clear_bit:
rd %psr, %g3
- andcc %g3, PSR_PIL, %g0
- bne 1f
- nop
- wr %g3, PSR_PIL, %psr
nop; nop; nop
-1:
+ or %g3, PSR_PIL, %g5
+ wr %g5, 0x0, %psr
+ nop; nop; nop
#ifdef __SMP__
set C_LABEL(bitops_spinlock), %g5
2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
@@ -74,17 +65,12 @@ ___clear_bit:
#ifdef __SMP__
st %g5, [%g1]
set C_LABEL(bitops_spinlock), %g5
- andcc %g3, PSR_PIL, %g0
- bne 1f
- stb %g0, [%g5]
+ stb %g0, [%g5]
#else
- andcc %g3, PSR_PIL, %g0
- bne 1f
- st %g5, [%g1]
+ st %g5, [%g1]
#endif
wr %g3, 0x0, %psr
nop; nop; nop
-1:
jmpl %o7, %g0
mov %g4, %o7
@@ -92,12 +78,10 @@ ___clear_bit:
.globl ___change_bit
___change_bit:
rd %psr, %g3
- andcc %g3, PSR_PIL, %g0
- bne 1f
- nop
- wr %g3, PSR_PIL, %psr
nop; nop; nop
-1:
+ or %g3, PSR_PIL, %g5
+ wr %g5, 0x0, %psr
+ nop; nop; nop
#ifdef __SMP__
set C_LABEL(bitops_spinlock), %g5
2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
@@ -110,17 +94,12 @@ ___change_bit:
#ifdef __SMP__
st %g5, [%g1]
set C_LABEL(bitops_spinlock), %g5
- andcc %g3, PSR_PIL, %g0
- bne 1f
- stb %g0, [%g5]
+ stb %g0, [%g5]
#else
- andcc %g3, PSR_PIL, %g0
- bne 1f
- st %g5, [%g1]
+ st %g5, [%g1]
#endif
wr %g3, 0x0, %psr
nop; nop; nop
-1:
jmpl %o7, %g0
mov %g4, %o7
@@ -128,12 +107,10 @@ ___change_bit:
.globl ___set_le_bit
___set_le_bit:
rd %psr, %g3
- andcc %g3, PSR_PIL, %g0
- bne 1f
- nop
- wr %g3, PSR_PIL, %psr
nop; nop; nop
-1:
+ or %g3, PSR_PIL, %g5
+ wr %g5, 0x0, %psr
+ nop; nop; nop
#ifdef __SMP__
set C_LABEL(bitops_spinlock), %g5
2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
@@ -146,29 +123,22 @@ ___set_le_bit:
#ifdef __SMP__
stb %g5, [%g1]
set C_LABEL(bitops_spinlock), %g5
- andcc %g3, PSR_PIL, %g0
- bne 1f
- stb %g0, [%g5]
+ stb %g0, [%g5]
#else
- andcc %g3, PSR_PIL, %g0
- bne 1f
- stb %g5, [%g1]
+ stb %g5, [%g1]
#endif
wr %g3, 0x0, %psr
nop; nop; nop
-1:
jmpl %o7, %g0
mov %g4, %o7
.globl ___clear_le_bit
___clear_le_bit:
rd %psr, %g3
- andcc %g3, PSR_PIL, %g0
- bne 1f
- nop
- wr %g3, PSR_PIL, %psr
nop; nop; nop
-1:
+ or %g3, PSR_PIL, %g5
+ wr %g5, 0x0, %psr
+ nop; nop; nop
#ifdef __SMP__
set C_LABEL(bitops_spinlock), %g5
2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP.
@@ -181,16 +151,11 @@ ___clear_le_bit:
#ifdef __SMP__
stb %g5, [%g1]
set C_LABEL(bitops_spinlock), %g5
- andcc %g3, PSR_PIL, %g0
- bne 1f
- stb %g0, [%g5]
+ stb %g0, [%g5]
#else
- andcc %g3, PSR_PIL, %g0
- bne 1f
- stb %g5, [%g1]
+ stb %g5, [%g1]
#endif
wr %g3, 0x0, %psr
nop; nop; nop
-1:
jmpl %o7, %g0
mov %g4, %o7
diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c
index 8f0941ebf..62313e4ae 100644
--- a/arch/sparc/lib/debuglocks.c
+++ b/arch/sparc/lib/debuglocks.c
@@ -1,12 +1,13 @@
-/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $
+/* $Id: debuglocks.c,v 1.7 1999/04/21 02:26:58 anton Exp $
* debuglocks.c: Debugging versions of SMP locking primitives.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
+ * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au)
*/
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/tasks.h> /* For NR_CPUS */
#include <asm/psr.h>
#include <asm/system.h>
#include <asm/spinlock.h>
@@ -28,29 +29,33 @@
static inline void show(char *str, spinlock_t *lock, unsigned long caller)
{
int cpu = smp_processor_id();
+ extern spinlock_t console_lock;
- printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
- lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
+ if (lock != &console_lock)
+ printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
+ lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
}
static inline void show_read(char *str, rwlock_t *lock, unsigned long caller)
{
int cpu = smp_processor_id();
- printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
+ printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", str,
lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
}
static inline void show_write(char *str, rwlock_t *lock, unsigned long caller)
{
int cpu = smp_processor_id();
+ int i;
+
+ printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)", str,
+ lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
+
+ for(i = 0; i < NR_CPUS; i++)
+ printk(" reader[i]=%08lx", lock->reader_pc[i]);
- printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx) reader[0]=%08lx reader[1]=%08lx reader[2]=%08lx reader[3]=%08lx\n",
- str, lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3,
- lock->reader_pc[0],
- lock->reader_pc[1],
- lock->reader_pc[2],
- lock->reader_pc[3]);
+ printk("\n");
}
#undef INIT_STUCK
@@ -103,9 +108,6 @@ void _do_spin_unlock(spinlock_t *lock)
lock->lock = 0;
}
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
void _do_read_lock(rwlock_t *rw, char *str)
{
unsigned long caller;
@@ -133,9 +135,6 @@ wlock_again:
rw->lock++;
}
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
void _do_read_unlock(rwlock_t *rw, char *str)
{
unsigned long caller;
@@ -163,9 +162,6 @@ wlock_again:
rw->lock -= 0x1ff;
}
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
void _do_write_lock(rwlock_t *rw, char *str)
{
unsigned long caller;
diff --git a/arch/sparc/lib/irqlock.S b/arch/sparc/lib/irqlock.S
index 23194e723..4c41e9825 100644
--- a/arch/sparc/lib/irqlock.S
+++ b/arch/sparc/lib/irqlock.S
@@ -1,4 +1,4 @@
-/* $Id: irqlock.S,v 1.4 1997/05/01 02:26:54 davem Exp $
+/* $Id: irqlock.S,v 1.5 1999/04/20 13:22:37 anton Exp $
* irqlock.S: High performance IRQ global locking and interrupt entry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -10,69 +10,6 @@
.text
.align 4
- /* This is incredibly insane... */
- .globl ___irq_enter
-___irq_enter:
- sethi %hi(local_irq_count), %g2
- sll %g1, 2, %g1
- or %g2, %lo(local_irq_count), %g2
- ld [%g2 + %g1], %g3
- sethi %hi(global_irq_count), %g5
- add %g3, 1, %g3
- or %g5, %lo(global_irq_count), %g5
- st %g3, [%g2 + %g1]
-1:
- ldstub [%g5 + 3], %g2
- orcc %g2, 0x0, %g0
- bne 1b
- ld [%g5], %g3
- sra %g3, 8, %g3
- add %g3, 1, %g3
- sll %g3, 8, %g3
- st %g3, [%g5]
- sethi %hi(global_irq_lock), %g1
- ldub [%g1 + %lo(global_irq_lock)], %g2
-1:
- orcc %g2, 0x0, %g0
- bne,a 1b
- ldub [%g1 + %lo(global_irq_lock)], %g2
-___irq_enter_out:
- jmpl %o7, %g0
- mov %g4, %o7
-
- .globl ___irq_exit
-___irq_exit:
- rd %psr, %g3
- sethi %hi(global_irq_count), %g1
- or %g3, PSR_PIL, %g3
- or %g1, %lo(global_irq_count), %g1
- wr %g3, 0x0, %psr
- sethi %hi(local_irq_count), %g2
- sll %g7, 2, %g7
- or %g2, %lo(local_irq_count), %g2
- ld [%g2 + %g7], %g3
-1:
- ldstub [%g1 + 3], %g5
- orcc %g5, 0x0, %g0
- bne 1b
- ld [%g1], %g5
- sra %g5, 8, %g5
- sub %g5, 1, %g5
- sll %g5, 8, %g5
- st %g5, [%g1]
- sub %g3, 1, %g3
- sethi %hi(global_irq_holder), %g1
- st %g3, [%g2 + %g7]
- srl %g7, 2, %g7
- ldub [%g1 + %lo(global_irq_holder)], %g5
- cmp %g5, %g7
- bne ___irq_enter_out
- mov NO_PROC_ID, %g2
- stb %g2, [%g1 + %lo(global_irq_holder)]
- sethi %hi(global_irq_lock), %g5
- b ___irq_enter_out
- stb %g0, [%g5 + %lo(global_irq_lock)]
-
/* Weird calling conventions... %g7=flags, %g4=%prev_o7
* Very clever for the __global_sti case, the inline which
* gets us here clears %g7 and it just works.
diff --git a/arch/sparc/lib/lshrdi3.S b/arch/sparc/lib/lshrdi3.S
new file mode 100644
index 000000000..f5300a1c8
--- /dev/null
+++ b/arch/sparc/lib/lshrdi3.S
@@ -0,0 +1,29 @@
+/* $Id: lshrdi3.S,v 1.1 1999/03/21 06:37:45 davem Exp $ */
+
+#include <asm/cprefix.h>
+
+ .globl C_LABEL(__lshrdi3)
+C_LABEL(__lshrdi3):
+ cmp %o2, 0
+ be 3f
+ mov 0x20, %g2
+
+ sub %g2, %o2, %g2
+ cmp %g2, 0
+ bg 1f
+ srl %o0, %o2, %o4
+
+ clr %o4
+ neg %g2
+ b 2f
+ srl %o0, %g2, %o5
+1:
+ sll %o0, %g2, %g3
+ srl %o1, %o2, %g2
+ or %g2, %g3, %o5
+2:
+ mov %o4, %o0
+ mov %o5, %o1
+3:
+ retl
+ nop
diff --git a/arch/sparc/math-emu/fabss.c b/arch/sparc/math-emu/fabss.c
index accfd4f59..5429cc733 100644
--- a/arch/sparc/math-emu/fabss.c
+++ b/arch/sparc/math-emu/fabss.c
@@ -2,5 +2,5 @@ int FABSS(unsigned long *rd, unsigned long *rs2)
{
/* Clear the sign bit (high bit of word 0) */
rd[0] = rs2[0] & 0x7fffffffUL;
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fcmpd.c b/arch/sparc/math-emu/fcmpd.c
index 3a9926575..8adb30d88 100644
--- a/arch/sparc/math-emu/fcmpd.c
+++ b/arch/sparc/math-emu/fcmpd.c
@@ -14,5 +14,5 @@ int FCMPD(void *rd, void *rs2, void *rs1)
ret = 2;
*fsr = (*fsr & ~0xc00) | (ret << 10);
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fcmped.c b/arch/sparc/math-emu/fcmped.c
index a8c188042..2033b1dc8 100644
--- a/arch/sparc/math-emu/fcmped.c
+++ b/arch/sparc/math-emu/fcmped.c
@@ -14,5 +14,5 @@ int FCMPED(void *rd, void *rs2, void *rs1)
ret = 2;
*fsr = (*fsr & ~0xc00) | (ret << 10);
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fcmpeq.c b/arch/sparc/math-emu/fcmpeq.c
index c109c51ce..de99bf343 100644
--- a/arch/sparc/math-emu/fcmpeq.c
+++ b/arch/sparc/math-emu/fcmpeq.c
@@ -14,5 +14,5 @@ int FCMPEQ(void *rd, void *rs2, void *rs1)
fsr = *(unsigned long *)rd;
fsr &= ~0xc00; fsr |= (ret << 10);
*(unsigned long *)rd = fsr;
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fcmpes.c b/arch/sparc/math-emu/fcmpes.c
index e20884cfd..a078a1243 100644
--- a/arch/sparc/math-emu/fcmpes.c
+++ b/arch/sparc/math-emu/fcmpes.c
@@ -14,5 +14,5 @@ int FCMPES(void *rd, void *rs2, void *rs1)
ret = 2;
*fsr = (*fsr & ~0xc00) | (ret << 10);
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fcmpq.c b/arch/sparc/math-emu/fcmpq.c
index 549f02cae..f3d1b1233 100644
--- a/arch/sparc/math-emu/fcmpq.c
+++ b/arch/sparc/math-emu/fcmpq.c
@@ -14,5 +14,5 @@ int FCMPQ(void *rd, void *rs2, void *rs1)
fsr = *(unsigned long *)rd;
fsr &= ~0xc00; fsr |= (ret << 10);
*(unsigned long *)rd = fsr;
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fcmps.c b/arch/sparc/math-emu/fcmps.c
index 1b53312ae..7e273320f 100644
--- a/arch/sparc/math-emu/fcmps.c
+++ b/arch/sparc/math-emu/fcmps.c
@@ -14,5 +14,5 @@ int FCMPS(void *rd, void *rs2, void *rs1)
ret = 2;
*fsr = (*fsr & ~0xc00) | (ret << 10);
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fdmulq.c b/arch/sparc/math-emu/fdmulq.c
index 1d5bc5053..dd9c7953c 100644
--- a/arch/sparc/math-emu/fdmulq.c
+++ b/arch/sparc/math-emu/fdmulq.c
@@ -11,6 +11,5 @@ int FDMULQ(void *rd, void *rs2, void *rs1)
__FP_UNPACK_D(IN, rs2);
FP_CONV(Q,D,4,2,B,IN);
FP_MUL_Q(R, A, B);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc/math-emu/fdtoq.c b/arch/sparc/math-emu/fdtoq.c
index 84ebcf4a2..7b7746821 100644
--- a/arch/sparc/math-emu/fdtoq.c
+++ b/arch/sparc/math-emu/fdtoq.c
@@ -8,6 +8,5 @@ int FDTOQ(void *rd, void *rs2)
__FP_UNPACK_D(A, rs2);
FP_CONV(Q,D,4,2,R,A);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc/math-emu/fdtos.c b/arch/sparc/math-emu/fdtos.c
index 83b8a14ed..612434c40 100644
--- a/arch/sparc/math-emu/fdtos.c
+++ b/arch/sparc/math-emu/fdtos.c
@@ -8,6 +8,5 @@ int FDTOS(void *rd, void *rs2)
__FP_UNPACK_D(A, rs2);
FP_CONV(S,D,1,2,R,A);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc/math-emu/fnegs.c b/arch/sparc/math-emu/fnegs.c
index 1c662f201..26a90d778 100644
--- a/arch/sparc/math-emu/fnegs.c
+++ b/arch/sparc/math-emu/fnegs.c
@@ -2,5 +2,5 @@ int FNEGS(unsigned long *rd, unsigned long *rs2)
{
/* just change the sign bit */
rd[0] = rs2[0] ^ 0x80000000UL;
- return 1;
+ return 0;
}
diff --git a/arch/sparc/math-emu/fqtod.c b/arch/sparc/math-emu/fqtod.c
index dc5b6f9aa..62a437e31 100644
--- a/arch/sparc/math-emu/fqtod.c
+++ b/arch/sparc/math-emu/fqtod.c
@@ -8,6 +8,5 @@ int FQTOD(void *rd, void *rs2)
__FP_UNPACK_Q(A, rs2);
FP_CONV(D,Q,2,4,R,A);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc/math-emu/fqtos.c b/arch/sparc/math-emu/fqtos.c
index 608f57be0..2520affbf 100644
--- a/arch/sparc/math-emu/fqtos.c
+++ b/arch/sparc/math-emu/fqtos.c
@@ -8,6 +8,5 @@ int FQTOS(void *rd, void *rs2)
__FP_UNPACK_Q(A, rs2);
FP_CONV(S,Q,1,4,R,A);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc/math-emu/fsmuld.c b/arch/sparc/math-emu/fsmuld.c
index dead5a042..b7b992818 100644
--- a/arch/sparc/math-emu/fsmuld.c
+++ b/arch/sparc/math-emu/fsmuld.c
@@ -11,6 +11,5 @@ int FSMULD(void *rd, void *rs2, void *rs1)
__FP_UNPACK_S(IN, rs2);
FP_CONV(D,S,2,1,B,IN);
FP_MUL_D(R, A, B);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc/math-emu/fstod.c b/arch/sparc/math-emu/fstod.c
index cb34329c9..ea73660d8 100644
--- a/arch/sparc/math-emu/fstod.c
+++ b/arch/sparc/math-emu/fstod.c
@@ -8,6 +8,5 @@ int FSTOD(void *rd, void *rs2)
__FP_UNPACK_S(A, rs2);
FP_CONV(D,S,2,1,R,A);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc/math-emu/fstoq.c b/arch/sparc/math-emu/fstoq.c
index 081c4d4d0..7d201310c 100644
--- a/arch/sparc/math-emu/fstoq.c
+++ b/arch/sparc/math-emu/fstoq.c
@@ -8,6 +8,5 @@ int FSTOQ(void *rd, void *rs2)
__FP_UNPACK_S(A, rs2);
FP_CONV(Q,S,4,1,R,A);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc/math-emu/math.c b/arch/sparc/math-emu/math.c
index df5c879c5..68ccb932a 100644
--- a/arch/sparc/math-emu/math.c
+++ b/arch/sparc/math-emu/math.c
@@ -124,6 +124,7 @@
#include <linux/mm.h>
#include <asm/uaccess.h>
+#include "soft-fp.h"
#define FLOATFUNC(x) extern int x(void *,void *,void *)
@@ -189,6 +190,13 @@ FLOATFUNC(FNEGS); /* v6 */
FLOATFUNC(FITOS); /* v6 */
FLOATFUNC(FITOD); /* v6 */
+#define FSR_TEM_SHIFT 23UL
+#define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT)
+#define FSR_AEXC_SHIFT 5UL
+#define FSR_AEXC_MASK (0x1fUL << FSR_AEXC_SHIFT)
+#define FSR_CEXC_SHIFT 0UL
+#define FSR_CEXC_MASK (0x1fUL << FSR_CEXC_SHIFT)
+
static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);
/* Unlike the Sparc64 version (which has a struct fpustate), we
@@ -254,12 +262,85 @@ int do_mathemu(struct pt_regs *regs, struct task_struct *fpt)
break;
}
/* Now empty the queue and clear the queue_not_empty flag */
- fpt->tss.fsr &= ~0x3000;
+ if(retcode)
+ fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK);
+ else
+ fpt->tss.fsr &= ~0x3000;
fpt->tss.fpqdepth = 0;
return retcode;
}
+/* All routines returning an exception to raise should detect
+ * such exceptions _before_ rounding to be consistant with
+ * the behavior of the hardware in the implemented cases
+ * (and thus with the recommendations in the V9 architecture
+ * manual).
+ *
+ * We return 0 if a SIGFPE should be sent, 1 otherwise.
+ */
+static int record_exception(unsigned long *pfsr, int eflag)
+{
+ unsigned long fsr = *pfsr;
+ int would_trap;
+
+ /* Determine if this exception would have generated a trap. */
+ would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL;
+
+ /* If trapping, we only want to signal one bit. */
+ if(would_trap != 0) {
+ eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
+ if((eflag & (eflag - 1)) != 0) {
+ if(eflag & EFLAG_INVALID)
+ eflag = EFLAG_INVALID;
+ else if(eflag & EFLAG_DIVZERO)
+ eflag = EFLAG_DIVZERO;
+ else if(eflag & EFLAG_INEXACT)
+ eflag = EFLAG_INEXACT;
+ }
+ }
+
+ /* Set CEXC, here are the rules:
+ *
+ * 1) In general all FPU ops will set one and only one
+ * bit in the CEXC field, this is always the case
+ * when the IEEE exception trap is enabled in TEM.
+ *
+ * 2) As a special case, if an overflow or underflow
+ * is being signalled, AND the trap is not enabled
+ * in TEM, then the inexact field shall also be set.
+ */
+ fsr &= ~(FSR_CEXC_MASK);
+ if(would_trap ||
+ (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) {
+ fsr |= ((long)eflag << FSR_CEXC_SHIFT);
+ } else {
+ fsr |= (((long)eflag << FSR_CEXC_SHIFT) |
+ (EFLAG_INEXACT << FSR_CEXC_SHIFT));
+ }
+
+ /* Set the AEXC field, rules are:
+ *
+ * 1) If a trap would not be generated, the
+ * CEXC just generated is OR'd into the
+ * existing value of AEXC.
+ *
+ * 2) When a trap is generated, AEXC is cleared.
+ */
+ if(would_trap == 0)
+ fsr |= ((long)eflag << FSR_AEXC_SHIFT);
+ else
+ fsr &= ~(FSR_AEXC_MASK);
+
+ /* If trapping, indicate fault trap type IEEE. */
+ if(would_trap != 0)
+ fsr |= (1UL << 14);
+
+ *pfsr = fsr;
+
+ return (would_trap ? 0 : 1);
+}
+
static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs)
{
/* Emulate the given insn, updating fsr and fregs appropriately. */
@@ -270,7 +351,7 @@ static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs)
* (this field not used on sparc32 code, as we can't
* extract trap type info for ops on the FP queue)
*/
- int freg;
+ int freg, eflag;
int (*func)(void *,void *,void *) = NULL;
void *rs1 = NULL, *rs2 = NULL, *rd = NULL;
@@ -411,6 +492,8 @@ static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs)
#ifdef DEBUG_MATHEMU
printk("executing insn...\n");
#endif
- func(rd, rs2, rs1); /* do the Right Thing */
- return 1; /* success! */
+ eflag = func(rd, rs2, rs1); /* do the Right Thing */
+ if(eflag == 0)
+ return 1; /* success! */
+ return record_exception(fsr, eflag);
}
diff --git a/arch/sparc/math-emu/sfp-machine.h b/arch/sparc/math-emu/sfp-machine.h
index eafad4273..67a74580c 100644
--- a/arch/sparc/math-emu/sfp-machine.h
+++ b/arch/sparc/math-emu/sfp-machine.h
@@ -115,16 +115,6 @@
X##_s = _flo->bits.sign; \
} while (0)
-#define __FP_PACK_RAW_1(fs, val, X) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- _flo->bits.frac = X##_f; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } while (0)
-
#define __FP_UNPACK_RAW_2(fs, X, val) \
do { \
union _FP_UNION_##fs *_flo = \
@@ -136,17 +126,6 @@
X##_s = _flo->bits.sign; \
} while (0)
-#define __FP_PACK_RAW_2(fs, val, X) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- _flo->bits.frac0 = X##_f0; \
- _flo->bits.frac1 = X##_f1; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } while (0)
-
#define __FP_UNPACK_RAW_4(fs, X, val) \
do { \
union _FP_UNION_##fs *_flo = \
@@ -160,55 +139,103 @@
X##_s = _flo->bits.sign; \
} while (0)
-#define __FP_PACK_RAW_4(fs, val, X) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- _flo->bits.frac0 = X##_f[0]; \
- _flo->bits.frac1 = X##_f[1]; \
- _flo->bits.frac2 = X##_f[2]; \
- _flo->bits.frac3 = X##_f[3]; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } while (0)
-
#define __FP_UNPACK_S(X,val) \
do { \
__FP_UNPACK_RAW_1(S,X,val); \
_FP_UNPACK_CANONICAL(S,1,X); \
} while (0)
-#define __FP_PACK_S(val,X) \
- do { \
- _FP_PACK_CANONICAL(S,1,X); \
- __FP_PACK_RAW_1(S,val,X); \
- } while (0)
-
#define __FP_UNPACK_D(X,val) \
do { \
__FP_UNPACK_RAW_2(D,X,val); \
_FP_UNPACK_CANONICAL(D,2,X); \
} while (0)
-#define __FP_PACK_D(val,X) \
- do { \
- _FP_PACK_CANONICAL(D,2,X); \
- __FP_PACK_RAW_2(D,val,X); \
- } while (0)
-
#define __FP_UNPACK_Q(X,val) \
do { \
__FP_UNPACK_RAW_4(Q,X,val); \
_FP_UNPACK_CANONICAL(Q,4,X); \
} while (0)
-#define __FP_PACK_Q(val,X) \
- do { \
- _FP_PACK_CANONICAL(Q,4,X); \
- __FP_PACK_RAW_4(Q,val,X); \
+#define __FP_PACK_RAW_1(fs, val, X) \
+ do { \
+ union _FP_UNION_##fs *_flo = \
+ (union _FP_UNION_##fs *)val; \
+ \
+ _flo->bits.frac = X##_f; \
+ _flo->bits.exp = X##_e; \
+ _flo->bits.sign = X##_s; \
+ } while (0)
+
+#define __FP_PACK_RAW_2(fs, val, X) \
+ do { \
+ union _FP_UNION_##fs *_flo = \
+ (union _FP_UNION_##fs *)val; \
+ \
+ _flo->bits.frac0 = X##_f0; \
+ _flo->bits.frac1 = X##_f1; \
+ _flo->bits.exp = X##_e; \
+ _flo->bits.sign = X##_s; \
} while (0)
+#define __FP_PACK_RAW_4(fs, val, X) \
+ do { \
+ union _FP_UNION_##fs *_flo = \
+ (union _FP_UNION_##fs *)val; \
+ \
+ _flo->bits.frac0 = X##_f[0]; \
+ _flo->bits.frac1 = X##_f[1]; \
+ _flo->bits.frac2 = X##_f[2]; \
+ _flo->bits.frac3 = X##_f[3]; \
+ _flo->bits.exp = X##_e; \
+ _flo->bits.sign = X##_s; \
+ } while (0)
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+/* We only actually write to the destination register
+ * if exceptions signalled (if any) will not trap.
+ */
+#ifdef __SMP__
+#define __FPU_TEM \
+ (((current->tss.fsr)>>23)&0x1f)
+#else
+extern struct task_struct *last_task_used_math;
+#define __FPU_TEM \
+ (((last_task_used_math->tss.fsr)>>23)&0x1f)
+#endif
+#define __FPU_TRAP_P(bits) \
+ ((__FPU_TEM & (bits)) != 0)
+
+#define __FP_PACK_S(val,X) \
+({ int __exc = _FP_PACK_CANONICAL(S,1,X); \
+ if(!__exc || !__FPU_TRAP_P(__exc)) \
+ __FP_PACK_RAW_1(S,val,X); \
+ __exc; \
+})
+
+#define __FP_PACK_D(val,X) \
+({ int __exc = _FP_PACK_CANONICAL(D,2,X); \
+ if(!__exc || !__FPU_TRAP_P(__exc)) \
+ __FP_PACK_RAW_2(D,val,X); \
+ __exc; \
+})
+
+#define __FP_PACK_Q(val,X) \
+({ int __exc = _FP_PACK_CANONICAL(Q,4,X); \
+ if(!__exc || !__FPU_TRAP_P(__exc)) \
+ __FP_PACK_RAW_4(Q,val,X); \
+ __exc; \
+})
+
+/* Obtain the current rounding mode. */
+#ifdef __SMP__
+#define FP_ROUNDMODE ((current->tss.fsr >> 30) & 0x3)
+#else
+#define FP_ROUNDMODE ((last_task_used_math->tss.fsr >> 30) & 0x3)
+#endif
+
/* the asm fragments go here: all these are taken from glibc-2.0.5's stdlib/longlong.h */
#include <linux/types.h>
@@ -361,3 +388,9 @@
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
+/* Exception flags. */
+#define EFLAG_INVALID (1 << 4)
+#define EFLAG_OVERFLOW (1 << 3)
+#define EFLAG_UNDERFLOW (1 << 2)
+#define EFLAG_DIVZERO (1 << 1)
+#define EFLAG_INEXACT (1 << 0)
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index ecb1943c3..76dbf643a 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.32 1998/08/16 16:02:25 ecd Exp $
+# $Id: Makefile,v 1.33 1999/01/02 16:45:47 davem Exp $
# Makefile for the linux Sparc-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 3c8ffbfae..a6110b886 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.96 1998/11/08 11:13:56 davem Exp $
+/* $Id: fault.c,v 1.101 1999/01/04 06:24:52 jj Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -13,11 +13,13 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/tasks.h>
+#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/signal.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -149,9 +151,7 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk,
(unsigned long) tsk->mm->context);
printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
(unsigned long) tsk->mm->pgd);
- lock_kernel();
die_if_kernel("Oops", regs);
- unlock_kernel();
}
asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
@@ -202,6 +202,13 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
if(text_fault)
address = regs->pc;
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_interrupt() || mm == &init_mm)
+ goto do_kernel_fault;
+
down(&mm->mmap_sem);
/* The kernel referencing a bad kernel pointer can lock up
* a sun4c machine completely, so we must attempt recovery.
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 391a4dedb..4652e4fe6 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.60 1998/09/13 04:30:31 davem Exp $
+/* $Id: init.c,v 1.65 1999/04/09 16:28:03 davem Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -37,6 +37,8 @@
extern void show_net_buffers(void);
+unsigned long *sparc_valid_addr_bitmap;
+
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
unsigned long sparc_unmapped_base;
@@ -215,16 +217,20 @@ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long e
unsigned long limit = base + sp_banks[tmp2].num_bytes;
if((phys_addr >= base) && (phys_addr < limit) &&
- ((phys_addr + PAGE_SIZE) < limit))
+ ((phys_addr + PAGE_SIZE) < limit)) {
mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
+ set_bit(MAP_NR(addr) >> 8, sparc_valid_addr_bitmap);
+ }
}
}
} else {
if((sparc_cpu_model == sun4m) || (sparc_cpu_model == sun4d)) {
srmmu_frob_mem_map(start_mem);
} else {
- for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE)
+ for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE) {
mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
+ set_bit(MAP_NR(addr) >> 8, sparc_valid_addr_bitmap);
+ }
}
}
}
@@ -234,6 +240,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
int codepages = 0;
int datapages = 0;
int initpages = 0;
+ int i;
unsigned long addr;
struct page *page, *end;
@@ -243,6 +250,12 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
end_mem &= PAGE_MASK;
max_mapnr = MAP_NR(end_mem);
high_memory = (void *) end_mem;
+
+ sparc_valid_addr_bitmap = (unsigned long *)start_mem;
+ i = max_mapnr >> (8 + 5);
+ i += 1;
+ memset(sparc_valid_addr_bitmap, 0, i << 2);
+ start_mem += i << 2;
start_mem = PAGE_ALIGN(start_mem);
num_physpages = 0;
@@ -255,6 +268,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
else
#endif
mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
+ set_bit(MAP_NR(addr) >> 8, sparc_valid_addr_bitmap);
addr += PAGE_SIZE;
}
@@ -266,6 +280,9 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
if (PageSkip(page)) {
unsigned long low, high;
+ /* See srmmu_frob_mem_map() for why this is done. -DaveM */
+ page++;
+
low = PAGE_ALIGN((unsigned long)(page+1));
if (page->next_hash < page)
high = ((unsigned long)end) & PAGE_MASK;
@@ -313,11 +330,18 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
initpages << (PAGE_SHIFT-10),
(unsigned long)PAGE_OFFSET, end_mem);
- freepages.min = nr_free_pages >> 7;
- if(freepages.min < 16)
- freepages.min = 16;
- freepages.low = freepages.min + (freepages.min >> 1);
- freepages.high = freepages.min + freepages.min;
+ /* NOTE NOTE NOTE NOTE
+ * Please keep track of things and make sure this
+ * always matches the code in mm/page_alloc.c -DaveM
+ */
+ i = nr_free_pages >> 7;
+ if (i < 48)
+ i = 48;
+ if (i > 256)
+ i = 256;
+ freepages.min = i;
+ freepages.low = i << 1;
+ freepages.high = freepages.low + i;
}
void free_initmem (void)
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index c7c6bdd5f..a0f92ea79 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.9 1998/04/15 14:58:37 jj Exp $
+/* $Id: iommu.c,v 1.10 1999/05/07 17:03:34 jj Exp $
* iommu.c: IOMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -51,8 +51,7 @@ iommu_init(int iommund, struct linux_sbus *sbus))
unsigned long tmp;
struct iommu_struct *iommu;
struct linux_prom_registers iommu_promregs[PROMREG_MAX];
- int i, j, k, l, m;
- struct iommu_alloc { unsigned long addr; int next; } *ia;
+ int i;
iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
prom_getproperty(iommund, "reg", (void *) iommu_promregs,
@@ -97,62 +96,18 @@ iommu_init(int iommund, struct linux_sbus *sbus))
ptsize = (ptsize >> PAGE_SHIFT) * sizeof(iopte_t);
/* Stupid alignment constraints give me a headache.
- We want to get very large aligned memory area, larger than
- maximum what get_free_pages gives us (128K): we need
- 256K or 512K or 1M or 2M aligned to its size. */
- ia = (struct iommu_alloc *) kmalloc (sizeof(struct iommu_alloc) * 128, GFP_ATOMIC);
- for (i = 0; i < 128; i++) {
- ia[i].addr = 0;
- ia[i].next = -1;
- }
- k = 0;
- for (i = 0; i < 128; i++) {
- ia[i].addr = __get_free_pages(GFP_DMA, 5);
- if (ia[i].addr <= ia[k].addr) {
- if (i) {
- ia[i].next = k;
- k = i;
- }
- } else {
- for (m = k, l = ia[k].next; l != -1; m = l, l = ia[l].next)
- if (ia[i].addr <= ia[l].addr) {
- ia[i].next = l;
- ia[m].next = i;
- }
- if (l == -1)
- ia[m].next = i;
- }
- for (m = -1, j = 0, l = k; l != -1; l = ia[l].next) {
- if (!(ia[l].addr & (ptsize - 1))) {
- tmp = ia[l].addr;
- m = l;
- j = 128 * 1024;
- } else if (m != -1) {
- if (ia[l].addr != tmp + j)
- m = -1;
- else {
- j += 128 * 1024;
- if (j == ptsize) {
- break;
- }
- }
- }
- }
- if (l != -1)
+ We need 256K or 512K or 1M or 2M area aligned to
+ its size and current gfp will fortunately give
+ it to us. */
+ for (i = 6; i < 9; i++)
+ if ((1 << (i + PAGE_SHIFT)) == ptsize)
break;
- }
- if (i == 128) {
+ tmp = __get_free_pages(GFP_DMA, i);
+ if (!tmp) {
prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize);
prom_halt();
}
- for (l = m, j = 0; j < ptsize; j += 128 * 1024, l = ia[l].next)
- ia[l].addr = 0;
- for (l = k; l != -1; l = ia[l].next)
- if (ia[l].addr)
- free_pages(ia[l].addr, 5);
- kfree (ia);
iommu->lowest = iommu->page_table = (iopte_t *)tmp;
-
/* Initialize new table. */
flush_cache_all();
diff --git a/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
index f82599f42..b87b2bdeb 100644
--- a/arch/sparc/mm/nosrmmu.c
+++ b/arch/sparc/mm/nosrmmu.c
@@ -1,4 +1,4 @@
-/* $Id: nosrmmu.c,v 1.1 1998/03/09 14:04:15 jj Exp $
+/* $Id: nosrmmu.c,v 1.2 1999/03/30 10:17:39 jj Exp $
* nosrmmu.c: This file is a bunch of dummies for sun4 compiles,
* so that it does not need srmmu and avoid ifdefs.
*
@@ -48,3 +48,13 @@ __initfunc(void srmmu_end_memory(unsigned long memory_size, unsigned long *mem_e
{
return 0;
}
+
+__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size)
+{
+ return 0;
+}
+
+__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus)
+{
+ return 0;
+}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index d94fd4083..5b63aa11a 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.175 1998/08/28 18:57:31 zaitcev Exp $
+/* $Id: srmmu.c,v 1.187 1999/04/28 17:00:45 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -12,7 +12,9 @@
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
#include <linux/init.h>
+#include <linux/blk.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -216,24 +218,36 @@ __initfunc(void srmmu_frob_mem_map(unsigned long start_mem))
mem_map[MAP_NR(pg1)].flags &= ~(1<<PG_reserved);
mem_map[MAP_NR(pg2)].flags &= ~(1<<PG_reserved);
mem_map[MAP_NR(pg3)].flags &= ~(1<<PG_reserved);
-
+
start_mem = PAGE_ALIGN(start_mem);
for(i = 0; srmmu_map[i].size; i++) {
bank_start = srmmu_map[i].vbase;
- if (i && bank_start - bank_end > 2 * PAGE_SIZE) {
+ /* Making a one or two pages PG_skip holes
+ * is not necessary. We add one more because
+ * we must set the PG_skip flag on the first
+ * two mem_map[] entries for the hole. Go and
+ * see the mm/filemap.c:shrink_mmap() loop for
+ * details. -DaveM
+ */
+ if (i && bank_start - bank_end > 3 * PAGE_SIZE) {
mem_map[MAP_NR(bank_end)].flags |= (1<<PG_skip);
mem_map[MAP_NR(bank_end)].next_hash = mem_map + MAP_NR(bank_start);
+ mem_map[MAP_NR(bank_end)+1UL].flags |= (1<<PG_skip);
+ mem_map[MAP_NR(bank_end)+1UL].next_hash = mem_map + MAP_NR(bank_start);
PGSKIP_DEBUG(MAP_NR(bank_end), MAP_NR(bank_start));
if (bank_end > KERNBASE && bank_start < KERNBASE) {
mem_map[0].flags |= (1<<PG_skip);
mem_map[0].next_hash = mem_map + MAP_NR(bank_start);
+ mem_map[1].flags |= (1<<PG_skip);
+ mem_map[1].next_hash = mem_map + MAP_NR(bank_start);
PGSKIP_DEBUG(0, MAP_NR(bank_start));
}
}
bank_end = bank_start + srmmu_map[i].size;
while(bank_start < bank_end) {
+ set_bit(MAP_NR(bank_start) >> 8, sparc_valid_addr_bitmap);
if((bank_start >= KERNBASE) &&
(bank_start < start_mem)) {
bank_start += PAGE_SIZE;
@@ -250,14 +264,19 @@ __initfunc(void srmmu_frob_mem_map(unsigned long start_mem))
if (bank_end < KERNBASE) {
mem_map[MAP_NR(bank_end)].flags |= (1<<PG_skip);
mem_map[MAP_NR(bank_end)].next_hash = mem_map + MAP_NR(KERNBASE);
+ mem_map[MAP_NR(bank_end)+1UL].flags |= (1<<PG_skip);
+ mem_map[MAP_NR(bank_end)+1UL].next_hash = mem_map + MAP_NR(KERNBASE);
PGSKIP_DEBUG(MAP_NR(bank_end), MAP_NR(KERNBASE));
} else if (MAP_NR(bank_end) < max_mapnr) {
mem_map[MAP_NR(bank_end)].flags |= (1<<PG_skip);
+ mem_map[MAP_NR(bank_end)+1UL].flags |= (1<<PG_skip);
if (mem_map[0].flags & (1 << PG_skip)) {
mem_map[MAP_NR(bank_end)].next_hash = mem_map[0].next_hash;
+ mem_map[MAP_NR(bank_end)+1UL].next_hash = mem_map[0].next_hash;
PGSKIP_DEBUG(MAP_NR(bank_end), mem_map[0].next_hash - mem_map);
} else {
mem_map[MAP_NR(bank_end)].next_hash = mem_map;
+ mem_map[MAP_NR(bank_end)+1UL].next_hash = mem_map;
PGSKIP_DEBUG(MAP_NR(bank_end), 0);
}
}
@@ -447,7 +466,8 @@ static inline pte_t *srmmu_s_pte_offset(pmd_t * dir, unsigned long address)
/* This must update the context table entry for this process. */
static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
{
- if(tsk->mm->context != NO_CONTEXT) {
+ if(tsk->mm->context != NO_CONTEXT &&
+ tsk->mm->pgd != pgdp) {
flush_cache_mm(tsk->mm);
ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
flush_tlb_mm(tsk->mm);
@@ -800,9 +820,7 @@ static void srmmu_switch_to_context(struct task_struct *tsk)
{
if(tsk->mm->context == NO_CONTEXT) {
alloc_context(tsk->mm);
- flush_cache_mm(tsk->mm);
ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
- flush_tlb_mm(tsk->mm);
}
srmmu_set_context(tsk->mm->context);
}
@@ -1273,6 +1291,12 @@ extern void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end);
extern void viking_flush_tlb_page(struct vm_area_struct *vma,
unsigned long page);
+extern void sun4dsmp_flush_tlb_all(void);
+extern void sun4dsmp_flush_tlb_mm(struct mm_struct *mm);
+extern void sun4dsmp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+extern void sun4dsmp_flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long page);
/* hypersparc.S */
extern void hypersparc_flush_cache_all(void);
@@ -1311,7 +1335,8 @@ static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
if(pgdp != swapper_pg_dir)
hypersparc_flush_page_to_ram(page);
- if(tsk->mm->context != NO_CONTEXT) {
+ if(tsk->mm->context != NO_CONTEXT &&
+ tsk->mm->pgd != pgdp) {
flush_cache_mm(tsk->mm);
ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
flush_tlb_mm(tsk->mm);
@@ -1320,11 +1345,13 @@ static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
static void viking_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
{
- viking_flush_page((unsigned long)pgdp);
- if(tsk->mm->context != NO_CONTEXT) {
- flush_cache_mm(current->mm);
+ if(pgdp != swapper_pg_dir)
+ flush_chunk((unsigned long)pgdp);
+ if(tsk->mm->context != NO_CONTEXT &&
+ tsk->mm->pgd != pgdp) {
+ flush_cache_mm(tsk->mm);
ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
- flush_tlb_mm(current->mm);
+ flush_tlb_mm(tsk->mm);
}
}
@@ -1334,6 +1361,9 @@ static void cypress_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
unsigned long line;
+ if(pgdp == swapper_pg_dir)
+ goto skip_flush;
+
a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
page &= PAGE_MASK;
line = (page + PAGE_SIZE) - 0x100;
@@ -1354,11 +1384,12 @@ static void cypress_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
"r" (a), "r" (b), "r" (c), "r" (d),
"r" (e), "r" (f), "r" (g));
} while(line != page);
-
- if(tsk->mm->context != NO_CONTEXT) {
- flush_cache_mm(current->mm);
+skip_flush:
+ if(tsk->mm->context != NO_CONTEXT &&
+ tsk->mm->pgd != pgdp) {
+ flush_cache_mm(tsk->mm);
ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
- flush_tlb_mm(current->mm);
+ flush_tlb_mm(tsk->mm);
}
}
@@ -1386,9 +1417,10 @@ static void hypersparc_init_new_context(struct mm_struct *mm)
srmmu_set_entry((pte_t *)ctxp, __pte((SRMMU_ET_PTD | (srmmu_v2p((unsigned long) mm->pgd) >> 4))));
hypersparc_flush_page_to_ram((unsigned long)ctxp);
- hyper_flush_whole_icache();
- if(mm == current->mm)
+ if(mm == current->mm) {
+ hyper_flush_whole_icache();
srmmu_set_context(mm->context);
+ }
}
static unsigned long mempool;
@@ -1917,12 +1949,13 @@ __initfunc(unsigned long srmmu_paging_init(unsigned long start_mem, unsigned lon
/* Find the number of contexts on the srmmu. */
cpunode = prom_getchild(prom_root_node);
num_contexts = 0;
- while((cpunode = prom_getsibling(cpunode)) != 0) {
+ while(cpunode != 0) {
prom_getstring(cpunode, "device_type", node_str, sizeof(node_str));
if(!strcmp(node_str, "cpu")) {
num_contexts = prom_getintdefault(cpunode, "mmu-nctx", 0x8);
break;
}
+ cpunode = prom_getsibling(cpunode);
}
}
@@ -1969,6 +2002,18 @@ __initfunc(unsigned long srmmu_paging_init(unsigned long start_mem, unsigned lon
start_mem = sparc_context_init(start_mem, num_contexts);
start_mem = free_area_init(start_mem, end_mem);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* If initial ramdisk was specified with physical address,
+ translate it here, as the p2v translation in srmmu
+ is not straightforward. */
+ if (initrd_start && initrd_start < KERNBASE) {
+ initrd_start = srmmu_p2v(initrd_start);
+ initrd_end = srmmu_p2v(initrd_end);
+ if (initrd_end <= initrd_start)
+ initrd_start = 0;
+ }
+#endif
return PAGE_ALIGN(start_mem);
}
@@ -1998,6 +2043,11 @@ static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long ad
static void srmmu_destroy_context(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
+ /* XXX This could be drastically improved.
+ * XXX We are only called from __exit_mm and it just did
+ * XXX cache/tlb mm flush and right after this will (re-)
+ * XXX SET_PAGE_DIR to swapper_pg_dir. -DaveM
+ */
flush_cache_mm(mm);
ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
flush_tlb_mm(mm);
@@ -2028,8 +2078,11 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
offset = (address & PAGE_MASK) - vma->vm_start;
vmaring = inode->i_mmap;
do {
- vaddr = vmaring->vm_start + offset;
+ /* Do not mistake ourselves as another mapping. */
+ if(vmaring == vma)
+ continue;
+ vaddr = vmaring->vm_start + offset;
if ((vaddr ^ address) & vac_badbits) {
alias_found++;
start = vmaring->vm_start;
@@ -2042,7 +2095,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
if(!ptep) goto next;
if((pte_val(*ptep) & SRMMU_ET_MASK) == SRMMU_VALID) {
-#if 1
+#if 0
printk("Fixing USER/USER alias [%ld:%08lx]\n",
vmaring->vm_mm->context, start);
#endif
@@ -2057,11 +2110,12 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
}
} while ((vmaring = vmaring->vm_next_share) != NULL);
- if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
+ if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) {
pgdp = srmmu_pgd_offset(vma->vm_mm, address);
- ptep = srmmu_pte_offset((pmd_t *) pgdp, address);
+ pmdp = srmmu_pmd_offset(pgdp, address);
+ ptep = srmmu_pte_offset(pmdp, address);
flush_cache_page(vma, address);
- *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
+ set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE)));
flush_tlb_page(vma, address);
}
done:
@@ -2652,15 +2706,8 @@ __initfunc(static void init_viking(void))
/* Ahhh, the viking. SRMMU VLSI abortion number two... */
if(mreg & VIKING_MMODE) {
- unsigned long bpreg;
-
srmmu_name = "TI Viking";
viking_mxcc_present = 0;
-
- bpreg = viking_get_bpreg();
- bpreg &= ~(VIKING_ACTION_MIX);
- viking_set_bpreg(bpreg);
-
msi_set_sync();
BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_viking, BTFIXUPCALL_NORM);
@@ -2691,16 +2738,25 @@ __initfunc(static void init_viking(void))
BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page_for_dma, BTFIXUPCALL_NOP);
}
- /* flush_cache_* are nops */
- BTFIXUPSET_CALL(flush_cache_all, viking_flush_cache_all, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_cache_mm, viking_flush_cache_mm, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NOP);
- BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NOP);
+ BTFIXUPSET_CALL(flush_cache_all, viking_flush_cache_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_mm, viking_flush_cache_mm, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM);
+#ifdef __SMP__
+ if (sparc_cpu_model == sun4d) {
+ BTFIXUPSET_CALL(flush_tlb_all, sun4dsmp_flush_tlb_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_mm, sun4dsmp_flush_tlb_mm, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_page, sun4dsmp_flush_tlb_page, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_range, sun4dsmp_flush_tlb_range, BTFIXUPCALL_NORM);
+ } else
+#endif
+ {
+ BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM);
+ }
BTFIXUPSET_CALL(flush_page_to_ram, viking_flush_page_to_ram, BTFIXUPCALL_NOP);
BTFIXUPSET_CALL(flush_sig_insns, viking_flush_sig_insns, BTFIXUPCALL_NOP);
@@ -3027,10 +3083,12 @@ __initfunc(void ld_mmu_srmmu(void))
BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM);
+ if (sparc_cpu_model != sun4d) {
+ BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM);
+ }
BTFIXUPSET_CALL(flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index fa8105d57..d6387d473 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.171 1998/09/21 05:05:41 jj Exp $
+/* $Id: sun4c.c,v 1.173 1999/01/17 02:20:37 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2688,6 +2688,10 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
unsigned long vaddr = vmaring->vm_start + offset;
unsigned long start;
+ /* Do not mistake ourselves as another mapping. */
+ if(vmaring == vma)
+ continue;
+
if (S4CVAC_BADALIAS(vaddr, address)) {
alias_found++;
start = vmaring->vm_start;
@@ -2699,8 +2703,8 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
flush_cache_page(vmaring, start);
- pte_val(*ptep) = (pte_val(*ptep) |
- _SUN4C_PAGE_NOCACHE);
+ *ptep = __pte(pte_val(*ptep) |
+ _SUN4C_PAGE_NOCACHE);
flush_tlb_page(vmaring, start);
}
next:
@@ -2712,7 +2716,7 @@ static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long addr
if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = sun4c_pgd_offset(vma->vm_mm, address);
ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
- pte_val(*ptep) = (pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
+ *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
pte = pte_val(*ptep);
}
}
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S
index c65f72007..2ab87121f 100644
--- a/arch/sparc/mm/viking.S
+++ b/arch/sparc/mm/viking.S
@@ -1,8 +1,9 @@
-/* $Id: viking.S,v 1.11 1998/02/20 18:07:50 jj Exp $
+/* $Id: viking.S,v 1.13 1999/03/24 11:42:32 davem Exp $
* viking.S: High speed Viking cache/mmu operations
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 Pavel Semerad (semerad@ss1000.ms.mff.cuni.cz)
*/
#include <asm/ptrace.h>
@@ -15,16 +16,12 @@
#include <asm/cprefix.h>
#include <asm/btfixup.h>
-#define WINDOW_FLUSH(tmp1, tmp2) \
- mov 0, tmp1; \
-98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \
- orcc %g0, tmp2, %g0; \
- add tmp1, 1, tmp1; \
- bne 98b; \
- save %sp, -64, %sp; \
-99: subcc tmp1, 1, tmp1; \
- bne 99b; \
- restore %g0, %g0, %g0;
+#ifdef __SMP__
+ .data
+ .align 4
+sun4dsmp_flush_tlb_spin:
+ .word 0
+#endif
.text
.align 4
@@ -70,7 +67,7 @@ viking_flush_chunk:
clr %o1 ! set counter, 0 - 127
sethi %hi(KERNBASE + PAGE_SIZE - 0x80000000), %o3
sethi %hi(0x80000000), %o4
- sethi %hi(VIKING_PTAG_VALID | VIKING_PTAG_DIRTY), %o5
+ sethi %hi(VIKING_PTAG_VALID), %o5
sethi %hi(2*PAGE_SIZE), %o0
sethi %hi(PAGE_SIZE), %g7
clr %o2 ! block counter, 0 - 3
@@ -83,15 +80,12 @@ viking_flush_chunk:
or %g5, %g4, %g5
ldda [%g5] ASI_M_DATAC_TAG, %g2
cmp %g3, %g1 ! ptag == ppage?
- bne,a 7f
- inc %o2
-
- and %g2, %o5, %g3 ! ptag VALID and DIRTY?
- cmp %g3, %o5
- bne,a 7f
+ bne 7f
inc %o2
- add %g4, %o3, %g2 ! (KERNBASE + PAGE_SIZE) | (set << 5)
+ andcc %g2, %o5, %g0 ! ptag VALID?
+ be 7f
+ add %g4, %o3, %g2 ! (KERNBASE + PAGE_SIZE) | (set << 5)
ld [%g2], %g3
ld [%g2 + %g7], %g3
add %g2, %o0, %g2
@@ -102,18 +96,15 @@ viking_flush_chunk:
ld [%g2 + %g7], %g3
add %g2, %o0, %g2
ld [%g2], %g3
- ld [%g2 + %g7], %g3
-
b 8f
- inc %o1
+ ld [%g2 + %g7], %g3
7:
cmp %o2, 3
ble 6b
sll %o2, 26, %g5 ! block << 26
- inc %o1
-8:
+8: inc %o1
cmp %o1, 0x7f
ble 5b
clr %o2
@@ -151,10 +142,33 @@ viking_mxcc_flush_chunk:
retl
nop
-viking_flush_cache_all:
+#define WINDOW_FLUSH(tmp1, tmp2) \
+ mov 0, tmp1; \
+98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \
+ orcc %g0, tmp2, %g0; \
+ add tmp1, 1, tmp1; \
+ bne 98b; \
+ save %sp, -64, %sp; \
+99: subcc tmp1, 1, tmp1; \
+ bne 99b; \
+ restore %g0, %g0, %g0;
+
+viking_flush_cache_page:
+#ifndef __SMP__
+ ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+#endif
viking_flush_cache_mm:
viking_flush_cache_range:
-viking_flush_cache_page:
+#ifndef __SMP__
+ ld [%o0 + AOFF_mm_context], %g1
+ cmp %g1, -1
+ bne viking_flush_cache_all
+ nop
+ b,a viking_flush_cache_out
+#endif
+viking_flush_cache_all:
+ WINDOW_FLUSH(%g4, %g5)
+viking_flush_cache_out:
retl
nop
@@ -176,8 +190,10 @@ viking_flush_tlb_mm:
sta %g0, [%g2] ASI_M_FLUSH_PROBE
retl
sta %g5, [%g1] ASI_M_MMUREGS
+#ifndef __SMP__
1: retl
nop
+#endif
viking_flush_tlb_range:
mov SRMMU_CTX_REG, %g1
@@ -198,8 +214,10 @@ viking_flush_tlb_range:
sta %g0, [%o1] ASI_M_FLUSH_PROBE
retl
sta %g5, [%g1] ASI_M_MMUREGS
+#ifndef __SMP__
2: retl
nop
+#endif
viking_flush_tlb_page:
ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
@@ -215,11 +233,96 @@ viking_flush_tlb_page:
sta %g0, [%o1] ASI_M_FLUSH_PROBE
retl
sta %g5, [%g1] ASI_M_MMUREGS
+#ifndef __SMP__
1: retl
nop
+#endif
viking_flush_page_to_ram:
viking_flush_page_for_dma:
viking_flush_sig_insns:
retl
nop
+
+#ifdef __SMP__
+ .globl sun4dsmp_flush_tlb_all, sun4dsmp_flush_tlb_mm
+ .globl sun4dsmp_flush_tlb_range, sun4dsmp_flush_tlb_page
+sun4dsmp_flush_tlb_all:
+ sethi %hi(sun4dsmp_flush_tlb_spin), %g3
+1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ tst %g5
+ bne 2f
+ mov 0x400, %g1
+ sta %g0, [%g1] ASI_M_FLUSH_PROBE
+ retl
+ stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)]
+2: tst %g5
+ bne,a 2b
+ ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ b,a 1b
+
+sun4dsmp_flush_tlb_mm:
+ sethi %hi(sun4dsmp_flush_tlb_spin), %g3
+1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ tst %g5
+ bne 2f
+ mov SRMMU_CTX_REG, %g1
+ ld [%o0 + AOFF_mm_context], %o1
+ lda [%g1] ASI_M_MMUREGS, %g5
+ mov 0x300, %g2
+ sta %o1, [%g1] ASI_M_MMUREGS
+ sta %g0, [%g2] ASI_M_FLUSH_PROBE
+ sta %g5, [%g1] ASI_M_MMUREGS
+ retl
+ stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)]
+2: tst %g5
+ bne,a 2b
+ ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ b,a 1b
+
+sun4dsmp_flush_tlb_range:
+ sethi %hi(sun4dsmp_flush_tlb_spin), %g3
+1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ tst %g5
+ bne 3f
+ mov SRMMU_CTX_REG, %g1
+ ld [%o0 + AOFF_mm_context], %o3
+ lda [%g1] ASI_M_MMUREGS, %g5
+ sethi %hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4
+ sta %o3, [%g1] ASI_M_MMUREGS
+ and %o1, %o4, %o1
+ add %o1, 0x200, %o1
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+2: sub %o1, %o4, %o1
+ cmp %o1, %o2
+ blu,a 2b
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+ sta %g5, [%g1] ASI_M_MMUREGS
+ retl
+ stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)]
+3: tst %g5
+ bne,a 3b
+ ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ b,a 1b
+
+sun4dsmp_flush_tlb_page:
+ sethi %hi(sun4dsmp_flush_tlb_spin), %g3
+1: ldstub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ tst %g5
+ bne 2f
+ mov SRMMU_CTX_REG, %g1
+ ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + AOFF_mm_context], %o3
+ lda [%g1] ASI_M_MMUREGS, %g5
+ and %o1, PAGE_MASK, %o1
+ sta %o3, [%g1] ASI_M_MMUREGS
+ sta %g0, [%o1] ASI_M_FLUSH_PROBE
+ sta %g5, [%g1] ASI_M_MMUREGS
+ retl
+ stb %g0, [%g3 + %lo(sun4dsmp_flush_tlb_spin)]
+2: tst %g5
+ bne,a 2b
+ ldub [%g3 + %lo(sun4dsmp_flush_tlb_spin)], %g5
+ b,a 1b
+ nop
+#endif
diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds
index 13e4d7202..1edbd8cfa 100644
--- a/arch/sparc/vmlinux.lds
+++ b/arch/sparc/vmlinux.lds
@@ -31,6 +31,10 @@ SECTIONS
__start___ksymtab = .;
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
+
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
. = ALIGN(4096);
__init_begin = .;
.text.init : { *(.text.init) }
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index 9df70fc36..b76cd05b9 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.33 1998/10/19 07:04:02 jj Exp $
+# $Id: Makefile,v 1.35 1999/01/02 16:45:50 davem Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -46,6 +46,7 @@ ifneq ($(IS_EGCS),y)
else
CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
-ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
+ AFLAGS += -m64 -mcpu=ultrasparc
endif
# Uncomment this to get spinlock/rwlock debugging on SMP.
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index fa3539525..58ac24500 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -1,8 +1,8 @@
-# $Id: config.in,v 1.58 1998/11/16 04:47:30 davem Exp $
+# $Id: config.in,v 1.66 1999/03/29 05:08:42 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
-mainmenu_name "Linux/SPARC Kernel Configuration"
+mainmenu_name "Linux/UltraSPARC Kernel Configuration"
mainmenu_option next_comment
comment 'Code maturity level options'
@@ -24,7 +24,6 @@ comment 'General setup'
define_bool CONFIG_VT y
define_bool CONFIG_VT_CONSOLE y
-bool 'Support for AP1000 multicomputer' CONFIG_AP1000
bool 'Symmetric multi-processing support' CONFIG_SMP
mainmenu_option next_comment
@@ -34,28 +33,20 @@ bool 'Support Frame buffer devices' CONFIG_FB
source drivers/video/Config.in
endmenu
-if [ "$CONFIG_AP1000" = "y" ]; then
- define_bool CONFIG_NO_KEYBOARD y
- define_bool CONFIG_APFDDI y
- define_bool CONFIG_APBLOCK y
- define_bool CONFIG_APBIF y
- tristate 'OPIU DDV Driver' CONFIG_DDV
-else
- # Global things across all Sun machines.
- define_bool CONFIG_SBUS y
- define_bool CONFIG_SBUSCHAR y
- define_bool CONFIG_SUN_MOUSE y
- define_bool CONFIG_SERIAL y
- define_bool CONFIG_SUN_SERIAL y
- define_bool CONFIG_SERIAL_CONSOLE y
- define_bool CONFIG_SUN_KEYBOARD y
- define_bool CONFIG_SUN_CONSOLE y
- define_bool CONFIG_SUN_AUXIO y
- define_bool CONFIG_SUN_IO y
- bool 'PCI support' CONFIG_PCI
- source drivers/sbus/char/Config.in
- source drivers/sbus/audio/Config.in
-fi
+# Global things across all Sun machines.
+define_bool CONFIG_SBUS y
+define_bool CONFIG_SBUSCHAR y
+define_bool CONFIG_SUN_MOUSE y
+define_bool CONFIG_SERIAL y
+define_bool CONFIG_SUN_SERIAL y
+define_bool CONFIG_SERIAL_CONSOLE y
+define_bool CONFIG_SUN_KEYBOARD y
+define_bool CONFIG_SUN_CONSOLE y
+define_bool CONFIG_SUN_AUXIO y
+define_bool CONFIG_SUN_IO y
+bool 'PCI support' CONFIG_PCI
+source drivers/sbus/char/Config.in
+source drivers/sbus/audio/Config.in
tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS
if [ "$CONFIG_PCI" = "y" ]; then
@@ -194,6 +185,7 @@ if [ "$CONFIG_SCSI" != "n" ]; then
bool ' assume boards are SYMBIOS compatible' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
fi
fi
+ dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
fi
endmenu
@@ -221,14 +213,14 @@ if [ "$CONFIG_NET" = "y" ]; then
fi
bool 'Sun LANCE support' CONFIG_SUNLANCE
tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Sun BigMAC 10/100baseT support' CONFIG_SUNBMAC
+ fi
tristate 'Sun QuadEthernet support' CONFIG_SUNQE
tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
if [ "$CONFIG_PCI" = "y" ]; then
tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
-# Turned off until updated 3c59x.c driver
-# gets approved by Linus... --DAVEM
-#
-# tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
+ tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
fi
# bool 'FDDI driver support' CONFIG_FDDI
# if [ "$CONFIG_FDDI" = "y" ]; then
@@ -237,6 +229,15 @@ if [ "$CONFIG_NET" = "y" ]; then
endmenu
fi
+# This one must be before the filesystem configs. -DaveM
+mainmenu_option next_comment
+comment 'Unix 98 PTY support'
+bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+fi
+endmenu
+
source fs/Config.in
mainmenu_option next_comment
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 59b3b4618..8a132b01d 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -19,7 +19,6 @@ CONFIG_KMOD=y
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
-# CONFIG_AP1000 is not set
# CONFIG_SMP is not set
#
@@ -28,7 +27,9 @@ CONFIG_VT_CONSOLE=y
CONFIG_PROM_CONSOLE=y
CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
CONFIG_FB_SBUS=y
CONFIG_FB_CREATOR=y
CONFIG_FB_CGSIX=y
@@ -71,9 +72,9 @@ CONFIG_OBP_FLASH=m
#
# Linux/SPARC audio subsystem (EXPERIMENTAL)
#
-# CONFIG_SPARCAUDIO is not set
+CONFIG_SPARCAUDIO=y
# CONFIG_SPARCAUDIO_AMD7930 is not set
-# CONFIG_SPARCAUDIO_CS4231 is not set
+CONFIG_SPARCAUDIO_CS4231=y
# CONFIG_SPARCAUDIO_DBRI is not set
# CONFIG_SPARCAUDIO_DUMMY is not set
CONFIG_SUN_OPENPROMFS=m
@@ -128,7 +129,6 @@ CONFIG_BLK_DEV_CMD646=y
CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
-# CONFIG_NET_ALIAS is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -145,7 +145,6 @@ CONFIG_INET=y
# (it is safe to leave these untouched)
#
CONFIG_INET_RARP=m
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
CONFIG_IPV6=m
# CONFIG_IPV6_EUI64 is not set
@@ -166,6 +165,10 @@ CONFIG_ATALK=m
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
#
@@ -205,6 +208,7 @@ CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
CONFIG_SCSI_NCR53C8XX_SYNC=10
# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+CONFIG_SCSI_QLOGIC_ISP=y
#
# Fibre Channel support
@@ -215,11 +219,13 @@ CONFIG_FC4=m
# FC4 drivers
#
CONFIG_FC4_SOC=m
+CONFIG_FC4_SOCAL=m
#
# FC4 targets
#
CONFIG_SCSI_PLUTO=m
+CONFIG_SCSI_FCAL=m
#
# Network device support
@@ -237,29 +243,53 @@ CONFIG_SLIP_SMART=y
# CONFIG_SLIP_MODE_SLIP6 is not set
CONFIG_SUNLANCE=y
CONFIG_HAPPYMEAL=y
+CONFIG_SUNBMAC=m
CONFIG_SUNQE=m
CONFIG_MYRI_SBUS=m
CONFIG_DE4X5=m
+CONFIG_VORTEX=m
+
+#
+# Unix 98 PTY support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
#
# Filesystems
#
# CONFIG_QUOTA is not set
-CONFIG_MINIX_FS=m
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=m
-# CONFIG_JOLIET is not set
+CONFIG_AUTOFS_FS=m
+# CONFIG_ADFS_FS is not set
+CONFIG_AFFS_FS=m
+# CONFIG_HFS_FS is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+CONFIG_MINIX_FS=m
+# CONFIG_NTFS_FS is not set
+CONFIG_HPFS_FS=m
CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_EXT2_FS=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_UFS_FS_WRITE=y
+
+#
+# Network File Systems
+#
+CONFIG_CODA_FS=m
CONFIG_NFS_FS=y
CONFIG_NFSD=m
# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-CONFIG_CODA_FS=m
CONFIG_SMB_FS=m
CONFIG_SMB_WIN95=y
CONFIG_NCP_FS=m
@@ -269,21 +299,18 @@ CONFIG_NCP_FS=m
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_MOUNT_SUBDIR is not set
-CONFIG_HPFS_FS=m
-# CONFIG_NTFS_FS is not set
-CONFIG_SYSV_FS=m
-CONFIG_AFFS_FS=m
-# CONFIG_HFS_FS is not set
-CONFIG_ROMFS_FS=m
-CONFIG_AUTOFS_FS=m
-CONFIG_AMIGA_PARTITION=y
-CONFIG_UFS_FS=m
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
CONFIG_BSD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
CONFIG_SMD_DISKLABEL=y
CONFIG_SOLARIS_X86_PARTITION=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_MAC_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_AMIGA_PARTITION=y
CONFIG_NLS=y
#
@@ -314,6 +341,7 @@ CONFIG_NLS=y
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
#
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index fbeb83126..6934dda6e 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.41 1998/10/11 06:58:14 davem Exp $
+# $Id: Makefile,v 1.43 1999/01/02 16:45:53 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -20,7 +20,7 @@ O_OBJS := process.o setup.o cpu.o idprom.o \
traps.o devices.o auxio.o ioport.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o sys_sunos32.o sunos_ioctl32.o \
- central.o psycho.o
+ central.o psycho.o starfire.o
OX_OBJS := sparc64_ksyms.o
ifdef CONFIG_PCI
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index dc898e300..450451ac0 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
-#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -18,9 +17,10 @@
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <linux/file.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/malloc.h>
@@ -58,14 +58,13 @@ static void set_brk(unsigned long start, unsigned long end)
* macros to write out all the necessary info.
*/
#define DUMP_WRITE(addr,nr) \
-while (file.f_op->write(&file,(char *)(addr),(nr),&file.f_pos) != (nr)) \
- goto close_coredump
+while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump
#define DUMP_SEEK(offset) \
-if (file.f_op->llseek) { \
- if (file.f_op->llseek(&file,(offset),0) != (offset)) \
+if (file->f_op->llseek) { \
+ if (file->f_op->llseek(file,(offset),0) != (offset)) \
goto close_coredump; \
-} else file.f_pos = (offset)
+} else file->f_pos = (offset)
/*
* Routine writes a core dump image in the current directory.
@@ -82,7 +81,7 @@ do_aout32_core_dump(long signr, struct pt_regs * regs)
{
struct dentry * dentry = NULL;
struct inode * inode = NULL;
- struct file file;
+ struct file * file;
mm_segment_t fs;
int has_dumped = 0;
char corefile[6+sizeof(current->comm)];
@@ -106,29 +105,16 @@ do_aout32_core_dump(long signr, struct pt_regs * regs)
#else
corefile[4] = '\0';
#endif
- dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
- if (IS_ERR(dentry)) {
- dentry = NULL;
+ file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
+ if (IS_ERR(file))
goto end_coredump;
- }
+ dentry = file->f_dentry;
inode = dentry->d_inode;
if (!S_ISREG(inode->i_mode))
- goto end_coredump;
+ goto close_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
- goto end_coredump;
- if (get_write_access(inode))
- goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_dentry = dentry;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto done_coredump;
- if (!file.f_op->write)
+ goto close_coredump;
+ if (!file->f_op->write)
goto close_coredump;
has_dumped = 1;
current->flags |= PF_DUMPCORE;
@@ -175,13 +161,9 @@ do_aout32_core_dump(long signr, struct pt_regs * regs)
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
close_coredump:
- if (file.f_op->release)
- file.f_op->release(inode,&file);
-done_coredump:
- put_write_access(inode);
+ filp_close(file, NULL);
end_coredump:
set_fs(fs);
- dput(dentry);
return has_dumped;
}
@@ -269,7 +251,6 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
return -ENOEXEC;
}
- current->personality = PER_LINUX;
fd_offset = N_TXTOFF(ex);
/* Check initial limits. This avoids letting people circumvent
@@ -288,6 +269,8 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
return retval;
/* OK, This is the point of no return */
+ current->personality = PER_LINUX;
+
current->mm->end_code = ex.a_text +
(current->mm->start_code = N_TXTADDR(ex));
current->mm->end_data = ex.a_data +
@@ -297,8 +280,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
current->mm->rss = 0;
current->mm->mmap = NULL;
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
if (N_MAGIC(ex) == NMAGIC) {
/* Fuck me plenty... */
@@ -404,48 +386,44 @@ static inline int
do_load_aout32_library(int fd)
{
struct file * file;
- struct exec ex;
- struct dentry * dentry;
struct inode * inode;
- unsigned int len;
- unsigned int bss;
- unsigned int start_addr;
+ unsigned long bss, start_addr, len;
unsigned long error;
+ int retval;
+ loff_t offset = 0;
+ struct exec ex;
- file = fcheck(fd);
-
- if (!file || !file->f_op)
- return -EACCES;
-
- dentry = file->f_dentry;
- inode = dentry->d_inode;
-
- /* Seek into the file */
- if (file->f_op->llseek) {
- if ((error = file->f_op->llseek(file, 0, 0)) != 0)
- return -ENOEXEC;
- } else
- file->f_pos = 0;
+ retval = -EACCES;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ if (!file->f_op)
+ goto out_putf;
+ inode = file->f_dentry->d_inode;
+ retval = -ENOEXEC;
+ /* N.B. Save current fs? */
set_fs(KERNEL_DS);
- error = file->f_op->read(file, (char *) &ex, sizeof(ex), &file->f_pos);
+ error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset);
set_fs(USER_DS);
if (error != sizeof(ex))
- return -ENOEXEC;
+ goto out_putf;
/* We come in here for the regular a.out style of shared libraries */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) ||
N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
- return -ENOEXEC;
+ goto out_putf;
}
+
if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) &&
(N_TXTOFF(ex) < inode->i_sb->s_blocksize)) {
printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n");
- return -ENOEXEC;
+ goto out_putf;
}
- if (N_FLAGS(ex)) return -ENOEXEC;
+ if (N_FLAGS(ex))
+ goto out_putf;
/* For QMAGIC, the starting address is 0x20 into the page. We mask
this off to get the starting address for the page */
@@ -457,18 +435,26 @@ do_load_aout32_library(int fd)
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
N_TXTOFF(ex));
+ retval = error;
if (error != start_addr)
- return error;
+ goto out_putf;
+
len = PAGE_ALIGN(ex.a_text + ex.a_data);
bss = ex.a_text + ex.a_data + ex.a_bss;
if (bss > len) {
- error = do_mmap(NULL, start_addr + len, bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_PRIVATE|MAP_FIXED, 0);
+ error = do_mmap(NULL, start_addr + len, bss - len,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_FIXED, 0);
+ retval = error;
if (error != start_addr + len)
- return error;
+ goto out_putf;
}
- return 0;
+ retval = 0;
+
+out_putf:
+ fput(file);
+out:
+ return retval;
}
static int
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index 1d1cb25e1..198841f89 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -1,4 +1,4 @@
-/* $Id: central.c,v 1.6 1998/05/14 13:35:45 jj Exp $
+/* $Id: central.c,v 1.11 1998/12/14 12:18:16 davem Exp $
* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -7,11 +7,17 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
#include <asm/page.h>
#include <asm/fhc.h>
struct linux_central *central_bus = NULL;
+struct linux_fhc *fhc_list = NULL;
+
+#define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child)
static inline unsigned long long_align(unsigned long addr)
{
@@ -22,6 +28,156 @@ static inline unsigned long long_align(unsigned long addr)
extern void prom_central_ranges_init(int cnode, struct linux_central *central);
extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc);
+static unsigned long probe_other_fhcs(unsigned long memory_start)
+{
+ struct linux_prom64_registers fpregs[6];
+ char namebuf[128];
+ int node;
+
+ node = prom_getchild(prom_root_node);
+ node = prom_searchsiblings(node, "fhc");
+ if (node == 0) {
+ prom_printf("FHC: Cannot find any toplevel firehose controllers.\n");
+ prom_halt();
+ }
+ while(node) {
+ struct linux_fhc *fhc;
+ int board;
+ u32 tmp;
+
+ fhc = (struct linux_fhc *)memory_start;
+ memory_start += sizeof(struct linux_fhc);
+ memory_start = long_align(memory_start);
+
+ /* Link it into the FHC chain. */
+ fhc->next = fhc_list;
+ fhc_list = fhc;
+
+ /* Toplevel FHCs have no parent. */
+ fhc->parent = NULL;
+
+ fhc->prom_node = node;
+ prom_getstring(node, "name", namebuf, sizeof(namebuf));
+ strcpy(fhc->prom_name, namebuf);
+ prom_fhc_ranges_init(node, fhc);
+
+ /* Non-central FHC's have 64-bit OBP format registers. */
+ if(prom_getproperty(node, "reg",
+ (char *)&fpregs[0], sizeof(fpregs)) == -1) {
+ prom_printf("FHC: Fatal error, cannot get fhc regs.\n");
+ prom_halt();
+ }
+
+ /* Only central FHC needs special ranges applied. */
+ fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
+ __va(fpregs[0].phys_addr);
+ fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
+ __va(fpregs[1].phys_addr);
+ fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
+ __va(fpregs[2].phys_addr);
+ fhc->fhc_regs.sregs = (struct fhc_system_regs *)
+ __va(fpregs[3].phys_addr);
+ fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
+ __va(fpregs[4].phys_addr);
+ fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
+ __va(fpregs[5].phys_addr);
+
+ board = prom_getintdefault(node, "board#", -1);
+ fhc->board = board;
+
+ tmp = fhc->fhc_regs.pregs->fhc_jtag_ctrl;
+ if((tmp & FHC_JTAG_CTRL_MENAB) != 0)
+ fhc->jtag_master = 1;
+ else
+ fhc->jtag_master = 0;
+
+ tmp = fhc->fhc_regs.pregs->fhc_id;
+ printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
+ board,
+ (tmp & FHC_ID_VERS) >> 28,
+ (tmp & FHC_ID_PARTID) >> 12,
+ (tmp & FHC_ID_MANUF) >> 1,
+ (fhc->jtag_master ? "(JTAG Master)" : ""));
+
+ /* This bit must be set in all non-central FHC's in
+ * the system. When it is clear, this identifies
+ * the central board.
+ */
+ fhc->fhc_regs.pregs->fhc_control |= FHC_CONTROL_IXIST;
+
+ /* Look for the next FHC. */
+ node = prom_getsibling(node);
+ if(node == 0)
+ break;
+ node = prom_searchsiblings(node, "fhc");
+ if(node == 0)
+ break;
+ }
+
+ return memory_start;
+}
+
+static void probe_clock_board(struct linux_central *central,
+ struct linux_fhc *fhc,
+ int cnode, int fnode)
+{
+ struct linux_prom_registers cregs[3];
+ int clknode, nslots, tmp, nregs;
+
+ clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board");
+ if(clknode == 0 || clknode == -1) {
+ prom_printf("Critical error, central lacks clock-board.\n");
+ prom_halt();
+ }
+ nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs));
+ if (nregs == -1) {
+ prom_printf("CENTRAL: Fatal error, cannot map clock-board regs.\n");
+ prom_halt();
+ }
+ nregs /= sizeof(struct linux_prom_registers);
+ prom_apply_fhc_ranges(fhc, &cregs[0], nregs);
+ prom_apply_central_ranges(central, &cregs[0], nregs);
+ central->cfreg = (volatile u8 *)
+ __va((((unsigned long)cregs[0].which_io) << 32) |
+ (((unsigned long)cregs[0].phys_addr)+0x02));
+ central->clkregs = (struct clock_board_regs *)
+ __va((((unsigned long)cregs[1].which_io) << 32) |
+ (((unsigned long)cregs[1].phys_addr)));
+ if(nregs == 2)
+ central->clkver = NULL;
+ else
+ central->clkver = (volatile u8 *)
+ __va((((unsigned long)cregs[2].which_io) << 32) |
+ (((unsigned long)cregs[2].phys_addr)));
+
+ tmp = central->clkregs->stat1;
+ tmp &= 0xc0;
+ switch(tmp) {
+ case 0x40:
+ nslots = 16;
+ break;
+ case 0xc0:
+ nslots = 8;
+ break;
+ case 0x80:
+ if(central->clkver != NULL &&
+ *(central->clkver) != 0) {
+ if((*(central->clkver) & 0x80) != 0)
+ nslots = 4;
+ else
+ nslots = 5;
+ break;
+ }
+ default:
+ nslots = 4;
+ break;
+ };
+ central->slots = nslots;
+ printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
+ central->slots, *(central->cfreg),
+ (central->clkver ? *(central->clkver) : 0x00));
+}
+
unsigned long central_probe(unsigned long memory_start)
{
struct linux_prom_registers fpregs[6];
@@ -30,9 +186,12 @@ unsigned long central_probe(unsigned long memory_start)
int cnode, fnode, err;
cnode = prom_finddevice("/central");
- if(cnode == 0 || cnode == -1)
+ if(cnode == 0 || cnode == -1) {
+ extern void starfire_check(void);
+
+ starfire_check();
return memory_start;
- printk("CENTRAL: found central PROM node %08x.\n", cnode);
+ }
/* Ok we got one, grab some memory for software state. */
memory_start = long_align(memory_start);
@@ -54,7 +213,9 @@ unsigned long central_probe(unsigned long memory_start)
prom_central_ranges_init(cnode, central_bus);
/* And then central's FHC. */
- fhc->next = NULL;
+ fhc->next = fhc_list;
+ fhc_list = fhc;
+
fhc->parent = central_bus;
fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
if(fnode == 0 || fnode == -1) {
@@ -67,9 +228,9 @@ unsigned long central_probe(unsigned long memory_start)
prom_fhc_ranges_init(fnode, fhc);
- /* Finally, map in FHC register set. */
+ /* Now, map in FHC register set. */
if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1) {
- prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n");
+ prom_printf("CENTRAL: Fatal error, cannot get fhc regs.\n");
prom_halt();
}
prom_apply_central_ranges(central_bus, &fpregs[0], 6);
@@ -93,11 +254,144 @@ unsigned long central_probe(unsigned long memory_start)
__va((((unsigned long)fpregs[5].which_io)<<32) |
(((unsigned long)fpregs[5].phys_addr)));
+ /* Obtain board number from board status register, Central's
+ * FHC lacks "board#" property.
+ */
+ err = fhc->fhc_regs.pregs->fhc_bsr;
+ fhc->board = (((err >> 16) & 0x01) |
+ ((err >> 12) & 0x0e));
+
+ fhc->jtag_master = 0;
+
+ /* Attach the clock board registers for CENTRAL. */
+ probe_clock_board(central_bus, fhc, cnode, fnode);
+
err = fhc->fhc_regs.pregs->fhc_id;
- printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
+ printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
+ fhc->board,
((err & FHC_ID_VERS) >> 28),
((err & FHC_ID_PARTID) >> 12),
((err & FHC_ID_MANUF) >> 1));
- return memory_start;
+ return probe_other_fhcs(memory_start);
+}
+
+static __inline__ void fhc_ledblink(struct linux_fhc *fhc, int on)
+{
+ volatile u32 *ctrl = (volatile u32 *)
+ &fhc->fhc_regs.pregs->fhc_control;
+ u32 tmp;
+
+ tmp = *ctrl;
+
+ /* NOTE: reverse logic on this bit */
+ if (on)
+ tmp &= ~(FHC_CONTROL_RLED);
+ else
+ tmp |= FHC_CONTROL_RLED;
+ tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
+
+ *ctrl = tmp;
+ tmp = *ctrl;
+}
+
+static __inline__ void central_ledblink(struct linux_central *central, int on)
+{
+ volatile u8 *ctrl = (volatile u8 *) &central->clkregs->control;
+ int tmp;
+
+ tmp = *ctrl;
+
+ /* NOTE: reverse logic on this bit */
+ if(on)
+ tmp &= ~(CLOCK_CTRL_RLED);
+ else
+ tmp |= CLOCK_CTRL_RLED;
+
+ *ctrl = tmp;
+ tmp = *ctrl;
+}
+
+static struct timer_list sftimer;
+static int led_state;
+
+static void sunfire_timer(unsigned long __ignored)
+{
+ struct linux_fhc *fhc;
+
+ central_ledblink(central_bus, led_state);
+ for(fhc = fhc_list; fhc != NULL; fhc = fhc->next)
+ if(! IS_CENTRAL_FHC(fhc))
+ fhc_ledblink(fhc, led_state);
+ led_state = ! led_state;
+ sftimer.expires = jiffies + (HZ >> 1);
+ add_timer(&sftimer);
+}
+
+/* After PCI/SBUS busses have been probed, this is called to perform
+ * final initialization of all FireHose Controllers in the system.
+ */
+void firetruck_init(void)
+{
+ struct linux_central *central = central_bus;
+ struct linux_fhc *fhc;
+
+ /* No central bus, nothing to do. */
+ if (central == NULL)
+ return;
+
+ for(fhc = fhc_list; fhc != NULL; fhc = fhc->next) {
+ volatile u32 *ctrl = (volatile u32 *)
+ &fhc->fhc_regs.pregs->fhc_control;
+ u32 tmp;
+
+ /* Clear all of the interrupt mapping registers
+ * just in case OBP left them in a foul state.
+ */
+#define ZAP(REG1, REG2) \
+do { volatile u32 *__iclr = (volatile u32 *)(&(REG1)); \
+ volatile u32 *__imap = (volatile u32 *)(&(REG2)); \
+ *(__iclr) = 0; \
+ (void) *(__iclr); \
+ *(__imap) &= ~(0x80000000); \
+ (void) *(__imap); \
+} while(0)
+
+ ZAP(fhc->fhc_regs.ffregs->fhc_ff_iclr,
+ fhc->fhc_regs.ffregs->fhc_ff_imap);
+ ZAP(fhc->fhc_regs.sregs->fhc_sys_iclr,
+ fhc->fhc_regs.sregs->fhc_sys_imap);
+ ZAP(fhc->fhc_regs.uregs->fhc_uart_iclr,
+ fhc->fhc_regs.uregs->fhc_uart_imap);
+ ZAP(fhc->fhc_regs.tregs->fhc_tod_iclr,
+ fhc->fhc_regs.tregs->fhc_tod_imap);
+
+#undef ZAP
+
+ /* Setup FHC control register. */
+ tmp = *ctrl;
+
+ /* All non-central boards have this bit set. */
+ if(! IS_CENTRAL_FHC(fhc))
+ tmp |= FHC_CONTROL_IXIST;
+
+ /* For all FHCs, clear the firmware synchronization
+ * line and both low power mode enables.
+ */
+ tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
+ *ctrl = tmp;
+ tmp = *ctrl; /* Ensure completion */
+ }
+
+ /* OBP leaves it on, turn it off so clock board timer LED
+ * is in sync with FHC ones.
+ */
+ central->clkregs->control &= ~(CLOCK_CTRL_RLED);
+
+ led_state = 0;
+ init_timer(&sftimer);
+ sftimer.data = 0;
+ sftimer.function = &sunfire_timer;
+ sftimer.expires = jiffies + (HZ >> 1);
+ add_timer(&sftimer);
}
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 86efc4bb7..86518e50e 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -49,11 +49,11 @@ struct cpu_iu_info linux_sparc_chips[] = {
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
#ifdef __SMP__
-char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+char *sparc_cpu_type[64] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[64] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
#else
-char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", };
-char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", };
+char *sparc_cpu_type[64] = { "cpu-oops", };
+char *sparc_fpu_type[64] = { "fpu-oops", };
#endif
unsigned int fsr_storage;
@@ -65,11 +65,11 @@ __initfunc(void cpu_probe(void))
long ver, fpu_vers;
long fprs;
- cpuid = smp_processor_id();
+ cpuid = hard_smp_processor_id();
fprs = fprs_read ();
fprs_write (FPRS_FEF);
- __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=r" (ver) : "r" (&fpu_vers));
+ __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=&r" (ver) : "r" (&fpu_vers));
fprs_write (fprs);
manuf = ((ver >> 48)&0xffff);
@@ -88,7 +88,7 @@ __initfunc(void cpu_probe(void))
if(i==NSPARCCHIPS) {
printk("DEBUG: manuf = 0x%x impl = 0x%x\n", manuf,
impl);
- sparc_cpu_type[cpuid] = "Unknow CPU";
+ sparc_cpu_type[cpuid] = "Unknown CPU";
}
for(i = 0; i<NSPARCFPU; i++) {
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 93ea8ca4f..0aef0b019 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -13,8 +13,8 @@
#include <asm/system.h>
#include <asm/smp.h>
-struct prom_cpuinfo linux_cpus[NR_CPUS] __initdata = { { 0 } };
-unsigned prom_cpu_nodes[NR_CPUS];
+struct prom_cpuinfo linux_cpus[64] __initdata = { { 0 } };
+unsigned prom_cpu_nodes[64];
int linux_num_cpus = 0;
extern void cpu_probe(void);
@@ -25,11 +25,12 @@ device_scan(unsigned long mem_start))
{
char node_str[128];
int nd, prom_node_cpu, thismid;
- int cpu_nds[NR_CPUS]; /* One node for each cpu */
+ int cpu_nds[64]; /* One node for each cpu */
int cpu_ctr = 0;
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+ prom_printf("Booting Linux...\n");
if(strcmp(node_str, "cpu") == 0) {
cpu_nds[0] = prom_root_node;
linux_cpus[0].prom_node = prom_root_node;
@@ -38,7 +39,7 @@ device_scan(unsigned long mem_start))
} else {
int scan;
scan = prom_getchild(prom_root_node);
- prom_printf("root child is %08x\n", (unsigned) scan);
+ /* prom_printf("root child is %08x\n", (unsigned) scan); */
nd = 0;
while((scan = prom_getsibling(scan)) != 0) {
prom_getstring(scan, "device_type", node_str, sizeof(node_str));
@@ -49,11 +50,11 @@ device_scan(unsigned long mem_start))
(char *) &thismid, sizeof(thismid));
linux_cpus[cpu_ctr].mid = thismid;
#ifdef __SMP__
- prom_printf("Found CPU %d (node=%08x,mid=%d)\n",
- cpu_ctr, (unsigned) scan,
- thismid);
- printk("Found CPU %d (node=%08x,mid=%d)\n",
- cpu_ctr, (unsigned) scan, thismid);
+ /* Don't pollute PROM screen with these messages. If the kernel is screwed enough
+ that console does not start up, then we don't care how many CPUs have been found,
+ if it starts up, the user can use console=prom to see it. */
+ /* prom_printf("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); */
+ printk("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid);
#endif
cpu_ctr++;
}
@@ -72,6 +73,9 @@ device_scan(unsigned long mem_start))
prom_cpu_nodes[0] = prom_node_cpu;
+ mem_start = central_probe(mem_start);
+
cpu_probe();
- return central_probe(mem_start);
+
+ return mem_start;
}
diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S
index 6207101fd..9fe613a51 100644
--- a/arch/sparc64/kernel/dtlb_backend.S
+++ b/arch/sparc64/kernel/dtlb_backend.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_backend.S,v 1.6 1998/09/24 03:21:32 davem Exp $
+/* $Id: dtlb_backend.S,v 1.7 1998/12/16 04:33:28 davem Exp $
* dtlb_backend.S: Back end to DTLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -37,28 +37,30 @@
be,pn %xcc, sparc64_vpte_nucleus ! Is it from Nucleus?
and %g1, 0xffe, %g1 ! Mask PMD offset bits
brnz,pt %g5, sparc64_vpte_continue ! Yep, go like smoke
- nop ! Pipe bubble...
+ add %g1, %g1, %g1 ! Position PMD offset some more
srlx %g6, (PGD_SHIFT - 2), %g5 ! Position PGD offset
and %g5, 0xffc, %g5 ! Mask PGD offset
/* TLB1 ** ICACHE line 3: Quick VPTE miss */
lduwa [%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
- brz,pn %g5, 2f ! Valid?
+ brz,pn %g5, vpte_noent ! Valid?
+sparc64_kpte_continue:
+ sllx %g5, 11, %g5 ! Shift into place
sparc64_vpte_continue:
- add %g1, %g1, %g1 ! Position PMD offset once again
lduwa [%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD
- brz,pn %g5, 2f ! Valid?
+ sllx %g5, 11, %g5 ! Shift into place
+ brz,pn %g5, vpte_noent ! Valid?
sllx %g2, 62, %g1 ! Put _PAGE_VALID into %g1
or %g5, VPTE_BITS, %g5 ! Prepare VPTE data
- or %g5, %g1, %g5 ! ...
/* TLB1 ** ICACHE line 4: Quick VPTE miss */
+ or %g5, %g1, %g5 ! ...
mov TLB_SFSR, %g1 ! Restore %g1 value
stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load VPTE into TLB
- membar #Sync ! Synchronize ASI stores
stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS
retry ! Load PTE once again
-2: mov TLB_SFSR, %g1 ! Restore %g1 value
+vpte_noent:
+ mov TLB_SFSR, %g1 ! Restore %g1 value
stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS
done ! Slick trick
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index c4ce36502..067a1d051 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.17 1998/05/25 16:59:11 davem Exp $
+/* $Id: dtlb_prot.S,v 1.18 1999/03/02 15:42:14 jj Exp $
* dtlb_prot.S: DTLB protection trap strategy.
* This is included directly into the trap table.
*
@@ -45,13 +45,13 @@
mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr
bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup
ldxa [%g4] ASI_DMMU, %g5 ! Put tagaccess in %g5
- sethi %hi(1f), %g7 ! Nope, normal fault
+ ba,pt %xcc, sparc64_realfault_common ! Nope, normal fault
/* PROT ** ICACHE line 4: More real fault processing */
- ba,pt %xcc, etrap ! Save state
-1: or %g7, %lo(1b), %g7 ! ...
- ba,pt %xcc, sparc64_realfault_continue! Now call the fault handler
- mov 1, %o2 ! Indicate this was a write
+ mov 1, %g4 ! Indicate this was a write
+ nop
+ nop
+ nop
nop
nop
nop
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index e60a5dc62..e64e87299 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.33 1998/09/21 05:06:03 jj Exp $
+/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -35,9 +35,6 @@ extern void prom_ebus_intmap_init(struct linux_ebus *);
#ifdef CONFIG_SUN_OPENPROMIO
extern int openprom_init(void);
#endif
-#ifdef CONFIG_SPARCAUDIO
-extern int sparcaudio_init(void);
-#endif
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
@@ -263,6 +260,31 @@ __initfunc(void ebus_init(void))
ebus->next = 0;
while (ebusnd) {
+ /* SUNW,pci-qfe uses four empty ebuses on it.
+ I think we should not consider them here,
+ as they have half of the properties this
+ code expects and once we do PCI hot-plug,
+ we'd have to tweak with the ebus_chain
+ in the runtime after initialization. -jj */
+ if (!prom_getchild (ebusnd)) {
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_EBUS, pdev);
+ if (!pdev) {
+ if (ebus == ebus_chain) {
+ ebus_chain = NULL;
+ printk("ebus: No EBus's found.\n");
+#ifdef PROM_DEBUG
+ dprintf("ebus: No EBus's found.\n");
+#endif
+ return;
+ }
+ break;
+ }
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+ continue;
+ }
printk("ebus%d:", num_ebus);
#ifdef PROM_DEBUG
dprintf("ebus%d:", num_ebus);
@@ -280,6 +302,12 @@ __initfunc(void ebus_init(void))
pci_command |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+ /* Set reasonable cache line size and latency timer values. */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+
+ /* NOTE: Cache line size is in 32-bit word units. */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
+
len = prom_getproperty(ebusnd, "reg", (void *)regs,
sizeof(regs));
if (len == 0 || len == -1) {
@@ -368,9 +396,6 @@ __initfunc(void ebus_init(void))
#ifdef CONFIG_SUN_OPENPROMIO
openprom_init();
#endif
-#ifdef CONFIG_SPARCAUDIO
- sparcaudio_init();
-#endif
#ifdef CONFIG_SUN_BPP
bpp_init();
#endif
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 7c0d80eb4..4134dcc3a 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,10 +1,10 @@
-/* $Id: entry.S,v 1.91 1998/10/07 01:27:08 davem Exp $
+/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/config.h>
@@ -29,8 +29,17 @@
.text
.align 32
+ .globl sparc64_vpte_patchme1
+ .globl sparc64_vpte_patchme2
+sparc64_vpte_nucleus:
+sparc64_vpte_patchme1:
+ sethi %hi(0), %g5 ! This has to be patched
+sparc64_vpte_patchme2:
+ or %g5, %lo(0), %g5 ! This is patched too
+ ba,pt %xcc, sparc64_kpte_continue ! Part of dtlb_backend
+ add %g1, %g1, %g1 ! Finish PMD offset adjustment
+
/* This is trivial with the new code... */
- .align 32
.globl do_fpdis
do_fpdis:
ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g5 ! Load Group
@@ -155,6 +164,39 @@ fpdis_exit2:
wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits
retry
+ .globl do_fptrap
+ .align 32
+do_fptrap:
+ ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3
+ stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+ rd %fprs, %g1
+ or %g3, %g1, %g3
+ stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
+ rd %gsr, %g3
+ stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr]
+ mov SECONDARY_CONTEXT, %g3
+ add %g6, AOFF_task_fpregs, %g2
+ ldxa [%g3] ASI_DMMU, %g5
+ stxa %g0, [%g3] ASI_DMMU
+ flush %g6
+ membar #StoreStore | #LoadStore
+ andcc %g1, FPRS_DL, %g0
+ be,pn %icc, 4f
+ mov 0x40, %g3
+ stda %f0, [%g2] ASI_BLK_S
+ stda %f16, [%g2 + %g3] ASI_BLK_S
+ andcc %g1, FPRS_DU, %g0
+ be,pn %icc, 5f
+4: add %g2, 128, %g2
+ stda %f32, [%g2] ASI_BLK_S
+ stda %f48, [%g2 + %g3] ASI_BLK_S
+5: mov SECONDARY_CONTEXT, %g1
+ membar #Sync
+ stxa %g5, [%g1] ASI_DMMU
+ flush %g6
+ ba,pt %xcc, etrap
+ wr %g0, 0, %fprs
+
/* The registers for cross calls will be:
*
* DATA 0: [low 32-bits] Address of function to call, jmp to this
@@ -164,69 +206,57 @@ fpdis_exit2:
*
* With this method we can do most of the cross-call tlb/cache
* flushing very quickly.
+ *
+ * Current CPU's IRQ worklist table is locked into %g1,
+ * don't touch.
*/
- .data
- .align 8
- .globl ivec_spurious_cookie
-ivec_spurious_cookie: .xword 0
-
.text
- .align 32
- .globl do_ivec
+ .align 32
+ .globl do_ivec
do_ivec:
- ldxa [%g0] ASI_INTR_RECEIVE, %g5
- andcc %g5, 0x20, %g0
- be,pn %xcc, do_ivec_return
- mov 0x40, %g2
-
- /* Load up Interrupt Vector Data 0 register. */
+ wr %g0, ASI_UDB_INTR_R, %asi
+ ldxa [%g0 + 0x40] %asi, %g3
sethi %hi(KERNBASE), %g4
- ldxa [%g2] ASI_UDB_INTR_R, %g3
cmp %g3, %g4
bgeu,pn %xcc, do_ivec_xcall
- nop
- and %g3, 0x7ff, %g3
- sllx %g3, 3, %g3
- ldx [%g1 + %g3], %g2
- brz,pn %g2, do_ivec_spurious
- sethi %hi(0x80000000), %g5
+ srlx %g3, 32, %g5
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
- or %g2, %g5, %g2
- stx %g2, [%g1 + %g3]
+ sethi %hi(ivector_table), %g2
+ sllx %g3, 5, %g3
+ or %g2, %lo(ivector_table), %g2
+ add %g2, %g3, %g3
+ ldx [%g3 + 0x08], %g2 /* irq_info */
+ ldub [%g3 + 0x04], %g4 /* pil */
+ brz,pn %g2, do_ivec_spurious
+ mov 1, %g2
- /* No branches, worse case we don't know about this interrupt
- * yet, so we would just write a zero into the softint register
- * which is completely harmless.
- */
+ sllx %g2, %g4, %g2
+ sllx %g4, 2, %g4
+ lduw [%g1 + %g4], %g5 /* g5 = irq_work(cpu, pil) */
+ stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
+ stw %g3, [%g1 + %g4] /* irq_work(cpu, pil) = bucket */
wr %g2, 0x0, %set_softint
-do_ivec_return:
- stxa %g0, [%g0] ASI_INTR_RECEIVE
- membar #Sync
retry
do_ivec_xcall:
- srlx %g3, 32, %g5
- add %g2, 0x10, %g2
+ ldxa [%g0 + 0x50] %asi, %g6
+
srl %g3, 0, %g3
- ldxa [%g2] ASI_UDB_INTR_R, %g6
- add %g2, 0x10, %g2
- ldxa [%g2] ASI_UDB_INTR_R, %g7
+ ldxa [%g0 + 0x60] %asi, %g7
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
jmpl %g3, %g0
nop
-
do_ivec_spurious:
- srl %g3, 3, %g3
- sethi %hi(ivec_spurious_cookie), %g2
- stx %g3, [%g2 + %lo(ivec_spurious_cookie)]
- stxa %g0, [%g0] ASI_INTR_RECEIVE
- membar #Sync
+ stw %g3, [%g1 + 0x00] /* irq_work(cpu, 0) = bucket */
rdpr %pstate, %g5
+
wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate
sethi %hi(109f), %g7
ba,pt %xcc, etrap
109: or %g7, %lo(109b), %g7
- call report_spurious_ivec
+ call catch_disabled_ivec
add %sp, STACK_BIAS + REGWIN_SZ, %o0
ba,pt %xcc, rtrap
clr %l6
@@ -337,7 +367,7 @@ floppy_fifo_emptied:
or %g1, %lo(irq_action), %g1
ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq]
ldx [%g3 + 0x10], %g4 ! action->mask == ino_bucket ptr
- ldx [%g4 + 0x18], %g4 ! bucket->iclr
+ ldx [%g4 + 0x10], %g4 ! bucket->iclr
stw %g0, [%g4] ! SYSIO_ICLR_IDLE
membar #Sync ! probably not needed...
retry
@@ -588,12 +618,20 @@ sunos_getgid:
/* SunOS's execv() call only specifies the argv argument, the
* environment settings are the same as the calling processes.
*/
- .globl sunos_execv
+ .globl sunos_execv, sys_execve, sys32_execve
+sys_execve:
+ sethi %hi(sparc_execve), %g1
+ ba,pt %xcc, execve_merge
+ or %g1, %lo(sparc_execve), %g1
sunos_execv:
- sethi %hi(sparc32_execve), %g1
- stx %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
- jmpl %g1 + %lo(sparc32_execve), %g0
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ stx %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
+sys32_execve:
+ sethi %hi(sparc32_execve), %g1
+ or %g1, %lo(sparc32_execve), %g1
+execve_merge:
+ flushw
+ jmpl %g1, %g0
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
.globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
.globl sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend
@@ -612,14 +650,6 @@ sys_nis_syscall:sethi %hi(c_sys_nis_syscall), %g1
jmpl %g1 + %lo(c_sys_nis_syscall), %g0
nop
-sys_execve: sethi %hi(sparc_execve), %g1
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- jmpl %g1 + %lo(sparc_execve), %g0
- nop
-sys32_execve: sethi %hi(sparc32_execve), %g1
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- jmpl %g1 + %lo(sparc32_execve), %g0
- nop
sys_memory_ordering:
sethi %hi(sparc_memory_ordering), %g1
add %sp, STACK_BIAS + REGWIN_SZ, %o1
@@ -719,27 +749,31 @@ sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0
.globl sys_fork, sys_vfork, sys_clone, sparc_exit
.globl ret_from_syscall
.align 32
-sys_fork:
-sys_vfork: mov SIGCHLD, %o0
- clr %o1
+sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */
+ sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
+ or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
+ ba,pt %xcc, sys_clone
+sys_fork: clr %o1
+ mov SIGCHLD, %o0
sys_clone: flushw
- mov %o7, %l5
- add %sp, STACK_BIAS + REGWIN_SZ, %o2
movrz %o1, %fp, %o1
- call do_fork
- mov %l5, %o7
+ nop
+ ba,pt %xcc, do_fork
+ add %sp, STACK_BIAS + REGWIN_SZ, %o2
ret_from_syscall:
/* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in
* %o7 for us. Check performance counter stuff too.
*/
- andn %o7, 0x100, %o7
- sth %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags]
#ifdef __SMP__
- sethi %hi(scheduler_lock), %o4
- membar #StoreStore | #LoadStore
- stb %g0, [%o4 + %lo(scheduler_lock)]
+ andn %o7, 0x100, %l0
+ mov %g5, %o0 /* 'prev' */
+ call schedule_tail
+ sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
+#else
+ andn %o7, 0x100, %l0
+ sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
#endif
- andcc %o7, 0x200, %g0
+ andcc %l0, 0x200, %g0
be,pt %icc, 1f
nop
ldx [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 8c92688f1..21c1872a8 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.54 1998/10/06 20:48:30 ecd Exp $
+/* $Id: head.S,v 1.60 1999/04/12 08:08:21 davem Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,7 @@
* Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
*/
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <asm/asm_offsets.h>
@@ -46,7 +47,7 @@ bootup_user_stack:
* HdrS version should be incremented.
*/
.global root_flags, ram_flags, root_dev
- .global ramdisk_image, ramdisk_size
+ .global sparc_ramdisk_image, sparc_ramdisk_size
.globl silo_args
.ascii "HdrS"
@@ -58,9 +59,9 @@ root_dev:
.half 0
ram_flags:
.half 0
-ramdisk_image:
+sparc_ramdisk_image:
.word 0
-ramdisk_size:
+sparc_ramdisk_size:
.word 0
.xword reboot_command
.xword bootstr_len
@@ -330,7 +331,7 @@ sun4u_init:
/* IMPORTANT NOTE: Whenever making changes here, check
* trampoline.S as well. -jj */
.globl setup_tba
-setup_tba:
+setup_tba: /* i0 = is_starfire */
save %sp, -160, %sp
rdpr %tba, %g7
@@ -376,9 +377,34 @@ setup_tba:
/* Setup Interrupt globals */
wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate
- sethi %hi(ivector_to_mask), %g5
- or %g5, %lo(ivector_to_mask), %g1 /* IVECTOR table */
- mov 0x40, %g2 /* INTR data 0 register */
+#ifndef __SMP__
+ sethi %hi(__up_workvec), %g5
+ or %g5, %lo(__up_workvec), %g1
+#else
+ /* By definition of where we are, this is boot_cpu. */
+ sethi %hi(cpu_data), %g5
+ or %g5, %lo(cpu_data), %g5
+
+ brz,pt %i0, not_starfire
+ sethi %hi(0x1fff4000), %g1
+ or %g1, %lo(0x1fff4000), %g1
+ sllx %g1, 12, %g1
+ or %g1, 0xd0, %g1
+ lduwa [%g1] ASI_PHYS_BYPASS_EC_E, %g1
+ b,pt %xcc, set_worklist
+ nop
+
+not_starfire:
+ ldxa [%g0] ASI_UPA_CONFIG, %g1
+ srlx %g1, 17, %g1
+ and %g1, 0x1f, %g1
+
+ /* In theory this is: &(cpu_data[boot_cpu_id].irq_worklists[0]) */
+set_worklist:
+ sllx %g1, 7, %g1
+ add %g5, %g1, %g5
+ add %g5, 64, %g1
+#endif
/* Kill PROM timer */
wr %g0, 0, %tick_cmpr
@@ -408,6 +434,13 @@ bootup_user_stack_end:
empty_bad_page:
.skip 0x2000
+#ifdef CONFIG_SBUS
+/* This is just a hack to fool make depend config.h discovering
+ strategy: As the .S files below need config.h, but
+ make depend does not find it for them, we include config.h
+ in head.S */
+#endif
+
! 0x0000000000408000
#include "ttable.S"
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 42f3de3b8..84d4de363 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.55 1998/11/17 07:43:17 davem Exp $
+/* $Id: ioctl32.c,v 1.62 1999/05/01 09:17:44 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -26,6 +26,7 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/fd.h>
+#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
#include <linux/mtio.h>
#include <linux/cdrom.h>
@@ -35,6 +36,7 @@
#include <linux/vt_kern.h>
#include <linux/fb.h>
#include <linux/ext2_fs.h>
+#include <linux/videodev.h>
#include <scsi/scsi.h>
/* Ugly hack. */
@@ -52,6 +54,7 @@
#include <asm/openpromio.h>
#include <asm/envctrl.h>
#include <asm/audioio.h>
+#include <asm/ethtool.h>
#include <linux/soundcard.h>
@@ -116,6 +119,247 @@ static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
return sys_ioctl(fd, cmd, arg);
}
+struct video_tuner32 {
+ s32 tuner;
+ u8 name[32];
+ u32 rangelow, rangehigh;
+ u32 flags;
+ u16 mode, signal;
+};
+
+static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+ int i;
+
+ if(get_user(kp->tuner, &up->tuner))
+ return -EFAULT;
+ for(i = 0; i < 32; i++)
+ __get_user(kp->name[i], &up->name[i]);
+ __get_user(kp->rangelow, &up->rangelow);
+ __get_user(kp->rangehigh, &up->rangehigh);
+ __get_user(kp->flags, &up->flags);
+ __get_user(kp->mode, &up->mode);
+ __get_user(kp->signal, &up->signal);
+ return 0;
+}
+
+static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up)
+{
+ int i;
+
+ if(put_user(kp->tuner, &up->tuner))
+ return -EFAULT;
+ for(i = 0; i < 32; i++)
+ __put_user(kp->name[i], &up->name[i]);
+ __put_user(kp->rangelow, &up->rangelow);
+ __put_user(kp->rangehigh, &up->rangehigh);
+ __put_user(kp->flags, &up->flags);
+ __put_user(kp->mode, &up->mode);
+ __put_user(kp->signal, &up->signal);
+ return 0;
+}
+
+struct video_buffer32 {
+ /* void * */ u32 base;
+ s32 height, width, depth, bytesperline;
+};
+
+static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+ u32 tmp;
+
+ if(get_user(tmp, &up->base))
+ return -EFAULT;
+ kp->base = (void *) ((unsigned long)tmp);
+ __get_user(kp->height, &up->height);
+ __get_user(kp->width, &up->width);
+ __get_user(kp->depth, &up->depth);
+ __get_user(kp->bytesperline, &up->bytesperline);
+ return 0;
+}
+
+static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->base);
+
+ if(put_user(tmp, &up->base))
+ return -EFAULT;
+ __put_user(kp->height, &up->height);
+ __put_user(kp->width, &up->width);
+ __put_user(kp->depth, &up->depth);
+ __put_user(kp->bytesperline, &up->bytesperline);
+ return 0;
+}
+
+struct video_clip32 {
+ s32 x, y, width, height;
+ /* struct video_clip32 * */ u32 next;
+};
+
+struct video_window32 {
+ u32 x, y, width, height, chromakey, flags;
+ /* struct video_clip32 * */ u32 clips;
+ s32 clipcount;
+};
+
+static void free_kvideo_clips(struct video_window *kp)
+{
+ struct video_clip *cp;
+
+ cp = kp->clips;
+ if(cp != NULL)
+ kfree(cp);
+}
+
+static int get_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+ struct video_clip32 *ucp;
+ struct video_clip *kcp;
+ int nclips, err, i;
+ u32 tmp;
+
+ if(get_user(kp->x, &up->x))
+ return -EFAULT;
+ __get_user(kp->y, &up->y);
+ __get_user(kp->width, &up->width);
+ __get_user(kp->height, &up->height);
+ __get_user(kp->chromakey, &up->chromakey);
+ __get_user(kp->flags, &up->flags);
+ __get_user(kp->clipcount, &up->clipcount);
+ __get_user(tmp, &up->clips);
+ ucp = (struct video_clip32 *)A(tmp);
+ kp->clips = NULL;
+
+ nclips = kp->clipcount;
+ if(nclips == 0)
+ return 0;
+
+ if(ucp == 0)
+ return -EINVAL;
+
+ /* Peculiar interface... */
+ if(nclips < 0)
+ nclips = VIDEO_CLIPMAP_SIZE;
+
+ kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL);
+ err = -ENOMEM;
+ if(kcp == NULL)
+ goto cleanup_and_err;
+
+ kp->clips = kcp;
+ for(i = 0; i < nclips; i++) {
+ __get_user(kcp[i].x, &ucp[i].x);
+ __get_user(kcp[i].y, &ucp[i].y);
+ __get_user(kcp[i].width, &ucp[i].width);
+ __get_user(kcp[i].height, &ucp[i].height);
+ kcp[nclips].next = NULL;
+ }
+
+ return 0;
+
+cleanup_and_err:
+ free_kvideo_clips(kp);
+ return err;
+}
+
+/* You get back everything except the clips... */
+static int put_video_window32(struct video_window *kp, struct video_window32 *up)
+{
+ if(put_user(kp->x, &up->x))
+ return -EFAULT;
+ __put_user(kp->y, &up->y);
+ __put_user(kp->width, &up->width);
+ __put_user(kp->height, &up->height);
+ __put_user(kp->chromakey, &up->chromakey);
+ __put_user(kp->flags, &up->flags);
+ __put_user(kp->clipcount, &up->clipcount);
+ return 0;
+}
+
+#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
+#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
+#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
+#define VIDIOCSWIN32 _IOW('v',10, struct video_window32)
+#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32)
+#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32)
+#define VIDIOCGFREQ32 _IOR('v',14, u32)
+#define VIDIOCSFREQ32 _IOW('v',15, u32)
+
+static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ union {
+ struct video_tuner vt;
+ struct video_buffer vb;
+ struct video_window vw;
+ unsigned long vx;
+ } karg;
+ mm_segment_t old_fs = get_fs();
+ void *up = (void *)arg;
+ int err = 0;
+
+ /* First, convert the command. */
+ switch(cmd) {
+ case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+ case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+ case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+ case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+ case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+ case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+ case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+ case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+ };
+
+ switch(cmd) {
+ case VIDIOCSTUNER:
+ case VIDIOCGTUNER:
+ err = get_video_tuner32(&karg.vt, up);
+ break;
+
+ case VIDIOCSWIN:
+ err = get_video_window32(&karg.vw, up);
+ break;
+
+ case VIDIOCSFBUF:
+ err = get_video_buffer32(&karg.vb, up);
+ break;
+
+ case VIDIOCSFREQ:
+ err = get_user(karg.vx, (u32 *)up);
+ break;
+ };
+ if(err)
+ goto out;
+
+ set_fs(KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)&karg);
+ set_fs(old_fs);
+
+ if(cmd == VIDIOCSWIN)
+ free_kvideo_clips(&karg.vw);
+
+ if(err == 0) {
+ switch(cmd) {
+ case VIDIOCGTUNER:
+ err = put_video_tuner32(&karg.vt, up);
+ break;
+
+ case VIDIOCGWIN:
+ err = put_video_window32(&karg.vw, up);
+ break;
+
+ case VIDIOCGFBUF:
+ err = put_video_buffer32(&karg.vb, up);
+ break;
+
+ case VIDIOCGFREQ:
+ err = put_user(((u32)karg.vx), (u32 *)up);
+ break;
+ };
+ }
+out:
+ return err;
+}
+
struct timeval32 {
int tv_sec;
int tv_usec;
@@ -253,11 +497,23 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long ar
case SIOCGPPPSTATS:
case SIOCGPPPCSTATS:
case SIOCGPPPVER:
+ case SIOCETHTOOL:
if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
return -EFAULT;
ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
if (!ifr.ifr_data)
return -EAGAIN;
+ if(cmd == SIOCETHTOOL) {
+ u32 data;
+
+ __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+ if(copy_from_user(ifr.ifr_data,
+ (char *)A(data),
+ sizeof(struct ethtool_cmd))) {
+ free_page((unsigned long)ifr.ifr_data);
+ return -EFAULT;
+ }
+ }
break;
default:
if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
@@ -280,17 +536,21 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long ar
case SIOCGIFBRDADDR:
case SIOCGIFDSTADDR:
case SIOCGIFNETMASK:
+ case SIOCGIFTXQLEN:
if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
return -EFAULT;
break;
case SIOCGPPPSTATS:
case SIOCGPPPCSTATS:
case SIOCGPPPVER:
+ case SIOCETHTOOL:
{
u32 data;
int len;
__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+ if(cmd == SIOCETHTOOL)
+ len = sizeof(struct ethtool_cmd);
if(cmd == SIOCGPPPVER)
len = strlen(PPP_VERSION) + 1;
else if(cmd == SIOCGPPPCSTATS)
@@ -298,7 +558,9 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long ar
else
len = sizeof(struct ppp_stats);
- if (copy_to_user((char *)A(data), ifr.ifr_data, len))
+ len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+ free_page((unsigned long)ifr.ifr_data);
+ if(len)
return -EFAULT;
break;
}
@@ -558,8 +820,7 @@ static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
if (!cmap.transp)
goto out;
- } else
- cmap.transp = NULL;
+ }
if (cmd == FBIOGETCMAP)
break;
@@ -1458,6 +1719,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case SIOCGPPPSTATS:
case SIOCGPPPCSTATS:
case SIOCGPPPVER:
+ case SIOCGIFTXQLEN:
+ case SIOCSIFTXQLEN:
+ case SIOCETHTOOL:
error = dev_ifsioc(fd, cmd, arg);
goto out;
@@ -1579,11 +1843,22 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
error = do_ext2_ioctl(fd, cmd, arg);
goto out;
+ case VIDIOCGTUNER32:
+ case VIDIOCSTUNER32:
+ case VIDIOCGWIN32:
+ case VIDIOCSWIN32:
+ case VIDIOCGFBUF32:
+ case VIDIOCSFBUF32:
+ case VIDIOCGFREQ32:
+ case VIDIOCSFREQ32:
+ error = do_video_ioctl(fd, cmd, arg);
+ goto out;
+
/* List here exlicitly which ioctl's are known to have
* compatable types passed or none at all...
*/
- /* Bit T */
+ /* Big T */
case TCGETA:
case TCSETA:
case TCSETAW:
@@ -1618,6 +1893,8 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case TIOCSPGRP:
case TIOCGPGRP:
case TIOCSCTTY:
+ case TIOCGPTN:
+ case TIOCSPTLCK:
/* Big F */
case FBIOGTYPE:
@@ -1770,6 +2047,33 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case VUIDSFORMAT:
case VUIDGFORMAT:
+ /* Little v, the video4linux ioctls */
+ case VIDIOCGCAP:
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
+ case VIDIOCGPICT:
+ case VIDIOCSPICT:
+ case VIDIOCCAPTURE:
+ case VIDIOCKEY:
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ case VIDIOCSYNC:
+ case VIDIOCMCAPTURE:
+ case VIDIOCGMBUF:
+ case VIDIOCGUNIT:
+ case VIDIOCGCAPTURE:
+ case VIDIOCSCAPTURE:
+
+ /* BTTV specific... */
+ case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
+ case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
+ case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
+ case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
+ case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
+
/* Little p (/dev/rtc, /dev/envctrl, etc.) */
case RTCGET:
case RTCSET:
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index d8707261f..6eccb883a 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.66 1998/10/21 15:02:25 ecd Exp $
+/* $Id: irq.c,v 1.76 1999/04/02 14:54:30 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -41,20 +41,30 @@
#define SA_DMA_SYNC 0x200
#ifdef __SMP__
-void distribute_irqs(void);
-static int irqs_have_been_distributed = 0;
+static void distribute_irqs(void);
#endif
-/* UPA nodes send interrupt packet to UltraSparc with first data reg value
- * low 5 bits holding the IRQ identifier being delivered. We must translate
- * this into a non-vector IRQ so we can set the softint on this cpu. To
- * make things even more swift we store the complete mask here.
+/* UPA nodes send interrupt packet to UltraSparc with first data reg
+ * value low 5 (7 on Starfire) bits holding the IRQ identifier being
+ * delivered. We must translate this into a non-vector IRQ so we can
+ * set the softint on this cpu.
+ *
+ * To make processing these packets efficient and race free we use
+ * an array of irq buckets below. The interrupt vector handler in
+ * entry.S feeds incoming packets into per-cpu pil-indexed lists.
+ * The IVEC handler does not need to act atomically, the PIL dispatch
+ * code uses CAS to get an atomic snapshot of the list and clear it
+ * at the same time.
*/
-#define NUM_HARD_IVECS 2048
-#define NUM_IVECS (NUM_HARD_IVECS + 64) /* For SMP IRQ distribution alg. */
+struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (64)));
-unsigned long ivector_to_mask[NUM_IVECS];
+#ifndef __SMP__
+unsigned int __up_workvec[16] __attribute__ ((aligned (64)));
+#define irq_work(__cpu, __pil) &(__up_workvec[(__pil)])
+#else
+#define irq_work(__cpu, __pil) &(cpu_data[(__cpu)].irq_worklists[(__pil)])
+#endif
/* This is based upon code in the 32-bit Sparc kernel written mostly by
* David Redman (djhr@tadpole.co.uk).
@@ -63,30 +73,21 @@ unsigned long ivector_to_mask[NUM_IVECS];
static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
static int static_irq_count = 0;
-/* XXX Must be exported so that fast IRQ handlers can get at it... -DaveM */
+/* This is exported so that fast IRQ handlers can get at it... -DaveM */
struct irqaction *irq_action[NR_IRQS+1] = {
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
};
-#define IBF_DMA_SYNC 0x01
-#define IBF_PCI 0x02
-#define IBF_ACTIVE 0x04
+/* Only 8-bits are available, be careful. -DaveM */
+#define IBF_DMA_SYNC 0x01 /* DMA synchronization behind PCI bridge needed. */
+#define IBF_PCI 0x02 /* Indicates PSYCHO/SCHIZO PCI interrupt. */
+#define IBF_ACTIVE 0x04 /* This interrupt is active and has a handler. */
+#define IBF_MULTI 0x08 /* On PCI, indicates shared bucket. */
-#define __imap(bucket) ((bucket)->iclr + (bucket)->imap_off)
#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
#define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
-static struct ino_bucket *bucket_base, *buckets, *endbuckets;
-
-__initfunc(unsigned long irq_init(unsigned long start_mem, unsigned long end_mem))
-{
- start_mem = (start_mem + 15) & ~15;
- bucket_base = buckets = (struct ino_bucket *)start_mem;
- endbuckets = buckets + 2048;
- return (unsigned long)endbuckets;
-}
-
int get_irq_list(char *buf)
{
int i, len = 0;
@@ -104,7 +105,7 @@ int get_irq_list(char *buf)
#else
for (j = 0; j < smp_num_cpus; j++)
len += sprintf(buf + len, "%10u ",
- kstat.irqs[cpu_logical_map(j)][i]);
+ kstat.irqs[cpu_logical_map(j)][i]);
#endif
len += sprintf(buf + len, "%c %s",
(action->flags & SA_INTERRUPT) ? '+' : ' ',
@@ -224,8 +225,7 @@ unsigned char psycho_ino_to_pil[] = {
1, /* Power Management */
};
-/* INO number to IMAP register offset for PSYCHO external IRQ's.
- */
+/* INO number to IMAP register offset for PSYCHO external IRQ's. */
#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
#define psycho_imap_offset(ino) \
@@ -241,16 +241,27 @@ unsigned char psycho_ino_to_pil[] = {
/* Now these are always passed a true fully specified sun4u INO. */
void enable_irq(unsigned int irq)
{
+ extern int this_is_starfire;
struct ino_bucket *bucket = __bucket(irq);
- unsigned long tid;
unsigned int *imap;
+ unsigned long tid;
- imap = __imap(bucket);
- if (!imap) return;
+ imap = bucket->imap;
+ if (!imap)
+ return;
- /* We send it to our UPA MID, for SMP this will be different. */
- __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
- tid = ((tid & UPA_CONFIG_MID) << 9);
+ if(this_is_starfire == 0) {
+ /* We set it to our UPA MID. */
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (tid)
+ : "i" (ASI_UPA_CONFIG));
+ tid = ((tid & UPA_CONFIG_MID) << 9);
+ } else {
+ extern unsigned int starfire_translate(unsigned int *imap,
+ unsigned int upaid);
+
+ tid = (starfire_translate(imap, current->processor) << 26);
+ }
/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
* of this SYSIO's preconfigured IGN in the SYSIO Control
@@ -269,35 +280,83 @@ void disable_irq(unsigned int irq)
struct ino_bucket *bucket = __bucket(irq);
unsigned int *imap;
- imap = __imap(bucket);
- if (!imap) return;
-
- /* NOTE: We do not want to futz with the IRQ clear registers
- * and move the state to IDLE, the SCSI code does call
- * disable_irq() to assure atomicity in the queue cmd
- * SCSI adapter driver code. Thus we'd lose interrupts.
- */
- *imap &= ~(SYSIO_IMAP_VALID);
+ imap = bucket->imap;
+ if (imap != NULL) {
+ /* NOTE: We do not want to futz with the IRQ clear registers
+ * and move the state to IDLE, the SCSI code does call
+ * disable_irq() to assure atomicity in the queue cmd
+ * SCSI adapter driver code. Thus we'd lose interrupts.
+ */
+ *imap &= ~(SYSIO_IMAP_VALID);
+ }
}
+/* The timer is the one "weird" interrupt which is generated by
+ * the CPU %tick register and not by some normal vectored interrupt
+ * source. To handle this special case, we use this dummy INO bucket.
+ */
+static struct ino_bucket pil0_dummy_bucket = {
+ 0, /* irq_chain */
+ 0, /* pil */
+ 0, /* pending */
+ 0, /* flags */
+ 0, /* __unused */
+ NULL, /* irq_info */
+ NULL, /* iclr */
+ NULL, /* imap */
+};
+
unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap)
{
- if (buckets == endbuckets)
- panic("Out of IRQ buckets. Should not happen.\n");
- buckets->pil = pil;
- if (pil && (!iclr || !imap)) {
- prom_printf("Invalid build_irq %d %d %016lx %016lx\n", pil, inofixup, iclr, imap);
+ struct ino_bucket *bucket;
+ int ino;
+
+ if(pil == 0) {
+ if(iclr != NULL || imap != NULL) {
+ prom_printf("Invalid dummy bucket for PIL0 (%p:%p)\n",
+ iclr, imap);
+ prom_halt();
+ }
+ return __irq(&pil0_dummy_bucket);
+ }
+
+ /* RULE: Both must be specified in all other cases. */
+ if (iclr == NULL || imap == NULL) {
+ prom_printf("Invalid build_irq %d %d %016lx %016lx\n",
+ pil, inofixup, iclr, imap);
prom_halt();
}
- if (imap)
- buckets->ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup;
- else
- buckets->ino = 0;
-
- buckets->iclr = iclr;
- buckets->flags = 0;
- buckets->imap_off = imap - iclr;
- return __irq(buckets++);
+
+ ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup;
+ if(ino > NUM_IVECS) {
+ prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n",
+ ino, pil, inofixup, iclr, imap);
+ prom_halt();
+ }
+
+ /* Ok, looks good, set it up. Don't touch the irq_chain or
+ * the pending flag.
+ */
+ bucket = &ivector_table[ino];
+ if ((bucket->flags & IBF_ACTIVE) ||
+ (bucket->irq_info != NULL)) {
+ /* This is a gross fatal error if it happens here. */
+ prom_printf("IRQ: Trying to reinit INO bucket, fatal error.\n");
+ prom_printf("IRQ: Request INO %04x (%d:%d:%016lx:%016lx)\n",
+ ino, pil, inofixup, iclr, imap);
+ prom_printf("IRQ: Existing (%d:%016lx:%016lx)\n",
+ bucket->pil, bucket->iclr, bucket->imap);
+ prom_printf("IRQ: Cannot continue, halting...\n");
+ prom_halt();
+ }
+ bucket->imap = imap;
+ bucket->iclr = iclr;
+ bucket->pil = pil;
+ bucket->flags = 0;
+
+ bucket->irq_info = NULL;
+
+ return __irq(bucket);
}
unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
@@ -382,8 +441,44 @@ unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_d
if(!(ino & 0x20))
inofixup = ino & 0x03;
- bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
-
+ /* First check for sharing. */
+ ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup;
+ if (ino > NUM_IVECS) {
+ prom_printf("PSYCHO: Invalid INO %04x (%d:%d:%016lx:%016lx)\n",
+ ino, pil, inofixup, iclr, imap);
+ prom_halt();
+ }
+ bucket = &ivector_table[ino];
+ if(bucket->flags & IBF_ACTIVE) {
+ void *old_handler = bucket->irq_info;
+ unsigned long flags;
+
+ if(old_handler == NULL) {
+ prom_printf("PSYCHO: Active bucket, but no handler.\n");
+ prom_halt();
+ }
+ save_and_cli(flags);
+ if((bucket->flags & IBF_MULTI) == 0) {
+ void **vector;
+
+ vector = kmalloc(sizeof(void *) * 4,
+ GFP_KERNEL);
+
+ /* We might have slept. */
+ if((bucket->flags & IBF_MULTI) != 0) {
+ kfree(vector);
+ } else {
+ vector[0] = old_handler;
+ vector[1] = vector[2] = vector[3] = NULL;
+ bucket->irq_info = vector;
+ bucket->flags |= IBF_MULTI;
+ }
+ }
+ restore_flags(flags);
+ } else {
+ /* Just init the bucket */
+ bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+ }
if (need_dma_sync)
bucket->flags |= IBF_DMA_SYNC;
@@ -392,6 +487,20 @@ unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_d
}
#endif
+static void atomic_bucket_insert(struct ino_bucket *bucket)
+{
+ unsigned long pstate;
+ unsigned int *ent;
+
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+ __asm__ __volatile__("wrpr %0, %1, %%pstate"
+ : : "r" (pstate), "i" (PSTATE_IE));
+ ent = irq_work(smp_processor_id(), bucket->pil);
+ bucket->irq_chain = *ent;
+ *ent = __irq(bucket);
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
+}
+
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char *name, void *dev_id)
{
@@ -400,11 +509,16 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
unsigned long flags;
int pending = 0;
- if (irq < 0x400000 || (irq & 0x80000000)) {
- prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler);
- prom_halt();
- }
-
+ if ((bucket != &pil0_dummy_bucket) &&
+ (bucket < &ivector_table[0] ||
+ bucket >= &ivector_table[NUM_IVECS])) {
+ unsigned int *caller;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ printk(KERN_CRIT "request_irq: Old style IRQ registry attempt "
+ "from %p, irq %08x.\n", caller, irq);
+ return -EINVAL;
+ }
if(!handler)
return -EINVAL;
@@ -429,24 +543,26 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
}
}
+ save_and_cli(flags);
+
action = *(bucket->pil + irq_action);
if(action) {
if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ))
for (tmp = action; tmp->next; tmp = tmp->next)
;
- else
+ else {
+ restore_flags(flags);
return -EBUSY;
-
+ }
if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) {
printk("Attempt to mix fast and slow interrupts on IRQ%d "
"denied\n", bucket->pil);
+ restore_flags(flags);
return -EBUSY;
}
action = NULL; /* Or else! */
}
- save_and_cli(flags);
-
/* If this is flagged as statically allocated then we use our
* private struct which is never freed.
*/
@@ -466,12 +582,65 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
return -ENOMEM;
}
- if (irqflags & SA_IMAP_MASKED) {
- pending = ((ivector_to_mask[bucket->ino] & 0x80000000) != 0);
- ivector_to_mask[bucket->ino] = (1 << bucket->pil);
- if(pending)
- ivector_to_mask[bucket->ino] |= 0x80000000;
+ if ((irqflags & SA_IMAP_MASKED) == 0) {
+ bucket->irq_info = action;
bucket->flags |= IBF_ACTIVE;
+ } else {
+ if((bucket->flags & IBF_ACTIVE) != 0) {
+ void *orig = bucket->irq_info;
+ void **vector = NULL;
+
+ if((bucket->flags & IBF_PCI) == 0) {
+ printk("IRQ: Trying to share non-PCI bucket.\n");
+ goto free_and_ebusy;
+ }
+ if((bucket->flags & IBF_MULTI) == 0) {
+ vector = kmalloc(sizeof(void *) * 4, GFP_KERNEL);
+ if(vector == NULL)
+ goto free_and_enomem;
+
+ /* We might have slept. */
+ if ((bucket->flags & IBF_MULTI) != 0) {
+ int ent;
+
+ kfree(vector);
+ vector = (void **)bucket->irq_info;
+ for(ent = 0; ent < 4; ent++) {
+ if (vector[ent] == NULL) {
+ vector[ent] = action;
+ break;
+ }
+ }
+ if (ent == 4)
+ goto free_and_ebusy;
+ } else {
+ vector[0] = orig;
+ vector[1] = action;
+ vector[2] = NULL;
+ vector[3] = NULL;
+ bucket->irq_info = vector;
+ bucket->flags |= IBF_MULTI;
+ }
+ } else {
+ int ent;
+
+ vector = (void **)orig;
+ for(ent = 0; ent < 4; ent++) {
+ if(vector[ent] == NULL) {
+ vector[ent] = action;
+ break;
+ }
+ }
+ if (ent == 4)
+ goto free_and_ebusy;
+ }
+ } else {
+ bucket->irq_info = action;
+ bucket->flags |= IBF_ACTIVE;
+ }
+ pending = bucket->pending;
+ if(pending)
+ bucket->pending = 0;
}
action->mask = (unsigned long) bucket;
@@ -489,15 +658,26 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
enable_irq(irq);
/* We ate the IVEC already, this makes sure it does not get lost. */
- if(pending)
+ if(pending) {
+ atomic_bucket_insert(bucket);
set_softint(1 << bucket->pil);
-
+ }
restore_flags(flags);
+
#ifdef __SMP__
- if(irqs_have_been_distributed)
- distribute_irqs();
+ distribute_irqs();
#endif
return 0;
+
+free_and_ebusy:
+ kfree(action);
+ restore_flags(flags);
+ return -EBUSY;
+
+free_and_enomem:
+ kfree(action);
+ restore_flags(flags);
+ return -ENOMEM;
}
void free_irq(unsigned int irq, void *dev_id)
@@ -507,9 +687,15 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long flags;
struct ino_bucket *bucket = __bucket(irq), *bp;
- if (irq < 0x400000 || (irq & 0x80000000)) {
- prom_printf("free_irq with old style irq %08x\n", irq);
- prom_halt();
+ if ((bucket != &pil0_dummy_bucket) &&
+ (bucket < &ivector_table[0] ||
+ bucket >= &ivector_table[NUM_IVECS])) {
+ unsigned int *caller;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ printk(KERN_CRIT "free_irq: Old style IRQ removal attempt "
+ "from %p, irq %08x.\n", caller, irq);
+ return;
}
action = *(bucket->pil + irq_action);
@@ -545,27 +731,59 @@ void free_irq(unsigned int irq, void *dev_id)
*(bucket->pil + irq_action) = action->next;
if(action->flags & SA_IMAP_MASKED) {
- unsigned int *imap = __imap(bucket);
+ unsigned int *imap = bucket->imap;
+ void **vector, *orig;
+ int ent;
+
+ orig = bucket->irq_info;
+ vector = (void **)orig;
+
+ if ((bucket->flags & IBF_MULTI) != 0) {
+ int other = 0;
+ void *orphan = NULL;
+ for(ent = 0; ent < 4; ent++) {
+ if(vector[ent] == action)
+ vector[ent] = NULL;
+ else if(vector[ent] != NULL) {
+ orphan = vector[ent];
+ other++;
+ }
+ }
- /*
- * Only free when no other shared irq uses this bucket.
- */
- tmp = *(bucket->pil + irq_action);
- for( ; tmp; tmp = tmp->next)
- if ((struct ino_bucket *)tmp->mask == bucket)
+ /* Only free when no other shared irq
+ * uses this bucket.
+ */
+ if(other) {
+ if (other == 1) {
+ /* Convert back to non-shared bucket. */
+ bucket->irq_info = orphan;
+ bucket->flags &= ~(IBF_MULTI);
+ kfree(vector);
+ }
goto out;
+ }
+ } else {
+ bucket->irq_info = NULL;
+ }
- ivector_to_mask[bucket->ino] = 0;
-
+ /* This unique interrupt source is now inactive. */
bucket->flags &= ~IBF_ACTIVE;
- for (bp = bucket_base; bp < endbuckets; bp++)
- if (__imap(bp) == imap && (bp->flags & IBF_ACTIVE))
+
+ /* See if any other buckets share this bucket's IMAP
+ * and are still active.
+ */
+ for(ent = 0; ent < NUM_IVECS; ent++) {
+ bp = &ivector_table[ent];
+ if(bp != bucket &&
+ bp->imap == imap &&
+ (bp->flags & IBF_ACTIVE) != 0)
break;
- /*
- * Only disable when no other sub-irq levels of
- * the same imap are active.
+ }
+
+ /* Only disable when no other sub-irq levels of
+ * the same IMAP are active.
*/
- if (bp == endbuckets)
+ if (ent == NUM_IVECS)
disable_irq(irq);
}
@@ -607,10 +825,10 @@ static void show(char * str)
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
- printk("irq: %d [%d %d]\n",
+ printk("irq: %d [%ld %ld]\n",
atomic_read(&global_irq_count),
cpu_data[0].irq_count, cpu_data[1].irq_count);
- printk("bh: %d [%d %d]\n",
+ printk("bh: %d [%ld %ld]\n",
(spin_is_locked(&global_bh_count) ? 1 : 0),
cpu_data[0].bh_count, cpu_data[1].bh_count);
}
@@ -755,57 +973,56 @@ void __global_restore_flags(unsigned long flags)
#endif /* __SMP__ */
-void report_spurious_ivec(struct pt_regs *regs)
+void catch_disabled_ivec(struct pt_regs *regs)
{
- extern unsigned long ivec_spurious_cookie;
-
-#if 0
- printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n",
- ivec_spurious_cookie, regs->tpc);
-#endif
+ int cpu = smp_processor_id();
+ struct ino_bucket *bucket = __bucket(*irq_work(cpu, 0));
/* We can actually see this on Ultra/PCI PCI cards, which are bridges
* to other devices. Here a single IMAP enabled potentially multiple
* unique interrupt sources (which each do have a unique ICLR register.
*
* So what we do is just register that the IVEC arrived, when registered
- * for real the request_irq() code will check the high bit and signal
+ * for real the request_irq() code will check the bit and signal
* a local CPU interrupt for it.
*/
- ivector_to_mask[ivec_spurious_cookie] |= (0x80000000);
+#if 0
+ printk("IVEC: Spurious interrupt vector (%x) received at (%016lx)\n",
+ bucket - &ivector_table[0], regs->tpc);
+#endif
+ *irq_work(cpu, 0) = 0;
+ bucket->pending = 1;
}
-void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
-{
- int i;
- struct irqaction *action;
- unsigned int cpu_irq;
-
- cpu_irq = irq & NR_IRQS;
- action = *(cpu_irq + irq_action);
-
- prom_printf("Unexpected IRQ[%d]: ", irq);
- prom_printf("PC[%016lx] NPC[%016lx] FP[%016lx]\n",
- regs->tpc, regs->tnpc, regs->u_regs[14]);
-
- if(action) {
- prom_printf("Expecting: ");
- for(i = 0; i < 16; i++) {
- if(action->handler)
- prom_printf("[%s:%d:0x%016lx] ", action->name,
- i, (unsigned long) action->handler);
- }
- }
- prom_printf("AIEEE\n");
- prom_printf("bogus interrupt received\n");
- prom_cmdline ();
-}
+/* Tune this... */
+#define FORWARD_VOLUME 12
void handler_irq(int irq, struct pt_regs *regs)
{
- struct ino_bucket *bucket = NULL;
- struct irqaction *action, *act;
+ struct ino_bucket *bp, *nbp;
int cpu = smp_processor_id();
+#ifdef __SMP__
+ extern int this_is_starfire;
+ int should_forward = (this_is_starfire == 0 &&
+ irq < 10 &&
+ current->pid != 0);
+ unsigned int buddy = 0;
+
+ /* 'cpu' is the MID (ie. UPAID), calculate the MID
+ * of our buddy.
+ */
+ if(should_forward != 0) {
+ buddy = cpu_number_map[cpu] + 1;
+ if (buddy >= NR_CPUS ||
+ (buddy = cpu_logical_map(buddy)) == -1)
+ buddy = cpu_logical_map(0);
+
+ /* Voo-doo programming. */
+ if(cpu_data[buddy].idle_volume < FORWARD_VOLUME)
+ should_forward = 0;
+ buddy <<= 26;
+ }
+#endif
#ifndef __SMP__
/*
@@ -817,30 +1034,55 @@ void handler_irq(int irq, struct pt_regs *regs)
clear_softint(1 << irq);
irq_enter(cpu, irq);
- action = *(irq + irq_action);
kstat.irqs[cpu][irq]++;
- if(!action) {
- unexpected_irq(irq, 0, regs);
- } else {
- act = action;
- do {
- if(act->flags & SA_IMAP_MASKED) {
- bucket = (struct ino_bucket *)act->mask;
- if(!(ivector_to_mask[bucket->ino] & 0x80000000))
- continue;
+
+ /* Sliiiick... */
+#ifndef __SMP__
+ bp = ((irq != 0) ?
+ __bucket(xchg32(irq_work(cpu, irq), 0)) :
+ &pil0_dummy_bucket);
+#else
+ bp = __bucket(xchg32(irq_work(cpu, irq), 0));
+#endif
+ for( ; bp != NULL; bp = nbp) {
+ unsigned char flags = bp->flags;
+
+ nbp = __bucket(bp->irq_chain);
+ if((flags & IBF_ACTIVE) != 0) {
+ if((flags & IBF_MULTI) == 0) {
+ struct irqaction *ap = bp->irq_info;
+ ap->handler(__irq(bp), ap->dev_id, regs);
+ } else {
+ void **vector = (void **)bp->irq_info;
+ int ent;
+ for(ent = 0; ent < 4; ent++) {
+ struct irqaction *ap = vector[ent];
+ if(ap != NULL)
+ ap->handler(__irq(bp), ap->dev_id, regs);
+ }
}
- act->handler(__irq(bucket), act->dev_id, regs);
- } while((act = act->next) != NULL);
- act = action;
- do {
- if(act->flags & SA_IMAP_MASKED) {
- bucket = (struct ino_bucket *)act->mask;
- if(!(ivector_to_mask[bucket->ino] & 0x80000000))
- continue;
- ivector_to_mask[bucket->ino] &= ~(0x80000000);
- *(bucket->iclr) = SYSIO_ICLR_IDLE;
+ /* Only the dummy bucket lacks IMAP/ICLR. */
+ if(bp->pil != 0) {
+#ifdef __SMP__
+ /* Ok, here is what is going on:
+ * 1) Retargeting IRQs on Starfire is very
+ * expensive so just forget about it on them.
+ * 2) Moving around very high priority interrupts
+ * is a losing game.
+ * 3) If the current cpu is idle, interrupts are
+ * useful work, so keep them here. But do not
+ * pass to our neighbour if he is not very idle.
+ */
+ if (should_forward != 0) {
+ /* Push it to our buddy. */
+ should_forward = 0;
+ *(bp->imap) = (buddy | SYSIO_IMAP_VALID);
+ }
+#endif
+ *(bp->iclr) = SYSIO_ICLR_IDLE;
}
- } while((act = act->next) != NULL);
+ } else
+ bp->pending = 1;
}
irq_exit(cpu, irq);
}
@@ -856,10 +1098,13 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
+
+ *(irq_work(cpu, irq)) = 0;
bucket = (struct ino_bucket *)action->mask;
+
floppy_interrupt(irq, dev_cookie, regs);
- ivector_to_mask[bucket->ino] &= ~(0x80000000);
*(bucket->iclr) = SYSIO_ICLR_IDLE;
+
irq_exit(cpu, irq);
}
#endif
@@ -897,11 +1142,21 @@ int request_fast_irq(unsigned int irq,
struct ino_bucket *bucket = __bucket(irq);
unsigned long flags;
- if (irq < 0x400000 || (irq & 0x80000000)) {
- prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler);
- prom_halt();
- }
+ /* No pil0 dummy buckets allowed here. */
+ if (bucket < &ivector_table[0] ||
+ bucket >= &ivector_table[NUM_IVECS]) {
+ unsigned int *caller;
+
+ __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+ printk(KERN_CRIT "request_fast_irq: Old style IRQ registry attempt "
+ "from %p, irq %08x.\n", caller, irq);
+ return -EINVAL;
+ }
+ /* Only IMAP style interrupts can be registered as fast. */
+ if(bucket->pil == 0)
+ return -EINVAL;
+
if(!handler)
return -EINVAL;
@@ -919,6 +1174,7 @@ int request_fast_irq(unsigned int irq,
printk("request_fast_irq: Trying to register yet already owned.\n");
return -EBUSY;
}
+
save_and_cli(flags);
if(irqflags & SA_STATIC_ALLOC) {
if(static_irq_count < MAX_STATIC_ALLOC)
@@ -936,7 +1192,8 @@ int request_fast_irq(unsigned int irq,
}
install_fast_irq(bucket->pil, handler);
- ivector_to_mask[bucket->ino] = (1 << bucket->pil);
+ bucket->irq_info = action;
+ bucket->flags |= IBF_ACTIVE;
action->mask = (unsigned long) bucket;
action->handler = handler;
@@ -949,9 +1206,9 @@ int request_fast_irq(unsigned int irq,
enable_irq(irq);
restore_flags(flags);
+
#ifdef __SMP__
- if(irqs_have_been_distributed)
- distribute_irqs();
+ distribute_irqs();
#endif
return 0;
}
@@ -1025,50 +1282,51 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
}
#ifdef __SMP__
-/* Called from smp_commence, when we know how many cpus are in the system
- * and can have device IRQ's directed at them.
- */
-/* #define SMP_IRQ_VERBOSE */
-void distribute_irqs(void)
+static int retarget_one_irq(struct irqaction *p, int goal_cpu)
+{
+ extern int this_is_starfire;
+ struct ino_bucket *bucket = __bucket(p->mask);
+ unsigned int *imap = bucket->imap;
+ unsigned int tid;
+
+ /* Never change this, it causes problems on Ex000 systems. */
+ if (bucket->pil == 12)
+ return goal_cpu;
+
+ if(this_is_starfire == 0) {
+ tid = __cpu_logical_map[goal_cpu] << 26;
+ } else {
+ extern unsigned int starfire_translate(unsigned int *imap,
+ unsigned int upaid);
+
+ tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26);
+ }
+ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+
+ goal_cpu++;
+ if(goal_cpu >= NR_CPUS ||
+ __cpu_logical_map[goal_cpu] == -1)
+ goal_cpu = 0;
+ return goal_cpu;
+}
+
+/* Called from request_irq. */
+static void distribute_irqs(void)
{
unsigned long flags;
int cpu, level;
-#ifdef SMP_IRQ_VERBOSE
- printk("SMP: redistributing interrupts...\n");
-#endif
save_and_cli(flags);
cpu = 0;
for(level = 0; level < NR_IRQS; level++) {
struct irqaction *p = irq_action[level];
-
while(p) {
- if(p->flags & SA_IMAP_MASKED) {
- struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
- unsigned int *imap = __imap(bucket);
- unsigned int val;
- unsigned long tid = __cpu_logical_map[cpu] << 26;
-
- val = *imap;
- *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
-
-#ifdef SMP_IRQ_VERBOSE
- printk("SMP: Redirecting IGN[%x] INO[%x] "
- "to cpu %d [%s]\n",
- (val & SYSIO_IMAP_IGN) >> 6,
- (val & SYSIO_IMAP_INO), cpu,
- p->name);
-#endif
-
- cpu++;
- if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1)
- cpu = 0;
- }
+ if(p->flags & SA_IMAP_MASKED)
+ cpu = retarget_one_irq(p, cpu);
p = p->next;
}
}
restore_flags(flags);
- irqs_have_been_distributed = 1;
}
#endif
@@ -1146,13 +1404,13 @@ __initfunc(void init_IRQ(void))
static int called = 0;
if (called == 0) {
- int i;
-
called = 1;
map_prom_timers();
kill_prom_timer();
- for(i = 0; i < NUM_IVECS; i++)
- ivector_to_mask[i] = 0;
+ memset(&ivector_table[0], 0, sizeof(ivector_table));
+#ifndef __SMP__
+ memset(&__up_workvec[0], 0, sizeof(__up_workvec));
+#endif
}
/* We need to clear any IRQ's pending in the soft interrupt
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S
index 34a542ac5..eefc1c074 100644
--- a/arch/sparc64/kernel/itlb_base.S
+++ b/arch/sparc64/kernel/itlb_base.S
@@ -1,4 +1,4 @@
-/* $Id: itlb_base.S,v 1.5 1998/06/15 16:59:32 jj Exp $
+/* $Id: itlb_base.S,v 1.7 1999/03/02 15:42:12 jj Exp $
* itlb_base.S: Front end to ITLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -15,11 +15,9 @@
* 2) All user instruction misses.
*
* All real page faults merge their code paths to the
- * sparc64_realfault_* labels below.
+ * sparc64_realfault_common label below.
*/
- .globl sparc64_vpte_patchme
-
/* ITLB ** ICACHE line 1: Quick user TLB misses */
ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS
srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset
@@ -42,28 +40,25 @@
/* ITLB ** ICACHE line 3: Real faults */
rdpr %tpc, %g5 ! And load faulting VA
+ clr %g4 ! It was read
sparc64_realfault_common: ! Called by TL0 dtlb_miss too
sethi %hi(1f), %g7 ! Save state
ba,pt %xcc, etrap ! ...
1: or %g7, %lo(1b), %g7 ! ...
- clr %o2 ! It was read
-sparc64_realfault_continue: ! Called by dtlb_prot handler
+ mov %l4, %o2 ! Read/Write/No idea
srlx %l5, PAGE_SHIFT, %o1 ! Page align faulting VA
add %sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg
- call do_sparc64_fault ! Call fault handler
/* ITLB ** ICACHE line 4: Call fault processing code */
+ call do_sparc64_fault ! Call fault handler
sllx %o1, PAGE_SHIFT, %o1 ! Finish page alignment
ba,a,pt %xcc, rtrap_clr_l6 ! Restore cpu state
+ nop
winfix_trampoline:
rdpr %tpc, %g3 ! Prepare winfixup TNPC
or %g3, 0x7c, %g3 ! Compute offset to branch
wrpr %g3, %tnpc ! Write it into TNPC
done ! Do it to it
-sparc64_vpte_nucleus:
- ba,pt %xcc, sparc64_vpte_continue ! Part of dtlb_backend
-sparc64_vpte_patchme:
- sethi %hi(0), %g5 ! This has to be patched
#undef TAG_CONTEXT_BITS
#undef VPTE_SHIFT
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index c5c7061f7..0d4871132 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.82 1998/10/19 21:52:23 davem Exp $
+/* $Id: process.c,v 1.92 1999/05/08 23:04:48 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -53,11 +53,19 @@ asmlinkage int sys_idle(void)
/* endless idle loop with no priority at all */
current->priority = 0;
- current->counter = 0;
+ current->counter = -100;
+ init_idle();
+
for (;;) {
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
+ /* If current->need_resched is zero we should really
+ * setup for a system wakup event and execute a shutdown
+ * instruction.
+ *
+ * But this requires writing back the contents of the
+ * L2 cache etc. so implement this later. -DaveM
+ */
schedule();
+ check_pgt_cache();
}
return 0;
}
@@ -67,20 +75,27 @@ asmlinkage int sys_idle(void)
/*
* the idle loop on a UltraMultiPenguin...
*/
+#define idle_me_harder() (cpu_data[current->processor].idle_volume += 1)
+#define unidle_me() (cpu_data[current->processor].idle_volume = 0)
asmlinkage int cpu_idle(void)
{
current->priority = 0;
- while(1) {
- struct task_struct *p;
+ current->counter = -100;
+ init_idle();
- check_pgt_cache();
- run_task_queue(&tq_scheduler);
- current->counter = 0;
- if (current->need_resched != 0 ||
- ((p = init_task.next_run) != NULL &&
- (p->processor == smp_processor_id() ||
- (p->tss.flags & SPARC_FLAG_NEWCHILD) != 0)))
+ while(1) {
+ if (current->need_resched != 0) {
+ unidle_me();
schedule();
+ check_pgt_cache();
+ }
+ idle_me_harder();
+
+ /* The store ordering is so that IRQ handlers on
+ * other cpus see our increasing idleness for the buddy
+ * redistribution algorithm. -DaveM
+ */
+ membar("#StoreStore | #StoreLoad");
}
}
@@ -158,12 +173,12 @@ static void show_regwindow32(struct pt_regs *regs)
}
rw = &r_w;
set_fs (old_fs);
- printk("l0: %016x l1: %016x l2: %016x l3: %016x\n"
- "l4: %016x l5: %016x l6: %016x l7: %016x\n",
+ printk("l0: %08x l1: %08x l2: %08x l3: %08x "
+ "l4: %08x l5: %08x l6: %08x l7: %08x\n",
rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
- printk("i0: %016x i1: %016x i2: %016x i3: %016x\n"
- "i4: %016x i5: %016x i6: %016x i7: %016x\n",
+ printk("i0: %08x i1: %08x i2: %08x i3: %08x "
+ "i4: %08x i5: %08x i6: %08x i7: %08x\n",
rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
}
@@ -340,13 +355,13 @@ void show_regs32(struct pt_regs32 *regs)
{
printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr,
regs->pc, regs->npc, regs->y);
- printk("g0: %08x g1: %08x g2: %08x g3: %08x\n",
+ printk("g0: %08x g1: %08x g2: %08x g3: %08x ",
regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
regs->u_regs[3]);
printk("g4: %08x g5: %08x g6: %08x g7: %08x\n",
regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
regs->u_regs[7]);
- printk("o0: %08x o1: %08x o2: %08x o3: %08x\n",
+ printk("o0: %08x o1: %08x o2: %08x o3: %08x ",
regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
regs->u_regs[11]);
printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n",
@@ -427,9 +442,7 @@ void flush_thread(void)
/* exec_mmap() set context to NO_CONTEXT, here is
* where we grab a new one.
*/
- current->mm->cpu_vm_mask = 0;
activate_context(current);
- current->mm->cpu_vm_mask = (1UL<<smp_processor_id());
}
if (current->tss.flags & SPARC_FLAG_32BIT)
__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -447,6 +460,11 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
{
unsigned long fp, distance, rval;
+ /* do_fork() grabs the parent semaphore, we must release it
+ * temporarily so we can build the child clone stack frame
+ * without deadlocking.
+ */
+ up(&current->mm->mmap_sem);
if(!(current->tss.flags & SPARC_FLAG_32BIT)) {
csp += STACK_BIAS;
psp += STACK_BIAS;
@@ -463,17 +481,20 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
distance = fp - psp;
rval = (csp - distance);
if(copy_in_user(rval, psp, distance))
- return 0;
- if(current->tss.flags & SPARC_FLAG_32BIT) {
+ rval = 0;
+ else if(current->tss.flags & SPARC_FLAG_32BIT) {
if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
- return 0;
- return rval;
+ rval = 0;
} else {
if(put_user(((u64)csp - STACK_BIAS),
&(((struct reg_window *)rval)->ins[6])))
- return 0;
- return rval - STACK_BIAS;
+ rval = 0;
+ else
+ rval = rval - STACK_BIAS;
}
+ down(&current->mm->mmap_sem);
+
+ return rval;
}
/* Standard stuff. */
@@ -624,6 +645,37 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
}
/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ long retval;
+
+ __asm__ __volatile("mov %1, %%g1\n\t"
+ "mov %2, %%o0\n\t" /* Clone flags. */
+ "mov 0, %%o1\n\t" /* usp arg == 0 */
+ "t 0x6d\n\t" /* Linux/Sparc clone(). */
+ "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
+ " mov %%o0, %0\n\t"
+ "jmpl %4, %%o7\n\t" /* Call the function. */
+ " mov %5, %%o0\n\t" /* Set arg in delay. */
+ "mov %3, %%g1\n\t"
+ "t 0x6d\n\t" /* Linux/Sparc exit(). */
+ /* Notreached by child. */
+ "1:" :
+ "=r" (retval) :
+ "i" (__NR_clone), "r" (flags | CLONE_VM),
+ "i" (__NR_exit), "r" (fn), "r" (arg) :
+ "g1", "o0", "o1", "memory", "cc");
+ return retval;
+}
+
+/*
* fill in the user structure for a core dump..
*/
void dump_thread(struct pt_regs * regs, struct user * dump)
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
index 96b1ac2e9..7df9a5882 100644
--- a/arch/sparc64/kernel/psycho.c
+++ b/arch/sparc64/kernel/psycho.c
@@ -1,8 +1,9 @@
-/* $Id: psycho.c,v 1.66 1998/11/02 22:27:45 davem Exp $
+/* $Id: psycho.c,v 1.85 1999/04/02 14:54:28 davem Exp $
* psycho.c: Ultra/AX U2P PCI controller support.
*
* Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <linux/config.h>
@@ -29,14 +30,13 @@
#define dprintf printk
#endif
-
unsigned long pci_dvma_offset = 0x00000000UL;
unsigned long pci_dvma_mask = 0xffffffffUL;
+#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL
unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
-
#ifndef CONFIG_PCI
int pcibios_present(void)
@@ -74,9 +74,12 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
#include <asm/apb.h>
#include <asm/uaccess.h>
+#define PSYCHO_REORDER_ONBOARDFIRST 1
+
struct linux_psycho *psycho_root = NULL;
int linux_num_psycho = 0;
static struct linux_pbm_info *bus2pbm[256];
+static int psycho_reorder __initdata = 0;
static int pbm_read_config_byte(struct linux_pbm_info *pbm,
unsigned char bus, unsigned char devfn,
@@ -112,8 +115,10 @@ static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr)
pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr;
}
-__initfunc(static void psycho_iommu_init(struct linux_psycho *psycho, int tsbsize))
+static void __init psycho_iommu_init(struct linux_psycho *psycho, int tsbsize)
{
+ extern int this_is_starfire;
+ extern void *starfire_hookup(int);
struct linux_mlist_p1275 *mlist;
unsigned long tsbbase;
unsigned long control, i, n;
@@ -137,37 +142,77 @@ __initfunc(static void psycho_iommu_init(struct linux_psycho *psycho, int tsbsiz
break;
}
tsbbase = __get_free_pages(GFP_DMA, order);
+ if (!tsbbase) {
+ prom_printf("IOMMU: Error, kmalloc(tsb) failed.\n");
+ prom_halt();
+ }
iopte = (unsigned long *)tsbbase;
- memset(pci_dvma_v2p_hash, 0, sizeof(pci_dvma_v2p_hash));
- memset(pci_dvma_p2v_hash, 0, sizeof(pci_dvma_p2v_hash));
+ /* Initialize to "none" settings. */
+ for(i = 0; i < PCI_DVMA_HASHSZ; i++) {
+ pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE;
+ pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE;
+ }
n = 0;
mlist = *prom_meminfo()->p1275_totphys;
while (mlist) {
unsigned long paddr = mlist->start_adr;
+ unsigned long num_bytes = mlist->num_bytes;
- for (i = 0; i < (mlist->num_bytes >> 16); i++) {
+ if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET))
+ goto next;
+
+ if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET))
+ num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr;
+
+ /* Align base and length so we map whole hash table sized chunks
+ * at a time (and therefore full 64K IOMMU pages).
+ */
+ paddr &= ~((1UL << 24UL) - 1);
+ num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1);
+
+ /* Move up the base for mappings already created. */
+ while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] !=
+ PCI_DVMA_HASH_NONE) {
+ paddr += (1UL << 24UL);
+ num_bytes -= (1UL << 24UL);
+ if(num_bytes == 0UL)
+ goto next;
+ }
+
+ /* Move down the size for tail mappings already created. */
+ while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] !=
+ PCI_DVMA_HASH_NONE) {
+ num_bytes -= (1UL << 24UL);
+ if(num_bytes == 0UL)
+ goto next;
+ }
+ /* Now map the rest. */
+ for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) {
*iopte = (IOPTE_VALID | IOPTE_64K |
IOPTE_CACHE | IOPTE_WRITE);
*iopte |= paddr;
if (!(n & 0xff))
set_dvma_hash(paddr, (n << 16));
-
+
if (++n > (tsbsize * 1024))
goto out;
paddr += (1 << 16);
iopte++;
}
-
+ next:
mlist = mlist->theres_more;
}
out:
- if (mlist)
- printk("WARNING: not all physical memory mapped in IOMMU\n");
+ if (mlist) {
+ prom_printf("WARNING: not all physical memory mapped in IOMMU\n");
+ prom_printf("Try booting with mem=xxxM or similar\n");
+ prom_halt();
+ }
psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase);
@@ -193,6 +238,12 @@ out:
break;
}
psycho->psycho_regs->iommu_control = control;
+
+ /* If necessary, hook us up for starfire IRQ translations. */
+ if(this_is_starfire)
+ psycho->starfire_cookie = starfire_hookup(psycho->upa_portid);
+ else
+ psycho->starfire_cookie = NULL;
}
extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
@@ -201,7 +252,7 @@ extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm);
/*
* Poor man's PCI...
*/
-__initfunc(void sabre_init(int pnode))
+void __init sabre_init(int pnode)
{
struct linux_prom64_registers pr_regs[2];
struct linux_psycho *sabre;
@@ -213,6 +264,10 @@ __initfunc(void sabre_init(int pnode))
int bus;
sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
+ if (!sabre) {
+ prom_printf("SABRE: Error, kmalloc(sabre) failed.\n");
+ prom_halt();
+ }
portid = prom_getintdefault(pnode, "upa-portid", 0xff);
@@ -248,9 +303,11 @@ __initfunc(void sabre_init(int pnode))
prom_halt();
}
- printk("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs);
+ printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
+ sabre->psycho_regs, sabre->psycho_regs->control);
#ifdef PROM_DEBUG
- dprintf("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs);
+ dprintf("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
+ sabre->psycho_regs, sabre->psycho_regs->control);
#endif
ctrl = sabre->psycho_regs->pci_a_control;
@@ -382,7 +439,7 @@ apb_present(struct linux_psycho *psycho)
return psycho->pci_bus ? 1 : 0;
}
-__initfunc(void pcibios_init(void))
+void __init pcibios_init(void)
{
struct linux_prom64_registers pr_regs[3];
struct linux_psycho *psycho;
@@ -408,8 +465,6 @@ __initfunc(void pcibios_init(void))
goto next_pci;
}
- psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
-
portid = prom_getintdefault(node, "upa-portid", 0xff);
for(search = psycho_root; search; search = search->next) {
if(search->upa_portid == portid) {
@@ -424,6 +479,11 @@ __initfunc(void pcibios_init(void))
}
}
+ psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
+ if (!psycho) {
+ prom_printf("PSYCHO: Error, kmalloc(psycho) failed.\n");
+ prom_halt();
+ }
memset(psycho, 0, sizeof(*psycho));
psycho->next = psycho_root;
@@ -494,8 +554,14 @@ __initfunc(void pcibios_init(void))
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
/* Enable arbitration for all PCI slots. */
- psycho->psycho_regs->pci_a_control |= 0x3f;
- psycho->psycho_regs->pci_b_control |= 0x3f;
+ psycho->psycho_regs->pci_a_control |= PSYCHO_PCICTRL_AEN;
+ psycho->psycho_regs->pci_b_control |= PSYCHO_PCICTRL_AEN;
+
+ /* Disable DMA write / PIO rd synchronization on both
+ * PCI bus segments.
+ */
+ psycho->psycho_regs->pci_a_diag |= PSYCHO_PCIDIAG_DDWSYNC;
+ psycho->psycho_regs->pci_b_diag |= PSYCHO_PCIDIAG_DDWSYNC;
other_pbm:
if(is_pbm_a)
@@ -609,25 +675,28 @@ static inline struct pcidev_cookie *pci_devcookie_alloc(void)
}
-__initfunc(static void
-pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus))
+static void __init
+pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
{
unsigned int devfn, l, class;
unsigned char hdr_type = 0;
+ int is_multi = 0;
for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) == 0) {
- pbm_read_config_byte(pbm, bus, devfn,
- PCI_HEADER_TYPE, &hdr_type);
- } else if (!(hdr_type & 0x80)) {
+ if (PCI_FUNC(devfn) != 0 && is_multi == 0) {
/* not a multi-function device */
continue;
}
+ pbm_read_config_byte(pbm, bus, devfn,
+ PCI_HEADER_TYPE, &hdr_type);
+ if (PCI_FUNC(devfn) == 0)
+ is_multi = hdr_type & 0x80;
/* Check if there is anything here. */
pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l);
- if (l == 0xffffffff || l == 0x00000000) {
- hdr_type = 0;
+ if (l == 0xffffffff || l == 0x00000000 ||
+ l == 0x0000ffff || l == 0xffff0000) {
+ is_multi = 0;
continue;
}
@@ -657,7 +726,7 @@ pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus))
}
}
-__initfunc(static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus))
+static void __init pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
{
unsigned int nbus;
@@ -682,8 +751,7 @@ __initfunc(static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char
} while (nbus--);
}
-
-__initfunc(static void apb_init(struct linux_psycho *sabre))
+static void __init apb_init(struct linux_psycho *sabre)
{
struct pci_dev *pdev;
unsigned short stmp;
@@ -692,21 +760,20 @@ __initfunc(static void apb_init(struct linux_psycho *sabre))
for(pdev = pci_devices; pdev; pdev = pdev->next) {
if(pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
- /* Increase latency timer on top level bridge. */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
break;
}
}
for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
-
pci_read_config_word(pdev, PCI_COMMAND, &stmp);
stmp |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
PCI_COMMAND_IO;
pci_write_config_word(pdev, PCI_COMMAND, stmp);
+ /* Status register bits are "write 1 to clear". */
pci_write_config_word(pdev, PCI_STATUS, 0xffff);
pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
@@ -721,28 +788,25 @@ __initfunc(static void apb_init(struct linux_psycho *sabre))
APB_PCI_CTL_HIGH_ARBITER_EN;
pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp);
+ /* Systems with SIMBA are usually workstations, so
+ * we configure to park to SIMBA not to the previous
+ * bus owner.
+ */
pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
- itmp = APB_PCI_CTL_LOW_ARB_PARK |
- APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
+ itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
- /*
- * Setup Registers for Guaranteed Completion.
+ /* Don't mess with the retry limit and PIO/DMA latency
+ * timer settings. But do set primary and secondary
+ * latency timers.
*/
- pci_write_config_byte(pdev, APB_PRIMARY_MASTER_RETRY_LIMIT, 0);
- pci_write_config_byte(pdev, APB_SECONDARY_MASTER_RETRY_LIMIT, 0);
- pci_write_config_byte(pdev, APB_PIO_TARGET_RETRY_LIMIT, 0x80);
- pci_write_config_byte(pdev, APB_PIO_TARGET_LATENCY_TIMER, 0);
- pci_write_config_byte(pdev, APB_DMA_TARGET_RETRY_LIMIT, 0x80);
- pci_write_config_byte(pdev, APB_DMA_TARGET_LATENCY_TIMER, 0);
-
- /* Increase primary latency timer. */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 128);
+ pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 128);
}
}
}
-__initfunc(static void sabre_probe(struct linux_psycho *sabre))
+static void __init sabre_probe(struct linux_psycho *sabre)
{
struct pci_bus *pbus = sabre->pci_bus;
static unsigned char busno = 0;
@@ -764,7 +828,7 @@ __initfunc(static void sabre_probe(struct linux_psycho *sabre))
}
-__initfunc(static void pbm_probe(struct linux_pbm_info *pbm))
+static void __init pbm_probe(struct linux_pbm_info *pbm)
{
static struct pci_bus *pchain = NULL;
struct pci_bus *pbus = &pbm->pci_bus;
@@ -803,9 +867,9 @@ __initfunc(static void pbm_probe(struct linux_pbm_info *pbm))
}
}
-__initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- int pnode))
+static int __init pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev,
+ int pnode)
{
struct linux_prom_pci_registers pregs[PROMREG_MAX];
int node;
@@ -827,8 +891,8 @@ __initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
return 0;
}
-__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm,
- struct pci_dev *pdev, int pnode))
+static void __init pdev_cookie_fillin(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev, int pnode)
{
struct pcidev_cookie *pcp;
int node;
@@ -846,9 +910,9 @@ __initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm,
#endif
}
-__initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus,
- struct linux_pbm_info *pbm,
- int node))
+static void __init fill_in_pbm_cookies(struct pci_bus *pbus,
+ struct linux_pbm_info *pbm,
+ int node)
{
struct pci_dev *pdev;
@@ -868,7 +932,7 @@ __initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus,
}
}
-__initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre))
+static void __init sabre_cookie_fillin(struct linux_psycho *sabre)
{
struct pci_bus *pbus = sabre->pci_bus;
@@ -886,9 +950,9 @@ __initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre))
* properties, and recording them in pci_vma's linked in via
* PBM->assignments.
*/
-__initfunc(static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs))
+static int __init gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)
{
- struct linux_prom_ebus_ranges erng[PROMREG_MAX];
+ struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
int err, iter;
err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng));
@@ -911,7 +975,7 @@ __initfunc(static int gimme_ebus_assignments(int node, struct linux_prom_pci_reg
return err;
}
-__initfunc(static void assignment_process(struct linux_pbm_info *pbm, int node))
+static void __init assignment_process(struct linux_pbm_info *pbm, int node)
{
struct linux_prom_pci_registers aregs[PROMREG_MAX];
char pname[256];
@@ -968,7 +1032,7 @@ __initfunc(static void assignment_process(struct linux_pbm_info *pbm, int node))
}
}
-__initfunc(static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node))
+static void __init assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
{
while(node) {
int child = prom_getchild(node);
@@ -1077,12 +1141,12 @@ static inline void record_assignments(struct linux_pbm_info *pbm)
#endif
}
-__initfunc(static void fixup_regs(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *pregs,
- int nregs,
- struct linux_prom_pci_registers *assigned,
- int numaa))
+static void __init fixup_regs(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ struct linux_prom_pci_registers *pregs,
+ int nregs,
+ struct linux_prom_pci_registers *assigned,
+ int numaa)
{
int preg, rng;
int IO_seen = 0;
@@ -1173,12 +1237,13 @@ __initfunc(static void fixup_regs(struct pci_dev *pdev,
}
if (bsreg == PCI_ROM_ADDRESS) {
pdev->rom_address = (unsigned long)__va(pci_addr);
- pdev->rom_address |= 1;
+ pdev->rom_address &= ~1UL;
+
/*
- * Enable access to the ROM.
+ * Disable access to the ROM.
*/
pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp);
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp | 1);
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp & ~1);
} else
pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
@@ -1347,7 +1412,7 @@ __initfunc(static void fixup_regs(struct pci_dev *pdev,
rtmp = new_base;
pci_read_config_dword(pdev, breg, &base);
- rtmp |= (base & ~PCI_ROM_ADDRESS_MASK);
+ rtmp &= ~(base & ~PCI_ROM_ADDRESS_MASK);
pci_write_config_dword(pdev, breg, rtmp);
/* Apply PBM ranges and update pci_dev. */
@@ -1370,8 +1435,7 @@ __initfunc(static void fixup_regs(struct pci_dev *pdev,
"PBM ranges\n");
}
pdev->rom_address = (unsigned long)__va(pci_addr);
-
- pdev->rom_address |= (base & ~PCI_ROM_ADDRESS_MASK);
+ pdev->rom_address &= ~(base & ~PCI_ROM_ADDRESS_MASK);
MEM_seen = 1;
}
rom_address_done:
@@ -1415,7 +1479,7 @@ __initfunc(static void fixup_regs(struct pci_dev *pdev,
#define imap_offset(__member) \
((unsigned long)(&(((struct psycho_regs *)0)->__member)))
-__initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino))
+static unsigned long __init psycho_pcislot_imap_offset(unsigned long ino)
{
unsigned int bus, slot;
@@ -1431,11 +1495,8 @@ __initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino))
case 2:
return imap_offset(imap_a_slot2);
case 3:
- return imap_offset(imap_a_slot3);
default:
- prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n",
- bus, slot);
- prom_halt();
+ return imap_offset(imap_a_slot3);
}
} else {
switch(slot) {
@@ -1446,19 +1507,16 @@ __initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino))
case 2:
return imap_offset(imap_b_slot2);
case 3:
- return imap_offset(imap_b_slot3);
default:
- prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n",
- bus, slot);
- prom_halt();
+ return imap_offset(imap_b_slot3);
}
}
}
/* Exported for EBUS probing layer. */
-__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int ino))
+unsigned int __init psycho_irq_build(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev,
+ unsigned int ino)
{
unsigned long imap_off;
int need_dma_sync = 0;
@@ -1533,6 +1591,36 @@ __initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
imap_off = imap_offset(imap_ser);
break;
+ case 0x2c:
+ /* Onboard Timer 0 */
+ imap_off = imap_offset(imap_tim0);
+ break;
+
+ case 0x2d:
+ /* Onboard Timer 1 */
+ imap_off = imap_offset(imap_tim1);
+ break;
+
+ case 0x2e:
+ /* Psycho UE Interrupt */
+ imap_off = imap_offset(imap_ue);
+ break;
+
+ case 0x2f:
+ /* Psycho CE Interrupt */
+ imap_off = imap_offset(imap_ce);
+ break;
+
+ case 0x30:
+ /* Psycho PCI A Error Interrupt */
+ imap_off = imap_offset(imap_a_err);
+ break;
+
+ case 0x31:
+ /* Psycho PCI B Error Interrupt */
+ imap_off = imap_offset(imap_b_err);
+ break;
+
case 0x32:
/* Power Management */
imap_off = imap_offset(imap_pmgmt);
@@ -1554,37 +1642,78 @@ __initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync);
}
-__initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- struct linux_prom_pci_registers *preg,
- unsigned int *interrupt))
+static int __init pbm_intmap_match(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev,
+ struct linux_prom_pci_registers *preg,
+ unsigned int *interrupt)
{
struct linux_prom_pci_registers ppreg;
unsigned int hi, mid, lo, irq;
int i;
- if (!pbm->num_pbm_intmap)
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("pbm_intmap_match: ");
+#endif
+ if (!pbm->num_pbm_intmap) {
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("No intmap UPA[%x:%c]\n",
+ pbm->parent->upa_portid,
+ (pbm == &pbm->parent->pbm_A) ? 'A' : 'B');
+#endif
return 0;
-
+ }
/*
* Underneath a bridge, use register of parent bridge.
*/
if (pdev->bus->number != pbm->pci_first_busno) {
- struct pcidev_cookie *pcp = pdev->bus->self->sysdata;
- int node;
+ struct pcidev_cookie *pcp;
+ int node, offset;
+ char prom_name[64];
- if (!pcp)
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("UnderBridge, ");
+#endif
+ pcp = pdev->bus->self->sysdata;
+ if (!pcp) {
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("No bus PCP\n");
+#endif
goto out;
-
+ }
node = pcp->prom_node;
i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg));
- if(i == 0 || i == -1)
+ if(i == 0 || i == -1) {
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("No reg property.\n");
+#endif
goto out;
+ }
+ /*
+ * Did PROM know better and assign an interrupt different
+ * to #INTA to the device? - We test here for presence of
+ * FCODE on the card, in this case we assume PROM has set
+ * correct 'interrupts' property, unless it is quadhme.
+ */
+ pcp = pdev->sysdata;
+ if (!pcp) {
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("No dev PCP\n");
+#endif
+ goto out;
+ }
+ node = pcp->prom_node;
- /* Use low slot number bits of child as IRQ line. */
- *interrupt = ((pdev->devfn >> 3) & 3) + 1;
-
+ offset = prom_getint(node, "fcode-rom-offset");
+ prom_getstring(node, "name", prom_name, sizeof(prom_name));
+ if (offset == -1 ||
+ !strcmp(prom_name, "SUNW,qfe") ||
+ !strcmp(prom_name, "qfe")) {
+ /*
+ * No, use low slot number bits of child as IRQ line.
+ */
+ *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1;
+ }
preg = &ppreg;
}
@@ -1618,13 +1747,12 @@ out:
prom_halt();
}
-__initfunc(static void fixup_irq(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *preg,
- int node))
+static void __init fixup_irq(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ struct linux_prom_pci_registers *preg,
+ int node)
{
unsigned int prom_irq, portid = pbm->parent->upa_portid;
- unsigned char pci_irq_line = pdev->irq;
int err;
#ifdef FIXUP_IRQ_DEBUG
@@ -1668,7 +1796,25 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev,
unsigned int bus, slot, line;
bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0;
- line = (pci_irq_line) & 3;
+
+ /* Use the given interrupt property value as the line if it
+ * is non-zero and legal. Legal encodings are INTA=1, INTB=2,
+ * INTC=3, INTD=4 as per PCI OBP binding spec version 2.1 -DaveM
+ */
+ if(prom_irq > 0 && prom_irq < 5) {
+ line = ((prom_irq - 1) & 3);
+ } else {
+ unsigned char pci_irq_line;
+
+ /* The generic PCI probing layer will read the
+ * interrupt line into pdev->irq if the interrupt
+ * pin is non-zero, so we have to explicitly fetch
+ * the pin here to be certain (the interrupt line is
+ * typically left at zero by OBP).
+ */
+ pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line);
+ line = ((pci_irq_line - 1) & 3);
+ }
/* Slot determination is only slightly complex. Handle
* the easy case first.
@@ -1721,11 +1867,11 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev,
#endif
}
-__initfunc(static void fixup_doit(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *pregs,
- int nregs,
- int node))
+static void __init fixup_doit(struct pci_dev *pdev,
+ struct linux_pbm_info *pbm,
+ struct linux_prom_pci_registers *pregs,
+ int nregs,
+ int node)
{
struct linux_prom_pci_registers assigned[PROMREG_MAX];
int numaa, err;
@@ -1745,9 +1891,9 @@ __initfunc(static void fixup_doit(struct pci_dev *pdev,
fixup_irq(pdev, pbm, &pregs[0], node);
}
-__initfunc(static void fixup_pci_dev(struct pci_dev *pdev,
- struct pci_bus *pbus,
- struct linux_pbm_info *pbm))
+static void __init fixup_pci_dev(struct pci_dev *pdev,
+ struct pci_bus *pbus,
+ struct linux_pbm_info *pbm)
{
struct linux_prom_pci_registers pregs[PROMREG_MAX];
struct pcidev_cookie *pcp = pdev->sysdata;
@@ -1762,8 +1908,12 @@ __initfunc(static void fixup_pci_dev(struct pci_dev *pdev,
cmd |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, cmd);
- /* Now, set cache line size to 64-bytes. */
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64);
+ /* Now, set cache line size to 64-bytes.
+ * NOTE: Cache line size is in 32-bit word units.
+ */
+ pci_write_config_byte(pdev,
+ PCI_CACHE_LINE_SIZE,
+ (64 / sizeof(u32)));
}
/* Ignore if this is one of the PBM's, EBUS, or a
@@ -1808,7 +1958,7 @@ __initfunc(static void fixup_pci_dev(struct pci_dev *pdev,
}
}
-__initfunc(static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm))
+static void __init fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
{
struct pci_dev *pdev;
@@ -1819,7 +1969,7 @@ __initfunc(static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info
fixup_pci_bus(pbus, pbm);
}
-__initfunc(static void fixup_addr_irq(struct linux_pbm_info *pbm))
+static void __init fixup_addr_irq(struct linux_pbm_info *pbm)
{
struct pci_bus *pbus = &pbm->pci_bus;
@@ -1832,7 +1982,7 @@ __initfunc(static void fixup_addr_irq(struct linux_pbm_info *pbm))
/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
* We use OBP for most of this work.
*/
-__initfunc(static void psycho_final_fixup(struct linux_psycho *psycho))
+static void __init psycho_final_fixup(struct linux_psycho *psycho)
{
/* Second, fixup base address registers and IRQ lines... */
if (psycho->pbm_A.parent)
@@ -1841,7 +1991,33 @@ __initfunc(static void psycho_final_fixup(struct linux_psycho *psycho))
fixup_addr_irq(&psycho->pbm_B);
}
-__initfunc(void pcibios_fixup(void))
+/* Reorder the pci_dev chain, so that onboard devices come first
+ and then come the pluggable cards. */
+void __init psycho_reorder_devs(void)
+{
+ struct pci_dev **pci_onboard = &pci_devices;
+ struct pci_dev **pci_tail = &pci_devices;
+ struct pci_dev *pdev = pci_devices, *pci_other = NULL;
+
+ while (pdev) {
+ if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) {
+ if (pci_other) {
+ *pci_onboard = pdev;
+ pci_onboard = &pdev->next;
+ pdev = pdev->next;
+ *pci_onboard = pci_other;
+ *pci_tail = pdev;
+ continue;
+ } else
+ pci_onboard = &pdev->next;
+ } else if (!pci_other)
+ pci_other = pdev;
+ pci_tail = &pdev->next;
+ pdev = pdev->next;
+ }
+}
+
+void __init pcibios_fixup(void)
{
struct linux_psycho *psycho;
@@ -1861,9 +2037,9 @@ __initfunc(void pcibios_fixup(void))
for (psycho = psycho_root; psycho; psycho = psycho->next) {
/* Probe bus on builtin PCI. */
- if (apb_present(psycho))
+ if (apb_present(psycho)) {
sabre_probe(psycho);
- else {
+ } else {
/* Probe busses under PBM B. */
pbm_probe(&psycho->pbm_B);
@@ -1896,6 +2072,9 @@ __initfunc(void pcibios_fixup(void))
psycho_final_fixup(psycho);
}
+ if (psycho_reorder & PSYCHO_REORDER_ONBOARDFIRST)
+ psycho_reorder_devs();
+
return ebus_init();
}
@@ -2418,12 +2597,20 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
return err;
}
-__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+void __init pcibios_fixup_bus(struct pci_bus *bus)
{
}
-__initfunc(char *pcibios_setup(char *str))
+char * __init pcibios_setup(char *str)
{
+ if (!strcmp(str, "onboardfirst")) {
+ psycho_reorder |= PSYCHO_REORDER_ONBOARDFIRST;
+ return NULL;
+ }
+ if (!strcmp(str, "noreorder")) {
+ psycho_reorder = 0;
+ return NULL;
+ }
return str;
}
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 4063a1e86..4dd9651b3 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -591,6 +591,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH))
|| (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) {
+ unsigned long flags;
+
if(child == current) {
/* Try this under SunOS/Solaris, bwa haha
* You'll never be able to kill the process. ;-)
@@ -602,8 +604,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
(current->uid != child->euid) ||
(current->uid != child->uid) ||
(current->gid != child->egid) ||
- (current->gid != child->gid)) &&
- !capable(CAP_SYS_PTRACE)) {
+ (current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
pt_error_return(regs, EPERM);
goto out;
}
@@ -613,15 +616,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
child->flags |= PF_PTRACED;
+ write_lock_irqsave(&tasklist_lock, flags);
if(child->p_pptr != current) {
- unsigned long flags;
-
- write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
- write_unlock_irqrestore(&tasklist_lock, flags);
}
+ write_unlock_irqrestore(&tasklist_lock, flags);
send_sig(SIGSTOP, child, 1);
pt_succ_return(regs, 0);
goto out;
@@ -670,14 +671,18 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_error_return(regs, EINVAL);
goto out;
}
+ down(&child->mm->mmap_sem);
res = read_int(child, addr, &x);
+ up(&child->mm->mmap_sem);
tmp = x;
} else {
if(addr & (sizeof(unsigned long) - 1)) {
pt_error_return(regs, EINVAL);
goto out;
}
+ down(&child->mm->mmap_sem);
res = read_long(child, addr, &tmp);
+ up(&child->mm->mmap_sem);
}
if (res < 0) {
pt_error_return(regs, -res);
@@ -709,13 +714,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_error_return(regs, EINVAL);
goto out;
}
+ down(&child->mm->mmap_sem);
res = write_int(child, addr, data);
+ up(&child->mm->mmap_sem);
} else {
if(addr & (sizeof(unsigned long) - 1)) {
pt_error_return(regs, EINVAL);
goto out;
}
+ down(&child->mm->mmap_sem);
res = write_long(child, addr, data);
+ up(&child->mm->mmap_sem);
}
if(res < 0)
pt_error_return(regs, -res);
@@ -944,12 +953,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long page;
while(len) {
+ down(&child->mm->mmap_sem);
vma = find_extend_vma(child, src);
if (!vma) {
+ up(&child->mm->mmap_sem);
pt_error_return(regs, EIO);
goto flush_and_out;
}
pgtable = get_page (child, vma, src, 0);
+ up(&child->mm->mmap_sem);
if (src & ~PAGE_MASK) {
curlen = PAGE_SIZE - (src & ~PAGE_MASK);
if (curlen > len) curlen = len;
@@ -988,12 +1000,15 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long page;
while(len) {
+ down(&child->mm->mmap_sem);
vma = find_extend_vma(child, dest);
if (!vma) {
+ up(&child->mm->mmap_sem);
pt_error_return(regs, EIO);
goto flush_and_out;
}
pgtable = get_page (child, vma, dest, 1);
+ up(&child->mm->mmap_sem);
if (dest & ~PAGE_MASK) {
curlen = PAGE_SIZE - (dest & ~PAGE_MASK);
if (curlen > len) curlen = len;
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 570322eec..caa1d99ef 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.37 1998/10/14 15:49:09 ecd Exp $
+/* $Id: setup.c,v 1.43 1999/04/12 08:08:24 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -277,6 +277,22 @@ static int console_fb __initdata = 0;
#endif
static unsigned long memory_size = 0;
+#ifdef PROM_DEBUG_CONSOLE
+static struct console prom_debug_console = {
+ "debug",
+ prom_console_write,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+#endif
+
/* XXX Implement this at some point... */
void kernel_enter_debugger(void)
{
@@ -397,13 +413,12 @@ __initfunc(static void boot_flags_init(char *commands))
extern int prom_probe_memory(void);
extern unsigned long start, end;
extern void panic_setup(char *, int *);
-extern unsigned long sun_serial_setup(unsigned long);
extern unsigned short root_flags;
extern unsigned short root_dev;
extern unsigned short ram_flags;
-extern unsigned int ramdisk_image;
-extern unsigned int ramdisk_size;
+extern unsigned int sparc_ramdisk_image;
+extern unsigned int sparc_ramdisk_size;
#define RAMDISK_IMAGE_START_MASK 0x07FF
#define RAMDISK_PROMPT_FLAG 0x8000
#define RAMDISK_LOAD_FLAG 0x4000
@@ -430,6 +445,10 @@ __initfunc(void setup_arch(char **cmdline_p,
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
+#ifdef PROM_DEBUG_CONSOLE
+ register_console(&prom_debug_console);
+#endif
+
printk("ARCH: SUN4U\n");
#ifdef CONFIG_DUMMY_CONSOLE
@@ -489,13 +508,13 @@ __initfunc(void setup_arch(char **cmdline_p,
rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);
#endif
#ifdef CONFIG_BLK_DEV_INITRD
- if (ramdisk_image) {
+ if (sparc_ramdisk_image) {
unsigned long start = 0;
- if (ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE)
- ramdisk_image -= KERNBASE;
- initrd_start = ramdisk_image + phys_base + PAGE_OFFSET;
- initrd_end = initrd_start + ramdisk_size;
+ if (sparc_ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE)
+ sparc_ramdisk_image -= KERNBASE;
+ initrd_start = sparc_ramdisk_image + phys_base + PAGE_OFFSET;
+ initrd_end = initrd_start + sparc_ramdisk_size;
if (initrd_end > *memory_end_p) {
printk(KERN_CRIT "initrd extends beyond end of memory "
"(0x%016lx > 0x%016lx)\ndisabling initrd\n",
@@ -503,10 +522,10 @@ __initfunc(void setup_arch(char **cmdline_p,
initrd_start = 0;
}
if (initrd_start)
- start = ramdisk_image + KERNBASE;
+ start = sparc_ramdisk_image + KERNBASE;
if (start >= *memory_start_p && start < *memory_start_p + 2 * PAGE_SIZE) {
initrd_below_start_ok = 1;
- *memory_start_p = PAGE_ALIGN (start + ramdisk_size);
+ *memory_start_p = PAGE_ALIGN (start + sparc_ramdisk_size);
}
}
#endif
@@ -531,7 +550,7 @@ __initfunc(void setup_arch(char **cmdline_p,
ic_servaddr = sv;
if (gw)
ic_gateway = gw;
- ic_bootp_flag = ic_rarp_flag = 0;
+ ic_proto_enabled = 0;
}
}
#endif
@@ -566,7 +585,6 @@ __initfunc(void setup_arch(char **cmdline_p,
serial_console = 2;
break;
}
- *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
#else
serial_console = 0;
#endif
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 4bdfca1b7..27344f4b6 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -5,6 +5,8 @@
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
#include <linux/tasks.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -34,24 +36,23 @@ extern int linux_num_cpus;
extern void calibrate_delay(void);
extern unsigned prom_cpu_nodes[];
-volatile int smp_processors_ready = 0;
-unsigned long cpu_present_map = 0;
-int smp_num_cpus = 1;
-int smp_threads_ready = 0;
+struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
-struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
+volatile int cpu_number_map[NR_CPUS] __attribute__ ((aligned (64)));
+volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (64)));
-/* Please don't make this initdata!!! --DaveM */
+/* Please don't make this stuff initdata!!! --DaveM */
static unsigned char boot_cpu_id = 0;
-
static int smp_activated = 0;
-volatile int cpu_number_map[NR_CPUS];
-volatile int __cpu_logical_map[NR_CPUS];
-
/* Kernel spinlock */
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+volatile int smp_processors_ready = 0;
+unsigned long cpu_present_map = 0;
+int smp_num_cpus = 1;
+int smp_threads_ready = 0;
+
__initfunc(void smp_setup(char *str, int *ints))
{
/* XXX implement me XXX */
@@ -84,6 +85,8 @@ int smp_bogo(char *buf)
__initfunc(void smp_store_cpu_info(int id))
{
+ int i;
+
cpu_data[id].irq_count = 0;
cpu_data[id].bh_count = 0;
/* multiplier and counter set by
@@ -94,16 +97,18 @@ __initfunc(void smp_store_cpu_info(int id))
cpu_data[id].pte_cache = NULL;
cpu_data[id].pgdcache_size = 0;
cpu_data[id].pgd_cache = NULL;
-}
+ cpu_data[id].idle_volume = 1;
-extern void distribute_irqs(void);
+ for(i = 0; i < 16; i++)
+ cpu_data[id].irq_worklists[i] = 0;
+}
__initfunc(void smp_commence(void))
{
- distribute_irqs();
}
static void smp_setup_percpu_timer(void);
+static void smp_tune_scheduling(void);
static volatile unsigned long callin_flag = 0;
@@ -173,10 +178,16 @@ void cpu_panic(void)
panic("SMP bolixed\n");
}
-extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern struct prom_cpuinfo linux_cpus[64];
extern unsigned long smp_trampoline;
+/* The OBP cpu startup callback truncates the 3rd arg cookie to
+ * 32-bits (I think) so to be safe we have it read the pointer
+ * contained here so we work on >4GB machines. -DaveM
+ */
+static struct task_struct *cpu_new_task = NULL;
+
__initfunc(void smp_boot_cpus(void))
{
int cpucount = 0, i;
@@ -184,6 +195,8 @@ __initfunc(void smp_boot_cpus(void))
printk("Entering UltraSMPenguin Mode...\n");
__sti();
smp_store_cpu_info(boot_cpu_id);
+ smp_tune_scheduling();
+ init_idle();
if(linux_num_cpus == 1)
return;
@@ -194,21 +207,25 @@ __initfunc(void smp_boot_cpus(void))
if(cpu_present_map & (1UL << i)) {
unsigned long entry = (unsigned long)(&smp_trampoline);
+ unsigned long cookie = (unsigned long)(&cpu_new_task);
struct task_struct *p;
int timeout;
int no;
extern unsigned long phys_base;
entry += phys_base - KERNBASE;
+ cookie += phys_base - KERNBASE;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
+ p->has_cpu = 1; /* we schedule the first task manually */
callin_flag = 0;
for (no = 0; no < linux_num_cpus; no++)
if (linux_cpus[no].mid == i)
break;
+ cpu_new_task = p;
prom_startcpu(linux_cpus[no].prom_node,
- entry, ((unsigned long)p));
+ entry, cookie);
for(timeout = 0; timeout < 5000000; timeout++) {
if(callin_flag)
break;
@@ -216,8 +233,8 @@ __initfunc(void smp_boot_cpus(void))
}
if(callin_flag) {
cpu_number_map[i] = cpucount;
- prom_cpu_nodes[i] = linux_cpus[no].prom_node;
__cpu_logical_map[cpucount] = i;
+ prom_cpu_nodes[i] = linux_cpus[no].prom_node;
} else {
cpucount--;
printk("Processor %d is stuck.\n", i);
@@ -228,6 +245,7 @@ __initfunc(void smp_boot_cpus(void))
cpu_number_map[i] = -1;
}
}
+ cpu_new_task = NULL;
if(cpucount == 0) {
printk("Error: only one processor found.\n");
cpu_present_map = (1UL << smp_processor_id());
@@ -249,17 +267,6 @@ __initfunc(void smp_boot_cpus(void))
membar("#StoreStore | #StoreLoad");
}
-/* We don't even need to do anything, the only generic message pass done
- * anymore is to stop all cpus during a panic(). When the user drops to
- * the PROM prompt, the firmware will send the other cpu's it's MONDO
- * vector anyways, so doing anything special here is pointless.
- *
- * This whole thing should go away anyways...
- */
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
-{
-}
-
/* #define XCALL_DEBUG */
static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu)
@@ -342,6 +349,17 @@ extern unsigned long xcall_flush_tlb_all;
extern unsigned long xcall_tlbcachesync;
extern unsigned long xcall_flush_cache_all;
extern unsigned long xcall_report_regs;
+extern unsigned long xcall_receive_signal;
+
+void smp_receive_signal(int cpu)
+{
+ if(smp_processors_ready &&
+ (cpu_present_map & (1UL<<cpu)) != 0) {
+ u64 pstate, data0 = (((u64)&xcall_receive_signal) & 0xffffffff);
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+ xcall_deliver(data0, 0, 0, pstate, cpu);
+ }
+}
void smp_report_regs(void)
{
@@ -364,37 +382,51 @@ void smp_flush_tlb_all(void)
* to the stack before we get here because all callers of us
* are flush_tlb_*() routines, and these run after flush_cache_*()
* which performs the flushw.
+ *
+ * The SMP TLB coherency scheme we use works as follows:
+ *
+ * 1) mm->cpu_vm_mask is a bit mask of which cpus an address
+ * space has (potentially) executed on, this is the heuristic
+ * we use to avoid doing cross calls.
+ *
+ * 2) TLB context numbers are shared globally across all processors
+ * in the system, this allows us to play several games to avoid
+ * cross calls.
+ *
+ * One invariant is that when a cpu switches to a process, and
+ * that processes tsk->mm->cpu_vm_mask does not have the current
+ * cpu's bit set, that tlb context is flushed locally.
+ *
+ * If the address space is non-shared (ie. mm->count == 1) we avoid
+ * cross calls when we want to flush the currently running process's
+ * tlb state. This is done by clearing all cpu bits except the current
+ * processor's in current->mm->cpu_vm_mask and performing the flush
+ * locally only. This will force any subsequent cpus which run this
+ * task to flush the context from the local tlb if the process migrates
+ * to another cpu (again).
+ *
+ * 3) For shared address spaces (threads) and swapping we bite the
+ * bullet for most cases and perform the cross call.
+ *
+ * The performance gain from "optimizing" away the cross call for threads is
+ * questionable (in theory the big win for threads is the massive sharing of
+ * address space state across processors).
+ *
+ * For the swapping case the locking is difficult to get right, we'd have to
+ * enforce strict ordered access to mm->cpu_vm_mask via a spinlock for example.
+ * Then again one could argue that when you are swapping, the cost of a cross
+ * call won't even show up on the performance radar. But in any case we do get
+ * rid of the cross-call when the task has a dead context or the task has only
+ * ever run on the local cpu.
*/
-static void smp_cross_call_avoidance(struct mm_struct *mm)
-{
- u32 ctx;
-
- spin_lock(&scheduler_lock);
- get_new_mmu_context(mm);
- mm->cpu_vm_mask = (1UL << smp_processor_id());
- current->tss.ctx = ctx = mm->context & 0x3ff;
- spitfire_set_secondary_context(ctx);
- __asm__ __volatile__("flush %g6");
- spitfire_flush_dtlb_secondary_context();
- spitfire_flush_itlb_secondary_context();
- __asm__ __volatile__("flush %g6");
- if(!segment_eq(current->tss.current_ds,USER_DS)) {
- /* Rarely happens. */
- current->tss.ctx = 0;
- spitfire_set_secondary_context(0);
- __asm__ __volatile__("flush %g6");
- }
- spin_unlock(&scheduler_lock);
-}
-
void smp_flush_tlb_mm(struct mm_struct *mm)
{
u32 ctx = mm->context & 0x3ff;
if(mm == current->mm && atomic_read(&mm->count) == 1) {
- if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
- goto local_flush_and_out;
- return smp_cross_call_avoidance(mm);
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
+ mm->cpu_vm_mask = (1UL << smp_processor_id());
+ goto local_flush_and_out;
}
smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
@@ -410,9 +442,9 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
start &= PAGE_MASK;
end &= PAGE_MASK;
if(mm == current->mm && atomic_read(&mm->count) == 1) {
- if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
- goto local_flush_and_out;
- return smp_cross_call_avoidance(mm);
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
+ mm->cpu_vm_mask = (1UL << smp_processor_id());
+ goto local_flush_and_out;
}
smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
@@ -426,22 +458,26 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
page &= PAGE_MASK;
if(mm == current->mm && atomic_read(&mm->count) == 1) {
- if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
- goto local_flush_and_out;
- return smp_cross_call_avoidance(mm);
- }
-#if 0 /* XXX Disabled until further notice... */
- else if(atomic_read(&mm->count) == 1) {
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
+ mm->cpu_vm_mask = (1UL << smp_processor_id());
+ goto local_flush_and_out;
+ } else {
/* Try to handle two special cases to avoid cross calls
* in common scenerios where we are swapping process
* pages out.
*/
- if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)
+ if(((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK) ||
+ (mm->cpu_vm_mask == 0)) {
+ /* A dead context cannot ever become "alive" until
+ * a task switch is done to it.
+ */
return; /* It's dead, nothing to do. */
- if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
- goto local_flush_and_out;
+ }
+ if(mm->cpu_vm_mask == (1UL << smp_processor_id())) {
+ __flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
+ return; /* Only local flush is necessary. */
+ }
}
-#endif
smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
local_flush_and_out:
@@ -644,6 +680,100 @@ __initfunc(void smp_tick_init(void))
prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1;
}
+static inline unsigned long find_flush_base(unsigned long size)
+{
+ struct page *p = mem_map;
+ unsigned long found, base;
+
+ size = PAGE_ALIGN(size);
+ found = size;
+ base = page_address(p);
+ while(found != 0) {
+ /* Failure. */
+ if(p >= (mem_map + max_mapnr))
+ return 0UL;
+ if(PageSkip(p)) {
+ p = p->next_hash;
+ base = page_address(p);
+ found = size;
+ } else {
+ found -= PAGE_SIZE;
+ p++;
+ }
+ }
+ return base;
+}
+
+cycles_t cacheflush_time;
+
+__initfunc(static void smp_tune_scheduling (void))
+{
+ unsigned long flush_base, flags, *p;
+ unsigned int ecache_size;
+ cycles_t tick1, tick2, raw;
+
+ /* Approximate heuristic for SMP scheduling. It is an
+ * estimation of the time it takes to flush the L2 cache
+ * on the local processor.
+ *
+ * The ia32 chooses to use the L1 cache flush time instead,
+ * and I consider this complete nonsense. The Ultra can service
+ * a miss to the L1 with a hit to the L2 in 7 or 8 cycles, and
+ * L2 misses are what create extra bus traffic (ie. the "cost"
+ * of moving a process from one cpu to another).
+ */
+ printk("SMP: Calibrating ecache flush... ");
+ ecache_size = prom_getintdefault(linux_cpus[0].prom_node,
+ "ecache-size", (512 *1024));
+ flush_base = find_flush_base(ecache_size << 1);
+
+ if(flush_base != 0UL) {
+ __save_and_cli(flags);
+
+ /* Scan twice the size once just to get the TLB entries
+ * loaded and make sure the second scan measures pure misses.
+ */
+ for(p = (unsigned long *)flush_base;
+ ((unsigned long)p) < (flush_base + (ecache_size<<1));
+ p += (64 / sizeof(unsigned long)))
+ *((volatile unsigned long *)p);
+
+ /* Now the real measurement. */
+ __asm__ __volatile__("
+ b,pt %%xcc, 1f
+ rd %%tick, %0
+
+ .align 64
+1: ldx [%2 + 0x000], %%g1
+ ldx [%2 + 0x040], %%g2
+ ldx [%2 + 0x080], %%g3
+ ldx [%2 + 0x0c0], %%g5
+ add %2, 0x100, %2
+ cmp %2, %4
+ bne,pt %%xcc, 1b
+ nop
+
+ rd %%tick, %1"
+ : "=&r" (tick1), "=&r" (tick2), "=&r" (flush_base)
+ : "2" (flush_base), "r" (flush_base + ecache_size)
+ : "g1", "g2", "g3", "g5");
+
+ __restore_flags(flags);
+
+ raw = (tick2 - tick1);
+
+ /* Dampen it a little, considering two processes
+ * sharing the cache and fitting.
+ */
+ cacheflush_time = (raw - (raw >> 2));
+ } else
+ cacheflush_time = ((ecache_size << 2) +
+ (ecache_size << 1));
+
+ printk("Using heuristic of %d cycles.\n",
+ (int) cacheflush_time);
+}
+
int __init setup_profiling_timer(unsigned int multiplier)
{
unsigned long flags;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index a42505edc..305f37ad8 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,8 +1,9 @@
-/* $Id: sparc64_ksyms.c,v 1.49 1998/10/28 08:11:28 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.58 1999/05/08 03:00:31 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
*/
/* Tell string.h we don't want memcpy etc. as cpp defines */
@@ -52,8 +53,9 @@ struct poll {
short revents;
};
-extern unsigned prom_cpu_nodes[NR_CPUS];
+extern unsigned prom_cpu_nodes[64];
extern void die_if_kernel(char *str, struct pt_regs *regs);
+extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long);
void _sigpause_common (unsigned int set, struct pt_regs *);
@@ -88,7 +90,6 @@ extern int __ashrdi3(int, int);
extern void dump_thread(struct pt_regs *, struct user *);
#ifdef __SMP__
-extern spinlock_t scheduler_lock;
extern spinlock_t kernel_flag;
extern int smp_num_cpus;
#ifdef SPIN_LOCK_DEBUG
@@ -102,6 +103,8 @@ extern void _do_write_unlock(rwlock_t *rw);
#endif
#endif
+extern unsigned long phys_base;
+
/* One thing to note is that the way the symbols of the mul/div
* support routines are named is a mess, they all start with
* a '.' which makes it a bitch to export, here is the trick:
@@ -116,7 +119,6 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
#ifdef __SMP__
/* Kernel wide locking */
-EXPORT_SYMBOL(scheduler_lock);
EXPORT_SYMBOL(kernel_flag);
/* Software-IRQ BH locking */
@@ -155,6 +157,8 @@ EXPORT_SYMBOL(_do_write_unlock);
EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(local_bh_count);
#endif
+
+EXPORT_SYMBOL(ivector_table);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
@@ -171,6 +175,7 @@ EXPORT_SYMBOL(sparc_dvma_malloc);
EXPORT_SYMBOL(mmu_release_scsi_one);
EXPORT_SYMBOL(mmu_release_scsi_sgl);
#if CONFIG_SBUS
+EXPORT_SYMBOL(mmu_set_sbus64);
EXPORT_SYMBOL(SBus_chain);
EXPORT_SYMBOL(dma_chain);
#endif
@@ -199,6 +204,9 @@ EXPORT_SYMBOL(dump_thread);
/* math-emu wants this */
EXPORT_SYMBOL(die_if_kernel);
+/* Kernel thread creation. */
+EXPORT_SYMBOL(kernel_thread);
+
/* prom symbols */
EXPORT_SYMBOL(idprom);
EXPORT_SYMBOL(prom_root_node);
@@ -214,6 +222,7 @@ EXPORT_SYMBOL(prom_setprop);
EXPORT_SYMBOL(saved_command_line);
EXPORT_SYMBOL(prom_getname);
EXPORT_SYMBOL(prom_feval);
+EXPORT_SYMBOL(prom_getbool);
EXPORT_SYMBOL(prom_getstring);
EXPORT_SYMBOL(prom_apply_sbus_ranges);
EXPORT_SYMBOL(prom_getint);
@@ -257,7 +266,6 @@ EXPORT_SYMBOL(svr4_setcontext);
EXPORT_SYMBOL(prom_cpu_nodes);
EXPORT_SYMBOL(sys_ioctl);
EXPORT_SYMBOL(sys32_ioctl);
-EXPORT_SYMBOL(get_unmapped_area);
EXPORT_SYMBOL(move_addr_to_kernel);
EXPORT_SYMBOL(move_addr_to_user);
#endif
@@ -281,6 +289,10 @@ EXPORT_SYMBOL(__copy_from_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__bzero_noasi);
+/* Various address conversion macros use this. */
+EXPORT_SYMBOL(phys_base);
+EXPORT_SYMBOL(sparc64_valid_addr_bitmap);
+
/* No version information on this, heavily used in inline asm,
* and will always be 'void __ret_efault(void)'.
*/
diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
new file mode 100644
index 000000000..38f33ecd6
--- /dev/null
+++ b/arch/sparc64/kernel/starfire.c
@@ -0,0 +1,121 @@
+/* $Id: starfire.c,v 1.2 1998/12/09 18:53:11 davem Exp $
+ * starfire.c: Starfire/E10000 support.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+
+#include <asm/page.h>
+#include <asm/oplib.h>
+#include <asm/smp.h>
+
+/* A few places around the kernel check this to see if
+ * they need to call us to do things in a Starfire specific
+ * way.
+ */
+int this_is_starfire = 0;
+
+void starfire_check(void)
+{
+ int ssnode = prom_finddevice("/ssp-serial");
+
+ if(ssnode != 0 && ssnode != -1) {
+ int i;
+
+ this_is_starfire = 1;
+
+ /* Now must fixup cpu MIDs. OBP gave us a logical
+ * linear cpuid number, not the real upaid.
+ */
+ for(i = 0; i < linux_num_cpus; i++) {
+ unsigned int mid = linux_cpus[i].mid;
+
+ mid = (((mid & 0x3c) << 1) |
+ ((mid & 0x40) >> 4) |
+ (mid & 0x3));
+
+ linux_cpus[i].mid = mid;
+ }
+ }
+}
+
+int starfire_hard_smp_processor_id(void)
+{
+ return *((unsigned int *) __va(0x1fff40000d0));
+}
+
+/* Each Starfire board has 32 registers which perform translation
+ * and delivery of traditional interrupt packets into the extended
+ * Starfire hardware format. Essentially UPAID's now have 2 more
+ * bits than in all previous Sun5 systems.
+ */
+struct starfire_irqinfo {
+ unsigned int *imap_slots[32];
+ unsigned int *tregs[32];
+ struct starfire_irqinfo *next;
+ int upaid, hwmid;
+};
+
+static struct starfire_irqinfo *sflist = NULL;
+
+/* Beam me up Scott(McNeil)y... */
+void *starfire_hookup(int upaid)
+{
+ struct starfire_irqinfo *p;
+ unsigned long treg_base, hwmid, i;
+
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if(!p) {
+ prom_printf("starfire_hookup: No memory, this is insane.\n");
+ prom_halt();
+ }
+ treg_base = 0x100fc000000UL;
+ hwmid = ((upaid & 0x3c) << 1) |
+ ((upaid & 0x40) >> 4) |
+ (upaid & 0x3);
+ p->hwmid = hwmid;
+ treg_base += (hwmid << 33UL);
+ treg_base += 0x200UL;
+ for(i = 0; i < 32; i++) {
+ p->imap_slots[i] = NULL;
+ p->tregs[i] = __va(treg_base + (i * 0x10));
+ }
+ p->upaid = upaid;
+ p->next = sflist;
+ sflist = p;
+
+ return (void *) p;
+}
+
+unsigned int starfire_translate(unsigned int *imap,
+ unsigned int upaid)
+{
+ struct starfire_irqinfo *p;
+ unsigned int bus_hwmid;
+ unsigned int i;
+
+ bus_hwmid = (((unsigned long)imap) >> 33) & 0x7f;
+ for(p = sflist; p != NULL; p = p->next)
+ if(p->hwmid == bus_hwmid)
+ break;
+ if(p == NULL) {
+ prom_printf("XFIRE: Cannot find irqinfo for imap %016lx\n",
+ ((unsigned long)imap));
+ prom_halt();
+ }
+ for(i = 0; i < 32; i++) {
+ if(p->imap_slots[i] == imap ||
+ p->imap_slots[i] == NULL)
+ break;
+ }
+ if(i == 32) {
+ printk("starfire_translate: Are you kidding me?\n");
+ panic("Lucy in the sky....");
+ }
+ p->imap_slots[i] = imap;
+ *(p->tregs[i]) = upaid;
+
+ return i;
+}
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 08ce07244..8d11f10b8 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem Exp $
+/* $Id: sys_sparc.c,v 1.26 1999/01/07 19:07:01 jj Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -27,6 +27,8 @@
#include <asm/utrap.h>
#include <asm/perfctr.h>
+/* #define DEBUG_UNIMP_SYSCALL */
+
/* XXX Make this per-binary type, this way we can detect the type of
* XXX a binary. Every Sparc executable calls this very early on.
*/
@@ -200,11 +202,14 @@ asmlinkage unsigned long
c_sys_nis_syscall (struct pt_regs *regs)
{
static int count=0;
+
+ /* Don't make the system unusable, if someone goes stuck */
+ if (count++ > 5) return -ENOSYS;
lock_kernel();
- if (++count <= 20) { /* Don't make the system unusable, if someone goes stuck */
- printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
- show_regs (regs);
- }
+ printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]);
+#ifdef DEBUG_UNIMP_SYSCALL
+ show_regs (regs);
+#endif
unlock_kernel();
return -ENOSYS;
}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 1a49380f1..a7f85ca58 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.100 1998/11/08 11:14:00 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107 1999/03/05 13:21:02 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -43,6 +43,7 @@
#include <linux/poll.h>
#include <linux/personality.h>
#include <linux/stat.h>
+#include <linux/timex.h>
#include <asm/types.h>
#include <asm/ipc.h>
@@ -50,6 +51,8 @@
#include <asm/fpumacro.h>
#include <asm/semaphore.h>
+#include <net/scm.h>
+
/* Use this to get at 32-bit user passed pointers. */
/* Things to consider: the low-level assembly stub does
srl x, 0, x for first four arguments, so if you have
@@ -74,15 +77,6 @@
__ret; \
})
-static inline char * get_page(void)
-{
- char * res;
- res = (char *)__get_free_page(GFP_KERNEL);
- return res;
-}
-
-#define putname32 putname
-
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
@@ -109,13 +103,13 @@ char * getname32(const char *filename)
char *tmp, *result;
result = ERR_PTR(-ENOMEM);
- tmp = get_page();
+ tmp = (char *)__get_free_page(GFP_KERNEL);
if (tmp) {
int retval = do_getname32(filename, tmp);
result = tmp;
if (retval < 0) {
- putname32(tmp);
+ putname(tmp);
result = ERR_PTR(retval);
}
}
@@ -243,7 +237,10 @@ static int do_sys32_semctl(int first, int second, int third, void *uptr)
err = -EFAULT;
if (get_user (pad, (u32 *)uptr))
goto out;
- fourth.__pad = (void *)A(pad);
+ if(third == SETVAL)
+ fourth.val = (int)pad;
+ else
+ fourth.__pad = (void *)A(pad);
if (IPCOP_MASK (third) &
(IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | IPCOP_MASK (GETVAL) |
IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) |
@@ -652,7 +649,7 @@ asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned lon
set_fs (KERNEL_DS);
err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
set_fs (old_fs);
- putname32 (spec);
+ putname (spec);
if (cmds == Q_GETQUOTA) {
__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
((struct dqblk32 *)&d)->dqb_itime = i;
@@ -696,7 +693,7 @@ asmlinkage int sys32_statfs(const char * path, struct statfs32 *buf)
set_fs (KERNEL_DS);
ret = sys_statfs((const char *)pth, &s);
set_fs (old_fs);
- putname32 (pth);
+ putname (pth);
if (put_statfs(buf, &s))
return -EFAULT;
}
@@ -744,7 +741,7 @@ asmlinkage int sys32_utime(char * filename, struct utimbuf32 *times)
set_fs (KERNEL_DS);
ret = sys_utime(filenam, &t);
set_fs (old_fs);
- putname32 (filenam);
+ putname (filenam);
}
return ret;
}
@@ -796,8 +793,9 @@ static long do_readv_writev32(int type, struct file *file,
}
inode = file->f_dentry->d_inode;
- retval = locks_verify_area((type == VERIFY_READ) ?
- FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
+ /* VERIFY_WRITE actually means a read, as we write to user space */
+ retval = locks_verify_area((type == VERIFY_WRITE
+ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
inode, file, file->f_pos, tot_len);
if (retval) {
if (iov != iovstack)
@@ -1106,13 +1104,17 @@ set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
__put_user(*fdset, ufdset);
}
+#define MAX_SELECT_SECONDS \
+ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+
asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
{
- fd_set_buffer *fds;
+ fd_set_bits fds;
struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x);
+ char *bits;
unsigned long nn;
long timeout;
- int ret;
+ int ret, size;
timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
@@ -1123,30 +1125,47 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
|| (ret = __get_user(usec, &tvp->tv_usec)))
goto out_nofds;
- timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
- timeout += sec * HZ;
+ ret = -EINVAL;
+ if(sec < 0 || usec < 0)
+ goto out_nofds;
+
+ if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+ timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
+ timeout += sec * (unsigned long) HZ;
+ }
}
+ ret = -EINVAL;
+ if (n < 0 || n > KFDS_NR)
+ goto out_nofds;
+
+ /*
+ * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
+ * since we used fdset we need to allocate memory in units of
+ * long-words.
+ */
ret = -ENOMEM;
- fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL);
- if (!fds)
+ size = FDS_BYTES(n);
+ bits = kmalloc(6 * size, GFP_KERNEL);
+ if (!bits)
goto out_nofds;
- ret = -EINVAL;
- if (n < 0)
- goto out;
- if (n > KFDS_NR)
- n = KFDS_NR;
+ fds.in = (unsigned long *) bits;
+ fds.out = (unsigned long *) (bits + size);
+ fds.ex = (unsigned long *) (bits + 2*size);
+ fds.res_in = (unsigned long *) (bits + 3*size);
+ fds.res_out = (unsigned long *) (bits + 4*size);
+ fds.res_ex = (unsigned long *) (bits + 5*size);
nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
- if ((ret = get_fd_set32(nn, fds->in, inp)) ||
- (ret = get_fd_set32(nn, fds->out, outp)) ||
- (ret = get_fd_set32(nn, fds->ex, exp)))
+ if ((ret = get_fd_set32(nn, fds.in, inp)) ||
+ (ret = get_fd_set32(nn, fds.out, outp)) ||
+ (ret = get_fd_set32(nn, fds.ex, exp)))
goto out;
- zero_fd_set(n, fds->res_in);
- zero_fd_set(n, fds->res_out);
- zero_fd_set(n, fds->res_ex);
+ zero_fd_set(n, fds.res_in);
+ zero_fd_set(n, fds.res_out);
+ zero_fd_set(n, fds.res_ex);
- ret = do_select(n, fds, &timeout);
+ ret = do_select(n, &fds, &timeout);
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
time_t sec = 0, usec = 0;
@@ -1168,12 +1187,12 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
ret = 0;
}
- set_fd_set32(nn, inp, fds->res_in);
- set_fd_set32(nn, outp, fds->res_out);
- set_fd_set32(nn, exp, fds->res_ex);
+ set_fd_set32(nn, inp, fds.res_in);
+ set_fd_set32(nn, outp, fds.res_out);
+ set_fd_set32(nn, exp, fds.res_ex);
out:
- free_page ((unsigned long)fds);
+ kfree(bits);
out_nofds:
return ret;
}
@@ -1213,7 +1232,7 @@ asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
set_fs (KERNEL_DS);
ret = sys_newstat(filenam, &s);
set_fs (old_fs);
- putname32 (filenam);
+ putname (filenam);
if (putstat (statbuf, &s))
return -EFAULT;
}
@@ -1235,7 +1254,7 @@ asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
set_fs (KERNEL_DS);
ret = sys_newlstat(filenam, &s);
set_fs (old_fs);
- putname32 (filenam);
+ putname (filenam);
if (putstat (statbuf, &s))
return -EFAULT;
}
@@ -2010,74 +2029,6 @@ asmlinkage int sys32_getrusage(int who, struct rusage32 *ru)
return ret;
}
-struct timex32 {
- unsigned int modes;
- s32 offset;
- s32 freq;
- s32 maxerror;
- s32 esterror;
- int status;
- s32 constant;
- s32 precision;
- s32 tolerance;
- struct timeval32 time;
- s32 tick;
- s32 ppsfreq;
- s32 jitter;
- int shift;
- s32 stabil;
- s32 jitcnt;
- s32 calcnt;
- s32 errcnt;
- s32 stbcnt;
- int :32; int :32; int :32; int :32;
- int :32; int :32; int :32; int :32;
- int :32; int :32; int :32; int :32;
-};
-
-extern int do_adjtimex(struct timex *);
-
-asmlinkage int sys32_adjtimex(struct timex32 *txc_p)
-{
- struct timex t;
- int ret;
-
- ret = get_user (t.modes, &txc_p->modes);
- ret |= __get_user (t.offset, &txc_p->offset);
- ret |= __get_user (t.freq, &txc_p->freq);
- ret |= __get_user (t.maxerror, &txc_p->maxerror);
- ret |= __get_user (t.esterror, &txc_p->esterror);
- ret |= __get_user (t.status, &txc_p->status);
- ret |= __get_user (t.constant, &txc_p->constant);
- ret |= __get_user (t.tick, &txc_p->tick);
- ret |= __get_user (t.shift, &txc_p->shift);
- if (ret || (ret = do_adjtimex(&t)))
- return ret;
- ret = __put_user (t.modes, &txc_p->modes);
- ret |= __put_user (t.offset, &txc_p->offset);
- ret |= __put_user (t.freq, &txc_p->freq);
- ret |= __put_user (t.maxerror, &txc_p->maxerror);
- ret |= __put_user (t.esterror, &txc_p->esterror);
- ret |= __put_user (t.status, &txc_p->status);
- ret |= __put_user (t.constant, &txc_p->constant);
- ret |= __put_user (t.precision, &txc_p->precision);
- ret |= __put_user (t.tolerance, &txc_p->tolerance);
- ret |= __put_user (t.time.tv_sec, &txc_p->time.tv_sec);
- ret |= __put_user (t.time.tv_usec, &txc_p->time.tv_usec);
- ret |= __put_user (t.tick, &txc_p->tick);
- ret |= __put_user (t.ppsfreq, &txc_p->ppsfreq);
- ret |= __put_user (t.jitter, &txc_p->jitter);
- ret |= __put_user (t.shift, &txc_p->shift);
- ret |= __put_user (t.stabil, &txc_p->stabil);
- ret |= __put_user (t.jitcnt, &txc_p->jitcnt);
- ret |= __put_user (t.calcnt, &txc_p->calcnt);
- ret |= __put_user (t.errcnt, &txc_p->errcnt);
- ret |= __put_user (t.stbcnt, &txc_p->stbcnt);
- if (!ret)
- ret = time_state;
- return ret;
-}
-
/* XXX This really belongs in some header file... -DaveM */
#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
16 for IP, 16 for IPX,
@@ -2131,9 +2082,44 @@ struct cmsghdr32 {
__kernel_size_t32 cmsg_len;
int cmsg_level;
int cmsg_type;
- unsigned char cmsg_data[0];
};
+/* Bleech... */
+#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
+#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
+
+#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
+
+#define CMSG32_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))
+#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))
+#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))
+
+#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \
+ (struct cmsghdr32 *)(ctl) : \
+ (struct cmsghdr32 *)NULL)
+#define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+
+__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
+ struct cmsghdr32 *__cmsg, int __cmsg_len)
+{
+ struct cmsghdr32 * __ptr;
+
+ __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) +
+ CMSG32_ALIGN(__cmsg_len));
+ if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+ return NULL;
+
+ return __ptr;
+}
+
+__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg,
+ struct cmsghdr32 *__cmsg,
+ int __cmsg_len)
+{
+ return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen,
+ __cmsg, __cmsg_len);
+}
+
static inline int iov_from_user32_to_kern(struct iovec *kiov,
struct iovec32 *uiov32,
int niov)
@@ -2175,6 +2161,7 @@ static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
kmsg->msg_control = (void *)A(tmp3);
err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+ err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
@@ -2217,6 +2204,165 @@ static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
return tot_len;
}
+/* There is a lot of hair here because the alignment rules (and
+ * thus placement) of cmsg headers and length are different for
+ * 32-bit apps. -DaveM
+ */
+static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,
+ unsigned char *stackbuf, int stackbuf_size)
+{
+ struct cmsghdr32 *ucmsg;
+ struct cmsghdr *kcmsg, *kcmsg_base;
+ __kernel_size_t32 ucmlen;
+ __kernel_size_t kcmlen, tmp;
+
+ kcmlen = 0;
+ kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
+ ucmsg = CMSG32_FIRSTHDR(kmsg);
+ while(ucmsg != NULL) {
+ if(get_user(ucmlen, &ucmsg->cmsg_len))
+ return -EFAULT;
+
+ /* Catch bogons. */
+ if(CMSG32_ALIGN(ucmlen) <
+ CMSG32_ALIGN(sizeof(struct cmsghdr32)))
+ return -EINVAL;
+ if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
+ + ucmlen) > kmsg->msg_controllen)
+ return -EINVAL;
+
+ tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+ CMSG_ALIGN(sizeof(struct cmsghdr)));
+ kcmlen += tmp;
+ ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+ }
+ if(kcmlen == 0)
+ return -EINVAL;
+
+ /* The kcmlen holds the 64-bit version of the control length.
+ * It may not be modified as we do not stick it into the kmsg
+ * until we have successfully copied over all of the data
+ * from the user.
+ */
+ if(kcmlen > stackbuf_size)
+ kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
+ if(kcmsg == NULL)
+ return -ENOBUFS;
+
+ /* Now copy them over neatly. */
+ memset(kcmsg, 0, kcmlen);
+ ucmsg = CMSG32_FIRSTHDR(kmsg);
+ while(ucmsg != NULL) {
+ __get_user(ucmlen, &ucmsg->cmsg_len);
+ tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+ CMSG_ALIGN(sizeof(struct cmsghdr)));
+ kcmsg->cmsg_len = tmp;
+ __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
+ __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
+
+ /* Copy over the data. */
+ if(copy_from_user(CMSG_DATA(kcmsg),
+ CMSG32_DATA(ucmsg),
+ (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+ goto out_free_efault;
+
+ /* Advance. */
+ kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+ ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+ }
+
+ /* Ok, looks like we made it. Hook it up and return success. */
+ kmsg->msg_control = kcmsg_base;
+ kmsg->msg_controllen = kcmlen;
+ return 0;
+
+out_free_efault:
+ if(kcmsg_base != (struct cmsghdr *)stackbuf)
+ kfree(kcmsg_base);
+ return -EFAULT;
+}
+
+static void put_cmsg32(struct msghdr *kmsg, int level, int type,
+ int len, void *data)
+{
+ struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+ struct cmsghdr32 cmhdr;
+ int cmlen = CMSG32_LEN(len);
+
+ if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
+ kmsg->msg_flags |= MSG_CTRUNC;
+ return;
+ }
+
+ if(kmsg->msg_controllen < cmlen) {
+ kmsg->msg_flags |= MSG_CTRUNC;
+ cmlen = kmsg->msg_controllen;
+ }
+ cmhdr.cmsg_level = level;
+ cmhdr.cmsg_type = type;
+ cmhdr.cmsg_len = cmlen;
+
+ if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
+ return;
+ if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32)))
+ return;
+ cmlen = CMSG32_SPACE(len);
+ kmsg->msg_control += cmlen;
+ kmsg->msg_controllen -= cmlen;
+}
+
+static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm)
+{
+ struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+ int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int);
+ int fdnum = scm->fp->count;
+ struct file **fp = scm->fp->fp;
+ int *cmfptr;
+ int err = 0, i;
+
+ if (fdnum < fdmax)
+ fdmax = fdnum;
+
+ for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) {
+ int new_fd;
+ err = get_unused_fd();
+ if (err < 0)
+ break;
+ new_fd = err;
+ err = put_user(new_fd, cmfptr);
+ if (err) {
+ put_unused_fd(new_fd);
+ break;
+ }
+ /* Bump the usage count and install the file. */
+ fp[i]->f_count++;
+ current->files->fd[new_fd] = fp[i];
+ }
+
+ if (i > 0) {
+ int cmlen = CMSG32_LEN(i * sizeof(int));
+ if (!err)
+ err = put_user(SOL_SOCKET, &cm->cmsg_level);
+ if (!err)
+ err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+ if (!err)
+ err = put_user(cmlen, &cm->cmsg_len);
+ if (!err) {
+ cmlen = CMSG32_SPACE(i * sizeof(int));
+ kmsg->msg_control += cmlen;
+ kmsg->msg_controllen -= cmlen;
+ }
+ }
+ if (i < fdnum)
+ kmsg->msg_flags |= MSG_CTRUNC;
+
+ /*
+ * All of the files that fit in the message have had their
+ * usage counts incremented, so we just free the list.
+ */
+ __scm_destroy(scm);
+}
+
asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
{
struct socket *sock;
@@ -2237,25 +2383,10 @@ asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_fl
total_len = err;
if(kern_msg.msg_controllen) {
- struct cmsghdr32 *ucmsg = (struct cmsghdr32 *)kern_msg.msg_control;
- unsigned long *kcmsg;
- __kernel_size_t32 cmlen;
-
- if(kern_msg.msg_controllen > sizeof(ctl) &&
- kern_msg.msg_controllen <= 256) {
- err = -ENOBUFS;
- ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
- if(!ctl_buf)
- goto out_freeiov;
- }
- __get_user(cmlen, &ucmsg->cmsg_len);
- kcmsg = (unsigned long *) ctl_buf;
- *kcmsg++ = (unsigned long)cmlen;
- err = -EFAULT;
- if(copy_from_user(kcmsg, &ucmsg->cmsg_level,
- kern_msg.msg_controllen - sizeof(__kernel_size_t32)))
- goto out_freectl;
- kern_msg.msg_control = ctl_buf;
+ err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl));
+ if(err)
+ goto out_freeiov;
+ ctl_buf = kern_msg.msg_control;
}
kern_msg.msg_flags = user_flags;
@@ -2269,7 +2400,6 @@ asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_fl
}
unlock_kernel();
-out_freectl:
/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
if(ctl_buf != ctl)
kfree(ctl_buf);
@@ -2310,26 +2440,43 @@ asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int use
lock_kernel();
sock = sockfd_lookup(fd, &err);
if (sock != NULL) {
+ struct scm_cookie scm;
+
if (sock->file->f_flags & O_NONBLOCK)
user_flags |= MSG_DONTWAIT;
- err = sock_recvmsg(sock, &kern_msg, total_len, user_flags);
- if(err >= 0)
+ memset(&scm, 0, sizeof(scm));
+ err = sock->ops->recvmsg(sock, &kern_msg, total_len,
+ user_flags, &scm);
+ if(err >= 0) {
len = err;
+ if(!kern_msg.msg_control) {
+ if(sock->passcred || scm.fp)
+ kern_msg.msg_flags |= MSG_CTRUNC;
+ if(scm.fp)
+ __scm_destroy(&scm);
+ } else {
+ /* Wheee... */
+ if(sock->passcred)
+ put_cmsg32(&kern_msg,
+ SOL_SOCKET, SCM_CREDENTIALS,
+ sizeof(scm.creds), &scm.creds);
+ if(scm.fp != NULL)
+ scm_detach_fds32(&kern_msg, &scm);
+ }
+ }
sockfd_put(sock);
}
unlock_kernel();
if(uaddr != NULL && err >= 0)
err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
- if(err >= 0) {
- err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
- if(!err) {
- /* XXX Convert cmsg back into userspace 32-bit format... */
- err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr,
- &user_msg->msg_controllen);
- }
+ if(cmsg_ptr != 0 && err >= 0) {
+ u32 ucmsg_ptr = ((u32)(unsigned long)kern_msg.msg_control);
+ err = __put_user(ucmsg_ptr, &user_msg->msg_control);
+ err |= __put_user(kern_msg.msg_controllen, &user_msg->msg_controllen);
}
-
+ if(err >= 0)
+ err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
if(kern_msg.msg_iov != iov)
kfree(kern_msg.msg_iov);
out:
@@ -2653,7 +2800,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
error = do_execve32(filename,
(u32 *)AA((u32)regs->u_regs[base + UREG_I1]),
(u32 *)AA((u32)regs->u_regs[base + UREG_I2]), regs);
- putname32(filename);
+ putname(filename);
if(!error) {
fprs_write(0);
@@ -2943,8 +3090,10 @@ qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
info.addr = (unsigned long)mod;
info.size = mod->size;
info.flags = mod->flags;
- info.usecount = (mod_member_present(mod, can_unload)
- && mod->can_unload ? -1 : mod->usecount);
+ info.usecount =
+ ((mod_member_present(mod, can_unload)
+ && mod->can_unload)
+ ? -1 : atomic_read(&mod->uc.usecount));
if (copy_to_user(buf, &info, sizeof(struct module_info32)))
return -EFAULT;
@@ -3452,7 +3601,7 @@ asmlinkage int sys32_utimes(char *filename, struct timeval32 *tvs)
ret = sys_utimes(kfilename, &ktvs[0]);
set_fs(old_fs);
- putname32(kfilename);
+ putname(kfilename);
}
return ret;
}
@@ -3577,3 +3726,76 @@ asmlinkage int sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s
return ret;
}
+
+/* Handle adjtimex compatability. */
+
+struct timex32 {
+ u32 modes;
+ s32 offset, freq, maxerror, esterror;
+ s32 status, constant, precision, tolerance;
+ struct timeval32 time;
+ s32 tick;
+ s32 ppsfreq, jitter, shift, stabil;
+ s32 jitcnt, calcnt, errcnt, stbcnt;
+ s32 :32; s32 :32; s32 :32; s32 :32;
+ s32 :32; s32 :32; s32 :32; s32 :32;
+ s32 :32; s32 :32; s32 :32; s32 :32;
+};
+
+extern int do_adjtimex(struct timex *);
+
+asmlinkage int sys32_adjtimex(struct timex32 *utp)
+{
+ struct timex txc;
+ int ret;
+
+ memset(&txc, 0, sizeof(struct timex));
+
+ if(get_user(txc.modes, &utp->modes) ||
+ __get_user(txc.offset, &utp->offset) ||
+ __get_user(txc.freq, &utp->freq) ||
+ __get_user(txc.maxerror, &utp->maxerror) ||
+ __get_user(txc.esterror, &utp->esterror) ||
+ __get_user(txc.status, &utp->status) ||
+ __get_user(txc.constant, &utp->constant) ||
+ __get_user(txc.precision, &utp->precision) ||
+ __get_user(txc.tolerance, &utp->tolerance) ||
+ __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+ __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+ __get_user(txc.tick, &utp->tick) ||
+ __get_user(txc.ppsfreq, &utp->ppsfreq) ||
+ __get_user(txc.jitter, &utp->jitter) ||
+ __get_user(txc.shift, &utp->shift) ||
+ __get_user(txc.stabil, &utp->stabil) ||
+ __get_user(txc.jitcnt, &utp->jitcnt) ||
+ __get_user(txc.calcnt, &utp->calcnt) ||
+ __get_user(txc.errcnt, &utp->errcnt) ||
+ __get_user(txc.stbcnt, &utp->stbcnt))
+ return -EFAULT;
+
+ ret = do_adjtimex(&txc);
+
+ if(put_user(txc.modes, &utp->modes) ||
+ __put_user(txc.offset, &utp->offset) ||
+ __put_user(txc.freq, &utp->freq) ||
+ __put_user(txc.maxerror, &utp->maxerror) ||
+ __put_user(txc.esterror, &utp->esterror) ||
+ __put_user(txc.status, &utp->status) ||
+ __put_user(txc.constant, &utp->constant) ||
+ __put_user(txc.precision, &utp->precision) ||
+ __put_user(txc.tolerance, &utp->tolerance) ||
+ __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+ __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+ __put_user(txc.tick, &utp->tick) ||
+ __put_user(txc.ppsfreq, &utp->ppsfreq) ||
+ __put_user(txc.jitter, &utp->jitter) ||
+ __put_user(txc.shift, &utp->shift) ||
+ __put_user(txc.stabil, &utp->stabil) ||
+ __put_user(txc.jitcnt, &utp->jitcnt) ||
+ __put_user(txc.calcnt, &utp->calcnt) ||
+ __put_user(txc.errcnt, &utp->errcnt) ||
+ __put_user(txc.stbcnt, &utp->stbcnt))
+ ret = -EFAULT;
+
+ return ret;
+}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 11c86ef5f..d2a75033a 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.50 1998/10/07 01:27:27 davem Exp $
+/* $Id: systbls.S,v 1.53 1999/04/07 17:14:11 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -26,7 +26,7 @@ sys_call_table32:
/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
.word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys32_sendfile
/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall
- .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+ .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
.word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys32_execve
/*60*/ .word sys_umask, sys_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
@@ -48,7 +48,7 @@ sys_call_table32:
/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
.word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
- .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_umount
+ .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
@@ -85,7 +85,7 @@ sys_call_table:
/*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
.word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile
/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
- .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+ .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
/*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl
.word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
@@ -107,7 +107,7 @@ sys_call_table:
/*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
.word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
- .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+ .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
@@ -188,7 +188,7 @@ sunos_sys_table:
/*150*/ .word sys_getsockname, sunos_nosys, sunos_nosys
.word sys_poll, sunos_nosys, sunos_nosys
.word sunos_getdirentries, sys32_statfs, sys32_fstatfs
- .word sys_umount, sunos_nosys, sunos_nosys
+ .word sys_oldumount, sunos_nosys, sunos_nosys
.word sys_getdomainname, sys_setdomainname
.word sunos_nosys, sys32_quotactl, sunos_nosys
.word sunos_mount, sys_ustat, sunos_semsys
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index c826ce56d..0b72e6e0b 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.16 1998/09/05 17:25:28 jj Exp $
+/* $Id: time.c,v 1.20 1999/03/15 22:13:40 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -31,6 +31,8 @@
#include <asm/pbm.h>
#include <asm/ebus.h>
+extern rwlock_t xtime_lock;
+
struct mostek48t02 *mstk48t02_regs = 0;
static struct mostek48t08 *mstk48t08_regs = 0;
static struct mostek48t59 *mstk48t59_regs = 0;
@@ -69,6 +71,8 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned long ticks;
+ write_lock(&xtime_lock);
+
do {
do_timer(regs);
@@ -82,11 +86,15 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
} while (ticks >= timer_tick_compare);
timer_check_rtc();
+
+ write_unlock(&xtime_lock);
}
#ifdef __SMP__
void timer_tick_interrupt(struct pt_regs *regs)
{
+ write_lock(&xtime_lock);
+
do_timer(regs);
/*
@@ -99,6 +107,8 @@ void timer_tick_interrupt(struct pt_regs *regs)
: "r" (timer_tick_offset));
timer_check_rtc();
+
+ write_unlock(&xtime_lock);
}
#endif
@@ -256,13 +266,17 @@ void __init clock_probe(void)
node = prom_getchild(busnd);
while(1) {
- prom_getstring(node, "model", model, sizeof(model));
+ if (!node)
+ model[0] = 0;
+ else
+ prom_getstring(node, "model", model, sizeof(model));
if(strcmp(model, "mk48t02") &&
strcmp(model, "mk48t08") &&
strcmp(model, "mk48t59")) {
- node = prom_getsibling(node);
+ if (node)
+ node = prom_getsibling(node);
#ifdef CONFIG_PCI
- if ((node == 0) && ebus) {
+ while ((node == 0) && ebus) {
ebus = ebus->next;
if (ebus) {
busnd = ebus->prom_node;
@@ -397,6 +411,9 @@ static __inline__ unsigned long do_gettimeoffset(void)
return ticks / timer_ticks_per_usec;
}
+/* This need not obtain the xtime_lock as it is coded in
+ * an implicitly SMP safe way already.
+ */
void do_gettimeofday(struct timeval *tv)
{
/* Load doubles must be used on xtime so that what we get
@@ -450,7 +467,7 @@ void do_gettimeofday(struct timeval *tv)
void do_settimeofday(struct timeval *tv)
{
- cli();
+ write_lock_irq(&xtime_lock);
tv->tv_usec -= do_gettimeoffset();
if(tv->tv_usec < 0) {
@@ -461,10 +478,10 @@ void do_settimeofday(struct timeval *tv)
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
- time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
- sti();
+
+ write_unlock_irq(&xtime_lock);
}
static int set_rtc_mmss(unsigned long nowtime)
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 9c0498348..2c19cc39d 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.6 1998/10/11 06:58:23 davem Exp $
+/* $Id: trampoline.S,v 1.8 1998/12/09 21:01:15 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -34,8 +34,8 @@ sparc64_cpu_startup:
sllx %g4, 32, %g4
/* XXX Buggy PROM... */
- srl %o0, 0, %g6
- add %g6, %g4, %g6
+ srl %o0, 0, %o0
+ ldx [%o0], %g6
sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
sllx %g5, 32, %g5
@@ -197,10 +197,18 @@ bounce:
#undef KERN_LOWBITS
#undef VPTE_BASE
+ /* Setup interrupt globals, we are always SMP. */
wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate
- sethi %hi(ivector_to_mask), %g5
- or %g5, %lo(ivector_to_mask), %g1
- mov 0x40, %g2
+
+ /* Get our UPA MID. */
+ lduw [%o2 + AOFF_task_processor], %g1
+ sethi %hi(cpu_data), %g5
+ or %g5, %lo(cpu_data), %g5
+
+ /* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */
+ sllx %g1, 7, %g1
+ add %g5, %g1, %g1
+ add %g1, 64, %g1
wrpr %g0, 0, %wstate
or %o1, PSTATE_IE, %o1
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index cb5180fff..5f7049822 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,8 +1,8 @@
-/* $Id: traps.c,v 1.55 1998/10/11 06:58:22 davem Exp $
+/* $Id: traps.c,v 1.58 1999/03/29 12:38:10 jj Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
/*
@@ -406,8 +406,6 @@ void do_fpe_common(struct pt_regs *regs)
void do_fpieee(struct pt_regs *regs)
{
#ifdef DEBUG_FPU
- save_and_clear_fpu();
-
printk("fpieee %016lx\n", current->tss.xfsr[0]);
#endif
do_fpe_common(regs);
@@ -420,7 +418,6 @@ void do_fpother(struct pt_regs *regs)
struct fpustate *f = FPUSTATE;
int ret = 0;
- save_and_clear_fpu();
switch ((current->tss.xfsr[0] & 0x1c000)) {
case (2 << 14): /* unfinished_FPop */
case (3 << 14): /* unimplemented_FPop */
@@ -428,7 +425,7 @@ void do_fpother(struct pt_regs *regs)
break;
}
if (ret) return;
-#ifdef DEBUG_FPU
+#ifdef DEBUG_FPU
printk("fpother %016lx\n", current->tss.xfsr[0]);
#endif
do_fpe_common(regs);
@@ -462,6 +459,9 @@ void instruction_dump (unsigned int *pc)
void die_if_kernel(char *str, struct pt_regs *regs)
{
+ extern void __show_regs(struct pt_regs * regs);
+ extern void smp_report_regs(void);
+
/* Amuse the user. */
printk(
" \\|/ ____ \\|/\n"
@@ -471,7 +471,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
printk("%s(%d): %s\n", current->comm, current->pid, str);
__asm__ __volatile__("flushw");
- show_regs(regs);
+ __show_regs(regs);
{
struct reg_window *rw = (struct reg_window *)
(regs->u_regs[UREG_FP] + STACK_BIAS);
@@ -491,6 +491,10 @@ void die_if_kernel(char *str, struct pt_regs *regs)
printk("Instruction DUMP:");
instruction_dump ((unsigned int *) regs->tpc);
}
+#ifdef __SMP__
+ smp_report_regs();
+#endif
+
lock_kernel(); /* Or else! */
if(regs->tstate & TSTATE_PRIV)
do_exit(SIGKILL);
@@ -498,7 +502,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
}
extern int handle_popc(u32 insn, struct pt_regs *regs);
-extern int handle_ldq_stq(u32 insn, struct pt_regs *regs);
+extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
void do_illegal_instruction(struct pt_regs *regs)
{
@@ -515,7 +519,7 @@ void do_illegal_instruction(struct pt_regs *regs)
if (handle_popc(insn, regs))
return;
} else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ {
- if (handle_ldq_stq(insn, regs))
+ if (handle_ldf_stq(insn, regs))
return;
}
}
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 656d29454..3a9fdf4d2 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.27 1998/09/25 01:09:10 davem Exp $
+/* $Id: ttable.S,v 1.28 1999/03/29 12:38:10 jj Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -21,8 +21,8 @@ tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0
tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d)
tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f)
tl0_fpdis: TRAP_NOSAVE(do_fpdis)
-tl0_fpieee: TRAP(do_fpieee)
-tl0_fpother: TRAP(do_fpother)
+tl0_fpieee: TRAP_SAVEFPU(do_fpieee)
+tl0_fpother: TRAP_SAVEFPU(do_fpother)
tl0_tof: TRAP(do_tof)
tl0_cwin: CLEAN_WINDOW
tl0_div0: TRAP(do_div0)
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index d32309b9d..f4599bbdb 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.13 1998/10/07 22:43:13 davem Exp $
+/* $Id: unaligned.c,v 1.15 1999/04/03 11:36:21 anton Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -374,7 +374,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
- lock_kernel();
if(!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n",
regs->tpc);
@@ -423,7 +422,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
}
advance(regs);
}
- unlock_kernel();
}
static char popc_helper[] = {
@@ -470,7 +468,7 @@ extern void do_fpother(struct pt_regs *regs);
extern void do_privact(struct pt_regs *regs);
extern void data_access_exception(struct pt_regs *regs);
-int handle_ldq_stq(u32 insn, struct pt_regs *regs)
+int handle_ldf_stq(u32 insn, struct pt_regs *regs)
{
unsigned long addr = compute_effective_address(regs, insn, 0);
int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
@@ -522,8 +520,10 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs)
return 1;
}
} else {
- /* LDQ */
- u32 first, second, third, fourth;
+ /* LDF, LDDF, LDQF */
+ u32 data[4] __attribute__ ((aligned(8)));
+ int size, i;
+ int err;
if (asi < 0x80) {
do_privact(regs);
@@ -532,25 +532,35 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs)
data_access_exception(regs);
return 1;
}
- if (get_user (first, (u32 *)addr) ||
- __get_user (second, (u32 *)(addr + 4)) ||
- __get_user (third, (u32 *)(addr + 8)) ||
- __get_user (fourth, (u32 *)(addr + 12))) {
- if (asi & 0x2) /* NF */ {
- first = 0; second = 0; third = 0; fourth = 0;
- } else {
- data_access_exception(regs);
- return 1;
- }
+ switch (insn & 0x180000) {
+ case 0x000000: size = 1; break;
+ case 0x100000: size = 4; break;
+ default: size = 2; break;
+ }
+ for (i = 0; i < size; i++)
+ data[i] = 0;
+
+ err = get_user (data[0], (u32 *)addr);
+ if (!err) {
+ for (i = 1; i < size; i++)
+ err |= __get_user (data[i], (u32 *)(addr + 4*i));
+ }
+ if (err && !(asi & 0x2 /* NF */)) {
+ data_access_exception(regs);
+ return 1;
}
if (asi & 0x8) /* Little */ {
- u32 tmp = le32_to_cpup(&first);
-
- first = le32_to_cpup(&fourth);
- fourth = tmp;
- tmp = le32_to_cpup(&second);
- second = le32_to_cpup(&third);
- third = tmp;
+ u64 tmp;
+
+ switch (size) {
+ case 1: data[0] = le32_to_cpup(data + 0); break;
+ default:*(u64 *)(data + 0) = le64_to_cpup((u64 *)(data + 0));
+ break;
+ case 4: tmp = le64_to_cpup((u64 *)(data + 0));
+ *(u64 *)(data + 0) = le64_to_cpup((u64 *)(data + 2));
+ *(u64 *)(data + 2) = tmp;
+ break;
+ }
}
if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
current->tss.fpsaved[0] = FPRS_FEF;
@@ -562,16 +572,27 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs)
else
memset(f->regs+32, 0, 32*sizeof(u32));
}
- f->regs[freg] = first;
- f->regs[freg+1] = second;
- f->regs[freg+2] = third;
- f->regs[freg+3] = fourth;
+ memcpy(f->regs + freg, data, size * 4);
current->tss.fpsaved[0] |= flag;
}
advance(regs);
return 1;
}
+void handle_ld_nf(u32 insn, struct pt_regs *regs)
+{
+ int rd = ((insn >> 25) & 0x1f);
+ int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
+ unsigned long *reg;
+
+ maybe_flush_windows(0, 0, rd, from_kernel);
+ reg = fetch_reg_addr(rd, regs);
+ if ((insn & 0x780000) == 0x180000)
+ reg[1] = 0;
+ reg[0] = 0;
+ advance(regs);
+}
+
void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
{
unsigned long pc = regs->tpc;
diff --git a/arch/sparc64/math-emu/fabsq.c b/arch/sparc64/math-emu/fabsq.c
index e01b02046..62a7e1839 100644
--- a/arch/sparc64/math-emu/fabsq.c
+++ b/arch/sparc64/math-emu/fabsq.c
@@ -2,5 +2,5 @@ int FABSQ(unsigned long *rd, unsigned long *rs2)
{
rd[0] = rs2[0] & 0x7fffffffffffffffUL;
rd[1] = rs2[1];
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/faddd.c b/arch/sparc64/math-emu/faddd.c
index 69b9f7c24..7c755b872 100644
--- a/arch/sparc64/math-emu/faddd.c
+++ b/arch/sparc64/math-emu/faddd.c
@@ -8,6 +8,5 @@ int FADDD(void *rd, void *rs2, void *rs1)
__FP_UNPACK_D(A, rs1);
__FP_UNPACK_D(B, rs2);
FP_ADD_D(R, A, B);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc64/math-emu/faddq.c b/arch/sparc64/math-emu/faddq.c
index 07245eb95..052c6c9cd 100644
--- a/arch/sparc64/math-emu/faddq.c
+++ b/arch/sparc64/math-emu/faddq.c
@@ -8,6 +8,5 @@ int FADDQ(void *rd, void *rs2, void *rs1)
__FP_UNPACK_Q(A, rs1);
__FP_UNPACK_Q(B, rs2);
FP_ADD_Q(R, A, B);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fadds.c b/arch/sparc64/math-emu/fadds.c
index 71295ae47..35bb2030e 100644
--- a/arch/sparc64/math-emu/fadds.c
+++ b/arch/sparc64/math-emu/fadds.c
@@ -8,6 +8,5 @@ int FADDS(void *rd, void *rs2, void *rs1)
__FP_UNPACK_S(A, rs1);
__FP_UNPACK_S(B, rs2);
FP_ADD_S(R, A, B);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc64/math-emu/fcmpeq.c b/arch/sparc64/math-emu/fcmpeq.c
index e74b1b06b..e99864f55 100644
--- a/arch/sparc64/math-emu/fcmpeq.c
+++ b/arch/sparc64/math-emu/fcmpeq.c
@@ -21,5 +21,5 @@ int FCMPEQ(void *rd, void *rs2, void *rs1)
case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
}
*(unsigned long *)rd = fsr;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fcmpq.c b/arch/sparc64/math-emu/fcmpq.c
index 9effefb1f..54ec4492f 100644
--- a/arch/sparc64/math-emu/fcmpq.c
+++ b/arch/sparc64/math-emu/fcmpq.c
@@ -21,5 +21,5 @@ int FCMPQ(void *rd, void *rs2, void *rs1)
case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
}
*(unsigned long *)rd = fsr;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fdivd.c b/arch/sparc64/math-emu/fdivd.c
index 2984290fc..a19dbdd78 100644
--- a/arch/sparc64/math-emu/fdivd.c
+++ b/arch/sparc64/math-emu/fdivd.c
@@ -4,10 +4,16 @@
int FDIVD(void *rd, void *rs2, void *rs1)
{
FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
+ int ret = 0;
__FP_UNPACK_D(A, rs1);
__FP_UNPACK_D(B, rs2);
+ if(B_c == FP_CLS_ZERO &&
+ A_c != FP_CLS_ZERO) {
+ ret |= EFLAG_DIVZERO;
+ if(__FPU_TRAP_P(EFLAG_DIVZERO))
+ return ret;
+ }
FP_DIV_D(R, A, B);
- __FP_PACK_D(rd, R);
- return 1;
+ return (ret | __FP_PACK_D(rd, R));
}
diff --git a/arch/sparc64/math-emu/fdivq.c b/arch/sparc64/math-emu/fdivq.c
index e5858c0af..9bc0987f5 100644
--- a/arch/sparc64/math-emu/fdivq.c
+++ b/arch/sparc64/math-emu/fdivq.c
@@ -4,10 +4,16 @@
int FDIVQ(void *rd, void *rs2, void *rs1)
{
FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
+ int ret;
__FP_UNPACK_Q(A, rs1);
__FP_UNPACK_Q(B, rs2);
+ if(B_c == FP_CLS_ZERO &&
+ A_c != FP_CLS_ZERO) {
+ ret |= EFLAG_DIVZERO;
+ if(__FPU_TRAP_P(EFLAG_DIVZERO))
+ return ret;
+ }
FP_DIV_Q(R, A, B);
- __FP_PACK_Q(rd, R);
- return 1;
+ return (ret | __FP_PACK_Q(rd, R));
}
diff --git a/arch/sparc64/math-emu/fdivs.c b/arch/sparc64/math-emu/fdivs.c
index 704f218c9..41095dc4c 100644
--- a/arch/sparc64/math-emu/fdivs.c
+++ b/arch/sparc64/math-emu/fdivs.c
@@ -4,10 +4,17 @@
int FDIVS(void *rd, void *rs2, void *rs1)
{
FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
+ int ret = 0;
__FP_UNPACK_S(A, rs1);
__FP_UNPACK_S(B, rs2);
+ if(B_c == FP_CLS_ZERO &&
+ A_c != FP_CLS_ZERO) {
+ ret |= EFLAG_DIVZERO;
+ if(__FPU_TRAP_P(EFLAG_DIVZERO))
+ return ret;
+ }
FP_DIV_S(R, A, B);
- __FP_PACK_S(rd, R);
- return 1;
+ return (ret | __FP_PACK_S(rd, R));
}
+
diff --git a/arch/sparc64/math-emu/fdmulq.c b/arch/sparc64/math-emu/fdmulq.c
index 7862a0039..4d4b5916a 100644
--- a/arch/sparc64/math-emu/fdmulq.c
+++ b/arch/sparc64/math-emu/fdmulq.c
@@ -11,6 +11,5 @@ int FDMULQ(void *rd, void *rs2, void *rs1)
__FP_UNPACK_D(IN, rs2);
FP_CONV(Q,D,2,1,B,IN);
FP_MUL_Q(R, A, B);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fdtoi.c b/arch/sparc64/math-emu/fdtoi.c
index f7ba0f1f2..1b12a6395 100644
--- a/arch/sparc64/math-emu/fdtoi.c
+++ b/arch/sparc64/math-emu/fdtoi.c
@@ -9,5 +9,5 @@ int FDTOI(unsigned *rd, void *rs2)
__FP_UNPACK_D(A, rs2);
FP_TO_INT_D(r, A, 32, 1);
*rd = r;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fdtoq.c b/arch/sparc64/math-emu/fdtoq.c
index 42e4009c6..b37b31198 100644
--- a/arch/sparc64/math-emu/fdtoq.c
+++ b/arch/sparc64/math-emu/fdtoq.c
@@ -8,6 +8,5 @@ int FDTOQ(void *rd, void *rs2)
__FP_UNPACK_D(A, rs2);
FP_CONV(Q,D,2,1,R,A);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fdtos.c b/arch/sparc64/math-emu/fdtos.c
index fb7fede54..ae9f382ed 100644
--- a/arch/sparc64/math-emu/fdtos.c
+++ b/arch/sparc64/math-emu/fdtos.c
@@ -8,6 +8,5 @@ int FDTOS(void *rd, void *rs2)
__FP_UNPACK_D(A, rs2);
FP_CONV(S,D,1,1,R,A);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc64/math-emu/fdtox.c b/arch/sparc64/math-emu/fdtox.c
index 1a93b585c..062651a47 100644
--- a/arch/sparc64/math-emu/fdtox.c
+++ b/arch/sparc64/math-emu/fdtox.c
@@ -9,5 +9,5 @@ int FDTOX(unsigned long *rd, void *rs2)
__FP_UNPACK_D(A, rs2);
FP_TO_INT_D(r, A, 64, 1);
*rd = r;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fitoq.c b/arch/sparc64/math-emu/fitoq.c
index 5d08bbe18..68ba2839b 100644
--- a/arch/sparc64/math-emu/fitoq.c
+++ b/arch/sparc64/math-emu/fitoq.c
@@ -7,6 +7,5 @@ int FITOQ(void *rd, void *rs2)
int a = *(int *)rs2;
FP_FROM_INT_Q(R, a, 32, int);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fmuld.c b/arch/sparc64/math-emu/fmuld.c
index 04d1f38df..707bb45c1 100644
--- a/arch/sparc64/math-emu/fmuld.c
+++ b/arch/sparc64/math-emu/fmuld.c
@@ -8,6 +8,5 @@ int FMULD(void *rd, void *rs2, void *rs1)
__FP_UNPACK_D(A, rs1);
__FP_UNPACK_D(B, rs2);
FP_MUL_D(R, A, B);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc64/math-emu/fmulq.c b/arch/sparc64/math-emu/fmulq.c
index 4d099be6f..94400d023 100644
--- a/arch/sparc64/math-emu/fmulq.c
+++ b/arch/sparc64/math-emu/fmulq.c
@@ -8,6 +8,5 @@ int FMULQ(void *rd, void *rs2, void *rs1)
__FP_UNPACK_Q(A, rs1);
__FP_UNPACK_Q(B, rs2);
FP_MUL_Q(R, A, B);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fmuls.c b/arch/sparc64/math-emu/fmuls.c
index 8a358d030..b16509964 100644
--- a/arch/sparc64/math-emu/fmuls.c
+++ b/arch/sparc64/math-emu/fmuls.c
@@ -8,6 +8,5 @@ int FMULS(void *rd, void *rs2, void *rs1)
__FP_UNPACK_S(A, rs1);
__FP_UNPACK_S(B, rs2);
FP_MUL_S(R, A, B);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc64/math-emu/fnegq.c b/arch/sparc64/math-emu/fnegq.c
index 2251e3308..745020ee3 100644
--- a/arch/sparc64/math-emu/fnegq.c
+++ b/arch/sparc64/math-emu/fnegq.c
@@ -2,6 +2,6 @@ int FNEGQ(unsigned long *rd, unsigned long *rs2)
{
rd[0] = rs2[0] ^ 0x8000000000000000UL;
rd[1] = rs2[1];
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fqtod.c b/arch/sparc64/math-emu/fqtod.c
index 1f9161999..29e41cf6a 100644
--- a/arch/sparc64/math-emu/fqtod.c
+++ b/arch/sparc64/math-emu/fqtod.c
@@ -8,6 +8,5 @@ int FQTOD(void *rd, void *rs2)
__FP_UNPACK_Q(A, rs2);
FP_CONV(D,Q,1,2,R,A);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc64/math-emu/fqtoi.c b/arch/sparc64/math-emu/fqtoi.c
index 06d67ff81..1bb213f19 100644
--- a/arch/sparc64/math-emu/fqtoi.c
+++ b/arch/sparc64/math-emu/fqtoi.c
@@ -9,5 +9,5 @@ int FQTOI(unsigned *rd, void *rs2)
__FP_UNPACK_Q(A, rs2);
FP_TO_INT_Q(r, A, 32, 1);
*rd = r;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fqtos.c b/arch/sparc64/math-emu/fqtos.c
index 833f10618..382912d11 100644
--- a/arch/sparc64/math-emu/fqtos.c
+++ b/arch/sparc64/math-emu/fqtos.c
@@ -8,6 +8,5 @@ int FQTOS(void *rd, void *rs2)
__FP_UNPACK_Q(A, rs2);
FP_CONV(S,Q,1,2,R,A);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc64/math-emu/fqtox.c b/arch/sparc64/math-emu/fqtox.c
index 6cdabc8cd..484ca6900 100644
--- a/arch/sparc64/math-emu/fqtox.c
+++ b/arch/sparc64/math-emu/fqtox.c
@@ -9,5 +9,5 @@ int FQTOX(unsigned long *rd, void *rs2)
__FP_UNPACK_Q(A, rs2);
FP_TO_INT_Q(r, A, 64, 1);
*rd = r;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fsmuld.c b/arch/sparc64/math-emu/fsmuld.c
index 1a0eefd06..b6bf61b0f 100644
--- a/arch/sparc64/math-emu/fsmuld.c
+++ b/arch/sparc64/math-emu/fsmuld.c
@@ -11,6 +11,5 @@ int FSMULD(void *rd, void *rs2, void *rs1)
__FP_UNPACK_S(IN, rs2);
FP_CONV(D,S,1,1,B,IN);
FP_MUL_D(R, A, B);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc64/math-emu/fsqrtd.c b/arch/sparc64/math-emu/fsqrtd.c
index 59f5e3bf3..b022f7d37 100644
--- a/arch/sparc64/math-emu/fsqrtd.c
+++ b/arch/sparc64/math-emu/fsqrtd.c
@@ -7,6 +7,5 @@ int FSQRTD(void *rd, void *rs2)
__FP_UNPACK_D(A, rs2);
FP_SQRT_D(R, A);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc64/math-emu/fsqrtq.c b/arch/sparc64/math-emu/fsqrtq.c
index 8f84aa850..7e620079f 100644
--- a/arch/sparc64/math-emu/fsqrtq.c
+++ b/arch/sparc64/math-emu/fsqrtq.c
@@ -7,6 +7,5 @@ int FSQRTQ(void *rd, void *rs2)
__FP_UNPACK_Q(A, rs2);
FP_SQRT_Q(R, A);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fsqrts.c b/arch/sparc64/math-emu/fsqrts.c
index d57cdc98e..62ff0b782 100644
--- a/arch/sparc64/math-emu/fsqrts.c
+++ b/arch/sparc64/math-emu/fsqrts.c
@@ -7,6 +7,5 @@ int FSQRTS(void *rd, void *rs2)
__FP_UNPACK_S(A, rs2);
FP_SQRT_S(R, A);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc64/math-emu/fstod.c b/arch/sparc64/math-emu/fstod.c
index 60f1bc8a4..91935f78e 100644
--- a/arch/sparc64/math-emu/fstod.c
+++ b/arch/sparc64/math-emu/fstod.c
@@ -8,6 +8,5 @@ int FSTOD(void *rd, void *rs2)
__FP_UNPACK_S(A, rs2);
FP_CONV(D,S,1,1,R,A);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc64/math-emu/fstoi.c b/arch/sparc64/math-emu/fstoi.c
index 4adc7d170..5ff3854cc 100644
--- a/arch/sparc64/math-emu/fstoi.c
+++ b/arch/sparc64/math-emu/fstoi.c
@@ -9,5 +9,5 @@ int FSTOI(unsigned *rd, void *rs2)
__FP_UNPACK_S(A, rs2);
FP_TO_INT_S(r, A, 32, 1);
*rd = r;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fstoq.c b/arch/sparc64/math-emu/fstoq.c
index 06313a77f..1a56e0055 100644
--- a/arch/sparc64/math-emu/fstoq.c
+++ b/arch/sparc64/math-emu/fstoq.c
@@ -8,6 +8,5 @@ int FSTOQ(void *rd, void *rs2)
__FP_UNPACK_S(A, rs2);
FP_CONV(Q,S,2,1,R,A);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fstox.c b/arch/sparc64/math-emu/fstox.c
index 555fba2ee..fa2135f8b 100644
--- a/arch/sparc64/math-emu/fstox.c
+++ b/arch/sparc64/math-emu/fstox.c
@@ -9,5 +9,5 @@ int FSTOX(unsigned long *rd, void *rs2)
__FP_UNPACK_S(A, rs2);
FP_TO_INT_S(r, A, 64, 1);
*rd = r;
- return 1;
+ return 0;
}
diff --git a/arch/sparc64/math-emu/fsubd.c b/arch/sparc64/math-emu/fsubd.c
index b0f451b32..bbd11c611 100644
--- a/arch/sparc64/math-emu/fsubd.c
+++ b/arch/sparc64/math-emu/fsubd.c
@@ -10,6 +10,5 @@ int FSUBD(void *rd, void *rs2, void *rs1)
if (B_c != FP_CLS_NAN)
B_s ^= 1;
FP_ADD_D(R, A, B);
- __FP_PACK_D(rd, R);
- return 1;
+ return __FP_PACK_D(rd, R);
}
diff --git a/arch/sparc64/math-emu/fsubq.c b/arch/sparc64/math-emu/fsubq.c
index ef006a540..d5cc260cf 100644
--- a/arch/sparc64/math-emu/fsubq.c
+++ b/arch/sparc64/math-emu/fsubq.c
@@ -10,6 +10,5 @@ int FSUBQ(void *rd, void *rs2, void *rs1)
if (B_c != FP_CLS_NAN)
B_s ^= 1;
FP_ADD_Q(R, A, B);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/fsubs.c b/arch/sparc64/math-emu/fsubs.c
index d060f095a..ff8fa12b1 100644
--- a/arch/sparc64/math-emu/fsubs.c
+++ b/arch/sparc64/math-emu/fsubs.c
@@ -10,6 +10,5 @@ int FSUBS(void *rd, void *rs2, void *rs1)
if (B_c != FP_CLS_NAN)
B_s ^= 1;
FP_ADD_S(R, A, B);
- __FP_PACK_S(rd, R);
- return 1;
+ return __FP_PACK_S(rd, R);
}
diff --git a/arch/sparc64/math-emu/fxtoq.c b/arch/sparc64/math-emu/fxtoq.c
index 7c2f7df48..411e51571 100644
--- a/arch/sparc64/math-emu/fxtoq.c
+++ b/arch/sparc64/math-emu/fxtoq.c
@@ -7,6 +7,5 @@ int FXTOQ(void *rd, void *rs2)
long a = *(long *)rs2;
FP_FROM_INT_Q(R, a, 64, long);
- __FP_PACK_Q(rd, R);
- return 1;
+ return __FP_PACK_Q(rd, R);
}
diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c
index 5a71804b9..f4493e224 100644
--- a/arch/sparc64/math-emu/math.c
+++ b/arch/sparc64/math-emu/math.c
@@ -1,7 +1,8 @@
-/* $Id: math.c,v 1.5 1998/06/12 14:54:27 jj Exp $
+/* $Id: math.c,v 1.7 1999/02/10 14:16:26 davem Exp $
* arch/sparc64/math-emu/math.c
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
*
* Emulation routines originate from soft-fp package, which is part
* of glibc and has appropriate copyrights in it.
@@ -14,6 +15,8 @@
#include <asm/ptrace.h>
#include <asm/uaccess.h>
+#include "soft-fp.h"
+
#define FLOATFUNC(x) extern int x(void *,void *,void *);
FLOATFUNC(FMOVQ)
@@ -54,6 +57,91 @@ FLOATFUNC(FSTOD)
FLOATFUNC(FSTOI)
FLOATFUNC(FDTOI)
+#define FSR_TEM_SHIFT 23UL
+#define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT)
+#define FSR_AEXC_SHIFT 5UL
+#define FSR_AEXC_MASK (0x1fUL << FSR_AEXC_SHIFT)
+#define FSR_CEXC_SHIFT 0UL
+#define FSR_CEXC_MASK (0x1fUL << FSR_CEXC_SHIFT)
+
+/* All routines returning an exception to raise should detect
+ * such exceptions _before_ rounding to be consistant with
+ * the behavior of the hardware in the implemented cases
+ * (and thus with the recommendations in the V9 architecture
+ * manual).
+ *
+ * We return 0 if a SIGFPE should be sent, 1 otherwise.
+ */
+static int record_exception(struct pt_regs *regs, int eflag)
+{
+ u64 fsr = current->tss.xfsr[0];
+ int would_trap;
+
+ /* Determine if this exception would have generated a trap. */
+ would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL;
+
+ /* If trapping, we only want to signal one bit. */
+ if(would_trap != 0) {
+ eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
+ if((eflag & (eflag - 1)) != 0) {
+ if(eflag & EFLAG_INVALID)
+ eflag = EFLAG_INVALID;
+ else if(eflag & EFLAG_DIVZERO)
+ eflag = EFLAG_DIVZERO;
+ else if(eflag & EFLAG_INEXACT)
+ eflag = EFLAG_INEXACT;
+ }
+ }
+
+ /* Set CEXC, here are the rules:
+ *
+ * 1) In general all FPU ops will set one and only one
+ * bit in the CEXC field, this is always the case
+ * when the IEEE exception trap is enabled in TEM.
+ *
+ * 2) As a special case, if an overflow or underflow
+ * is being signalled, AND the trap is not enabled
+ * in TEM, then the inexact field shall also be set.
+ */
+ fsr &= ~(FSR_CEXC_MASK);
+ if(would_trap ||
+ (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) {
+ fsr |= ((long)eflag << FSR_CEXC_SHIFT);
+ } else {
+ fsr |= (((long)eflag << FSR_CEXC_SHIFT) |
+ (EFLAG_INEXACT << FSR_CEXC_SHIFT));
+ }
+
+ /* Set the AEXC field, rules are:
+ *
+ * 1) If a trap would not be generated, the
+ * CEXC just generated is OR'd into the
+ * existing value of AEXC.
+ *
+ * 2) When a trap is generated, AEXC is cleared.
+ */
+ if(would_trap == 0)
+ fsr |= ((long)eflag << FSR_AEXC_SHIFT);
+ else
+ fsr &= ~(FSR_AEXC_MASK);
+
+ /* If trapping, indicate fault trap type IEEE. */
+ if(would_trap != 0)
+ fsr |= (1UL << 14);
+
+ current->tss.xfsr[0] = fsr;
+
+ /* If we will not trap, advance the program counter over
+ * the instruction being handled.
+ */
+ if(would_trap == 0) {
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ }
+
+ return (would_trap ? 0 : 1);
+}
+
int do_mathemu(struct pt_regs *regs, struct fpustate *f)
{
unsigned long pc = regs->tpc;
@@ -175,7 +263,12 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
current->tss.fpsaved[0] |= flags;
break;
}
- func(rd, rs2, rs1);
+ flags = func(rd, rs2, rs1);
+ if(flags != 0)
+ return record_exception(regs, flags);
+
+ /* Success and no exceptions detected. */
+ current->tss.xfsr[0] &= ~(FSR_CEXC_MASK);
regs->tpc = regs->tnpc;
regs->tnpc += 4;
return 1;
diff --git a/arch/sparc64/math-emu/op-2.h b/arch/sparc64/math-emu/op-2.h
index 5999cfc3b..8ac63188c 100644
--- a/arch/sparc64/math-emu/op-2.h
+++ b/arch/sparc64/math-emu/op-2.h
@@ -190,14 +190,14 @@
\
__FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
_FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
+ 0, _b_f1, _b_f0, 0, \
_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
- _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
- 0, _b_f1, _b_f0, 0); \
+ _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \
__FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
_FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
+ 0, _c_f1, _c_f0, 0, \
_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
- _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
- 0, _c_f1, _c_f0, 0); \
+ _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \
\
/* Normalize since we know where the msb of the multiplicands \
were (bit B), we know that the msb of the of the product is \
diff --git a/arch/sparc64/math-emu/op-common.h b/arch/sparc64/math-emu/op-common.h
index ac49cd6c2..6090e0213 100644
--- a/arch/sparc64/math-emu/op-common.h
+++ b/arch/sparc64/math-emu/op-common.h
@@ -53,14 +53,14 @@ do { \
*/
#define _FP_PACK_CANONICAL(fs, wc, X) \
-do { \
+({int __ret = 0; \
switch (X##_c) \
{ \
case FP_CLS_NORMAL: \
X##_e += _FP_EXPBIAS_##fs; \
if (X##_e > 0) \
{ \
- _FP_ROUND(wc, X); \
+ __ret |= _FP_ROUND(wc, X); \
if (_FP_FRAC_OVERP_##wc(fs, X)) \
{ \
_FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \
@@ -73,6 +73,7 @@ do { \
/* overflow to infinity */ \
X##_e = _FP_EXPMAX_##fs; \
_FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
+ __ret |= EFLAG_OVERFLOW; \
} \
} \
else \
@@ -82,7 +83,7 @@ do { \
if (X##_e <= _FP_WFRACBITS_##fs) \
{ \
_FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \
- _FP_ROUND(wc, X); \
+ __ret |= _FP_ROUND(wc, X); \
_FP_FRAC_SLL_##wc(X, 1); \
if (_FP_FRAC_OVERP_##wc(fs, X)) \
{ \
@@ -93,6 +94,7 @@ do { \
{ \
X##_e = 0; \
_FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \
+ __ret |= EFLAG_UNDERFLOW; \
} \
} \
else \
@@ -100,6 +102,7 @@ do { \
/* underflow to zero */ \
X##_e = 0; \
_FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
+ __ret |= EFLAG_UNDERFLOW; \
} \
} \
break; \
@@ -125,7 +128,8 @@ do { \
_FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \
break; \
} \
-} while (0)
+ __ret; \
+})
/*
@@ -424,11 +428,19 @@ do { \
} \
else \
{ \
- /* Force -0 -> +0 */ \
- if (!X##_e && _FP_FRAC_ZEROP_##wc(X)) X##_s = 0; \
- if (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) X##_s = 0; \
+ int __is_zero_x; \
+ int __is_zero_y; \
+ \
+ __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \
+ __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \
\
- if (X##_s != Y##_s) \
+ if (__is_zero_x && __is_zero_y) \
+ ret = 0; \
+ else if (__is_zero_x) \
+ ret = Y##_s ? 1 : -1; \
+ else if (__is_zero_y) \
+ ret = X##_s ? -1 : 1; \
+ else if (X##_s != Y##_s) \
ret = X##_s ? -1 : 1; \
else if (X##_e > Y##_e) \
ret = X##_s ? -1 : 1; \
diff --git a/arch/sparc64/math-emu/sfp-machine.h b/arch/sparc64/math-emu/sfp-machine.h
index f15a5ea4a..3846ac4f9 100644
--- a/arch/sparc64/math-emu/sfp-machine.h
+++ b/arch/sparc64/math-emu/sfp-machine.h
@@ -52,16 +52,6 @@
X##_s = _flo->bits.sign; \
} while (0)
-#define __FP_PACK_RAW_1(fs, val, X) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- _flo->bits.frac = X##_f; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } while (0)
-
#define __FP_UNPACK_RAW_2(fs, X, val) \
do { \
union _FP_UNION_##fs *_flo = \
@@ -73,53 +63,80 @@
X##_s = _flo->bits.sign; \
} while (0)
-#define __FP_PACK_RAW_2(fs, val, X) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- _flo->bits.frac0 = X##_f0; \
- _flo->bits.frac1 = X##_f1; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } while (0)
-
#define __FP_UNPACK_S(X,val) \
do { \
__FP_UNPACK_RAW_1(S,X,val); \
_FP_UNPACK_CANONICAL(S,1,X); \
} while (0)
-#define __FP_PACK_S(val,X) \
- do { \
- _FP_PACK_CANONICAL(S,1,X); \
- __FP_PACK_RAW_1(S,val,X); \
- } while (0)
-
#define __FP_UNPACK_D(X,val) \
do { \
__FP_UNPACK_RAW_1(D,X,val); \
_FP_UNPACK_CANONICAL(D,1,X); \
} while (0)
-#define __FP_PACK_D(val,X) \
- do { \
- _FP_PACK_CANONICAL(D,1,X); \
- __FP_PACK_RAW_1(D,val,X); \
- } while (0)
-
#define __FP_UNPACK_Q(X,val) \
do { \
__FP_UNPACK_RAW_2(Q,X,val); \
_FP_UNPACK_CANONICAL(Q,2,X); \
} while (0)
-#define __FP_PACK_Q(val,X) \
- do { \
- _FP_PACK_CANONICAL(Q,2,X); \
- __FP_PACK_RAW_2(Q,val,X); \
+#define __FP_PACK_RAW_1(fs, val, X) \
+ do { \
+ union _FP_UNION_##fs *_flo = \
+ (union _FP_UNION_##fs *)val; \
+ \
+ _flo->bits.frac = X##_f; \
+ _flo->bits.exp = X##_e; \
+ _flo->bits.sign = X##_s; \
+ } while (0)
+
+#define __FP_PACK_RAW_2(fs, val, X) \
+ do { \
+ union _FP_UNION_##fs *_flo = \
+ (union _FP_UNION_##fs *)val; \
+ \
+ _flo->bits.frac0 = X##_f0; \
+ _flo->bits.frac1 = X##_f1; \
+ _flo->bits.exp = X##_e; \
+ _flo->bits.sign = X##_s; \
} while (0)
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+/* We only actually write to the destination register
+ * if exceptions signalled (if any) will not trap.
+ */
+#define __FPU_TEM \
+ (((current->tss.xfsr[0])>>23)&0x1f)
+#define __FPU_TRAP_P(bits) \
+ ((__FPU_TEM & (bits)) != 0)
+
+#define __FP_PACK_S(val,X) \
+({ int __exc = _FP_PACK_CANONICAL(S,1,X); \
+ if(!__exc || !__FPU_TRAP_P(__exc)) \
+ __FP_PACK_RAW_1(S,val,X); \
+ __exc; \
+})
+
+#define __FP_PACK_D(val,X) \
+({ int __exc = _FP_PACK_CANONICAL(D,1,X); \
+ if(!__exc || !__FPU_TRAP_P(__exc)) \
+ __FP_PACK_RAW_1(D,val,X); \
+ __exc; \
+})
+
+#define __FP_PACK_Q(val,X) \
+({ int __exc = _FP_PACK_CANONICAL(Q,2,X); \
+ if(!__exc || !__FPU_TRAP_P(__exc)) \
+ __FP_PACK_RAW_2(Q,val,X); \
+ __exc; \
+})
+
+/* Obtain the current rounding mode. */
+#define FP_ROUNDMODE ((current->tss.xfsr[0] >> 30) & 0x3)
+
#include <linux/types.h>
#include <asm/byteorder.h>
@@ -153,28 +170,24 @@
#define umul_ppmm(wh, wl, u, v) \
do { \
- long tmp1 = 0, tmp2 = 0, tmp3 = 0; \
__asm__ ("mulx %2,%3,%1
- srlx %2,32,%4
- srl %3,0,%5
- mulx %4,%5,%6
- srlx %3,32,%4
- srl %2,0,%5
- mulx %4,%5,%5
- srlx %2,32,%4
- add %5,%6,%6
- srlx %3,32,%5
- mulx %4,%5,%4
- srlx %6,32,%5
- add %4,%5,%0" \
+ srlx %2,32,%%g1
+ srl %3,0,%%g2
+ mulx %%g1,%%g2,%%g3
+ srlx %3,32,%%g1
+ srl %2,0,%%g2
+ mulx %%g1,%%g2,%%g2
+ srlx %2,32,%%g1
+ add %%g2,%%g3,%%g3
+ srlx %3,32,%%g2
+ mulx %%g1,%%g2,%%g1
+ srlx %%g3,32,%%g2
+ add %%g1,%%g2,%0" \
: "=r" ((UDItype)(wh)), \
"=&r" ((UDItype)(wl)) \
: "r" ((UDItype)(u)), \
- "r" ((UDItype)(v)), \
- "r" ((UDItype)(tmp1)), \
- "r" ((UDItype)(tmp2)), \
- "r" ((UDItype)(tmp3)) \
- : "cc"); \
+ "r" ((UDItype)(v)) \
+ : "g1", "g2", "g3", "cc"); \
} while (0)
#define udiv_qrnnd(q, r, n1, n0, d) \
@@ -223,3 +236,10 @@
#else
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
+
+/* Exception flags. */
+#define EFLAG_INVALID (1 << 4)
+#define EFLAG_OVERFLOW (1 << 3)
+#define EFLAG_UNDERFLOW (1 << 2)
+#define EFLAG_DIVZERO (1 << 1)
+#define EFLAG_INEXACT (1 << 0)
diff --git a/arch/sparc64/math-emu/soft-fp.h b/arch/sparc64/math-emu/soft-fp.h
index a4f72e78f..b54f86217 100644
--- a/arch/sparc64/math-emu/soft-fp.h
+++ b/arch/sparc64/math-emu/soft-fp.h
@@ -14,45 +14,56 @@
# define FP_RND_ZERO 1
# define FP_RND_PINF 2
# define FP_RND_MINF 3
+#ifndef FP_ROUNDMODE
# define FP_ROUNDMODE FP_RND_NEAREST
#endif
+#endif
#define _FP_ROUND_NEAREST(wc, X) \
- do { \
+({ int __ret = EFLAG_INEXACT; \
if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND) \
_FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \
- } while(0)
+ else __ret = 0; \
+ __ret; \
+})
-#define _FP_ROUND_ZERO(wc, X)
+#define _FP_ROUND_ZERO(wc, X) 0 /* XXX */
#define _FP_ROUND_PINF(wc, X) \
- do { \
+({ int __ret = EFLAG_INEXACT; \
if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \
_FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \
- } while (0)
+ else __ret = 0; \
+ __ret; \
+})
#define _FP_ROUND_MINF(wc, X) \
- do { \
+({ int __ret = EFLAG_INEXACT; \
if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \
_FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \
- } while (0)
+ else __ret = 0; \
+ __ret; \
+})
#define _FP_ROUND(wc, X) \
+({ int __ret = 0; \
switch (FP_ROUNDMODE) \
{ \
case FP_RND_NEAREST: \
- _FP_ROUND_NEAREST(wc,X); \
+ __ret |= _FP_ROUND_NEAREST(wc,X); \
break; \
case FP_RND_ZERO: \
- _FP_ROUND_ZERO(wc,X); \
+ __ret |= _FP_ROUND_ZERO(wc,X); \
break; \
case FP_RND_PINF: \
- _FP_ROUND_PINF(wc,X); \
+ __ret |= _FP_ROUND_PINF(wc,X); \
break; \
case FP_RND_MINF: \
- _FP_ROUND_MINF(wc,X); \
+ __ret |= _FP_ROUND_MINF(wc,X); \
break; \
- }
+ }; \
+ __ret; \
+})
#define FP_CLS_NORMAL 0
#define FP_CLS_ZERO 1
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 737872fb2..88fd55e03 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -1,8 +1,8 @@
-/* $Id: fault.c,v 1.26 1998/11/08 11:14:03 davem Exp $
+/* $Id: fault.c,v 1.34 1999/03/16 12:12:28 jj Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
*/
#include <asm/head.h>
@@ -14,6 +14,8 @@
#include <linux/signal.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -26,7 +28,7 @@
extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
/* Nice, simple, prom library does all the sweating for us. ;) */
-unsigned long prom_probe_memory (void)
+unsigned long __init prom_probe_memory (void)
{
register struct linux_mlist_p1275 *mlist;
register unsigned long bytes, base_paddr, tally;
@@ -35,7 +37,7 @@ unsigned long prom_probe_memory (void)
i = 0;
mlist = *prom_meminfo()->p1275_available;
bytes = tally = mlist->num_bytes;
- base_paddr = (unsigned int) mlist->start_adr;
+ base_paddr = mlist->start_adr;
sp_banks[0].base_addr = base_paddr;
sp_banks[0].num_bytes = bytes;
@@ -55,12 +57,12 @@ unsigned long prom_probe_memory (void)
break;
}
- sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
+ sp_banks[i].base_addr = mlist->start_adr;
sp_banks[i].num_bytes = mlist->num_bytes;
}
i++;
- sp_banks[i].base_addr = 0xdeadbeef;
+ sp_banks[i].base_addr = 0xdeadbeefbeefdeadUL;
sp_banks[i].num_bytes = 0;
/* Now mask all bank sizes on a page boundary, it is all we can
@@ -72,26 +74,12 @@ unsigned long prom_probe_memory (void)
return tally;
}
-/* Traverse the memory lists in the prom to see how much physical we
- * have.
- */
-unsigned long
-probe_memory(void)
-{
- unsigned long total;
-
- total = prom_probe_memory();
-
- /* Oh man, much nicer, keep the dirt in promlib. */
- return total;
-}
-
void unhandled_fault(unsigned long address, struct task_struct *tsk,
struct pt_regs *regs)
{
if((unsigned long) address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL "
- "pointer dereference");
+ "pointer dereference\n");
} else {
printk(KERN_ALERT "Unable to handle kernel paging request "
"at virtual address %016lx\n", (unsigned long)address);
@@ -100,22 +88,74 @@ void unhandled_fault(unsigned long address, struct task_struct *tsk,
(unsigned long) tsk->mm->context);
printk(KERN_ALERT "tsk->mm->pgd = %016lx\n",
(unsigned long) tsk->mm->pgd);
- lock_kernel();
die_if_kernel("Oops", regs);
- unlock_kernel();
}
/* #define DEBUG_EXCEPTIONS */
/* #define DEBUG_LOCKUPS */
+/* #define INSN_VPTE_LOOKUP */
+
+static inline u32 get_user_insn(unsigned long tpc)
+{
+ u32 insn;
+#ifndef INSN_VPTE_LOOKUP
+ pgd_t *pgdp = pgd_offset(current->mm, tpc);
+ pmd_t *pmdp;
+ pte_t *ptep;
+
+ if(pgd_none(*pgdp))
+ return 0;
+ pmdp = pmd_offset(pgdp, tpc);
+ if(pmd_none(*pmdp))
+ return 0;
+ ptep = pte_offset(pmdp, tpc);
+ if(!pte_present(*ptep))
+ return 0;
+ insn = *(unsigned int *)(pte_page(*ptep) + (tpc & ~PAGE_MASK));
+#else
+ register unsigned long pte asm("l1");
+
+ /* So that we don't pollute TLB, we read the instruction
+ * using PHYS bypass. For that, we of course need
+ * to know its page table entry. Do this by simulating
+ * dtlb_miss handler. -jj */
+ pte = ((((long)tpc) >> (PAGE_SHIFT-3)) & ~7);
+ asm volatile ("
+ rdpr %%pstate, %%l0
+ wrpr %%l0, %2, %%pstate
+ wrpr %%g0, 1, %%tl
+ mov %%l1, %%g6
+ ldxa [%%g3 + %%l1] %3, %%g5
+ mov %%g5, %%l1
+ wrpr %%g0, 0, %%tl
+ wrpr %%l0, 0, %%pstate
+ " : "=r" (pte) : "0" (pte), "i" (PSTATE_MG|PSTATE_IE), "i" (ASI_S) : "l0");
+
+ if ((long)pte >= 0) return 0;
+
+ pte = (pte & _PAGE_PADDR) + (tpc & ~PAGE_MASK);
+ asm ("lduwa [%1] %2, %0" : "=r" (insn) : "r" (pte), "i" (ASI_PHYS_USE_EC));
+#endif
+
+ return insn;
+}
+
asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, int write)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
+ unsigned int insn = 0;
#ifdef DEBUG_LOCKUPS
static unsigned long lastaddr, lastpc;
static int lastwrite, lockcnt;
#endif
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_interrupt() || mm == &init_mm)
+ goto do_kernel_fault;
down(&mm->mmap_sem);
#ifdef DEBUG_LOCKUPS
@@ -135,6 +175,21 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, in
vma = find_vma(mm, address);
if(!vma)
goto bad_area;
+#ifndef INSN_VPTE_LOOKUP
+ write &= 0xf;
+#else
+ if (write & 0x10) {
+ write = 0;
+ if((vma->vm_flags & VM_WRITE)) {
+ if (regs->tstate & TSTATE_PRIV)
+ insn = *(unsigned int *)regs->tpc;
+ else
+ insn = get_user_insn(regs->tpc);
+ if ((insn & 0xc0200000) == 0xc0200000 && (insn & 0x1780000) != 0x1680000)
+ write = 1;
+ }
+ }
+#endif
if(vma->vm_start <= address)
goto good_area;
if(!(vma->vm_flags & VM_GROWSDOWN))
@@ -168,16 +223,44 @@ bad_area:
do_kernel_fault:
{
- unsigned long g2 = regs->u_regs[UREG_G2];
+ unsigned long g2;
+ unsigned char asi = ASI_P;
+
+ if (!insn) {
+ if (regs->tstate & TSTATE_PRIV)
+ insn = *(unsigned int *)regs->tpc;
+ else
+ insn = get_user_insn(regs->tpc);
+ }
+ if (write != 1 && (insn & 0xc0800000) == 0xc0800000) {
+ if (insn & 0x2000)
+ asi = (regs->tstate >> 24);
+ else
+ asi = (insn >> 5);
+ if ((asi & 0xf2) == 0x82) {
+ /* This was a non-faulting load. Just clear the
+ destination register(s) and continue with the next
+ instruction. -jj */
+ if (insn & 0x1000000) {
+ extern int handle_ldf_stq(u32, struct pt_regs *);
+
+ handle_ldf_stq(insn, regs);
+ } else {
+ extern int handle_ld_nf(u32, struct pt_regs *);
+
+ handle_ld_nf(insn, regs);
+ }
+ return;
+ }
+ }
+
+ g2 = regs->u_regs[UREG_G2];
/* Is this in ex_table? */
if (regs->tstate & TSTATE_PRIV) {
- unsigned char asi = ASI_P;
- unsigned int insn;
unsigned long fixup;
-
- insn = *(unsigned int *)regs->tpc;
- if ((insn & 0xc0800000) == 0xc0800000) {
+
+ if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
if (insn & 0x2000)
asi = (regs->tstate >> 24);
else
diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c
index 0b869a2f2..ccb0951cc 100644
--- a/arch/sparc64/mm/generic.c
+++ b/arch/sparc64/mm/generic.c
@@ -1,4 +1,4 @@
-/* $Id: generic.c,v 1.3 1998/10/27 23:28:07 davem Exp $
+/* $Id: generic.c,v 1.8 1999/03/12 06:51:50 davem Exp $
* generic.c: Generic Sparc mm routines that are not dependent upon
* MMU type but are Sparc specific.
*
@@ -56,6 +56,10 @@ static inline void forget_pte(pte_t page)
*
* They use a pgprot that sets PAGE_IO and does not check the
* mem_map table as this is independent of normal memory.
+ *
+ * As a special hack if the lowest bit of offset is set the
+ * side-effect bit will be turned off. This is used as a
+ * performance improvement on FFB/AFB. -DaveM
*/
static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
unsigned long offset, pgprot_t prot, int space)
@@ -71,23 +75,32 @@ static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsign
pte_t entry;
unsigned long curend = address + PAGE_SIZE;
- entry = mk_pte_io(offset, prot, space);
- offset += PAGE_SIZE;
+ entry = mk_pte_io((offset & ~(0x1UL)), prot, space);
if (!(address & 0xffff)) {
- if (!(address & 0x3fffff) && !(offset & 0x3fffff) && end >= address + 0x400000) {
- entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ4MB), space);
+ if (!(address & 0x3fffff) && !(offset & 0x3ffffe) && end >= address + 0x400000) {
+ entry = mk_pte_io((offset & ~(0x1UL)),
+ __pgprot(pgprot_val (prot) | _PAGE_SZ4MB),
+ space);
curend = address + 0x400000;
- offset += 0x400000 - PAGE_SIZE;
- } else if (!(address & 0x7ffff) && !(offset & 0x7ffff) && end >= address + 0x80000) {
- entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ512K), space);
+ offset += 0x400000;
+ } else if (!(address & 0x7ffff) && !(offset & 0x7fffe) && end >= address + 0x80000) {
+ entry = mk_pte_io((offset & ~(0x1UL)),
+ __pgprot(pgprot_val (prot) | _PAGE_SZ512K),
+ space);
curend = address + 0x80000;
- offset += 0x80000 - PAGE_SIZE;
- } else if (!(offset & 0xffff) && end >= address + 0x10000) {
- entry = mk_pte_io(offset, __pgprot(pgprot_val (prot) | _PAGE_SZ64K), space);
+ offset += 0x80000;
+ } else if (!(offset & 0xfffe) && end >= address + 0x10000) {
+ entry = mk_pte_io((offset & ~(0x1UL)),
+ __pgprot(pgprot_val (prot) | _PAGE_SZ64K),
+ space);
curend = address + 0x10000;
- offset += 0x10000 - PAGE_SIZE;
+ offset += 0x10000;
}
- }
+ } else
+ offset += PAGE_SIZE;
+
+ if (offset & 0x1UL)
+ pte_val(entry) &= ~(_PAGE_E);
do {
oldpage = *pte;
pte_clear(pte);
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 236c866d6..aeb4b26b7 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,8 +1,8 @@
-/* $Id: init.c,v 1.103 1998/10/20 03:09:12 jj Exp $
+/* $Id: init.c,v 1.127 1999/05/08 03:00:38 davem Exp $
* arch/sparc64/mm/init.c
*
- * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <linux/config.h>
@@ -23,6 +23,7 @@
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/vaddrs.h>
+#include <asm/dma.h>
/* Turn this off if you suspect some place in some physical memory hole
might get into page tables (something would be broken very much). */
@@ -34,6 +35,8 @@ extern unsigned long device_scan(unsigned long);
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+unsigned long *sparc64_valid_addr_bitmap;
+
/* Ugly, but necessary... -DaveM */
unsigned long phys_base;
@@ -69,7 +72,7 @@ int do_check_pgt_cache(int low, int high)
page->next_hash = NULL;
page->pprev_hash = NULL;
pgd_cache_size -= 2;
- free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT));
+ __free_page(page);
freed++;
if (page2)
page = page2->next_hash;
@@ -139,9 +142,9 @@ void show_mem(void)
printk("%d reserved pages\n",reserved);
printk("%d pages shared\n",shared);
printk("%d pages swap cached\n",cached);
- printk("%ld pages in page table cache\n",pgtable_cache_size);
+ printk("%d pages in page table cache\n",pgtable_cache_size);
#ifndef __SMP__
- printk("%ld entries in page dir cache\n",pgd_cache_size);
+ printk("%d entries in page dir cache\n",pgd_cache_size);
#endif
show_buffers();
#ifdef CONFIG_NET
@@ -160,27 +163,31 @@ static int dvma_pages_current_index;
static unsigned long dvmaiobase = 0;
static unsigned long dvmaiosz __initdata = 0;
-/* #define E3000_DEBUG */
-
__initfunc(void dvmaio_init(void))
{
- int i;
+ long i;
if (!dvmaiobase) {
for (i = 0; sp_banks[i].num_bytes != 0; i++)
if (sp_banks[i].base_addr + sp_banks[i].num_bytes > dvmaiobase)
dvmaiobase = sp_banks[i].base_addr + sp_banks[i].num_bytes;
+
+ /* We map directly phys_base to phys_base+(4GB-DVMAIO_SIZE). */
+ dvmaiobase -= phys_base;
+
dvmaiobase = (dvmaiobase + DVMAIO_SIZE + 0x400000 - 1) & ~(0x400000 - 1);
for (i = 0; i < 6; i++)
- if (dvmaiobase <= ((1024 * 64 * 1024) << i))
+ if (dvmaiobase <= ((1024L * 64 * 1024) << i))
break;
- dvmaiobase = ((1024 * 64 * 1024) << i) - DVMAIO_SIZE;
+ dvmaiobase = ((1024L * 64 * 1024) << i) - DVMAIO_SIZE;
dvmaiosz = i;
}
}
__initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus))
{
+ extern int this_is_starfire;
+ extern void *starfire_hookup(int);
struct iommu_struct *iommu;
struct sysio_regs *sregs;
struct linux_prom64_registers rprop;
@@ -191,10 +198,6 @@ __initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus))
int err, i, j;
dvmaio_init();
-#ifdef E3000_DEBUG
- prom_printf("\niommu_init: [%x:%p] ",
- iommu_node, sbus);
-#endif
err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
sizeof(rprop));
if(err == -1) {
@@ -203,19 +206,16 @@ __initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus))
}
sregs = (struct sysio_regs *) __va(rprop.phys_addr);
-#ifdef E3000_DEBUG
- prom_printf("sregs[%p]\n");
-#endif
if(!sregs) {
prom_printf("iommu_init: Fatal error, sysio regs not mapped\n");
prom_halt();
}
iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
-
-#ifdef E3000_DEBUG
- prom_printf("iommu_init: iommu[%p] ", iommu);
-#endif
+ if (!iommu) {
+ prom_printf("iommu_init: Fatal error, kmalloc(iommu) failed\n");
+ prom_halt();
+ }
spin_lock_init(&iommu->iommu_lock);
iommu->sysio_regs = sregs;
@@ -224,14 +224,19 @@ __initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus))
control = sregs->iommu_control;
impl = (control & IOMMU_CTRL_IMPL) >> 60;
vers = (control & IOMMU_CTRL_VERS) >> 56;
-#ifdef E3000_DEBUG
- prom_printf("sreg_control[%08x]\n", control);
- prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
- (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
-#endif
printk("IOMMU(SBUS): IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
(unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
+ /* Streaming buffer is unreliable on VERS 0 of SYSIO,
+ * although such parts were never shipped in production
+ * Sun hardware, I check just to be robust. --DaveM
+ */
+ vers = ((sregs->control & SYSIO_CONTROL_VER) >> 56);
+ if (vers == 0)
+ iommu->strbuf_enabled = 0;
+ else
+ iommu->strbuf_enabled = 1;
+
control &= ~(IOMMU_CTRL_TSBSZ);
control |= ((IOMMU_TSBSZ_2K * dvmaiosz) | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
@@ -281,9 +286,14 @@ __initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus))
/* Setup aliased mappings... */
for(i = 0; i < (dvmaiobase >> 16); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF |
- IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= (i << 16);
+ unsigned long val = ((((unsigned long)i) << 16UL) + phys_base);
+
+ val |= IOPTE_VALID | IOPTE_64K | IOPTE_WRITE;
+ if (iommu->strbuf_enabled)
+ val |= IOPTE_STBUF;
+ else
+ val |= IOPTE_CACHE;
+ *iopte = val;
iopte++;
}
@@ -291,38 +301,34 @@ __initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus))
for( ; i < ((dvmaiobase + DVMAIO_SIZE) >> 16); i++)
*iopte++ = 0;
-#ifdef E3000_DEBUG
- prom_printf("IOMMU: pte's mapped, enabling IOMMU... ");
-#endif
sregs->iommu_tsbbase = __pa(tsbbase);
sregs->iommu_control = control;
-#ifdef E3000_DEBUG
- prom_printf("done\n");
-#endif
/* Get the streaming buffer going. */
control = sregs->sbuf_control;
impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60;
vers = (control & SYSIO_SBUFCTRL_REV) >> 56;
-#ifdef E3000_DEBUG
- prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ",
- control);
-#endif
- printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ",
+ printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ... ",
(unsigned int)impl, (unsigned int)vers);
- iommu->sbuf_flushflag_va = kmalloc(sizeof(unsigned long), GFP_DMA);
- printk("FlushFLAG[%016lx] ... ", (iommu->sbuf_flushflag_pa = __pa(iommu->sbuf_flushflag_va)));
- *(iommu->sbuf_flushflag_va) = 0;
-
- sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
+ iommu->flushflag = 0;
-#ifdef E3000_DEBUG
- prom_printf("done, returning\n");
-#endif
- printk("ENABLED\n");
+ if (iommu->strbuf_enabled != 0) {
+ sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
+ printk("ENABLED\n");
+ } else {
+ sregs->sbuf_control = (control & ~(SYSIO_SBUFCTRL_SB_EN));
+ printk("DISABLED\n");
+ }
/* Finally enable DVMA arbitration for all devices, just in case. */
sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
+
+ /* If necessary, hook us up for starfire IRQ translations. */
+ sbus->upaid = prom_getintdefault(sbus->prom_node, "upa-portid", -1);
+ if(this_is_starfire)
+ sbus->starfire_cookie = starfire_hookup(sbus->upaid);
+ else
+ sbus->starfire_cookie = NULL;
}
void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
@@ -397,19 +403,35 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
__u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus)
{
- __u32 sbus_addr = (__u32) __pa(vaddr);
-
-#ifndef DEBUG_IOMMU
- return sbus_addr;
-#else
- if((sbus_addr < dvmaiobase) &&
- ((sbus_addr + len) < dvmaiobase))
- return sbus_addr;
-
- /* "can't happen"... GFP_DMA assures this. */
- panic("Very high scsi_one mappings should never happen.");
- return (__u32)0;
-#endif
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long start = (unsigned long) vaddr;
+ unsigned long end = PAGE_ALIGN(start + len);
+ unsigned long flags, tmp;
+ volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
+
+ start &= PAGE_MASK;
+ if (end > MAX_DMA_ADDRESS) {
+ printk("mmu_get_scsi_one: Bogus DMA buffer address [%016lx:%d]\n",
+ (unsigned long) vaddr, (int)len);
+ panic("DMA address too large, tell DaveM");
+ }
+
+ if (iommu->strbuf_enabled) {
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+ iommu->flushflag = 0;
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sregs->sbuf_fsync = __pa(&(iommu->flushflag));
+ tmp = *sbctrl;
+ while(iommu->flushflag == 0)
+ membar("#LoadLoad");
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+ }
+
+ return sbus_dvma_addr(vaddr);
}
void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
@@ -418,43 +440,89 @@ void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
struct sysio_regs *sregs = iommu->sysio_regs;
unsigned long start = (unsigned long) vaddr;
unsigned long end = PAGE_ALIGN(start + len);
- unsigned long flags;
- unsigned int *sync_word;
+ unsigned long flags, tmp;
+ volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
start &= PAGE_MASK;
- spin_lock_irqsave(&iommu->iommu_lock, flags);
+ if (iommu->strbuf_enabled) {
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ /* 1) Clear the flush flag word */
+ iommu->flushflag = 0;
- while(start < end) {
- sregs->sbuf_pflush = start;
- start += PAGE_SIZE;
+ /* 2) Tell the streaming buffer which entries
+ * we want flushed.
+ */
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+
+ /* 3) Initiate flush sequence. */
+ sregs->sbuf_fsync = __pa(&(iommu->flushflag));
+
+ /* 4) Guarentee completion of all previous writes
+ * by reading SYSIO's SBUS control register.
+ */
+ tmp = *sbctrl;
+
+ /* 5) Wait for flush flag to get set. */
+ while(iommu->flushflag == 0)
+ membar("#LoadLoad");
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
}
- sync_word = iommu->sbuf_flushflag_va;
- sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
- membar("#StoreLoad | #MemIssue");
- while((*sync_word & 0x1) == 0)
- membar("#LoadLoad");
- *sync_word = 0;
-
- spin_unlock_irqrestore(&iommu->iommu_lock, flags);
}
void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
{
- while(sz >= 0) {
- __u32 page = (__u32) __pa(((unsigned long) sg[sz].addr));
-#ifndef DEBUG_IOMMU
- sg[sz].dvma_addr = page;
-#else
- if((page < dvmaiobase) &&
- (page + sg[sz].len) < dvmaiobase) {
- sg[sz].dvma_addr = page;
- } else {
- /* "can't happen"... GFP_DMA assures this. */
- panic("scsi_sgl high mappings should never happen.");
+ struct iommu_struct *iommu = sbus->iommu;
+ struct sysio_regs *sregs = iommu->sysio_regs;
+ unsigned long flags, tmp;
+ volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
+
+ if (iommu->strbuf_enabled) {
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+ iommu->flushflag = 0;
+
+ while(sz >= 0) {
+ unsigned long start = (unsigned long)sg[sz].addr;
+ unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+
+ if (end > MAX_DMA_ADDRESS) {
+ printk("mmu_get_scsi_sgl: Bogus DMA buffer address "
+ "[%016lx:%d]\n", start, (int) sg[sz].len);
+ panic("DMA address too large, tell DaveM");
+ }
+
+ sg[sz--].dvma_addr = sbus_dvma_addr(start);
+ start &= PAGE_MASK;
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ }
+
+ sregs->sbuf_fsync = __pa(&(iommu->flushflag));
+ tmp = *sbctrl;
+ while(iommu->flushflag == 0)
+ membar("#LoadLoad");
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+ } else {
+ /* Just verify the addresses and fill in the
+ * dvma_addr fields in this case.
+ */
+ while(sz >= 0) {
+ unsigned long start = (unsigned long)sg[sz].addr;
+ unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+ if (end > MAX_DMA_ADDRESS) {
+ printk("mmu_get_scsi_sgl: Bogus DMA buffer address "
+ "[%016lx:%d]\n", start, (int) sg[sz].len);
+ panic("DMA address too large, tell DaveM");
+ }
+ sg[sz--].dvma_addr = sbus_dvma_addr(start);
}
-#endif
- sz--;
}
}
@@ -462,30 +530,98 @@ void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus
{
struct iommu_struct *iommu = sbus->iommu;
struct sysio_regs *sregs = iommu->sysio_regs;
- unsigned long flags;
- unsigned int *sync_word;
+ volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
+ unsigned long flags, tmp;
+
+ if (iommu->strbuf_enabled) {
+ spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+ /* 1) Clear the flush flag word */
+ iommu->flushflag = 0;
+
+ /* 2) Tell the streaming buffer which entries
+ * we want flushed.
+ */
+ while(sz >= 0) {
+ unsigned long start = sg[sz].dvma_addr;
+ unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+
+ start &= PAGE_MASK;
+ while(start < end) {
+ sregs->sbuf_pflush = start;
+ start += PAGE_SIZE;
+ }
+ sz--;
+ }
- spin_lock_irqsave(&iommu->iommu_lock, flags);
+ /* 3) Initiate flush sequence. */
+ sregs->sbuf_fsync = __pa(&(iommu->flushflag));
- while(sz >= 0) {
- unsigned long start = sg[sz].dvma_addr;
- unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+ /* 4) Guarentee completion of previous writes
+ * by reading SYSIO's SBUS control register.
+ */
+ tmp = *sbctrl;
- start &= PAGE_MASK;
- while(start < end) {
- sregs->sbuf_pflush = start;
- start += PAGE_SIZE;
- }
- sz--;
+ /* 5) Wait for flush flag to get set. */
+ while(iommu->flushflag == 0)
+ membar("#LoadLoad");
+
+ spin_unlock_irqrestore(&iommu->iommu_lock, flags);
}
- sync_word = iommu->sbuf_flushflag_va;
- sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
- membar("#StoreLoad | #MemIssue");
- while((*sync_word & 0x1) == 0)
- membar("#LoadLoad");
- *sync_word = 0;
-
- spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
+void mmu_set_sbus64(struct linux_sbus_device *sdev, int bursts)
+{
+ struct linux_sbus *sbus = sdev->my_bus;
+ struct sysio_regs *sregs = sbus->iommu->sysio_regs;
+ int slot = sdev->slot;
+ u64 *cfg, tmp;
+
+ switch(slot) {
+ case 0:
+ cfg = &sregs->sbus_s0cfg;
+ break;
+ case 1:
+ cfg = &sregs->sbus_s1cfg;
+ break;
+ case 2:
+ cfg = &sregs->sbus_s2cfg;
+ break;
+ case 3:
+ cfg = &sregs->sbus_s3cfg;
+ break;
+
+ case 13:
+ cfg = &sregs->sbus_s4cfg;
+ break;
+ case 14:
+ cfg = &sregs->sbus_s5cfg;
+ break;
+ case 15:
+ cfg = &sregs->sbus_s6cfg;
+ break;
+
+ default:
+ return;
+ };
+
+ /* ETM already enabled? If so, we're done. */
+ tmp = *cfg;
+ if ((tmp & SYSIO_SBSCFG_ETM) != 0)
+ return;
+
+ /* Set burst bits. */
+ if (bursts & DMA_BURST8)
+ tmp |= SYSIO_SBSCFG_BA8;
+ if (bursts & DMA_BURST16)
+ tmp |= SYSIO_SBSCFG_BA16;
+ if (bursts & DMA_BURST32)
+ tmp |= SYSIO_SBSCFG_BA32;
+ if (bursts & DMA_BURST64)
+ tmp |= SYSIO_SBSCFG_BA64;
+
+ /* Finally turn on ETM and set register. */
+ *cfg = (tmp | SYSIO_SBSCFG_ETM);
}
int mmu_info(char *buf)
@@ -562,16 +698,9 @@ static inline void inherit_prom_mappings(void)
*/
static void __flush_nucleus_vptes(void)
{
- unsigned long pstate;
unsigned long prom_reserved_base = 0xfffffffc00000000UL;
int i;
- __asm__ __volatile__("flushw\n\t"
- "rdpr %%pstate, %0\n\t"
- "wrpr %0, %1, %%pstate"
- : "=r" (pstate)
- : "i" (PSTATE_IE));
-
/* Only DTLB must be checked for VPTE entries. */
for(i = 0; i < 63; i++) {
unsigned long tag = spitfire_get_dtlb_tag(i);
@@ -586,8 +715,6 @@ static void __flush_nucleus_vptes(void)
membar("#Sync");
}
}
- __asm__ __volatile__("wrpr %0, 0, %%pstate"
- : : "r" (pstate));
}
static int prom_ditlb_set = 0;
@@ -600,10 +727,19 @@ struct prom_tlb_entry prom_itlb[8], prom_dtlb[8];
void prom_world(int enter)
{
+ unsigned long pstate;
int i;
if (!prom_ditlb_set)
return;
+
+ /* Make sure the following runs atomically. */
+ __asm__ __volatile__("flushw\n\t"
+ "rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate"
+ : "=r" (pstate)
+ : "i" (PSTATE_IE));
+
if (enter) {
/* Kick out nucleus VPTEs. */
__flush_nucleus_vptes();
@@ -648,6 +784,8 @@ void prom_world(int enter)
}
}
}
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (pstate));
}
void inherit_locked_prom_mappings(int save_p)
@@ -680,7 +818,7 @@ void inherit_locked_prom_mappings(int save_p)
unsigned long data;
data = spitfire_get_dtlb_data(i);
- if(data & _PAGE_L) {
+ if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
unsigned long tag = spitfire_get_dtlb_tag(i);
if(save_p) {
@@ -703,7 +841,7 @@ void inherit_locked_prom_mappings(int save_p)
unsigned long data;
data = spitfire_get_itlb_data(i);
- if(data & _PAGE_L) {
+ if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
unsigned long tag = spitfire_get_itlb_tag(i);
if(save_p) {
@@ -811,8 +949,7 @@ void __flush_tlb_all(void)
#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6))
unsigned long mmu_context_bmap[CTX_BMAP_SLOTS];
-/* We are always protected by scheduler_lock under SMP.
- * Caller does TLB context flushing on local CPU if necessary.
+/* Caller does TLB context flushing on local CPU if necessary.
*
* We must be careful about boundary cases so that we never
* let the user have CTX 0 (nucleus) or we ever use a CTX
@@ -867,15 +1004,11 @@ out:
struct pgtable_cache_struct pgt_quicklists;
#endif
-/* XXX Add __GFP_HIGH to these calls to "fool" page allocator
- * XXX so we don't go to swap so quickly... then do the same
- * XXX for get_user_page as well -DaveM
- */
pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
{
pmd_t *pmd;
- pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
+ pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
if(pmd) {
memset(pmd, 0, PAGE_SIZE);
pgd_set(pgd, pmd);
@@ -888,7 +1021,7 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
{
pte_t *pte;
- pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL);
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
if(pte) {
memset(pte, 0, PAGE_SIZE);
pmd_set(pmd, pte);
@@ -993,15 +1126,16 @@ void sparc_ultra_dump_dtlb(void)
/* paging_init() sets up the page tables */
extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long sun_serial_setup(unsigned long);
__initfunc(unsigned long
paging_init(unsigned long start_mem, unsigned long end_mem))
{
- extern void setup_tba(void);
extern pmd_t swapper_pmd_dir[1024];
- extern unsigned long irq_init(unsigned long start_mem, unsigned long end_mem);
- extern unsigned int sparc64_vpte_patchme[1];
+ extern unsigned int sparc64_vpte_patchme1[1];
+ extern unsigned int sparc64_vpte_patchme2[1];
unsigned long alias_base = phys_base + PAGE_OFFSET;
+ unsigned long second_alias_page = 0;
unsigned long pt;
unsigned long flags;
unsigned long shift = alias_base - ((unsigned long)&empty_zero_page);
@@ -1026,6 +1160,21 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
: "memory");
+ if (start_mem >= KERNBASE + 0x340000) {
+ second_alias_page = alias_base + 0x400000;
+ __asm__ __volatile__("
+ stxa %1, [%0] %3
+ stxa %2, [%5] %4
+ membar #Sync
+ flush %%g6
+ nop
+ nop
+ nop"
+ : /* No outputs */
+ : "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000),
+ "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3)
+ : "memory");
+ }
__restore_flags(flags);
/* Now set kernel pgd to upper alias so physical page computations
@@ -1038,22 +1187,40 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
/* Now can init the kernel/bad page tables. */
pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t)));
- sparc64_vpte_patchme[0] |= (init_mm.pgd[0] >> 10);
+ sparc64_vpte_patchme1[0] |= (init_mm.pgd[0] >> 10);
+ sparc64_vpte_patchme2[0] |= (init_mm.pgd[0] & 0x3ff);
+ flushi((long)&sparc64_vpte_patchme1[0]);
- start_mem = irq_init(start_mem, end_mem);
-
/* We use mempool to create page tables, therefore adjust it up
* such that __pa() macros etc. work.
*/
mempool = PAGE_ALIGN(start_mem) + shift;
+
+#ifdef CONFIG_SUN_SERIAL
+ /* This does not logically belong here, but is the first place
+ we can initialize it at, so that we work in the PAGE_OFFSET+
+ address space. */
+ mempool = sun_serial_setup(mempool);
+#endif
/* Allocate 64M for dynamic DVMA mapping area. */
allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000);
inherit_prom_mappings();
-
- /* Ok, we can use our TLB miss and window trap handlers safely. */
- setup_tba();
+ /* Ok, we can use our TLB miss and window trap handlers safely.
+ * We need to do a quick peek here to see if we are on StarFire
+ * or not, so setup_tba can setup the IRQ globals correctly (it
+ * needs to get the hard smp processor id correctly).
+ */
+ {
+ extern void setup_tba(int);
+ int is_starfire = prom_finddevice("/ssp-serial");
+ if(is_starfire != 0 && is_starfire != -1)
+ is_starfire = 1;
+ else
+ is_starfire = 0;
+ setup_tba(is_starfire);
+ }
/* Really paranoid. */
flushi((long)&empty_zero_page);
@@ -1064,6 +1231,8 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
*/
/* We only created DTLB mapping of this stuff. */
spitfire_flush_dtlb_nucleus_page(alias_base);
+ if (second_alias_page)
+ spitfire_flush_dtlb_nucleus_page(second_alias_page);
membar("#Sync");
/* Paranoid */
@@ -1079,10 +1248,6 @@ paging_init(unsigned long start_mem, unsigned long end_mem))
return device_scan (PAGE_ALIGN (start_mem));
}
-/* XXX Add also PG_Hole flag, set it in the page structs here,
- * XXX remove FREE_UNUSED_MEM_MAP code, and the nfsd file handle
- * problems will all be gone. -DaveM
- */
__initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
{
unsigned long tmp = 0, paddr, endaddr;
@@ -1096,14 +1261,24 @@ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long e
if (!sp_banks[tmp].num_bytes) {
mem_map[paddr>>PAGE_SHIFT].flags |= (1<<PG_skip);
mem_map[paddr>>PAGE_SHIFT].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
+ mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<<PG_skip);
+ mem_map[(paddr>>PAGE_SHIFT)+1UL].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
return;
}
if (sp_banks[tmp].base_addr > paddr) {
- /* Making a one or two pages PG_skip holes is not necessary */
- if (sp_banks[tmp].base_addr - paddr > 2 * PAGE_SIZE) {
+ /* Making a one or two pages PG_skip holes
+ * is not necessary. We add one more because
+ * we must set the PG_skip flag on the first
+ * two mem_map[] entries for the hole. Go and
+ * see the mm/filemap.c:shrink_mmap() loop for
+ * details. -DaveM
+ */
+ if (sp_banks[tmp].base_addr - paddr > 3 * PAGE_SIZE) {
mem_map[paddr>>PAGE_SHIFT].flags |= (1<<PG_skip);
mem_map[paddr>>PAGE_SHIFT].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT);
+ mem_map[(paddr>>PAGE_SHIFT)+1UL].flags |= (1<<PG_skip);
+ mem_map[(paddr>>PAGE_SHIFT)+1UL].next_hash = mem_map + (sp_banks[tmp].base_addr >> PAGE_SHIFT);
}
paddr = sp_banks[tmp].base_addr;
}
@@ -1111,7 +1286,8 @@ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long e
endaddr = sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes;
while (paddr < endaddr) {
mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_reserved);
- if (paddr >= dvmaiobase)
+ set_bit(paddr >> 22, sparc64_valid_addr_bitmap);
+ if (paddr >= (MAX_DMA_ADDRESS - PAGE_OFFSET))
mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_DMA);
paddr += PAGE_SIZE;
}
@@ -1131,6 +1307,12 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
end_mem &= PAGE_MASK;
max_mapnr = MAP_NR(end_mem);
high_memory = (void *) end_mem;
+
+ sparc64_valid_addr_bitmap = (unsigned long *)start_mem;
+ i = max_mapnr >> ((22 - PAGE_SHIFT) + 6);
+ i += 1;
+ memset(sparc64_valid_addr_bitmap, 0, i << 3);
+ start_mem += i << 3;
start_mem = PAGE_ALIGN(start_mem);
num_physpages = 0;
@@ -1138,6 +1320,8 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
if (phys_base) {
mem_map[0].flags |= (1<<PG_skip) | (1<<PG_reserved);
mem_map[0].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
+ mem_map[1].flags |= (1<<PG_skip) | (1<<PG_reserved);
+ mem_map[1].next_hash = mem_map + (phys_base >> PAGE_SHIFT);
}
addr = PAGE_OFFSET + phys_base;
@@ -1148,6 +1332,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
else
#endif
mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
+ set_bit(__pa(addr) >> 22, sparc64_valid_addr_bitmap);
addr += PAGE_SIZE;
}
@@ -1159,6 +1344,9 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
if (PageSkip(page)) {
unsigned long low, high;
+ /* See taint_real_pages() for why this is done. -DaveM */
+ page++;
+
low = PAGE_ALIGN((unsigned long)(page+1));
if (page->next_hash < page)
high = ((unsigned long)end) & PAGE_MASK;
@@ -1255,7 +1443,7 @@ void si_meminfo(struct sysinfo *val)
val->totalram = 0;
val->sharedram = 0;
- val->freeram = nr_free_pages << PAGE_SHIFT;
+ val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT;
val->bufferram = buffermem;
for (page = mem_map, end = mem_map + max_mapnr;
page < end; page++) {
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 4362a15b4..3d3d1a289 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.31 1998/11/07 06:39:21 davem Exp $
+/* $Id: ultra.S,v 1.32 1999/03/28 08:39:34 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -261,6 +261,21 @@ xcall_capture:
b,pt %xcc, rtrap
clr %l6
+ .globl xcall_receive_signal
+xcall_receive_signal:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ rdpr %tstate, %g1
+ andcc %g1, TSTATE_PRIV, %g0
+ /* If we did not trap from user space, just ignore. */
+ bne,pn %xcc, 99f
+ sethi %hi(109f), %g7
+ b,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ b,pt %xcc, rtrap
+ clr %l6
+99: retry
+
/* These two are not performance critical... */
.globl xcall_flush_tlb_all
xcall_flush_tlb_all:
diff --git a/arch/sparc64/prom/memory.c b/arch/sparc64/prom/memory.c
index bb3e50a92..3523c3b1d 100644
--- a/arch/sparc64/prom/memory.c
+++ b/arch/sparc64/prom/memory.c
@@ -1,4 +1,4 @@
-/* $Id: memory.c,v 1.3 1997/03/04 16:27:10 jj Exp $
+/* $Id: memory.c,v 1.4 1998/11/25 10:04:06 jj Exp $
* memory.c: Prom routine for acquiring various bits of information
* about RAM on the machine, both virtual and physical.
*
@@ -41,8 +41,8 @@ __initfunc(static void
prom_sortmemlist(struct linux_mlist_p1275 *thislist))
{
int swapi = 0;
- int i, mitr, tmpsize;
- unsigned long tmpaddr;
+ int i, mitr;
+ unsigned long tmpaddr, tmpsize;
unsigned long lowest;
for(i=0; thislist[i].theres_more != 0; i++) {
@@ -79,7 +79,7 @@ __initfunc(void prom_meminit(void))
prom_phys_avail[iter].start_adr =
prom_reg_memlist[iter].phys_addr;
prom_phys_avail[iter].num_bytes =
- (unsigned long) prom_reg_memlist[iter].reg_size;
+ prom_reg_memlist[iter].reg_size;
prom_phys_avail[iter].theres_more =
&prom_phys_avail[iter+1];
}
@@ -93,7 +93,7 @@ __initfunc(void prom_meminit(void))
prom_phys_total[iter].start_adr =
prom_reg_memlist[iter].phys_addr;
prom_phys_total[iter].num_bytes =
- (unsigned long) prom_reg_memlist[iter].reg_size;
+ prom_reg_memlist[iter].reg_size;
prom_phys_total[iter].theres_more =
&prom_phys_total[iter+1];
}
@@ -112,7 +112,7 @@ __initfunc(void prom_meminit(void))
prom_prom_taken[iter].start_adr =
prom_reg_memlist[iter].phys_addr;
prom_prom_taken[iter].num_bytes =
- (unsigned long) prom_reg_memlist[iter].reg_size;
+ prom_reg_memlist[iter].reg_size;
prom_prom_taken[iter].theres_more =
&prom_phys_total[iter+1];
}
@@ -130,7 +130,7 @@ __initfunc(void prom_meminit(void))
prom_prom_taken[iter].start_adr;
}
prom_prom_taken[iter-1].num_bytes =
- ((unsigned long)-1) - (unsigned long) prom_prom_taken[iter-1].start_adr;
+ -1UL - prom_prom_taken[iter-1].start_adr;
/* Sort the other two lists. */
prom_sortmemlist(prom_phys_total);
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 340c27223..83af773df 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.13 1998/10/13 14:03:49 davem Exp $
+/* $Id: misc.c,v 1.14 1998/12/18 10:01:59 davem Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
@@ -122,9 +122,123 @@ void prom_set_trap_table(unsigned long tba)
p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
}
+/* This is only used internally below. */
+static int prom_get_mmu_ihandle(void)
+{
+ int node;
+ int ret;
+
+ node = prom_finddevice("/chosen");
+ ret = prom_getint(node, "mmu");
+ if(ret == -1 || ret == 0) {
+ prom_printf("PROMLIB: Fatal error, cannot get mmu ihandle.\n");
+ prom_halt();
+ }
+ return ret;
+}
+
+/* Load explicit I/D TLB entries. */
+long prom_itlb_load(unsigned long index,
+ unsigned long tte_data,
+ unsigned long vaddr)
+{
+ return p1275_cmd("call-method",
+ (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+ "SUNW,itlb-load",
+ prom_get_mmu_ihandle(),
+ /* And then our actual args are pushed backwards. */
+ vaddr,
+ tte_data,
+ index);
+}
+
+long prom_dtlb_load(unsigned long index,
+ unsigned long tte_data,
+ unsigned long vaddr)
+{
+ return p1275_cmd("call-method",
+ (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 1)),
+ "SUNW,dtlb-load",
+ prom_get_mmu_ihandle(),
+ /* And then our actual args are pushed backwards. */
+ vaddr,
+ tte_data,
+ index);
+}
+
+/* Set aside physical memory which is not touched or modified
+ * across soft resets.
+ */
+unsigned long prom_retain(char *name,
+ unsigned long pa_low, unsigned long pa_high,
+ long size, long align)
+{
+ /* XXX I don't think we return multiple values correctly.
+ * XXX OBP supposedly returns pa_low/pa_high here, how does
+ * XXX it work?
+ */
+
+ /* If align is zero, the pa_low/pa_high args are passed,
+ * else they are not.
+ */
+ if(align == 0)
+ return p1275_cmd("SUNW,retain",
+ (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
+ name, pa_low, pa_high, size, align);
+ else
+ return p1275_cmd("SUNW,retain",
+ (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
+ name, size, align);
+}
+
+/* Get "Unumber" string for the SIMM at the given
+ * memory address. Usually this will be of the form
+ * "Uxxxx" where xxxx is a decimal number which is
+ * etched into the motherboard next to the SIMM slot
+ * in question.
+ */
+int prom_getunumber(unsigned long phys_lo, unsigned long phys_hi,
+ char *buf, int buflen)
+{
+ return p1275_cmd("SUNW,get-unumber",
+ (P1275_ARG(2, P1275_ARG_OUT_BUF) | P1275_INOUT(4, 1)),
+ phys_lo, phys_hi, buf, buflen);
+}
+
+/* Power management extensions. */
+void prom_sleepself(void)
+{
+ p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
+}
+
+int prom_sleepsystem(void)
+{
+ return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
+}
+
+int prom_wakeupsystem(void)
+{
+ return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
+}
+
#ifdef __SMP__
void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
{
p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
}
+
+void prom_stopself(void)
+{
+ p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
+}
+
+void prom_idleself(void)
+{
+ p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
+}
+
+void prom_resumecpu(int cpunode)
+{
+ p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
+}
#endif
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 3631d43b2..f0921ab9f 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.11 1998/10/28 08:12:04 jj Exp $
+/* $Id: fs.c,v 1.12 1999/01/02 16:46:06 davem Exp $
* fs.c: fs related syscall emulation for Solaris
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/smp_lock.h>
@@ -21,7 +22,6 @@
#include "conv.h"
extern char * getname32(u32 filename);
-#define putname32 putname
#define R4_DEV(DEV) ((DEV & 0xff) | ((DEV & 0xff00) << 10))
#define R4_MAJOR(DEV) (((DEV) >> 18) & 0x3fff)
@@ -138,7 +138,7 @@ asmlinkage int solaris_stat(u32 filename, u32 statbuf)
set_fs (KERNEL_DS);
ret = sys_newstat(filenam, &s);
set_fs (old_fs);
- putname32 (filenam);
+ putname (filenam);
if (putstat ((struct sol_stat *)A(statbuf), &s))
return -EFAULT;
}
@@ -166,7 +166,7 @@ asmlinkage int solaris_stat64(u32 filename, u32 statbuf)
set_fs (KERNEL_DS);
ret = sys_newstat(filenam, &s);
set_fs (old_fs);
- putname32 (filenam);
+ putname (filenam);
if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
return -EFAULT;
}
@@ -188,7 +188,7 @@ asmlinkage int solaris_lstat(u32 filename, u32 statbuf)
set_fs (KERNEL_DS);
ret = sys_newlstat(filenam, &s);
set_fs (old_fs);
- putname32 (filenam);
+ putname (filenam);
if (putstat ((struct sol_stat *)A(statbuf), &s))
return -EFAULT;
}
@@ -215,7 +215,7 @@ asmlinkage int solaris_lstat64(u32 filename, u32 statbuf)
set_fs (KERNEL_DS);
ret = sys_newlstat(filenam, &s);
set_fs (old_fs);
- putname32 (filenam);
+ putname (filenam);
if (putstat64 ((struct sol_stat64 *)A(statbuf), &s))
return -EFAULT;
}
diff --git a/arch/sparc64/solaris/systbl.S b/arch/sparc64/solaris/systbl.S
index f47470e4c..7c7c7b8b1 100644
--- a/arch/sparc64/solaris/systbl.S
+++ b/arch/sparc64/solaris/systbl.S
@@ -1,4 +1,4 @@
-/* $Id: systbl.S,v 1.7 1998/10/28 08:11:49 jj Exp $
+/* $Id: systbl.S,v 1.8 1999/02/11 18:34:02 davem Exp $
* systbl.S: System call entry point table for Solaris compatibility.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -72,7 +72,7 @@ solaris_sys_table:
.word CHAIN(dup) /* dup d 41 */
.word CHAIN(pipe) /* pipe 42 */
.word CHAIN(times) /* times p 43 */
- .word CHAIN(profil) /* prof xxxx 44 */
+ .word 44 /*CHAIN(profil)*/ /* prof xxxx 44 */
.word solaris_unimplemented /* lock/plock 45 */
.word CHAIN(setgid) /* setgid d 46 */
.word solaris_getgid /* getgid 47 */