summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-04-05 04:55:58 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-04-05 04:55:58 +0000
commit74a9f2e1b4d3ab45a9f72cb5b556c9f521524ab3 (patch)
tree7c4cdb103ab1b388c9852a88bd6fb1e73eba0b5c /arch/sparc64/kernel
parentee6374c8b0d333c08061c6a97bc77090d7461225 (diff)
Merge with Linux 2.4.3.
Note that mingetty does no longer work with serial console, you have to switch to another getty like getty_ps. This commit also includes a fix for a setitimer bug which did prevent getty_ps from working on older kernels.
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile4
-rw-r--r--arch/sparc64/kernel/auxio.c3
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c15
-rw-r--r--arch/sparc64/kernel/cpu.c6
-rw-r--r--arch/sparc64/kernel/devices.c11
-rw-r--r--arch/sparc64/kernel/dtlb_base.S6
-rw-r--r--arch/sparc64/kernel/ebus.c52
-rw-r--r--arch/sparc64/kernel/entry.S196
-rw-r--r--arch/sparc64/kernel/etrap.S4
-rw-r--r--arch/sparc64/kernel/head.S298
-rw-r--r--arch/sparc64/kernel/ioctl32.c117
-rw-r--r--arch/sparc64/kernel/irq.c79
-rw-r--r--arch/sparc64/kernel/pci.c9
-rw-r--r--arch/sparc64/kernel/pci_common.c40
-rw-r--r--arch/sparc64/kernel/pci_iommu.c6
-rw-r--r--arch/sparc64/kernel/pci_psycho.c22
-rw-r--r--arch/sparc64/kernel/pci_sabre.c20
-rw-r--r--arch/sparc64/kernel/pci_schizo.c1664
-rw-r--r--arch/sparc64/kernel/process.c12
-rw-r--r--arch/sparc64/kernel/ptrace.c186
-rw-r--r--arch/sparc64/kernel/rtrap.S4
-rw-r--r--arch/sparc64/kernel/setup.c24
-rw-r--r--arch/sparc64/kernel/signal.c43
-rw-r--r--arch/sparc64/kernel/signal32.c67
-rw-r--r--arch/sparc64/kernel/smp.c278
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c7
-rw-r--r--arch/sparc64/kernel/sys_sparc.c26
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c6
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c14
-rw-r--r--arch/sparc64/kernel/time.c286
-rw-r--r--arch/sparc64/kernel/trampoline.S349
-rw-r--r--arch/sparc64/kernel/traps.c99
-rw-r--r--arch/sparc64/kernel/ttable.S4
-rw-r--r--arch/sparc64/kernel/unaligned.c6
34 files changed, 3313 insertions, 650 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 8648bb190..218242631 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.63 2000/12/14 22:57:25 davem Exp $
+# $Id: Makefile,v 1.64 2001/02/28 05:59:45 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -27,7 +27,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o
obj-$(CONFIG_PCI) += ebus.o pci_common.o pci_iommu.o \
- pci_psycho.o pci_sabre.o
+ pci_psycho.o pci_sabre.o pci_schizo.o
obj-$(CONFIG_SMP) += smp.o trampoline.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o ioctl32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index cc26817b4..10787f22f 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -18,6 +18,7 @@
#include <asm/sbus.h>
#include <asm/ebus.h>
#include <asm/fhc.h>
+#include <asm/spitfire.h>
#include <asm/starfire.h>
/* Probe and map in the Auxiliary I/O register */
@@ -56,7 +57,7 @@ found_sdev:
return;
}
#endif
- if(central_bus || this_is_starfire) {
+ if (central_bus || this_is_starfire || (tlb_type == cheetah)) {
auxio_register = 0UL;
return;
}
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index bda2fb6a5..314230ef2 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -277,24 +277,24 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto beyond_if;
}
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
if (error != N_TXTADDR(ex)) {
send_sig(SIGKILL, current, 0);
return error;
}
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset + ex.a_text);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
if (error != N_DATADDR(ex)) {
send_sig(SIGKILL, current, 0);
return error;
@@ -318,7 +318,8 @@ beyond_if:
unsigned long pgd_cache;
pgd_cache = ((unsigned long)current->mm->pgd[0])<<11UL;
- __asm__ __volatile__("stxa\t%0, [%1] %2"
+ __asm__ __volatile__("stxa\t%0, [%1] %2\n\t"
+ "membar #Sync"
: /* no outputs */
: "r" (pgd_cache),
"r" (TSB_REG), "i" (ASI_DMMU));
@@ -368,12 +369,12 @@ static int load_aout32_library(struct file *file)
start_addr = ex.a_entry & 0xfffff000;
/* Now use mmap to map the library into memory. */
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
N_TXTOFF(ex));
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
retval = error;
if (error != start_addr)
goto out;
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 8e1a0367c..a3bf89bb2 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -34,7 +34,8 @@ struct cpu_fp_info linux_sparc_fpu[] = {
{ 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
{ 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
{ 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
- { 0x17, 0x14, 0, "UltraSparc III integrated FPU"},
+ { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
+ { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
};
#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -44,7 +45,8 @@ struct cpu_iu_info linux_sparc_chips[] = {
{ 0x22, 0x10, "TI UltraSparc II (BlackBird)"},
{ 0x17, 0x11, "TI UltraSparc II (BlackBird)"},
{ 0x17, 0x12, "TI UltraSparc IIi"},
- { 0x17, 0x14, "TI UltraSparc III (Cheetah)"}, /* A guess... */
+ { 0x17, 0x13, "TI UltraSparc IIe"},
+ { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
};
#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 be8771985..849a44c87 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -13,6 +13,7 @@
#include <asm/oplib.h>
#include <asm/system.h>
#include <asm/smp.h>
+#include <asm/spitfire.h>
struct prom_cpuinfo linux_cpus[64] __initdata = { { 0 } };
unsigned prom_cpu_nodes[64];
@@ -50,8 +51,14 @@ void __init device_scan(void)
if(strcmp(node_str, "cpu") == 0) {
cpu_nds[cpu_ctr] = scan;
linux_cpus[cpu_ctr].prom_node = scan;
- prom_getproperty(scan, "upa-portid",
- (char *) &thismid, sizeof(thismid));
+ thismid = 0;
+ if (tlb_type == spitfire) {
+ prom_getproperty(scan, "upa-portid",
+ (char *) &thismid, sizeof(thismid));
+ } else if (tlb_type == cheetah) {
+ prom_getproperty(scan, "portid",
+ (char *) &thismid, sizeof(thismid));
+ }
linux_cpus[cpu_ctr].mid = thismid;
printk("Found CPU %d (node=%08x,mid=%d)\n",
cpu_ctr, (unsigned) scan, thismid);
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S
index 80c74aa18..f3a32d714 100644
--- a/arch/sparc64/kernel/dtlb_base.S
+++ b/arch/sparc64/kernel/dtlb_base.S
@@ -1,4 +1,4 @@
-/* $Id: dtlb_base.S,v 1.8 2000/11/10 08:28:45 davem Exp $
+/* $Id: dtlb_base.S,v 1.9 2001/03/22 00:12:32 davem Exp $
* dtlb_base.S: Front end to DTLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -10,8 +10,6 @@
#define VPTE_SHIFT (PAGE_SHIFT - 3)
#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)
-#define KERN_IOBITS (KERN_LOWBITS ^ KERN_LOWBITS_IO)
/* %g1 TLB_SFSR (%g1 + %g1 == TLB_TAG_ACCESS)
* %g2 (KERN_HIGHBITS | KERN_LOWBITS)
@@ -94,5 +92,3 @@
#undef VPTE_SHIFT
#undef KERN_HIGHBITS
#undef KERN_LOWBITS
-#undef KERN_LOWBITS_IO
-#undef KERN_IOBITS
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 6dbe45a6c..a1e633353 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.54 2001/02/13 01:16:44 davem Exp $
+/* $Id: ebus.c,v 1.60 2001/03/15 02:11:09 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -25,6 +25,7 @@ struct linux_ebus *ebus_chain = 0;
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
+extern void rs_init(void);
static inline void *ebus_alloc(size_t size)
{
@@ -159,7 +160,7 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
struct pci_controller_info *p = pbm->parent;
if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
- dev->irqs[i] = p->irq_build(p,
+ dev->irqs[i] = p->irq_build(pbm,
dev->bus->self,
irqs[i]);
} else {
@@ -200,7 +201,10 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
dev->num_addrs = len / sizeof(struct linux_prom_registers);
for (i = 0; i < dev->num_addrs; i++) {
- n = (regs[i].which_io - 0x10) >> 2;
+ if (dev->bus->is_rio == 0)
+ n = (regs[i].which_io - 0x10) >> 2;
+ else
+ n = regs[i].which_io;
dev->resource[i].start = dev->bus->self->resource[n].start;
dev->resource[i].start += (unsigned long)regs[i].phys_addr;
@@ -222,7 +226,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
struct pci_controller_info *p = pbm->parent;
if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
- dev->irqs[i] = p->irq_build(p,
+ dev->irqs[i] = p->irq_build(pbm,
dev->bus->self,
irqs[i]);
} else {
@@ -269,14 +273,19 @@ void __init ebus_init(void)
struct linux_ebus *ebus;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
- int nd, ebusnd;
+ int nd, ebusnd, is_rio;
int num_ebus = 0;
if (!pci_present())
return;
+ is_rio = 0;
pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
if (!pdev) {
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_EBUS, 0);
+ is_rio = 1;
+ }
+ if (!pdev) {
printk("ebus: No EBus's found.\n");
return;
}
@@ -286,6 +295,7 @@ void __init ebus_init(void)
ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
ebus->next = 0;
+ ebus->is_rio = is_rio;
while (ebusnd) {
/* SUNW,pci-qfe uses four empty ebuses on it.
@@ -295,8 +305,16 @@ void __init ebus_init(void)
we'd have to tweak with the ebus_chain
in the runtime after initialization. -jj */
if (!prom_getchild (ebusnd)) {
+ struct pci_dev *orig_pdev = pdev;
+
+ is_rio = 0;
pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_EBUS, pdev);
+ PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
+ if (!pdev) {
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
+ is_rio = 1;
+ }
if (!pdev) {
if (ebus == ebus_chain) {
ebus_chain = NULL;
@@ -305,7 +323,7 @@ void __init ebus_init(void)
}
break;
}
-
+ ebus->is_rio = is_rio;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
continue;
@@ -346,10 +364,20 @@ void __init ebus_init(void)
next_ebus:
printk("\n");
- pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_EBUS, pdev);
- if (!pdev)
- break;
+ {
+ struct pci_dev *orig_pdev = pdev;
+
+ is_rio = 0;
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
+ if (!pdev) {
+ pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
+ is_rio = 1;
+ }
+ if (!pdev)
+ break;
+ }
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
@@ -357,9 +385,11 @@ void __init ebus_init(void)
ebus->next = ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
ebus->next = 0;
+ ebus->is_rio = is_rio;
++num_ebus;
}
+ rs_init();
#ifdef CONFIG_SUN_AUXIO
auxio_probe();
#endif
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index fd6096ec5..9aed69e26 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.120 2000/09/08 13:58:12 jj Exp $
+/* $Id: entry.S,v 1.127 2001/03/23 07:56:30 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -42,13 +42,29 @@ sparc64_vpte_patchme2:
/* This is trivial with the new code... */
.globl do_fpdis
do_fpdis:
- ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5 ! Load Group
sethi %hi(TSTATE_PEF), %g4 ! IEU0
+ rdpr %tstate, %g5
+ andcc %g5, %g4, %g0
+ be,pt %xcc, 1f
+ nop
+ rd %fprs, %g5
+ andcc %g5, FPRS_FEF, %g0
+ be,pt %xcc, 1f
+ nop
+
+ /* Legal state when DCR_IFPOE is set in Cheetah %dcr. */
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ add %g0, %g0, %g0
+ ba,a,pt %xcc, rtrap_clr_l6
+
+1: ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5 ! Load Group
wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles
andcc %g5, FPRS_FEF, %g0 ! IEU1 Group
be,a,pt %icc, 1f ! CTI
clr %g7 ! IEU0
- ldub [%g6 + AOFF_task_thread + AOFF_thread_gsr], %g7 ! Load Group
+ ldx [%g6 + AOFF_task_thread + AOFF_thread_gsr], %g7 ! Load Group
1: andcc %g5, FPRS_DL, %g0 ! IEU1
bne,pn %icc, 2f ! CTI
fzero %f0 ! FPA
@@ -92,10 +108,9 @@ do_fpdis:
ldxa [%g3] ASI_DMMU, %g5
add %g6, AOFF_task_fpregs + 0xc0, %g2
stxa %g0, [%g3] ASI_DMMU
+ membar #Sync
faddd %f0, %f2, %f8
fmuld %f0, %f2, %f10
- flush %g6
- membar #StoreLoad | #LoadLoad
ldda [%g1] ASI_BLK_S, %f32 ! grrr, where is ASI_BLK_NUCLEUS 8-(
ldda [%g2] ASI_BLK_S, %f48
faddd %f0, %f2, %f12
@@ -118,11 +133,10 @@ do_fpdis:
ldxa [%g3] ASI_DMMU, %g5
add %g6, AOFF_task_fpregs, %g1
stxa %g0, [%g3] ASI_DMMU
+ membar #Sync
add %g6, AOFF_task_fpregs + 0x40, %g2
faddd %f32, %f34, %f36
fmuld %f32, %f34, %f38
- flush %g6
- membar #StoreLoad | #LoadLoad
ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-(
ldda [%g2] ASI_BLK_S, %f16
faddd %f32, %f34, %f40
@@ -137,15 +151,14 @@ do_fpdis:
fmuld %f32, %f34, %f58
faddd %f32, %f34, %f60
fmuld %f32, %f34, %f62
- b,pt %xcc, fpdis_exit
+ ba,pt %xcc, fpdis_exit
membar #Sync
3: mov SECONDARY_CONTEXT, %g3
add %g6, AOFF_task_fpregs, %g1
ldxa [%g3] ASI_DMMU, %g5
mov 0x40, %g2
stxa %g0, [%g3] ASI_DMMU
- flush %g6
- membar #StoreLoad | #LoadLoad
+ membar #Sync
ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-(
ldda [%g1 + %g2] ASI_BLK_S, %f16
add %g1, 0x80, %g1
@@ -154,7 +167,7 @@ do_fpdis:
membar #Sync
fpdis_exit:
stxa %g5, [%g3] ASI_DMMU
- flush %g6
+ membar #Sync
fpdis_exit2:
wr %g7, 0, %gsr
ldx [%g6 + AOFF_task_thread + AOFF_thread_xfsr], %fsr
@@ -164,22 +177,152 @@ fpdis_exit2:
wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits
retry
+ .align 32
+fp_other_bounce:
+ call do_fpother
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+ ba,pt %xcc, rtrap
+ clr %l6
+
+ .globl do_fpother_check_fitos
+ .align 32
+do_fpother_check_fitos:
+ sethi %hi(fp_other_bounce - 4), %g7
+ or %g7, %lo(fp_other_bounce - 4), %g7
+
+ /* NOTE: Need to preserve %g7 until we fully commit
+ * to the fitos fixup.
+ */
+ stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
+ rdpr %tstate, %g3
+ andcc %g3, TSTATE_PRIV, %g0
+ bne,pn %xcc, do_fptrap_after_fsr
+ nop
+ ldx [%g6 + AOFF_task_thread + AOFF_thread_xfsr], %g3
+ srlx %g3, 14, %g1
+ and %g1, 7, %g1
+ cmp %g1, 2 ! Unfinished FP-OP
+ bne,pn %xcc, do_fptrap_after_fsr
+ sethi %hi(1 << 23), %g1 ! Inexact
+ andcc %g3, %g1, %g0
+ bne,pn %xcc, do_fptrap_after_fsr
+ rdpr %tpc, %g1
+ lduwa [%g1] ASI_AIUP, %g3 ! This cannot ever fail
+#define FITOS_MASK 0xc1f83fe0
+#define FITOS_COMPARE 0x81a01880
+ sethi %hi(FITOS_MASK), %g1
+ or %g1, %lo(FITOS_MASK), %g1
+ and %g3, %g1, %g1
+ sethi %hi(FITOS_COMPARE), %g2
+ or %g2, %lo(FITOS_COMPARE), %g2
+ cmp %g1, %g2
+ bne,pn %xcc, do_fptrap_after_fsr
+ nop
+ std %f62, [%g6 + AOFF_task_fpregs + (62 * 4)]
+ sethi %hi(fitos_table_1), %g1
+ and %g3, 0x1f, %g2
+ or %g1, %lo(fitos_table_1), %g1
+ sllx %g2, 2, %g2
+ jmpl %g1 + %g2, %g0
+ ba,pt %xcc, fitos_emul_continue
+
+fitos_table_1:
+ fitod %f0, %f62
+ fitod %f1, %f62
+ fitod %f2, %f62
+ fitod %f3, %f62
+ fitod %f4, %f62
+ fitod %f5, %f62
+ fitod %f6, %f62
+ fitod %f7, %f62
+ fitod %f8, %f62
+ fitod %f9, %f62
+ fitod %f10, %f62
+ fitod %f11, %f62
+ fitod %f12, %f62
+ fitod %f13, %f62
+ fitod %f14, %f62
+ fitod %f15, %f62
+ fitod %f16, %f62
+ fitod %f17, %f62
+ fitod %f18, %f62
+ fitod %f19, %f62
+ fitod %f20, %f62
+ fitod %f21, %f62
+ fitod %f22, %f62
+ fitod %f23, %f62
+ fitod %f24, %f62
+ fitod %f25, %f62
+ fitod %f26, %f62
+ fitod %f27, %f62
+ fitod %f28, %f62
+ fitod %f29, %f62
+ fitod %f30, %f62
+ fitod %f31, %f62
+
+fitos_emul_continue:
+ sethi %hi(fitos_table_2), %g1
+ srl %g3, 25, %g2
+ or %g1, %lo(fitos_table_2), %g1
+ and %g2, 0x1f, %g2
+ sllx %g2, 2, %g2
+ jmpl %g1 + %g2, %g0
+ ba,pt %xcc, fitos_emul_fini
+
+fitos_table_2:
+ fdtos %f62, %f0
+ fdtos %f62, %f1
+ fdtos %f62, %f2
+ fdtos %f62, %f3
+ fdtos %f62, %f4
+ fdtos %f62, %f5
+ fdtos %f62, %f6
+ fdtos %f62, %f7
+ fdtos %f62, %f8
+ fdtos %f62, %f9
+ fdtos %f62, %f10
+ fdtos %f62, %f11
+ fdtos %f62, %f12
+ fdtos %f62, %f13
+ fdtos %f62, %f14
+ fdtos %f62, %f15
+ fdtos %f62, %f16
+ fdtos %f62, %f17
+ fdtos %f62, %f18
+ fdtos %f62, %f19
+ fdtos %f62, %f20
+ fdtos %f62, %f21
+ fdtos %f62, %f22
+ fdtos %f62, %f23
+ fdtos %f62, %f24
+ fdtos %f62, %f25
+ fdtos %f62, %f26
+ fdtos %f62, %f27
+ fdtos %f62, %f28
+ fdtos %f62, %f29
+ fdtos %f62, %f30
+ fdtos %f62, %f31
+
+fitos_emul_fini:
+ ldd [%g6 + AOFF_task_fpregs + (62 * 4)], %f62
+ done
+
.globl do_fptrap
.align 32
do_fptrap:
- ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3
stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
+do_fptrap_after_fsr:
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3
rd %fprs, %g1
or %g3, %g1, %g3
stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
rd %gsr, %g3
- stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr]
+ stx %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr]
mov SECONDARY_CONTEXT, %g3
add %g6, AOFF_task_fpregs, %g2
ldxa [%g3] ASI_DMMU, %g5
stxa %g0, [%g3] ASI_DMMU
- flush %g6
- membar #StoreStore | #LoadStore
+ membar #Sync
andcc %g1, FPRS_DL, %g0
be,pn %icc, 4f
mov 0x40, %g3
@@ -193,7 +336,7 @@ do_fptrap:
5: mov SECONDARY_CONTEXT, %g1
membar #Sync
stxa %g5, [%g1] ASI_DMMU
- flush %g6
+ membar #Sync
ba,pt %xcc, etrap
wr %g0, 0, %fprs
@@ -215,7 +358,7 @@ do_fptrap:
.globl do_ivec
do_ivec:
mov 0x40, %g3
- ldxa [%g3 + %g0] ASI_UDB_INTR_R, %g3
+ ldxa [%g3 + %g0] ASI_INTR_R, %g3
sethi %hi(KERNBASE), %g4
cmp %g3, %g4
bgeu,pn %xcc, do_ivec_xcall
@@ -242,10 +385,10 @@ do_ivec:
do_ivec_xcall:
mov 0x50, %g1
- ldxa [%g1 + %g0] ASI_UDB_INTR_R, %g1
+ ldxa [%g1 + %g0] ASI_INTR_R, %g1
srl %g3, 0, %g3
mov 0x60, %g7
- ldxa [%g7 + %g0] ASI_UDB_INTR_R, %g7
+ ldxa [%g7 + %g0] ASI_INTR_R, %g7
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
jmpl %g3, %g0
@@ -1114,9 +1257,18 @@ do_gettimeofday: /* %o0 = timevalp */
ldx [%g3 + %lo(timer_tick_offset)], %g3
or %g2, %lo(xtime), %g2
or %g1, %lo(timer_tick_compare), %g1
-1: ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4
- rd %tick, %o1
- ldx [%g1], %g7
+1: rdpr %ver, %o2
+ sethi %hi(0x003e0014), %o1
+ srlx %o2, 32, %o2
+ or %o1, %lo(0x003e0014), %o1
+ ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4
+ cmp %o2, %o1
+ bne,pt %xcc, 2f
+ nop
+ ba,pt %xcc, 3f
+ rd %asr24, %o1
+2: rd %tick, %o1
+3: ldx [%g1], %g7
ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o2
xor %o4, %o2, %o2
xor %o5, %o3, %o3
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index b0a8f766d..c6df20212 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.43 2000/03/29 09:55:30 davem Exp $
+/* $Id: etrap.S,v 1.44 2001/03/22 00:51:25 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -186,3 +186,5 @@ scetrap: rdpr %pil, %g2 ! Single Group
nop
#undef TASK_REGOFF
+#undef ETRAP_PSTATE1
+#undef ETRAP_PSTATE2
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 5e855ad2c..6d52fb821 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.65 2000/05/09 17:40:13 davem Exp $
+/* $Id: head.S,v 1.75 2001/03/22 09:54:26 davem Exp $
* head.S: Initial boot code for the Sparc64 port of Linux.
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,8 @@
#include <asm/signal.h>
#include <asm/processor.h>
#include <asm/lsu.h>
+#include <asm/dcr.h>
+#include <asm/dcu.h>
#include <asm/head.h>
#include <asm/ttable.h>
@@ -76,11 +78,145 @@ sparc_ramdisk_size:
* PROM entry point is on %o4
*/
sparc64_boot:
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g5
+ srlx %g1, 32, %g1
+ or %g5, %lo(0x003e0014), %g5
+ cmp %g1, %g5
+ bne,pt %icc, spitfire_boot
+ nop
+
+cheetah_boot:
+ mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
+ wr %g1, %asr18
+
+ sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+ or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+ sllx %g5, 32, %g5
+ or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g3
+ or %g5, %g3, %g5
+ stxa %g5, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+
+ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+ wr %g0, 0, %fprs
+
+ /* Just like for Spitfire, we probe itlb-2 for a mapping which
+ * matches our current %pc. We take the physical address in
+ * that mapping and use it to make our own.
+ */
+
+ /* %g5 holds the tlb data */
+ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+ sllx %g5, 32, %g5
+ or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+ /* Put PADDR tlb data mask into %g3. */
+ sethi %uhi(_PAGE_PADDR), %g3
+ or %g3, %ulo(_PAGE_PADDR), %g3
+ sllx %g3, 32, %g3
+ sethi %hi(_PAGE_PADDR), %g7
+ or %g7, %lo(_PAGE_PADDR), %g7
+ or %g3, %g7, %g3
+
+ set 2 << 16, %l0 /* TLB entry walker. */
+ set 0x1fff, %l2 /* Page mask. */
+ rd %pc, %l3
+ andn %l3, %l2, %g2 /* vaddr comparator */
+
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ membar #Sync
+ andn %g1, %l2, %g1
+ cmp %g1, %g2
+ be,pn %xcc, cheetah_got_tlbentry
+ nop
+ and %l0, (127 << 3), %g1
+ cmp %g1, (127 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+cheetah_got_tlbentry:
+ ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
+ membar #Sync
+ and %g1, %g3, %g1
+ sub %g1, %g2, %g1
+ or %g5, %g1, %g5
+
+ /* Clear out any KERNBASE area entries. */
+ set 2 << 16, %l0
+ sethi %hi(KERNBASE), %g3
+ sethi %hi(KERNBASE<<1), %g7
+ mov TLB_TAG_ACCESS, %l7
+
+ /* First, check ITLB */
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ membar #Sync
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_IMMU
+ membar #Sync
+ stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+
+2: and %l0, (127 << 3), %g1
+ cmp %g1, (127 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ /* Next, check DTLB */
+ set 2 << 16, %l0
+1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1
+ membar #Sync
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_DMMU
+ membar #Sync
+ stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
+2: and %l0, (511 << 3), %g1
+ cmp %g1, (511 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ /* Now lock the TTE we created into ITLB-0 and DTLB-0,
+ * entry 15.
+ */
+ sethi %hi(KERNBASE), %g3
+ set (0 << 16) | (15 << 3), %g7
+ stxa %g3, [%l7] ASI_DMMU
+ membar #Sync
+ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+ stxa %g3, [%l7] ASI_IMMU
+ membar #Sync
+ stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+ flush %g3
+ membar #Sync
+ ba,pt %xcc, 1f
+ nop
+
+1: set sun4u_init, %g2
+ jmpl %g2 + %g0, %g0
+ nop
+
+spitfire_boot:
/* Typically PROM has already enabled both MMU's and both on-chip
* caches, but we do it here anyway just to be paranoid.
*/
mov (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1
stxa %g1, [%g0] ASI_LSU_CONTROL
+ membar #Sync
/*
* Make sure we are in privileged mode, have address masking,
@@ -93,7 +229,7 @@ sparc64_boot:
wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
wr %g0, 0, %fprs
-create_mappings:
+spitfire_create_mappings:
/* %g5 holds the tlb data */
sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
sllx %g5, 32, %g5
@@ -104,11 +240,11 @@ create_mappings:
*/
/* Put PADDR tlb data mask into %g3. */
- sethi %uhi(_PAGE_PADDR), %g3
- or %g3, %ulo(_PAGE_PADDR), %g3
+ sethi %uhi(_PAGE_PADDR_SF), %g3
+ or %g3, %ulo(_PAGE_PADDR_SF), %g3
sllx %g3, 32, %g3
- sethi %hi(_PAGE_PADDR), %g7
- or %g7, %lo(_PAGE_PADDR), %g7
+ sethi %hi(_PAGE_PADDR_SF), %g7
+ or %g7, %lo(_PAGE_PADDR_SF), %g7
or %g3, %g7, %g3
/* Walk through entire ITLB, looking for entry which maps
@@ -126,13 +262,13 @@ create_mappings:
nop
andn %g1, %l2, %g1 /* Get vaddr */
cmp %g1, %g2
- be,a,pn %xcc, got_tlbentry
+ be,a,pn %xcc, spitfire_got_tlbentry
ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
cmp %l0, (63 << 3)
blu,pt %xcc, 1b
add %l0, (1 << 3), %l0
-got_tlbentry:
+spitfire_got_tlbentry:
/* Nops here again, perhaps Cheetah/Blackbird are better behaved... */
nop
nop
@@ -164,6 +300,7 @@ got_tlbentry:
nop
stxa %g0, [%l7] ASI_IMMU
stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS
+ membar #Sync
2:
cmp %l0, (63 << 3)
blu,pt %xcc, 1b
@@ -186,6 +323,7 @@ got_tlbentry:
nop
stxa %g0, [%l7] ASI_DMMU
stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
+ membar #Sync
2:
cmp %l0, (63 << 3)
blu,pt %xcc, 1b
@@ -235,7 +373,47 @@ sun4u_init:
mov TLB_TAG_ACCESS, %g2
stxa %g3, [%g2] ASI_IMMU
stxa %g3, [%g2] ASI_DMMU
+ membar #Sync
+
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g5
+ srlx %g1, 32, %g1
+ or %g5, %lo(0x003e0014), %g5
+ cmp %g1, %g5
+ bne,pt %icc, spitfire_tlb_fixup
+ nop
+
+cheetah_tlb_fixup:
+ set (0 << 16) | (15 << 3), %g7
+ ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+ ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
+ /* Kill instruction prefetch queues. */
+ flush %g3
+ membar #Sync
+
+ /* Set TLB type to cheetah. */
+ mov 1, %g2
+ sethi %hi(tlb_type), %g5
+ stw %g2, [%g5 + %lo(tlb_type)]
+
+ /* Patch copy/page operations to cheetah optimized versions. */
+ call cheetah_patch_copyops
+ nop
+ call cheetah_patch_pgcopyops
+ nop
+
+ ba,pt %xcc, tlb_fixup_done
+ nop
+
+spitfire_tlb_fixup:
mov (63 << 3), %g7
ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
andn %g1, (_PAGE_G), %g1
@@ -251,6 +429,12 @@ sun4u_init:
flush %g3
membar #Sync
+ /* Set TLB type to spitfire. */
+ mov 0, %g2
+ sethi %hi(tlb_type), %g5
+ stw %g2, [%g5 + %lo(tlb_type)]
+
+tlb_fixup_done:
sethi %hi(init_task_union), %g6
or %g6, %lo(init_task_union), %g6
mov %sp, %l6
@@ -285,28 +469,19 @@ sun4u_init:
wrpr %g0, 0x0, %tl
/* Clear the bss */
- sethi %hi(8191), %l2
- or %l2, %lo(8191), %l2
- sethi %hi(__bss_start), %l0
- or %l0, %lo(__bss_start), %l0
- sethi %hi(_end), %l1
- or %l1, %lo(_end), %l1
- add %l1, %l2, %l1
- andn %l1, %l2, %l1
- add %l2, 1, %l2
- add %l0, %g0, %o0
-1:
- mov %l2, %o1
+ sethi %hi(__bss_start), %o0
+ or %o0, %lo(__bss_start), %o0
+ sethi %hi(_end), %o1
+ or %o1, %lo(_end), %o1
call __bzero
- add %l0, %l2, %l0
- cmp %l0, %l1
- blu,pt %xcc, 1b
- add %l0, %g0, %o0
+ sub %o1, %o0, %o1
/* Now clear empty_zero_page */
- mov %l2, %o1
+ sethi %hi(8192), %o1
+ or %o1, %lo(8192), %o1
+ sethi %hi(KERNBASE), %g3
call __bzero
- mov %g3, %o0
+ or %g3, %lo(KERNBASE), %o0
mov %l6, %o1 ! OpenPROM stack
call prom_init
@@ -340,14 +515,16 @@ setup_tba: /* i0 = is_starfire */
wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate
/* Set fixed globals used by dTLB miss handler. */
-#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+#define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#ifdef THIS_IS_CHEETAH
-#error Dave, make sure you took care of other issues in rest of sparc64 code...
-#define VPTE_BASE 0xffe0000000000000
-#else /* Spitfire/Blackbird */
-#define VPTE_BASE 0xfffffffe00000000
+
+#define VPTE_BASE_SPITFIRE 0xfffffffe00000000
+#if 1
+#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE
+#else
+#define VPTE_BASE_CHEETAH 0xffe0000000000000
#endif
+
mov TSB_REG, %g1
stxa %g0, [%g1] ASI_DMMU
membar #Sync
@@ -356,13 +533,30 @@ setup_tba: /* i0 = is_starfire */
or %g2, %ulo(KERN_HIGHBITS), %g2
sllx %g2, 32, %g2
or %g2, KERN_LOWBITS, %g2
- sethi %uhi(VPTE_BASE), %g3
- or %g3, %ulo(VPTE_BASE), %g3
- sllx %g3, 32, %g3
+
+ rdpr %ver, %g3
+ sethi %hi(0x003e0014), %g7
+ srlx %g3, 32, %g3
+ or %g7, %lo(0x003e0014), %g7
+ cmp %g3, %g7
+ bne,pt %icc, 1f
+ nop
+
+ sethi %uhi(VPTE_BASE_CHEETAH), %g3
+ or %g3, %ulo(VPTE_BASE_CHEETAH), %g3
+ ba,pt %xcc, 2f
+ sllx %g3, 32, %g3
+1:
+ sethi %uhi(VPTE_BASE_SPITFIRE), %g3
+ or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3
+ sllx %g3, 32, %g3
+
+2:
clr %g7
#undef KERN_HIGHBITS
#undef KERN_LOWBITS
-#undef VPTE_BASE
+#undef VPTE_BASE_SPITFIRE
+#undef VPTE_BASE_CHEETAH
/* Setup Interrupt globals */
wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate
@@ -371,9 +565,6 @@ setup_tba: /* i0 = is_starfire */
or %g5, %lo(__up_workvec), %g6
#else
/* By definition of where we are, this is boot_cpu. */
- sethi %hi(cpu_data), %g5
- or %g5, %lo(cpu_data), %g5
-
brz,pt %i0, not_starfire
sethi %hi(0x1fff4000), %g1
or %g1, %lo(0x1fff4000), %g1
@@ -384,12 +575,27 @@ setup_tba: /* i0 = is_starfire */
nop
not_starfire:
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g5
+ srlx %g1, 32, %g1
+ or %g7, %lo(0x003e0014), %g5
+ cmp %g1, %g5
+ bne,pt %icc, not_cheetah
+ nop
+
+ ldxa [%g0] ASI_SAFARI_CONFIG, %g1
+ srlx %g1, 17, %g1
+ and %g1, 0x3ff, %g1 ! 10bit Safari Agent ID
+
+not_cheetah:
ldxa [%g0] ASI_UPA_CONFIG, %g1
srlx %g1, 17, %g1
and %g1, 0x1f, %g1
/* In theory this is: &(cpu_data[boot_cpu_id].irq_worklists[0]) */
set_worklist:
+ sethi %hi(cpu_data), %g5
+ or %g5, %lo(cpu_data), %g5
sllx %g1, 7, %g1
add %g5, %g1, %g5
add %g5, 64, %g6
@@ -398,9 +604,23 @@ set_worklist:
/* Kill PROM timer */
wr %g0, 0, %tick_cmpr
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g5
+ srlx %g1, 32, %g1
+ or %g7, %lo(0x003e0014), %g5
+ cmp %g1, %g5
+ bne,pt %icc, 1f
+ nop
+
+ /* Disable STICK_INT interrupts. */
+ sethi %hi(0x80000000), %g1
+ sllx %g1, 32, %g1
+ wr %g1, %asr25
+
/* Ok, we're done setting up all the state our trap mechanims needs,
* now get back into normal globals and let the PROM know what is up.
*/
+1:
wrpr %g0, %g0, %wstate
wrpr %o1, PSTATE_IE, %pstate
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index e2cdc3613..621e5762f 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.107 2001/02/13 01:16:44 davem Exp $
+/* $Id: ioctl32.c,v 1.110 2001/03/22 12:51:25 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
@@ -48,6 +48,7 @@
#include <linux/blkpg.h>
#include <linux/blk.h>
#include <linux/elevator.h>
+#include <linux/rtc.h>
#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
/* Ugh. This header really is not clean */
#define min min
@@ -67,7 +68,6 @@
#include <asm/fbio.h>
#include <asm/kbio.h>
#include <asm/vuid_event.h>
-#include <asm/rtc.h>
#include <asm/openpromio.h>
#include <asm/envctrl.h>
#include <asm/audioio.h>
@@ -2068,6 +2068,7 @@ typedef struct {
u32 proc;
u32 pv[ABS_MAX_PV + 1];
u32 lv[ABS_MAX_LV + 1];
+ uint8_t vg_uuid[UUID_LEN+1]; /* volume group UUID */
} vg32_t;
typedef struct {
@@ -2093,6 +2094,7 @@ typedef struct {
uint32_t pe_stale;
u32 pe;
u32 inode;
+ uint8_t pv_uuid[UUID_LEN+1];
} pv32_t;
typedef struct {
@@ -2103,9 +2105,16 @@ typedef struct {
typedef struct {
u32 lv_index;
u32 lv;
+ /* Transfer size because user space and kernel space differ */
+ uint16_t size;
} lv_status_byindex_req32_t;
typedef struct {
+ dev_t dev;
+ u32 lv;
+} lv_status_bydev_req32_t;
+
+typedef struct {
uint8_t lv_name[NAME_LEN];
kdev_t old_dev;
kdev_t new_dev;
@@ -2204,11 +2213,12 @@ static lv_t *get_lv_t(u32 p, int *errp)
if (l->lv_block_exception) {
lbe32 = (lv_block_exception32_t *)A(ptr2);
memset(lbe, 0, size);
- for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
- err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
- err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
- err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
- err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
+ for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) {
+ err |= get_user(lbe->rsector_org, &lbe32->rsector_org);
+ err |= __get_user(lbe->rdev_org, &lbe32->rdev_org);
+ err |= __get_user(lbe->rsector_new, &lbe32->rsector_new);
+ err |= __get_user(lbe->rdev_new, &lbe32->rdev_new);
+
}
}
}
@@ -2239,8 +2249,9 @@ static int copy_lv_t(u32 ptr, lv_t *l)
err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr,
((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr));
size = l->lv_allocated_le * sizeof(pe_t);
- err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size);
- return -EFAULT;
+ if (ptr1)
+ err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size);
+ return err ? -EFAULT : 0;
}
static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -2250,7 +2261,8 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
lv_req_t lv_req;
le_remap_req_t le_remap;
lv_status_byindex_req_t lv_byindex;
- pv_status_req32_t pv_status;
+ lv_status_bydev_req_t lv_bydev;
+ pv_status_req_t pv_status;
} u;
pv_t p;
int err;
@@ -2273,6 +2285,11 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
kfree(v);
return -EFAULT;
}
+ if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) {
+ kfree(v);
+ return -EFAULT;
+ }
+
karg = v;
memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv));
if (v->pv_max > ABS_MAX_PV || v->lv_max > ABS_MAX_LV)
@@ -2286,11 +2303,18 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
err = -ENOMEM;
break;
}
- err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8);
+ err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
if (err) {
err = -EFAULT;
break;
}
+ err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1);
+ if (err) {
+ err = -EFAULT;
+ break;
+ }
+
+
v->pv[i]->pe = NULL; v->pv[i]->inode = NULL;
}
}
@@ -2309,8 +2333,9 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case LV_EXTEND:
case LV_REDUCE:
case LV_REMOVE:
+ case LV_RENAME:
case LV_STATUS_BYNAME:
- err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
+ err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name));
if (err) return -EFAULT;
if (cmd != LV_REMOVE) {
err = __get_user(ptr, &((lv_req32_t *)arg)->lv);
@@ -2319,24 +2344,29 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
} else
u.lv_req.lv = NULL;
break;
+
+
case LV_STATUS_BYINDEX:
err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index);
err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv);
if (err) return err;
u.lv_byindex.lv = get_lv_t(ptr, &err);
break;
+ case LV_STATUS_BYDEV:
+ err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev);
+ u.lv_bydev.lv = get_lv_t(ptr, &err);
+ if (err) return err;
+ u.lv_bydev.lv = &p;
+ p.pe = NULL; p.inode = NULL;
+ break;
case VG_EXTEND:
- err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8);
+ err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1);
+ if (err) return -EFAULT;
+ err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1);
if (err) return -EFAULT;
p.pe = NULL; p.inode = NULL;
karg = &p;
break;
- case LE_REMAP:
- err = copy_from_user(&u.le_remap, (void *)arg, sizeof(le_remap_req32_t));
- if (err) return -EFAULT;
- u.le_remap.new_pe = ((le_remap_req32_t *)&u.le_remap)->new_pe;
- u.le_remap.old_pe = ((le_remap_req32_t *)&u.le_remap)->old_pe;
- break;
case PV_CHANGE:
case PV_STATUS:
err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name));
@@ -2345,7 +2375,7 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
if (err) return err;
u.pv_status.pv = &p;
if (cmd == PV_CHANGE) {
- err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8);
+ err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1);
if (err) return -EFAULT;
p.pe = NULL; p.inode = NULL;
}
@@ -2361,6 +2391,9 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc))
err = -EFAULT;
}
+ if (copy_to_user(((vg32_t *)arg)->vg_uuid, v->vg_uuid, UUID_LEN+1)) {
+ err = -EFAULT;
+ }
kfree(v);
break;
case VG_CREATE:
@@ -2383,12 +2416,21 @@ static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv);
put_lv_t(u.lv_byindex.lv);
}
+ break;
case PV_STATUS:
if (!err) {
- err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8);
- if (err) return -EFAULT;
+ err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1);
+ if (err) return -EFAULT;
+ err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1);
+ if (err) return -EFAULT;
}
break;
+ case LV_STATUS_BYDEV:
+ if (!err) {
+ if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv);
+ put_lv_t(u.lv_byindex.lv);
+ }
+ break;
}
return err;
}
@@ -3222,8 +3264,22 @@ COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
/* Little p (/dev/rtc, /dev/envctrl, etc.) */
-COMPATIBLE_IOCTL(RTCGET)
-COMPATIBLE_IOCTL(RTCSET)
+COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
+COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)
+COMPATIBLE_IOCTL(RTC_ALM_READ)
+COMPATIBLE_IOCTL(RTC_RD_TIME)
+COMPATIBLE_IOCTL(RTC_SET_TIME)
+COMPATIBLE_IOCTL(RTC_WKALM_SET)
+COMPATIBLE_IOCTL(RTC_WKALM_RD)
COMPATIBLE_IOCTL(ENVCTRL_RD_WARNING_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_SHUTDOWN_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_TEMPERATURE)
@@ -3331,6 +3387,7 @@ COMPATIBLE_IOCTL(PPPIOCSMRRU)
COMPATIBLE_IOCTL(PPPIOCCONNECT)
COMPATIBLE_IOCTL(PPPIOCDISCONN)
COMPATIBLE_IOCTL(PPPIOCATTCHAN)
+COMPATIBLE_IOCTL(PPPIOCGCHAN)
/* PPPOX */
COMPATIBLE_IOCTL(PPPOEIOCSFWD);
COMPATIBLE_IOCTL(PPPOEIOCDFWD);
@@ -3565,6 +3622,7 @@ COMPATIBLE_IOCTL(VG_SET_EXTENDABLE)
COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT)
COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST)
COMPATIBLE_IOCTL(VG_REMOVE)
+COMPATIBLE_IOCTL(VG_RENAME)
COMPATIBLE_IOCTL(VG_REDUCE)
COMPATIBLE_IOCTL(PE_LOCK_UNLOCK)
COMPATIBLE_IOCTL(PV_FLUSH)
@@ -3576,6 +3634,9 @@ COMPATIBLE_IOCTL(LVM_RESET)
COMPATIBLE_IOCTL(LV_SET_ACCESS)
COMPATIBLE_IOCTL(LV_SET_STATUS)
COMPATIBLE_IOCTL(LV_SET_ALLOCATION)
+COMPATIBLE_IOCTL(LE_REMAP)
+COMPATIBLE_IOCTL(LV_BMAP)
+COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
#endif /* LVM */
#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
@@ -3749,9 +3810,9 @@ HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl)
HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl)
HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl)
HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl)
+HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl)
HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl)
HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
-HANDLE_IOCTL(LE_REMAP, do_lvm_ioctl)
HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
#endif /* LVM */
@@ -3766,6 +3827,12 @@ HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
#endif /* DRM */
+#if 0
+HANDLE_IOCTL(RTC32_IRQP_READ, do_rtc_ioctl)
+HANDLE_IOCTL(RTC32_IRQP_SET, do_rtc_ioctl)
+HANDLE_IOCTL(RTC32_EPOCH_READ, do_rtc_ioctl)
+HANDLE_IOCTL(RTC32_EPOCH_SET, do_rtc_ioctl)
+#endif
IOCTL_TABLE_END
unsigned int ioctl32_hash_table[1024];
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 1bd29505b..dbb55aaed 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.95 2001/02/13 01:16:44 davem Exp $
+/* $Id: irq.c,v 1.99 2001/03/22 02:19:23 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -132,14 +132,23 @@ void enable_irq(unsigned int irq)
if (imap == 0UL)
return;
- if(this_is_starfire == 0) {
+ if (tlb_type == cheetah) {
+ /* We set it to our Safari AID. */
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (tid)
+ : "i" (ASI_SAFARI_CONFIG));
+ tid = ((tid & (0x3ffUL<<17)) << 9);
+ tid &= IMAP_AID_SAFARI;
+ } else if (this_is_starfire == 0) {
/* We set it to our UPA MID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid)
: "i" (ASI_UPA_CONFIG));
tid = ((tid & UPA_CONFIG_MID) << 9);
+ tid &= IMAP_TID_UPA;
} else {
tid = (starfire_translate(imap, current->processor) << 26);
+ tid &= IMAP_TID_UPA;
}
/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
@@ -150,7 +159,7 @@ void enable_irq(unsigned int irq)
*
* Things like FFB can now be handled via the new IRQ mechanism.
*/
- upa_writel(IMAP_VALID | (tid & IMAP_TID), imap);
+ upa_writel(tid | IMAP_VALID, imap);
}
/* This now gets passed true ino's as well. */
@@ -729,6 +738,10 @@ void handler_irq(int irq, struct pt_regs *regs)
/* Voo-doo programming. */
if (cpu_data[buddy].idle_volume < FORWARD_VOLUME)
should_forward = 0;
+
+ /* This just so happens to be correct on Cheetah
+ * at the moment.
+ */
buddy <<= 26;
}
#endif
@@ -737,10 +750,23 @@ void handler_irq(int irq, struct pt_regs *regs)
/*
* Check for TICK_INT on level 14 softint.
*/
- if ((irq == 14) && (get_softint() & (1UL << 0)))
- irq = 0;
-#endif
+ {
+ unsigned long clr_mask = 1 << irq;
+ unsigned long tick_mask;
+
+ if (SPARC64_USE_STICK)
+ tick_mask = (1UL << 16);
+ else
+ tick_mask = (1UL << 0);
+ if ((irq == 14) && (get_softint() & tick_mask)) {
+ irq = 0;
+ clr_mask = tick_mask;
+ }
+ clear_softint(clr_mask);
+ }
+#else
clear_softint(1 << irq);
+#endif
irq_enter(cpu, irq);
kstat.irqs[cpu][irq]++;
@@ -952,8 +978,13 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
extern void smp_tick_init(void);
#endif
- node = linux_cpus[0].prom_node;
- *clock = prom_getint(node, "clock-frequency");
+ if (!SPARC64_USE_STICK) {
+ node = linux_cpus[0].prom_node;
+ *clock = prom_getint(node, "clock-frequency");
+ } else {
+ node = prom_root_node;
+ *clock = prom_getint(node, "stick-frequency");
+ }
timer_tick_offset = *clock / HZ;
#ifdef CONFIG_SMP
smp_tick_init();
@@ -1003,6 +1034,7 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
* at the start of an I-cache line, and perform a dummy
* read back from %tick_cmpr right after writing to it. -DaveM
*/
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick, %%g1
ba,pt %%xcc, 1f
@@ -1013,6 +1045,26 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
: /* no outputs */
: "r" (timer_tick_offset)
: "g1");
+ } else {
+ /* Let the user get at STICK too. */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%asr24, %%g2
+ andn %%g2, %%g1, %%g2
+ wr %%g2, 0, %%asr24"
+ : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
+
+ __asm__ __volatile__("
+ rd %%asr24, %%g1
+ add %%g1, %0, %%g1
+ wr %%g1, 0x0, %%asr25"
+ : /* no outputs */
+ : "r" (timer_tick_offset)
+ : "g1");
+ }
/* Restore PSTATE_IE. */
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
@@ -1033,12 +1085,17 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
if (bucket->pil == 12)
return goal_cpu;
- if(this_is_starfire == 0) {
+ if (tlb_type == cheetah) {
+ tid = __cpu_logical_map[goal_cpu] << 26;
+ tid &= IMAP_AID_SAFARI;
+ } else if (this_is_starfire == 0) {
tid = __cpu_logical_map[goal_cpu] << 26;
+ tid &= IMAP_TID_UPA;
} else {
tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26);
+ tid &= IMAP_TID_UPA;
}
- upa_writel(IMAP_VALID | (tid & IMAP_TID), imap);
+ upa_writel(tid | IMAP_VALID, imap);
goal_cpu++;
if(goal_cpu >= NR_CPUS ||
@@ -1120,7 +1177,7 @@ static void kill_prom_timer(void)
stxa %%g0, [%%g0] %0
membar #Sync
" : /* no outputs */
- : "i" (ASI_INTR_RECEIVE), "i" (ASI_UDB_INTR_R)
+ : "i" (ASI_INTR_RECEIVE), "i" (ASI_INTR_R)
: "g1", "g2");
}
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 009900165..fbdb39748 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.21 2001/01/10 18:22:59 davem Exp $
+/* $Id: pci.c,v 1.23 2001/03/14 04:17:14 davem Exp $
* pci.c: UltraSparc PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -78,9 +78,7 @@ volatile int pci_poke_faulted;
/* Probe for all PCI controllers in the system. */
extern void sabre_init(int);
extern void psycho_init(int);
-#if 0
extern void schizo_init(int);
-#endif
static struct {
char *model_name;
@@ -88,12 +86,11 @@ static struct {
} pci_controller_table[] = {
{ "SUNW,sabre", sabre_init },
{ "pci108e,a000", sabre_init },
+ { "pci108e,a001", sabre_init },
{ "SUNW,psycho", psycho_init },
- { "pci108e,8000", psycho_init }
-#if 0
+ { "pci108e,8000", psycho_init },
{ "SUNW,schizo", schizo_init },
{ "pci108e,8001", schizo_init }
-#endif
};
#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
sizeof(pci_controller_table[0]))
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index ff7060c0a..bcf950ee0 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.13 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_common.c,v 1.14 2001/02/28 03:28:55 davem Exp $
* pci_common.c: PCI controller common support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -560,19 +560,19 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
/* Fully specified already? */
if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) {
- pdev->irq = p->irq_build(p, pdev, prom_irq);
+ pdev->irq = p->irq_build(pbm, pdev, prom_irq);
goto have_irq;
}
/* An onboard device? (bit 5 set) */
if ((prom_irq & PCI_IRQ_INO) & 0x20) {
- pdev->irq = p->irq_build(p, pdev, (portid << 6 | prom_irq));
+ pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq));
goto have_irq;
}
/* Can we find a matching entry in the interrupt-map? */
if (pci_intmap_match(pdev, &prom_irq)) {
- pdev->irq = p->irq_build(p, pdev, (portid << 6) | prom_irq);
+ pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq);
goto have_irq;
}
@@ -609,7 +609,7 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
}
slot = slot << 2;
- pdev->irq = p->irq_build(p, pdev,
+ pdev->irq = p->irq_build(pbm, pdev,
((portid << 6) & PCI_IRQ_IGN) |
(bus | slot | line));
}
@@ -632,17 +632,11 @@ void __init pci_fixup_irq(struct pci_pbm_info *pbm,
pci_fixup_irq(pbm, pci_bus_b(walk));
}
-#undef DEBUG_BUSMASTERING
-
static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
{
u16 cmd;
u8 hdr_type, min_gnt, ltimer;
-#ifdef DEBUG_BUSMASTERING
- printk("PCI: Checking DEV(%s), ", pdev->name);
-#endif
-
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, cmd);
@@ -652,43 +646,28 @@ static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
* mastering so we have nothing to do here.
*/
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- if ((cmd & PCI_COMMAND_MASTER) == 0) {
-#ifdef DEBUG_BUSMASTERING
- printk("no bus mastering...\n");
-#endif
+ if ((cmd & PCI_COMMAND_MASTER) == 0)
return;
- }
/* Set correct cache line size, 64-byte on all
* Sparc64 PCI systems. Note that the value is
* measured in 32-bit words.
*/
-#ifdef DEBUG_BUSMASTERING
- printk("set cachelinesize, ");
-#endif
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
64 / sizeof(u32));
pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type);
hdr_type &= ~0x80;
- if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
-#ifdef DEBUG_BUSMASTERING
- printk("hdr_type=%x, exit\n", hdr_type);
-#endif
+ if (hdr_type != PCI_HEADER_TYPE_NORMAL)
return;
- }
/* If the latency timer is already programmed with a non-zero
* value, assume whoever set it (OBP or whoever) knows what
* they are doing.
*/
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ltimer);
- if (ltimer != 0) {
-#ifdef DEBUG_BUSMASTERING
- printk("ltimer was %x, exit\n", ltimer);
-#endif
+ if (ltimer != 0)
return;
- }
/* XXX Since I'm tipping off the min grant value to
* XXX choose a suitable latency timer value, I also
@@ -738,9 +717,6 @@ static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
}
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer);
-#ifdef DEBUG_BUSMASTERING
- printk("set ltimer to %x\n", ltimer);
-#endif
}
void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 08d5b8ee3..5e21a9649 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.12 2001/01/11 16:26:45 davem Exp $
+/* $Id: pci_iommu.c,v 1.13 2001/03/14 08:42:38 davem Exp $
* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -213,9 +213,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad
first_page += PAGE_SIZE;
}
- if (iommu->iommu_ctxflush) {
- pci_iommu_write(iommu->iommu_ctxflush, ctx);
- } else {
+ {
int i;
u32 daddr = *dma_addrp;
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 7a671158e..ac7f5ab81 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.19 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_psycho.c,v 1.21 2001/02/28 03:28:55 davem Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -72,7 +72,7 @@
* ---------------------------------------------------------
*/
#define PSYCHO_CONFIG_BASE(PBM) \
- ((PBM)->parent->config_space | (1UL << 24))
+ ((PBM)->config_space | (1UL << 24))
#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \
(((unsigned long)(BUS) << 16) | \
((unsigned long)(DEVFN) << 8) | \
@@ -376,10 +376,11 @@ static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
return ret;
}
-static unsigned int __init psycho_irq_build(struct pci_controller_info *p,
+static unsigned int __init psycho_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int ino)
{
+ struct pci_controller_info *p = pbm->parent;
struct ino_bucket *bucket;
unsigned long imap, iclr;
unsigned long imap_off, iclr_off;
@@ -1002,12 +1003,13 @@ static void psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
#define PSYCHO_PCIERR_B_INO 0x31
static void __init psycho_register_error_handlers(struct pci_controller_info *p)
{
+ struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
unsigned long base = p->controller_regs;
unsigned int irq, portid = p->portid;
u64 tmp;
/* Build IRQs and register handlers. */
- irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_UE_INO);
+ irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO);
if (request_irq(irq, psycho_ue_intr,
SA_SHIRQ, "PSYCHO UE", p) < 0) {
prom_printf("PSYCHO%d: Cannot register UE interrupt.\n",
@@ -1015,7 +1017,7 @@ static void __init psycho_register_error_handlers(struct pci_controller_info *p)
prom_halt();
}
- irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_CE_INO);
+ irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO);
if (request_irq(irq, psycho_ce_intr,
SA_SHIRQ, "PSYCHO CE", p) < 0) {
prom_printf("PSYCHO%d: Cannot register CE interrupt.\n",
@@ -1023,7 +1025,7 @@ static void __init psycho_register_error_handlers(struct pci_controller_info *p)
prom_halt();
}
- irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO);
+ irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO);
if (request_irq(irq, psycho_pcierr_intr,
SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) {
prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n",
@@ -1031,7 +1033,7 @@ static void __init psycho_register_error_handlers(struct pci_controller_info *p)
prom_halt();
}
- irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO);
+ irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO);
if (request_irq(irq, psycho_pcierr_intr,
SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) {
prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n",
@@ -1574,8 +1576,10 @@ void __init psycho_init(int node)
printk("PCI: Found PSYCHO, control regs at %016lx\n",
p->controller_regs);
- p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE;
- printk("PSYCHO: PCI config space at %016lx\n", p->config_space);
+ p->pbm_A.config_space = p->pbm_B.config_space =
+ (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
+ printk("PSYCHO: Shared PCI config space at %016lx\n",
+ p->pbm_A.config_space);
/*
* Psycho's PCI MEM space is mapped to a 2GB aligned area, so
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index cce2e5467..07632eaec 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.23 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_sabre.c,v 1.25 2001/02/28 03:28:55 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -209,7 +209,7 @@
* ---------------------------------------------------------
*/
#define SABRE_CONFIG_BASE(PBM) \
- ((PBM)->parent->config_space | (1UL << 24))
+ ((PBM)->config_space | (1UL << 24))
#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \
(((unsigned long)(BUS) << 16) | \
((unsigned long)(DEVFN) << 8) | \
@@ -604,10 +604,11 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
return ret;
}
-static unsigned int __init sabre_irq_build(struct pci_controller_info *p,
+static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int ino)
{
+ struct pci_controller_info *p = pbm->parent;
struct ino_bucket *bucket;
unsigned long imap, iclr;
unsigned long imap_off, iclr_off;
@@ -961,6 +962,7 @@ static void sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
#define SABRE_PCIERR_INO 0x30
static void __init sabre_register_error_handlers(struct pci_controller_info *p)
{
+ struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
unsigned long base = p->controller_regs;
unsigned long irq, portid = p->portid;
u64 tmp;
@@ -973,7 +975,7 @@ static void __init sabre_register_error_handlers(struct pci_controller_info *p)
(SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
- irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_UE_INO);
+ irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO);
if (request_irq(irq, sabre_ue_intr,
SA_SHIRQ, "SABRE UE", p) < 0) {
prom_printf("SABRE%d: Cannot register UE interrupt.\n",
@@ -984,7 +986,7 @@ static void __init sabre_register_error_handlers(struct pci_controller_info *p)
sabre_write(base + SABRE_CE_AFSR,
(SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
- irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_CE_INO);
+ irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO);
if (request_irq(irq, sabre_ce_intr,
SA_SHIRQ, "SABRE CE", p) < 0) {
prom_printf("SABRE%d: Cannot register CE interrupt.\n",
@@ -992,7 +994,7 @@ static void __init sabre_register_error_handlers(struct pci_controller_info *p)
prom_halt();
}
- irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_PCIERR_INO);
+ irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO);
if (request_irq(irq, sabre_pcierr_intr,
SA_SHIRQ, "SABRE PCIERR", p) < 0) {
prom_printf("SABRE%d: Cannot register PciERR interrupt.\n",
@@ -1434,8 +1436,10 @@ void __init sabre_init(int pnode)
SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
/* Now map in PCI config space for entire SABRE. */
- p->config_space = p->controller_regs + SABRE_CONFIGSPACE;
- printk("SABRE: PCI config space at %016lx\n", p->config_space);
+ p->pbm_A.config_space = p->pbm_B.config_space =
+ (p->controller_regs + SABRE_CONFIGSPACE);
+ printk("SABRE: Shared PCI config space at %016lx\n",
+ p->pbm_A.config_space);
err = prom_getproperty(pnode, "virtual-dma",
(char *)&vdma[0], sizeof(vdma));
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index daac0d783..ebeeb0bfa 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.3 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_schizo.c,v 1.13 2001/03/21 00:29:58 davem Exp $
* pci_schizo.c: SCHIZO specific PCI controller support.
*
* Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -13,37 +13,244 @@
#include <asm/pbm.h>
#include <asm/iommu.h>
#include <asm/irq.h>
+#include <asm/upa.h>
#include "pci_impl.h"
+/* All SCHIZO registers are 64-bits. The following accessor
+ * routines are how they are accessed. The REG parameter
+ * is a physical address.
+ */
+#define schizo_read(__reg) \
+({ u64 __ret; \
+ __asm__ __volatile__("ldxa [%1] %2, %0" \
+ : "=r" (__ret) \
+ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory"); \
+ __ret; \
+})
+#define schizo_write(__reg, __val) \
+ __asm__ __volatile__("stxa %0, [%1] %2" \
+ : /* no outputs */ \
+ : "r" (__val), "r" (__reg), \
+ "i" (ASI_PHYS_BYPASS_EC_E))
+
+/* This is a convention that at least Excalibur and Merlin
+ * follow. I suppose the SCHIZO used in Starcat and friends
+ * will do similar.
+ *
+ * The only way I could see this changing is if the newlink
+ * block requires more space in Schizo's address space than
+ * they predicted, thus requiring an address space reorg when
+ * the newer Schizo is taped out.
+ *
+ * These offsets look weird because I keep in p->controller_regs
+ * the second PROM register property minus 0x10000 which is the
+ * base of the Safari and UPA64S registers of SCHIZO.
+ */
+#define SCHIZO_PBM_A_REGS_OFF (0x600000UL - 0x400000UL)
+#define SCHIZO_PBM_B_REGS_OFF (0x700000UL - 0x400000UL)
+
+/* Streaming buffer control register. */
+#define SCHIZO_STRBUF_CTRL_LPTR 0x00000000000000f0UL /* LRU Lock Pointer */
+#define SCHIZO_STRBUF_CTRL_LENAB 0x0000000000000008UL /* LRU Lock Enable */
+#define SCHIZO_STRBUF_CTRL_RRDIS 0x0000000000000004UL /* Rerun Disable */
+#define SCHIZO_STRBUF_CTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */
+#define SCHIZO_STRBUF_CTRL_ENAB 0x0000000000000001UL /* Streaming Buffer Enable */
+
+/* IOMMU control register. */
+#define SCHIZO_IOMMU_CTRL_RESV 0xfffffffff9000000 /* Reserved */
+#define SCHIZO_IOMMU_CTRL_XLTESTAT 0x0000000006000000 /* Translation Error Status */
+#define SCHIZO_IOMMU_CTRL_XLTEERR 0x0000000001000000 /* Translation Error encountered */
+#define SCHIZO_IOMMU_CTRL_LCKEN 0x0000000000800000 /* Enable translation locking */
+#define SCHIZO_IOMMU_CTRL_LCKPTR 0x0000000000780000 /* Translation lock pointer */
+#define SCHIZO_IOMMU_CTRL_TSBSZ 0x0000000000070000 /* TSB Size */
+#define SCHIZO_IOMMU_TSBSZ_1K 0x0000000000000000 /* TSB Table 1024 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_2K 0x0000000000010000 /* TSB Table 2048 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_4K 0x0000000000020000 /* TSB Table 4096 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_8K 0x0000000000030000 /* TSB Table 8192 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_16K 0x0000000000040000 /* TSB Table 16k 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_32K 0x0000000000050000 /* TSB Table 32k 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_64K 0x0000000000060000 /* TSB Table 64k 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_128K 0x0000000000070000 /* TSB Table 128k 8-byte entries */
+#define SCHIZO_IOMMU_CTRL_RESV2 0x000000000000fff8 /* Reserved */
+#define SCHIZO_IOMMU_CTRL_TBWSZ 0x0000000000000004 /* Assumed page size, 0=8k 1=64k */
+#define SCHIZO_IOMMU_CTRL_DENAB 0x0000000000000002 /* Diagnostic mode enable */
+#define SCHIZO_IOMMU_CTRL_ENAB 0x0000000000000001 /* IOMMU Enable */
+
+/* Schizo config space address format is nearly identical to
+ * that of PSYCHO:
+ *
+ * 32 24 23 16 15 11 10 8 7 2 1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 0| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define SCHIZO_CONFIG_BASE(PBM) ((PBM)->config_space)
+#define SCHIZO_CONFIG_ENCODE(BUS, DEVFN, REG) \
+ (((unsigned long)(BUS) << 16) | \
+ ((unsigned long)(DEVFN) << 8) | \
+ ((unsigned long)(REG)))
+
+static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm,
+ unsigned char bus,
+ unsigned int devfn,
+ int where)
+{
+ if (!pbm)
+ return NULL;
+ return (void *)
+ (SCHIZO_CONFIG_BASE(pbm) |
+ SCHIZO_CONFIG_ENCODE(bus, devfn, where));
+}
+
+/* 4 slots on pbm A, and 6 slots on pbm B. In both cases
+ * slot 0 is the SCHIZO host bridge itself.
+ */
+static int schizo_out_of_range(struct pci_pbm_info *pbm,
+ unsigned char bus,
+ unsigned char devfn)
+{
+ return ((pbm->parent == 0) ||
+ ((pbm == &pbm->parent->pbm_B) &&
+ (bus == pbm->pci_first_busno) &&
+ PCI_SLOT(devfn) > 6) ||
+ ((pbm == &pbm->parent->pbm_A) &&
+ (bus == pbm->pci_first_busno) &&
+ PCI_SLOT(devfn) > 4));
+}
+
+/* SCHIZO PCI configuration space accessors. */
+
static int schizo_read_byte(struct pci_dev *dev, int where, u8 *value)
{
- /* IMPLEMENT ME */
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u8 *addr;
+
+ *value = 0xff;
+ addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (schizo_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+ pci_config_read8(addr, value);
+ return PCIBIOS_SUCCESSFUL;
}
static int schizo_read_word(struct pci_dev *dev, int where, u16 *value)
{
- /* IMPLEMENT ME */
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u16 *addr;
+
+ *value = 0xffff;
+ addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (schizo_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where & 0x01) {
+ printk("pcibios_read_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_read16(addr, value);
+ return PCIBIOS_SUCCESSFUL;
}
static int schizo_read_dword(struct pci_dev *dev, int where, u32 *value)
{
- /* IMPLEMENT ME */
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u32 *addr;
+
+ *value = 0xffffffff;
+ addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (schizo_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where & 0x03) {
+ printk("pcibios_read_config_dword: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ pci_config_read32(addr, value);
+ return PCIBIOS_SUCCESSFUL;
}
static int schizo_write_byte(struct pci_dev *dev, int where, u8 value)
{
- /* IMPLEMENT ME */
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u8 *addr;
+
+ addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (schizo_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_config_write8(addr, value);
+ return PCIBIOS_SUCCESSFUL;
}
static int schizo_write_word(struct pci_dev *dev, int where, u16 value)
{
- /* IMPLEMENT ME */
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u16 *addr;
+
+ addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (schizo_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where & 0x01) {
+ printk("pcibios_write_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_write16(addr, value);
+ return PCIBIOS_SUCCESSFUL;
}
static int schizo_write_dword(struct pci_dev *dev, int where, u32 value)
{
- /* IMPLEMENT ME */
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u32 *addr;
+
+ addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (schizo_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where & 0x03) {
+ printk("pcibios_write_config_dword: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_write32(addr, value);
+ return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops schizo_ops = {
@@ -55,34 +262,1445 @@ static struct pci_ops schizo_ops = {
schizo_write_dword
};
-static void __init schizo_scan_bus(struct pci_controller_info *p)
+/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the
+ * imap/iclr registers are per-PBM.
+ */
+#define SCHIZO_IMAP_BASE 0x1000UL
+#define SCHIZO_ICLR_BASE 0x1400UL
+
+static unsigned long schizo_imap_offset(unsigned long ino)
{
- /* IMPLEMENT ME */
+ return SCHIZO_IMAP_BASE + (ino * 8UL);
}
-static unsigned int __init schizo_irq_build(struct pci_controller_info *p,
+static unsigned long schizo_iclr_offset(unsigned long ino)
+{
+ return SCHIZO_ICLR_BASE + (ino * 8UL);
+}
+
+/* PCI SCHIZO INO number to Sparc PIL level. This table only matters for
+ * INOs which will not have an associated PCI device struct, ie. onboard
+ * EBUS devices and PCI controller internal error interrupts.
+ */
+static unsigned char schizo_pil_table[] = {
+/*0x00*/0, 0, 0, 0, /* PCI slot 0 Int A, B, C, D */
+/*0x04*/0, 0, 0, 0, /* PCI slot 1 Int A, B, C, D */
+/*0x08*/0, 0, 0, 0, /* PCI slot 2 Int A, B, C, D */
+/*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */
+/*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */
+/*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */
+/*0x18*/3, /* SCSI */
+/*0x19*/3, /* second SCSI */
+/*0x1a*/0, /* UNKNOWN */
+/*0x1b*/0, /* UNKNOWN */
+/*0x1c*/8, /* Parallel */
+/*0x1d*/5, /* Ethernet */
+/*0x1e*/8, /* Firewire-1394 */
+/*0x1f*/9, /* USB */
+/*0x20*/13, /* Audio Record */
+/*0x21*/14, /* Audio Playback */
+/*0x22*/12, /* Serial */
+/*0x23*/2, /* EBUS I2C */
+/*0x24*/10, /* RTC Clock */
+/*0x25*/11, /* Floppy */
+/*0x26*/0, /* UNKNOWN */
+/*0x27*/0, /* UNKNOWN */
+/*0x28*/0, /* UNKNOWN */
+/*0x29*/0, /* UNKNOWN */
+/*0x2a*/10, /* UPA 1 */
+/*0x2b*/10, /* UPA 2 */
+/*0x2c*/0, /* UNKNOWN */
+/*0x2d*/0, /* UNKNOWN */
+/*0x2e*/0, /* UNKNOWN */
+/*0x2f*/0, /* UNKNOWN */
+/*0x30*/15, /* Uncorrectable ECC */
+/*0x31*/15, /* Correctable ECC */
+/*0x32*/15, /* PCI Bus A Error */
+/*0x33*/15, /* PCI Bus B Error */
+/*0x34*/15, /* Safari Bus Error */
+/*0x35*/0, /* Reserved */
+/*0x36*/0, /* Reserved */
+/*0x37*/0, /* Reserved */
+/*0x38*/0, /* Reserved for NewLink */
+/*0x39*/0, /* Reserved for NewLink */
+/*0x3a*/0, /* Reserved for NewLink */
+/*0x3b*/0, /* Reserved for NewLink */
+/*0x3c*/0, /* Reserved for NewLink */
+/*0x3d*/0, /* Reserved for NewLink */
+/*0x3e*/0, /* Reserved for NewLink */
+/*0x3f*/0, /* Reserved for NewLink */
+};
+
+static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
+{
+ int ret;
+
+ ret = schizo_pil_table[ino];
+ if (ret == 0 && pdev == NULL) {
+ ret = 1;
+ } else if (ret == 0) {
+ switch ((pdev->class >> 16) & 0x0f) {
+ case PCI_BASE_CLASS_STORAGE:
+ ret = 4;
+
+ case PCI_BASE_CLASS_NETWORK:
+ ret = 6;
+
+ case PCI_BASE_CLASS_DISPLAY:
+ ret = 9;
+
+ case PCI_BASE_CLASS_MULTIMEDIA:
+ case PCI_BASE_CLASS_MEMORY:
+ case PCI_BASE_CLASS_BRIDGE:
+ ret = 10;
+
+ default:
+ ret = 1;
+ };
+ }
+
+ return ret;
+}
+
+static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int ino)
{
- /* IMPLEMENT ME */
+ struct pci_controller_info *p = pbm->parent;
+ struct ino_bucket *bucket;
+ unsigned long imap, iclr, pbm_off;
+ unsigned long imap_off, iclr_off;
+ int pil, inofixup = 0;
+
+ if (pbm == &p->pbm_A)
+ pbm_off = SCHIZO_PBM_A_REGS_OFF;
+ else
+ pbm_off = SCHIZO_PBM_B_REGS_OFF;
+
+ ino &= PCI_IRQ_INO;
+ imap_off = schizo_imap_offset(ino);
+
+ /* Now build the IRQ bucket. */
+ pil = schizo_ino_to_pil(pdev, ino);
+ imap = p->controller_regs + pbm_off + imap_off;
+ imap += 4;
+
+ iclr_off = schizo_iclr_offset(ino);
+ iclr = p->controller_regs + pbm_off + iclr_off;
+ iclr += 4;
+
+ if (ino < 0x18)
+ inofixup = ino & 0x03;
+
+ bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+ bucket->flags |= IBF_PCI;
+
+ return __irq(bucket);
+}
+
+/* SCHIZO error handling support. */
+enum schizo_error_type {
+ UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
+};
+
+static spinlock_t stc_buf_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long stc_error_buf[128];
+static unsigned long stc_tag_buf[16];
+static unsigned long stc_line_buf[16];
+
+static void schizo_clear_other_err_intr(int irq)
+{
+ struct ino_bucket *bucket = __bucket(irq);
+ unsigned long iclr = bucket->iclr;
+
+ iclr += (SCHIZO_PBM_B_REGS_OFF - SCHIZO_PBM_A_REGS_OFF);
+ upa_writel(ICLR_IDLE, iclr);
+}
+
+#define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */
+#define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */
+#define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */
+
+#define SCHIZO_STCERR_WRITE 0x2UL
+#define SCHIZO_STCERR_READ 0x1UL
+
+#define SCHIZO_STCTAG_PPN 0x3fffffff00000000UL
+#define SCHIZO_STCTAG_VPN 0x00000000ffffe000UL
+#define SCHIZO_STCTAG_VALID 0x8000000000000000UL
+#define SCHIZO_STCTAG_READ 0x4000000000000000UL
+
+#define SCHIZO_STCLINE_LINDX 0x0000000007800000UL
+#define SCHIZO_STCLINE_SPTR 0x000000000007e000UL
+#define SCHIZO_STCLINE_LADDR 0x0000000000001fc0UL
+#define SCHIZO_STCLINE_EPTR 0x000000000000003fUL
+#define SCHIZO_STCLINE_VALID 0x0000000000600000UL
+#define SCHIZO_STCLINE_FOFN 0x0000000000180000UL
+
+static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
+ enum schizo_error_type type)
+{
+ struct pci_controller_info *p = pbm->parent;
+ struct pci_strbuf *strbuf = &pbm->stc;
+ unsigned long regbase = p->controller_regs;
+ unsigned long err_base, tag_base, line_base;
+ u64 control;
+ char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B');
+ int i;
+
+ if (pbm == &p->pbm_A)
+ regbase += SCHIZO_PBM_A_REGS_OFF;
+ else
+ regbase += SCHIZO_PBM_B_REGS_OFF;
+
+ err_base = regbase + SCHIZO_STC_ERR;
+ tag_base = regbase + SCHIZO_STC_TAG;
+ line_base = regbase + SCHIZO_STC_LINE;
+
+ spin_lock(&stc_buf_lock);
+
+ /* This is __REALLY__ dangerous. When we put the
+ * streaming buffer into diagnostic mode to probe
+ * it's tags and error status, we _must_ clear all
+ * of the line tag valid bits before re-enabling
+ * the streaming buffer. If any dirty data lives
+ * in the STC when we do this, we will end up
+ * invalidating it before it has a chance to reach
+ * main memory.
+ */
+ control = schizo_read(strbuf->strbuf_control);
+ schizo_write(strbuf->strbuf_control,
+ (control | SCHIZO_STRBUF_CTRL_DENAB));
+ for (i = 0; i < 128; i++) {
+ unsigned long val;
+
+ val = schizo_read(err_base + (i * 8UL));
+ schizo_write(err_base + (i * 8UL), 0UL);
+ stc_error_buf[i] = val;
+ }
+ for (i = 0; i < 16; i++) {
+ stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL));
+ stc_line_buf[i] = schizo_read(line_base + (i * 8UL));
+ schizo_write(tag_base + (i * 8UL), 0UL);
+ schizo_write(line_base + (i * 8UL), 0UL);
+ }
+
+ /* OK, state is logged, exit diagnostic mode. */
+ schizo_write(strbuf->strbuf_control, control);
+
+ for (i = 0; i < 16; i++) {
+ int j, saw_error, first, last;
+
+ saw_error = 0;
+ first = i * 8;
+ last = first + 8;
+ for (j = first; j < last; j++) {
+ unsigned long errval = stc_error_buf[j];
+ if (errval != 0) {
+ saw_error++;
+ printk("SCHIZO%d: PBM-%c STC_ERR(%d)[wr(%d)rd(%d)]\n",
+ p->index, pbm_name,
+ j,
+ (errval & SCHIZO_STCERR_WRITE) ? 1 : 0,
+ (errval & SCHIZO_STCERR_READ) ? 1 : 0);
+ }
+ }
+ if (saw_error != 0) {
+ unsigned long tagval = stc_tag_buf[i];
+ unsigned long lineval = stc_line_buf[i];
+ printk("SCHIZO%d: PBM-%c STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n",
+ p->index, pbm_name,
+ i,
+ ((tagval & SCHIZO_STCTAG_PPN) >> 19UL),
+ (tagval & SCHIZO_STCTAG_VPN),
+ ((tagval & SCHIZO_STCTAG_VALID) ? 1 : 0),
+ ((tagval & SCHIZO_STCTAG_READ) ? 1 : 0));
+
+ /* XXX Should spit out per-bank error information... -DaveM */
+ printk("SCHIZO%d: PBM-%c STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
+ "V(%d)FOFN(%d)]\n",
+ p->index, pbm_name,
+ i,
+ ((lineval & SCHIZO_STCLINE_LINDX) >> 23UL),
+ ((lineval & SCHIZO_STCLINE_SPTR) >> 13UL),
+ ((lineval & SCHIZO_STCLINE_LADDR) >> 6UL),
+ ((lineval & SCHIZO_STCLINE_EPTR) >> 0UL),
+ ((lineval & SCHIZO_STCLINE_VALID) ? 1 : 0),
+ ((lineval & SCHIZO_STCLINE_FOFN) ? 1 : 0));
+ }
+ }
+
+ spin_unlock(&stc_buf_lock);
+}
+
+/* IOMMU is per-PBM in Schizo, so interrogate both for anonymous
+ * controller level errors.
+ */
+
+#define SCHIZO_IOMMU_TAG 0xa580UL
+#define SCHIZO_IOMMU_DATA 0xa600UL
+
+#define SCHIZO_IOMMU_TAG_CTXT 0x0000001ffe000000UL
+#define SCHIZO_IOMMU_TAG_ERRSTS 0x0000000001800000UL
+#define SCHIZO_IOMMU_TAG_ERR 0x0000000000400000UL
+#define SCHIZO_IOMMU_TAG_WRITE 0x0000000000200000UL
+#define SCHIZO_IOMMU_TAG_STREAM 0x0000000000100000UL
+#define SCHIZO_IOMMU_TAG_SIZE 0x0000000000080000UL
+#define SCHIZO_IOMMU_TAG_VPAGE 0x000000000007ffffUL
+
+#define SCHIZO_IOMMU_DATA_VALID 0x0000000100000000UL
+#define SCHIZO_IOMMU_DATA_CACHE 0x0000000040000000UL
+#define SCHIZO_IOMMU_DATA_PPAGE 0x000000003fffffffUL
+
+static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
+ enum schizo_error_type type)
+{
+ struct pci_controller_info *p = pbm->parent;
+ struct pci_iommu *iommu = pbm->iommu;
+ unsigned long iommu_tag[16];
+ unsigned long iommu_data[16];
+ unsigned long flags;
+ u64 control;
+ char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B');
+ int i;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ control = schizo_read(iommu->iommu_control);
+ if (control & SCHIZO_IOMMU_CTRL_XLTEERR) {
+ unsigned long base;
+ char *type_string;
+
+ /* Clear the error encountered bit. */
+ control &= ~SCHIZO_IOMMU_CTRL_XLTEERR;
+ schizo_write(iommu->iommu_control, control);
+
+ switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
+ case 0:
+ type_string = "Protection Error";
+ break;
+ case 1:
+ type_string = "Invalid Error";
+ break;
+ case 2:
+ type_string = "TimeOut Error";
+ break;
+ case 3:
+ default:
+ type_string = "ECC Error";
+ break;
+ };
+ printk("SCHIZO%d: PBM-%c IOMMU Error, type[%s]\n",
+ p->index, pbm_name, type_string);
+
+ /* Put the IOMMU into diagnostic mode and probe
+ * it's TLB for entries with error status.
+ *
+ * It is very possible for another DVMA to occur
+ * while we do this probe, and corrupt the system
+ * further. But we are so screwed at this point
+ * that we are likely to crash hard anyways, so
+ * get as much diagnostic information to the
+ * console as we can.
+ */
+ schizo_write(iommu->iommu_control,
+ control | SCHIZO_IOMMU_CTRL_DENAB);
+
+ base = p->controller_regs;
+ if (pbm == &p->pbm_A)
+ base += SCHIZO_PBM_A_REGS_OFF;
+ else
+ base += SCHIZO_PBM_B_REGS_OFF;
+
+ for (i = 0; i < 16; i++) {
+ iommu_tag[i] =
+ schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+ iommu_data[i] =
+ schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+
+ /* Now clear out the entry. */
+ schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
+ schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+ }
+
+ /* Leave diagnostic mode. */
+ schizo_write(iommu->iommu_control, control);
+
+ for (i = 0; i < 16; i++) {
+ unsigned long tag, data;
+
+ tag = iommu_tag[i];
+ if (!(tag & SCHIZO_IOMMU_TAG_ERR))
+ continue;
+
+ data = iommu_data[i];
+ switch((tag & SCHIZO_IOMMU_TAG_ERRSTS) >> 23UL) {
+ case 0:
+ type_string = "Protection Error";
+ break;
+ case 1:
+ type_string = "Invalid Error";
+ break;
+ case 2:
+ type_string = "TimeOut Error";
+ break;
+ case 3:
+ default:
+ type_string = "ECC Error";
+ break;
+ };
+ printk("SCHIZO%d: PBM-%c IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) "
+ "sz(%dK) vpg(%08lx)]\n",
+ p->index, pbm_name, i, type_string,
+ (int)((tag & SCHIZO_IOMMU_TAG_CTXT) >> 25UL),
+ ((tag & SCHIZO_IOMMU_TAG_WRITE) ? 1 : 0),
+ ((tag & SCHIZO_IOMMU_TAG_STREAM) ? 1 : 0),
+ ((tag & SCHIZO_IOMMU_TAG_SIZE) ? 64 : 8),
+ (tag & SCHIZO_IOMMU_TAG_VPAGE) << PAGE_SHIFT);
+ printk("SCHIZO%d: PBM-%c IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
+ p->index, pbm_name, i,
+ ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0),
+ ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0),
+ (data & SCHIZO_IOMMU_DATA_PPAGE) << PAGE_SHIFT);
+ }
+ }
+ __schizo_check_stc_error_pbm(pbm, type);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void schizo_check_iommu_error(struct pci_controller_info *p,
+ enum schizo_error_type type)
+{
+ schizo_check_iommu_error_pbm(&p->pbm_A, type);
+ schizo_check_iommu_error_pbm(&p->pbm_B, type);
+}
+
+/* Uncorrectable ECC error status gathering. */
+#define SCHIZO_UE_AFSR 0x10030UL
+#define SCHIZO_UE_AFAR 0x10038UL
+
+#define SCHIZO_UEAFSR_PPIO 0x8000000000000000UL
+#define SCHIZO_UEAFSR_PDRD 0x4000000000000000UL
+#define SCHIZO_UEAFSR_PDWR 0x2000000000000000UL
+#define SCHIZO_UEAFSR_SPIO 0x1000000000000000UL
+#define SCHIZO_UEAFSR_SDMA 0x0800000000000000UL
+#define SCHIZO_UEAFSR_ERRPNDG 0x0300000000000000UL
+#define SCHIZO_UEAFSR_BMSK 0x000003ff00000000UL
+#define SCHIZO_UEAFSR_QOFF 0x00000000c0000000UL
+#define SCHIZO_UEAFSR_AID 0x000000001f000000UL
+#define SCHIZO_UEAFSR_PARTIAL 0x0000000000800000UL
+#define SCHIZO_UEAFSR_OWNEDIN 0x0000000000400000UL
+#define SCHIZO_UEAFSR_MTAGSYND 0x00000000000f0000UL
+#define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL
+#define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL
+
+static void schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->controller_regs + SCHIZO_UE_AFSR;
+ unsigned long afar_reg = p->controller_regs + SCHIZO_UE_AFAR;
+ unsigned long afsr, afar, error_bits;
+ int reported, limit;
+
+ /* Latch uncorrectable error status. */
+ afar = schizo_read(afar_reg);
+
+ /* If either of the error pending bits are set in the
+ * AFSR, the error status is being actively updated by
+ * the hardware and we must re-read to get a clean value.
+ */
+ limit = 1000;
+ do {
+ afsr = schizo_read(afsr_reg);
+ } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
+
+ /* Clear the primary/secondary error status bits. */
+ error_bits = afsr &
+ (SCHIZO_UEAFSR_PPIO | SCHIZO_UEAFSR_PDRD | SCHIZO_UEAFSR_PDWR |
+ SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
+ schizo_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("SCHIZO%d: Uncorrectable Error, primary error type[%s]\n",
+ p->index,
+ (((error_bits & SCHIZO_UEAFSR_PPIO) ?
+ "PIO" :
+ ((error_bits & SCHIZO_UEAFSR_PDRD) ?
+ "DMA Read" :
+ ((error_bits & SCHIZO_UEAFSR_PDWR) ?
+ "DMA Write" : "???")))));
+ printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+ p->index,
+ (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
+ (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
+ (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
+ printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+ p->index,
+ (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
+ (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
+ (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
+ (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
+ (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
+ printk("SCHIZO%d: UE AFAR [%016lx]\n", p->index, afar);
+ printk("SCHIZO%d: UE Secondary errors [", p->index);
+ reported = 0;
+ if (afsr & SCHIZO_UEAFSR_SPIO) {
+ reported++;
+ printk("(PIO)");
+ }
+ if (afsr & SCHIZO_UEAFSR_SDMA) {
+ reported++;
+ printk("(DMA)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ /* Interrogate IOMMU for error status. */
+ schizo_check_iommu_error(p, UE_ERR);
+
+ schizo_clear_other_err_intr(irq);
+}
+
+#define SCHIZO_CE_AFSR 0x10040UL
+#define SCHIZO_CE_AFAR 0x10048UL
+
+#define SCHIZO_CEAFSR_PPIO 0x8000000000000000UL
+#define SCHIZO_CEAFSR_PDRD 0x4000000000000000UL
+#define SCHIZO_CEAFSR_PDWR 0x2000000000000000UL
+#define SCHIZO_CEAFSR_SPIO 0x1000000000000000UL
+#define SCHIZO_CEAFSR_SDMA 0x0800000000000000UL
+#define SCHIZO_CEAFSR_ERRPNDG 0x0300000000000000UL
+#define SCHIZO_CEAFSR_BMSK 0x000003ff00000000UL
+#define SCHIZO_CEAFSR_QOFF 0x00000000c0000000UL
+#define SCHIZO_CEAFSR_AID 0x000000001f000000UL
+#define SCHIZO_CEAFSR_PARTIAL 0x0000000000800000UL
+#define SCHIZO_CEAFSR_OWNEDIN 0x0000000000400000UL
+#define SCHIZO_CEAFSR_MTAGSYND 0x00000000000f0000UL
+#define SCHIZO_CEAFSR_MTAG 0x000000000000e000UL
+#define SCHIZO_CEAFSR_ECCSYND 0x00000000000001ffUL
+
+static void schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg = p->controller_regs + SCHIZO_CE_AFSR;
+ unsigned long afar_reg = p->controller_regs + SCHIZO_CE_AFAR;
+ unsigned long afsr, afar, error_bits;
+ int reported, limit;
+
+ /* Latch error status. */
+ afar = schizo_read(afar_reg);
+
+ /* If either of the error pending bits are set in the
+ * AFSR, the error status is being actively updated by
+ * the hardware and we must re-read to get a clean value.
+ */
+ limit = 1000;
+ do {
+ afsr = schizo_read(afsr_reg);
+ } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (SCHIZO_CEAFSR_PPIO | SCHIZO_CEAFSR_PDRD | SCHIZO_CEAFSR_PDWR |
+ SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
+ schizo_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("SCHIZO%d: Correctable Error, primary error type[%s]\n",
+ p->index,
+ (((error_bits & SCHIZO_CEAFSR_PPIO) ?
+ "PIO" :
+ ((error_bits & SCHIZO_CEAFSR_PDRD) ?
+ "DMA Read" :
+ ((error_bits & SCHIZO_CEAFSR_PDWR) ?
+ "DMA Write" : "???")))));
+
+ /* XXX Use syndrome and afar to print out module string just like
+ * XXX UDB CE trap handler does... -DaveM
+ */
+ printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+ p->index,
+ (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
+ (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
+ (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
+ printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+ p->index,
+ (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
+ (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
+ (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
+ (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
+ (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
+ printk("SCHIZO%d: CE AFAR [%016lx]\n", p->index, afar);
+ printk("SCHIZO%d: CE Secondary errors [", p->index);
+ reported = 0;
+ if (afsr & SCHIZO_CEAFSR_SPIO) {
+ reported++;
+ printk("(PIO)");
+ }
+ if (afsr & SCHIZO_CEAFSR_SDMA) {
+ reported++;
+ printk("(DMA)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ schizo_clear_other_err_intr(irq);
+}
+
+#define SCHIZO_PCI_AFSR 0x2010UL
+#define SCHIZO_PCI_AFAR 0x2018UL
+
+#define SCHIZO_PCIAFSR_PMA 0x8000000000000000UL
+#define SCHIZO_PCIAFSR_PTA 0x4000000000000000UL
+#define SCHIZO_PCIAFSR_PRTRY 0x2000000000000000UL
+#define SCHIZO_PCIAFSR_PPERR 0x1000000000000000UL
+#define SCHIZO_PCIAFSR_PTTO 0x0800000000000000UL
+#define SCHIZO_PCIAFSR_PUNUS 0x0400000000000000UL
+#define SCHIZO_PCIAFSR_SMA 0x0200000000000000UL
+#define SCHIZO_PCIAFSR_STA 0x0100000000000000UL
+#define SCHIZO_PCIAFSR_SRTRY 0x0080000000000000UL
+#define SCHIZO_PCIAFSR_SPERR 0x0040000000000000UL
+#define SCHIZO_PCIAFSR_STTO 0x0020000000000000UL
+#define SCHIZO_PCIAFSR_SUNUS 0x0010000000000000UL
+#define SCHIZO_PCIAFSR_BMSK 0x000003ff00000000UL
+#define SCHIZO_PCIAFSR_BLK 0x0000000080000000UL
+#define SCHIZO_PCIAFSR_CFG 0x0000000040000000UL
+#define SCHIZO_PCIAFSR_MEM 0x0000000020000000UL
+#define SCHIZO_PCIAFSR_IO 0x0000000010000000UL
+
+static void schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pci_pbm_info *pbm = dev_id;
+ struct pci_controller_info *p = pbm->parent;
+ unsigned long afsr_reg, afar_reg, base;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+ char pbm_name;
+
+ base = p->controller_regs;
+ if (pbm == &pbm->parent->pbm_A) {
+ base += SCHIZO_PBM_A_REGS_OFF;
+ pbm_name = 'A';
+ } else {
+ base += SCHIZO_PBM_B_REGS_OFF;
+ pbm_name = 'B';
+ }
+
+ afsr_reg = base + SCHIZO_PCI_AFSR;
+ afar_reg = base + SCHIZO_PCI_AFAR;
+
+ /* Latch error status. */
+ afar = schizo_read(afar_reg);
+ afsr = schizo_read(afsr_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+ SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+ SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+ SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+ SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+ SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
+ schizo_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("SCHIZO%d: PBM-%c PCI Error, primary error type[%s]\n",
+ p->index, pbm_name,
+ (((error_bits & SCHIZO_PCIAFSR_PMA) ?
+ "Master Abort" :
+ ((error_bits & SCHIZO_PCIAFSR_PTA) ?
+ "Target Abort" :
+ ((error_bits & SCHIZO_PCIAFSR_PRTRY) ?
+ "Excessive Retries" :
+ ((error_bits & SCHIZO_PCIAFSR_PPERR) ?
+ "Parity Error" :
+ ((error_bits & SCHIZO_PCIAFSR_PTTO) ?
+ "Timeout" :
+ ((error_bits & SCHIZO_PCIAFSR_PUNUS) ?
+ "Bus Unusable" : "???"))))))));
+ printk("SCHIZO%d: PBM-%c bytemask[%04lx] was_block(%d) space(%s)\n",
+ p->index, pbm_name,
+ (afsr & SCHIZO_PCIAFSR_BMSK) >> 32UL,
+ (afsr & SCHIZO_PCIAFSR_BLK) ? 1 : 0,
+ ((afsr & SCHIZO_PCIAFSR_CFG) ?
+ "Config" :
+ ((afsr & SCHIZO_PCIAFSR_MEM) ?
+ "Memory" :
+ ((afsr & SCHIZO_PCIAFSR_IO) ?
+ "I/O" : "???"))));
+ printk("SCHIZO%d: PBM-%c PCI AFAR [%016lx]\n",
+ p->index, pbm_name, afar);
+ printk("SCHIZO%d: PBM-%c PCI Secondary errors [",
+ p->index, pbm_name);
+ reported = 0;
+ if (afsr & SCHIZO_PCIAFSR_SMA) {
+ reported++;
+ printk("(Master Abort)");
+ }
+ if (afsr & SCHIZO_PCIAFSR_STA) {
+ reported++;
+ printk("(Target Abort)");
+ }
+ if (afsr & SCHIZO_PCIAFSR_SRTRY) {
+ reported++;
+ printk("(Excessive Retries)");
+ }
+ if (afsr & SCHIZO_PCIAFSR_SPERR) {
+ reported++;
+ printk("(Parity Error)");
+ }
+ if (afsr & SCHIZO_PCIAFSR_STTO) {
+ reported++;
+ printk("(Timeout)");
+ }
+ if (afsr & SCHIZO_PCIAFSR_SUNUS) {
+ reported++;
+ printk("(Bus Unusable)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ /* For the error types shown, scan PBM's PCI bus for devices
+ * which have logged that error type.
+ */
+
+ /* If we see a Target Abort, this could be the result of an
+ * IOMMU translation error of some sort. It is extremely
+ * useful to log this information as usually it indicates
+ * a bug in the IOMMU support code or a PCI device driver.
+ */
+ if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
+ schizo_check_iommu_error(p, PCI_ERR);
+ pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+ }
+ if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
+ pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+
+ /* For excessive retries, PSYCHO/PBM will abort the device
+ * and there is no way to specifically check for excessive
+ * retries in the config space status registers. So what
+ * we hope is that we'll catch it via the master/target
+ * abort events.
+ */
+
+ if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
+ pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+
+ schizo_clear_other_err_intr(irq);
+}
+
+#define SCHIZO_SAFARI_ERRLOG 0x10018UL
+
+#define SAFARI_ERRLOG_ERROUT 0x8000000000000000UL
+
+#define SAFARI_ERROR_BADCMD 0x4000000000000000UL
+#define SAFARI_ERROR_SSMDIS 0x2000000000000000UL
+#define SAFARI_ERROR_BADMA 0x1000000000000000UL
+#define SAFARI_ERROR_BADMB 0x0800000000000000UL
+#define SAFARI_ERROR_BADMC 0x0400000000000000UL
+#define SAFARI_ERROR_CPU1PS 0x0000000000002000UL
+#define SAFARI_ERROR_CPU1PB 0x0000000000001000UL
+#define SAFARI_ERROR_CPU0PS 0x0000000000000800UL
+#define SAFARI_ERROR_CPU0PB 0x0000000000000400UL
+#define SAFARI_ERROR_CIQTO 0x0000000000000200UL
+#define SAFARI_ERROR_LPQTO 0x0000000000000100UL
+#define SAFARI_ERROR_SFPQTO 0x0000000000000080UL
+#define SAFARI_ERROR_UFPQTO 0x0000000000000040UL
+#define SAFARI_ERROR_APERR 0x0000000000000020UL
+#define SAFARI_ERROR_UNMAP 0x0000000000000010UL
+#define SAFARI_ERROR_BUSERR 0x0000000000000004UL
+#define SAFARI_ERROR_TIMEOUT 0x0000000000000002UL
+#define SAFARI_ERROR_ILL 0x0000000000000001UL
+
+/* We only expect UNMAP errors here. The rest of the Safari errors
+ * are marked fatal and thus cause a system reset.
+ */
+static void schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pci_controller_info *p = dev_id;
+ u64 errlog;
+
+ errlog = schizo_read(p->controller_regs + SCHIZO_SAFARI_ERRLOG);
+ schizo_write(p->controller_regs + SCHIZO_SAFARI_ERRLOG,
+ errlog & ~(SAFARI_ERRLOG_ERROUT));
+
+ if (!(errlog & SAFARI_ERROR_UNMAP)) {
+ printk("SCHIZO%d: Unexpected Safari error interrupt, errlog[%016lx]\n",
+ p->index, errlog);
+
+ schizo_clear_other_err_intr(irq);
+ return;
+ }
+
+ printk("SCHIZO%d: Safari interrupt, UNMAPPED error, interrogating IOMMUs.\n",
+ p->index);
+ schizo_check_iommu_error(p, SAFARI_ERR);
+
+ schizo_clear_other_err_intr(irq);
+}
+
+/* Nearly identical to PSYCHO equivalents... */
+#define SCHIZO_ECC_CTRL 0x10020UL
+#define SCHIZO_ECCCTRL_EE 0x8000000000000000 /* Enable ECC Checking */
+#define SCHIZO_ECCCTRL_UE 0x4000000000000000 /* Enable UE Interrupts */
+#define SCHIZO_ECCCTRL_CE 0x2000000000000000 /* Enable CE INterrupts */
+
+#define SCHIZO_SAFARI_ERRCTRL 0x10008UL
+#define SCHIZO_SAFERRCTRL_EN 0x8000000000000000UL
+#define SCHIZO_SAFARI_IRQCTRL 0x10010UL
+#define SCHIZO_SAFIRQCTRL_EN 0x8000000000000000UL
+
+#define SCHIZO_UE_INO 0x30 /* Uncorrectable ECC error */
+#define SCHIZO_CE_INO 0x31 /* Correctable ECC error */
+#define SCHIZO_PCIERR_A_INO 0x32 /* PBM A PCI bus error */
+#define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */
+#define SCHIZO_SERR_INO 0x34 /* Safari interface error */
+
+#define SCHIZO_PCIA_CTRL (SCHIZO_PBM_A_REGS_OFF + 0x2000UL)
+#define SCHIZO_PCIB_CTRL (SCHIZO_PBM_B_REGS_OFF + 0x2000UL)
+#define SCHIZO_PCICTRL_BUNUS (1UL << 63UL)
+#define SCHIZO_PCICTRL_ESLCK (1UL << 51UL)
+#define SCHIZO_PCICTRL_TTO_ERR (1UL << 38UL)
+#define SCHIZO_PCICTRL_RTRY_ERR (1UL << 37UL)
+#define SCHIZO_PCICTRL_DTO_ERR (1UL << 36UL)
+#define SCHIZO_PCICTRL_SBH_ERR (1UL << 35UL)
+#define SCHIZO_PCICTRL_SERR (1UL << 34UL)
+#define SCHIZO_PCICTRL_SBH_INT (1UL << 18UL)
+#define SCHIZO_PCICTRL_EEN (1UL << 17UL)
+
+static void __init schizo_register_error_handlers(struct pci_controller_info *p)
+{
+ struct pci_pbm_info *pbm_a = &p->pbm_A;
+ struct pci_pbm_info *pbm_b = &p->pbm_B;
+ unsigned long base = p->controller_regs;
+ unsigned int irq, portid = p->portid;
+ struct ino_bucket *bucket;
+ u64 tmp;
+
+ /* Build IRQs and register handlers. */
+ irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_UE_INO);
+ if (request_irq(irq, schizo_ue_intr,
+ SA_SHIRQ, "SCHIZO UE", p) < 0) {
+ prom_printf("SCHIZO%d: Cannot register UE interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+ bucket = __bucket(irq);
+ tmp = readl(bucket->imap);
+ upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_UE_INO) + 4));
+
+ irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_CE_INO);
+ if (request_irq(irq, schizo_ce_intr,
+ SA_SHIRQ, "SCHIZO CE", p) < 0) {
+ prom_printf("SCHIZO%d: Cannot register CE interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+ bucket = __bucket(irq);
+ tmp = upa_readl(bucket->imap);
+ upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_CE_INO) + 4));
+
+ irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_A_INO);
+ if (request_irq(irq, schizo_pcierr_intr,
+ SA_SHIRQ, "SCHIZO PCIERR", pbm_a) < 0) {
+ prom_printf("SCHIZO%d(PBMA): Cannot register PciERR interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+ bucket = __bucket(irq);
+ tmp = upa_readl(bucket->imap);
+ upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+
+ irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
+ if (request_irq(irq, schizo_pcierr_intr,
+ SA_SHIRQ, "SCHIZO PCIERR", pbm_b) < 0) {
+ prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+ bucket = __bucket(irq);
+ tmp = upa_readl(bucket->imap);
+ upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
+
+ irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_SERR_INO);
+ if (request_irq(irq, schizo_safarierr_intr,
+ SA_SHIRQ, "SCHIZO SERR", p) < 0) {
+ prom_printf("SCHIZO%d(PBMB): Cannot register SafariERR interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+ bucket = __bucket(irq);
+ tmp = upa_readl(bucket->imap);
+ upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_SERR_INO) + 4));
+
+ /* Enable UE and CE interrupts for controller. */
+ schizo_write(base + SCHIZO_ECC_CTRL,
+ (SCHIZO_ECCCTRL_EE |
+ SCHIZO_ECCCTRL_UE |
+ SCHIZO_ECCCTRL_CE));
+
+ /* Enable PCI Error interrupts and clear error
+ * bits for each PBM.
+ */
+ tmp = schizo_read(base + SCHIZO_PCIA_CTRL);
+ tmp |= (SCHIZO_PCICTRL_BUNUS |
+ SCHIZO_PCICTRL_ESLCK |
+ SCHIZO_PCICTRL_TTO_ERR |
+ SCHIZO_PCICTRL_RTRY_ERR |
+ SCHIZO_PCICTRL_DTO_ERR |
+ SCHIZO_PCICTRL_SBH_ERR |
+ SCHIZO_PCICTRL_SERR |
+ SCHIZO_PCICTRL_SBH_INT |
+ SCHIZO_PCICTRL_EEN);
+ schizo_write(base + SCHIZO_PCIA_CTRL, tmp);
+
+ tmp = schizo_read(base + SCHIZO_PCIB_CTRL);
+ tmp |= (SCHIZO_PCICTRL_BUNUS |
+ SCHIZO_PCICTRL_ESLCK |
+ SCHIZO_PCICTRL_TTO_ERR |
+ SCHIZO_PCICTRL_RTRY_ERR |
+ SCHIZO_PCICTRL_DTO_ERR |
+ SCHIZO_PCICTRL_SBH_ERR |
+ SCHIZO_PCICTRL_SERR |
+ SCHIZO_PCICTRL_SBH_INT |
+ SCHIZO_PCICTRL_EEN);
+ schizo_write(base + SCHIZO_PCIB_CTRL, tmp);
+
+ schizo_write(base + SCHIZO_PBM_A_REGS_OFF + SCHIZO_PCI_AFSR,
+ (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+ SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+ SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+ SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+ SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+ SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
+ schizo_write(base + SCHIZO_PBM_B_REGS_OFF + SCHIZO_PCI_AFSR,
+ (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+ SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+ SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+ SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+ SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+ SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
+
+ /* Make all Safari error conditions fatal except unmapped errors
+ * which we make generate interrupts.
+ */
+ schizo_write(base + SCHIZO_SAFARI_ERRCTRL,
+ (SCHIZO_SAFERRCTRL_EN |
+ (SAFARI_ERROR_BADCMD | SAFARI_ERROR_SSMDIS |
+ SAFARI_ERROR_BADMA | SAFARI_ERROR_BADMB |
+ SAFARI_ERROR_BADMC | SAFARI_ERROR_CPU1PS |
+ SAFARI_ERROR_CPU1PB | SAFARI_ERROR_CPU0PS |
+ SAFARI_ERROR_CPU0PB | SAFARI_ERROR_CIQTO |
+ SAFARI_ERROR_LPQTO | SAFARI_ERROR_SFPQTO |
+ SAFARI_ERROR_UFPQTO | SAFARI_ERROR_APERR |
+ SAFARI_ERROR_BUSERR | SAFARI_ERROR_TIMEOUT |
+ SAFARI_ERROR_ILL)));
+
+ schizo_write(base + SCHIZO_SAFARI_IRQCTRL,
+ (SCHIZO_SAFIRQCTRL_EN | (SAFARI_ERROR_UNMAP)));
+}
+
+/* We have to do the config space accesses by hand, thus... */
+#define PBM_BRIDGE_BUS 0x40
+#define PBM_BRIDGE_SUBORDINATE 0x41
+static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno)
+{
+ u8 *addr, busno;
+ int nbus;
+
+ busno = pci_highest_busnum;
+ nbus = pbm->pci_last_busno - pbm->pci_first_busno;
+
+ addr = schizo_pci_config_mkaddr(pbm, orig_busno,
+ 0, PBM_BRIDGE_BUS);
+ pci_config_write8(addr, busno);
+ addr = schizo_pci_config_mkaddr(pbm, busno,
+ 0, PBM_BRIDGE_SUBORDINATE);
+ pci_config_write8(addr, busno + nbus);
+
+ pbm->pci_first_busno = busno;
+ pbm->pci_last_busno = busno + nbus;
+ pci_highest_busnum = busno + nbus + 1;
+
+ do {
+ pci_bus2pbm[busno++] = pbm;
+ } while (nbus--);
+}
+
+/* We have to do the config space accesses by hand here since
+ * the pci_bus2pbm array is not ready yet.
+ */
+static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm,
+ u8 busno)
+{
+ u32 devfn, l, class;
+ u8 hdr_type;
+ int is_multi = 0;
+
+ for(devfn = 0; devfn < 0xff; ++devfn) {
+ u32 *dwaddr;
+ u8 *baddr;
+
+ if (PCI_FUNC(devfn) != 0 && is_multi == 0)
+ continue;
+
+ /* Anything there? */
+ dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID);
+ l = 0xffffffff;
+ pci_config_read32(dwaddr, &l);
+ if (l == 0xffffffff || l == 0x00000000 ||
+ l == 0x0000ffff || l == 0xffff0000) {
+ is_multi = 0;
+ continue;
+ }
+
+ baddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE);
+ pci_config_read8(baddr, &hdr_type);
+ if (PCI_FUNC(devfn) == 0)
+ is_multi = hdr_type & 0x80;
+
+ dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION);
+ class = 0xffffffff;
+ pci_config_read32(dwaddr, &class);
+ if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+ u32 buses = 0xffffffff;
+
+ dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn,
+ PCI_PRIMARY_BUS);
+ pci_config_read32(dwaddr, &buses);
+ pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff);
+ buses &= 0xff000000;
+ pci_config_write32(dwaddr, buses);
+ }
+ }
+}
+
+static void __init pbm_bridge_reconfigure(struct pci_controller_info *p)
+{
+ struct pci_pbm_info *pbm;
+ u8 *addr;
+
+ /* Clear out primary/secondary/subordinate bus numbers on
+ * all PCI-to-PCI bridges under each PBM. The generic bus
+ * probing will fix them up.
+ */
+ pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno);
+ pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno);
+
+ /* Move PBM A out of the way. */
+ pbm = &p->pbm_A;
+ addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PBM_BRIDGE_BUS);
+ pci_config_write8(addr, 0xff);
+ addr = schizo_pci_config_mkaddr(pbm, 0xff,
+ 0, PBM_BRIDGE_SUBORDINATE);
+ pci_config_write8(addr, 0xff);
+
+ /* Now we can safely renumber both PBMs. */
+ pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno);
+ pbm_renumber(&p->pbm_A, 0xff);
+}
+
+static void __init pbm_config_busmastering(struct pci_pbm_info *pbm)
+{
+ u8 *addr;
+
+ /* Set cache-line size to 64 bytes, this is actually
+ * a nop but I do it for completeness.
+ */
+ addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PCI_CACHE_LINE_SIZE);
+ pci_config_write8(addr, 64 / sizeof(u32));
+
+ /* Set PBM latency timer to 64 PCI clocks. */
+ addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PCI_LATENCY_TIMER);
+ pci_config_write8(addr, 64);
+}
+
+static void __init pbm_scan_bus(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm)
+{
+ pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
+ p->pci_ops,
+ pbm);
+ pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
+ pci_record_assignments(pbm, pbm->pci_bus);
+ pci_assign_unassigned(pbm, pbm->pci_bus);
+ pci_fixup_irq(pbm, pbm->pci_bus);
+ pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
+ pci_setup_busmastering(pbm, pbm->pci_bus);
+}
+
+static void __init schizo_scan_bus(struct pci_controller_info *p)
+{
+ pbm_bridge_reconfigure(p);
+ pbm_config_busmastering(&p->pbm_B);
+ p->pbm_B.is_66mhz_capable = 0;
+ pbm_config_busmastering(&p->pbm_A);
+ p->pbm_A.is_66mhz_capable = 1;
+ pbm_scan_bus(p, &p->pbm_B);
+ pbm_scan_bus(p, &p->pbm_A);
+
+ /* After the PCI bus scan is complete, we can register
+ * the error interrupt handlers.
+ */
+ schizo_register_error_handlers(p);
}
static void __init schizo_base_address_update(struct pci_dev *pdev, int resource)
{
- /* IMPLEMENT ME */
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_pbm_info *pbm = pcp->pbm;
+ struct resource *res, *root;
+ u32 reg;
+ int where, size, is_64bit;
+
+ res = &pdev->resource[resource];
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+
+ is_64bit = 0;
+ if (res->flags & IORESOURCE_IO)
+ root = &pbm->io_space;
+ else {
+ root = &pbm->mem_space;
+ if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+ == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ is_64bit = 1;
+ }
+
+ size = res->end - res->start;
+ pci_read_config_dword(pdev, where, &reg);
+ reg = ((reg & size) |
+ (((u32)(res->start - root->start)) & ~size));
+ pci_write_config_dword(pdev, where, reg);
+
+ /* This knows that the upper 32-bits of the address
+ * must be zero. Our PCI common layer enforces this.
+ */
+ if (is_64bit)
+ pci_write_config_dword(pdev, where + 4, 0);
}
static void __init schizo_resource_adjust(struct pci_dev *pdev,
struct resource *res,
struct resource *root)
{
- /* IMPLEMENT ME */
+ res->start += root->start;
+ res->end += root->start;
+}
+
+/* Interrogate Safari match/mask registers to figure out where
+ * PCI MEM, I/O, and Config space are for this PCI bus module.
+ */
+
+#define SCHIZO_PCI_A_MEM_MATCH 0x00040UL
+#define SCHIZO_PCI_A_MEM_MASK 0x00048UL
+#define SCHIZO_PCI_A_IO_MATCH 0x00050UL
+#define SCHIZO_PCI_A_IO_MASK 0x00058UL
+#define SCHIZO_PCI_B_MEM_MATCH 0x00060UL
+#define SCHIZO_PCI_B_MEM_MASK 0x00068UL
+#define SCHIZO_PCI_B_IO_MATCH 0x00070UL
+#define SCHIZO_PCI_B_IO_MASK 0x00078UL
+
+/* VAL must be non-zero. */
+static unsigned long strip_to_lowest_bit_set(unsigned long val)
+{
+ unsigned long tmp;
+
+ tmp = 1UL;
+ while (!(tmp & val))
+ tmp <<= 1UL;
+
+ return tmp;
+}
+
+static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm,
+ int is_pbm_a, unsigned long reg_base)
+{
+ u64 mem_match, mem_mask;
+ u64 io_match;
+ u64 long a, b;
+
+ if (is_pbm_a) {
+ mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH;
+ io_match = reg_base + SCHIZO_PCI_A_IO_MATCH;
+ } else {
+ mem_match = reg_base + SCHIZO_PCI_B_MEM_MATCH;
+ io_match = reg_base + SCHIZO_PCI_B_IO_MATCH;
+ }
+ mem_mask = mem_match + 0x8UL;
+
+ a = schizo_read(mem_match) & ~0x8000000000000000UL;
+ b = strip_to_lowest_bit_set(schizo_read(mem_mask));
+
+ /* It should be 2GB in size. */
+ pbm->mem_space.start = a;
+ pbm->mem_space.end = a + (b - 1UL);
+ pbm->mem_space.flags = IORESOURCE_MEM;
+
+ /* This 32MB area is divided into two pieces. The first
+ * 16MB is Config space, the next 16MB is I/O space.
+ */
+
+ a = schizo_read(io_match) & ~0x8000000000000000UL;
+ pbm->config_space = a;
+ printk("SCHIZO PBM%c: Local PCI config space at %016lx\n",
+ (is_pbm_a ? 'A' : 'B'), pbm->config_space);
+
+ a += (16UL * 1024UL * 1024UL);
+ pbm->io_space.start = a;
+ pbm->io_space.end = a + ((16UL * 1024UL * 1024UL) - 1UL);
+ pbm->io_space.flags = IORESOURCE_IO;
+}
+
+static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm)
+{
+ char *name = pbm->name;
+
+ sprintf(name, "SCHIZO%d PBM%c",
+ p->index,
+ (pbm == &p->pbm_A ? 'A' : 'B'));
+ pbm->io_space.name = pbm->mem_space.name = name;
+
+ request_resource(&ioport_resource, &pbm->io_space);
+ request_resource(&iomem_resource, &pbm->mem_space);
+}
+
+#define SCHIZO_STRBUF_CONTROL_A (SCHIZO_PBM_A_REGS_OFF + 0x02800UL)
+#define SCHIZO_STRBUF_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02808UL)
+#define SCHIZO_STRBUF_FSYNC_A (SCHIZO_PBM_A_REGS_OFF + 0x02810UL)
+#define SCHIZO_STRBUF_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02818UL)
+#define SCHIZO_STRBUF_CTXMATCH_A (SCHIZO_PBM_A_REGS_OFF + 0x10000UL)
+
+#define SCHIZO_STRBUF_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x02800UL)
+#define SCHIZO_STRBUF_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02808UL)
+#define SCHIZO_STRBUF_FSYNC_B (SCHIZO_PBM_B_REGS_OFF + 0x02810UL)
+#define SCHIZO_STRBUF_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02818UL)
+#define SCHIZO_STRBUF_CTXMATCH_B (SCHIZO_PBM_B_REGS_OFF + 0x10000UL)
+
+static void schizo_pbm_strbuf_init(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm,
+ int is_pbm_a)
+{
+ unsigned long base = p->controller_regs;
+ u64 control;
+
+ /* SCHIZO has context flushing. */
+ if (is_pbm_a) {
+ pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_A;
+ pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_A;
+ pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_A;
+ pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_A;
+ pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_A;
+ } else {
+ pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_B;
+ pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_B;
+ pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_B;
+ pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_B;
+ pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_B;
+ }
+
+ pbm->stc.strbuf_flushflag = (volatile unsigned long *)
+ ((((unsigned long)&pbm->stc.__flushflag_buf[0])
+ + 63UL)
+ & ~63UL);
+ pbm->stc.strbuf_flushflag_pa = (unsigned long)
+ __pa(pbm->stc.strbuf_flushflag);
+
+ /* Turn off LRU locking and diag mode, enable the
+ * streaming buffer and leave the rerun-disable
+ * setting however OBP set it.
+ */
+ control = schizo_read(pbm->stc.strbuf_control);
+ control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
+ SCHIZO_STRBUF_CTRL_LENAB |
+ SCHIZO_STRBUF_CTRL_DENAB);
+ control |= SCHIZO_STRBUF_CTRL_ENAB;
+ schizo_write(pbm->stc.strbuf_control, control);
+
+ pbm->stc.strbuf_enabled = 1;
+}
+
+#define SCHIZO_IOMMU_CONTROL_A (SCHIZO_PBM_A_REGS_OFF + 0x00200UL)
+#define SCHIZO_IOMMU_TSBBASE_A (SCHIZO_PBM_A_REGS_OFF + 0x00208UL)
+#define SCHIZO_IOMMU_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00210UL)
+#define SCHIZO_IOMMU_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00218UL)
+#define SCHIZO_IOMMU_TAG_A (SCHIZO_PBM_A_REGS_OFF + 0x0a580UL)
+#define SCHIZO_IOMMU_DATA_A (SCHIZO_PBM_A_REGS_OFF + 0x0a600UL)
+#define SCHIZO_IOMMU_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x00200UL)
+#define SCHIZO_IOMMU_TSBBASE_B (SCHIZO_PBM_B_REGS_OFF + 0x00208UL)
+#define SCHIZO_IOMMU_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00210UL)
+#define SCHIZO_IOMMU_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00218UL)
+#define SCHIZO_IOMMU_TAG_B (SCHIZO_PBM_B_REGS_OFF + 0x0a580UL)
+#define SCHIZO_IOMMU_DATA_B (SCHIZO_PBM_B_REGS_OFF + 0x0a600UL)
+
+static void schizo_pbm_iommu_init(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm,
+ int is_pbm_a)
+{
+ struct pci_iommu *iommu = pbm->iommu;
+ unsigned long tsbbase, i, tagbase, database;
+ u64 control;
+
+ /* Setup initial software IOMMU state. */
+ spin_lock_init(&iommu->lock);
+ iommu->iommu_cur_ctx = 0;
+
+ /* Register addresses, SCHIZO has iommu ctx flushing. */
+ if (is_pbm_a) {
+ iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_A;
+ iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_A;
+ iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_A;
+ iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_A;
+ } else {
+ iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_B;
+ iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_B;
+ iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_B;
+ iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_B;
+ }
+
+ /* We use the main control/status register of SCHIZO as the write
+ * completion register.
+ */
+ iommu->write_complete_reg = p->controller_regs + 0x10000UL;
+
+ /*
+ * Invalidate TLB Entries.
+ */
+ control = schizo_read(iommu->iommu_control);
+ control |= SCHIZO_IOMMU_CTRL_DENAB;
+ schizo_write(iommu->iommu_control, control);
+
+ if (is_pbm_a)
+ tagbase = SCHIZO_IOMMU_TAG_A, database = SCHIZO_IOMMU_DATA_A;
+ else
+ tagbase = SCHIZO_IOMMU_TAG_B, database = SCHIZO_IOMMU_DATA_B;
+ for(i = 0; i < 16; i++) {
+ schizo_write(p->controller_regs + tagbase + (i * 8UL), 0);
+ schizo_write(p->controller_regs + database + (i * 8UL), 0);
+ }
+
+ /* Leave diag mode enabled for full-flushing done
+ * in pci_iommu.c
+ */
+
+ /* Using assumed page size 8K with 128K entries we need 1MB iommu page
+ * table (128K ioptes * 8 bytes per iopte). This is
+ * page order 7 on UltraSparc.
+ */
+ tsbbase = __get_free_pages(GFP_KERNEL, 7);
+ if (!tsbbase) {
+ prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n");
+ prom_halt();
+ }
+ iommu->page_table = (iopte_t *)tsbbase;
+ iommu->page_table_sz_bits = 17;
+ iommu->page_table_map_base = 0xc0000000;
+ iommu->dma_addr_mask = 0xffffffff;
+ memset((char *)tsbbase, 0, PAGE_SIZE << 7);
+
+ /* We start with no consistent mappings. */
+ iommu->lowest_consistent_map =
+ 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS);
+
+ for (i = 0; i < PBM_NCLUSTERS; i++) {
+ iommu->alloc_info[i].flush = 0;
+ iommu->alloc_info[i].next = 0;
+ }
+
+ schizo_write(iommu->iommu_tsbbase, __pa(tsbbase));
+
+ control = schizo_read(iommu->iommu_control);
+ control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
+ control |= (SCHIZO_IOMMU_TSBSZ_128K | SCHIZO_IOMMU_CTRL_ENAB);
+ schizo_write(iommu->iommu_control, control);
}
static void schizo_pbm_init(struct pci_controller_info *p,
int prom_node, int is_pbm_a)
{
- /* IMPLEMENT ME */
+ unsigned int busrange[2];
+ struct pci_pbm_info *pbm;
+ int err;
+
+ if (is_pbm_a)
+ pbm = &p->pbm_A;
+ else
+ pbm = &p->pbm_B;
+
+ schizo_determine_mem_io_space(pbm, is_pbm_a, p->controller_regs);
+ pbm_register_toplevel_resources(p, pbm);
+
+ pbm->parent = p;
+ pbm->prom_node = prom_node;
+ prom_getstring(prom_node, "name",
+ pbm->prom_name,
+ sizeof(pbm->prom_name));
+
+ err = prom_getproperty(prom_node, "ranges",
+ (char *) pbm->pbm_ranges,
+ sizeof(pbm->pbm_ranges));
+ if (err != -1)
+ pbm->num_pbm_ranges =
+ (err / sizeof(struct linux_prom_pci_ranges));
+ else
+ pbm->num_pbm_ranges = 0;
+
+ err = prom_getproperty(prom_node, "interrupt-map",
+ (char *)pbm->pbm_intmap,
+ sizeof(pbm->pbm_intmap));
+ if (err != -1) {
+ pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
+ err = prom_getproperty(prom_node, "interrupt-map-mask",
+ (char *)&pbm->pbm_intmask,
+ sizeof(pbm->pbm_intmask));
+ if (err == -1) {
+ prom_printf("SCHIZO-PBM: Fatal error, no "
+ "interrupt-map-mask.\n");
+ prom_halt();
+ }
+ } else {
+ pbm->num_pbm_intmap = 0;
+ memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
+ }
+
+ err = prom_getproperty(prom_node, "bus-range",
+ (char *)&busrange[0],
+ sizeof(busrange));
+ if (err == 0 || err == -1) {
+ prom_printf("SCHIZO-PBM: Fatal error, no bus-range.\n");
+ prom_halt();
+ }
+ pbm->pci_first_busno = busrange[0];
+ pbm->pci_last_busno = busrange[1];
+
+ schizo_pbm_iommu_init(p, pbm, is_pbm_a);
+ schizo_pbm_strbuf_init(p, pbm, is_pbm_a);
+}
+
+static void schizo_controller_hwinit(struct pci_controller_info *p)
+{
+ unsigned long pbm_a_base, pbm_b_base;
+ u64 tmp;
+
+ pbm_a_base = p->controller_regs + SCHIZO_PBM_A_REGS_OFF;
+ pbm_b_base = p->controller_regs + SCHIZO_PBM_B_REGS_OFF;
+
+ /* Set IRQ retry to infinity. */
+ schizo_write(pbm_a_base + 0x1a00UL, 0xff);
+ schizo_write(pbm_b_base + 0x1a00UL, 0xff);
+
+ /* Enable arbiter for all PCI slots. */
+ tmp = schizo_read(pbm_a_base + 0x2000UL);
+ tmp |= 0x3fUL;
+ schizo_write(pbm_a_base + 0x2000UL, tmp);
+
+ tmp = schizo_read(pbm_b_base + 0x2000UL);
+ tmp |= 0x3fUL;
+ schizo_write(pbm_b_base + 0x2000UL, tmp);
}
void __init schizo_init(int node)
@@ -90,6 +1708,7 @@ void __init schizo_init(int node)
struct linux_prom64_registers pr_regs[3];
struct pci_controller_info *p;
struct pci_iommu *iommu;
+ unsigned long flags;
u32 portid;
int is_pbm_a, err;
@@ -142,11 +1761,10 @@ void __init schizo_init(int node)
p->resource_adjust = schizo_resource_adjust;
p->pci_ops = &schizo_ops;
-pbm_init:
/* Three OBP regs:
* 1) PBM controller regs
* 2) Schizo front-end controller regs (same for both PBMs)
- * 3) Unknown... (0x7ffec000000 and 0x7ffee000000 on Excalibur)
+ * 3) PBM PCI config space
*/
err = prom_getproperty(node, "reg",
(char *)&pr_regs[0],
@@ -156,14 +1774,16 @@ pbm_init:
prom_halt();
}
- /* XXX Read REG base, record in controller/pbm structures. */
-
- /* XXX Report controller to console. */
+ p->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
+ printk("PCI: Found SCHIZO, control regs at %016lx\n",
+ p->controller_regs);
- /* XXX Setup pci_memspace_mask */
+ /* Like PSYCHO we have a 2GB aligned area for memory space. */
+ pci_memspace_mask = 0x7fffffffUL;
- /* XXX Init core controller and IOMMU */
+ /* Init core controller. */
+ schizo_controller_hwinit(p);
- is_pbm_a = XXX; /* Figure out this test */
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);
schizo_pbm_init(p, node, is_pbm_a);
}
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 3fc337d71..e0930d55e 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.114 2001/02/13 01:16:44 davem Exp $
+/* $Id: process.c,v 1.116 2001/03/24 09:36:01 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -416,14 +416,14 @@ void flush_thread(void)
unsigned long pgd_cache;
if (pgd_none(*pgd0)) {
- pmd_t *page = get_pmd_fast();
+ pmd_t *page = pmd_alloc_one_fast(NULL, 0);
if (!page)
- (void) get_pmd_slow(pgd0, 0);
- else
- pgd_set(pgd0, page);
+ page = pmd_alloc_one(NULL, 0);
+ pgd_set(pgd0, page);
}
pgd_cache = pgd_val(*pgd0) << 11UL;
- __asm__ __volatile__("stxa %0, [%1] %2"
+ __asm__ __volatile__("stxa %0, [%1] %2\n\t"
+ "membar #Sync"
: /* no outputs */
: "r" (pgd_cache),
"r" (TSB_REG),
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 7f791c4d0..031ec5582 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -53,10 +53,10 @@ static inline void
pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
{
if (current->thread.flags & SPARC_FLAG_32BIT) {
- if(put_user(value, (unsigned int *)addr))
+ if (put_user(value, (unsigned int *)addr))
return pt_error_return(regs, EFAULT);
} else {
- if(put_user(value, addr))
+ if (put_user(value, addr))
return pt_error_return(regs, EFAULT);
}
regs->u_regs[UREG_I0] = 0;
@@ -137,7 +137,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
s, request, pid, addr, data, addr2);
}
#endif
- if(request == PTRACE_TRACEME) {
+ if (request == PTRACE_TRACEME) {
/* are we already being traced? */
if (current->ptrace & PT_PTRACED) {
pt_error_return(regs, EPERM);
@@ -149,7 +149,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
#ifndef ALLOW_INIT_TRACING
- if(pid == 1) {
+ if (pid == 1) {
/* Can't dork with init. */
pt_error_return(regs, EPERM);
goto out;
@@ -157,9 +157,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
#endif
read_lock(&tasklist_lock);
child = find_task_by_pid(pid);
+ if (child)
+ get_task_struct(child);
read_unlock(&tasklist_lock);
- if(!child) {
+ if (!child) {
pt_error_return(regs, ESRCH);
goto out;
}
@@ -168,32 +170,32 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
|| (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
unsigned long flags;
- if(child == current) {
+ if (child == current) {
/* Try this under SunOS/Solaris, bwa haha
* You'll never be able to kill the process. ;-)
*/
pt_error_return(regs, EPERM);
- goto out;
+ goto out_tsk;
}
- if((!child->dumpable ||
- (current->uid != child->euid) ||
- (current->uid != child->uid) ||
- (current->uid != child->suid) ||
- (current->gid != child->egid) ||
- (current->gid != child->sgid) ||
- (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
- (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->uid) ||
+ (current->uid != child->suid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
pt_error_return(regs, EPERM);
- goto out;
+ goto out_tsk;
}
/* the same process cannot be attached many times */
if (child->ptrace & PT_PTRACED) {
pt_error_return(regs, EPERM);
- goto out;
+ goto out_tsk;
}
child->ptrace |= PT_PTRACED;
write_lock_irqsave(&tasklist_lock, flags);
- if(child->p_pptr != current) {
+ if (child->p_pptr != current) {
REMOVE_LINKS(child);
child->p_pptr = current;
SET_LINKS(child);
@@ -201,32 +203,32 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
write_unlock_irqrestore(&tasklist_lock, flags);
send_sig(SIGSTOP, child, 1);
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
if (!(child->ptrace & PT_PTRACED)) {
pt_error_return(regs, ESRCH);
- goto out;
+ goto out_tsk;
}
- if(child->state != TASK_STOPPED) {
- if(request != PTRACE_KILL) {
+ if (child->state != TASK_STOPPED) {
+ if (request != PTRACE_KILL) {
pt_error_return(regs, ESRCH);
- goto out;
+ goto out_tsk;
}
}
- if(child->p_pptr != current) {
+ if (child->p_pptr != current) {
pt_error_return(regs, ESRCH);
- goto out;
+ goto out_tsk;
}
- if(!(child->thread.flags & SPARC_FLAG_32BIT) &&
- ((request == PTRACE_READDATA64) ||
- (request == PTRACE_WRITEDATA64) ||
- (request == PTRACE_READTEXT64) ||
- (request == PTRACE_WRITETEXT64) ||
- (request == PTRACE_PEEKTEXT64) ||
- (request == PTRACE_POKETEXT64) ||
- (request == PTRACE_PEEKDATA64) ||
- (request == PTRACE_POKEDATA64))) {
+ if (!(child->thread.flags & SPARC_FLAG_32BIT) &&
+ ((request == PTRACE_READDATA64) ||
+ (request == PTRACE_WRITEDATA64) ||
+ (request == PTRACE_READTEXT64) ||
+ (request == PTRACE_WRITETEXT64) ||
+ (request == PTRACE_PEEKTEXT64) ||
+ (request == PTRACE_POKETEXT64) ||
+ (request == PTRACE_PEEKDATA64) ||
+ (request == PTRACE_POKEDATA64))) {
addr = regs->u_regs[UREG_G2];
addr2 = regs->u_regs[UREG_G3];
request -= 30; /* wheee... */
@@ -278,7 +280,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (copied == sizeof(tmp64))
res = 0;
}
- if(res < 0)
+ if (res < 0)
pt_error_return(regs, -res);
else
pt_succ_return(regs, res);
@@ -295,42 +297,45 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
__put_user(cregs->tnpc, (&pregs->npc)) ||
__put_user(cregs->y, (&pregs->y))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
- for(rval = 1; rval < 16; rval++)
+ for (rval = 1; rval < 16; rval++)
if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
- goto out;
+ goto out_tsk;
}
case PTRACE_GETREGS64: {
struct pt_regs *pregs = (struct pt_regs *) addr;
struct pt_regs *cregs = child->thread.kregs;
+ unsigned long tpc = cregs->tpc;
int rval;
+ if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
+ tpc &= 0xffffffff;
if (__put_user(cregs->tstate, (&pregs->tstate)) ||
- __put_user(cregs->tpc, (&pregs->tpc)) ||
+ __put_user(tpc, (&pregs->tpc)) ||
__put_user(cregs->tnpc, (&pregs->tnpc)) ||
__put_user(cregs->y, (&pregs->y))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
- for(rval = 1; rval < 16; rval++)
+ for (rval = 1; rval < 16; rval++)
if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
pt_succ_return(regs, 0);
#ifdef DEBUG_PTRACE
printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
#endif
- goto out;
+ goto out_tsk;
}
case PTRACE_SETREGS: {
@@ -347,23 +352,23 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
__get_user(npc, (&pregs->npc)) ||
__get_user(y, (&pregs->y))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
cregs->tstate &= ~(TSTATE_ICC);
cregs->tstate |= psr_to_tstate_icc(psr);
- if(!((pc | npc) & 3)) {
+ if (!((pc | npc) & 3)) {
cregs->tpc = pc;
cregs->tnpc = npc;
}
cregs->y = y;
- for(i = 1; i < 16; i++) {
+ for (i = 1; i < 16; i++) {
if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
}
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
case PTRACE_SETREGS64: {
@@ -380,24 +385,28 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
__get_user(tnpc, (&pregs->tnpc)) ||
__get_user(y, (&pregs->y))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
+ }
+ if ((child->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ tpc &= 0xffffffff;
+ tnpc &= 0xffffffff;
}
tstate &= (TSTATE_ICC | TSTATE_XCC);
cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
cregs->tstate |= tstate;
- if(!((tpc | tnpc) & 3)) {
+ if (!((tpc | tnpc) & 3)) {
cregs->tpc = tpc;
cregs->tnpc = tnpc;
}
cregs->y = y;
- for(i = 1; i < 16; i++) {
+ for (i = 1; i < 16; i++) {
if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
}
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
case PTRACE_GETFPREGS: {
@@ -422,10 +431,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
__put_user(0, (&fps->extra)) ||
clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
case PTRACE_GETFPREGS64: {
@@ -439,10 +448,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
(64 * sizeof(unsigned int))) ||
__put_user(child->thread.xfsr[0], (&fps->fsr))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
case PTRACE_SETFPREGS: {
@@ -464,7 +473,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
(32 * sizeof(unsigned int))) ||
__get_user(fsr, (&fps->fsr))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
child->thread.xfsr[0] &= 0xffffffff00000000UL;
child->thread.xfsr[0] |= fsr;
@@ -472,7 +481,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
child->thread.gsr[0] = 0;
child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
case PTRACE_SETFPREGS64: {
@@ -486,13 +495,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
(64 * sizeof(unsigned int))) ||
__get_user(child->thread.xfsr[0], (&fps->fsr))) {
pt_error_return(regs, EFAULT);
- goto out;
+ goto out_tsk;
}
if (!(child->thread.fpsaved[0] & FPRS_FEF))
child->thread.gsr[0] = 0;
child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
case PTRACE_READTEXT:
@@ -528,19 +537,24 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
case PTRACE_CONT: { /* restart after signal. */
if (data > _NSIG) {
pt_error_return(regs, EIO);
- goto out;
+ goto out_tsk;
}
if (addr != 1) {
+ unsigned long pc_mask = ~0UL;
+
+ if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
+ pc_mask = 0xffffffff;
+
if (addr & 3) {
pt_error_return(regs, EINVAL);
- goto out;
+ goto out_tsk;
}
#ifdef DEBUG_PTRACE
printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc);
printk ("Continuing with %016lx %016lx\n", addr, addr+4);
#endif
- child->thread.kregs->tpc = addr;
- child->thread.kregs->tnpc = addr + 4;
+ child->thread.kregs->tpc = (addr & pc_mask);
+ child->thread.kregs->tnpc = ((addr + 4) & pc_mask);
}
if (request == PTRACE_SYSCALL)
@@ -558,7 +572,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
#endif
wake_up_process(child);
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
/*
@@ -569,12 +583,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
case PTRACE_KILL: {
if (child->state == TASK_ZOMBIE) { /* already dead */
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
child->exit_code = SIGKILL;
wake_up_process(child);
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
case PTRACE_SUNDETACH: { /* detach a process that was attached. */
@@ -582,7 +596,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if ((unsigned long) data > _NSIG) {
pt_error_return(regs, EIO);
- goto out;
+ goto out_tsk;
}
child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
child->exit_code = data;
@@ -595,29 +609,39 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
wake_up_process(child);
pt_succ_return(regs, 0);
- goto out;
+ goto out_tsk;
}
/* PTRACE_DUMPCORE unsupported... */
default:
pt_error_return(regs, EIO);
- goto out;
+ goto out_tsk;
}
flush_and_out:
{
unsigned long va;
- for(va = 0; va < (PAGE_SIZE << 1); va += 32)
- spitfire_put_dcache_tag(va, 0x0);
- if (request == PTRACE_PEEKTEXT ||
- request == PTRACE_POKETEXT ||
- request == PTRACE_READTEXT ||
- request == PTRACE_WRITETEXT) {
- for(va = 0; va < (PAGE_SIZE << 1); va += 32)
- spitfire_put_icache_tag(va, 0x0);
- __asm__ __volatile__("flush %g6");
+
+ if (tlb_type == cheetah) {
+ for (va = 0; va < (1 << 16); va += (1 << 5))
+ spitfire_put_dcache_tag(va, 0x0);
+ /* No need to mess with I-cache on Cheetah. */
+ } else {
+ for (va = 0; va < (PAGE_SIZE << 1); va += 32)
+ spitfire_put_dcache_tag(va, 0x0);
+ if (request == PTRACE_PEEKTEXT ||
+ request == PTRACE_POKETEXT ||
+ request == PTRACE_READTEXT ||
+ request == PTRACE_WRITETEXT) {
+ for (va = 0; va < (PAGE_SIZE << 1); va += 32)
+ spitfire_put_icache_tag(va, 0x0);
+ __asm__ __volatile__("flush %g6");
+ }
}
}
+out_tsk:
+ if (child)
+ free_task_struct(child);
out:
unlock_kernel();
}
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 729ecd911..952f0caa5 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.53 2000/08/06 05:20:35 davem Exp $
+/* $Id: rtrap.S,v 1.54 2001/03/08 22:08:51 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -192,7 +192,7 @@ to_kernel: ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
rd %fprs, %g5
wr %g5, FPRS_FEF, %fprs
- ldub [%o1 + %o0], %g5
+ ldx [%o1 + %o5], %g5
add %g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
membar #StoreLoad | #LoadLoad
sll %o0, 8, %o2
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 7817f4566..cf6bbb896 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.59 2001/02/13 01:16:44 davem Exp $
+/* $Id: setup.c,v 1.63 2001/03/09 22:04:25 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -43,8 +43,6 @@
#include <net/ipconfig.h>
#endif
-#undef PROM_DEBUG_CONSOLE
-
struct screen_info screen_info = {
0, 0, /* orig-x, orig-y */
0, /* unused */
@@ -166,10 +164,14 @@ int prom_callback(long *args)
"r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
/*
- * Locked down tlb entry 63.
+ * Locked down tlb entry.
*/
- tte = spitfire_get_dtlb_data(63);
+ if (tlb_type == spitfire)
+ tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
+ else if (tlb_type == cheetah)
+ tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
+
res = PROM_TRUE;
goto done;
}
@@ -253,7 +255,7 @@ int prom_callback(long *args)
unsigned long tte;
tte = args[3];
- prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50);
+ prom_printf("%lx ", (tte & 0x07FC000000000000) >> 50);
args[2] = 2;
args[args[1] + 3] = 0;
@@ -285,14 +287,12 @@ static int console_fb __initdata = 0;
/* Exported for mm/init.c:paging_init. */
unsigned long cmdline_memory_size = 0;
-#ifdef PROM_DEBUG_CONSOLE
static struct console prom_debug_console = {
name: "debug",
write: prom_console_write,
flags: CON_PRINTBUFFER,
index: -1,
};
-#endif
/* XXX Implement this at some point... */
void kernel_enter_debugger(void)
@@ -326,6 +326,10 @@ static void __init process_switch(char c)
prom_printf("boot_flags_init: Halt!\n");
prom_halt();
break;
+ case 'p':
+ /* Use PROM debug console. */
+ register_console(&prom_debug_console);
+ break;
default:
printk("Unknown boot switch (-%c)\n", c);
break;
@@ -454,10 +458,6 @@ void __init setup_arch(char **cmdline_p)
*cmdline_p = prom_getbootargs();
strcpy(saved_command_line, *cmdline_p);
-#ifdef PROM_DEBUG_CONSOLE
- register_console(&prom_debug_console);
-#endif
-
printk("ARCH: SUN4U\n");
#ifdef CONFIG_DUMMY_CONSOLE
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 23d0774b4..354021278 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.55 2001/01/24 21:05:13 davem Exp $
+/* $Id: signal.c,v 1.56 2001/03/21 11:46:20 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -108,6 +108,10 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
}
+ if ((tp->flags & SPARC_FLAG_32BIT) != 0) {
+ pc &= 0xffffffff;
+ npc &= 0xffffffff;
+ }
regs->tpc = pc;
regs->tnpc = npc;
err |= __get_user(regs->y, &((*grp)[MC_Y]));
@@ -190,9 +194,13 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
grp = &mcp->mc_gregs;
/* Skip over the trap instruction, first. */
- regs->tpc = regs->tnpc;
- regs->tnpc += 4;
-
+ if ((tp->flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc = (regs->tnpc & 0xffffffff);
+ regs->tnpc = (regs->tnpc + 4) & 0xffffffff;
+ } else {
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ }
err = 0;
if (_NSIG_WORDS == 1)
err |= __put_user(current->blocked.sig[0],
@@ -289,8 +297,13 @@ asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs)
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
- regs->tpc = regs->tnpc;
- regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc = (regs->tnpc & 0xffffffff);
+ regs->tnpc = (regs->tnpc + 4) & 0xffffffff;
+ } else {
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ }
/* Condition codes and return value where set here for sigpause,
* and so got used by setup_frame, which again causes sigreturn()
@@ -344,8 +357,13 @@ asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, struct pt_re
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
- regs->tpc = regs->tnpc;
- regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc = (regs->tnpc & 0xffffffff);
+ regs->tnpc = (regs->tnpc + 4) & 0xffffffff;
+ } else {
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ }
/* Condition codes and return value where set here for sigpause,
* and so got used by setup_frame, which again causes sigreturn()
@@ -407,6 +425,10 @@ void do_rt_sigreturn(struct pt_regs *regs)
err = get_user(tpc, &sf->regs.tpc);
err |= __get_user(tnpc, &sf->regs.tnpc);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ tpc &= 0xffffffff;
+ tnpc &= 0xffffffff;
+ }
err |= ((tpc | tnpc) & 3);
/* 2. Restore the state */
@@ -555,7 +577,10 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* 5. signal handler */
regs->tpc = (unsigned long) ka->sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
-
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
/* 4. return to kernel instructions */
regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
return;
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 0886d9d39..9613c7869 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.68 2001/01/24 21:05:13 davem Exp $
+/* $Id: signal32.c,v 1.69 2001/03/21 11:46:20 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -155,6 +155,10 @@ asmlinkage void _sigpause32_common(old_sigset_t32 set, struct pt_regs *regs)
regs->tpc = regs->tnpc;
regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
/* Condition codes and return value where set here for sigpause,
* and so got used by setup_frame, which again causes sigreturn()
@@ -206,6 +210,10 @@ asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs *
regs->tpc = regs->tnpc;
regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
/* Condition codes and return value where set here for sigpause,
* and so got used by setup_frame, which again causes sigreturn()
@@ -268,6 +276,10 @@ void do_new_sigreturn32(struct pt_regs *regs)
if ((pc | npc) & 3)
goto segv;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ pc &= 0xffffffff;
+ npc &= 0xffffffff;
+ }
regs->tpc = pc;
regs->tnpc = npc;
@@ -355,6 +367,10 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ pc &= 0xffffffff;
+ npc &= 0xffffffff;
+ }
regs->tpc = pc;
regs->tnpc = npc;
err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp);
@@ -398,6 +414,10 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
if ((pc | npc) & 3)
goto segv;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ pc &= 0xffffffff;
+ npc &= 0xffffffff;
+ }
regs->tpc = pc;
regs->tnpc = npc;
@@ -489,6 +509,11 @@ setup_frame32(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *o
#endif
unsigned psr;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ pc &= 0xffffffff;
+ npc &= 0xffffffff;
+ }
+
synchronize_user_stack();
save_and_clear_fpu();
@@ -615,6 +640,10 @@ setup_frame32(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *o
regs->u_regs[UREG_FP] = (unsigned long) sframep;
regs->tpc = (unsigned long) sa->sa_handler;
regs->tnpc = (regs->tpc + 4);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
return;
sigsegv:
@@ -678,6 +707,10 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
}
/* 2. Save the current process state */
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
err = put_user(regs->tpc, &sf->info.si_regs.pc);
err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
err |= __put_user(regs->y, &sf->info.si_regs.y);
@@ -728,11 +761,15 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
/* 4. signal handler */
regs->tpc = (unsigned long) ka->sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
/* 5. return to kernel instructions */
- if (ka->ka_restorer)
+ if (ka->ka_restorer) {
regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
- else {
+ } else {
/* Flush instruction space. */
unsigned long address = ((unsigned long)&(sf->insns[0]));
pgd_t *pgdp = pgd_offset(current->mm, address);
@@ -819,6 +856,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
/* Store registers */
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
err |= __put_user(regs->tpc, &((*gr) [SVR4_PC]));
err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
psr = tstate_to_psr (regs->tstate);
@@ -883,6 +924,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
regs->u_regs[UREG_FP] = (unsigned long) sfp;
regs->tpc = (unsigned long) sa->sa_handler;
regs->tnpc = (regs->tpc + 4);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
#ifdef DEBUG_SIGNALS
printk ("Solaris-frame: %x %x\n", (int) regs->tpc, (int) regs->tnpc);
@@ -940,6 +985,10 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
/* Store registers */
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
err |= __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
err |= __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
#if 1
@@ -1037,6 +1086,10 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
spin_unlock_irq(&current->sigmask_lock);
regs->tpc = pc;
regs->tnpc = npc | 1;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
err |= __get_user(psr, &((*gr) [SVR4_PSR]));
regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
@@ -1095,6 +1148,10 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
}
/* 2. Save the current process state */
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
err = put_user(regs->tpc, &sf->regs.pc);
err |= __put_user(regs->tnpc, &sf->regs.npc);
err |= __put_user(regs->y, &sf->regs.y);
@@ -1150,6 +1207,10 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
/* 4. signal handler */
regs->tpc = (unsigned long) ka->sa.sa_handler;
regs->tnpc = (regs->tpc + 4);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
/* 5. return to kernel instructions */
if (ka->ka_restorer)
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 76045d0d2..bceac6597 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -65,7 +65,7 @@ int smp_info(char *buf)
strcpy(buf, "State:\n");
for (i = 0; i < NR_CPUS; i++)
- if(cpu_present_map & (1UL << i))
+ if (cpu_present_map & (1UL << i))
len += sprintf(buf + len,
"CPU%d:\t\tonline\n", i);
return len;
@@ -76,7 +76,7 @@ int smp_bogo(char *buf)
int len = 0, i;
for (i = 0; i < NR_CPUS; i++)
- if(cpu_present_map & (1UL << i))
+ if (cpu_present_map & (1UL << i))
len += sprintf(buf + len,
"Cpu%dBogo\t: %lu.%02lu\n",
i, cpu_data[i].udelay_val / (500000/HZ),
@@ -99,7 +99,7 @@ void __init smp_store_cpu_info(int id)
cpu_data[id].pgd_cache = NULL;
cpu_data[id].idle_volume = 1;
- for(i = 0; i < 16; i++)
+ for (i = 0; i < 16; i++)
cpu_data[id].irq_worklists[i] = 0;
}
@@ -153,6 +153,19 @@ void __init smp_callin(void)
: /* no inputs */
: "g1", "g2");
+ if (SPARC64_USE_STICK) {
+ /* Let the user get at STICK too. */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%asr24, %%g2
+ andn %%g2, %%g1, %%g2
+ wr %%g2, 0, %%asr24"
+ : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
+ }
+
/* Restore PSTATE_IE. */
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: /* no outputs */
@@ -177,7 +190,7 @@ void __init smp_callin(void)
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
- while(!smp_processors_ready)
+ while (!smp_processors_ready)
membar("#LoadLoad");
}
@@ -222,14 +235,14 @@ void __init smp_boot_cpus(void)
smp_tune_scheduling();
init_idle();
- if(linux_num_cpus == 1)
+ if (linux_num_cpus == 1)
return;
- for(i = 0; i < NR_CPUS; i++) {
- if(i == boot_cpu_id)
+ for (i = 0; i < NR_CPUS; i++) {
+ if (i == boot_cpu_id)
continue;
- if(cpu_present_map & (1UL << i)) {
+ if (cpu_present_map & (1UL << i)) {
unsigned long entry = (unsigned long)(&sparc64_cpu_startup);
unsigned long cookie = (unsigned long)(&cpu_new_task);
struct task_struct *p;
@@ -256,12 +269,12 @@ void __init smp_boot_cpus(void)
cpu_new_task = p;
prom_startcpu(linux_cpus[no].prom_node,
entry, cookie);
- for(timeout = 0; timeout < 5000000; timeout++) {
- if(callin_flag)
+ for (timeout = 0; timeout < 5000000; timeout++) {
+ if (callin_flag)
break;
udelay(100);
}
- if(callin_flag) {
+ if (callin_flag) {
__cpu_number_map[i] = cpucount;
__cpu_logical_map[cpucount] = i;
prom_cpu_nodes[i] = linux_cpus[no].prom_node;
@@ -272,20 +285,20 @@ void __init smp_boot_cpus(void)
prom_printf("FAILED\n");
}
}
- if(!callin_flag) {
+ if (!callin_flag) {
cpu_present_map &= ~(1UL << i);
__cpu_number_map[i] = -1;
}
}
cpu_new_task = NULL;
- if(cpucount == 0) {
+ if (cpucount == 0) {
printk("Error: only one processor found.\n");
cpu_present_map = (1UL << smp_processor_id());
} else {
unsigned long bogosum = 0;
- for(i = 0; i < NR_CPUS; i++) {
- if(cpu_present_map & (1UL << i))
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_present_map & (1UL << i))
bogosum += cpu_data[i].udelay_val;
}
printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -299,9 +312,7 @@ void __init smp_boot_cpus(void)
membar("#StoreStore | #StoreLoad");
}
-/* #define XCALL_DEBUG */
-
-static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu)
+static void spitfire_xcall_helper(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu)
{
u64 result, target;
int stuck, tmp;
@@ -314,10 +325,6 @@ static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, un
}
target = (cpu << 14) | 0x70;
-#ifdef XCALL_DEBUG
- printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n",
- smp_processor_id(), data0, data1, data2, target);
-#endif
again:
/* Ok, this is the real Spitfire Errata #54.
* One must read back from a UDB internal register
@@ -340,7 +347,7 @@ again:
ldxa [%%g1] 0x7f, %%g0
membar #Sync"
: "=r" (tmp)
- : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
+ : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_INTR_W),
"r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp)
: "g1");
@@ -350,46 +357,155 @@ again:
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (result)
: "i" (ASI_INTR_DISPATCH_STAT));
- if(result == 0) {
+ if (result == 0) {
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
return;
}
stuck -= 1;
- if(stuck == 0)
+ if (stuck == 0)
break;
- } while(result & 0x1);
+ } while (result & 0x1);
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
- if(stuck == 0) {
-#ifdef XCALL_DEBUG
+ if (stuck == 0) {
printk("CPU[%d]: mondo stuckage result[%016lx]\n",
smp_processor_id(), result);
-#endif
} else {
-#ifdef XCALL_DEBUG
- printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu);
-#endif
udelay(2);
goto again;
}
}
-void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
+static __inline__ void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, unsigned long mask)
{
- if(smp_processors_ready) {
- unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
- u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
+ int ncpus = smp_num_cpus - 1;
+ int i;
+ u64 pstate;
+
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+ for (i = 0; (i < NR_CPUS) && ncpus; i++) {
+ if (mask & (1UL << i)) {
+ spitfire_xcall_helper(data0, data1, data2, pstate, i);
+ ncpus--;
+ }
+ }
+}
+
+/* Cheetah now allows to send the whole 64-bytes of data in the interrupt
+ * packet, but we have no use for that. However we do take advantage of
+ * the new pipelining feature (ie. dispatch to multiple cpus simultaneously).
+ */
+#if NR_CPUS > 32
+#error Fixup cheetah_xcall_deliver Dave...
+#endif
+static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, unsigned long mask)
+{
+ u64 pstate;
+ int nack_busy_id;
+
+ if (!mask)
+ return;
+
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+
+retry:
+ __asm__ __volatile__("wrpr %0, %1, %%pstate\n\t"
+ : : "r" (pstate), "i" (PSTATE_IE));
+
+ /* Setup the dispatch data registers. */
+ __asm__ __volatile__("stxa %0, [%3] %6\n\t"
+ "membar #Sync\n\t"
+ "stxa %1, [%4] %6\n\t"
+ "membar #Sync\n\t"
+ "stxa %2, [%5] %6\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (data0), "r" (data1), "r" (data2),
+ "r" (0x40), "r" (0x50), "r" (0x60),
+ "i" (ASI_INTR_W));
+
+ nack_busy_id = 0;
+ {
int i, ncpus = smp_num_cpus - 1;
- __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- for(i = 0; i < NR_CPUS; i++) {
- if(mask & (1UL << i)) {
- xcall_deliver(data0, data1, data2, pstate, i);
+ for (i = 0; (i < NR_CPUS) && ncpus; i++) {
+ if (mask & (1UL << i)) {
+ u64 target = (i << 14) | 0x70;
+
+ target |= (nack_busy_id++ << 24);
+ __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+ "membar #Sync\n\t"
+ : /* no outputs */
+ : "r" (target), "i" (ASI_INTR_W));
ncpus--;
}
- if (!ncpus) break;
}
+ }
+
+ /* Now, poll for completion. */
+ {
+ u64 dispatch_stat;
+ long stuck;
+
+ stuck = 100000 * nack_busy_id;
+ do {
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (dispatch_stat)
+ : "i" (ASI_INTR_DISPATCH_STAT));
+ if (dispatch_stat == 0UL) {
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+ return;
+ }
+ if (!--stuck)
+ break;
+ } while (dispatch_stat & 0x5555555555555555UL);
+
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+
+ if ((stuck & ~(0x5555555555555555UL)) == 0) {
+ /* Busy bits will not clear, continue instead
+ * of freezing up on this cpu.
+ */
+ printk("CPU[%d]: mondo stuckage result[%016lx]\n",
+ smp_processor_id(), dispatch_stat);
+ } else {
+ int i, this_busy_nack = 0;
+
+ /* Delay some random time with interrupts enabled
+ * to prevent deadlock.
+ */
+ udelay(2 * nack_busy_id);
+
+ /* Clear out the mask bits for cpus which did not
+ * NACK us.
+ */
+ for (i = 0; i < NR_CPUS; i++) {
+ if (mask & (1UL << i)) {
+ if ((dispatch_stat & (0x2 << this_busy_nack)) == 0)
+ mask &= ~(1UL << i);
+ this_busy_nack += 2;
+ }
+ }
+
+ goto retry;
+ }
+ }
+}
+
+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 data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
+
+ if (tlb_type == spitfire)
+ spitfire_xcall_deliver(data0, data1, data2, mask);
+ else
+ cheetah_xcall_deliver(data0, data1, data2, mask);
+
/* NOTE: Caller runs local copy on master. */
}
}
@@ -445,11 +561,17 @@ extern unsigned long xcall_receive_signal;
void smp_receive_signal(int cpu)
{
- if(smp_processors_ready &&
- (cpu_present_map & (1UL<<cpu)) != 0) {
- u64 pstate, data0 = (((u64)&xcall_receive_signal) & 0xffffffff);
- __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- xcall_deliver(data0, 0, 0, pstate, cpu);
+ if (smp_processors_ready) {
+ unsigned long mask = 1UL << cpu;
+
+ if ((cpu_present_map & mask) != 0) {
+ u64 data0 = (((u64)&xcall_receive_signal) & 0xffffffff);
+
+ if (tlb_type == spitfire)
+ spitfire_xcall_deliver(data0, 0, 0, mask);
+ else
+ cheetah_xcall_deliver(data0, 0, 0, mask);
+ }
}
}
@@ -609,7 +731,7 @@ void smp_capture(void)
int result = __atomic_add(1, &smp_capture_depth);
membar("#StoreStore | #LoadStore");
- if(result == 1) {
+ if (result == 1) {
int ncpus = smp_num_cpus;
#ifdef CAPTURE_DEBUG
@@ -620,7 +742,7 @@ void smp_capture(void)
membar("#StoreStore | #LoadStore");
atomic_inc(&smp_capture_registry);
smp_cross_call(&xcall_capture, 0, 0, 0);
- while(atomic_read(&smp_capture_registry) != ncpus)
+ while (atomic_read(&smp_capture_registry) != ncpus)
membar("#LoadLoad");
#ifdef CAPTURE_DEBUG
printk("done\n");
@@ -631,8 +753,8 @@ void smp_capture(void)
void smp_release(void)
{
- if(smp_processors_ready) {
- if(atomic_dec_and_test(&smp_capture_depth)) {
+ if (smp_processors_ready) {
+ if (atomic_dec_and_test(&smp_capture_depth)) {
#ifdef CAPTURE_DEBUG
printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
smp_processor_id());
@@ -659,7 +781,7 @@ void smp_penguin_jailcell(void)
prom_world(1);
atomic_inc(&smp_capture_registry);
membar("#StoreLoad | #StoreStore");
- while(penguins_are_doing_time)
+ while (penguins_are_doing_time)
membar("#LoadLoad");
restore_alternate_globals(global_save);
atomic_dec(&smp_capture_registry);
@@ -690,14 +812,23 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
/*
* Check for level 14 softint.
*/
- if (!(get_softint() & (1UL << 0))) {
- extern void handler_irq(int, struct pt_regs *);
+ {
+ unsigned long tick_mask;
- handler_irq(14, regs);
- return;
+ if (SPARC64_USE_STICK)
+ tick_mask = (1UL << 16);
+ else
+ tick_mask = (1UL << 0);
+
+ if (!(get_softint() & tick_mask)) {
+ extern void handler_irq(int, struct pt_regs *);
+
+ handler_irq(14, regs);
+ return;
+ }
+ clear_softint(tick_mask);
}
- clear_softint((1UL << 0));
do {
if (!user)
sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
@@ -740,6 +871,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
* that %tick is not prone to this bug, but I am not
* taking any chances.
*/
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
"ba,pt %%xcc, 1f\n\t"
" add %0, %2, %0\n\t"
@@ -750,6 +882,14 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
"mov %1, %1"
: "=&r" (compare), "=r" (tick)
: "r" (current_tick_offset));
+ } else {
+ __asm__ __volatile__("rd %%asr25, %0\n\t"
+ "add %0, %2, %0\n\t"
+ "wr %0, 0x0, %%asr25\n\t"
+ "rd %%asr24, %1\n\t"
+ : "=&r" (compare), "=r" (tick)
+ : "r" (current_tick_offset));
+ }
/* Restore PSTATE_IE. */
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
@@ -782,6 +922,7 @@ static void __init smp_setup_percpu_timer(void)
* at the start of an I-cache line, and perform a dummy
* read back from %tick_cmpr right after writing to it. -DaveM
*/
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick, %%g1
ba,pt %%xcc, 1f
@@ -792,6 +933,15 @@ static void __init smp_setup_percpu_timer(void)
: /* no outputs */
: "r" (current_tick_offset)
: "g1");
+ } else {
+ __asm__ __volatile__("
+ rd %%asr24, %%g1
+ add %%g1, %0, %%g1
+ wr %%g1, 0x0, %%asr25"
+ : /* no outputs */
+ : "r" (current_tick_offset)
+ : "g1");
+ }
/* Restore PSTATE_IE. */
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
@@ -806,9 +956,9 @@ void __init smp_tick_init(void)
boot_cpu_id = hard_smp_processor_id();
current_tick_offset = timer_tick_offset;
cpu_present_map = 0;
- for(i = 0; i < linux_num_cpus; i++)
+ for (i = 0; i < linux_num_cpus; i++)
cpu_present_map |= (1UL << linux_cpus[i].mid);
- for(i = 0; i < NR_CPUS; i++) {
+ for (i = 0; i < NR_CPUS; i++) {
__cpu_number_map[i] = -1;
__cpu_logical_map[i] = -1;
}
@@ -827,11 +977,11 @@ static inline unsigned long find_flush_base(unsigned long size)
size = PAGE_ALIGN(size);
found = size;
base = (unsigned long) page_address(p);
- while(found != 0) {
+ while (found != 0) {
/* Failure. */
- if(p >= (mem_map + max_mapnr))
+ if (p >= (mem_map + max_mapnr))
return 0UL;
- if(PageReserved(p)) {
+ if (PageReserved(p)) {
found = size;
base = (unsigned long) page_address(p);
} else {
@@ -924,12 +1074,12 @@ int setup_profiling_timer(unsigned int multiplier)
unsigned long flags;
int i;
- if((!multiplier) || (timer_tick_offset / multiplier) < 1000)
+ if ((!multiplier) || (timer_tick_offset / multiplier) < 1000)
return -EINVAL;
save_and_cli(flags);
- for(i = 0; i < NR_CPUS; i++) {
- if(cpu_present_map & (1UL << i))
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_present_map & (1UL << i))
prof_multiplier(i) = multiplier;
}
current_tick_offset = (timer_tick_offset / multiplier);
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index f35e38a5d..2dc8ddb4f 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.100 2001/01/11 15:07:09 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.102 2001/03/24 09:36:01 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -179,6 +179,8 @@ EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(__flushw_user);
+EXPORT_SYMBOL(tlb_type);
+
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(__flush_dcache_page);
@@ -232,8 +234,7 @@ EXPORT_SYMBOL(_sigpause_common);
/* Should really be in linux/kernel/ksyms.c */
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(get_pmd_slow);
-EXPORT_SYMBOL(get_pte_slow);
+EXPORT_SYMBOL(pte_alloc_one);
#ifndef CONFIG_SMP
EXPORT_SYMBOL(pgt_quicklists);
#endif
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index e3cd81c97..16c9e7e19 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.48 2001/02/13 01:16:44 davem Exp $
+/* $Id: sys_sparc.c,v 1.50 2001/03/24 09:36:10 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -243,9 +243,9 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
if (flags & MAP_SHARED)
current->thread.flags |= SPARC_FLAG_MMAPSHARED;
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
retval = do_mmap(file, addr, len, prot, flags, off);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
@@ -263,9 +263,9 @@ asmlinkage long sys64_munmap(unsigned long addr, size_t len)
if (len > -PAGE_OFFSET ||
(addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET))
return -EINVAL;
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
ret = do_munmap(current->mm, addr, len);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
return ret;
}
@@ -285,7 +285,7 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr,
goto out;
if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET)
goto out;
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
vma = find_vma(current->mm, addr);
if (vma && (vma->vm_flags & VM_SHARED))
current->thread.flags |= SPARC_FLAG_MMAPSHARED;
@@ -305,7 +305,7 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr,
ret = do_mremap(addr, old_len, new_len, flags, new_addr);
out_sem:
current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
out:
return ret;
}
@@ -335,6 +335,10 @@ sparc_breakpoint (struct pt_regs *regs)
{
siginfo_t info;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
#ifdef DEBUG_SPARC_BREAKPOINT
printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc);
#endif
@@ -384,6 +388,10 @@ asmlinkage int solaris_syscall(struct pt_regs *regs)
regs->tpc = regs->tnpc;
regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
if(++count <= 5) {
printk ("For Solaris binary emulation you need solaris module loaded\n");
show_regs (regs);
@@ -400,6 +408,10 @@ asmlinkage int sunos_syscall(struct pt_regs *regs)
regs->tpc = regs->tnpc;
regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
if(++count <= 20)
printk ("SunOS binary emulation not compiled in\n");
force_sig(SIGSEGV, current);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index d68b75cab..571826a12 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.173 2001/02/13 01:16:44 davem Exp $
+/* $Id: sys_sparc32.c,v 1.174 2001/03/24 09:36:10 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -4133,7 +4133,7 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
goto out;
if (addr > 0xf0000000UL - old_len)
goto out;
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
vma = find_vma(current->mm, addr);
if (vma && (vma->vm_flags & VM_SHARED))
current->thread.flags |= SPARC_FLAG_MMAPSHARED;
@@ -4152,7 +4152,7 @@ asmlinkage unsigned long sys32_mremap(unsigned long addr,
ret = do_mremap(addr, old_len, new_len, flags, new_addr);
out_sem:
current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
out:
return ret;
}
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index bfbd8841c..a51b69783 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.57 2001/02/13 01:16:44 davem Exp $
+/* $Id: sys_sunos32.c,v 1.59 2001/03/24 09:36:11 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -100,12 +100,12 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
flags &= ~_MAP_NEW;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
retval = do_mmap(file,
(unsigned long) addr, (unsigned long) len,
(unsigned long) prot, (unsigned long) flags,
(unsigned long) off);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
if(!ret_type)
retval = ((retval < 0xf0000000) ? 0 : retval);
out_putf:
@@ -126,7 +126,7 @@ asmlinkage int sunos_brk(u32 baddr)
unsigned long rlim;
unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
if (brk < current->mm->end_code)
goto out;
newbrk = PAGE_ALIGN(brk);
@@ -170,7 +170,7 @@ asmlinkage int sunos_brk(u32 baddr)
do_brk(oldbrk, newbrk-oldbrk);
retval = 0;
out:
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
return retval;
}
@@ -456,6 +456,10 @@ asmlinkage int sunos_nosys(void)
static int cnt;
regs = current->thread.kregs;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGSYS;
info.si_errno = 0;
info.si_code = __SI_FAULT|0x100;
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index a3340f54a..f369368d2 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.33 2001/01/11 15:07:09 davem Exp $
+/* $Id: time.c,v 1.36 2001/03/15 08:51:24 anton Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,8 @@
#include <linux/timex.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/mc146818rtc.h>
+#include <linux/delay.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
@@ -35,7 +37,11 @@
extern rwlock_t xtime_lock;
spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
unsigned long mstk48t02_regs = 0UL;
+#ifdef CONFIG_PCI
+unsigned long ds1287_regs = 0UL;
+#endif
static unsigned long mstk48t08_regs = 0UL;
static unsigned long mstk48t59_regs = 0UL;
@@ -77,6 +83,7 @@ void sparc64_do_profile(unsigned long pc, unsigned long o7)
extern int rwlock_impl_begin, rwlock_impl_end;
extern int atomic_impl_begin, atomic_impl_end;
extern int __memcpy_begin, __memcpy_end;
+ extern int __bzero_begin, __bzero_end;
extern int __bitops_begin, __bitops_end;
if ((pc >= (unsigned long) &atomic_impl_begin &&
@@ -85,6 +92,8 @@ void sparc64_do_profile(unsigned long pc, unsigned long o7)
pc < (unsigned long) &rwlock_impl_end) ||
(pc >= (unsigned long) &__memcpy_begin &&
pc < (unsigned long) &__memcpy_end) ||
+ (pc >= (unsigned long) &__bzero_begin &&
+ pc < (unsigned long) &__bzero_end) ||
(pc >= (unsigned long) &__bitops_begin &&
pc < (unsigned long) &__bitops_end))
pc = o7;
@@ -135,6 +144,7 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* that %tick is not prone to this bug, but I am not
* taking any chances.
*/
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick_cmpr, %0
ba,pt %%xcc, 1f
@@ -146,6 +156,15 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
mov %1, %1"
: "=&r" (timer_tick_compare), "=r" (ticks)
: "r" (timer_tick_offset));
+ } else {
+ __asm__ __volatile__("
+ rd %%asr25, %0
+ add %0, %2, %0
+ wr %0, 0, %%asr25
+ rd %%asr24, %1"
+ : "=&r" (timer_tick_compare), "=r" (ticks)
+ : "r" (timer_tick_offset));
+ }
/* Restore PSTATE_IE. */
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
@@ -168,11 +187,19 @@ void timer_tick_interrupt(struct pt_regs *regs)
/*
* Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
*/
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick_cmpr, %0
add %0, %1, %0"
: "=&r" (timer_tick_compare)
: "r" (timer_tick_offset));
+ } else {
+ __asm__ __volatile__("
+ rd %%asr25, %0
+ add %0, %1, %0"
+ : "=&r" (timer_tick_compare)
+ : "r" (timer_tick_offset));
+ }
timer_check_rtc();
@@ -282,41 +309,95 @@ static int __init has_low_battery(void)
return (data1 == data2); /* Was the write blocked? */
}
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+#endif
/* Probe for the real time clock chip. */
static void __init set_system_time(void)
{
unsigned int year, mon, day, hour, min, sec;
unsigned long mregs = mstk48t02_regs;
+#ifdef CONFIG_PCI
+ unsigned long dregs = ds1287_regs;
+#else
+ unsigned long dregs = 0UL;
+#endif
u8 tmp;
do_get_fast_time = do_gettimeofday;
- if(!mregs) {
+ if (!mregs && !dregs) {
prom_printf("Something wrong, clock regs not mapped yet.\n");
prom_halt();
}
- spin_lock_irq(&mostek_lock);
+ if (mregs) {
+ spin_lock_irq(&mostek_lock);
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
+ /* Traditional Mostek chip. */
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
+
+ sec = MSTK_REG_SEC(mregs);
+ min = MSTK_REG_MIN(mregs);
+ hour = MSTK_REG_HOUR(mregs);
+ day = MSTK_REG_DOM(mregs);
+ mon = MSTK_REG_MONTH(mregs);
+ year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+ } else {
+ int i;
+
+ /* Dallas 12887 RTC chip. */
+
+ /* Stolen from arch/i386/kernel/time.c, see there for
+ * credits and descriptive comments.
+ */
+ for (i = 0; i < 1000000; i++) {
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ udelay(10);
+ }
+ for (i = 0; i < 1000000; i++) {
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ udelay(10);
+ }
+ do {
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ }
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
+ if (mregs) {
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
- spin_unlock_irq(&mostek_lock);
+ spin_unlock_irq(&mostek_lock);
+ }
}
void __init clock_probe(void)
@@ -358,21 +439,22 @@ void __init clock_probe(void)
busnd = sbus_root->prom_node;
}
- if(busnd == -1) {
+ if (busnd == -1) {
prom_printf("clock_probe: problem, cannot find bus to search.\n");
prom_halt();
}
node = prom_getchild(busnd);
- while(1) {
+ while (1) {
if (!node)
model[0] = 0;
else
prom_getstring(node, "model", model, sizeof(model));
- if(strcmp(model, "mk48t02") &&
- strcmp(model, "mk48t08") &&
- strcmp(model, "mk48t59")) {
+ if (strcmp(model, "mk48t02") &&
+ strcmp(model, "mk48t08") &&
+ strcmp(model, "mk48t59") &&
+ strcmp(model, "ds1287")) {
if (node)
node = prom_getsibling(node);
#ifdef CONFIG_PCI
@@ -384,7 +466,7 @@ void __init clock_probe(void)
}
}
#endif
- if(node == 0) {
+ if (node == 0) {
prom_printf("clock_probe: Cannot find timer chip\n");
prom_halt();
}
@@ -415,8 +497,12 @@ void __init clock_probe(void)
prom_halt();
}
- mstk48t59_regs = edev->resource[0].start;
- mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+ if (!strcmp(model, "ds1287")) {
+ ds1287_regs = edev->resource[0].start;
+ } else {
+ mstk48t59_regs = edev->resource[0].start;
+ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+ }
break;
}
#endif
@@ -456,27 +542,21 @@ void __init clock_probe(void)
break;
}
- /* Report a low battery voltage condition. */
- if (has_low_battery())
- prom_printf("NVRAM: Low battery voltage!\n");
+ if (mstk48t02_regs != 0UL) {
+ /* Report a low battery voltage condition. */
+ if (has_low_battery())
+ prom_printf("NVRAM: Low battery voltage!\n");
- /* Kick start the clock if it is completely stopped. */
- if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
- kick_start_clock();
+ /* Kick start the clock if it is completely stopped. */
+ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
+ kick_start_clock();
+ }
set_system_time();
__restore_flags(flags);
}
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
-#endif
-
extern void init_timers(void (*func)(int, void *, struct pt_regs *),
unsigned long *);
@@ -497,6 +577,7 @@ static __inline__ unsigned long do_gettimeoffset(void)
{
unsigned long ticks;
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick, %%g1
add %1, %%g1, %0
@@ -505,6 +586,14 @@ static __inline__ unsigned long do_gettimeoffset(void)
: "=r" (ticks)
: "r" (timer_tick_offset), "r" (timer_tick_compare)
: "g1", "g2");
+ } else {
+ __asm__ __volatile__("rd %%asr24, %%g1\n\t"
+ "add %1, %%g1, %0\n\t"
+ "sub %0, %2, %0\n\t"
+ : "=&r" (ticks)
+ : "r" (timer_tick_offset), "r" (timer_tick_compare)
+ : "g1");
+ }
return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
}
@@ -533,8 +622,13 @@ void do_settimeofday(struct timeval *tv)
static int set_rtc_mmss(unsigned long nowtime)
{
- int real_seconds, real_minutes, mostek_minutes;
- unsigned long regs = mstk48t02_regs;
+ int real_seconds, real_minutes, chip_minutes;
+ unsigned long mregs = mstk48t02_regs;
+#ifdef CONFIG_PCI
+ unsigned long dregs = ds1287_regs;
+#else
+ unsigned long dregs = 0UL;
+#endif
unsigned long flags;
u8 tmp;
@@ -542,52 +636,96 @@ static int set_rtc_mmss(unsigned long nowtime)
* Not having a register set can lead to trouble.
* Also starfire doesnt have a tod clock.
*/
- if (!regs)
+ if (!mregs && !dregs)
return -1;
- spin_lock_irqsave(&mostek_lock, flags);
+ if (mregs) {
+ spin_lock_irqsave(&mostek_lock, flags);
- /* Read the current RTC minutes. */
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
+ /* Read the current RTC minutes. */
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
- mostek_minutes = MSTK_REG_MIN(regs);
+ chip_minutes = MSTK_REG_MIN(mregs);
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
- if (abs(real_minutes - mostek_minutes) < 30) {
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
+ if (abs(real_minutes - chip_minutes) < 30) {
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_WRITE;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
- MSTK_SET_REG_SEC(regs,real_seconds);
- MSTK_SET_REG_MIN(regs,real_minutes);
+ MSTK_SET_REG_SEC(mregs,real_seconds);
+ MSTK_SET_REG_MIN(mregs,real_minutes);
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_WRITE;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
+
+ spin_unlock_irqrestore(&mostek_lock, flags);
- spin_unlock_irqrestore(&mostek_lock, flags);
+ return 0;
+ } else {
+ spin_unlock_irqrestore(&mostek_lock, flags);
- return 0;
+ return -1;
+ }
} else {
- spin_unlock_irqrestore(&mostek_lock, flags);
+ int retval = 0;
+ unsigned char save_control, save_freq_select;
- return -1;
+ /* Stolen from arch/i386/kernel/time.c, see there for
+ * credits and descriptive comments.
+ */
+ spin_lock_irqsave(&rtc_lock, flags);
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ chip_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(chip_minutes);
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
+ real_minutes += 30;
+ real_minutes %= 60;
+
+ if (abs(real_minutes - chip_minutes) < 30) {
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ }
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ chip_minutes, real_minutes);
+ retval = -1;
+ }
+
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ return retval;
}
}
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 4f2606c97..578a5ae80 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.12 1999/12/15 15:45:12 davem Exp $
+/* $Id: trampoline.S,v 1.19 2001/03/22 09:54:26 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,8 @@
#include <asm/head.h>
#include <asm/asi.h>
#include <asm/lsu.h>
+#include <asm/dcr.h>
+#include <asm/dcu.h>
#include <asm/pstate.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -30,177 +32,246 @@ dtlb_load:
sparc64_cpu_startup:
flushw
- mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
- stxa %g1, [%g0] ASI_LSU_CONTROL
- membar #Sync
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g5
+ srlx %g1, 32, %g1
+ or %g5, %lo(0x003e0014), %g5
+ cmp %g1, %g5
+ bne,pt %icc, spitfire_startup
+ nop
+
+cheetah_startup:
+ mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
+ wr %g1, %asr18
+
+ sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+ or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+ sllx %g5, 32, %g5
+ or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g3
+ or %g5, %g3, %g5
+ stxa %g5, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+
+ /* Disable STICK_INT interrupts. */
+ sethi %hi(0x80000000), %g5
+ sllx %g5, 32, %g5
+ wr %g5, %asr25
+
+ ba,pt %xcc, startup_continue
+ nop
- wrpr %g0, 15, %pil
- wr %g0, 0, %tick_cmpr
+spitfire_startup:
+ mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
+ stxa %g1, [%g0] ASI_LSU_CONTROL
+ membar #Sync
+
+startup_continue:
+ wrpr %g0, 15, %pil
+ wr %g0, 0, %tick_cmpr
/* Call OBP by hand to lock KERNBASE into i/d tlbs. */
- mov %o0, %l0
-
- sethi %hi(prom_entry_lock), %g2
-1: ldstub [%g2 + %lo(prom_entry_lock)], %g1
- brnz,pn %g1, 1b
- membar #StoreLoad | #StoreStore
-
- sethi %hi(p1275buf), %g2
- or %g2, %lo(p1275buf), %g2
- ldx [%g2 + 0x10], %l2
- mov %sp, %l1
- add %l2, -(192 + 128), %sp
+ mov %o0, %l0
+
+ sethi %hi(prom_entry_lock), %g2
+1: ldstub [%g2 + %lo(prom_entry_lock)], %g1
+ brnz,pn %g1, 1b
+ membar #StoreLoad | #StoreStore
+
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x10], %l2
+ mov %sp, %l1
+ add %l2, -(192 + 128), %sp
flushw
- sethi %hi(call_method), %g2
- or %g2, %lo(call_method), %g2
- stx %g2, [%sp + 2047 + 128 + 0x00]
- mov 5, %g2
- stx %g2, [%sp + 2047 + 128 + 0x08]
- mov 1, %g2
- stx %g2, [%sp + 2047 + 128 + 0x10]
- sethi %hi(itlb_load), %g2
- or %g2, %lo(itlb_load), %g2
- stx %g2, [%sp + 2047 + 128 + 0x18]
- sethi %hi(mmu_ihandle_cache), %g2
- lduw [%g2 + %lo(mmu_ihandle_cache)], %g2
- stx %g2, [%sp + 2047 + 128 + 0x20]
- sethi %hi(KERNBASE), %g2
- stx %g2, [%sp + 2047 + 128 + 0x28]
- sethi %hi(kern_locked_tte_data), %g2
- ldx [%g2 + %lo(kern_locked_tte_data)], %g2
- stx %g2, [%sp + 2047 + 128 + 0x30]
- mov 63, %g2
- stx %g2, [%sp + 2047 + 128 + 0x38]
- sethi %hi(p1275buf), %g2
- or %g2, %lo(p1275buf), %g2
- ldx [%g2 + 0x08], %o1
- call %o1
- add %sp, (2047 + 128), %o0
-
- sethi %hi(call_method), %g2
- or %g2, %lo(call_method), %g2
- stx %g2, [%sp + 2047 + 128 + 0x00]
- mov 5, %g2
- stx %g2, [%sp + 2047 + 128 + 0x08]
- mov 1, %g2
- stx %g2, [%sp + 2047 + 128 + 0x10]
- sethi %hi(dtlb_load), %g2
- or %g2, %lo(dtlb_load), %g2
- stx %g2, [%sp + 2047 + 128 + 0x18]
- sethi %hi(mmu_ihandle_cache), %g2
- lduw [%g2 + %lo(mmu_ihandle_cache)], %g2
- stx %g2, [%sp + 2047 + 128 + 0x20]
- sethi %hi(KERNBASE), %g2
- stx %g2, [%sp + 2047 + 128 + 0x28]
- sethi %hi(kern_locked_tte_data), %g2
- ldx [%g2 + %lo(kern_locked_tte_data)], %g2
- stx %g2, [%sp + 2047 + 128 + 0x30]
- mov 63, %g2
- stx %g2, [%sp + 2047 + 128 + 0x38]
- sethi %hi(p1275buf), %g2
- or %g2, %lo(p1275buf), %g2
- ldx [%g2 + 0x08], %o1
- call %o1
- add %sp, (2047 + 128), %o0
-
- sethi %hi(prom_entry_lock), %g2
- stb %g0, [%g2 + %lo(prom_entry_lock)]
- membar #StoreStore | #StoreLoad
-
- mov %l1, %sp
+ sethi %hi(call_method), %g2
+ or %g2, %lo(call_method), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 5, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ sethi %hi(itlb_load), %g2
+ or %g2, %lo(itlb_load), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(mmu_ihandle_cache), %g2
+ lduw [%g2 + %lo(mmu_ihandle_cache)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(KERNBASE), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x28]
+ sethi %hi(kern_locked_tte_data), %g2
+ ldx [%g2 + %lo(kern_locked_tte_data)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x30]
+
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g5
+ srlx %g1, 32, %g1
+ or %g5, %lo(0x003e0014), %g5
+ cmp %g1, %g5
+ bne,a,pt %icc, 1f
+ mov 63, %g2
+ mov 15, %g2
+1:
+ stx %g2, [%sp + 2047 + 128 + 0x38]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
+
+ sethi %hi(call_method), %g2
+ or %g2, %lo(call_method), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 5, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ sethi %hi(dtlb_load), %g2
+ or %g2, %lo(dtlb_load), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(mmu_ihandle_cache), %g2
+ lduw [%g2 + %lo(mmu_ihandle_cache)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(KERNBASE), %g2
+ stx %g2, [%sp + 2047 + 128 + 0x28]
+ sethi %hi(kern_locked_tte_data), %g2
+ ldx [%g2 + %lo(kern_locked_tte_data)], %g2
+ stx %g2, [%sp + 2047 + 128 + 0x30]
+
+ rdpr %ver, %g1
+ sethi %hi(0x003e0014), %g5
+ srlx %g1, 32, %g1
+ or %g5, %lo(0x003e0014), %g5
+ cmp %g1, %g5
+ bne,a,pt %icc, 1f
+ mov 63, %g2
+ mov 15, %g2
+1:
+
+ stx %g2, [%sp + 2047 + 128 + 0x38]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
+
+ sethi %hi(prom_entry_lock), %g2
+ stb %g0, [%g2 + %lo(prom_entry_lock)]
+ membar #StoreStore | #StoreLoad
+
+ mov %l1, %sp
flushw
- mov %l0, %o0
+ mov %l0, %o0
- wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
- wr %g0, 0, %fprs
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+ wr %g0, 0, %fprs
- sethi %uhi(PAGE_OFFSET), %g4
- sllx %g4, 32, %g4
+ sethi %uhi(PAGE_OFFSET), %g4
+ sllx %g4, 32, %g4
/* XXX Buggy PROM... */
- srl %o0, 0, %o0
- ldx [%o0], %g6
+ srl %o0, 0, %o0
+ ldx [%o0], %g6
- wr %g0, ASI_P, %asi
+ wr %g0, ASI_P, %asi
- mov PRIMARY_CONTEXT, %g7
- stxa %g0, [%g7] ASI_DMMU
- membar #Sync
- mov SECONDARY_CONTEXT, %g7
- stxa %g0, [%g7] ASI_DMMU
- membar #Sync
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
- mov 1, %g5
- sllx %g5, (PAGE_SHIFT + 1), %g5
- sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
- add %g6, %g5, %sp
- mov 0, %fp
+ mov 1, %g5
+ sllx %g5, (PAGE_SHIFT + 1), %g5
+ sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
+ mov 0, %fp
- wrpr %g0, 0, %wstate
- wrpr %g0, 0, %tl
+ wrpr %g0, 0, %wstate
+ wrpr %g0, 0, %tl
/* Setup the trap globals, then we can resurface. */
- rdpr %pstate, %o1
- mov %g6, %o2
- wrpr %o1, PSTATE_AG, %pstate
- sethi %hi(sparc64_ttable_tl0), %g5
- wrpr %g5, %tba
- mov %o2, %g6
-
- wrpr %o1, PSTATE_MG, %pstate
-#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+ rdpr %pstate, %o1
+ mov %g6, %o2
+ wrpr %o1, PSTATE_AG, %pstate
+ sethi %hi(sparc64_ttable_tl0), %g5
+ wrpr %g5, %tba
+ mov %o2, %g6
+
+ wrpr %o1, PSTATE_MG, %pstate
+#define KERN_HIGHBITS ((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#ifdef THIS_IS_CHEETAH
-#error Dave, make sure you took care of other issues in rest of sparc64 code...
-#define VPTE_BASE 0xffe0000000000000
-#else /* Spitfire/Blackbird */
-#define VPTE_BASE 0xfffffffe00000000
+
+#define VPTE_BASE_SPITFIRE 0xfffffffe00000000
+#if 1
+#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE
+#else
+#define VPTE_BASE_CHEETAH 0xffe0000000000000
#endif
- mov TSB_REG, %g1
- stxa %g0, [%g1] ASI_DMMU
- membar #Sync
- mov TLB_SFSR, %g1
- sethi %uhi(KERN_HIGHBITS), %g2
- or %g2, %ulo(KERN_HIGHBITS), %g2
- sllx %g2, 32, %g2
- or %g2, KERN_LOWBITS, %g2
- sethi %uhi(VPTE_BASE), %g3
- or %g3, %ulo(VPTE_BASE), %g3
- sllx %g3, 32, %g3
+
+ mov TSB_REG, %g1
+ stxa %g0, [%g1] ASI_DMMU
+ membar #Sync
+ mov TLB_SFSR, %g1
+ sethi %uhi(KERN_HIGHBITS), %g2
+ or %g2, %ulo(KERN_HIGHBITS), %g2
+ sllx %g2, 32, %g2
+ or %g2, KERN_LOWBITS, %g2
+
+ rdpr %ver, %g3
+ sethi %hi(0x003e0014), %g7
+ srlx %g3, 32, %g3
+ or %g7, %lo(0x003e0014), %g7
+ cmp %g3, %g7
+ bne,pt %icc, 1f
+ nop
+
+ sethi %uhi(VPTE_BASE_CHEETAH), %g3
+ or %g3, %ulo(VPTE_BASE_CHEETAH), %g3
+ ba,pt %xcc, 2f
+ sllx %g3, 32, %g3
+1:
+ sethi %uhi(VPTE_BASE_SPITFIRE), %g3
+ or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3
+ sllx %g3, 32, %g3
+
+2:
clr %g7
#undef KERN_HIGHBITS
#undef KERN_LOWBITS
-#undef VPTE_BASE
+#undef VPTE_BASE_SPITFIRE
+#undef VPTE_BASE_CHEETAH
/* Setup interrupt globals, we are always SMP. */
- wrpr %o1, PSTATE_IG, %pstate
+ wrpr %o1, PSTATE_IG, %pstate
/* Get our UPA MID. */
- lduw [%o2 + AOFF_task_processor], %g1
- sethi %hi(cpu_data), %g5
- or %g5, %lo(cpu_data), %g5
+ lduw [%o2 + AOFF_task_processor], %g1
+ sethi %hi(cpu_data), %g5
+ or %g5, %lo(cpu_data), %g5
/* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */
- sllx %g1, 7, %g1
- add %g5, %g1, %g1
- add %g1, 64, %g6
+ sllx %g1, 7, %g1
+ add %g5, %g1, %g1
+ add %g1, 64, %g6
- wrpr %g0, 0, %wstate
- or %o1, PSTATE_IE, %o1
- wrpr %o1, 0, %pstate
+ wrpr %g0, 0, %wstate
+ or %o1, PSTATE_IE, %o1
+ wrpr %o1, 0, %pstate
- call prom_set_trap_table
- sethi %hi(sparc64_ttable_tl0), %o0
+ call prom_set_trap_table
+ sethi %hi(sparc64_ttable_tl0), %o0
- call smp_callin
+ call smp_callin
nop
- call cpu_idle
- mov 0, %o0
- call cpu_panic
+ call cpu_idle
+ mov 0, %o0
+ call cpu_panic
nop
-1: b,a,pt %xcc, 1b
+1: b,a,pt %xcc, 1b
.align 8
sparc64_cpu_startup_end:
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index cc703d3bc..0a368bcee 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.70 2001/02/09 05:46:44 davem Exp $
+/* $Id: traps.c,v 1.73 2001/03/22 07:26:03 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
#include <asm/lsu.h>
+#include <asm/dcu.h>
#include <asm/psrcompat.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -263,6 +264,10 @@ void bad_trap (struct pt_regs *regs, long lvl)
}
if (regs->tstate & TSTATE_PRIV)
die_if_kernel ("Kernel bad trap", regs);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLTRP;
@@ -291,6 +296,10 @@ void instruction_access_exception (struct pt_regs *regs,
#endif
die_if_kernel("Iax", regs);
}
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
@@ -342,32 +351,41 @@ void data_access_exception (struct pt_regs *regs,
#ifdef CONFIG_PCI
/* This is really pathetic... */
-/* #define DEBUG_PCI_POKES */
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)
+static 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);
- }
+ if (tlb_type == spitfire) {
+ /* 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");
+ /* Re-enable in LSU. */
+ __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");
+ } else if (tlb_type == cheetah) {
+ /* Flush D-cache */
+ for (va = 0; va < (1 << 16); va += (1 << 5)) {
+ __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (va), "i" (ASI_DCACHE_TAG));
+ }
+ }
}
void do_iae(struct pt_regs *regs)
@@ -387,20 +405,16 @@ void do_iae(struct pt_regs *regs)
void do_dae(struct pt_regs *regs)
{
#ifdef CONFIG_PCI
- if(pci_poke_in_progress) {
-#ifdef DEBUG_PCI_POKES
- prom_printf(" (POKE tpc[%016lx] tnpc[%016lx] ",
- regs->tpc, regs->tnpc);
-#endif
+ if (pci_poke_in_progress) {
+ clean_and_reenable_l1_caches();
+
pci_poke_faulted = 1;
- regs->tnpc = regs->tpc + 4;
+ /* Why the fuck did they have to change this? */
+ if (tlb_type == cheetah)
+ regs->tpc += 4;
-#ifdef DEBUG_PCI_POKES
- prom_printf("PCI) ");
- /* prom_halt(); */
-#endif
- clean_and_reenable_l1_caches();
+ regs->tnpc = regs->tpc + 4;
return;
}
#endif
@@ -534,6 +548,10 @@ void do_fpe_common(struct pt_regs *regs)
unsigned long fsr = current->thread.xfsr[0];
siginfo_t info;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_addr = (void *)regs->tpc;
@@ -589,6 +607,10 @@ void do_tof(struct pt_regs *regs)
if(regs->tstate & TSTATE_PRIV)
die_if_kernel("Penguin overflow trap from kernel mode", regs);
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGEMT;
info.si_errno = 0;
info.si_code = EMT_TAGOVF;
@@ -601,6 +623,10 @@ void do_div0(struct pt_regs *regs)
{
siginfo_t info;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = FPE_INTDIV;
@@ -700,8 +726,13 @@ void die_if_kernel(char *str, struct pt_regs *regs)
(rw->ins[6] + STACK_BIAS);
}
instruction_dump ((unsigned int *) regs->tpc);
- } else
+ } else {
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
user_instruction_dump ((unsigned int *) regs->tpc);
+ }
#ifdef CONFIG_SMP
smp_report_regs();
#endif
@@ -765,6 +796,10 @@ void do_privop(struct pt_regs *regs)
{
siginfo_t info;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_PRVOPC;
@@ -907,6 +942,10 @@ void do_getpsr(struct pt_regs *regs)
regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate);
regs->tpc = regs->tnpc;
regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
}
void trap_init(void)
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index b1081b9fe..2f7e0e16c 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.31 2000/05/09 17:40:14 davem Exp $
+/* $Id: ttable.S,v 1.32 2001/03/23 07:56:30 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -22,7 +22,7 @@ tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0
tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f)
tl0_fpdis: TRAP_NOSAVE(do_fpdis)
tl0_fpieee: TRAP_SAVEFPU(do_fpieee)
-tl0_fpother: TRAP_SAVEFPU(do_fpother)
+tl0_fpother: TRAP_NOSAVE(do_fpother_check_fitos)
tl0_tof: TRAP(do_tof)
tl0_cwin: CLEAN_WINDOW
tl0_div0: TRAP(do_div0)
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index f43204c3b..7a21f0080 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.20 2000/04/29 08:05:21 anton Exp $
+/* $Id: unaligned.c,v 1.21 2001/03/21 11:46:20 davem Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -334,6 +334,10 @@ static inline void advance(struct pt_regs *regs)
{
regs->tpc = regs->tnpc;
regs->tnpc += 4;
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
+ regs->tpc &= 0xffffffff;
+ regs->tnpc &= 0xffffffff;
+ }
}
static inline int floating_point_load_or_store_p(unsigned int insn)