summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
commitdcec8a13bf565e47942a1751a9cec21bec5648fe (patch)
tree548b69625b18cc2e88c3e68d0923be546c9ebb03 /arch/sparc64/kernel
parent2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff)
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash. o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile58
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c10
-rw-r--r--arch/sparc64/kernel/central.c31
-rw-r--r--arch/sparc64/kernel/cpu.c6
-rw-r--r--arch/sparc64/kernel/devices.c5
-rw-r--r--arch/sparc64/kernel/dtlb_miss.S50
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S24
-rw-r--r--arch/sparc64/kernel/ebus.c99
-rw-r--r--arch/sparc64/kernel/head.S19
-rw-r--r--arch/sparc64/kernel/init_task.c2
-rw-r--r--arch/sparc64/kernel/ioctl32.c166
-rw-r--r--arch/sparc64/kernel/irq.c392
-rw-r--r--arch/sparc64/kernel/itlb_miss.S36
-rw-r--r--arch/sparc64/kernel/process.c31
-rw-r--r--arch/sparc64/kernel/psycho.c1166
-rw-r--r--arch/sparc64/kernel/setup.c45
-rw-r--r--arch/sparc64/kernel/signal32.c3
-rw-r--r--arch/sparc64/kernel/smp.c196
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c17
-rw-r--r--arch/sparc64/kernel/sunos_ioctl32.c10
-rw-r--r--arch/sparc64/kernel/sys32.S13
-rw-r--r--arch/sparc64/kernel/sys_sparc.c49
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c185
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c130
-rw-r--r--arch/sparc64/kernel/systbls.S18
-rw-r--r--arch/sparc64/kernel/time.c133
-rw-r--r--arch/sparc64/kernel/trampoline.S8
-rw-r--r--arch/sparc64/kernel/traps.c103
-rw-r--r--arch/sparc64/kernel/ttable.S6
29 files changed, 2080 insertions, 931 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 7889c84a4..1c3f459bc 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.35 1997/09/20 21:48:58 davem Exp $
+# $Id: Makefile,v 1.36 1998/02/01 11:15:55 ecd Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -61,13 +61,24 @@ head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
check_asm: dummy
+ @echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
+ @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
+ @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
+ @echo "#ifndef __SMP__" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
@echo "#include <linux/sched.h>" > tmp.c
$(CC) -E tmp.c -o tmp.i
- @echo "/* Automatically generated. Do not edit. */" > check_asm.c; echo "#include <linux/sched.h>" >> check_asm.c; echo 'struct task_struct _task; struct mm_struct _mm; struct thread_struct _thread; int main(void) { printf ("/* Automatically generated. Do not edit. */\n#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n\n");' >> check_asm.c
+ @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/sched.h>" >> check_asm.c
+ @echo 'struct task_struct _task;' >> check_asm.c
+ @echo 'struct mm_struct _mm;' >> check_asm.c
+ @echo 'struct thread_struct _thread;' >> check_asm.c
+ @echo 'int main(void) {' >> check_asm.c
$(SH) ./check_asm.sh task tmp.i check_asm.c
$(SH) ./check_asm.sh mm tmp.i check_asm.c
$(SH) ./check_asm.sh thread tmp.i check_asm.c
- @echo 'printf ("\n#endif /* __ASM_OFFSETS_H__ */\n"); return 0; }' >> check_asm.c
+ @echo 'return 0; }' >> check_asm.c
@rm -f tmp.[ci]
#$(CC) -o check_asm check_asm.c
# <hack> Until we can do this natively, a hack has to take place
@@ -75,9 +86,46 @@ check_asm: dummy
$(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
@rm -f check_asm.s
# </hack>
- ./check_asm > asm_offsets.h
- @if test -r $(HPATH)/asm/asm_offsets.h; then if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then echo $(HPATH)/asm/asm_offsets.h is unchanged; rm -f asm_offsets.h; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi; else mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; fi
+ ./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
+ @echo "" >> asm_offsets.h
+ @echo "#else /* __SMP__ */" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
+ @echo "#include <linux/sched.h>" > tmp.c
+ $(CC) -D__SMP__ -E tmp.c -o tmp.i
+ @echo "/* Automatically generated. Do not edit. */" > check_asm.c
+ @echo "#include <linux/sched.h>" >> check_asm.c
+ @echo 'struct task_struct _task;' >> check_asm.c
+ @echo 'struct mm_struct _mm;' >> check_asm.c
+ @echo 'struct thread_struct _thread;' >> check_asm.c
+ @echo 'int main(void) {' >> check_asm.c
+ $(SH) ./check_asm.sh task tmp.i check_asm.c
+ $(SH) ./check_asm.sh mm tmp.i check_asm.c
+ $(SH) ./check_asm.sh thread tmp.i check_asm.c
+ @echo 'return 0; }' >> check_asm.c
+ @rm -f tmp.[ci]
+ #$(CC) -D__SMP__ -o check_asm check_asm.c
+ # <hack> Until we can do this natively, a hack has to take place
+ $(CC) -D__SMP__ -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c
+ $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
+ @rm -f check_asm.s
+ # </hack>
+ ./check_asm >> asm_offsets.h
+ @rm -f check_asm check_asm.c
+ @echo "" >> asm_offsets.h
+ @echo "#endif /* __SMP__ */" >> asm_offsets.h
+ @echo "" >> asm_offsets.h
+ @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
+ @if test -r $(HPATH)/asm/asm_offsets.h; then \
+ if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
+ echo $(HPATH)/asm/asm_offsets.h is unchanged; \
+ rm -f asm_offsets.h; \
+ else \
+ mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
+ fi; \
+ else \
+ mv -f asm_offsets.h $(HPATH)/asm/asm_offsets.h; \
+ fi
include $(TOPDIR)/Rules.make
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index 55ccbc203..b0dd675b0 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -20,6 +20,7 @@
#include <linux/string.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>
@@ -257,7 +258,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
unsigned long p = bprm->p;
unsigned long fd_offset;
unsigned long rlim;
-int retval;
+ int retval;
ex = *((struct exec *) bprm->buf); /* exec-header */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
@@ -326,10 +327,10 @@ int retval;
printk(KERN_NOTICE "executable not page aligned\n");
fd = open_dentry(bprm->dentry, O_RDONLY);
-
if (fd < 0)
return fd;
- file = current->files->fd[fd];
+ file = fcheck(fd);
+
if (!file->f_op || !file->f_op->mmap) {
sys_close(fd);
do_mmap(NULL, 0, ex.a_text+ex.a_data,
@@ -397,6 +398,7 @@ load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
return retval;
}
+/* N.B. Move to .h file and use code in fs/binfmt_aout.c? */
static inline int
do_load_aout32_library(int fd)
{
@@ -409,7 +411,7 @@ do_load_aout32_library(int fd)
unsigned int start_addr;
unsigned long error;
- file = current->files->fd[fd];
+ file = fcheck(fd);
if (!file || !file->f_op)
return -EACCES;
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index 817a8ecd3..a54e89f2d 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -1,4 +1,4 @@
-/* $Id: central.c,v 1.4 1997/08/19 14:17:49 jj Exp $
+/* $Id: central.c,v 1.5 1998/02/12 15:57:59 jj Exp $
* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -35,22 +35,18 @@ unsigned long central_probe(unsigned long memory_start)
printk("no central found.\n");
return memory_start;
}
- prom_printf("CENTRAL: found central PROM node.\n");
printk("found central PROM node.\n");
/* Ok we got one, grab some memory for software state. */
memory_start = long_align(memory_start);
central_bus = (struct linux_central *) (memory_start);
- prom_printf("CENTRAL: central_bus[%p] ", central_bus);
memory_start += sizeof(struct linux_central);
memory_start = long_align(memory_start);
fhc = (struct linux_fhc *)(memory_start);
memory_start += sizeof(struct linux_fhc);
memory_start = long_align(memory_start);
- prom_printf("fhc[%p] ", fhc);
-
/* First init central. */
central_bus->child = fhc;
central_bus->prom_node = cnode;
@@ -58,7 +54,6 @@ unsigned long central_probe(unsigned long memory_start)
prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
strcpy(central_bus->prom_name, namebuf);
- prom_printf("init_central_ranges ");
prom_central_ranges_init(cnode, central_bus);
/* And then central's FHC. */
@@ -73,27 +68,15 @@ unsigned long central_probe(unsigned long memory_start)
prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
strcpy(fhc->prom_name, namebuf);
- prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode);
prom_fhc_ranges_init(fnode, fhc);
- /* Finally, map in FHC register set. (From the prtconf dumps
- * I have seen on Ex000 boxes only the central ranges need to
- * be applied to the fhc internal register set) -DaveM
- */
- err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs));
- if(err == -1) {
+ /* Finally, 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_halt();
}
prom_apply_central_ranges(central_bus, &fpregs[0], 6);
- prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) "
- "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n",
- fpregs[0].which_io, fpregs[0].phys_addr,
- fpregs[1].which_io, fpregs[1].phys_addr,
- fpregs[2].which_io, fpregs[2].phys_addr,
- fpregs[3].which_io, fpregs[3].phys_addr,
- fpregs[4].which_io, fpregs[4].phys_addr,
- fpregs[5].which_io, fpregs[5].phys_addr);
+
fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
__va((((unsigned long)fpregs[0].which_io)<<32) |
(((unsigned long)fpregs[0].phys_addr)));
@@ -112,14 +95,8 @@ unsigned long central_probe(unsigned long memory_start)
fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
__va((((unsigned long)fpregs[5].which_io)<<32) |
(((unsigned long)fpregs[5].phys_addr)));
- prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n",
- fhc->fhc_regs.pregs, fhc->fhc_regs.ireg,
- fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs,
- fhc->fhc_regs.uregs, fhc->fhc_regs.tregs);
- prom_printf("CENTRAL: reading FHC_ID register... ");
err = fhc->fhc_regs.pregs->fhc_id;
- prom_printf("VALUE[%x]\n", err);
printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
((err & FHC_ID_VERS) >> 28),
((err & FHC_ID_PARTID) >> 12),
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index d009f39d8..86efc4bb7 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -32,7 +32,8 @@ struct cpu_fp_info linux_sparc_fpu[] = {
{ 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
{ 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
{ 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
- { 0x17, 0x12, 0, "UltraSparc III integrated FPU"},
+ { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
+ { 0x17, 0x13, 0, "UltraSparc III integrated FPU"},
};
#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -41,7 +42,8 @@ struct cpu_iu_info linux_sparc_chips[] = {
{ 0x17, 0x10, "TI UltraSparc I (SpitFire)"},
{ 0x22, 0x10, "TI UltraSparc II (BlackBird)"},
{ 0x17, 0x11, "TI UltraSparc II (BlackBird)"},
- { 0x17, 0x12, "TI UltraSparc III (Cheetah)"}, /* A guess... */
+ { 0x17, 0x12, "TI UltraSparc IIi"},
+ { 0x17, 0x13, "TI UltraSparc III (Cheetah)"}, /* A guess... */
};
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 24ca3ff10..8d3aca325 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -13,7 +13,8 @@
#include <asm/system.h>
#include <asm/smp.h>
-struct prom_cpuinfo linux_cpus[NR_CPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS] __initdata = { { 0 } };
+unsigned prom_cpu_nodes[NR_CPUS];
int linux_num_cpus = 0;
extern void cpu_probe(void);
@@ -64,6 +65,8 @@ device_scan(unsigned long mem_start))
prom_node_cpu = cpu_nds[0];
linux_num_cpus = cpu_ctr;
+
+ prom_cpu_nodes[0] = prom_node_cpu;
cpu_probe();
return central_probe(mem_start);
diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S
index 4d71d967c..e5606cf33 100644
--- a/arch/sparc64/kernel/dtlb_miss.S
+++ b/arch/sparc64/kernel/dtlb_miss.S
@@ -1,9 +1,9 @@
-/* $Id: dtlb_miss.S,v 1.14 1997/10/14 01:48:28 davem Exp $
+/* $Id: dtlb_miss.S,v 1.15 1998/01/14 17:14:44 jj Exp $
* dtlb_miss.S: Data TLB miss code, this is included directly
* into the trap table.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
/* The basic algorithm is:
@@ -36,22 +36,22 @@
#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#define KERN_LOWBITS_IO ((_PAGE_E | _PAGE_P | _PAGE_W) ^ KERN_LOWBITS)
+#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W)
/* ICACHE line 1 */
/*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET
- /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
- /*0x08*/ srlx %g1, 48, %g5 ! Shift down CONTEXT bits
- /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
- /*0x10*/ sllx %g1, 2, %g4 ! Position PMD offset
- /*0x14*/ brz,pn %g5, 3f ! Context 0 == kernel
- /*0x18*/ and %g4, %g2, %g4 ! Mask PMD offset
+ /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset
+ /*0x08*/ andcc %g1, %g2, %g0 ! Test CONTEXT bits
+ /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset
+ /*0x18*/ and %g1, 0xffe, %g4 ! Mask PMD offset
+ /*0x14*/ be,pn %xcc, 3f ! Context 0 == kernel
+ /*0x10*/ add %g4, %g4, %g4 ! Position PMD offset
/*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
/* ICACHE line 2 */
- /*0x20*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
+ /*0x20*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
/*0x24*/ srlx %g1, 1, %g1 ! PTE offset
-2:/*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
+2:/*0x28*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
/*0x30*/ brgez,pn %g5, sparc64_dtlb_refbit_catch ! Valid set?
/*0x34*/ nop ! delay
@@ -61,22 +61,22 @@
3: /* ICACHE line 3 */
/*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET
/*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables
- /*0x48*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE ^ PAGE_OFFSET
- /*0x4c*/ andcc %g3, 0x400, %g0 ! Slick trick...
- /*0x50*/ sllx %g1, 32, %g1 ! Move high bits up
- /*0x54*/ or %g1, (KERN_LOWBITS), %g1 ! Assume not IO
- /*0x58*/ bne,a,pn %icc, 5f ! Is it an IO page?
- /*0x5c*/ xor %g1, (KERN_LOWBITS_IO), %g1 ! Aha, it is IO...
+ /*0x48*/ or %g2, (KERN_LOWBITS), %g1 ! Construct PTE ^ PAGE_OFFSET
+ /*0x4c*/ andcc %g3, 0x100, %g0 ! Slick trick...
+ /*0x50*/ bne,a,pn %icc, 5f ! Is it an IO page?
+ /*0x54*/ or %g2, (KERN_LOWBITS_IO), %g1 ! Aha, it is IO...
+5:/*0x58*/ xor %g1, %g5, %g1 ! Slick trick II...
+ /*0x5c*/ stxa %g1, [%g0] ASI_DTLB_DATA_IN ! TLB load
/* ICACHE line 4 */
-5:/*0x60*/ xor %g1, %g5, %g1 ! Slick trick II...
- /*0x64*/ stxa %g1, [%g0] ASI_DTLB_DATA_IN ! TLB load
- /*0x68*/ retry ! Trap return
-4:/*0x6c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
- /*0x70*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
- /*0x74*/ ba,pt %xcc, 2b ! Go back up top
- /*0x78*/ srlx %g1, 1, %g1
- /*0x7c*/ nop
+ /*0x60*/ retry ! Trap return
+ /*0x64*/ nop
+ /*0x68*/ nop
+ /*0x6c*/ nop
+4:/*0x70*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
+ /*0x74*/ lduwa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
+ /*0x78*/ ba,pt %xcc, 2b ! Go back up top
+ /*0x7c*/ srlx %g1, 1, %g1
#undef KERN_HIGHBITS
#undef KERN_LOWBITS
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 55e86c887..86cbfdc52 100644
--- a/arch/sparc64/kernel/dtlb_prot.S
+++ b/arch/sparc64/kernel/dtlb_prot.S
@@ -1,9 +1,9 @@
-/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $
+/* $Id: dtlb_prot.S,v 1.15 1998/01/14 17:14:46 jj Exp $
* dtlb_prot.S: Data TLB protection code, this is included directly
* into the trap table.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
/* We know kernel never takes protection trap,
@@ -15,12 +15,12 @@
/* ICACHE line 1 */
/*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET
- /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
- /*0x08*/ sllx %g1, 2, %g4 ! Position PMD offset
- /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
- /*0x10*/ and %g4, %g2, %g4 ! Mask PMD offset
- /*0x14*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
- /*0x18*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g4 ! Load PMD
+ /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset
+ /*0x08*/ and %g1, 0xffe, %g4 ! Mask PMD offset
+ /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset
+ /*0x10*/ add %g4, %g4, %g4 ! Position PMD offset
+ /*0x14*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD
+ /*0x18*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g4 ! Load PMD
/*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset
/* ICACHE line 2 */
@@ -34,10 +34,10 @@
/*0x3c*/ ldxa [%g5] ASI_DMMU, %g4 ! From MMU
/* ICACHE line 3 */
- /*0x40*/ add %g2, 7, %g5 ! Compute mask
- /*0x44*/ andn %g4, %g5, %g4 ! Mask page
- /*0x48*/ mov TLB_SFSR, %g5 ! read SFSR
- /*0x4c*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for
+ /*0x40*/ mov TLB_SFSR, %g5 ! read SFSR
+ /*0x44*/ srlx %g4, 13, %g4 ! Prepare...
+ /*0x48*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for
+ /*0x4c*/ sllx %g4, 13, %g4 ! ...and mask page
/*0x50*/ and %g5, 0x10, %g5 ! context bit
/*0x54*/ or %g4, %g5, %g4 ! for prot trap
1:/*0x58*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 02faf4e3c..954cfd4bc 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.17 1998/01/10 18:26:13 ecd Exp $
+/* $Id: ebus.c,v 1.23 1998/03/29 16:27:24 ecd Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -29,14 +29,12 @@
struct linux_ebus *ebus_chain = 0;
extern void prom_ebus_ranges_init(struct linux_ebus *);
+extern void prom_ebus_intmap_init(struct linux_ebus *);
extern unsigned long pci_console_init(unsigned long memory_start);
#ifdef CONFIG_SUN_OPENPROMIO
extern int openprom_init(void);
#endif
-#ifdef CONFIG_SUN_MOSTEK_RTC
-extern int rtc_init(void);
-#endif
#ifdef CONFIG_SPARCAUDIO
extern int sparcaudio_init(void);
#endif
@@ -46,6 +44,9 @@ extern void auxio_probe(void);
#ifdef CONFIG_OBP_FLASH
extern int flash_init(void);
#endif
+#ifdef CONFIG_ENVCTRL
+extern int envctrl_init(void);
+#endif
extern unsigned int psycho_irq_build(struct linux_pbm_info *pbm,
unsigned int full_ino);
@@ -62,7 +63,35 @@ ebus_alloc(unsigned long *memory_start, size_t size)
return mem;
}
-__initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
+__initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
+ struct linux_prom_registers *reg,
+ int *interrupt))
+{
+ unsigned int hi, lo, irq;
+ int i;
+
+ if (!ebus->num_ebus_intmap)
+ return;
+
+ hi = reg->which_io & ebus->ebus_intmask.phys_hi;
+ lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
+ irq = *interrupt & ebus->ebus_intmask.interrupt;
+ for (i = 0; i < ebus->num_ebus_intmap; i++) {
+ if ((ebus->ebus_intmap[i].phys_hi == hi) &&
+ (ebus->ebus_intmap[i].phys_lo == lo) &&
+ (ebus->ebus_intmap[i].interrupt == irq)) {
+ *interrupt = ebus->ebus_intmap[i].cinterrupt;
+ return;
+ }
+ }
+
+ prom_printf("ebus: IRQ [%08x.%08x.%08x] not found in interrupt-map\n",
+ reg->which_io, reg->phys_addr, *interrupt);
+ prom_halt();
+}
+
+__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
+ struct linux_ebus_child *dev))
{
int regs[PROMREG_MAX];
int irqs[PROMREG_MAX];
@@ -90,8 +119,10 @@ __initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
dev->num_irqs = 0;
} else {
dev->num_irqs = len / sizeof(irqs[0]);
- for (i = 0; i < dev->num_irqs; i++)
+ for (i = 0; i < dev->num_irqs; i++) {
+ ebus_intmap_match(dev->bus, preg, &irqs[i]);
dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
+ }
}
#ifdef DEBUG_FILL_EBUS_DEV
@@ -108,7 +139,8 @@ __initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
#endif
}
-__initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *dev,
+__initfunc(unsigned long fill_ebus_device(int node,
+ struct linux_ebus_device *dev,
unsigned long memory_start))
{
struct linux_prom_registers regs[PROMREG_MAX];
@@ -142,8 +174,10 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
dev->num_irqs = 0;
} else {
dev->num_irqs = len / sizeof(irqs[0]);
- for (i = 0; i < dev->num_irqs; i++)
+ for (i = 0; i < dev->num_irqs; i++) {
+ ebus_intmap_match(dev->bus, &regs[0], &irqs[i]);
dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]);
+ }
}
#ifdef DEBUG_FILL_EBUS_DEV
@@ -166,7 +200,7 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
child->next = 0;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, child);
+ fill_ebus_child(node, &regs[0], child);
while ((node = prom_getsibling(node))) {
child->next = (struct linux_ebus_child *)
@@ -176,13 +210,16 @@ __initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *de
child->next = 0;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, child);
+ fill_ebus_child(node, &regs[0], child);
}
}
return memory_start;
}
+extern void sun4u_start_timers(void);
+extern void clock_probe(void);
+
__initfunc(unsigned long ebus_init(unsigned long memory_start,
unsigned long memory_end))
{
@@ -199,14 +236,10 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
int reg, rng, nreg;
int num_ebus = 0;
- if (!pcibios_present())
+ if (!pci_present())
return memory_start;
- for (pdev = pci_devices; pdev; pdev = pdev->next) {
- if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
- (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
- break;
- }
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
if (!pdev) {
printk("ebus: No EBus's found.\n");
#ifdef PROM_DEBUG
@@ -236,11 +269,9 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
ebus->parent = pbm = cookie->pbm;
/* Enable BUS Master. */
- pcibios_read_config_word(pdev->bus->number, pdev->devfn,
- PCI_COMMAND, &pci_command);
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pdev->bus->number, pdev->devfn,
- PCI_COMMAND, pci_command);
+ pci_write_config_word(pdev, PCI_COMMAND, pci_command);
len = prom_getproperty(ebusnd, "reg", (void *)regs,
sizeof(regs));
@@ -285,6 +316,7 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
#endif
prom_ebus_ranges_init(ebus);
+ prom_ebus_intmap_init(ebus);
nd = prom_getchild(ebusnd);
if (!nd)
@@ -312,11 +344,8 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
}
next_ebus:
- for (pdev = pdev->next; pdev; pdev = pdev->next) {
- if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
- (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
- break;
- }
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_EBUS, pdev);
if (!pdev)
break;
@@ -335,9 +364,6 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
#ifdef CONFIG_SUN_OPENPROMIO
openprom_init();
#endif
-#ifdef CONFIG_SUN_MOSTEK_RTC
- rtc_init();
-#endif
#ifdef CONFIG_SPARCAUDIO
sparcaudio_init();
#endif
@@ -345,20 +371,15 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start,
bpp_init();
#endif
#ifdef CONFIG_SUN_AUXIO
- if (sparc_cpu_model == sun4u)
- auxio_probe();
+ auxio_probe();
+#endif
+#ifdef CONFIG_ENVCTRL
+ envctrl_init();
#endif
#ifdef CONFIG_OBP_FLASH
flash_init();
#endif
-#ifdef __sparc_v9__
- if (sparc_cpu_model == sun4u) {
- extern void sun4u_start_timers(void);
- extern void clock_probe(void);
-
- sun4u_start_timers();
- clock_probe();
- }
-#endif
+ sun4u_start_timers();
+ clock_probe();
return memory_start;
}
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 43f950b25..c0531f30a 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,9 +1,9 @@
-/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $
+/* $Id: head.S,v 1.49 1998/03/03 12:31:17 jj Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
*/
@@ -26,7 +26,7 @@
/* This section from from _start to sparc64_boot_end should fit into
* 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
* with bootup_user_stack, which is from 0x0000.0000.0040.4000 to
- * 0x0000.0000.0040.6000 and bootup_kernel_stack, which is from
+ * 0x0000.0000.0040.6000 and empty_bad_page, which is from
* 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000.
*/
@@ -326,6 +326,8 @@ sun4u_init:
nop
/* Not reached... */
+/* IMPORTANT NOTE: Whenever making changes here, check
+ * trampoline.S as well. -jj */
.globl setup_tba
setup_tba:
save %sp, -160, %sp
@@ -346,9 +348,11 @@ setup_tba:
/* Set up MMU globals */
wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate
- /* PGD/PMD offset mask, used by TLB miss handlers. */
- sethi %hi(0x1ff8), %g2
- or %g2, %lo(0x1ff8), %g2
+ /* Set KERN_HIGHBITS used by dTLB miss handler. */
+#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+ sethi %uhi(KERN_HIGHBITS), %g2
+ sllx %g2, 32, %g2
+#undef KERN_HIGHBITS
/* Kernel PGDIR used by TLB miss handlers. */
mov %i0, %g6
@@ -391,7 +395,8 @@ sparc64_boot_end:
.skip 0x2000 + _start - sparc64_boot_end
bootup_user_stack_end:
-bootup_kernel_stack:
+ .globl empty_bad_page
+empty_bad_page:
.skip 0x2000
! 0x0000000000408000
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
index 1829daeea..86b6c3dd6 100644
--- a/arch/sparc64/kernel/init_task.c
+++ b/arch/sparc64/kernel/init_task.c
@@ -6,7 +6,7 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct files * init_fd_array[NR_OPEN] = { NULL, };
+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;
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 64465663d..17e904f25 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.26 1997/12/15 15:11:02 jj Exp $
+/* $Id: ioctl32.c,v 1.35 1998/04/10 02:01:46 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -23,9 +23,11 @@
#include <linux/netlink.h>
#include <linux/vt.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/fd.h>
#include <linux/if_ppp.h>
#include <linux/mtio.h>
+#include <linux/cdrom.h>
#include <scsi/scsi.h>
/* Ugly hack. */
@@ -64,6 +66,30 @@ static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
return err;
}
+struct timeval32 {
+ int tv_sec;
+ int tv_usec;
+};
+
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ struct timeval32 *up = (struct timeval32 *)A(arg);
+ struct timeval ktv;
+ mm_segment_t old_fs = get_fs();
+ int err;
+
+ set_fs(KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+ set_fs(old_fs);
+ if(!err) {
+ if(!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+ __put_user(ktv.tv_sec, &up->tv_sec) ||
+ __put_user(ktv.tv_usec, &up->tv_usec))
+ err = -EFAULT;
+ }
+ return err;
+}
+
struct ifmap32 {
u32 mem_start;
u32 mem_end;
@@ -948,6 +974,90 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
return 0;
}
+struct cdrom_read32 {
+ int cdread_lba;
+ __kernel_caddr_t32 cdread_bufaddr;
+ int cdread_buflen;
+};
+
+struct cdrom_read_audio32 {
+ union cdrom_addr addr;
+ u_char addr_format;
+ int nframes;
+ __kernel_caddr_t32 buf;
+};
+
+static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+{
+ mm_segment_t old_fs = get_fs();
+ struct cdrom_read cdread;
+ struct cdrom_read_audio cdreadaudio;
+ __kernel_caddr_t32 addr;
+ char *data = 0;
+ void *karg;
+ int err = 0;
+
+ switch(cmd) {
+ case CDROMREADMODE2:
+ case CDROMREADMODE1:
+ case CDROMREADRAW:
+ case CDROMREADCOOKED:
+ karg = &cdread;
+ if (__get_user(cdread.cdread_lba, &((struct cdrom_read32 *)A(arg))->cdread_lba) ||
+ __get_user(addr, &((struct cdrom_read32 *)A(arg))->cdread_bufaddr) ||
+ __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)A(arg))->cdread_buflen))
+ return -EFAULT;
+ data = kmalloc(cdread.cdread_buflen, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ cdread.cdread_bufaddr = data;
+ break;
+ case CDROMREADAUDIO:
+ karg = &cdreadaudio;
+ if (copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)A(arg))->addr, sizeof(cdreadaudio.addr)) ||
+ __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)A(arg))->addr_format) ||
+ __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)A(arg))->nframes) ||
+ __get_user(addr, &((struct cdrom_read_audio32 *)A(arg))->buf))
+ return -EFAULT;
+ data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ cdreadaudio.buf = data;
+ break;
+ default:
+ printk("cdrom_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
+ (int)fd, (unsigned int)cmd, (unsigned int)arg);
+ return -EINVAL;
+ }
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)karg);
+ set_fs (old_fs);
+ if (err) {
+ if (data) kfree(data);
+ return err;
+ }
+ switch (cmd) {
+ case CDROMREADMODE2:
+ case CDROMREADMODE1:
+ case CDROMREADRAW:
+ case CDROMREADCOOKED:
+ if (copy_to_user((char *)A(addr), data, cdread.cdread_buflen)) {
+ kfree(data);
+ return -EFAULT;
+ }
+ break;
+ case CDROMREADAUDIO:
+ if (copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352)) {
+ kfree(data);
+ return -EFAULT;
+ }
+ break;
+ default:
+ break;
+ }
+ if (data) kfree(data);
+ return 0;
+}
asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
{
@@ -955,10 +1065,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
int error = -EBADF;
lock_kernel();
- if(fd >= NR_OPEN)
- goto out;
-
- filp = current->files->fd[fd];
+ filp = fcheck(fd);
if(!filp)
goto out;
@@ -966,7 +1073,6 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = sys_ioctl (fd, cmd, (unsigned long)arg);
goto out;
}
- error = -EFAULT;
switch (cmd) {
case SIOCGIFCONF:
error = dev_ifconf(fd, arg);
@@ -1014,6 +1120,11 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = -EINVAL;
goto out;
+ case SIOCGSTAMP:
+ /* Sorry, timeval in the kernel is different now. */
+ error = do_siocgstamp(fd, cmd, arg);
+ goto out;
+
case HDIO_GETGEO:
error = hdio_getgeo(fd, arg);
goto out;
@@ -1066,6 +1177,15 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
error = mt_ioctl_trans(fd, cmd, arg);
goto out;
+ case CDROMREADMODE2:
+ case CDROMREADMODE1:
+ case CDROMREADRAW:
+ case CDROMREADCOOKED:
+ case CDROMREADAUDIO:
+ case CDROMREADALL:
+ error = cdrom_ioctl_trans(fd, cmd, arg);
+ goto out;
+
/* List here exlicitly which ioctl's are known to have
* compatable types passed or none at all...
*/
@@ -1170,6 +1290,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
/* 0x09 */
case REGISTER_DEV:
+ case REGISTER_DEV_NEW:
case START_MD:
case STOP_MD:
@@ -1219,6 +1340,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case SCSI_IOCTL_TAGGED_ENABLE:
case SCSI_IOCTL_TAGGED_DISABLE:
case SCSI_IOCTL_GET_BUS_NUMBER:
+ case SCSI_IOCTL_SEND_COMMAND:
/* Big V */
case VT_SETMODE:
@@ -1267,7 +1389,6 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case FIOGETOWN:
case SIOCGPGRP:
case SIOCATMARK:
- case SIOCGSTAMP:
case SIOCSIFLINK:
case SIOCSIFENCAP:
case SIOCGIFENCAP:
@@ -1305,6 +1426,36 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case PPPIOCSNPMODE:
case PPPIOCGDEBUG:
case PPPIOCSDEBUG:
+
+ /* CDROM stuff */
+ case CDROMPAUSE:
+ case CDROMRESUME:
+ case CDROMPLAYMSF:
+ case CDROMPLAYTRKIND:
+ case CDROMREADTOCHDR:
+ case CDROMREADTOCENTRY:
+ case CDROMSTOP:
+ case CDROMSTART:
+ case CDROMEJECT:
+ case CDROMVOLCTRL:
+ case CDROMSUBCHNL:
+ case CDROMEJECT_SW:
+ case CDROMMULTISESSION:
+ case CDROM_GET_MCN:
+ case CDROMRESET:
+ case CDROMVOLREAD:
+ case CDROMSEEK:
+ case CDROMPLAYBLK:
+ case CDROMCLOSETRAY:
+ case CDROM_SET_OPTIONS:
+ case CDROM_CLEAR_OPTIONS:
+ case CDROM_SELECT_SPEED:
+ case CDROM_SELECT_DISC:
+ case CDROM_MEDIA_CHANGED:
+ case CDROM_DRIVE_STATUS:
+ case CDROM_DISC_STATUS:
+ case CDROM_CHANGER_NSLOTS:
+
error = sys_ioctl (fd, cmd, (unsigned long)arg);
goto out;
@@ -1312,7 +1463,6 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
(int)fd, (unsigned int)cmd, (unsigned int)arg);
error = -EINVAL;
- goto out;
break;
}
out:
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index a84fe8eaa..176079643 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,7 +1,8 @@
-/* $Id: irq.c,v 1.47 1998/01/10 18:26:17 ecd Exp $
+/* $Id: irq.c,v 1.52 1998/03/19 00:22:54 ecd Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
*/
#include <linux/config.h>
@@ -98,12 +99,22 @@ int get_irq_list(char *buf)
{
int i, len = 0;
struct irqaction *action;
+#ifdef __SMP__
+ int j;
+#endif
for(i = 0; i < (NR_IRQS + 1); i++) {
if(!(action = *(i + irq_action)))
continue;
- len += sprintf(buf + len, "%2d: %8d %c %s",
- i, kstat.interrupts[i],
+ len += sprintf(buf + len, "%3d: ", i);
+#ifndef __SMP__
+ len += sprintf(buf + len, "%10u ", kstat_irqs(i));
+#else
+ for (j = 0; j < smp_num_cpus; j++)
+ len += sprintf(buf + len, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+ len += sprintf(buf + len, "%c %s",
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
for(action = action->next; action; action = action->next) {
@@ -113,19 +124,6 @@ int get_irq_list(char *buf)
}
len += sprintf(buf + len, "\n");
}
-#if 0
-#ifdef CONFIG_PCI
- {
- struct linux_psycho *p;
- for (p = psycho_root; p; p = p->next)
- len += sprintf(buf + len,
- "ISTAT[%d]: PCI[%016lx] OBIO[%016lx]\n",
- p->index,
- p->psycho_regs->pci_istate,
- p->psycho_regs->obio_istate);
- }
-#endif
-#endif
return len;
}
@@ -197,8 +195,7 @@ static unsigned int *sysio_irq_to_imap(unsigned int irq)
unsigned long offset;
struct sysio_regs *sregs;
- if((irq == 14) ||
- (irq >= NUM_SYSIO_OFFSETS) ||
+ if((irq >= NUM_SYSIO_OFFSETS) ||
((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
return NULL;
sregs = SBus_chain->iommu->sysio_regs;
@@ -224,8 +221,8 @@ static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
unsigned char psycho_ino_to_pil[] = {
7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */
7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */
- 0, 0, 0, 0,
- 0, 0, 0, 0,
+ 7, 5, 5, 2, /* PCI A slot 2 Int A, B, C, D */
+ 7, 5, 5, 2, /* PCI A slot 3 Int A, B, C, D */
6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */
6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */
6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */
@@ -255,13 +252,13 @@ unsigned char psycho_ino_to_pil[] = {
*/
#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
-#define psycho_imap_offset(ino) \
- ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \
+#define psycho_imap_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \
(psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
-#define psycho_iclr_offset(ino) \
- ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \
- (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3)))
+#define psycho_iclr_offset(ino) \
+ ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \
+ (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f)<<3)))
#endif
@@ -529,7 +526,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
unsigned long flags;
unsigned int *imap, *iclr;
void *bus_id = NULL;
- int ivindex, ivindex_fixup, cpu_irq = -1, pending;
+ int ivindex = -1, ivindex_fixup, cpu_irq = -1, pending = 0;
if(!handler)
return -EINVAL;
@@ -537,43 +534,47 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
imap = iclr = NULL;
ivindex_fixup = 0;
+
+ if (irq == 0) {
+ cpu_irq = irq;
+ irqflags &= ~(SA_IMAP_MASKED);
+ } else {
+ irqflags |= SA_IMAP_MASKED;
#ifdef CONFIG_PCI
- if(PCI_IRQ_P(irq)) {
- pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
- } else
+ if(PCI_IRQ_P(irq)) {
+ pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
+ } else
#endif
- if(irqflags & SA_DCOOKIE) {
- if(!dev_id) {
- printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
- panic("Bogus irq registry.");
- }
- dcookie = dev_id;
- dev_id = dcookie->real_dev_id;
- cpu_irq = dcookie->pil;
- imap = dcookie->imap;
- iclr = dcookie->iclr;
- bus_id = dcookie->bus_cookie;
- get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
- &iclr, bus_id, irqflags, irq);
- } else {
- /* XXX NOTE: This code is maintained for compatability until I can
- * XXX verify that all drivers sparc64 will use are updated
- * XXX to use the new IRQ registry dcookie interface. -DaveM
- */
- if(irq == 14)
- cpu_irq = irq;
- else
+ if(irqflags & SA_DCOOKIE) {
+ if(!dev_id) {
+ printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
+ panic("Bogus irq registry.");
+ }
+ dcookie = dev_id;
+ dev_id = dcookie->real_dev_id;
+ cpu_irq = dcookie->pil;
+ imap = dcookie->imap;
+ iclr = dcookie->iclr;
+ bus_id = dcookie->bus_cookie;
+ get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+ &iclr, bus_id, irqflags, irq);
+ } else {
+ /* XXX NOTE: This code is maintained for compatability until I can
+ * XXX verify that all drivers sparc64 will use are updated
+ * XXX to use the new IRQ registry dcookie interface. -DaveM
+ */
cpu_irq = sysio_ino_to_pil[irq];
- imap = sysio_irq_to_imap(irq);
- if(!imap) {
- printk("request_irq: BAD, null imap for old style "
- "irq registry IRQ[%x].\n", irq);
- panic("Bad IRQ registery...");
+ imap = sysio_irq_to_imap(irq);
+ if(!imap) {
+ printk("request_irq: BAD, null imap for old style "
+ "irq registry IRQ[%x].\n", irq);
+ panic("Bad IRQ registery...");
+ }
+ iclr = sysio_imap_to_iclr(imap);
}
- iclr = sysio_imap_to_iclr(imap);
+ ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+ ivindex += ivindex_fixup;
}
- ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
- ivindex += ivindex_fixup;
action = *(cpu_irq + irq_action);
if(action) {
@@ -612,26 +613,28 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
return -ENOMEM;
}
- bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
- if(!bucket) {
- kfree(action);
- restore_flags(flags);
- return -ENOMEM;
- }
+ if (irqflags & SA_IMAP_MASKED) {
+ bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+ if(!bucket) {
+ kfree(action);
+ restore_flags(flags);
+ return -ENOMEM;
+ }
- pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0);
- ivector_to_mask[ivindex] = (1 << cpu_irq);
- if(pending)
- ivector_to_mask[ivindex] |= 0x80000000;
+ pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0);
+ ivector_to_mask[ivindex] = (1 << cpu_irq);
+ if(pending)
+ ivector_to_mask[ivindex] |= 0x80000000;
- if(dcookie) {
- dcookie->ret_ino = ivindex;
- dcookie->ret_pil = cpu_irq;
+ if(dcookie) {
+ dcookie->ret_ino = ivindex;
+ dcookie->ret_pil = cpu_irq;
+ }
}
action->mask = (unsigned long) bucket;
action->handler = handler;
- action->flags = irqflags | SA_IMAP_MASKED;
+ action->flags = irqflags;
action->name = name;
action->next = NULL;
action->dev_id = dev_id;
@@ -664,7 +667,7 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned int cpu_irq;
int ivindex = -1;
- if(irq == 14) {
+ if(irq == 0) {
cpu_irq = irq;
} else {
#ifdef CONFIG_PCI
@@ -951,34 +954,43 @@ void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs)
void handler_irq(int irq, struct pt_regs *regs)
{
struct ino_bucket *bucket = NULL;
- struct irqaction *action;
+ struct irqaction *action, *act;
int cpu = smp_processor_id();
+#ifndef __SMP__
+ /*
+ * Check for TICK_INT on level 14 softint.
+ */
+ if ((irq == 14) && get_softint() & (1UL << 0))
+ irq = 0;
+#endif
clear_softint(1 << irq);
irq_enter(cpu, irq);
action = *(irq + irq_action);
- kstat.interrupts[irq]++;
+ kstat.irqs[cpu][irq]++;
if(!action) {
unexpected_irq(irq, 0, regs);
} else {
+ act = action;
do {
- unsigned long *swmask = NULL;
-
- if(action->flags & SA_IMAP_MASKED) {
- bucket = (struct ino_bucket *)action->mask;
-
- swmask = &ivector_to_mask[bucket->ino];
- if(!(*swmask & 0x80000000))
+ if(act->flags & SA_IMAP_MASKED) {
+ bucket = (struct ino_bucket *)act->mask;
+ if(!(ivector_to_mask[bucket->ino] & 0x80000000))
continue;
}
-
- action->handler(irq, action->dev_id, regs);
- if(swmask) {
- *swmask &= ~(0x80000000);
+ act->handler(irq, 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;
}
- } while((action = action->next) != NULL);
+ } while((act = act->next) != NULL);
}
irq_exit(cpu, irq);
}
@@ -993,6 +1005,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
int cpu = smp_processor_id();
irq_enter(cpu, irq);
+ kstat.irqs[cpu][irq]++;
bucket = (struct ino_bucket *)action->mask;
floppy_interrupt(irq, dev_cookie, regs);
ivector_to_mask[bucket->ino] &= ~(0x80000000);
@@ -1036,13 +1049,19 @@ int request_fast_irq(unsigned int irq,
unsigned long flags;
unsigned int *imap, *iclr;
void *bus_id = NULL;
- int ivindex, ivindex_fixup, cpu_irq = -1;
+ int ivindex = -1, ivindex_fixup, cpu_irq = -1;
if(!handler)
return -EINVAL;
imap = iclr = NULL;
ivindex_fixup = 0;
+
+ if ((irq == 0) || (irq == 14)) {
+ printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n");
+ return -EBUSY;
+ }
+
#ifdef CONFIG_PCI
if(PCI_IRQ_P(irq)) {
pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq);
@@ -1066,10 +1085,7 @@ int request_fast_irq(unsigned int irq,
* XXX verify that all drivers sparc64 will use are updated
* XXX to use the new IRQ registry dcookie interface. -DaveM
*/
- if(irq == 14)
- cpu_irq = irq;
- else
- cpu_irq = sysio_ino_to_pil[irq];
+ cpu_irq = sysio_ino_to_pil[irq];
imap = sysio_irq_to_imap(irq);
if(!imap) {
printk("request_irq: BAD, null imap for old style "
@@ -1153,85 +1169,100 @@ int probe_irq_off(unsigned long mask)
return 0;
}
-struct sun5_timer *linux_timers = NULL;
-
-/* This is gets the master level10 timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
+/* This is gets the master TICK_INT timer going. */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
+ unsigned long *clock)
{
- struct linux_prom64_registers pregs[3];
- struct devid_cookie dcookie;
- unsigned int *imap, *iclr;
- u32 pirqs[2];
+ unsigned long flags;
+ unsigned long timer_tick_offset;
int node, err;
- node = prom_finddevice("/counter-timer");
- if(node == 0 || node == -1) {
- prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
- prom_halt();
- }
- err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
- if(err == -1) {
- prom_printf("init_timers: Cannot obtain 'reg' for counter-timer.\n");
- prom_halt();
- }
- err = prom_getproperty(node, "interrupts", (char *)&pirqs[0], sizeof(pirqs));
- if(err == -1) {
- prom_printf("init_timers: Cannot obtain 'interrupts' "
- "for counter-timer.\n");
- prom_halt();
- }
- linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
- iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1);
- imap = (((unsigned int *)__va(pregs[2].phys_addr))+1);
-
- /* Shut it up first. */
- linux_timers->limit0 = 0;
+ node = linux_cpus[0].prom_node;
+ *clock = prom_getint(node, "clock-frequency");
+ timer_tick_offset = *clock / HZ;
/* Register IRQ handler. */
- dcookie.real_dev_id = NULL;
- dcookie.imap = imap;
- dcookie.iclr = iclr;
- dcookie.pil = 10;
- dcookie.bus_cookie = NULL;
-
- err = request_irq(pirqs[0], cfunc,
- (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC),
- "timer", &dcookie);
+ err = request_irq(0, cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC),
+ "timer", NULL);
if(err) {
- prom_printf("Serious problem, cannot register timer interrupt\n");
+ prom_printf("Serious problem, cannot register TICK_INT\n");
prom_halt();
- } else {
- unsigned long flags;
+ }
- save_and_cli(flags);
+ save_and_cli(flags);
- /* Set things up so user can access tick register for profiling
- * purposes.
- */
- __asm__ __volatile__("
- sethi %%hi(0x80000000), %%g1
- sllx %%g1, 32, %%g1
- rd %%tick, %%g2
- add %%g2, 6, %%g2
- andn %%g2, %%g1, %%g2
- wrpr %%g2, 0, %%tick
-" : /* no outputs */
- : /* no inputs */
- : "g1", "g2");
-
- linux_timers->limit0 =
- (SUN5_LIMIT_ENABLE | SUN5_LIMIT_ZRESTART | SUN5_LIMIT_TOZERO |
- (SUN5_HZ_TO_LIMIT(HZ) & SUN5_LIMIT_CMASK));
+ /* Set things up so user can access tick register for profiling
+ * purposes.
+ */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%tick, %%g2
+ add %%g2, 6, %%g2
+ andn %%g2, %%g1, %%g2
+ wrpr %%g2, 0, %%tick
+" : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
- restore_flags(flags);
- }
+ __asm__ __volatile__("
+ rd %%tick, %%g1
+ add %%g1, %0, %%g1
+ wr %%g1, 0x0, %%tick_cmpr"
+ : /* no outputs */
+ : "r" (timer_tick_offset)
+ : "g1");
+ restore_flags(flags);
sti();
}
-struct sun5_timer *prom_timers;
+#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.
+ */
+void distribute_irqs(void)
+{
+ unsigned long flags;
+ int cpu, level;
+
+ printk("SMP: redistributing interrupts...\n");
+ 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 = bucket->imap;
+ unsigned int val;
+ unsigned long tid = __cpu_logical_map[cpu] << 9;
+
+ val = *imap;
+ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+ printk("SMP: Redirecting IGN[%x] INO[%x] "
+ "to cpu %d [%s]\n",
+ (val & SYSIO_IMAP_IGN) >> 6,
+ (val & SYSIO_IMAP_INO), cpu,
+ p->name);
+
+ cpu++;
+ if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1)
+ cpu = 0;
+ }
+ p = p->next;
+ }
+ }
+ restore_flags(flags);
+ irqs_have_been_distributed = 1;
+}
+#endif
+
+
+struct sun5_timer *prom_timers;
static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
@@ -1245,9 +1276,8 @@ static void map_prom_timers(void)
/* Assume if node is not present, PROM uses different tick mechanism
* which we should not care about.
*/
- if(tnode == 0) {
+ if(tnode == 0 || tnode == -1) {
prom_timers = (struct sun5_timer *) 0;
- prom_printf("AIEEE, no timers\n");
return;
}
@@ -1300,52 +1330,6 @@ void enable_prom_timer(void)
prom_timers->count0 = 0;
}
-#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.
- */
-void distribute_irqs(void)
-{
- unsigned long flags;
- int cpu, level;
-
- printk("SMP: redistributing interrupts...\n");
- 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 = bucket->imap;
- unsigned int val;
- unsigned long tid = linux_cpus[cpu].mid << 9;
-
- val = *imap;
- *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
-
- printk("SMP: Redirecting IGN[%x] INO[%x] "
- "to cpu %d [%s]\n",
- (val & SYSIO_IMAP_IGN) >> 6,
- (val & SYSIO_IMAP_INO), cpu,
- p->name);
-
- cpu += 1;
- while(!(cpu_present_map & (1UL << cpu))) {
- cpu += 1;
- if(cpu >= smp_num_cpus)
- cpu = 0;
- }
- }
- p = p->next;
- }
- }
- restore_flags(flags);
- irqs_have_been_distributed = 1;
-}
-#endif
-
__initfunc(void init_IRQ(void))
{
int i;
diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S
index 9317587a7..94e3f44f6 100644
--- a/arch/sparc64/kernel/itlb_miss.S
+++ b/arch/sparc64/kernel/itlb_miss.S
@@ -1,42 +1,42 @@
-/* $Id: itlb_miss.S,v 1.11 1997/10/14 01:48:25 davem Exp $
+/* $Id: itlb_miss.S,v 1.12 1998/01/14 17:14:47 jj Exp $
* itlb_miss.S: Instruction TLB miss code, this is included directly
* into the trap table.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
/* Gratuitous comment. */
/* ICACHE line 1 */
/*0x00*/ ldxa [%g0] ASI_IMMU, %g1 ! Get TAG_TARGET
- /*0x04*/ srlx %g1, 8, %g3 ! Position PGD offset
- /*0x08*/ srlx %g1, 48, %g5 ! Shift down CONTEXT bits
- /*0x0c*/ and %g3, %g2, %g3 ! Mask PGD offset
- /*0x10*/ sllx %g1, 2, %g4 ! Position PMD offset
+ /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset
+ /*0x08*/ andcc %g1, %g2, %g0 ! Test CONTEXT bits
+ /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset
+ /*0x10*/ and %g1, 0xffe, %g4 ! Mask PMD offset
/*0x14*/ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! For PTE offset
- /*0x18*/ brz,pn %g5, 3f ! Context 0 == kernel
- /*0x1c*/ and %g4, %g2, %g4 ! Mask PMD offset
+ /*0x18*/ be,pn %xcc, 3f ! Context 0 == kernel
+ /*0x1c*/ add %g4, %g4, %g4 ! Position PMD offset
/* ICACHE line 2 */
- /*0x20*/ ldxa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load user PGD
+ /*0x20*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load user PGD
/*0x24*/ srlx %g1, 1, %g1 ! PTE offset
- /*0x28*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
-2:/*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
+ /*0x28*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
+ /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
/*0x30*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set?
/*0x34*/ nop ! delay
/*0x38*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
/*0x3c*/ retry ! Trap return
3: /* ICACHE line 3 */
- /*0x40*/ ldxa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
+ /*0x40*/ lduwa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD
/*0x44*/ srlx %g1, 1, %g1 ! PTE offset
- /*0x48*/ ba,pt %xcc, 2b ! Continue above
- /*0x4c*/ ldxa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
- /*0x50*/ nop
- /*0x54*/ nop
- /*0x58*/ nop
- /*0x5c*/ nop
+ /*0x48*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD
+ /*0x4c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE
+ /*0x50*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set?
+ /*0x54*/ nop ! delay
+ /*0x58*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load
+ /*0x5c*/ retry ! Trap return
/* ICACHE line 4 */
/*0x60*/ nop
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 4e5ead982..c0058afd9 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.50 1998/01/09 16:39:33 jj Exp $
+/* $Id: process.c,v 1.52 1998/03/29 12:57:53 ecd Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -41,9 +41,6 @@
/* #define VERBOSE_SHOWREGS */
-#define PGTCACHE_HIGH_WATER 50
-#define PGTCACHE_LOW_WATER 25
-
#ifndef __SMP__
/*
@@ -58,16 +55,7 @@ asmlinkage int sys_idle(void)
current->priority = -100;
current->counter = -100;
for (;;) {
- if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
- do {
- if(pgd_quicklist)
- free_page((unsigned long) get_pgd_fast());
- if(pmd_quicklist)
- free_page((unsigned long) get_pmd_fast());
- if(pte_quicklist)
- free_page((unsigned long) get_pte_fast());
- } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
- }
+ check_pgt_cache();
run_task_queue(&tq_scheduler);
schedule();
}
@@ -83,16 +71,7 @@ asmlinkage int cpu_idle(void)
{
current->priority = -100;
while(1) {
- if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
- do {
- if(pgd_quicklist)
- free_page((unsigned long) get_pgd_fast());
- if(pmd_quicklist)
- free_page((unsigned long) get_pmd_fast());
- if(pte_quicklist)
- free_page((unsigned long) get_pte_fast());
- } while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
- }
+ check_pgt_cache();
if(tq_scheduler) {
lock_kernel();
run_task_queue(&tq_scheduler);
@@ -592,6 +571,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.flags |= SPARC_FLAG_KTHREAD;
p->tss.current_ds = KERNEL_DS;
p->tss.ctx = 0;
+ __asm__ __volatile__("flushw");
+ memcpy((void *)(p->tss.ksp + STACK_BIAS),
+ (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
+ sizeof(struct reg_window));
p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
if(current->tss.flags & SPARC_FLAG_32BIT) {
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
index b3b403e33..78a69e8df 100644
--- a/arch/sparc64/kernel/psycho.c
+++ b/arch/sparc64/kernel/psycho.c
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.31 1998/01/10 18:26:15 ecd Exp $
+/* $Id: psycho.c,v 1.50 1998/04/10 12:29:47 ecd Exp $
* psycho.c: Ultra/AX U2P PCI controller support.
*
* Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -8,6 +8,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/init.h>
#include <asm/ebus.h>
#include <asm/sbus.h> /* for sanity check... */
@@ -15,6 +16,7 @@
#undef PROM_DEBUG
#undef FIXUP_REGS_DEBUG
#undef FIXUP_IRQ_DEBUG
+#undef FIXUP_VMA_DEBUG
#ifdef PROM_DEBUG
#define dprintf prom_printf
@@ -22,6 +24,9 @@
#define dprintf printk
#endif
+unsigned long pci_dvma_offset = 0x00000000UL;
+unsigned long pci_dvma_mask = 0xffffffffUL;
+
#ifndef CONFIG_PCI
int pcibios_present(void)
@@ -51,12 +56,12 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/oplib.h>
#include <asm/pbm.h>
+#include <asm/apb.h>
#include <asm/uaccess.h>
struct linux_psycho *psycho_root = NULL;
@@ -95,8 +100,9 @@ static inline unsigned long long_align(unsigned long addr)
~(sizeof(unsigned long) - 1));
}
-static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
- unsigned long memory_start)
+__initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
+ int tsbsize,
+ unsigned long memory_start))
{
unsigned long tsbbase = PAGE_ALIGN(memory_start);
unsigned long control, i;
@@ -114,10 +120,10 @@ static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
control &= ~(IOMMU_CTRL_DENAB);
psycho->psycho_regs->iommu_control = control;
- memory_start = (tsbbase + ((32 * 1024) * 8));
+ memory_start = (tsbbase + ((tsbsize * 1024) * 8));
iopte = (unsigned long *)tsbbase;
- for(i = 0; i < (32 * 1024); i++) {
+ for(i = 0; i < (tsbsize * 1024); i++) {
*iopte = (IOPTE_VALID | IOPTE_64K |
IOPTE_CACHE | IOPTE_WRITE);
*iopte |= (i << 16);
@@ -128,15 +134,215 @@ static unsigned long psycho_iommu_init(struct linux_psycho *psycho,
control = psycho->psycho_regs->iommu_control;
control &= ~(IOMMU_CTRL_TSBSZ);
- control |= (IOMMU_TSBSZ_32K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+ control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+ switch(tsbsize) {
+ case 8:
+ pci_dvma_mask = 0x1fffffffUL;
+ control |= IOMMU_TSBSZ_8K;
+ break;
+ case 16:
+ pci_dvma_mask = 0x3fffffffUL;
+ control |= IOMMU_TSBSZ_16K;
+ break;
+ case 32:
+ pci_dvma_mask = 0x7fffffffUL;
+ control |= IOMMU_TSBSZ_32K;
+ break;
+ default:
+ prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
+ prom_halt();
+ break;
+ }
psycho->psycho_regs->iommu_control = control;
return memory_start;
}
extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
+extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm);
+
+/*
+ * Poor man's PCI...
+ */
+__initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start))
+{
+ struct linux_prom64_registers pr_regs[2];
+ struct linux_psycho *sabre;
+ unsigned long ctrl;
+ int tsbsize, node, err;
+ u32 busrange[2];
+ u32 vdma[2];
+ u32 portid;
+ int bus;
+
+ sabre = (struct linux_psycho *)memory_start;
+ memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+
+ portid = prom_getintdefault(pnode, "upa-portid", 0xff);
+
+ memset(sabre, 0, sizeof(*sabre));
+
+ sabre->next = psycho_root;
+ psycho_root = sabre;
+
+ sabre->upa_portid = portid;
+ sabre->index = linux_num_psycho++;
+
+ /*
+ * Map in SABRE register set and report the presence of this SABRE.
+ */
+ err = prom_getproperty(pnode, "reg",
+ (char *)&pr_regs[0], sizeof(pr_regs));
+ if(err == 0 || err == -1) {
+ prom_printf("SABRE: Error, cannot get U2P registers "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ /*
+ * First REG in property is base of entire SABRE register space.
+ */
+ sabre->psycho_regs =
+ sparc_alloc_io((pr_regs[0].phys_addr & 0xffffffff),
+ NULL, sizeof(struct psycho_regs),
+ "SABRE Registers",
+ (pr_regs[0].phys_addr >> 32), 0);
+ if(sabre->psycho_regs == NULL) {
+ prom_printf("SABRE: Error, cannot map SABRE main registers.\n");
+ prom_halt();
+ }
+
+ printk("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs);
+#ifdef PROM_DEBUG
+ dprintf("PCI: Found SABRE, main regs at %p\n", sabre->psycho_regs);
+#endif
+
+ ctrl = sabre->psycho_regs->pci_a_control;
+ ctrl = (1UL << 36) | (1UL << 34) | (1UL << 21) | (1UL << 8) | 0x0fUL;
+ sabre->psycho_regs->pci_a_control = ctrl;
+
+ /* Now map in PCI config space for entire SABRE. */
+ sabre->pci_config_space =
+ sparc_alloc_io(((pr_regs[0].phys_addr & 0xffffffff)
+ + 0x01000000),
+ NULL, 0x01000000,
+ "PCI Config Space",
+ (pr_regs[0].phys_addr >> 32), 0);
+ if(sabre->pci_config_space == NULL) {
+ prom_printf("SABRE: Error, cannot map PCI config space.\n");
+ prom_halt();
+ }
+
+ /* Report some more info. */
+ printk("SABRE: PCI config space at %p\n", sabre->pci_config_space);
+#ifdef PROM_DEBUG
+ dprintf("SABRE: PCI config space at %p\n", sabre->pci_config_space);
+#endif
+
+ err = prom_getproperty(pnode, "virtual-dma",
+ (char *)&vdma[0], sizeof(vdma));
+ if(err == 0 || err == -1) {
+ prom_printf("SABRE: Error, cannot get virtual-dma property "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ switch(vdma[1]) {
+ case 0x20000000:
+ tsbsize = 8;
+ break;
+ case 0x40000000:
+ tsbsize = 16;
+ break;
+ case 0x80000000:
+ tsbsize = 32;
+ break;
+ default:
+ prom_printf("SABRE: strange virtual-dma size.\n");
+ prom_halt();
+ }
+
+ memory_start = psycho_iommu_init(sabre, tsbsize, memory_start);
+ pci_dvma_offset = vdma[0];
+
+ printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
+#ifdef PROM_DEBUG
+ dprintf("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
+#endif
+
+ err = prom_getproperty(pnode, "bus-range",
+ (char *)&busrange[0], sizeof(busrange));
+ if(err == 0 || err == -1) {
+ prom_printf("SIMBA: Error, cannot get PCI bus-range "
+ " from PROM.\n");
+ prom_halt();
+ }
+
+ sabre->pci_first_busno = busrange[0];
+ sabre->pci_last_busno = busrange[1];
+ sabre->pci_bus = &pci_root;
+
+ /*
+ * Handle config space reads through any Simba on APB.
+ */
+ for (bus = sabre->pci_first_busno; bus <= sabre->pci_last_busno; bus++)
+ bus2pbm[bus] = &sabre->pbm_A;
+
+ /*
+ * Look for APB underneath.
+ */
+ node = prom_getchild(pnode);
+ while ((node = prom_searchsiblings(node, "pci"))) {
+ struct linux_pbm_info *pbm;
+ char namebuf[128];
+
+ err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
+ if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
+ goto next_pci;
+
+ err = prom_getproperty(node, "bus-range",
+ (char *)&busrange[0], sizeof(busrange));
+ if(err == 0 || err == -1) {
+ prom_printf("SIMBA: Error, cannot get PCI bus-range "
+ " from PROM.\n");
+ prom_halt();
+ }
+
+ if (busrange[0] == 1)
+ pbm = &sabre->pbm_B;
+ else
+ pbm = &sabre->pbm_A;
+
+ pbm->parent = sabre;
+ pbm->IO_assignments = NULL;
+ pbm->MEM_assignments = NULL;
+ pbm->prom_node = node;
+
+ prom_getstring(node, "name", namebuf, sizeof(namebuf));
+ strcpy(pbm->prom_name, namebuf);
+
+ /* Now the ranges. */
+ prom_pbm_ranges_init(pnode, pbm);
+ prom_pbm_intmap_init(node, pbm);
+
+ pbm->pci_first_busno = busrange[0];
+ pbm->pci_last_busno = busrange[1];
+ memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+
+ for (bus = pbm->pci_first_busno;
+ bus <= pbm->pci_last_busno; bus++)
+ bus2pbm[bus] = pbm;
-unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+ next_pci:
+ node = prom_getsibling(node);
+ if (!node)
+ break;
+ }
+
+ return memory_start;
+}
+
+__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
{
struct linux_prom64_registers pr_regs[3];
struct linux_psycho *psycho;
@@ -144,9 +350,9 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
u32 portid;
int node;
- printk("PSYCHO: Probing for controllers.\n");
+ printk("PCI: Probing for controllers.\n");
#ifdef PROM_DEBUG
- dprintf("PSYCHO: Probing for controllers.\n");
+ dprintf("PCI: Probing for controllers.\n");
#endif
memory_start = long_align(memory_start);
@@ -157,6 +363,12 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
u32 busrange[2];
int err, is_pbm_a;
+ err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
+ if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) {
+ memory_start = sabre_init(node, memory_start);
+ goto next_pci;
+ }
+
psycho = (struct linux_psycho *)memory_start;
portid = prom_getintdefault(node, "upa-portid", 0xff);
@@ -200,34 +412,30 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
* Third REG in property is base of entire PSYCHO
* register space.
*/
- psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
- NULL, sizeof(struct psycho_regs),
- "PSYCHO Registers",
- (pr_regs[2].phys_addr >> 32), 0);
+ psycho->psycho_regs =
+ sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
+ NULL, sizeof(struct psycho_regs),
+ "PSYCHO Registers",
+ (pr_regs[2].phys_addr >> 32), 0);
if(psycho->psycho_regs == NULL) {
prom_printf("PSYCHO: Error, cannot map PSYCHO "
"main registers.\n");
prom_halt();
}
- printk("PSYCHO: Found controller, main regs at %p\n",
+ printk("PCI: Found PSYCHO, main regs at %p\n",
psycho->psycho_regs);
#ifdef PROM_DEBUG
- dprintf("PSYCHO: Found controller, main regs at %p\n",
+ dprintf("PCI: Found PSYCHO, main regs at %p\n",
psycho->psycho_regs);
#endif
psycho->psycho_regs->irq_retry = 0xff;
-#if 0
- psycho->psycho_regs->ecc_control |= 1;
- psycho->psycho_regs->sbuf_a_control = 0;
- psycho->psycho_regs->sbuf_b_control = 0;
-#endif
-
/* Now map in PCI config space for entire PSYCHO. */
psycho->pci_config_space =
- sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
+ sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)
+ + 0x01000000),
NULL, 0x01000000,
"PCI Config Space",
(pr_regs[2].phys_addr >> 32), 0);
@@ -244,7 +452,8 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
psycho->pci_config_space);
#endif
- memory_start = psycho_iommu_init(psycho, memory_start);
+ memory_start = psycho_iommu_init(psycho, 32, memory_start);
+ pci_dvma_offset = 0x80000000UL;
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
@@ -268,6 +477,7 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
/* Now the ranges. */
prom_pbm_ranges_init(node, pbm);
+ prom_pbm_intmap_init(node, pbm);
/* Finally grab the pci bus root array for this pbm after
* having found the bus range existing under it.
@@ -282,6 +492,7 @@ unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
pbm->pci_last_busno = busrange[1];
memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+ next_pci:
node = prom_getsibling(node);
if(!node)
break;
@@ -308,54 +519,18 @@ int pcibios_present(void)
return psycho_root != NULL;
}
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->vendor == vendor && dev->device == device_id) {
- if (curr == index) {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *devfn)
-{
- unsigned int curr = 0;
- struct pci_dev *dev;
-
- for (dev = pci_devices; dev; dev = dev->next) {
- if (dev->class == class_code) {
- if (curr == index) {
- *devfn = dev->devfn;
- *bus = dev->bus->number;
- return PCIBIOS_SUCCESSFUL;
- }
- ++curr;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm,
unsigned long start,
- int io)
+ unsigned int offset, int io)
{
struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
- while(vp) {
- if(vp->end > start)
+ while (vp) {
+ if (offset && (vp->offset != offset))
+ goto next;
+ if (vp->end >= start)
break;
+ next:
vp = vp->next;
}
return vp;
@@ -391,7 +566,7 @@ static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new,
/* Check for programming errors. */
if(vp &&
((vp->start >= new->start && vp->start < new->end) ||
- ((vp->end - 1) >= new->start && (vp->end - 1) < new->end))) {
+ (vp->end >= new->start && vp->end < new->end))) {
prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n",
io ? "IO" : "MEM");
prom_printf("pci_add_vma: vp[%016lx:%016lx] "
@@ -414,7 +589,7 @@ static inline void pci_init_alloc_fini(void)
pci_alloc_arena = NULL;
}
-static void *pci_init_alloc(int size)
+__initfunc(static void *pci_init_alloc(int size))
{
unsigned long start = long_align(*pci_alloc_arena);
void *mp = (void *)start;
@@ -439,8 +614,8 @@ static inline struct pcidev_cookie *pci_devcookie_alloc(void)
}
-static void
-pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
+__initfunc(static void
+pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus))
{
unsigned int devfn, l, class;
unsigned char hdr_type = 0;
@@ -487,7 +662,7 @@ pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
}
}
-static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
+__initfunc(static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus))
{
unsigned int nbus;
@@ -513,7 +688,79 @@ static void pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
}
-static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
+__initfunc(static void apb_init(struct linux_psycho *sabre))
+{
+ struct pci_dev *pdev;
+ unsigned short stmp;
+ unsigned int itmp;
+
+ 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);
+
+ pci_write_config_word(pdev, PCI_STATUS, 0xffff);
+ pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
+
+ pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp);
+ stmp = PCI_BRIDGE_CTL_MASTER_ABORT |
+ PCI_BRIDGE_CTL_SERR |
+ PCI_BRIDGE_CTL_PARITY;
+ pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp);
+
+ pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp);
+ itmp = APB_PCI_CTL_HIGH_SERR |
+ APB_PCI_CTL_HIGH_ARBITER_EN;
+ pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp);
+
+ pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
+ itmp = APB_PCI_CTL_LOW_ARB_PARK |
+ APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
+ pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
+
+ /*
+ * Setup Registers for Guaranteed Completion.
+ */
+ 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);
+ }
+ }
+}
+
+__initfunc(static void sabre_probe(struct linux_psycho *sabre,
+ unsigned long *mstart))
+{
+ struct pci_bus *pbus = sabre->pci_bus;
+ static unsigned char busno = 0;
+
+ pbus->number = pbus->secondary = busno;
+ pbus->sysdata = sabre;
+
+ pbus->subordinate = pci_scan_bus(pbus, mstart);
+ busno = pbus->subordinate + 1;
+
+ for(pbus = pbus->children; pbus; pbus = pbus->next) {
+ if (pbus->number == sabre->pbm_A.pci_first_busno)
+ memcpy(&sabre->pbm_A.pci_bus, pbus, sizeof(*pbus));
+ if (pbus->number == sabre->pbm_B.pci_first_busno)
+ memcpy(&sabre->pbm_B.pci_bus, pbus, sizeof(*pbus));
+ }
+
+ apb_init(sabre);
+}
+
+
+__initfunc(static void pbm_probe(struct linux_pbm_info *pbm,
+ unsigned long *mstart))
{
static struct pci_bus *pchain = NULL;
struct pci_bus *pbus = &pbm->pci_bus;
@@ -552,9 +799,9 @@ static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
}
}
-static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- int node)
+__initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
+ struct pci_dev *pdev,
+ int node))
{
struct linux_prom_pci_registers pregs[PROMREG_MAX];
int err;
@@ -583,7 +830,7 @@ static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
return 0;
}
-static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev)
+__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev))
{
struct pcidev_cookie *pcp;
int node = prom_getchild(pbm->prom_node);
@@ -597,24 +844,37 @@ static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev)
pdev->sysdata = pcp;
}
-static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
+__initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus,
+ struct linux_pbm_info *pbm))
{
- struct pci_bus *pbtmp, *pbus = &pbm->pci_bus;
struct pci_dev *pdev;
- for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children)
- pbtmp->sysdata = pbm;
+ pbus->sysdata = pbm;
+
+ for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ pdev_cookie_fillin(pbm, pdev);
+
+ for(pbus = pbus->children; pbus; pbus = pbus->next)
+ fill_in_pbm_cookies(pbus, pbm);
+}
+
+__initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre))
+{
+ struct pci_bus *pbus = sabre->pci_bus;
- for( ; pbus; pbus = pbus->children)
- for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_cookie_fillin(pbm, pdev);
+ for(pbus = pbus->children; pbus; pbus = pbus->next) {
+ if (pbus->number == sabre->pbm_A.pci_first_busno)
+ pdev_cookie_fillin(&sabre->pbm_A, pbus->self);
+ else if (pbus->number == sabre->pbm_B.pci_first_busno)
+ pdev_cookie_fillin(&sabre->pbm_B, pbus->self);
+ }
}
/* Walk PROM device tree under PBM, looking for 'assigned-address'
* properties, and recording them in pci_vma's linked in via
* PBM->assignments.
*/
-static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)
+__initfunc(static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs))
{
struct linux_prom_ebus_ranges erng[PROMREG_MAX];
int err, iter;
@@ -632,18 +892,26 @@ static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *are
ap->phys_hi = ep->parent_phys_hi;
ap->phys_mid = ep->parent_phys_mid;
ap->phys_lo = ep->parent_phys_lo;
+
+ ap->size_hi = 0;
+ ap->size_lo = ep->size;
}
return err;
}
-static void assignment_process(struct linux_pbm_info *pbm, int node)
+__initfunc(static void assignment_process(struct linux_pbm_info *pbm, int node))
{
struct linux_prom_pci_registers aregs[PROMREG_MAX];
char pname[256];
int err, iter, numa;
err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname));
- if(strncmp(pname, "ebus", 4) == 0) {
+ if (err > 0)
+ pname[err] = 0;
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%s: %s\n", __FUNCTION__, err > 0 ? pname : "???");
+#endif
+ if(strcmp(pname, "ebus") == 0) {
numa = gimme_ebus_assignments(node, &aregs[0]);
} else {
err = prom_getproperty(node, "assigned-addresses",
@@ -653,7 +921,7 @@ static void assignment_process(struct linux_pbm_info *pbm, int node)
if(err == 0 || err == -1)
return;
- numa = (err / sizeof(struct linux_prom_pci_ranges));
+ numa = (err / sizeof(struct linux_prom_pci_registers));
}
for(iter = 0; iter < numa; iter++) {
@@ -667,8 +935,6 @@ static void assignment_process(struct linux_pbm_info *pbm, int node)
io = (space == 1);
breg = (ap->phys_hi & 0xff);
- if(breg == PCI_ROM_ADDRESS)
- continue;
vp = pci_vma_alloc();
@@ -677,21 +943,20 @@ static void assignment_process(struct linux_pbm_info *pbm, int node)
* XXX either due to it's layout so...
*/
vp->start = ap->phys_lo;
- vp->end = vp->start + ap->size_lo;
- vp->base_reg = breg;
-
- /* Sanity */
- if(io && (vp->end & ~(0xffff))) {
- prom_printf("assignment_process: Out of range PCI I/O "
- "[%08lx:%08lx]\n", vp->start, vp->end);
- prom_halt();
- }
+ vp->end = vp->start + ap->size_lo - 1;
+ vp->offset = (ap->phys_hi & 0xffffff);
pci_add_vma(pbm, vp, io);
+
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%s: BaseReg %02x", pname, breg);
+ dprintf(" %s vma [%08x,%08x]\n",
+ io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
+#endif
}
}
-static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
+__initfunc(static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node))
{
while(node) {
int child = prom_getchild(node);
@@ -704,17 +969,112 @@ static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
}
}
-static void record_assignments(struct linux_pbm_info *pbm)
+static inline void record_assignments(struct linux_pbm_info *pbm)
{
+ struct pci_vma *vp;
+
+ if (pbm->parent->pci_bus) {
+ /*
+ * Disallow anything that is not in our IO/MEM map on SIMBA.
+ */
+ struct pci_bus *pbus = pbm->parent->pci_bus;
+ struct pci_dev *pdev;
+ unsigned char map;
+ int bit;
+
+ for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ if (!pcp) {
+ prom_printf("record_assignments: "
+ "no pcidev_cookie for pdev %02x\n",
+ pdev->devfn);
+ prom_halt();
+ }
+ if (pcp->pbm == pbm)
+ break;
+ }
+
+ if (!pdev) {
+ prom_printf("record_assignments: no pdev for PBM\n");
+ prom_halt();
+ }
+
+ pci_read_config_byte(pdev, APB_IO_ADDRESS_MAP, &map);
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%s: IO %02x\n", __FUNCTION__, map);
+#endif
+ for (bit = 0; bit < 8; bit++) {
+ if (!(map & (1 << bit))) {
+ vp = pci_vma_alloc();
+ vp->start = (bit << 21);
+ vp->end = vp->start + (1 << 21) - 1;
+ vp->offset = 0;
+ pci_add_vma(pbm, vp, 1);
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%s: IO prealloc vma [%08x,%08x]\n",
+ __FUNCTION__, vp->start, vp->end);
+#endif
+ }
+ }
+ pci_read_config_byte(pdev, APB_MEM_ADDRESS_MAP, &map);
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%s: MEM %02x\n", __FUNCTION__, map);
+#endif
+ for (bit = 0; bit < 8; bit++) {
+ if (!(map & (1 << bit))) {
+ vp = pci_vma_alloc();
+ vp->start = (bit << 29);
+ vp->end = vp->start + (1 << 29) - 1;
+ vp->offset = 0;
+ pci_add_vma(pbm, vp, 0);
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%s: MEM prealloc vma [%08x,%08x]\n",
+ __FUNCTION__, vp->start, vp->end);
+#endif
+ }
+ }
+ }
+
assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node));
+
+ /*
+ * Protect ISA IO space from being used.
+ */
+ vp = pci_find_vma(pbm, 0, 0, 1);
+ if (!vp || 0x400 <= vp->start) {
+ vp = pci_vma_alloc();
+ vp->start = 0;
+ vp->end = vp->start + 0x400 - 1;
+ vp->offset = 0;
+ pci_add_vma(pbm, vp, 1);
+ }
+
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("PROM IO assignments for PBM %s:\n",
+ pbm == &pbm->parent->pbm_A ? "A" : "B");
+ vp = pbm->IO_assignments;
+ while (vp) {
+ dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end,
+ vp->offset ? "Register" : "Unmapped");
+ vp = vp->next;
+ }
+ dprintf("PROM MEM assignments for PBM %s:\n",
+ pbm == &pbm->parent->pbm_A ? "A" : "B");
+ vp = pbm->MEM_assignments;
+ while (vp) {
+ dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end,
+ vp->offset ? "Register" : "Unmapped");
+ vp = vp->next;
+ }
+#endif
}
-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)
+__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))
{
int preg, rng;
int IO_seen = 0;
@@ -724,34 +1084,39 @@ static void fixup_regs(struct pci_dev *pdev,
struct linux_prom_pci_registers *ap = NULL;
int bustype = (pregs[preg].phys_hi >> 24) & 0x3;
int bsreg, brindex;
+ unsigned int rtmp;
u64 pci_addr;
if(bustype == 0) {
/* Config space cookie, nothing to do. */
if(preg != 0)
- printk("%s: strange, config space not 0\n",
- __FUNCTION__);
+ printk("%s %02x.%02x [%04x,%04x]: "
+ "strange, config space not 0\n",
+ __FUNCTION__,
+ pdev->bus->number, pdev->devfn,
+ pdev->vendor, pdev->device);
continue;
} else if(bustype == 3) {
/* XXX add support for this... */
- printk("%s: Warning, ignoring 64-bit PCI memory space, "
+ printk("%s %02x.%02x [%04x,%04x]: "
+ "Warning, ignoring 64-bit PCI memory space, "
"tell Eddie C. Dost (ecd@skynet.be).\n",
- __FUNCTION__);
+ __FUNCTION__,
+ pdev->bus->number, pdev->devfn,
+ pdev->vendor, pdev->device);
continue;
}
- bsreg = (pregs[preg].phys_hi & 0xff);
- /* We can safely ignore these. */
- if(bsreg == PCI_ROM_ADDRESS)
- continue;
+ bsreg = (pregs[preg].phys_hi & 0xff);
/* Sanity */
if((bsreg < PCI_BASE_ADDRESS_0) ||
- (bsreg > (PCI_BASE_ADDRESS_5 + 4)) ||
+ ((bsreg > (PCI_BASE_ADDRESS_5 + 4)) && (bsreg != PCI_ROM_ADDRESS)) ||
(bsreg & 3)) {
- printk("%s: [%04x:%04x]: "
+ printk("%s %02x.%02x [%04x:%04x]: "
"Warning, ignoring bogus basereg [%x]\n",
- __FUNCTION__, pdev->vendor, pdev->device, bsreg);
+ __FUNCTION__, pdev->bus->number, pdev->devfn,
+ pdev->vendor, pdev->device, bsreg);
printk(" PROM reg: %08x.%08x.%08x %08x.%08x\n",
pregs[preg].phys_hi, pregs[preg].phys_mid,
pregs[preg].phys_lo, pregs[preg].size_hi,
@@ -798,7 +1163,16 @@ static void fixup_regs(struct pci_dev *pdev,
/* AIEEE */
prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n");
}
- pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
+ if (bsreg == PCI_ROM_ADDRESS) {
+ pdev->rom_address = (unsigned long)__va(pci_addr);
+ pdev->rom_address |= 1;
+ /*
+ * Enable access to the ROM.
+ */
+ pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp);
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp | 1);
+ } else
+ pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
/* Preserve I/O space bit. */
if(bustype == 0x1) {
@@ -811,15 +1185,18 @@ static void fixup_regs(struct pci_dev *pdev,
/* Now handle assignments PROM did not take care of. */
if(nregs) {
+ unsigned int rtmp, ridx;
+ unsigned int offset, base;
+ struct pci_vma *vp;
+ u64 pci_addr;
int breg;
for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) {
- unsigned int rtmp, ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
- unsigned int base = (unsigned int)pdev->base_address[ridx];
- struct pci_vma *vp;
- u64 pci_addr;
int io;
+ ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
+ base = (unsigned int)pdev->base_address[ridx];
+
if(pdev->base_address[ridx] > PAGE_OFFSET)
continue;
@@ -827,19 +1204,14 @@ static void fixup_regs(struct pci_dev *pdev,
base &= ~((io ?
PCI_BASE_ADDRESS_IO_MASK :
PCI_BASE_ADDRESS_MEM_MASK));
- vp = pci_find_vma(pbm, base, io);
+ offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
+ vp = pci_find_vma(pbm, base, offset, io);
if(!vp || vp->start > base) {
unsigned int size, new_base;
- pcibios_read_config_dword(pdev->bus->number,
- pdev->devfn,
- breg, &rtmp);
- pcibios_write_config_dword(pdev->bus->number,
- pdev->devfn,
- breg, 0xffffffff);
- pcibios_read_config_dword(pdev->bus->number,
- pdev->devfn,
- breg, &size);
+ pci_read_config_dword(pdev, breg, &rtmp);
+ pci_write_config_dword(pdev, breg, 0xffffffff);
+ pci_read_config_dword(pdev, breg, &size);
if(io)
size &= ~1;
size = (~(size) + 1);
@@ -847,7 +1219,8 @@ static void fixup_regs(struct pci_dev *pdev,
continue;
new_base = 0;
- for(vp=pci_find_vma(pbm,new_base,io); ; vp=vp->next) {
+ for(vp = pci_find_vma(pbm, new_base, 0, io); ;
+ vp = vp->next) {
if(!vp || new_base + size <= vp->start)
break;
new_base = (vp->end + (size - 1)) & ~(size-1);
@@ -859,26 +1232,27 @@ static void fixup_regs(struct pci_dev *pdev,
}
vp = pci_vma_alloc();
vp->start = new_base;
- vp->end = vp->start + size;
- vp->base_reg = breg;
-
- /* Sanity */
- if(io && vp->end & ~(0xffff)) {
- prom_printf("PCI: Out of range PCI I/O "
- "[%08lx:%08lx] during fixup\n",
- vp->start, vp->end);
- prom_halt();
- }
+ vp->end = vp->start + size - 1;
+ vp->offset = offset;
+
pci_add_vma(pbm, vp, io);
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%02x.%02x.%x: BaseReg %02x",
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn),
+ breg);
+ dprintf(" %s vma [%08x,%08x]\n",
+ io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
+#endif
rtmp = new_base;
+ pci_read_config_dword(pdev, breg, &base);
if(io)
- rtmp |= (rtmp & PCI_BASE_ADDRESS_IO_MASK);
+ rtmp |= (base & ~PCI_BASE_ADDRESS_IO_MASK);
else
- rtmp |= (rtmp & PCI_BASE_ADDRESS_MEM_MASK);
- pcibios_write_config_dword(pdev->bus->number,
- pdev->devfn,
- breg, rtmp);
+ rtmp |= (base & ~PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(pdev, breg, rtmp);
/* Apply PBM ranges and update pci_dev. */
pci_addr = new_base;
@@ -912,13 +1286,93 @@ static void fixup_regs(struct pci_dev *pdev,
}
}
}
+
+ /*
+ * Handle PCI_ROM_ADDRESS.
+ */
+ breg = PCI_ROM_ADDRESS;
+ base = (unsigned int)pdev->rom_address;
+
+ if(pdev->rom_address > PAGE_OFFSET)
+ goto rom_address_done;
+
+ base &= PCI_ROM_ADDRESS_MASK;
+ offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
+ vp = pci_find_vma(pbm, base, offset, 0);
+ if(!vp || vp->start > base) {
+ unsigned int size, new_base;
+
+ pci_read_config_dword(pdev, breg, &rtmp);
+ pci_write_config_dword(pdev, breg, 0xffffffff);
+ pci_read_config_dword(pdev, breg, &size);
+ size &= ~1;
+ size = (~(size) + 1);
+ if(!size)
+ goto rom_address_done;
+
+ new_base = 0;
+ for(vp = pci_find_vma(pbm, new_base, 0, 0); ; vp = vp->next) {
+ if(!vp || new_base + size <= vp->start)
+ break;
+ new_base = (vp->end + (size - 1)) & ~(size-1);
+ }
+ if(vp && (new_base + size > vp->start)) {
+ prom_printf("PCI: Impossible full MEM space.\n");
+ prom_halt();
+ }
+ vp = pci_vma_alloc();
+ vp->start = new_base;
+ vp->end = vp->start + size - 1;
+ vp->offset = offset;
+
+ pci_add_vma(pbm, vp, 0);
+
+#ifdef FIXUP_VMA_DEBUG
+ dprintf("%02x.%02x.%x: BaseReg %02x",
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn),
+ breg);
+ dprintf(" %s vma [%08x,%08x]\n",
+ "ROM", vp->start, vp->end);
+#endif
+
+ rtmp = new_base;
+ pci_read_config_dword(pdev, breg, &base);
+ rtmp |= (base & ~PCI_ROM_ADDRESS_MASK);
+ pci_write_config_dword(pdev, breg, rtmp);
+
+ /* Apply PBM ranges and update pci_dev. */
+ pci_addr = new_base;
+ for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp;
+ int rspace;
+
+ rp = &pbm->pbm_ranges[rng];
+ rspace = (rp->child_phys_hi >> 24) & 3;
+ if(rspace != 2)
+ continue;
+ pci_addr += ((u64)rp->parent_phys_lo);
+ pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
+ break;
+ }
+ if(rng == pbm->num_pbm_ranges) {
+ /* AIEEE */
+ prom_printf("fixup_doit: YIEEE, cannot find "
+ "PBM ranges\n");
+ }
+ pdev->rom_address = (unsigned long)__va(pci_addr);
+
+ pdev->rom_address |= (base & ~PCI_ROM_ADDRESS_MASK);
+ MEM_seen = 1;
+ }
+ rom_address_done:
+
}
if(IO_seen || MEM_seen) {
unsigned int l;
- pcibios_read_config_dword(pdev->bus->number,
- pdev->devfn,
- PCI_COMMAND, &l);
+ pci_read_config_dword(pdev, PCI_COMMAND, &l);
#ifdef FIXUP_REGS_DEBUG
dprintf("[");
#endif
@@ -937,9 +1391,7 @@ static void fixup_regs(struct pci_dev *pdev,
#ifdef FIXUP_REGS_DEBUG
dprintf("]");
#endif
- pcibios_write_config_dword(pdev->bus->number,
- pdev->devfn,
- PCI_COMMAND, l);
+ pci_write_config_dword(pdev, PCI_COMMAND, l);
}
#ifdef FIXUP_REGS_DEBUG
@@ -955,7 +1407,7 @@ static void fixup_regs(struct pci_dev *pdev,
#define imap_offset(__member) \
((unsigned long)(&(((struct psycho_regs *)0)->__member)))
-static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
+__initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino))
{
unsigned int bus, slot;
@@ -963,17 +1415,20 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
slot = (ino & 0x0c) >> 2;
if(bus == 0) {
- /* Perform a sanity check, we might as well.
- * PBM A only has 2 PCI slots.
- */
- if(slot > 1) {
- prom_printf("pcislot_imap: Bogus slot on PBM A (%ld)\n", slot);
- prom_halt();
- }
- if(slot == 0)
+ switch(slot) {
+ case 0:
return imap_offset(imap_a_slot0);
- else
+ case 1:
return imap_offset(imap_a_slot1);
+ 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();
+ }
} else {
switch(slot) {
case 0:
@@ -988,13 +1443,12 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n",
bus, slot);
prom_halt();
- return 0; /* Make gcc happy */
- };
+ }
}
}
/* Exported for EBUS probing layer. */
-unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino)
+__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino))
{
unsigned long imap_off, ign, ino;
@@ -1089,9 +1543,62 @@ unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino)
return pci_irq_encode(imap_off, pbm->parent->index, ign, ino);
}
-static void fixup_irq(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- int node)
+__initfunc(static int 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)
+ 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;
+
+ if (!pcp)
+ goto out;
+
+ node = pcp->prom_node;
+
+ i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg));
+ if(i == 0 || i == -1)
+ goto out;
+
+ preg = &ppreg;
+ }
+
+ hi = preg->phys_hi & pbm->pbm_intmask.phys_hi;
+ mid = preg->phys_mid & pbm->pbm_intmask.phys_mid;
+ lo = preg->phys_lo & pbm->pbm_intmask.phys_lo;
+ irq = *interrupt & pbm->pbm_intmask.interrupt;
+ for (i = 0; i < pbm->num_pbm_intmap; i++) {
+ if ((pbm->pbm_intmap[i].phys_hi == hi) &&
+ (pbm->pbm_intmap[i].phys_mid == mid) &&
+ (pbm->pbm_intmap[i].phys_lo == lo) &&
+ (pbm->pbm_intmap[i].interrupt == irq)) {
+ *interrupt = pbm->pbm_intmap[i].cinterrupt;
+ return *interrupt;
+ }
+ }
+
+out:
+ prom_printf("pbm_intmap_match: IRQ [%08x.%08x.%08x.%08x] "
+ "not found in interrupt-map\n", preg->phys_hi,
+ preg->phys_mid, preg->phys_lo, *interrupt);
+ prom_halt();
+}
+
+__initfunc(static void 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;
@@ -1102,13 +1609,24 @@ static void fixup_irq(struct pci_dev *pdev,
#endif
err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq));
if(err == 0 || err == -1) {
- prom_printf("fixup_irq: No interrupts property for dev[%04x:%04x]\n",
- pdev->vendor, pdev->device);
- prom_halt();
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("No interrupts property.\n");
+#endif
+ pdev->irq = 0;
+ return;
}
+ /* See if we find a matching interrupt-map entry. */
+ if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
+ pdev->irq = psycho_irq_build(pbm,
+ (pbm->parent->upa_portid << 6)
+ | prom_irq);
+#ifdef FIXUP_IRQ_DEBUG
+ dprintf("interrupt-map specified prom_irq[%x] pdev->irq[%x]",
+ prom_irq, pdev->irq);
+#endif
/* See if fully specified already (ie. for onboard devices like hme) */
- if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
+ } else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
pdev->irq = psycho_irq_build(pbm, prom_irq);
#ifdef FIXUP_IRQ_DEBUG
dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
@@ -1147,7 +1665,7 @@ static void fixup_irq(struct pci_dev *pdev,
slot = (pdev->bus->self->devfn >> 3) - 2;
/* Use low slot number bits of child as IRQ line. */
- line = (line + ((pdev->devfn >> 3) - 4)) % 4;
+ line = (pdev->devfn >> 3) & 0x03;
}
slot = (slot << 2);
@@ -1159,16 +1677,10 @@ static void fixup_irq(struct pci_dev *pdev,
do {
unsigned char iline, ipin;
- (void)pcibios_read_config_byte(pdev->bus->number,
- pdev->devfn,
- PCI_INTERRUPT_PIN,
- &ipin);
- (void)pcibios_read_config_byte(pdev->bus->number,
- pdev->devfn,
- PCI_INTERRUPT_LINE,
- &iline);
- dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] "
- "iline[%x] ipin[%x] prom_irq[%x]",
+ pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &ipin);
+ pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &iline);
+ dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] "
+ "irq[%x] iline[%x] ipin[%x] prom_irq[%x]",
portid, bus>>4, slot>>2, line, pdev->irq,
iline, ipin, prom_irq);
} while(0);
@@ -1178,21 +1690,19 @@ static void fixup_irq(struct pci_dev *pdev,
/*
* Write the INO to config space PCI_INTERRUPT_LINE.
*/
- (void)pcibios_write_config_byte(pdev->bus->number,
- pdev->devfn,
- PCI_INTERRUPT_LINE,
- pdev->irq & PCI_IRQ_INO);
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
+ pdev->irq & PCI_IRQ_INO);
#ifdef FIXUP_IRQ_DEBUG
dprintf("\n");
#endif
}
-static void fixup_doit(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *pregs,
- int nregs,
- int node)
+__initfunc(static void 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;
@@ -1209,12 +1719,12 @@ static void fixup_doit(struct pci_dev *pdev,
fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa);
/* Next, fixup interrupt numbers. */
- fixup_irq(pdev, pbm, node);
+ fixup_irq(pdev, pbm, &pregs[0], node);
}
-static void fixup_pci_dev(struct pci_dev *pdev,
- struct pci_bus *pbus,
- struct linux_pbm_info *pbm)
+__initfunc(static void 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;
@@ -1225,18 +1735,12 @@ static void fixup_pci_dev(struct pci_dev *pdev,
unsigned short cmd;
/* First, enable bus mastering. */
- pcibios_read_config_word(pdev->bus->number,
- pdev->devfn,
- PCI_COMMAND, &cmd);
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pdev->bus->number,
- pdev->devfn,
- PCI_COMMAND, cmd);
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
/* Now, set cache line size to 64-bytes. */
- pcibios_write_config_byte(pdev->bus->number,
- pdev->devfn,
- PCI_CACHE_LINE_SIZE, 64);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64);
}
/* Ignore if this is one of the PBM's, EBUS, or a
@@ -1246,8 +1750,17 @@ static void fixup_pci_dev(struct pci_dev *pdev,
if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) ||
(pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) ||
(pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
- (pcp == NULL))
+ (pcp == NULL)) {
+ /*
+ * Prevent access to PCI_ROM_ADDRESS, in case present
+ * as we don't fixup the address.
+ */
+ if (pdev->rom_address) {
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS, 0);
+ pdev->rom_address = 0;
+ }
return;
+ }
node = pcp->prom_node;
@@ -1260,20 +1773,30 @@ static void fixup_pci_dev(struct pci_dev *pdev,
nregs = (err / sizeof(pregs[0]));
fixup_doit(pdev, pbm, &pregs[0], nregs, node);
+
+ /* Enable bus mastering on IDE interfaces. */
+ if ((pdev->class >> 8 == PCI_CLASS_STORAGE_IDE)
+ && (pdev->class & 0x80)) {
+ unsigned short cmd;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ }
}
-static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
+__initfunc(static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm))
{
struct pci_dev *pdev;
for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
fixup_pci_dev(pdev, pbus, pbm);
- for(pbus = pbus->children; pbus; pbus = pbus->children)
+ for(pbus = pbus->children; pbus; pbus = pbus->next)
fixup_pci_bus(pbus, pbm);
}
-static void fixup_addr_irq(struct linux_pbm_info *pbm)
+__initfunc(static void fixup_addr_irq(struct linux_pbm_info *pbm))
{
struct pci_bus *pbus = &pbm->pci_bus;
@@ -1286,14 +1809,16 @@ 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.
*/
-static void psycho_final_fixup(struct linux_psycho *psycho)
+__initfunc(static void psycho_final_fixup(struct linux_psycho *psycho))
{
/* Second, fixup base address registers and IRQ lines... */
- fixup_addr_irq(&psycho->pbm_A);
- fixup_addr_irq(&psycho->pbm_B);
+ if (psycho->pbm_A.parent)
+ fixup_addr_irq(&psycho->pbm_A);
+ if (psycho->pbm_B.parent)
+ fixup_addr_irq(&psycho->pbm_B);
}
-unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end))
{
struct linux_psycho *psycho;
@@ -1312,11 +1837,16 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end
*/
for (psycho = psycho_root; psycho; psycho = psycho->next) {
- /* Probe busses under PBM B. */
- pbm_probe(&psycho->pbm_B, &memory_start);
-
- /* Probe busses under PBM A. */
- pbm_probe(&psycho->pbm_A, &memory_start);
+ /* Probe bus on builtin PCI. */
+ if (psycho->pci_bus)
+ sabre_probe(psycho, &memory_start);
+ else {
+ /* Probe busses under PBM B. */
+ pbm_probe(&psycho->pbm_B, &memory_start);
+
+ /* Probe busses under PBM A. */
+ pbm_probe(&psycho->pbm_A, &memory_start);
+ }
}
pci_init_alloc_init(&memory_start);
@@ -1327,8 +1857,13 @@ unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end
* a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
*/
for (psycho = psycho_root; psycho; psycho = psycho->next) {
- fill_in_pbm_cookies(&psycho->pbm_A);
- fill_in_pbm_cookies(&psycho->pbm_B);
+ if (psycho->pci_bus)
+ sabre_cookie_fillin(psycho);
+
+ fill_in_pbm_cookies(&psycho->pbm_A.pci_bus,
+ &psycho->pbm_A);
+ fill_in_pbm_cookies(&psycho->pbm_B.pci_bus,
+ &psycho->pbm_B);
/* See what OBP has taken care of already. */
record_assignments(&psycho->pbm_A);
@@ -1373,11 +1908,157 @@ pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus,
static inline int
out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn)
{
- return (((pbm == &pbm->parent->pbm_B) && PCI_SLOT(devfn) > 4) ||
- ((pbm == &pbm->parent->pbm_A) && PCI_SLOT(devfn) > 6) ||
+ return ((pbm->parent == 0) ||
+ ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 4) ||
+ ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 6) ||
(pci_probe_enable == 0));
}
+static inline int
+sabre_out_of_range(unsigned char devfn)
+{
+ return ((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
+ ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
+ (PCI_SLOT(devfn) > 1);
+}
+
+static int
+sabre_read_config_byte(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char *value)
+{
+ if (bus)
+ return pbm_read_config_byte(pbm, bus, devfn, where, value);
+
+ if (sabre_out_of_range(devfn)) {
+ *value = 0xff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ if (where < 8) {
+ unsigned short tmp;
+
+ pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
+ if (where & 1)
+ *value = tmp >> 8;
+ else
+ *value = tmp & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+ } else
+ return pbm_read_config_byte(pbm, bus, devfn, where, value);
+}
+
+static int
+sabre_read_config_word(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short *value)
+{
+ if (bus)
+ return pbm_read_config_word(pbm, bus, devfn, where, value);
+
+ if (sabre_out_of_range(devfn)) {
+ *value = 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ if (where < 8)
+ return pbm_read_config_word(pbm, bus, devfn, where, value);
+ else {
+ unsigned char tmp;
+
+ pbm_read_config_byte(pbm, bus, devfn, where, &tmp);
+ *value = tmp;
+ pbm_read_config_byte(pbm, bus, devfn, where + 1, &tmp);
+ *value |= tmp << 8;
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+static int
+sabre_read_config_dword(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned short tmp;
+
+ if (bus)
+ return pbm_read_config_dword(pbm, bus, devfn, where, value);
+
+ if (sabre_out_of_range(devfn)) {
+ *value = 0xffffffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ sabre_read_config_word(pbm, bus, devfn, where, &tmp);
+ *value = tmp;
+ sabre_read_config_word(pbm, bus, devfn, where + 2, &tmp);
+ *value |= tmp << 16;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+sabre_write_config_byte(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned char value)
+{
+ if (bus)
+ return pbm_write_config_byte(pbm, bus, devfn, where, value);
+
+ if (sabre_out_of_range(devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where < 8) {
+ unsigned short tmp;
+
+ pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
+ if (where & 1) {
+ value &= 0x00ff;
+ value |= tmp << 8;
+ } else {
+ value &= 0xff00;
+ value |= tmp;
+ }
+ return pbm_write_config_word(pbm, bus, devfn, where & ~1, tmp);
+ } else
+ return pbm_write_config_byte(pbm, bus, devfn, where, value);
+}
+
+static int
+sabre_write_config_word(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned short value)
+{
+ if (bus)
+ return pbm_write_config_word(pbm, bus, devfn, where, value);
+
+ if (sabre_out_of_range(devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where < 8)
+ return pbm_write_config_word(pbm, bus, devfn, where, value);
+ else {
+ pbm_write_config_byte(pbm, bus, devfn, where, value & 0xff);
+ pbm_write_config_byte(pbm, bus, devfn, where + 1, value >> 8);
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+static int
+sabre_write_config_dword(struct linux_pbm_info *pbm,
+ unsigned char bus, unsigned char devfn,
+ unsigned char where, unsigned int value)
+{
+ if (bus)
+ return pbm_write_config_dword(pbm, bus, devfn, where, value);
+
+ if (sabre_out_of_range(devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ sabre_write_config_word(pbm, bus, devfn, where, value & 0xffff);
+ sabre_write_config_word(pbm, bus, devfn, where + 2, value >> 16);
+ return PCIBIOS_SUCCESSFUL;
+}
+
static int
pbm_read_config_byte(struct linux_pbm_info *pbm,
unsigned char bus, unsigned char devfn,
@@ -1574,36 +2255,60 @@ pbm_write_config_dword(struct linux_pbm_info *pbm,
int pcibios_read_config_byte (unsigned char bus, unsigned char devfn,
unsigned char where, unsigned char *value)
{
- return pbm_read_config_byte(bus2pbm[bus], bus, devfn, where, value);
+ struct linux_pbm_info *pbm = bus2pbm[bus];
+
+ if (pbm && pbm->parent && pbm->parent->pci_bus)
+ return sabre_read_config_byte(pbm, bus, devfn, where, value);
+ return pbm_read_config_byte(pbm, bus, devfn, where, value);
}
int pcibios_read_config_word (unsigned char bus, unsigned char devfn,
unsigned char where, unsigned short *value)
{
- return pbm_read_config_word(bus2pbm[bus], bus, devfn, where, value);
+ struct linux_pbm_info *pbm = bus2pbm[bus];
+
+ if (pbm && pbm->parent && pbm->parent->pci_bus)
+ return sabre_read_config_word(pbm, bus, devfn, where, value);
+ return pbm_read_config_word(pbm, bus, devfn, where, value);
}
int pcibios_read_config_dword (unsigned char bus, unsigned char devfn,
unsigned char where, unsigned int *value)
{
- return pbm_read_config_dword(bus2pbm[bus], bus, devfn, where, value);
+ struct linux_pbm_info *pbm = bus2pbm[bus];
+
+ if (pbm && pbm->parent && pbm->parent->pci_bus)
+ return sabre_read_config_dword(pbm, bus, devfn, where, value);
+ return pbm_read_config_dword(pbm, bus, devfn, where, value);
}
int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
unsigned char where, unsigned char value)
{
- return pbm_write_config_byte(bus2pbm[bus], bus, devfn, where, value);
+ struct linux_pbm_info *pbm = bus2pbm[bus];
+
+ if (pbm && pbm->parent && pbm->parent->pci_bus)
+ return sabre_write_config_byte(pbm, bus, devfn, where, value);
+ return pbm_write_config_byte(pbm, bus, devfn, where, value);
}
int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
unsigned char where, unsigned short value)
{
+ struct linux_pbm_info *pbm = bus2pbm[bus];
+
+ if (pbm && pbm->parent && pbm->parent->pci_bus)
+ return sabre_write_config_word(pbm, bus, devfn, where, value);
return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value);
}
int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
unsigned char where, unsigned int value)
{
+ struct linux_pbm_info *pbm = bus2pbm[bus];
+
+ if (pbm && pbm->parent && pbm->parent->pci_bus)
+ return sabre_write_config_dword(pbm, bus, devfn, where, value);
return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value);
}
@@ -1692,4 +2397,9 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
return err;
}
+__initfunc(char *pcibios_setup(char *str))
+{
+ return str;
+}
+
#endif
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 932addbb4..cdc8f47de 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.18 1997/12/18 02:43:00 ecd Exp $
+/* $Id: setup.c,v 1.20 1998/02/24 17:02:39 jj Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -55,11 +55,6 @@ struct screen_info screen_info = {
unsigned int phys_bytes_of_ram, end_of_phys_memory;
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
- return memory_start;
-}
-
/* Typing sync at the prom prompt calls the function pointed to by
* the sync callback which I set to the following function.
* This should sync all filesystems and return, for now it just
@@ -413,14 +408,17 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
extern char *sparc_cpu_type[];
extern char *sparc_fpu_type[];
-extern char *smp_info(void);
-extern char *mmu_info(void);
+extern int smp_info(char *);
+extern int smp_bogo(char *);
+extern int mmu_info(char *);
int get_cpuinfo(char *buffer)
{
int cpuid=smp_processor_id();
+ int len;
- return sprintf(buffer, "cpu\t\t: %s\n"
+ len = sprintf(buffer,
+ "cpu\t\t: %s\n"
"fpu\t\t: %s\n"
"promlib\t\t: Version 3 Revision %d\n"
"prom\t\t: %d.%d.%d\n"
@@ -429,33 +427,22 @@ int get_cpuinfo(char *buffer)
"ncpus active\t: %d\n"
#ifndef __SMP__
"BogoMips\t: %lu.%02lu\n"
-#else
- "Cpu0Bogo\t: %lu.%02lu\n"
- "Cpu1Bogo\t: %lu.%02lu\n"
- "Cpu2Bogo\t: %lu.%02lu\n"
- "Cpu3Bogo\t: %lu.%02lu\n"
-#endif
- "%s"
-#ifdef __SMP__
- "%s"
#endif
,
sparc_cpu_type[cpuid],
sparc_fpu_type[cpuid],
prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
- linux_num_cpus, smp_num_cpus,
+ linux_num_cpus, smp_num_cpus
#ifndef __SMP__
- loops_per_sec/500000, (loops_per_sec/5000) % 100,
-#else
- cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100,
- cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100,
- cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100,
- cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100,
+ , loops_per_sec/500000, (loops_per_sec/5000) % 100
#endif
- mmu_info()
+ );
#ifdef __SMP__
- , smp_info()
+ len += smp_bogo(buffer + len);
#endif
- );
-
+ len += mmu_info(buffer + len);
+#ifdef __SMP__
+ len += smp_info(buffer + len);
+#endif
+ return len;
}
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 8ca15c80b..269ff413d 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.34 1997/12/15 15:04:49 jj Exp $
+/* $Id: signal32.c,v 1.35 1998/04/01 07:00:43 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -1023,6 +1023,7 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
spin_lock_irq(&current->sigmask_lock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
sigaddset(&current->blocked,signr);
+ recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
}
}
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 932534c05..ca2aa4360 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/head.h>
#include <asm/ptrace.h>
@@ -25,12 +26,14 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
#include <asm/uaccess.h>
+#include <asm/timer.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
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;
@@ -39,35 +42,46 @@ int smp_threads_ready = 0;
struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
-static unsigned char boot_cpu_id = 0;
+static unsigned char boot_cpu_id __initdata = 0;
static int smp_activated = 0;
volatile int cpu_number_map[NR_CPUS];
-volatile int cpu_logical_map[NR_CPUS];
+volatile int __cpu_logical_map[NR_CPUS];
struct klock_info klock_info = { KLOCK_CLEAR, 0 };
-void smp_setup(char *str, int *ints)
+__initfunc(void smp_setup(char *str, int *ints))
{
/* XXX implement me XXX */
}
-static char smp_buf[512];
+int smp_info(char *buf)
+{
+ int len = 7, i;
+
+ strcpy(buf, "State:\n");
+ for (i = 0; i < NR_CPUS; i++)
+ if(cpu_present_map & (1UL << i))
+ len += sprintf(buf + len,
+ "CPU%d:\t\t%s\n",
+ i, klock_info.akp == i ? "akp" : "online");
+ return len;
+}
-char *smp_info(void)
+int smp_bogo(char *buf)
{
- /* XXX not SMP safe and need to support up to 64 penguins */
- sprintf(smp_buf,
-" CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
-"State: %s\t\t%s\t\t%s\t\t%s\n",
-(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
-(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
-(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
-(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
- return smp_buf;
+ int len = 0, i;
+
+ for (i = 0; i < NR_CPUS; i++)
+ if(cpu_present_map & (1UL << i))
+ len += sprintf(buf + len,
+ "Cpu%dBogo\t: %lu.%02lu\n",
+ i, cpu_data[i].udelay_val / 500000,
+ (cpu_data[i].udelay_val / 5000) % 100);
+ return len;
}
-void smp_store_cpu_info(int id)
+__initfunc(void smp_store_cpu_info(int id))
{
cpu_data[id].udelay_val = loops_per_sec;
cpu_data[id].irq_count = 0;
@@ -80,7 +94,7 @@ void smp_store_cpu_info(int id)
extern void distribute_irqs(void);
-void smp_commence(void)
+__initfunc(void smp_commence(void))
{
distribute_irqs();
}
@@ -92,7 +106,7 @@ static volatile unsigned long callin_flag = 0;
extern void inherit_locked_prom_mappings(int save_p);
extern void cpu_probe(void);
-void smp_callin(void)
+__initfunc(void smp_callin(void))
{
int cpuid = hard_smp_processor_id();
@@ -156,22 +170,24 @@ extern struct prom_cpuinfo linux_cpus[NR_CPUS];
extern unsigned long smp_trampoline;
-void smp_boot_cpus(void)
+__initfunc(void smp_boot_cpus(void))
{
int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
+ boot_cpu_id = hard_smp_processor_id();
smp_tickoffset_init();
__sti();
cpu_present_map = 0;
for(i = 0; i < linux_num_cpus; i++)
- cpu_present_map |= (1UL << i);
+ cpu_present_map |= (1UL << linux_cpus[i].mid);
for(i = 0; i < NR_CPUS; i++) {
cpu_number_map[i] = -1;
- cpu_logical_map[i] = -1;
+ __cpu_logical_map[i] = -1;
}
cpu_number_map[boot_cpu_id] = 0;
- cpu_logical_map[0] = boot_cpu_id;
+ prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node;
+ __cpu_logical_map[0] = boot_cpu_id;
klock_info.akp = boot_cpu_id;
current->processor = boot_cpu_id;
smp_store_cpu_info(boot_cpu_id);
@@ -188,13 +204,18 @@ void smp_boot_cpus(void)
unsigned long entry = (unsigned long)(&smp_trampoline);
struct task_struct *p;
int timeout;
+ int no;
+ extern unsigned long phys_base;
- entry -= KERNBASE;
+ entry += phys_base - KERNBASE;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
callin_flag = 0;
- prom_startcpu(linux_cpus[i].prom_node,
+ for (no = 0; no < linux_num_cpus; no++)
+ if (linux_cpus[no].mid == i)
+ break;
+ prom_startcpu(linux_cpus[no].prom_node,
entry, ((unsigned long)p));
for(timeout = 0; timeout < 5000000; timeout++) {
if(callin_flag)
@@ -202,8 +223,9 @@ void smp_boot_cpus(void)
udelay(100);
}
if(callin_flag) {
- cpu_number_map[i] = i;
- cpu_logical_map[i] = i;
+ cpu_number_map[i] = cpucount;
+ prom_cpu_nodes[i] = linux_cpus[no].prom_node;
+ __cpu_logical_map[cpucount] = i;
} else {
cpucount--;
printk("Processor %d is stuck.\n", i);
@@ -248,9 +270,9 @@ 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, int cpu)
+static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu)
{
- u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70;
+ u64 result, target = (cpu << 14) | 0x70;
int stuck;
#ifdef XCALL_DEBUG
@@ -307,12 +329,15 @@ void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
if(smp_processors_ready) {
unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
- int i, ncpus = smp_num_cpus;
+ int i, ncpus = smp_num_cpus - 1;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- for(i = 0; i < ncpus; i++) {
- if(mask & (1UL << i))
+ for(i = 0; i < NR_CPUS; i++) {
+ if(mask & (1UL << i)) {
xcall_deliver(data0, data1, data2, pstate, i);
+ ncpus--;
+ }
+ if (!ncpus) break;
}
/* NOTE: Caller runs local copy on master. */
}
@@ -489,13 +514,14 @@ static inline void sparc64_do_profile(unsigned long pc)
#endif
}
-static unsigned long real_tick_offset, current_tick_offset;
+static unsigned long current_tick_offset;
#define prof_multiplier(__cpu) cpu_data[(__cpu)].multiplier
#define prof_counter(__cpu) cpu_data[(__cpu)].counter
extern void update_one_process(struct task_struct *p, unsigned long ticks,
- unsigned long user, unsigned long system);
+ unsigned long user, unsigned long system,
+ int cpu);
void smp_percpu_timer_interrupt(struct pt_regs *regs)
{
@@ -503,32 +529,62 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
int cpu = smp_processor_id();
int user = user_mode(regs);
+ /*
+ * Check for level 14 softint.
+ */
+ if (!(get_softint() & (1UL << 0))) {
+ extern void handler_irq(int, struct pt_regs *);
+
+ handler_irq(14, regs);
+ return;
+ }
+
clear_softint((1UL << 0));
do {
if(!user)
sparc64_do_profile(regs->tpc);
if(!--prof_counter(cpu)) {
+
+ if (cpu == boot_cpu_id) {
+ extern void irq_enter(int, int);
+ extern void irq_exit(int, int);
+
+ irq_enter(cpu, 0);
+ kstat.irqs[cpu][0]++;
+
+ timer_tick_interrupt(regs);
+
+ irq_exit(cpu, 0);
+ }
+
if(current->pid) {
- unsigned int *inc_me;
+ unsigned int *inc, *inc2;
- update_one_process(current, 1, user, !user);
+ update_one_process(current, 1, user, !user, cpu);
if(--current->counter < 0) {
current->counter = 0;
need_resched = 1;
}
if(user) {
- if(current->priority < DEF_PRIORITY)
- inc_me = &kstat.cpu_nice;
- else
- inc_me = &kstat.cpu_user;
+ if(current->priority < DEF_PRIORITY) {
+ inc = &kstat.cpu_nice;
+ inc2 = &kstat.per_cpu_nice[cpu];
+ } else {
+ inc = &kstat.cpu_user;
+ inc2 = &kstat.per_cpu_user[cpu];
+ }
} else {
- inc_me = &kstat.cpu_system;
+ inc = &kstat.cpu_system;
+ inc2 = &kstat.per_cpu_system[cpu];
}
- atomic_inc((atomic_t *)inc_me);
+ atomic_inc((atomic_t *)inc);
+ atomic_inc((atomic_t *)inc2);
}
+
prof_counter(cpu) = prof_multiplier(cpu);
}
+
__asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
"add %0, %2, %0\n\t"
"wr %0, 0x0, %%tick_cmpr\n\t"
@@ -538,12 +594,55 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
} while (tick >= compare);
}
-static void smp_setup_percpu_timer(void)
+__initfunc(static void smp_setup_percpu_timer(void))
{
int cpu = smp_processor_id();
prof_counter(cpu) = prof_multiplier(cpu) = 1;
+ if (cpu == boot_cpu_id) {
+ extern unsigned long tl0_itick;
+ extern unsigned long tl0_smp_itick;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+ /*
+ * Steal TICK_INT interrupts from timer_interrupt().
+ */
+ __asm__ __volatile__("
+ .globl tl0_smp_itick
+ b,pt %%xcc, 1f
+ nop
+
+ tl0_smp_itick:
+ rdpr %%pil, %%g2
+ wrpr %%g0, 15, %%pil
+ b,pt %%xcc, etrap_irq
+ rd %%pc, %%g7
+ call smp_percpu_timer_interrupt
+ add %%sp, %0, %%o0
+ b,pt %%xcc, rtrap
+ clr %%l6
+
+ 1:"
+ : /* no outputs */
+ : "i" (STACK_BIAS + REGWIN_SZ));
+
+ memcpy(&tl0_itick, &tl0_smp_itick, 8 * 4);
+
+ __asm__ __volatile__("
+ membar #StoreStore
+ flush %0 + 0x00
+ flush %0 + 0x08
+ flush %0 + 0x10
+ flush %0 + 0x18"
+ : /* no outputs */
+ : "r" (&tl0_itick));
+
+ restore_flags(flags);
+ }
+
__asm__ __volatile__("rd %%tick, %%g1\n\t"
"add %%g1, %0, %%g1\n\t"
"wr %%g1, 0x0, %%tick_cmpr"
@@ -552,22 +651,17 @@ static void smp_setup_percpu_timer(void)
: "g1");
}
-static void smp_tickoffset_init(void)
+__initfunc(static void smp_tickoffset_init(void))
{
- int node;
-
- node = linux_cpus[0].prom_node;
- real_tick_offset = prom_getint(node, "clock-frequency");
- real_tick_offset = real_tick_offset / HZ;
- current_tick_offset = real_tick_offset;
+ current_tick_offset = timer_tick_offset;
}
-int setup_profiling_timer(unsigned int multiplier)
+__initfunc(int setup_profiling_timer(unsigned int multiplier))
{
unsigned long flags;
int i;
- if((!multiplier) || (real_tick_offset / multiplier) < 1000)
+ if((!multiplier) || (timer_tick_offset / multiplier) < 1000)
return -EINVAL;
save_and_cli(flags);
@@ -575,7 +669,7 @@ int setup_profiling_timer(unsigned int multiplier)
if(cpu_present_map & (1UL << i))
prof_multiplier(i) = multiplier;
}
- current_tick_offset = (real_tick_offset / multiplier);
+ current_tick_offset = (timer_tick_offset / multiplier);
restore_flags(flags);
return 0;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index b776ea06e..0eb16d7bb 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.27 1997/11/19 07:57:46 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.33 1998/04/06 16:09:40 jj Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -50,6 +50,7 @@ struct poll {
short revents;
};
+extern unsigned prom_cpu_nodes[NR_CPUS];
extern void die_if_kernel(char *str, struct pt_regs *regs);
extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long);
@@ -112,6 +113,8 @@ EXPORT_SYMBOL_PRIVATE(global_restore_flags);
#else
EXPORT_SYMBOL(local_irq_count);
#endif
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL_PRIVATE(_lock_kernel);
EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
@@ -134,7 +137,9 @@ EXPORT_SYMBOL(dma_chain);
#endif
#if CONFIG_PCI
EXPORT_SYMBOL(ebus_chain);
-EXPORT_SYMBOL(pci_devices);
+EXPORT_SYMBOL(pci_dvma_offset);
+EXPORT_SYMBOL(pci_dvma_mask);
+EXPORT_SYMBOL(empty_zero_page);
#endif
/* Solaris/SunOS binary compatibility */
@@ -171,7 +176,6 @@ EXPORT_SYMBOL(__prom_getsibling);
/* sparc library symbols */
EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strcpy);
@@ -179,7 +183,6 @@ EXPORT_SYMBOL(strncpy);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strpbrk);
@@ -201,15 +204,11 @@ EXPORT_SYMBOL(sys_sigsuspend);
EXPORT_SYMBOL(sys_getppid);
EXPORT_SYMBOL(svr4_getcontext);
EXPORT_SYMBOL(svr4_setcontext);
-EXPORT_SYMBOL(linux_cpus);
+EXPORT_SYMBOL(prom_cpu_nodes);
EXPORT_SYMBOL(sys_ioctl);
EXPORT_SYMBOL(sys32_ioctl);
#endif
-#ifdef CONFIG_MATHEMU_MODULE
-EXPORT_SYMBOL(handle_mathemu);
-#endif
-
/* Special internal versions of library functions. */
EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c
index d94a7c6d6..a0bfb47ef 100644
--- a/arch/sparc64/kernel/sunos_ioctl32.c
+++ b/arch/sparc64/kernel/sunos_ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl32.c,v 1.5 1997/09/18 10:37:57 rth Exp $
+/* $Id: sunos_ioctl32.c,v 1.9 1998/03/29 10:10:53 davem Exp $
* sunos_ioctl32.c: SunOS ioctl compatability on sparc64.
*
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -18,6 +18,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -88,15 +89,12 @@ extern asmlinkage int sys_setsid(void);
asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg)
{
- struct file *filp;
int ret = -EBADF;
lock_kernel();
if(fd >= SUNOS_NR_OPEN)
goto out;
-
- filp = current->files->fd[fd];
- if(!filp)
+ if(!fcheck(fd))
goto out;
if(cmd == TIOCSETD) {
@@ -168,7 +166,7 @@ asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg)
ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg);
goto out;
case _IOW('i', 24, struct ifreq32):
- ret = sys32_ioctl(fd, SIOCGIFBRDADDR, arg);
+ ret = sys32_ioctl(fd, SIOCSIFBRDADDR, arg);
goto out;
case _IOWR('i', 25, struct ifreq32):
ret = sys32_ioctl(fd, SIOCGIFNETMASK, arg);
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index 6fb6f739b..44f17ca01 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.4 1997/09/09 17:13:29 jj Exp $
+/* $Id: sys32.S,v 1.5 1998/03/24 05:57:56 ecd Exp $
* sys32.S: I-cache tricks for 32-bit compatability layer simple
* conversions.
*
@@ -24,7 +24,7 @@ sys32_mmap:
.align 32
.globl sys32_lseek
- .globl sys32_chmod, sys32_chown, sys32_mknod
+ .globl sys32_chmod, sys32_chown, sys32_lchown, sys32_mknod
sys32_lseek:
sra %o1, 0, %o1
mov %o7, %g1
@@ -46,6 +46,15 @@ sys32_chown:
srl %o2, 16, %o2
call sys_chown
mov %g1, %o7
+sys32_lchown:
+ sll %o1, 16, %o1
+ mov %o7, %g1
+ sll %o2, 16, %o2
+ srl %o0, 0, %o0
+ srl %o1, 16, %o1
+ srl %o2, 16, %o2
+ call sys_lchown
+ mov %g1, %o7
sys32_mknod:
sll %o2, 16, %o2
mov %o7, %g1
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index e0e69abd9..b5198074d 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.9 1997/12/11 15:15:44 jj Exp $
+/* $Id: sys_sparc.c,v 1.13 1998/03/29 10:10:52 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/mm.h>
#include <linux/sem.h>
#include <linux/msg.h>
@@ -40,7 +41,7 @@ asmlinkage unsigned long sparc_brk(unsigned long brk)
unsigned long ret;
lock_kernel();
- if(brk >= 0x80000000000ULL) { /* VM hole */
+ if(brk >= 0x80000000000UL) { /* VM hole */
ret = current->mm->brk;
goto out;
}
@@ -128,6 +129,16 @@ asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long thir
if (call <= SHMCTL)
switch (call) {
case SHMAT:
+ if (first >= 0) {
+ extern struct shmid_ds *shm_segs[];
+ struct shmid_ds *shp = shm_segs[(unsigned int) first % SHMMNI];
+ if (shp == IPC_UNUSED || shp == IPC_NOID) {
+ err = -ENOMEM;
+ if ((unsigned long)ptr >= 0x80000000000UL - shp->shm_segsz &&
+ (unsigned long)ptr < 0xfffff80000000000UL)
+ goto out; /* Somebody is trying to fool us */
+ }
+ }
err = sys_shmat (first, (char *) ptr, second, (ulong *) third);
goto out;
case SHMDT:
@@ -162,29 +173,39 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd])){
+ file = fget(fd);
+ if (!file)
goto out;
- }
}
retval = -ENOMEM;
+ len = PAGE_ALIGN(len);
if(!(flags & MAP_FIXED) && !addr) {
addr = get_unmapped_area(addr, len);
- if(!addr){
- goto out;
- }
+ if(!addr)
+ goto out_putf;
}
- /* See asm-sparc64/uaccess.h */
retval = -EINVAL;
- if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
- goto out;
-
- if(addr >= 0x80000000000ULL) {
- retval = current->mm->brk;
- goto out;
+ if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (len > 0xf0000000UL || addr > 0xf0000000UL - len)
+ goto out_putf;
+ } else {
+ if (len >= 0x80000000000UL ||
+ (addr < 0x80000000000UL &&
+ addr > 0x80000000000UL-len))
+ goto out_putf;
+ if (addr >= 0x80000000000ULL && addr < 0xfffff80000000000UL) {
+ /* VM hole */
+ retval = current->mm->brk;
+ goto out_putf;
+ }
}
retval = do_mmap(file, addr, len, prot, flags, off);
+
+out_putf:
+ if (file)
+ fput(file);
out:
unlock_kernel();
return retval;
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 66993ebcb..2844a4bf2 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,7 +1,7 @@
-/* $Id: sys_sparc32.c,v 1.71 1997/12/11 15:15:11 jj Exp $
+/* $Id: sys_sparc32.c,v 1.77 1998/03/29 10:10:50 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*
* These routines maintain argument size conversion between 32bit and 64bit
@@ -10,11 +10,12 @@
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/signal.h>
#include <linux/utime.h>
#include <linux/resource.h>
-#include <linux/sched.h>
#include <linux/times.h>
#include <linux/utime.h>
#include <linux/utsname.h>
@@ -41,6 +42,7 @@
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/personality.h>
+#include <linux/stat.h>
#include <asm/types.h>
#include <asm/ipc.h>
@@ -59,7 +61,6 @@
extern char * getname_quicklist;
extern int getname_quickcount;
extern struct semaphore getname_quicklock;
-extern int kerneld_msqid;
/* Tuning: increase locality by reusing same pages again...
* if getname_quicklist becomes too long on low memory machines, either a limit
@@ -324,19 +325,9 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
if (!p) err = -ENOMEM;
else {
err = 0;
- if (first == kerneld_msqid) {
- *(int *)p->mtext = 0;
- if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_from_user(&p->mtext[4], &(((struct msgbuf32 *)A(ptr))->mtext[0]), 4) ||
- __copy_from_user(&p->mtext[8], &(((struct msgbuf32 *)A(ptr))->mtext[4]), second-4))
- err = -EFAULT;
- else
- second += 4;
- } else {
- if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
- err = -EFAULT;
- }
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
+ err = -EFAULT;
if (!err) {
mm_segment_t old_fs = get_fs();
set_fs (KERNEL_DS);
@@ -379,18 +370,9 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
if (err < 0)
goto out;
- if (first == kerneld_msqid) {
- if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[0]), &p->mtext[4], 4) ||
- __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[4]), &p->mtext[8], err-8))
- err = -EFAULT;
- else
- err -= 4;
- } else {
- if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
- err = -EFAULT;
- }
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
+ err = -EFAULT;
kfree (p);
goto out;
}
@@ -939,14 +921,12 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
{
int error = -EBADF;
struct file * file;
+ struct inode * inode;
struct readdir_callback32 buf;
lock_kernel();
- if(fd >= NR_OPEN)
- goto out;
-
- file = current->files->fd[fd];
- if(!file)
+ file = fget(fd);
+ if (!file)
goto out;
buf.count = 0;
@@ -954,12 +934,18 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
-
+ goto out_putf;
+
+ inode = file->f_dentry->d_inode;
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, fillonedir);
+ up(&inode->i_sem);
if (error < 0)
- goto out;
+ goto out_putf;
error = buf.count;
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -1006,16 +992,14 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
{
struct file * file;
+ struct inode * inode;
struct linux_dirent32 * lastdirent;
struct getdents_callback32 buf;
int error = -EBADF;
lock_kernel();
- if(fd >= NR_OPEN)
- goto out;
-
- file = current->files->fd[fd];
- if(!file)
+ file = fget(fd);
+ if (!file)
goto out;
buf.current_dir = (struct linux_dirent32 *) A(dirent);
@@ -1025,17 +1009,22 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
+ goto out_putf;
+ inode = file->f_dentry->d_inode;
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, filldir);
+ up(&inode->i_sem);
if (error < 0)
- goto out;
+ goto out_putf;
lastdirent = buf.previous;
error = buf.error;
if(lastdirent) {
put_user(file->f_pos, &lastdirent->d_off);
error = count - buf.count;
}
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -1258,6 +1247,27 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
return ret;
}
+extern asmlinkage int sys_xstat(int ver, char *filename, struct stat64 * statbuf);
+
+asmlinkage int sys32_xstat(int ver, u32 file, u32 statbuf)
+{
+ switch (ver & __XSTAT_VER_MASK) {
+ case __XSTAT_VER_1:
+ switch (ver & __XSTAT_VER_TYPEMASK) {
+ case __XSTAT_VER_XSTAT:
+ return sys32_newstat(file, statbuf);
+ case __XSTAT_VER_LXSTAT:
+ return sys32_newlstat(file, statbuf);
+ case __XSTAT_VER_FXSTAT:
+ return sys32_newfstat(file, statbuf);
+ }
+ return -EINVAL;
+ case __XSTAT_VER_2:
+ return sys_xstat(ver, (char *)A(file), (struct stat64 *)A(statbuf));
+ }
+ return -EINVAL;
+}
+
extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
@@ -2222,18 +2232,19 @@ asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
char address[MAX_SOCK_ADDR];
struct iovec iov[UIO_FASTIOV];
unsigned char ctl[sizeof(struct cmsghdr) + 20];
- struct msghdr kern_msg;
- int err;
- int total_len;
unsigned char *ctl_buf = ctl;
+ struct msghdr kern_msg;
+ int err, total_len;
if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
return -EFAULT;
if(kern_msg.msg_iovlen > UIO_MAXIOV)
return -EINVAL;
- total_len = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
- if(total_len < 0)
- return total_len;
+ err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+ if (err < 0)
+ goto out;
+ total_len = err;
+
if(kern_msg.msg_controllen) {
struct cmsghdr32 *ucmsg = (struct cmsghdr32 *)kern_msg.msg_control;
unsigned long *kcmsg;
@@ -2241,41 +2252,40 @@ asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
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) {
- if(kern_msg.msg_iov != iov)
- kfree(kern_msg.msg_iov);
- return -ENOBUFS;
- }
+ 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))) {
- if(ctl_buf != ctl)
- kfree_s(ctl_buf, kern_msg.msg_controllen);
- if(kern_msg.msg_iov != iov)
- kfree(kern_msg.msg_iov);
- return -EFAULT;
- }
+ kern_msg.msg_controllen - sizeof(__kernel_size_t32)))
+ goto out_freectl;
kern_msg.msg_control = ctl_buf;
}
kern_msg.msg_flags = user_flags;
lock_kernel();
- if(current->files->fd[fd]->f_flags & O_NONBLOCK)
- kern_msg.msg_flags |= MSG_DONTWAIT;
- if((sock = sockfd_lookup(fd, &err)) != NULL) {
+ sock = sockfd_lookup(fd, &err);
+ if (sock != NULL) {
+ if (sock->file->f_flags & O_NONBLOCK)
+ kern_msg.msg_flags |= MSG_DONTWAIT;
err = sock_sendmsg(sock, &kern_msg, total_len);
sockfd_put(sock);
}
unlock_kernel();
+out_freectl:
+ /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
if(ctl_buf != ctl)
- kfree_s(ctl_buf, kern_msg.msg_controllen);
+ kfree(ctl_buf);
+out_freeiov:
if(kern_msg.msg_iov != iov)
kfree(kern_msg.msg_iov);
+out:
return err;
}
@@ -2299,17 +2309,18 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
uaddr = kern_msg.msg_name;
uaddr_len = &((struct msghdr32 *)A(user_msg))->msg_namelen;
err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
- if(err < 0)
- return err;
+ if (err < 0)
+ goto out;
total_len = err;
cmsg_ptr = (unsigned long) kern_msg.msg_control;
kern_msg.msg_flags = 0;
lock_kernel();
- if(current->files->fd[fd]->f_flags & O_NONBLOCK)
- user_flags |= MSG_DONTWAIT;
- if((sock = sockfd_lookup(fd, &err)) != NULL) {
+ sock = sockfd_lookup(fd, &err);
+ if (sock != NULL) {
+ if (sock->file->f_flags & O_NONBLOCK)
+ user_flags |= MSG_DONTWAIT;
err = sock_recvmsg(sock, &kern_msg, total_len, user_flags);
if(err >= 0)
len = err;
@@ -2317,8 +2328,6 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
}
unlock_kernel();
- if(kern_msg.msg_iov != iov)
- kfree(kern_msg.msg_iov);
if(uaddr != NULL && err >= 0)
err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
if(err >= 0) {
@@ -2330,6 +2339,10 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
&((struct msghdr32 *)A(user_msg))->msg_controllen);
}
}
+
+ if(kern_msg.msg_iov != iov)
+ kfree(kern_msg.msg_iov);
+out:
if(err < 0)
return err;
return len;
@@ -2838,25 +2851,25 @@ asmlinkage int sys32_get_kernel_syms(u32 table)
#else /* CONFIG_MODULES */
asmlinkage unsigned long
-sys_create_module(const char *name_user, size_t size)
+sys32_create_module(const char *name_user, size_t size)
{
return -ENOSYS;
}
asmlinkage int
-sys_init_module(const char *name_user, struct module *mod_user)
+sys32_init_module(const char *name_user, struct module *mod_user)
{
return -ENOSYS;
}
asmlinkage int
-sys_delete_module(const char *name_user)
+sys32_delete_module(const char *name_user)
{
return -ENOSYS;
}
asmlinkage int
-sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize,
size_t *ret)
{
/* Let the program know about the new interface. Not that
@@ -2868,7 +2881,7 @@ sys_query_module(const char *name_user, int which, char *buf, size_t bufsize,
}
asmlinkage int
-sys_get_kernel_syms(struct kernel_sym *table)
+sys32_get_kernel_syms(struct kernel_sym *table)
{
return -ENOSYS;
}
@@ -3327,3 +3340,19 @@ asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, u32 ubuf,
{
return sys_pwrite(fd, (char *) A(ubuf), count, pos);
}
+
+
+extern asmlinkage int sys_personality(unsigned long);
+
+asmlinkage int sys32_personality(unsigned long personality)
+{
+ int ret;
+ lock_kernel();
+ if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+ personality = PER_LINUX32;
+ ret = sys_personality(personality);
+ unlock_kernel();
+ if (ret == PER_LINUX32)
+ ret = PER_LINUX;
+ return ret;
+}
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 4af388b99..ad7bac534 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.7 1997/12/11 15:15:19 jj Exp $
+/* $Id: sys_sunos32.c,v 1.11 1998/03/29 10:10:55 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -16,6 +16,7 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/resource.h>
#include <linux/ipc.h>
#include <linux/shm.h>
@@ -70,23 +71,30 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
flags &= ~MAP_NORESERVE;
}
retval = -EBADF;
- if(!(flags & MAP_ANONYMOUS))
- if(fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd]))
+ if(!(flags & MAP_ANONYMOUS)) {
+ if(fd >= SUNOS_NR_OPEN)
goto out;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ if (file->f_dentry && file->f_dentry->d_inode) {
+ struct inode * inode = file->f_dentry->d_inode;
+ if(MAJOR(inode->i_rdev) == MEM_MAJOR &&
+ MINOR(inode->i_rdev) == 5) {
+ flags |= MAP_ANONYMOUS;
+ fput(file);
+ file = NULL;
+ }
+ }
+ }
+
retval = -ENOMEM;
if(!(flags & MAP_FIXED) && !addr) {
unsigned long attempt = get_unmapped_area(addr, len);
if(!attempt || (attempt >= 0xf0000000UL))
- goto out;
+ goto out_putf;
addr = (u32) attempt;
}
- if(file->f_dentry && file->f_dentry->d_inode) {
- if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR &&
- MINOR(file->f_dentry->d_inode->i_rdev) == 5) {
- flags |= MAP_ANONYMOUS;
- file = 0;
- }
- }
if(!(flags & MAP_FIXED))
addr = 0;
ret_type = flags & _MAP_NEW;
@@ -98,6 +106,9 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
(unsigned long) off);
if(!ret_type)
retval = ((retval < 0xf0000000) ? 0 : retval);
+out_putf:
+ if (file)
+ fput(file);
out:
unlock_kernel();
return (u32) retval;
@@ -372,6 +383,7 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
{
struct file * file;
+ struct inode * inode;
struct sunos_dirent * lastdirent;
struct sunos_dirent_callback buf;
int error = -EBADF;
@@ -381,32 +393,39 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt)
if(fd >= SUNOS_NR_OPEN)
goto out;
- file = current->files->fd[fd];
+ file = fget(fd);
if(!file)
goto out;
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
+ goto out_putf;
error = -EINVAL;
if(cnt < (sizeof(struct sunos_dirent) + 255))
- goto out;
+ goto out_putf;
buf.curr = (struct sunos_dirent *) dirent;
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
+ inode = file->f_dentry->d_inode;
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, sunos_filldir);
+ up(&inode->i_sem);
if (error < 0)
- goto out;
+ goto out_putf;
+
lastdirent = buf.previous;
error = buf.error;
if (lastdirent) {
put_user(file->f_pos, &lastdirent->d_off);
error = cnt - buf.count;
}
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -454,43 +473,51 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
asmlinkage int sunos_getdirentries(unsigned int fd, u32 u_dirent,
int cnt, u32 u_basep)
{
+ void *dirent = (void *) A(u_dirent);
+ unsigned int *basep = (unsigned int *)A(u_basep);
struct file * file;
+ struct inode * inode;
struct sunos_direntry * lastdirent;
- struct sunos_direntry_callback buf;
int error = -EBADF;
- void *dirent = (void *) A(u_dirent);
- unsigned int *basep = (unsigned int *)A(u_basep);
+ struct sunos_direntry_callback buf;
lock_kernel();
if(fd >= SUNOS_NR_OPEN)
goto out;
- file = current->files->fd[fd];
+ file = fget(fd);
if(!file)
goto out;
error = -ENOTDIR;
if (!file->f_op || !file->f_op->readdir)
- goto out;
+ goto out_putf;
error = -EINVAL;
if(cnt < (sizeof(struct sunos_direntry) + 255))
- goto out;
+ goto out_putf;
buf.curr = (struct sunos_direntry *) dirent;
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
+ inode = file->f_dentry->d_inode;
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, sunos_filldirentry);
+ up(&inode->i_sem);
if (error < 0)
- goto out;
+ goto out_putf;
+
lastdirent = buf.previous;
error = buf.error;
if (lastdirent) {
put_user(file->f_pos, basep);
error = cnt - buf.count;
}
+
+out_putf:
+ fput(file);
out:
unlock_kernel();
return error;
@@ -622,14 +649,28 @@ asmlinkage int sunos_pathconf(u32 u_path, int name)
extern asmlinkage int
sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp);
-asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp)
+struct timeval32
+{
+ int tv_sec, tv_usec;
+};
+
+asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x)
{
int ret;
/* SunOS binaries expect that select won't change the tvp contents */
lock_kernel();
current->personality |= STICKY_TIMEOUTS;
- ret = sys32_select (width, inp, outp, exp, tvp);
+ ret = sys32_select (width, inp, outp, exp, tvp_x);
+ if (ret == -EINTR && tvp_x) {
+ struct timeval32 *tvp = (struct timeval32 *)A(tvp_x);
+ time_t sec, usec;
+
+ __get_user(sec, &tvp->tv_sec);
+ __get_user(usec, &tvp->tv_usec);
+ if (sec == 0 && usec == 0)
+ ret = 0;
+ }
unlock_kernel();
return ret;
}
@@ -1297,8 +1338,11 @@ asmlinkage int sunos_open(u32 filename, int flags, int mode)
static inline int check_nonblock(int ret, int fd)
{
- if (ret == -EAGAIN && (current->files->fd[fd]->f_flags & O_NDELAY))
- return -SUNOS_EWOULDBLOCK;
+ if (ret == -EAGAIN) {
+ struct file * file = fcheck(fd);
+ if (file && (file->f_flags & O_NDELAY))
+ ret = -SUNOS_EWOULDBLOCK;
+ }
return ret;
}
@@ -1370,12 +1414,42 @@ asmlinkage int sunos_send(int fd, u32 buff, int len, unsigned flags)
return ret;
}
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen);
+
+asmlinkage int sunos_socket(int family, int type, int protocol)
+{
+ int ret, one = 1;
+
+ lock_kernel();
+ ret = sys_socket(family, type, protocol);
+ if (ret < 0)
+ goto out;
+
+ sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+ (char *)&one, sizeof(one));
+out:
+ unlock_kernel();
+ return ret;
+}
+
asmlinkage int sunos_accept(int fd, u32 sa, u32 addrlen)
{
- int ret;
+ int ret, one = 1;
lock_kernel();
- ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa), (int *)A(addrlen)), fd);
+ while (1) {
+ ret = check_nonblock(sys_accept(fd, (struct sockaddr *)A(sa),
+ (int *)A(addrlen)), fd);
+ if (ret != -ENETUNREACH && ret != -EHOSTUNREACH)
+ break;
+ }
+ if (ret < 0)
+ goto out;
+
+ sys_setsockopt(ret, SOL_SOCKET, SO_BSDCOMPAT,
+ (char *)&one, sizeof(one));
+out:
unlock_kernel();
return ret;
}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 48ae0ecdf..6389681dd 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.37 1997/12/24 17:27:31 ecd Exp $
+/* $Id: systbls.S,v 1.41 1998/03/24 05:57:57 ecd Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -19,8 +19,8 @@
sys_call_table32:
/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
/*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
-/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod
-/*15*/ .word sys32_chmod, sys32_chown, sparc_brk, sys_nis_syscall, sys32_lseek
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_xstat, sys32_mknod
+/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_xmknod, sys32_lseek
/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys32_pause
/*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -55,7 +55,7 @@ sys_call_table32:
.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/ .word sys32_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*190*/ .word sys32_init_module, sys32_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
.word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
@@ -78,8 +78,8 @@ sys_call_table64:
sys_call_table:
/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write
/*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_xstat, sys_mknod
+/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_xmknod, sys_lseek
/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_nis_syscall
/*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -117,7 +117,7 @@ sys_call_table:
/*190*/ .word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_sigaction, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
- .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+ .word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
.word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
/*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
@@ -139,7 +139,7 @@ sunos_sys_table:
.word sys_close, sunos_wait4, sys_creat
.word sys_link, sys_unlink, sunos_execv
.word sys_chdir, sunos_nosys, sys32_mknod
- .word sys32_chmod, sys32_chown, sunos_brk
+ .word sys32_chmod, sys32_lchown, sunos_brk
.word sunos_nosys, sys32_lseek, sunos_getpid
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_getuid, sunos_nosys, sys_ptrace
@@ -166,7 +166,7 @@ sunos_sys_table:
.word sys32_getitimer, sys_gethostname, sys_sethostname
.word sunos_getdtablesize, sys_dup2, sunos_nop
.word sys32_fcntl, sunos_select, sunos_nop
- .word sys_fsync, sys_setpriority, sys_socket
+ .word sys_fsync, sys_setpriority, sunos_socket
.word sys_connect, sunos_accept
/*100*/ .word sys_getpriority, sunos_send, sunos_recv
.word sunos_nosys, sys_bind, sunos_setsockopt
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 8b0152231..debb08888 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,7 +1,8 @@
-/* $Id: time.c,v 1.12 1997/08/22 20:12:13 davem Exp $
+/* $Id: time.c,v 1.13 1998/03/15 17:23:47 ecd Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
*
* Based largely on code which is:
*
@@ -42,29 +43,64 @@ static int set_rtc_mmss(unsigned long);
* NOTE: On SUN5 systems the ticker interrupt comes in using 2
* interrupts, one at level14 and one with softint bit 0.
*/
-extern struct sun5_timer *linux_timers;
+unsigned long timer_tick_offset;
+static unsigned long timer_tick_compare;
+static unsigned long timer_ticks_per_usec;
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static __inline__ void timer_check_rtc(void)
{
/* last time the cmos clock got updated */
static long last_rtc_update=0;
- __asm__ __volatile__("ldx [%0], %%g0"
- : /* no outputs */
- : "r" (&((linux_timers)->limit0)));
-
- do_timer(regs);
-
/* Determine when to update the Mostek clock. */
if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ xtime.tv_usec < 500000 + (tick >> 1)) {
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600;
+ /* do it again in 60 s */
+ }
+}
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ unsigned long ticks;
+
+ do {
+ do_timer(regs);
+
+ __asm__ __volatile__("
+ rd %%tick_cmpr, %0
+ add %0, %2, %0
+ wr %0, 0, %%tick_cmpr
+ rd %%tick, %1"
+ : "=&r" (timer_tick_compare), "=r" (ticks)
+ : "r" (timer_tick_offset));
+ } while (ticks >= timer_tick_compare);
+
+ timer_check_rtc();
}
+#ifdef __SMP__
+void timer_tick_interrupt(struct pt_regs *regs)
+{
+ do_timer(regs);
+
+ /*
+ * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
+ */
+ __asm__ __volatile__("
+ rd %%tick_cmpr, %0
+ add %0, %1, %0"
+ : "=&r" (timer_tick_compare)
+ : "r" (timer_tick_offset));
+
+ timer_check_rtc();
+}
+#endif
+
/* 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.
@@ -318,29 +354,32 @@ __initfunc(void time_init(void))
*/
}
-extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+extern void init_timers(void (*func)(int, void *, struct pt_regs *),
+ unsigned long *);
__initfunc(void sun4u_start_timers(void))
{
- init_timers(timer_interrupt);
+ unsigned long clock;
+
+ init_timers(timer_interrupt, &clock);
+ timer_tick_offset = clock / HZ;
+ timer_ticks_per_usec = clock / 1000000;
}
static __inline__ unsigned long do_gettimeoffset(void)
{
- unsigned long offset = 0;
- unsigned int count;
-
- /* XXX -DaveM */
-#if 0
- count = (*master_l10_counter >> 10) & 0x1fffff;
-#else
- count = 0;
-#endif
+ unsigned long ticks;
- if(test_bit(TIMER_BH, &bh_active))
- offset = 1000000;
-
- return offset + count;
+ __asm__ __volatile__("
+ rd %%tick, %%g1
+ add %1, %%g1, %0
+ sub %0, %2, %0
+"
+ : "=r" (ticks)
+ : "r" (timer_tick_offset), "r" (timer_tick_compare)
+ : "g1", "g2");
+
+ return ticks / timer_ticks_per_usec;
}
void do_gettimeofday(struct timeval *tv)
@@ -353,13 +392,16 @@ void do_gettimeofday(struct timeval *tv)
* nucleus atomic quad 128-bit loads.
*/
__asm__ __volatile__("
- sethi %hi(linux_timers), %o1
+ sethi %hi(timer_tick_offset), %g3
sethi %hi(xtime), %g2
- ldx [%o1 + %lo(linux_timers)], %g3
+ sethi %hi(timer_tick_compare), %g1
+ ldx [%g3 + %lo(timer_tick_offset)], %g3
or %g2, %lo(xtime), %g2
+ or %g1, %lo(timer_tick_compare), %g1
1: ldda [%g2] 0x24, %o4
membar #LoadLoad | #MemIssue
- ldx [%g3], %o1
+ rd %tick, %o1
+ ldx [%g1], %g7
membar #LoadLoad | #MemIssue
ldda [%g2] 0x24, %o2
membar #LoadLoad
@@ -367,24 +409,28 @@ void do_gettimeofday(struct timeval *tv)
xor %o5, %o3, %o3
orcc %o2, %o3, %g0
bne,pn %xcc, 1b
- cmp %o1, 0
- bge,pt %icc, 1f
- sethi %hi(tick), %o3
- ldx [%o3 + %lo(tick)], %o3
- sethi %hi(0x1fffff), %o2
- or %o2, %lo(0x1fffff), %o2
- add %o5, %o3, %o5
- and %o1, %o2, %o1
-1: add %o5, %o1, %o5
- sethi %hi(1000000), %o2
+ sethi %hi(lost_ticks), %o2
+ sethi %hi(timer_ticks_per_usec), %o3
+ ldx [%o2 + %lo(lost_ticks)], %o2
+ add %g3, %o1, %o1
+ ldx [%o3 + %lo(timer_ticks_per_usec)], %o3
+ sub %o1, %g7, %o1
+ brz,pt %o2, 1f
+ udivx %o1, %o3, %o1
+ sethi %hi(10000), %g2
+ or %g2, %lo(10000), %g2
+ add %o1, %g2, %o1
+1: sethi %hi(1000000), %o2
+ srlx %o5, 32, %o5
or %o2, %lo(1000000), %o2
+ add %o5, %o1, %o5
cmp %o5, %o2
bl,a,pn %xcc, 1f
stx %o4, [%o0 + 0x0]
add %o4, 0x1, %o4
sub %o5, %o2, %o5
stx %o4, [%o0 + 0x0]
-1: stx %o5, [%o0 + 0x8]");
+1: st %o5, [%o0 + 0x8]");
}
void do_settimeofday(struct timeval *tv)
@@ -401,6 +447,7 @@ void do_settimeofday(struct timeval *tv)
time_state = TIME_BAD;
time_maxerror = 0x70000000;
time_esterror = 0x70000000;
+
sti();
}
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index b5ca851ac..8604b3301 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.2 1997/07/28 02:57:32 davem Exp $
+/* $Id: trampoline.S,v 1.3 1998/02/22 21:06:11 jj Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -172,8 +172,10 @@ bounce:
mov %o2, %g6
wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate
- sethi %hi(0x1ff8), %g2
- or %g2, %lo(0x1ff8), %g2
+#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+ sethi %uhi(KERN_HIGHBITS), %g2
+ sllx %g2, 32, %g2
+#undef KERN_HIGHBITS
ldx [%o2 + AOFF_task_mm], %g6
ldx [%g6 + AOFF_mm_pgd], %g6
clr %g7
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 6e1d30990..b255c7623 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.44 1998/01/09 16:39:35 jj Exp $
+/* $Id: traps.c,v 1.49 1998/04/06 16:09:38 jj Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -191,7 +191,7 @@ void bad_trap (struct pt_regs *regs, long lvl)
die_if_kernel ("Kernel bad trap", regs);
current->tss.sig_desc = SUBSIG_BADTRAP(lvl - 0x100);
current->tss.sig_address = regs->tpc;
- send_sig(SIGILL, current, 1);
+ force_sig(SIGILL, current);
unlock_kernel ();
}
@@ -225,7 +225,9 @@ void data_access_exception (struct pt_regs *regs)
return;
}
}
- send_sig(SIGSEGV, current, 1);
+ lock_kernel();
+ force_sig(SIGSEGV, current);
+ unlock_kernel();
}
#ifdef CONFIG_PCI
@@ -235,16 +237,35 @@ extern volatile int pci_poke_in_progress;
extern volatile int pci_poke_faulted;
#endif
+/* When access exceptions happen, we must do this. */
+static __inline__ void clean_and_reenable_l1_caches(void)
+{
+ unsigned long va;
+
+ /* Clean 'em. */
+ for(va = 0; va < (PAGE_SIZE << 1); va += 32) {
+ spitfire_put_icache_tag(va, 0x0);
+ spitfire_put_dcache_tag(va, 0x0);
+ }
+
+ /* Re-enable. */
+ __asm__ __volatile__("flush %%g6\n\t"
+ "membar #Sync\n\t"
+ "stxa %0, [%%g0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+ LSU_CONTROL_IM | LSU_CONTROL_DM),
+ "i" (ASI_LSU_CONTROL)
+ : "memory");
+}
+
void do_dae(struct pt_regs *regs)
{
#ifdef CONFIG_PCI
-#ifdef DEBUG_PCI_POKES
- prom_printf(" (POKE ");
-#endif
if(pci_poke_in_progress) {
- unsigned long va;
#ifdef DEBUG_PCI_POKES
- prom_printf("tpc[%016lx] tnpc[%016lx] ",
+ prom_printf(" (POKE tpc[%016lx] tnpc[%016lx] ",
regs->tpc, regs->tnpc);
#endif
pci_poke_faulted = 1;
@@ -255,39 +276,30 @@ void do_dae(struct pt_regs *regs)
prom_printf("PCI) ");
/* prom_halt(); */
#endif
- /* Re-enable I/D caches, Ultra turned them off. */
- for(va = 0; va < (PAGE_SIZE << 1); va += 32) {
- spitfire_put_icache_tag(va, 0x0);
- spitfire_put_dcache_tag(va, 0x0);
- }
- __asm__ __volatile__("flush %%g6\n\t"
- "membar #Sync\n\t"
- "stxa %0, [%%g0] %1\n\t"
- "membar #Sync"
- : /* no outputs */
- : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
- LSU_CONTROL_IM | LSU_CONTROL_DM),
- "i" (ASI_LSU_CONTROL)
- : "memory");
+ clean_and_reenable_l1_caches();
return;
}
-#ifdef DEBUG_PCI_POKES
- prom_printf("USER) ");
- prom_printf("tpc[%016lx] tnpc[%016lx]\n");
- prom_halt();
#endif
-#endif
- send_sig(SIGSEGV, current, 1);
+ clean_and_reenable_l1_caches();
+ lock_kernel();
+ force_sig(SIGSEGV, current);
+ unlock_kernel();
}
void instruction_access_exception (struct pt_regs *regs)
{
- send_sig(SIGSEGV, current, 1);
+ clean_and_reenable_l1_caches();
+
+ lock_kernel();
+ force_sig(SIGSEGV, current);
+ unlock_kernel();
}
void do_iae(struct pt_regs *regs)
{
- send_sig(SIGSEGV, current, 1);
+ lock_kernel();
+ force_sig(SIGSEGV, current);
+ unlock_kernel();
}
void do_fpe_common(struct pt_regs *regs)
@@ -312,11 +324,7 @@ void do_fpieee(struct pt_regs *regs)
do_fpe_common(regs);
}
-#ifdef CONFIG_MATHEMU_MODULE
-volatile int (*handle_mathemu)(struct pt_regs *, struct fpustate *) = NULL;
-#else
extern int do_mathemu(struct pt_regs *, struct fpustate *);
-#endif
void do_fpother(struct pt_regs *regs)
{
@@ -326,18 +334,7 @@ void do_fpother(struct pt_regs *regs)
switch ((f->fsr & 0x1c000)) {
case (2 << 14): /* unfinished_FPop */
case (3 << 14): /* unimplemented_FPop */
-#ifdef CONFIG_MATHEMU_MODULE
-#ifdef CONFIG_KMOD
- if (!handle_mathemu)
- request_module("math-emu");
-#endif
- if (handle_mathemu)
- ret = handle_mathemu(regs, f);
-#else
-#ifdef CONFIG_MATHEMU
ret = do_mathemu(regs, f);
-#endif
-#endif
break;
}
if (ret) return;
@@ -576,27 +573,33 @@ void cache_flush_trap(struct pt_regs *regs)
#else
#error SMP not supported on sparc64 yet
#endif
+
+#if 0
+/* Broken */
int size = prom_getintdefault(node, "ecache-size", 512*1024);
int i, j;
- unsigned long addr, page_nr;
+ unsigned long addr;
+ struct page *page, *end;
regs->tpc = regs->tnpc;
regs->tnpc = regs->tnpc + 4;
if (!suser()) return;
size >>= PAGE_SHIFT;
addr = PAGE_OFFSET - PAGE_SIZE;
+ page = mem_map - 1;
+ end = mem_map + max_mapnr;
for (i = 0; i < size; i++) {
do {
addr += PAGE_SIZE;
- page_nr = MAP_NR(addr);
- if (page_nr >= max_mapnr) {
+ page++;
+ if (page >= end)
return;
- }
- } while (!PageReserved (mem_map + page_nr));
+ } while (!PageReserved(page));
/* E-Cache line size is 64B. Let us pollute it :)) */
for (j = 0; j < PAGE_SIZE; j += 64)
__asm__ __volatile__ ("ldx [%0 + %1], %%g1" : : "r" (j), "r" (addr) : "g1");
}
+#endif
}
#endif
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index b22cf82f7..3d17fb3cb 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.22 1997/10/16 07:07:46 jj Exp $
+/* $Id: ttable.S,v 1.23 1998/03/15 17:23:48 ecd Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -6,7 +6,7 @@
#include <linux/config.h>
- .globl sparc64_ttable_tl0, sparc64_ttable_tl1
+ .globl sparc64_ttable_tl0, tl0_itick, sparc64_ttable_tl1,
sparc64_ttable_tl0:
tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
@@ -45,7 +45,7 @@ tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8)
tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10)
tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
tl0_irq13: TRAP_IRQ(handler_irq, 13)
-tl0_itick: TRAP_TICK
+tl0_itick: TRAP_IRQ(handler_irq, 14)
tl0_irq15: TRAP_IRQ(handler_irq, 15)
tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)