summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /arch/sparc64/kernel
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile39
-rw-r--r--arch/sparc64/kernel/auxio.c14
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c55
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c2
-rw-r--r--arch/sparc64/kernel/cpu.c6
-rw-r--r--arch/sparc64/kernel/devices.c11
-rw-r--r--arch/sparc64/kernel/ebus.c221
-rw-r--r--arch/sparc64/kernel/entry.S178
-rw-r--r--arch/sparc64/kernel/etrap.S10
-rw-r--r--arch/sparc64/kernel/idprom.c6
-rw-r--r--arch/sparc64/kernel/init_task.c1
-rw-r--r--arch/sparc64/kernel/ioctl32.c14
-rw-r--r--arch/sparc64/kernel/irq.c157
-rw-r--r--arch/sparc64/kernel/pci.c339
-rw-r--r--arch/sparc64/kernel/pci_common.c651
-rw-r--r--arch/sparc64/kernel/pci_impl.h166
-rw-r--r--arch/sparc64/kernel/pci_iommu.c510
-rw-r--r--arch/sparc64/kernel/pci_psycho.c1606
-rw-r--r--arch/sparc64/kernel/pci_sabre.c1487
-rw-r--r--arch/sparc64/kernel/power.c105
-rw-r--r--arch/sparc64/kernel/process.c256
-rw-r--r--arch/sparc64/kernel/psycho.c2619
-rw-r--r--arch/sparc64/kernel/ptrace.c52
-rw-r--r--arch/sparc64/kernel/rtrap.S39
-rw-r--r--arch/sparc64/kernel/semaphore.c129
-rw-r--r--arch/sparc64/kernel/setup.c31
-rw-r--r--arch/sparc64/kernel/signal.c203
-rw-r--r--arch/sparc64/kernel/signal32.c142
-rw-r--r--arch/sparc64/kernel/smp.c115
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c6
-rw-r--r--arch/sparc64/kernel/starfire.c12
-rw-r--r--arch/sparc64/kernel/sys_sparc.c102
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c141
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c26
-rw-r--r--arch/sparc64/kernel/systbls.S14
-rw-r--r--arch/sparc64/kernel/time.c162
-rw-r--r--arch/sparc64/kernel/trampoline.S4
-rw-r--r--arch/sparc64/kernel/traps.c186
-rw-r--r--arch/sparc64/kernel/ttable.S6
-rw-r--r--arch/sparc64/kernel/unaligned.c50
-rw-r--r--arch/sparc64/kernel/winfixup.S206
41 files changed, 6150 insertions, 3929 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 6934dda6e..34f52698e 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.43 1999/01/02 16:45:53 davem Exp $
+# $Id: Makefile,v 1.46 1999/08/31 04:39:34 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -20,7 +20,9 @@ O_OBJS := process.o setup.o cpu.o idprom.o \
traps.o devices.o auxio.o ioport.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o sys_sunos32.o sunos_ioctl32.o \
- central.o psycho.o starfire.o
+ central.o pci.o pci_common.o pci_iommu.o \
+ pci_psycho.o pci_sabre.o starfire.o semaphore.o \
+ power.o
OX_OBJS := sparc64_ksyms.o
ifdef CONFIG_PCI
@@ -61,12 +63,16 @@ endif
check_asm: dummy
@echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
@echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
- @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
- @echo "" >> asm_offsets.h
- @echo "#include <linux/config.h>" >> asm_offsets.h
- @echo "" >> asm_offsets.h
- @echo "#ifndef CONFIG_SMP" >> asm_offsets.h
- @echo "" >> asm_offsets.h
+ @echo -e "#define __ASM_OFFSETS_H__\n" >> asm_offsets.h
+ @echo -e "#include <linux/config.h>\n" >> asm_offsets.h
+ @echo '#if defined(__KERNEL__) && !defined(__ASSEMBLY__)' >> asm_offsets.h
+ @if $(CC) -c -m64 -mcmodel=medlow -o /dev/null /dev/null >/dev/null 2>&1; then \
+ echo '# if !((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))' >> asm_offsets.h; \
+ else \
+ echo '# if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)' >> asm_offsets.h; \
+ fi
+ @echo -e "# error Please issue 'make check_asm' in linux top-level directory first\n# endif\n#endif\n" >> asm_offsets.h
+ @echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h
@echo "#include <linux/config.h>" > tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#include <linux/sched.h>" >> tmp.c
@@ -92,11 +98,8 @@ check_asm: dummy
# </hack>
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
- @echo "" >> asm_offsets.h
- @echo "#else /* CONFIG_SMP */" >> asm_offsets.h
- @echo "" >> asm_offsets.h
- @echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h
- @echo "" >> asm_offsets.h
+ @echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
+ @echo -e "#ifndef SPIN_LOCK_DEBUG\n" >>asm_offsets.h
@echo "#include <linux/config.h>" > tmp.c
@echo "#undef CONFIG_SMP" >> tmp.c
@echo "#define CONFIG_SMP 1" >> tmp.c
@@ -124,9 +127,7 @@ check_asm: dummy
# </hack>
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
- @echo "" >> asm_offsets.h
- @echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
- @echo "" >> asm_offsets.h
+ @echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
@echo "#include <linux/sched.h>" > tmp.c
$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i
@echo "/* Automatically generated. Do not edit. */" > check_asm.c
@@ -151,10 +152,8 @@ check_asm: dummy
# </hack>
./check_asm >> asm_offsets.h
@rm -f check_asm check_asm.c
- @echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h
- @echo "" >> asm_offsets.h
- @echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
- @echo "" >> asm_offsets.h
+ @echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h
+ @echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
@if test -r $(HPATH)/asm/asm_offsets.h; then \
if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index a674399e4..c6bcb6bd7 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -22,7 +22,7 @@
/* Probe and map in the Auxiliary I/O register */
unsigned char *auxio_register;
-__initfunc(void auxio_probe(void))
+void __init auxio_probe(void)
{
struct linux_sbus *bus;
struct linux_sbus_device *sdev = 0;
@@ -51,17 +51,7 @@ __initfunc(void auxio_probe(void))
ebus_done:
if (edev) {
- if (check_region(edev->base_address[0],
- sizeof(unsigned int))) {
- prom_printf("%s: Can't get region %lx, %d\n",
- __FUNCTION__, edev->base_address[0],
- sizeof(unsigned int));
- prom_halt();
- }
- request_region(edev->base_address[0],
- sizeof(unsigned int), "LED auxio");
-
- led_auxio = edev->base_address[0];
+ led_auxio = edev->resource[0].start;
outl(0x01, led_auxio);
return;
}
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index bc77266f9..cbbb3557b 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -39,7 +39,8 @@ static int aout32_core_dump(long signr, struct pt_regs * regs);
extern void dump_thread(struct pt_regs *, struct user *);
static struct linux_binfmt aout32_format = {
- NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump
+ NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump,
+ PAGE_SIZE
};
static void set_brk(unsigned long start, unsigned long end)
@@ -63,12 +64,12 @@ static int dump_write(struct file *file, const void *addr, int nr)
#define DUMP_WRITE(addr, nr) \
if (!dump_write(file, (void *)(addr), (nr))) \
- goto close_coredump;
+ goto end_coredump;
#define DUMP_SEEK(offset) \
if (file->f_op->llseek) { \
if (file->f_op->llseek(file,(offset),0) != (offset)) \
- goto close_coredump; \
+ goto end_coredump; \
} else file->f_pos = (offset)
/*
@@ -82,45 +83,17 @@ if (file->f_op->llseek) { \
*/
static inline int
-do_aout32_core_dump(long signr, struct pt_regs * regs)
+do_aout32_core_dump(long signr, struct pt_regs * regs, struct file *file)
{
- struct dentry * dentry = NULL;
- struct inode * inode = NULL;
- struct file * file;
mm_segment_t fs;
int has_dumped = 0;
- char corefile[6+sizeof(current->comm)];
unsigned long dump_start, dump_size;
struct user dump;
# define START_DATA(u) (u.u_tsize)
# define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
- if (!current->dumpable || atomic_read(&current->mm->count) != 1)
- return 0;
- current->dumpable = 0;
-
-/* See if we have enough room to write the upage. */
- if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
- return 0;
fs = get_fs();
set_fs(KERNEL_DS);
- memcpy(corefile,"core.",5);
-#if 0
- memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
- corefile[4] = '\0';
-#endif
- file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
- if (IS_ERR(file))
- goto end_coredump;
- dentry = file->f_dentry;
- inode = dentry->d_inode;
- if (!S_ISREG(inode->i_mode))
- goto close_coredump;
- if (!inode->i_op || !inode->i_op->default_file_ops)
- goto close_coredump;
- if (!file->f_op->write)
- goto close_coredump;
has_dumped = 1;
current->flags |= PF_DUMPCORE;
strncpy(dump.u_comm, current->comm, sizeof(current->comm));
@@ -165,20 +138,18 @@ do_aout32_core_dump(long signr, struct pt_regs * regs)
/* Finally dump the task struct. Not be used by gdb, but could be useful */
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
-close_coredump:
- filp_close(file, NULL);
end_coredump:
set_fs(fs);
return has_dumped;
}
static int
-aout32_core_dump(long signr, struct pt_regs * regs)
+aout32_core_dump(long signr, struct pt_regs * regs, struct file * file)
{
int retval;
MOD_INC_USE_COUNT;
- retval = do_aout32_core_dump(signr, regs);
+ retval = do_aout32_core_dump(signr, regs, file);
MOD_DEC_USE_COUNT;
return retval;
}
@@ -368,6 +339,16 @@ beyond_if:
current->mm->start_stack =
(unsigned long) create_aout32_tables((char *)bprm->p, bprm);
+ if (!(current->thread.flags & SPARC_FLAG_32BIT)) {
+ unsigned long pgd_cache;
+
+ pgd_cache = ((unsigned long)current->mm->pgd[0])<<11UL;
+ __asm__ __volatile__("stxa\t%0, [%1] %2"
+ : /* no outputs */
+ : "r" (pgd_cache),
+ "r" (TSB_REG), "i" (ASI_DMMU));
+ current->thread.flags |= SPARC_FLAG_32BIT;
+ }
start_thread32(regs, ex.a_entry, current->mm->start_stack);
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
@@ -472,7 +453,7 @@ load_aout32_library(int fd)
}
-__initfunc(int init_aout32_binfmt(void))
+int __init init_aout32_binfmt(void)
{
return register_binfmt(&aout32_format);
}
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index f0c36d1a7..252a685f4 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -142,7 +142,7 @@ struct elf_prpsinfo32
#ifdef CONFIG_BINFMT_ELF32_MODULE
#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
#endif
-#define ELF_FLAGS_INIT current->tss.flags |= SPARC_FLAG_32BIT
+#define ELF_FLAGS_INIT current->thread.flags |= SPARC_FLAG_32BIT
MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra");
MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek");
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 86518e50e..dbcc0d45f 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -33,7 +33,7 @@ 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, 0x13, 0, "UltraSparc III integrated FPU"},
+ { 0x17, 0x14, 0, "UltraSparc III integrated FPU"},
};
#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -43,7 +43,7 @@ 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, 0x13, "TI UltraSparc III (Cheetah)"}, /* A guess... */
+ { 0x17, 0x14, "TI UltraSparc III (Cheetah)"}, /* A guess... */
};
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
@@ -58,7 +58,7 @@ char *sparc_fpu_type[64] = { "fpu-oops", };
unsigned int fsr_storage;
-__initfunc(void cpu_probe(void))
+void __init cpu_probe(void)
{
int manuf, impl;
unsigned i, cpuid;
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 0aef0b019..d8085bf06 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -5,8 +5,9 @@
*/
#include <linux/kernel.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <asm/page.h>
#include <asm/oplib.h>
@@ -20,14 +21,18 @@ int linux_num_cpus = 0;
extern void cpu_probe(void);
extern unsigned long central_probe(unsigned long);
-__initfunc(unsigned long
-device_scan(unsigned long mem_start))
+unsigned long __init
+device_scan(unsigned long mem_start)
{
char node_str[128];
int nd, prom_node_cpu, thismid;
int cpu_nds[64]; /* One node for each cpu */
int cpu_ctr = 0;
+ /* FIX ME FAST... -DaveM */
+ ioport_resource.end = 0xffffffffffffffffUL;
+ iomem_resource.end = 0xffffffffffffffffUL;
+
prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
prom_printf("Booting Linux...\n");
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index e64e87299..0b3d16007 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,7 +1,8 @@
-/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $
+/* $Id: ebus.c,v 1.44 1999/09/05 09:28:09 ecd Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
#include <linux/config.h>
@@ -17,15 +18,7 @@
#include <asm/ebus.h>
#include <asm/oplib.h>
#include <asm/bpp.h>
-
-#undef PROM_DEBUG
-#undef DEBUG_FILL_EBUS_DEV
-
-#ifdef PROM_DEBUG
-#define dprintf prom_printf
-#else
-#define dprintf printk
-#endif
+#include <asm/irq.h>
struct linux_ebus *ebus_chain = 0;
@@ -45,20 +38,20 @@ extern int flash_init(void);
extern int envctrl_init(void);
#endif
-static inline unsigned long ebus_alloc(size_t size)
+static inline void *ebus_alloc(size_t size)
{
- unsigned long mem;
+ void *mem;
- mem = (unsigned long)kmalloc(size, GFP_ATOMIC);
+ mem = kmalloc(size, GFP_ATOMIC);
if (!mem)
panic(__FUNCTION__ ": out of memory");
memset((char *)mem, 0, size);
return mem;
}
-__initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
- struct linux_prom_registers *reg,
- int *interrupt))
+void __init ebus_intmap_match(struct linux_ebus *ebus,
+ struct linux_prom_registers *reg,
+ int *interrupt)
{
unsigned int hi, lo, irq;
int i;
@@ -83,28 +76,43 @@ __initfunc(void ebus_intmap_match(struct linux_ebus *ebus,
prom_halt();
}
-__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
- struct linux_ebus_child *dev))
+void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
+ struct linux_ebus_child *dev, int non_standard_regs)
{
int regs[PROMREG_MAX];
int irqs[PROMREG_MAX];
- char lbuf[128];
int i, len;
dev->prom_node = node;
- prom_getstring(node, "name", lbuf, sizeof(lbuf));
- strcpy(dev->prom_name, lbuf);
+ prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
+ printk(" (%s)", dev->prom_name);
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
dev->num_addrs = len / sizeof(regs[0]);
- for (i = 0; i < dev->num_addrs; i++) {
- if (regs[i] >= dev->parent->num_addrs) {
- prom_printf("UGH: property for %s was %d, need < %d\n",
- dev->prom_name, len, dev->parent->num_addrs);
- panic(__FUNCTION__);
+ if (non_standard_regs) {
+ /* This is to handle reg properties which are not
+ * in the parent relative format. One example are
+ * children of the i2c device on CompactPCI systems.
+ *
+ * So, for such devices we just record the property
+ * raw in the child resources.
+ */
+ for (i = 0; i < dev->num_addrs; i++)
+ dev->resource[i].start = regs[i];
+ } else {
+ for (i = 0; i < dev->num_addrs; i++) {
+ int rnum = regs[i];
+ if (rnum >= dev->parent->num_addrs) {
+ prom_printf("UGH: property for %s was %d, need < %d\n",
+ dev->prom_name, len, dev->parent->num_addrs);
+ panic(__FUNCTION__);
+ }
+ dev->resource[i].start = dev->parent->resource[i].start;
+ dev->resource[i].end = dev->parent->resource[i].end;
+ dev->resource[i].flags = IORESOURCE_MEM;
+ dev->resource[i].name = dev->prom_name;
}
- dev->base_address[i] = dev->parent->base_address[regs[i]];
}
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
@@ -128,52 +136,53 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
} else {
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++) {
+ struct pci_pbm_info *pbm = dev->bus->parent;
+ struct pci_controller_info *p = pbm->parent;
+
ebus_intmap_match(dev->bus, preg, &irqs[i]);
- dev->irqs[i] = psycho_irq_build(dev->bus->parent,
- dev->bus->self, irqs[i]);
+ dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]);
}
}
+}
-#ifdef DEBUG_FILL_EBUS_DEV
- dprintf("child '%s': address%s\n", dev->prom_name,
- dev->num_addrs > 1 ? "es" : "");
- for (i = 0; i < dev->num_addrs; i++)
- dprintf(" %016lx\n", dev->base_address[i]);
- if (dev->num_irqs) {
- dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
- for (i = 0; i < dev->num_irqs; i++)
- dprintf(" %s", __irq_itoa(dev->irqs[i]));
- dprintf("\n");
- }
-#endif
+static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
+{
+ if (!strcmp(dev->prom_name, "i2c"))
+ return 1;
+ return 0;
}
-__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
{
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_ebus_child *child;
int irqs[PROMINTR_MAX];
- char lbuf[128];
int i, n, len;
dev->prom_node = node;
- prom_getstring(node, "name", lbuf, sizeof(lbuf));
- strcpy(dev->prom_name, lbuf);
+ prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
+ printk(" [%s", dev->prom_name);
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
dev->prom_name, len,
(int)sizeof(struct linux_prom_registers));
- panic(__FUNCTION__);
+ prom_halt();
}
dev->num_addrs = len / sizeof(struct linux_prom_registers);
for (i = 0; i < dev->num_addrs; i++) {
n = (regs[i].which_io - 0x10) >> 2;
- dev->base_address[i] = dev->bus->self->base_address[n];
- dev->base_address[i] += (unsigned long)regs[i].phys_addr;
+ dev->resource[i].start = dev->bus->self->resource[n].start;
+ dev->resource[i].start += (unsigned long)regs[i].phys_addr;
+ dev->resource[i].end =
+ (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
+ dev->resource[i].flags = IORESOURCE_MEM;
+ dev->resource[i].name = dev->prom_name;
+ request_resource(&dev->bus->self->resource[n],
+ &dev->resource[i]);
}
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
@@ -182,62 +191,51 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
} else {
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++) {
+ struct pci_pbm_info *pbm = dev->bus->parent;
+ struct pci_controller_info *p = pbm->parent;
+
ebus_intmap_match(dev->bus, &regs[0], &irqs[i]);
- dev->irqs[i] = psycho_irq_build(dev->bus->parent,
- dev->bus->self, irqs[i]);
+ dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]);
}
}
-#ifdef DEBUG_FILL_EBUS_DEV
- dprintf("'%s': address%s\n", dev->prom_name,
- dev->num_addrs > 1 ? "es" : "");
- for (i = 0; i < dev->num_addrs; i++)
- dprintf(" %016lx\n", dev->base_address[i]);
- if (dev->num_irqs) {
- dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
- for (i = 0; i < dev->num_irqs; i++)
- dprintf(" %s", __irq_itoa(dev->irqs[i]));
- dprintf("\n");
- }
-#endif
if ((node = prom_getchild(node))) {
- dev->children = (struct linux_ebus_child *)
- ebus_alloc(sizeof(struct linux_ebus_child));
+ printk(" ->");
+ dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
child = dev->children;
child->next = 0;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, &regs[0], child);
+ fill_ebus_child(node, &regs[0],
+ child, child_regs_nonstandard(dev));
while ((node = prom_getsibling(node))) {
- child->next = (struct linux_ebus_child *)
- ebus_alloc(sizeof(struct linux_ebus_child));
+ child->next = ebus_alloc(sizeof(struct linux_ebus_child));
child = child->next;
child->next = 0;
child->parent = dev;
child->bus = dev->bus;
- fill_ebus_child(node, &regs[0], child);
+ fill_ebus_child(node, &regs[0],
+ child, child_regs_nonstandard(dev));
}
}
+ printk("]");
}
extern void clock_probe(void);
+extern void power_init(void);
-__initfunc(void ebus_init(void))
+void __init ebus_init(void)
{
- struct linux_prom_pci_registers regs[PROMREG_MAX];
- struct linux_pbm_info *pbm;
+ struct pci_pbm_info *pbm;
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
- char lbuf[128];
- unsigned long addr, *base;
unsigned short pci_command;
- int nd, len, ebusnd;
- int reg, rng, nreg;
+ int nd, ebusnd;
int num_ebus = 0;
if (!pci_present())
@@ -246,17 +244,13 @@ __initfunc(void ebus_init(void))
pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
if (!pdev) {
printk("ebus: No EBus's found.\n");
-#ifdef PROM_DEBUG
- dprintf("ebus: No EBus's found.\n");
-#endif
return;
}
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
- ebus_chain = ebus = (struct linux_ebus *)
- ebus_alloc(sizeof(struct linux_ebus));
+ ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
ebus->next = 0;
while (ebusnd) {
@@ -273,9 +267,6 @@ __initfunc(void ebus_init(void))
if (ebus == ebus_chain) {
ebus_chain = NULL;
printk("ebus: No EBus's found.\n");
-#ifdef PROM_DEBUG
- dprintf("ebus: No EBus's found.\n");
-#endif
return;
}
break;
@@ -286,14 +277,10 @@ __initfunc(void ebus_init(void))
continue;
}
printk("ebus%d:", num_ebus);
-#ifdef PROM_DEBUG
- dprintf("ebus%d:", num_ebus);
-#endif
- prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
+ prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name));
+ ebus->index = num_ebus;
ebus->prom_node = ebusnd;
- strcpy(ebus->prom_name, lbuf);
-
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
@@ -306,49 +293,7 @@ __initfunc(void ebus_init(void))
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
/* NOTE: Cache line size is in 32-bit word units. */
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
-
- len = prom_getproperty(ebusnd, "reg", (void *)regs,
- sizeof(regs));
- if (len == 0 || len == -1) {
- prom_printf("%s: can't find reg property\n",
- __FUNCTION__);
- prom_halt();
- }
- nreg = len / sizeof(struct linux_prom_pci_registers);
-
- base = &ebus->self->base_address[0];
- for (reg = 0; reg < nreg; reg++) {
- if (!(regs[reg].phys_hi & 0x03000000))
- continue;
-
- for (rng = 0; rng < pbm->num_pbm_ranges; rng++) {
- struct linux_prom_pci_ranges *rp =
- &pbm->pbm_ranges[rng];
-
- if ((rp->child_phys_hi ^ regs[reg].phys_hi)
- & 0x03000000)
- continue;
-
- addr = (u64)regs[reg].phys_lo;
- addr += (u64)regs[reg].phys_mid << 32UL;
- addr += (u64)rp->parent_phys_lo;
- addr += (u64)rp->parent_phys_hi << 32UL;
- *base++ = (unsigned long)__va(addr);
-
- printk(" %lx[%x]", (unsigned long)__va(addr),
- regs[reg].size_lo);
-#ifdef PROM_DEBUG
- dprintf(" %lx[%x]", (unsigned long)__va(addr),
- regs[reg].size_lo);
-#endif
- break;
- }
- }
- printk("\n");
-#ifdef PROM_DEBUG
- dprintf("\n");
-#endif
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64/sizeof(u32));
prom_ebus_ranges_init(ebus);
prom_ebus_intmap_init(ebus);
@@ -357,8 +302,7 @@ __initfunc(void ebus_init(void))
if (!nd)
goto next_ebus;
- ebus->devices = (struct linux_ebus_device *)
- ebus_alloc(sizeof(struct linux_ebus_device));
+ ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
dev = ebus->devices;
dev->next = 0;
@@ -367,8 +311,7 @@ __initfunc(void ebus_init(void))
fill_ebus_device(nd, dev);
while ((nd = prom_getsibling(nd))) {
- dev->next = (struct linux_ebus_device *)
- ebus_alloc(sizeof(struct linux_ebus_device));
+ dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
dev = dev->next;
dev->next = 0;
@@ -378,6 +321,8 @@ __initfunc(void ebus_init(void))
}
next_ebus:
+ printk("\n");
+
pdev = pci_find_device(PCI_VENDOR_ID_SUN,
PCI_DEVICE_ID_SUN_EBUS, pdev);
if (!pdev)
@@ -386,8 +331,7 @@ __initfunc(void ebus_init(void))
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
- ebus->next = (struct linux_ebus *)
- ebus_alloc(sizeof(struct linux_ebus));
+ ebus->next = ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
ebus->next = 0;
++num_ebus;
@@ -409,4 +353,5 @@ __initfunc(void ebus_init(void))
flash_init();
#endif
clock_probe();
+ power_init();
}
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 4134dcc3a..fbd64a507 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $
+/* $Id: entry.S,v 1.107 1999/08/31 19:25:29 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,13 @@ sparc64_vpte_patchme2:
/* This is trivial with the new code... */
.globl do_fpdis
do_fpdis:
- ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g5 ! Load Group
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5 ! Load Group
sethi %hi(TSTATE_PEF), %g4 ! IEU0
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_tss + AOFF_thread_gsr], %g7 ! Load Group
+ ldub [%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
@@ -157,7 +157,7 @@ fpdis_exit:
flush %g6
fpdis_exit2:
wr %g7, 0, %gsr
- ldx [%g6 + AOFF_task_tss + AOFF_thread_xfsr], %fsr
+ ldx [%g6 + AOFF_task_thread + AOFF_thread_xfsr], %fsr
rdpr %tstate, %g3
or %g3, %g4, %g3 ! anal...
wrpr %g3, %tstate
@@ -167,13 +167,13 @@ fpdis_exit2:
.globl do_fptrap
.align 32
do_fptrap:
- ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3
- stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr]
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3
+ stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr]
rd %fprs, %g1
or %g3, %g1, %g3
- stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved]
+ stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved]
rd %gsr, %g3
- stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr]
+ stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr]
mov SECONDARY_CONTEXT, %g3
add %g6, AOFF_task_fpregs, %g2
ldxa [%g3] ASI_DMMU, %g5
@@ -478,6 +478,97 @@ __do_instruction_access_exception:
ba,pt %xcc, rtrap
clr %l6
+ /* This is the trap handler entry point for ECC correctable
+ * errors. They are corrected, but we listen for the trap
+ * so that the event can be logged.
+ *
+ * Disrupting errors are either:
+ * 1) single-bit ECC errors during UDB reads to system
+ * memory
+ * 2) data parity errors during write-back events
+ *
+ * As far as I can make out from the manual, the CEE trap
+ * is only for correctable errors during memory read
+ * accesses by the front-end of the processor.
+ *
+ * The code below is only for trap level 1 CEE events,
+ * as it is the only situation where we can safely record
+ * and log. For trap level >1 we just clear the CE bit
+ * in the AFSR and return.
+ */
+
+ /* Our trap handling infrastructure allows us to preserve
+ * two 64-bit values during etrap for arguments to
+ * subsequent C code. Therefore we encode the information
+ * as follows:
+ *
+ * value 1) Full 64-bits of AFAR
+ * value 2) Low 33-bits of AFSR, then bits 33-->42
+ * are UDBL error status and bits 43-->52
+ * are UDBH error status
+ */
+ .align 64
+ .globl cee_trap
+cee_trap:
+ ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR
+ ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR
+ sllx %g1, 31, %g1 ! Clear reserved bits
+ srlx %g1, 31, %g1 ! in AFSR
+
+ /* NOTE: UltraSparc-I/II have high and low UDB error
+ * registers, corresponding to the two UDB units
+ * present on those chips. UltraSparc-IIi only
+ * has a single UDB, called "SDB" in the manual.
+ * For IIi the upper UDB register always reads
+ * as zero so for our purposes things will just
+ * work with the checks below.
+ */
+ ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status
+ andcc %g3, (1 << 8), %g4 ! Check CE bit
+ sllx %g3, (64 - 10), %g3 ! Clear reserved bits
+ srlx %g3, (64 - 10), %g3 ! in UDB-Low error status
+
+ sllx %g3, (33 + 0), %g3 ! Shift up to encoding area
+ or %g1, %g3, %g1 ! Or it in
+ be,pn %xcc, 1f ! Branch if CE bit was clear
+ nop
+ stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL
+ membar #Sync ! Synchronize ASI stores
+1: mov 0x18, %g5 ! Addr of UDB-High error status
+ ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it
+
+ andcc %g3, (1 << 8), %g4 ! Check CE bit
+ sllx %g3, (64 - 10), %g3 ! Clear reserved bits
+ srlx %g3, (64 - 10), %g3 ! in UDB-High error status
+ sllx %g3, (33 + 10), %g3 ! Shift up to encoding area
+ or %g1, %g3, %g1 ! Or it in
+ be,pn %xcc, 1f ! Branch if CE bit was clear
+ nop
+ nop
+
+ stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH
+ membar #Sync ! Synchronize ASI stores
+1: mov 1, %g5 ! AFSR CE bit is
+ sllx %g5, 20, %g5 ! bit 20
+ stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR
+ membar #Sync ! Synchronize ASI stores
+ sllx %g2, (64 - 41), %g2 ! Clear reserved bits
+ srlx %g2, (64 - 41), %g2 ! in latched AFAR
+
+ andn %g2, 0x0f, %g2 ! Finish resv bit clearing
+ mov %g1, %g4 ! Move AFSR+UDB* into save reg
+ mov %g2, %g5 ! Move AFAR into save reg
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+ mov %l4, %o0
+
+ mov %l5, %o1
+ call cee_log
+ add %sp, STACK_BIAS + REGWIN_SZ, %o2
+ ba,a,pt %xcc, rtrap_clr_l6
+
.globl __do_privact
__do_privact:
mov TLB_SFSR, %g3
@@ -633,41 +724,28 @@ execve_merge:
jmpl %g1, %g0
add %sp, STACK_BIAS + REGWIN_SZ, %o0
- .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
+ .globl sys_pipe, sys_sigpause, sys_nis_syscall
.globl sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend
- .globl sys_sigreturn, sys_rt_sigreturn
+ .globl sys_rt_sigreturn
.globl sys32_sigreturn, sys32_rt_sigreturn
.globl sys32_execve, sys_ptrace
.globl sys_sigaltstack, sys32_sigaltstack
.globl sys32_sigstack
.align 32
-sys_pipe: sethi %hi(sparc_pipe), %g1
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- jmpl %g1 + %lo(sparc_pipe), %g0
- nop
-sys_nis_syscall:sethi %hi(c_sys_nis_syscall), %g1
- add %sp, STACK_BIAS + REGWIN_SZ, %o0
- jmpl %g1 + %lo(c_sys_nis_syscall), %g0
- nop
-
+sys_pipe: ba,pt %xcc, sparc_pipe
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
+sys_nis_syscall:ba,pt %xcc, c_sys_nis_syscall
+ add %sp, STACK_BIAS + REGWIN_SZ, %o0
sys_memory_ordering:
- sethi %hi(sparc_memory_ordering), %g1
- add %sp, STACK_BIAS + REGWIN_SZ, %o1
- jmpl %g1 + %lo(sparc_memory_ordering), %g0
- nop
-sys_sigaltstack:sethi %hi(do_sigaltstack), %g1
- add %i6, STACK_BIAS, %o2
- jmpl %g1 + %lo(do_sigaltstack), %g1
- nop
-sys32_sigstack: sethi %hi(do_sys32_sigstack), %g1
- mov %i6, %o2
- jmpl %g1 + %lo(do_sys32_sigstack), %g1
- nop
+ ba,pt %xcc, sparc_memory_ordering
+ add %sp, STACK_BIAS + REGWIN_SZ, %o1
+sys_sigaltstack:ba,pt %xcc, do_sigaltstack
+ add %i6, STACK_BIAS, %o2
+sys32_sigstack: ba,pt %xcc, do_sys32_sigstack
+ mov %i6, %o2
sys32_sigaltstack:
- sethi %hi(do_sys32_sigaltstack), %g1
- mov %i6, %o2
- jmpl %g1 + %lo(do_sys32_sigaltstack), %g1
- nop
+ ba,pt %xcc, do_sys32_sigaltstack
+ mov %i6, %o2
.align 32
sys_sigsuspend: add %sp, STACK_BIAS + REGWIN_SZ, %o0
@@ -689,10 +767,6 @@ sys_sigpause: add %sp, STACK_BIAS + REGWIN_SZ, %o1
call do_sigpause
add %o7, 1f-.-4, %o7
nop
-sys_sigreturn: add %sp, STACK_BIAS + REGWIN_SZ, %o0
- call do_sigreturn
- add %o7, 1f-.-4, %o7
- nop
sys32_sigreturn:
add %sp, STACK_BIAS + REGWIN_SZ, %o0
call do_sigreturn32
@@ -761,38 +835,30 @@ sys_clone: flushw
ba,pt %xcc, do_fork
add %sp, STACK_BIAS + REGWIN_SZ, %o2
ret_from_syscall:
- /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in
+ /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in
* %o7 for us. Check performance counter stuff too.
*/
-#ifdef __SMP__
- andn %o7, 0x100, %l0
+ andn %o7, SPARC_FLAG_NEWCHILD, %l0
mov %g5, %o0 /* 'prev' */
call schedule_tail
- sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
-#else
- andn %o7, 0x100, %l0
- sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags]
-#endif
- andcc %l0, 0x200, %g0
+ stb %l0, [%g6 + AOFF_task_thread + AOFF_thread_flags]
+ andcc %l0, SPARC_FLAG_PERFCTR, %g0
be,pt %icc, 1f
nop
- ldx [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7
+ ldx [%g6 + AOFF_task_thread + AOFF_thread_pcr_reg], %o7
wr %g0, %o7, %pcr
wr %g0, %g0, %pic
1: b,pt %xcc, ret_sys_call
ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
sparc_exit: rdpr %otherwin, %g1
- rdpr %pstate, %g2
- wrpr %g2, PSTATE_IE, %pstate
+ wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate
rdpr %cansave, %g3
add %g3, %g1, %g3
wrpr %g3, 0x0, %cansave
wrpr %g0, 0x0, %otherwin
- wrpr %g2, 0x0, %pstate
- mov %o7, %l5
- sth %g0, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
- call sys_exit
- mov %l5, %o7
+ wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE), %pstate
+ ba,pt %xcc, sys_exit
+ stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
linux_sparc_ni_syscall:
sethi %hi(sys_ni_syscall), %l7
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S
index 6a94cf3ab..d243a43b3 100644
--- a/arch/sparc64/kernel/etrap.S
+++ b/arch/sparc64/kernel/etrap.S
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.41 1999/05/25 16:53:09 jj Exp $
+/* $Id: etrap.S,v 1.42 1999/07/30 09:35:18 davem Exp $
* etrap.S: Preparing for entry into the kernel on Sparc V9.
*
* Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -56,7 +56,7 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group
wrpr %g0, 0, %canrestore ! Single Group+4bubbles
sll %g2, 3, %g2 ! IEU0 Group
mov 1, %l5 ! IEU1
- stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store
+ stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store
wrpr %g3, 0, %otherwin ! Single Group+4bubbles
wrpr %g2, 0, %wstate ! Single Group+4bubbles
stxa %g0, [%l4] ASI_DMMU ! Store Group
@@ -89,11 +89,11 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group
jmpl %l2 + 0x4, %g0 ! CTI Group
mov %l6, %g6 ! IEU0
-3: ldub [%l6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5 ! Load Group
- add %l6, AOFF_task_tss + AOFF_thread_fpsaved + 1, %l4 ! IEU0
+3: ldub [%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5 ! Load Group
+ add %l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4 ! IEU0
srl %l5, 1, %l3 ! IEU0 Group
add %l5, 2, %l5 ! IEU1
- stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store
+ stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store
ba,pt %xcc, 2b ! CTI
stb %g0, [%l4 + %l3] ! Store Group
diff --git a/arch/sparc64/kernel/idprom.c b/arch/sparc64/kernel/idprom.c
index 08a4a6b6a..3b6789e09 100644
--- a/arch/sparc64/kernel/idprom.c
+++ b/arch/sparc64/kernel/idprom.c
@@ -1,4 +1,4 @@
-/* $Id: idprom.c,v 1.2 1997/04/17 02:28:10 miguel Exp $
+/* $Id: idprom.c,v 1.3 1999/08/31 06:54:53 davem Exp $
* idprom.c: Routines to load the idprom into kernel addresses and
* interpret the data contained within.
*
@@ -16,7 +16,7 @@ struct idprom *idprom;
static struct idprom idprom_buffer;
/* Calculate the IDPROM checksum (xor of the data bytes). */
-__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom))
+static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
{
unsigned char cksum, i, *ptr = (unsigned char *)idprom;
@@ -27,7 +27,7 @@ __initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom))
}
/* Create a local IDPROM copy and verify integrity. */
-__initfunc(void idprom_init(void))
+void __init idprom_init(void)
{
prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
index 66869404d..d256b5761 100644
--- a/arch/sparc64/kernel/init_task.c
+++ b/arch/sparc64/kernel/init_task.c
@@ -6,7 +6,6 @@
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
-static struct file * init_fd_array[NR_OPEN] = { NULL, };
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM(init_mm);
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 833331202..0affcf0eb 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.63 1999/06/09 04:56:14 davem Exp $
+/* $Id: ioctl32.c,v 1.68 1999/09/10 05:59:25 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -38,6 +38,7 @@
#include <linux/ext2_fs.h>
#include <linux/videodev.h>
#include <linux/netdevice.h>
+#include <linux/raw.h>
#include <scsi/scsi.h>
/* Ugly hack. */
@@ -409,6 +410,7 @@ struct ifreq32 {
int ifru_mtu;
struct ifmap32 ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
+ char ifru_newname[IFNAMSIZ];
__kernel_caddr_t32 ifru_data;
} ifr_ifru;
};
@@ -420,7 +422,7 @@ struct ifconf32 {
static int dev_ifname32(unsigned int fd, unsigned long arg)
{
- struct device *dev;
+ struct net_device *dev;
struct ifreq32 ifr32;
int err;
@@ -431,6 +433,8 @@ static int dev_ifname32(unsigned int fd, unsigned long arg)
if (!dev)
return -ENODEV;
+ strcpy(ifr32.ifr_name, dev->name);
+
err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
return (err ? -EFAULT : 0);
}
@@ -570,7 +574,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long ar
if(cmd == SIOCETHTOOL)
len = sizeof(struct ethtool_cmd);
if(cmd == SIOCGPPPVER)
- len = strlen(PPP_VERSION) + 1;
+ len = strlen((char *)ifr.ifr_data) + 1;
else if(cmd == SIOCGPPPCSTATS)
len = sizeof(struct ppp_comp_stats);
else
@@ -2366,6 +2370,10 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
case AUTOFS_IOC_PROTOVER:
case AUTOFS_IOC_EXPIRE:
+ /* Raw devices */
+ case RAW_SETBIND:
+ case RAW_GETBIND:
+
error = sys_ioctl (fd, cmd, arg);
goto out;
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 6eccb883a..598cece4e 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.76 1999/04/02 14:54:30 davem Exp $
+/* $Id: irq.c,v 1.78 1999/08/31 06:54:54 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -31,11 +31,6 @@
#include <asm/hardirq.h>
#include <asm/softirq.h>
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#include <asm/pbm.h>
-#endif
-
/* Internal flag, should not be visible elsewhere at all. */
#define SA_IMAP_MASKED 0x100
#define SA_DMA_SYNC 0x200
@@ -79,15 +74,6 @@ struct irqaction *irq_action[NR_IRQS+1] = {
NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
};
-/* Only 8-bits are available, be careful. -DaveM */
-#define IBF_DMA_SYNC 0x01 /* DMA synchronization behind PCI bridge needed. */
-#define IBF_PCI 0x02 /* Indicates PSYCHO/SCHIZO PCI interrupt. */
-#define IBF_ACTIVE 0x04 /* This interrupt is active and has a handler. */
-#define IBF_MULTI 0x08 /* On PCI, indicates shared bucket. */
-
-#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq))
-#define __irq(bucket) ((unsigned int)(unsigned long)(bucket))
-
int get_irq_list(char *buf)
{
int i, len = 0;
@@ -183,67 +169,22 @@ offset(imap_pmgmt),
/* Convert Interrupt Mapping register pointer to assosciated
* Interrupt Clear register pointer, SYSIO specific version.
*/
-static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
+static volatile unsigned int *sysio_imap_to_iclr(volatile unsigned int *imap)
{
unsigned long diff;
diff = offset(iclr_unused0) - offset(imap_slot0);
- return (unsigned int *) (((unsigned long)imap) + diff);
+ return (volatile unsigned int *) (((unsigned long)imap) + diff);
}
#undef offset
-#ifdef CONFIG_PCI
-/* PCI PSYCHO INO number to Sparc PIL level. */
-unsigned char psycho_ino_to_pil[] = {
- 7, 5, 4, 2, /* PCI A slot 0 Int A, B, C, D */
- 7, 5, 4, 2, /* PCI A slot 1 Int A, B, C, D */
- 7, 5, 4, 2, /* PCI A slot 2 Int A, B, C, D */
- 7, 5, 4, 2, /* PCI A slot 3 Int A, B, C, D */
- 6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */
- 6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */
- 6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */
- 6, 4, 3, 1, /* PCI B slot 3 Int A, B, C, D */
- 3, /* SCSI */
- 5, /* Ethernet */
- 8, /* Parallel Port */
- 13, /* Audio Record */
- 14, /* Audio Playback */
- 15, /* PowerFail */
- 3, /* second SCSI */
- 11, /* Floppy */
- 2, /* Spare Hardware */
- 9, /* Keyboard */
- 4, /* Mouse */
- 12, /* Serial */
- 10, /* Timer 0 */
- 11, /* Timer 1 */
- 15, /* Uncorrectable ECC */
- 15, /* Correctable ECC */
- 15, /* PCI Bus A Error */
- 15, /* PCI Bus B Error */
- 1, /* Power Management */
-};
-
-/* INO number to IMAP register offset for PSYCHO external IRQ's. */
-#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
-
-#define psycho_imap_offset(ino) \
- ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \
- (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
-
-#define psycho_iclr_offset(ino) \
- ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \
- (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f)<<3)))
-
-#endif
-
/* Now these are always passed a true fully specified sun4u INO. */
void enable_irq(unsigned int irq)
{
extern int this_is_starfire;
struct ino_bucket *bucket = __bucket(irq);
- unsigned int *imap;
+ volatile unsigned int *imap;
unsigned long tid;
imap = bucket->imap;
@@ -257,7 +198,7 @@ void enable_irq(unsigned int irq)
: "i" (ASI_UPA_CONFIG));
tid = ((tid & UPA_CONFIG_MID) << 9);
} else {
- extern unsigned int starfire_translate(unsigned int *imap,
+ extern unsigned int starfire_translate(volatile unsigned int *imap,
unsigned int upaid);
tid = (starfire_translate(imap, current->processor) << 26);
@@ -278,7 +219,7 @@ void enable_irq(unsigned int irq)
void disable_irq(unsigned int irq)
{
struct ino_bucket *bucket = __bucket(irq);
- unsigned int *imap;
+ volatile unsigned int *imap;
imap = bucket->imap;
if (imap != NULL) {
@@ -306,7 +247,7 @@ static struct ino_bucket pil0_dummy_bucket = {
NULL, /* imap */
};
-unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap)
+unsigned int build_irq(int pil, int inofixup, volatile unsigned int *iclr, volatile unsigned int *imap)
{
struct ino_bucket *bucket;
int ino;
@@ -365,7 +306,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
struct sysio_regs *sregs = sbus->iommu->sysio_regs;
unsigned long offset;
int pil;
- unsigned int *imap, *iclr;
+ volatile unsigned int *imap, *iclr;
int sbus_level = 0;
pil = sysio_ino_to_pil[ino];
@@ -380,7 +321,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
panic("BAD SYSIO IRQ offset...");
}
offset += ((unsigned long)sregs);
- imap = ((unsigned int *)offset);
+ imap = ((volatile unsigned int *)offset);
/* SYSIO inconsistancy. For external SLOTS, we have to select
* the right ICLR register based upon the lower SBUS irq level
@@ -412,81 +353,11 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
iclraddr = (unsigned long) iclr;
iclraddr += ((sbus_level - 1) * 8);
- iclr = (unsigned int *) iclraddr;
+ iclr = (volatile unsigned int *) iclraddr;
}
return build_irq(pil, sbus_level, iclr, imap);
}
-#ifdef CONFIG_PCI
-unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_dma_sync)
-{
- struct linux_psycho *psycho = (struct linux_psycho *)buscookie;
- struct psycho_regs *pregs = psycho->psycho_regs;
- unsigned long addr;
- struct ino_bucket *bucket;
- int pil;
- unsigned int *imap, *iclr;
- int inofixup = 0;
-
- pil = psycho_ino_to_pil[ino & PCI_IRQ_INO];
-
- addr = (unsigned long) &pregs->imap_a_slot0;
- addr = addr + imap_off;
- imap = ((unsigned int *)addr) + 1;
-
- addr = (unsigned long) pregs;
- addr += psycho_iclr_offset(ino & (PCI_IRQ_INO));
- iclr = ((unsigned int *)addr) + 1;
-
- if(!(ino & 0x20))
- inofixup = ino & 0x03;
-
- /* First check for sharing. */
- ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup;
- if (ino > NUM_IVECS) {
- prom_printf("PSYCHO: Invalid INO %04x (%d:%d:%016lx:%016lx)\n",
- ino, pil, inofixup, iclr, imap);
- prom_halt();
- }
- bucket = &ivector_table[ino];
- if(bucket->flags & IBF_ACTIVE) {
- void *old_handler = bucket->irq_info;
- unsigned long flags;
-
- if(old_handler == NULL) {
- prom_printf("PSYCHO: Active bucket, but no handler.\n");
- prom_halt();
- }
- save_and_cli(flags);
- if((bucket->flags & IBF_MULTI) == 0) {
- void **vector;
-
- vector = kmalloc(sizeof(void *) * 4,
- GFP_KERNEL);
-
- /* We might have slept. */
- if((bucket->flags & IBF_MULTI) != 0) {
- kfree(vector);
- } else {
- vector[0] = old_handler;
- vector[1] = vector[2] = vector[3] = NULL;
- bucket->irq_info = vector;
- bucket->flags |= IBF_MULTI;
- }
- }
- restore_flags(flags);
- } else {
- /* Just init the bucket */
- bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
- }
- if (need_dma_sync)
- bucket->flags |= IBF_DMA_SYNC;
-
- bucket->flags |= IBF_PCI;
- return __irq(bucket);
-}
-#endif
-
static void atomic_bucket_insert(struct ino_bucket *bucket)
{
unsigned long pstate;
@@ -731,7 +602,7 @@ void free_irq(unsigned int irq, void *dev_id)
*(bucket->pil + irq_action) = action->next;
if(action->flags & SA_IMAP_MASKED) {
- unsigned int *imap = bucket->imap;
+ volatile unsigned int *imap = bucket->imap;
void **vector, *orig;
int ent;
@@ -1286,7 +1157,7 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
{
extern int this_is_starfire;
struct ino_bucket *bucket = __bucket(p->mask);
- unsigned int *imap = bucket->imap;
+ volatile unsigned int *imap = bucket->imap;
unsigned int tid;
/* Never change this, it causes problems on Ex000 systems. */
@@ -1296,7 +1167,7 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
if(this_is_starfire == 0) {
tid = __cpu_logical_map[goal_cpu] << 26;
} else {
- extern unsigned int starfire_translate(unsigned int *imap,
+ extern unsigned int starfire_translate(volatile unsigned int *imap,
unsigned int upaid);
tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26);
@@ -1399,7 +1270,7 @@ void enable_prom_timer(void)
prom_timers->count0 = 0;
}
-__initfunc(void init_IRQ(void))
+void __init init_IRQ(void)
{
static int called = 0;
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
new file mode 100644
index 000000000..1776e6d7e
--- /dev/null
+++ b/arch/sparc64/kernel/pci.c
@@ -0,0 +1,339 @@
+/* $Id: pci.c,v 1.6 1999/09/08 03:40:41 davem Exp $
+ * pci.c: UltraSparc PCI controller support.
+ *
+ * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pbm.h>
+#include <asm/irq.h>
+#include <asm/ebus.h>
+
+unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
+unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
+unsigned long pci_memspace_mask = 0xffffffffUL;
+
+#ifndef CONFIG_PCI
+/* A "nop" PCI implementation. */
+int pcibios_present(void) { return 0; }
+asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
+{
+ return 0;
+}
+#else
+
+/* List of all PCI controllers found in the system. */
+spinlock_t pci_controller_lock = SPIN_LOCK_UNLOCKED;
+struct pci_controller_info *pci_controller_root = NULL;
+
+/* Each PCI controller found gets a unique index. */
+int pci_num_controllers = 0;
+
+/* Given an 8-bit PCI bus number, this yields the
+ * controlling PBM module info.
+ *
+ * Some explanation is in order here. The Linux APIs for
+ * the PCI subsystem require that the configuration space
+ * types are enough to signify PCI configuration space
+ * accesses correctly. This gives us 8-bits for the bus
+ * number, however we have multiple PCI controllers on
+ * UltraSparc systems.
+ *
+ * So what we do is give the PCI busses under each controller
+ * a unique portion of the 8-bit PCI bus number space.
+ * Therefore one can obtain the controller from the bus
+ * number. For example, say PSYCHO PBM-A a subordinate bus
+ * space of 0 to 4, and PBM-B has a space of 0 to 2. PBM-A
+ * will use 0 to 4, and PBM-B will use 5 to 7.
+ */
+struct pci_pbm_info *pci_bus2pbm[256];
+unsigned char pci_highest_busnum = 0;
+
+/* At boot time the user can give the kernel a command
+ * line option which controls if and how PCI devices
+ * are reordered at PCI bus probing time.
+ */
+int pci_device_reorder = 0;
+
+spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED;
+volatile int pci_poke_in_progress;
+volatile int pci_poke_faulted;
+
+/* Probe for all PCI controllers in the system. */
+extern void sabre_init(int);
+extern void psycho_init(int);
+
+static struct {
+ char *model_name;
+ void (*init)(int);
+} pci_controller_table[] = {
+ { "SUNW,sabre", sabre_init },
+ { "pci108e,a000", sabre_init },
+ { "SUNW,psycho", psycho_init },
+ { "pci108e,8000", psycho_init }
+};
+#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
+ sizeof(pci_controller_table[0]))
+
+static void pci_controller_init(char *model_name, int namelen, int node)
+{
+ int i;
+
+ for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {
+ if (!strncmp(model_name,
+ pci_controller_table[i].model_name,
+ namelen)) {
+ pci_controller_table[i].init(node);
+ return;
+ }
+ }
+ printk("PCI: Warning unknown controller, model name [%s]\n",
+ model_name);
+ printk("PCI: Ignoring controller...\n");
+}
+
+/* Find each controller in the system, attach and initialize
+ * software state structure for each and link into the
+ * pci_controller_root. Setup the controller enough such
+ * that bus scanning can be done.
+ */
+static void pci_controller_probe(void)
+{
+ char namebuf[16];
+ int node;
+
+ printk("PCI: Probing for controllers.\n");
+ node = prom_getchild(prom_root_node);
+ while ((node = prom_searchsiblings(node, "pci")) != 0) {
+ int len;
+
+ len = prom_getproperty(node, "model",
+ namebuf, sizeof(namebuf));
+ if (len > 0)
+ pci_controller_init(namebuf, len, node);
+ else {
+ len = prom_getproperty(node, "compatible",
+ namebuf, sizeof(namebuf));
+ if (len > 0)
+ pci_controller_init(namebuf, len, node);
+ }
+ node = prom_getsibling(node);
+ if (!node)
+ break;
+ }
+}
+
+static void pci_scan_each_controller_bus(void)
+{
+ struct pci_controller_info *p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pci_controller_lock, flags);
+ for (p = pci_controller_root; p; p = p->next)
+ p->scan_bus(p);
+ spin_unlock_irqrestore(&pci_controller_lock, flags);
+}
+
+/* Reorder the pci_dev chain, so that onboard devices come first
+ * and then come the pluggable cards.
+ */
+static void __init pci_reorder_devs(void)
+{
+ struct pci_dev **pci_onboard = &pci_devices;
+ struct pci_dev **pci_tail = &pci_devices;
+ struct pci_dev *pdev = pci_devices, *pci_other = NULL;
+
+ while (pdev) {
+ if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) {
+ if (pci_other) {
+ *pci_onboard = pdev;
+ pci_onboard = &pdev->next;
+ pdev = pdev->next;
+ *pci_onboard = pci_other;
+ *pci_tail = pdev;
+ continue;
+ } else
+ pci_onboard = &pdev->next;
+ } else if (!pci_other)
+ pci_other = pdev;
+ pci_tail = &pdev->next;
+ pdev = pdev->next;
+ }
+}
+
+void __init pcibios_init(void)
+{
+ pci_controller_probe();
+ if (pci_controller_root == NULL)
+ return;
+
+ pci_scan_each_controller_bus();
+
+ if (pci_device_reorder)
+ pci_reorder_devs();
+
+ ebus_init();
+}
+
+struct pci_fixup pcibios_fixups[] = {
+ { 0 }
+};
+
+void pcibios_fixup_bus(struct pci_bus *pbus)
+{
+}
+
+int pcibios_assign_resource(struct pci_dev *pdev, int resource)
+{
+ return 0;
+}
+
+char * __init pcibios_setup(char *str)
+{
+ if (!strcmp(str, "onboardfirst")) {
+ pci_device_reorder = 1;
+ return NULL;
+ }
+ if (!strcmp(str, "noreorder")) {
+ pci_device_reorder = 0;
+ return NULL;
+ }
+ return str;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ struct pci_dev *dev;
+ u8 byte;
+ u16 word;
+ u32 dword;
+ int err = 0;
+
+ if(!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ dev = pci_find_slot(bus, dfn);
+ if (!dev) {
+ /* Xfree86 is such a turd, it does not check the
+ * return value and just relies on the buffer being
+ * set to all 1's to mean "device not present".
+ */
+ switch(len) {
+ case 1:
+ put_user(0xff, (unsigned char *)buf);
+ break;
+ case 2:
+ put_user(0xffff, (unsigned short *)buf);
+ break;
+ case 4:
+ put_user(0xffffffff, (unsigned int *)buf);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ };
+ goto out;
+ }
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ pci_read_config_byte(dev, off, &byte);
+ put_user(byte, (unsigned char *)buf);
+ break;
+ case 2:
+ pci_read_config_word(dev, off, &word);
+ put_user(word, (unsigned short *)buf);
+ break;
+ case 4:
+ pci_read_config_dword(dev, off, &dword);
+ put_user(dword, (unsigned int *)buf);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+ };
+ unlock_kernel();
+out:
+ return err;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+ unsigned long dfn,
+ unsigned long off,
+ unsigned long len,
+ unsigned char *buf)
+{
+ struct pci_dev *dev;
+ u8 byte;
+ u16 word;
+ u32 dword;
+ int err = 0;
+
+ if(!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ dev = pci_find_slot(bus, dfn);
+ if (!dev) {
+ /* See commentary above about Xfree86 */
+ goto out;
+ }
+
+ lock_kernel();
+ switch(len) {
+ case 1:
+ err = get_user(byte, (u8 *)buf);
+ if(err)
+ break;
+ pci_write_config_byte(dev, off, byte);
+ break;
+
+ case 2:
+ err = get_user(word, (u16 *)buf);
+ if(err)
+ break;
+ pci_write_config_byte(dev, off, word);
+ break;
+
+ case 4:
+ err = get_user(dword, (u32 *)buf);
+ if(err)
+ break;
+ pci_write_config_byte(dev, off, dword);
+ break;
+
+ default:
+ err = -EINVAL;
+ break;
+
+ };
+ unlock_kernel();
+
+out:
+ return err;
+}
+
+#endif /* !(CONFIG_PCI) */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
new file mode 100644
index 000000000..a3600df9c
--- /dev/null
+++ b/arch/sparc64/kernel/pci_common.c
@@ -0,0 +1,651 @@
+/* $Id: pci_common.c,v 1.3 1999/09/04 22:26:32 ecd Exp $
+ * pci_common.c: PCI controller common support.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+
+#include <asm/pbm.h>
+
+/* Find the OBP PROM device tree node for a PCI device.
+ * Return zero if not found.
+ */
+static int __init find_device_prom_node(struct pci_pbm_info *pbm,
+ struct pci_dev *pdev,
+ int bus_prom_node,
+ struct linux_prom_pci_registers *pregs,
+ int *nregs)
+{
+ int node;
+
+ /*
+ * Return the PBM's PROM node in case we are it's PCI device,
+ * as the PBM's reg property is different to standard PCI reg
+ * properties. We would delete this device entry otherwise,
+ * which confuses XFree86's device probing...
+ */
+ if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) &&
+ (pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_PBM)) {
+ *nregs = 0;
+ return bus_prom_node;
+ }
+
+ node = prom_getchild(bus_prom_node);
+ while (node != 0) {
+ int err = prom_getproperty(node, "reg",
+ (char *)pregs,
+ sizeof(*pregs) * PROMREG_MAX);
+ if (err == 0 || err == -1)
+ goto do_next_sibling;
+ if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
+ *nregs = err / sizeof(*pregs);
+ return node;
+ }
+
+ do_next_sibling:
+ node = prom_getsibling(node);
+ }
+ return 0;
+}
+
+/* Remove a PCI device from the device trees, then
+ * free it up. Note that this must run before
+ * the device's resources are registered because we
+ * do not handle unregistering them here.
+ */
+static void pci_device_delete(struct pci_dev *pdev)
+{
+ struct pci_dev **dpp;
+
+ /* First, unlink from list of all devices. */
+ dpp = &pci_devices;
+ while (*dpp != NULL) {
+ if (*dpp == pdev) {
+ *dpp = pdev->next;
+ pdev->next = NULL;
+ break;
+ }
+ dpp = &(*dpp)->next;
+ }
+
+ /* Next, unlink from bus sibling chain. */
+ dpp = &pdev->bus->devices;
+ while (*dpp != NULL) {
+ if (*dpp == pdev) {
+ *dpp = pdev->sibling;
+ pdev->sibling = NULL;
+ break;
+ }
+ dpp = &(*dpp)->sibling;
+ }
+
+ /* Ok, all references are gone, free it up. */
+ kfree(pdev);
+}
+
+/* Fill in the PCI device cookie sysdata for the given
+ * PCI device. This cookie is the means by which one
+ * can get to OBP and PCI controller specific information
+ * for a PCI device.
+ */
+static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
+ struct pci_dev *pdev,
+ int bus_prom_node)
+{
+ struct linux_prom_pci_registers pregs[PROMREG_MAX];
+ struct pcidev_cookie *pcp;
+ int device_prom_node, nregs, err;
+
+ device_prom_node = find_device_prom_node(pbm, pdev, bus_prom_node,
+ pregs, &nregs);
+ if (device_prom_node == 0) {
+ /* If it is not in the OBP device tree then
+ * there must be a damn good reason for it.
+ *
+ * So what we do is delete the device from the
+ * PCI device tree completely. This scenerio
+ * is seen, for example, on CP1500 for the
+ * second EBUS/HappyMeal pair if the external
+ * connector for it is not present.
+ */
+ pci_device_delete(pdev);
+ return;
+ }
+
+ pcp = kmalloc(sizeof(*pcp), GFP_ATOMIC);
+ if (pcp == NULL) {
+ prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n");
+ prom_halt();
+ }
+ pcp->pbm = pbm;
+ pcp->prom_node = device_prom_node;
+ memcpy(pcp->prom_regs, pregs, sizeof(pcp->prom_regs));
+ pcp->num_prom_regs = nregs;
+ err = prom_getproperty(device_prom_node, "name",
+ pcp->prom_name, sizeof(pcp->prom_name));
+ if (err > 0)
+ pcp->prom_name[err] = 0;
+ else
+ pcp->prom_name[0] = 0;
+ if (strcmp(pcp->prom_name, "ebus") == 0) {
+ struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
+ int iter;
+
+ /* EBUS is special... */
+ err = prom_getproperty(device_prom_node, "ranges",
+ (char *)&erng[0], sizeof(erng));
+ if (err == 0 || err == -1) {
+ prom_printf("EBUS: Fatal error, no range property\n");
+ prom_halt();
+ }
+ err = (err / sizeof(erng[0]));
+ for(iter = 0; iter < err; iter++) {
+ struct linux_prom_ebus_ranges *ep = &erng[iter];
+ struct linux_prom_pci_registers *ap;
+
+ ap = &pcp->prom_assignments[iter];
+
+ ap->phys_hi = ep->parent_phys_hi;
+ ap->phys_mid = ep->parent_phys_mid;
+ ap->phys_lo = ep->parent_phys_lo;
+ ap->size_hi = 0;
+ ap->size_lo = ep->size;
+ }
+ pcp->num_prom_assignments = err;
+ } else {
+ err = prom_getproperty(device_prom_node,
+ "assigned-addresses",
+ (char *)pcp->prom_assignments,
+ sizeof(pcp->prom_assignments));
+ if (err == 0 || err == -1)
+ pcp->num_prom_assignments = 0;
+ else
+ pcp->num_prom_assignments =
+ (err / sizeof(pcp->prom_assignments[0]));
+ }
+
+ pdev->sysdata = pcp;
+}
+
+void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
+ struct pci_pbm_info *pbm,
+ int prom_node)
+{
+ struct pci_dev *pdev;
+
+ /* This loop is coded like this because the cookie
+ * fillin routine can delete devices from the tree.
+ */
+ pdev = pbus->devices;
+ while (pdev != NULL) {
+ struct pci_dev *next = pdev->sibling;
+
+ pdev_cookie_fillin(pbm, pdev, prom_node);
+
+ pdev = next;
+ }
+
+ for (pbus = pbus->children; pbus; pbus = pbus->next) {
+ struct pcidev_cookie *pcp = pbus->self->sysdata;
+ pci_fill_in_pbm_cookies(pbus, pbm, pcp->prom_node);
+ }
+}
+
+static void __init bad_assignment(struct linux_prom_pci_registers *ap,
+ struct resource *res,
+ int do_prom_halt)
+{
+ prom_printf("PCI: Bogus PROM assignment.\n");
+ if (ap)
+ prom_printf("PCI: phys[%08x:%08x:%08x] size[%08x:%08x]\n",
+ ap->phys_hi, ap->phys_mid, ap->phys_lo,
+ ap->size_hi, ap->size_lo);
+ if (res)
+ prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n",
+ res->start, res->end, res->flags);
+ prom_printf("Please email this information to davem@redhat.com\n");
+ if (do_prom_halt)
+ prom_halt();
+}
+
+static struct resource *
+__init get_root_resource(struct linux_prom_pci_registers *ap,
+ struct pci_pbm_info *pbm)
+{
+ int space = (ap->phys_hi >> 24) & 3;
+
+ switch (space) {
+ case 0:
+ /* Configuration space, silently ignore it. */
+ return NULL;
+
+ case 1:
+ /* 16-bit IO space */
+ return &pbm->io_space;
+
+ case 2:
+ /* 32-bit MEM space */
+ return &pbm->mem_space;
+
+ case 3:
+ default:
+ /* 64-bit MEM space, unsupported. */
+ printk("PCI: 64-bit MEM assignment??? "
+ "Tell davem@redhat.com about it!\n");
+ return NULL;
+ };
+}
+
+static struct resource *
+__init get_device_resource(struct linux_prom_pci_registers *ap,
+ struct pci_dev *pdev)
+{
+ int breg = (ap->phys_hi & 0xff);
+ int space = (ap->phys_hi >> 24) & 3;
+
+ switch (breg) {
+ case PCI_ROM_ADDRESS:
+ /* It had better be MEM space. */
+ if (space != 2)
+ bad_assignment(ap, NULL, 0);
+
+ return &pdev->resource[PCI_ROM_RESOURCE];
+
+ case PCI_BASE_ADDRESS_0:
+ case PCI_BASE_ADDRESS_1:
+ case PCI_BASE_ADDRESS_2:
+ case PCI_BASE_ADDRESS_3:
+ case PCI_BASE_ADDRESS_4:
+ case PCI_BASE_ADDRESS_5:
+ return &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4];
+
+ default:
+ bad_assignment(ap, NULL, 0);
+ return NULL;
+ };
+}
+
+static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
+ struct pci_dev *pdev)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ int i;
+
+ for (i = 0; i < pcp->num_prom_assignments; i++) {
+ struct linux_prom_pci_registers *ap;
+ struct resource *root, *res;
+
+ /* The format of this property is specified in
+ * the PCI Bus Binding to IEEE1275-1994.
+ */
+ ap = &pcp->prom_assignments[i];
+ root = get_root_resource(ap, pbm);
+ res = get_device_resource(ap, pdev);
+ if (root == NULL || res == NULL)
+ continue;
+
+ /* Ok we know which resource this PROM assignment is
+ * for, sanity check it.
+ */
+ if ((res->start & 0xffffffffUL) != ap->phys_lo)
+ bad_assignment(ap, res, 1);
+
+ /* Adjust the resource into the physical address space
+ * of this PBM.
+ */
+ pbm->parent->resource_adjust(pdev, res, root);
+
+ if (request_resource(root, res) < 0) {
+ /* OK, there is some conflict. But this is fine
+ * since we'll reassign it in the fixup pass.
+ * Nevertheless notify the user that OBP made
+ * an error.
+ */
+ printk(KERN_ERR "PCI: Address space collision on region %ld "
+ "of device %s\n",
+ (res - &pdev->resource[0]), pdev->name);
+ }
+ }
+}
+
+void __init pci_record_assignments(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct pci_dev *pdev;
+
+ for (pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ pdev_record_assignments(pbm, pdev);
+
+ for (pbus = pbus->children; pbus; pbus = pbus->next)
+ pci_record_assignments(pbm, pbus);
+}
+
+static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm,
+ struct pci_dev *pdev)
+{
+ u32 reg;
+ u16 cmd;
+ int i, io_seen, mem_seen;
+
+ io_seen = mem_seen = 0;
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *root, *res;
+ unsigned long size, min, max, align;
+
+ res = &pdev->resource[i];
+
+ if (res->flags & IORESOURCE_IO)
+ io_seen++;
+ else if (res->flags & IORESOURCE_MEM)
+ mem_seen++;
+
+ /* If it is already assigned or the resource does
+ * not exist, there is nothing to do.
+ */
+ if (res->parent != NULL || res->flags == 0UL)
+ continue;
+
+ /* Determine the root we allocate from. */
+ if (res->flags & IORESOURCE_IO) {
+ root = &pbm->io_space;
+ min = root->start + 0x400UL;
+ max = root->end;
+ } else {
+ root = &pbm->mem_space;
+ min = root->start;
+ max = min + 0x80000000UL;
+ }
+
+ size = res->end - res->start;
+ align = size + 1;
+ if (allocate_resource(root, res, size + 1, min, max, align) < 0) {
+ /* uh oh */
+ prom_printf("PCI: Failed to allocate resource %d for %s\n",
+ i, pdev->name);
+ prom_halt();
+ }
+
+ /* Update PCI config space. */
+ pbm->parent->base_address_update(pdev, i);
+ }
+
+ /* Special case, disable the ROM. Several devices
+ * act funny (ie. do not respond to memory space writes)
+ * when it is left enabled. A good example are Qlogic,ISP
+ * adapters.
+ */
+ pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &reg);
+ reg &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS, reg);
+
+ /* If we saw I/O or MEM resources, enable appropriate
+ * bits in PCI command register.
+ */
+ if (io_seen || mem_seen) {
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if (io_seen)
+ cmd |= PCI_COMMAND_IO;
+ if (mem_seen)
+ cmd |= PCI_COMMAND_MEMORY;
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ }
+
+ /* If this is a PCI bridge or an IDE controller,
+ * enable bus mastering. In the former case also
+ * set the cache line size correctly.
+ */
+ if (((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) ||
+ (((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) &&
+ ((pdev->class & 0x80) != 0))) {
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+ if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+ pci_write_config_byte(pdev,
+ PCI_CACHE_LINE_SIZE,
+ (64 / sizeof(u32)));
+ }
+}
+
+void __init pci_assign_unassigned(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct pci_dev *pdev;
+
+ for (pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ pdev_assign_unassigned(pbm, pdev);
+
+ for (pbus = pbus->children; pbus; pbus = pbus->next)
+ pci_assign_unassigned(pbm, pbus);
+}
+
+static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt)
+{
+ struct pcidev_cookie *dev_pcp = pdev->sysdata;
+ struct pci_pbm_info *pbm = dev_pcp->pbm;
+ struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs;
+ unsigned int hi, mid, lo, irq;
+ int i;
+
+ if (pbm->num_pbm_intmap == 0)
+ return 0;
+
+ /* If we are underneath a PCI bridge, use PROM register
+ * property of parent bridge.
+ */
+ if (pdev->bus->number != pbm->pci_first_busno) {
+ struct pcidev_cookie *bus_pcp;
+ int offset;
+
+ bus_pcp = pdev->bus->self->sysdata;
+ pregs = bus_pcp->prom_regs;
+ offset = prom_getint(bus_pcp->prom_node,
+ "fcode-rom-offset");
+
+ /* Did PROM know better and assign an interrupt other
+ * than #INTA to the device? - We test here for presence of
+ * FCODE on the card, in this case we assume PROM has set
+ * correct 'interrupts' property, unless it is quadhme.
+ */
+ if (offset == -1 ||
+ !strcmp(bus_pcp->prom_name, "SUNW,qfe") ||
+ !strcmp(bus_pcp->prom_name, "qfe")) {
+ /*
+ * No, use low slot number bits of child as IRQ line.
+ */
+ *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1;
+ }
+ }
+
+ hi = pregs->phys_hi & pbm->pbm_intmask.phys_hi;
+ mid = pregs->phys_mid & pbm->pbm_intmask.phys_mid;
+ lo = pregs->phys_lo & pbm->pbm_intmask.phys_lo;
+ irq = *interrupt & pbm->pbm_intmask.interrupt;
+
+ for (i = 0; i < pbm->num_pbm_intmap; i++) {
+ if (pbm->pbm_intmap[i].phys_hi == hi &&
+ pbm->pbm_intmap[i].phys_mid == mid &&
+ pbm->pbm_intmap[i].phys_lo == lo &&
+ pbm->pbm_intmap[i].interrupt == irq) {
+ *interrupt = pbm->pbm_intmap[i].cinterrupt;
+ return 1;
+ }
+ }
+
+ prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ",
+ pdev->bus->number, pdev->devfn);
+ prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+ pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
+ prom_printf("Please email this information to davem@redhat.com\n");
+ prom_halt();
+}
+
+static void __init pdev_fixup_irq(struct pci_dev *pdev)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_pbm_info *pbm = pcp->pbm;
+ struct pci_controller_info *p = pbm->parent;
+ unsigned int portid = p->portid;
+ unsigned int prom_irq;
+ int prom_node = pcp->prom_node;
+ int err;
+
+ err = prom_getproperty(prom_node, "interrupts",
+ (char *)&prom_irq, sizeof(prom_irq));
+ if (err == 0 || err == -1) {
+ pdev->irq = 0;
+ return;
+ }
+
+ /* Fully specified already? */
+ if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) {
+ pdev->irq = p->irq_build(p, 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));
+ 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);
+ goto have_irq;
+ }
+
+ /* Ok, we have to do it the hard way. */
+ {
+ unsigned int bus, slot, line;
+
+ bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0;
+
+ /* If we have a legal interrupt property, use it as
+ * the IRQ line.
+ */
+ if (prom_irq > 0 && prom_irq < 5) {
+ line = ((prom_irq - 1) & 3);
+ } else {
+ u8 pci_irq_line;
+
+ /* Else just directly consult PCI config space. */
+ pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line);
+ line = ((pci_irq_line - 1) & 3);
+ }
+
+ /* Now figure out the slot. */
+ if (pdev->bus->number == pbm->pci_first_busno) {
+ if (pbm == &pbm->parent->pbm_A)
+ slot = (pdev->devfn >> 3) - 1;
+ else
+ slot = (pdev->devfn >> 3) - 2;
+ } else {
+ if (pbm == &pbm->parent->pbm_A)
+ slot = (pdev->bus->self->devfn >> 3) - 1;
+ else
+ slot = (pdev->bus->self->devfn >> 3) - 2;
+ }
+ slot = slot << 2;
+
+ pdev->irq = p->irq_build(p, pdev,
+ ((portid << 6) & PCI_IRQ_IGN) |
+ (bus | slot | line));
+ }
+
+have_irq:
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
+ pdev->irq & PCI_IRQ_INO);
+}
+
+void __init pci_fixup_irq(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct pci_dev *pdev;
+
+ for (pdev = pbus->devices; pdev; pdev = pdev->sibling)
+ pdev_fixup_irq(pdev);
+
+ for (pbus = pbus->children; pbus; pbus = pbus->next)
+ pci_fixup_irq(pbm, pbus);
+}
+
+/* Generic helper routines for PCI error reporting. */
+void pci_scan_for_target_abort(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct pci_dev *pdev;
+
+ for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+ u16 status, error_bits;
+
+ pci_read_config_word(pdev, PCI_STATUS, &status);
+ error_bits =
+ (status & (PCI_STATUS_SIG_TARGET_ABORT |
+ PCI_STATUS_REC_TARGET_ABORT));
+ if (error_bits) {
+ pci_write_config_word(pdev, PCI_STATUS, error_bits);
+ printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n",
+ p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
+ pdev->name, status);
+ }
+ }
+
+ for (pbus = pbus->children; pbus; pbus = pbus->next)
+ pci_scan_for_target_abort(p, pbm, pbus);
+}
+
+void pci_scan_for_master_abort(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct pci_dev *pdev;
+
+ for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+ u16 status, error_bits;
+
+ pci_read_config_word(pdev, PCI_STATUS, &status);
+ error_bits =
+ (status & (PCI_STATUS_REC_MASTER_ABORT));
+ if (error_bits) {
+ pci_write_config_word(pdev, PCI_STATUS, error_bits);
+ printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n",
+ p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
+ pdev->name, status);
+ }
+ }
+
+ for (pbus = pbus->children; pbus; pbus = pbus->next)
+ pci_scan_for_master_abort(p, pbm, pbus);
+}
+
+void pci_scan_for_parity_error(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm,
+ struct pci_bus *pbus)
+{
+ struct pci_dev *pdev;
+
+ for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
+ u16 status, error_bits;
+
+ pci_read_config_word(pdev, PCI_STATUS, &status);
+ error_bits =
+ (status & (PCI_STATUS_PARITY |
+ PCI_STATUS_DETECTED_PARITY));
+ if (error_bits) {
+ pci_write_config_word(pdev, PCI_STATUS, error_bits);
+ printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n",
+ p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
+ pdev->name, status);
+ }
+ }
+
+ for (pbus = pbus->children; pbus; pbus = pbus->next)
+ pci_scan_for_parity_error(p, pbm, pbus);
+}
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
new file mode 100644
index 000000000..24ed0319b
--- /dev/null
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -0,0 +1,166 @@
+/* $Id: pci_impl.h,v 1.3 1999/09/10 10:40:44 davem Exp $
+ * pci_impl.h: Helper definitions for PCI controller support.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef PCI_IMPL_H
+#define PCI_IMPL_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+extern spinlock_t pci_controller_lock;
+extern struct pci_controller_info *pci_controller_root;
+
+extern struct pci_pbm_info *pci_bus2pbm[256];
+extern unsigned char pci_highest_busnum;
+extern int pci_num_controllers;
+
+/* PCI bus scanning and fixup support. */
+extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus,
+ struct pci_pbm_info *pbm,
+ int prom_node);
+extern void pci_record_assignments(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus);
+extern void pci_assign_unassigned(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus);
+extern void pci_fixup_irq(struct pci_pbm_info *pbm,
+ struct pci_bus *pbus);
+
+/* Error reporting support. */
+extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
+
+/* IOMMU/DVMA initialization. */
+#define PCI_DVMA_HASH_NONE ~0UL
+static __inline__ void set_dvma_hash(unsigned long dvma_offset,
+ unsigned long paddr,
+ unsigned long daddr)
+{
+ unsigned long dvma_addr = dvma_offset + daddr;
+ unsigned long vaddr = (unsigned long)__va(paddr);
+
+ pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr;
+ pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr;
+}
+
+/* Configuration space access. */
+extern spinlock_t pci_poke_lock;
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_faulted;
+
+static __inline__ void pci_config_read8(u8 *addr, u8 *ret)
+{
+ unsigned long flags;
+ u8 byte;
+
+ spin_lock_irqsave(&pci_poke_lock, flags);
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduba [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (byte)
+ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+ : "memory");
+ pci_poke_in_progress = 0;
+ if (!pci_poke_faulted)
+ *ret = byte;
+ spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+static __inline__ void pci_config_read16(u16 *addr, u16 *ret)
+{
+ unsigned long flags;
+ u16 word;
+
+ spin_lock_irqsave(&pci_poke_lock, flags);
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduha [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (word)
+ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+ : "memory");
+ pci_poke_in_progress = 0;
+ if (!pci_poke_faulted)
+ *ret = word;
+ spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+static __inline__ void pci_config_read32(u32 *addr, u32 *ret)
+{
+ unsigned long flags;
+ u32 dword;
+
+ spin_lock_irqsave(&pci_poke_lock, flags);
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "lduwa [%1] %2, %0\n\t"
+ "membar #Sync"
+ : "=r" (dword)
+ : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+ : "memory");
+ pci_poke_in_progress = 0;
+ if (!pci_poke_faulted)
+ *ret = dword;
+ spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+static __inline__ void pci_config_write8(u8 *addr, u8 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pci_poke_lock, flags);
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stba %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+ : "memory");
+ pci_poke_in_progress = 0;
+ spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+static __inline__ void pci_config_write16(u16 *addr, u16 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pci_poke_lock, flags);
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stha %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+ : "memory");
+ pci_poke_in_progress = 0;
+ spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+static __inline__ void pci_config_write32(u32 *addr, u32 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pci_poke_lock, flags);
+ pci_poke_in_progress = 1;
+ pci_poke_faulted = 0;
+ __asm__ __volatile__("membar #Sync\n\t"
+ "stwa %0, [%1] %2\n\t"
+ "membar #Sync"
+ : /* no outputs */
+ : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+ : "memory");
+ pci_poke_in_progress = 0;
+ spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+#endif /* !(PCI_IMPL_H) */
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
new file mode 100644
index 000000000..a7f469ec8
--- /dev/null
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -0,0 +1,510 @@
+/* $Id: pci_iommu.c,v 1.1 1999/08/30 10:00:47 davem Exp $
+ * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <asm/pbm.h>
+#include <asm/iommu.h>
+#include <asm/scatterlist.h>
+
+#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \
+ ((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
+
+/* Accessing IOMMU and Streaming Buffer registers.
+ * REG parameter is a physical address. All registers
+ * are 64-bits in size.
+ */
+#define pci_iommu_read(__reg) \
+({ u64 __ret; \
+ __asm__ __volatile__("ldxa [%1] %2, %0" \
+ : "=r" (__ret) \
+ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory"); \
+ __ret; \
+})
+#define pci_iommu_write(__reg, __val) \
+ __asm__ __volatile__("stxa %0, [%1] %2" \
+ : /* no outputs */ \
+ : "r" (__val), "r" (__reg), \
+ "i" (ASI_PHYS_BYPASS_EC_E))
+
+/* Find a range of iommu mappings of size NPAGES in page
+ * table PGT. Return pointer to first iopte.
+ */
+static iopte_t *iommu_find_range(unsigned long npages, iopte_t *pgt, int pgt_size)
+{
+ int i;
+
+ pgt_size -= npages;
+ for (i = 0; i < pgt_size; i++) {
+ if (!iopte_val(pgt[i]) & IOPTE_VALID) {
+ int scan;
+
+ for (scan = 1; scan < npages; scan++) {
+ if (iopte_val(pgt[i + scan]) & IOPTE_VALID) {
+ i += scan;
+ goto do_next;
+ }
+ }
+ return &pgt[i];
+ }
+ do_next:
+ }
+ return NULL;
+}
+
+#define IOPTE_CONSISTANT(CTX, PADDR) \
+ (IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | \
+ (((CTX) << 47) & IOPTE_CONTEXT) | \
+ ((PADDR) & IOPTE_PAGE))
+
+#define IOPTE_STREAMING(CTX, PADDR) \
+ (IOPTE_CONSISTANT(CTX, PADDR) | IOPTE_STBUF)
+
+#define IOPTE_INVALID 0UL
+
+/* Map kernel buffer at ADDR of size SZ using consistant mode
+ * DMA for PCI device PDEV. Return 32-bit PCI DMA address.
+ */
+u32 pci_map_consistant(struct pci_dev *pdev, void *addr, int sz)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ iopte_t *base;
+ unsigned long flags, npages, oaddr;
+ u32 ret;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ oaddr = (unsigned long)addr;
+ npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ base = iommu_find_range(npages,
+ iommu->page_table, iommu->page_table_sz);
+ ret = 0;
+ if (base != NULL) {
+ unsigned long i, base_paddr, ctx;
+
+ ret = (iommu->page_table_map_base +
+ ((base - iommu->page_table) << PAGE_SHIFT));
+ ret |= (oaddr & ~PAGE_MASK);
+ base_paddr = __pa(oaddr & PAGE_MASK);
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush)
+ ctx = iommu->iommu_cur_ctx++;
+ for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
+ iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr);
+ }
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return ret;
+}
+
+/* Unmap a consistant DMA translation. */
+void pci_unmap_consistant(struct pci_dev *pdev, u32 bus_addr, int sz)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ iopte_t *base;
+ unsigned long flags, npages, i, ctx;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ base = iommu->page_table +
+ ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT);
+
+ /* Data for consistant mappings cannot enter the streaming
+ * buffers, so we only need to update the TSB and flush
+ * those entries from the IOMMU's TLB.
+ */
+
+ /* Step 1: Clear out the TSB entries. Save away
+ * the context if necessary.
+ */
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush)
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+ for (i = 0; i < npages; i++, base++)
+ iopte_val(*base) = IOPTE_INVALID;
+
+ /* Step 2: Flush from IOMMU TLB. */
+ if (iommu->iommu_has_ctx_flush) {
+ pci_iommu_write(iommu->iommu_ctxflush, ctx);
+ } else {
+ bus_addr &= PAGE_MASK;
+ for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+ pci_iommu_write(iommu->iommu_flush, bus_addr);
+ }
+
+ /* Step 3: Ensure completion of previous PIO writes. */
+ (void) pci_iommu_read(iommu->write_complete_reg);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* Map a single buffer at PTR of SZ bytes for PCI DMA
+ * in streaming mode.
+ */
+u32 pci_map_single(struct pci_dev *pdev, void *ptr, int sz)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ iopte_t *base;
+ unsigned long flags, npages, oaddr;
+ u32 ret;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ oaddr = (unsigned long)ptr;
+ npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ base = iommu_find_range(npages,
+ iommu->page_table, iommu->page_table_sz);
+ ret = 0;
+ if (base != NULL) {
+ unsigned long i, base_paddr, ctx;
+
+ ret = (iommu->page_table_map_base +
+ ((base - iommu->page_table) << PAGE_SHIFT));
+ ret |= (oaddr & ~PAGE_MASK);
+ base_paddr = __pa(oaddr & PAGE_MASK);
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush)
+ ctx = iommu->iommu_cur_ctx++;
+ for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
+ iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr);
+ }
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return ret;
+}
+
+/* Unmap a single streaming mode DMA translation. */
+void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, int sz)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ struct pci_strbuf *strbuf = &pcp->pbm->stc;
+ iopte_t *base;
+ unsigned long flags, npages, i, ctx;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ base = iommu->page_table +
+ ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT);
+ bus_addr &= PAGE_MASK;
+
+ /* Step 1: Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush)
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+
+ /* Step 2: Kick data out of streaming buffers if necessary. */
+ if (strbuf->strbuf_enabled) {
+ u32 vaddr = bus_addr;
+
+ PCI_STC_FLUSHFLAG_INIT(strbuf);
+ if (strbuf->strbuf_has_ctx_flush &&
+ iommu->iommu_has_ctx_flush) {
+ unsigned long matchreg, flushreg;
+
+ flushreg = strbuf->strbuf_ctxflush;
+ matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
+ do {
+ pci_iommu_write(flushreg, ctx);
+ } while(((long)pci_iommu_read(matchreg)) < 0L);
+ } else {
+ for (i = 0; i < npages; i++, vaddr += PAGE_SIZE)
+ pci_iommu_write(strbuf->strbuf_pflush, vaddr);
+ }
+
+ pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+ (void) pci_iommu_read(iommu->write_complete_reg);
+ while (!PCI_STC_FLUSHFLAG_SET(strbuf))
+ membar("#LoadLoad");
+ }
+
+ /* Step 3: Clear out TSB entries. */
+ for (i = 0; i < npages; i++, base++)
+ iopte_val(*base) = IOPTE_INVALID;
+
+ /* Step 4: Flush the IOMMU TLB. */
+ if (iommu->iommu_has_ctx_flush) {
+ pci_iommu_write(iommu->iommu_ctxflush, ctx);
+ } else {
+ for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+ pci_iommu_write(iommu->iommu_flush, bus_addr);
+ }
+
+ /* Step 5: Ensure completion of previous PIO writes. */
+ (void) pci_iommu_read(iommu->write_complete_reg);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* Map a set of buffers described by SGLIST with NELEMS array
+ * elements in streaming mode for PCI DMA.
+ */
+void pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ unsigned long flags, ctx, i;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ /* Step 1: Choose a context if necessary. */
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush)
+ ctx = iommu->iommu_cur_ctx++;
+
+ /* Step 2: Create the mappings. */
+ for (i = 0; i < nelems; i++) {
+ unsigned long oaddr, npages;
+ iopte_t *base;
+
+ oaddr = (unsigned long)sglist[i].address;
+ npages = PAGE_ALIGN(oaddr + sglist[i].length) - (oaddr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ base = iommu_find_range(npages,
+ iommu->page_table, iommu->page_table_sz);
+ if (base != NULL) {
+ unsigned long j, base_paddr;
+ u32 dvma_addr;
+
+ dvma_addr = (iommu->page_table_map_base +
+ ((base - iommu->page_table) << PAGE_SHIFT));
+ dvma_addr |= (oaddr & ~PAGE_MASK);
+ sglist[i].dvma_address = dvma_addr;
+ sglist[i].dvma_length = sglist[i].length;
+ base_paddr = __pa(oaddr & PAGE_MASK);
+ for (j = 0; j < npages; j++, base++, base_paddr += PAGE_SIZE)
+ iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr);
+ } else {
+ sglist[i].dvma_address = 0;
+ sglist[i].dvma_length = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* Unmap a set of streaming mode DMA translations. */
+void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ struct pci_strbuf *strbuf = &pcp->pbm->stc;
+ unsigned long flags, ctx, i;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ /* Step 1: Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush) {
+ iopte_t *iopte;
+
+ iopte = iommu->page_table +
+ ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT);
+ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
+ }
+
+ /* Step 2: Kick data out of streaming buffers if necessary. */
+ if (strbuf->strbuf_enabled) {
+ PCI_STC_FLUSHFLAG_INIT(strbuf);
+ if (strbuf->strbuf_has_ctx_flush &&
+ iommu->iommu_has_ctx_flush) {
+ unsigned long matchreg, flushreg;
+
+ flushreg = strbuf->strbuf_ctxflush;
+ matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
+ do {
+ pci_iommu_write(flushreg, ctx);
+ } while(((long)pci_iommu_read(matchreg)) < 0L);
+ } else {
+ for (i = 0; i < nelems; i++) {
+ unsigned long j, npages;
+ u32 vaddr;
+
+ j = sglist[i].dvma_length;
+ if (!j)
+ break;
+ vaddr = sglist[i].dvma_address;
+ npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ vaddr &= PAGE_MASK;
+ for (j = 0; j < npages; j++, vaddr += PAGE_SIZE)
+ pci_iommu_write(strbuf->strbuf_pflush, vaddr);
+ }
+
+ pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+ (void) pci_iommu_read(iommu->write_complete_reg);
+ while (!PCI_STC_FLUSHFLAG_SET(strbuf))
+ membar("#LoadLoad");
+ }
+ }
+
+ /* Step 3: Clear out TSB entries. */
+ for (i = 0; i < nelems; i++) {
+ unsigned long j, npages;
+ iopte_t *base;
+ u32 vaddr;
+
+ j = sglist[i].dvma_length;
+ if (!j)
+ break;
+ vaddr = sglist[i].dvma_address;
+ npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ base = iommu->page_table +
+ ((vaddr - iommu->page_table_map_base) >> PAGE_SHIFT);
+ for (j = 0; j < npages; j++, base++)
+ iopte_val(*base) = IOPTE_INVALID;
+ }
+
+ /* Step 4: Flush the IOMMU TLB. */
+ if (iommu->iommu_has_ctx_flush) {
+ pci_iommu_write(iommu->iommu_ctxflush, ctx);
+ } else {
+ for (i = 0; i < nelems; i++) {
+ unsigned long j, npages;
+ u32 vaddr;
+
+ j = sglist[i].dvma_length;
+ if (!j)
+ break;
+ vaddr = sglist[i].dvma_address;
+ npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ for (j = 0; j < npages; j++, vaddr += PAGE_SIZE)
+ pci_iommu_write(iommu->iommu_flush, vaddr);
+ }
+ }
+
+ /* Step 5: Ensure completion of previous PIO writes. */
+ (void) pci_iommu_read(iommu->write_complete_reg);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* Make physical memory consistant for a single
+ * streaming mode DMA translation after a transfer.
+ */
+void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, int sz)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ struct pci_strbuf *strbuf = &pcp->pbm->stc;
+ unsigned long flags, ctx, npages;
+
+ if (!strbuf->strbuf_enabled)
+ return;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ bus_addr &= PAGE_MASK;
+
+ /* Step 1: Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush &&
+ strbuf->strbuf_has_ctx_flush) {
+ iopte_t *iopte;
+
+ iopte = iommu->page_table +
+ ((bus_addr - iommu->page_table_map_base)>>PAGE_SHIFT);
+ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
+ }
+
+ /* Step 2: Kick data out of streaming buffers. */
+ PCI_STC_FLUSHFLAG_INIT(strbuf);
+ if (iommu->iommu_has_ctx_flush &&
+ strbuf->strbuf_has_ctx_flush) {
+ unsigned long matchreg, flushreg;
+
+ flushreg = strbuf->strbuf_ctxflush;
+ matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
+ do {
+ pci_iommu_write(flushreg, ctx);
+ } while(((long)pci_iommu_read(matchreg)) < 0L);
+ } else {
+ unsigned long i;
+
+ for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+ pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
+ }
+
+ /* Step 3: Perform flush synchronization sequence. */
+ pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+ (void) pci_iommu_read(iommu->write_complete_reg);
+ while (!PCI_STC_FLUSHFLAG_SET(strbuf))
+ membar("#LoadLoad");
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* Make physical memory consistant for a set of streaming
+ * mode DMA translations after a transfer.
+ */
+void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_iommu *iommu = &pcp->pbm->parent->iommu;
+ struct pci_strbuf *strbuf = &pcp->pbm->stc;
+ unsigned long flags, ctx;
+
+ if (!strbuf->strbuf_enabled)
+ return;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ /* Step 1: Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_has_ctx_flush &&
+ strbuf->strbuf_has_ctx_flush) {
+ iopte_t *iopte;
+
+ iopte = iommu->page_table +
+ ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT);
+ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
+ }
+
+ /* Step 2: Kick data out of streaming buffers. */
+ PCI_STC_FLUSHFLAG_INIT(strbuf);
+ if (iommu->iommu_has_ctx_flush &&
+ strbuf->strbuf_has_ctx_flush) {
+ unsigned long matchreg, flushreg;
+
+ flushreg = strbuf->strbuf_ctxflush;
+ matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
+ do {
+ pci_iommu_write(flushreg, ctx);
+ } while (((long)pci_iommu_read(matchreg)) < 0L);
+ } else {
+ unsigned long i;
+
+ for(i = 0; i < nelems; i++) {
+ unsigned long bus_addr, npages, j;
+
+ j = sglist[i].dvma_length;
+ if (!j)
+ break;
+ bus_addr = sglist[i].dvma_address;
+ npages = PAGE_ALIGN(bus_addr + j) - (bus_addr & PAGE_MASK);
+ npages >>= PAGE_SHIFT;
+ bus_addr &= PAGE_MASK;
+ for(j = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+ pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
+ }
+ }
+
+ /* Step 3: Perform flush synchronization sequence. */
+ pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+ (void) pci_iommu_read(iommu->write_complete_reg);
+ while (!PCI_STC_FLUSHFLAG_SET(strbuf))
+ membar("#LoadLoad");
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
new file mode 100644
index 000000000..1afe5a67b
--- /dev/null
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -0,0 +1,1606 @@
+/* $Id: pci_psycho.c,v 1.4 1999/09/05 09:33:36 ecd Exp $
+ * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
+ *
+ * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+
+#include <asm/pbm.h>
+#include <asm/iommu.h>
+#include <asm/irq.h>
+
+#include "pci_impl.h"
+
+/* All PSYCHO registers are 64-bits. The following accessor
+ * routines are how they are accessed. The REG parameter
+ * is a physical address.
+ */
+#define psycho_read(__reg) \
+({ u64 __ret; \
+ __asm__ __volatile__("ldxa [%1] %2, %0" \
+ : "=r" (__ret) \
+ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory"); \
+ __ret; \
+})
+#define psycho_write(__reg, __val) \
+ __asm__ __volatile__("stxa %0, [%1] %2" \
+ : /* no outputs */ \
+ : "r" (__val), "r" (__reg), \
+ "i" (ASI_PHYS_BYPASS_EC_E))
+
+/* Misc. PSYCHO PCI controller register offsets and definitions. */
+#define PSYCHO_CONTROL 0x0010UL
+#define PSYCHO_CONTROL_IMPL 0xf000000000000000 /* Implementation of this PSYCHO*/
+#define PSYCHO_CONTROL_VER 0x0f00000000000000 /* Version of this PSYCHO */
+#define PSYCHO_CONTROL_MID 0x00f8000000000000 /* UPA Module ID of PSYCHO */
+#define PSYCHO_CONTROL_IGN 0x0007c00000000000 /* Interrupt Group Number */
+#define PSYCHO_CONTROL_RESV 0x00003ffffffffff0 /* Reserved */
+#define PSYCHO_CONTROL_APCKEN 0x0000000000000008 /* Address Parity Check Enable */
+#define PSYCHO_CONTROL_APERR 0x0000000000000004 /* Incoming System Addr Parerr */
+#define PSYCHO_CONTROL_IAP 0x0000000000000002 /* Invert UPA Parity */
+#define PSYCHO_CONTROL_MODE 0x0000000000000001 /* PSYCHO clock mode */
+#define PSYCHO_PCIA_CTRL 0x2000UL
+#define PSYCHO_PCIB_CTRL 0x4000UL
+#define PSYCHO_PCICTRL_RESV1 0xfffffff000000000 /* Reserved */
+#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000 /* Streaming byte hole error */
+#define PSYCHO_PCICTRL_SERR 0x0000000400000000 /* SERR signal asserted */
+#define PSYCHO_PCICTRL_SPEED 0x0000000200000000 /* PCI speed (1 is U2P clock) */
+#define PSYCHO_PCICTRL_RESV2 0x00000001ffc00000 /* Reserved */
+#define PSYCHO_PCICTRL_ARB_PARK 0x0000000000200000 /* PCI arbitration parking */
+#define PSYCHO_PCICTRL_RESV3 0x00000000001ff800 /* Reserved */
+#define PSYCHO_PCICTRL_SBH_INT 0x0000000000000400 /* Streaming byte hole int enab */
+#define PSYCHO_PCICTRL_WEN 0x0000000000000200 /* Power Mgmt Wake Enable */
+#define PSYCHO_PCICTRL_EEN 0x0000000000000100 /* PCI Error Interrupt Enable */
+#define PSYCHO_PCICTRL_RESV4 0x00000000000000c0 /* Reserved */
+#define PSYCHO_PCICTRL_AEN 0x000000000000003f /* PCI DVMA Arbitration Enable */
+
+/* U2P Programmer's Manual, page 13-55, configuration space
+ * address format:
+ *
+ * 32 24 23 16 15 11 10 8 7 2 1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define PSYCHO_CONFIG_BASE(PBM) \
+ ((PBM)->parent->config_space | (1UL << 24))
+#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \
+ (((unsigned long)(BUS) << 16) | \
+ ((unsigned long)(DEVFN) << 8) | \
+ ((unsigned long)(REG)))
+
+static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
+ unsigned char bus,
+ unsigned int devfn,
+ int where)
+{
+ if (!pbm)
+ return NULL;
+ return (void *)
+ (PSYCHO_CONFIG_BASE(pbm) |
+ PSYCHO_CONFIG_ENCODE(bus, devfn, where));
+}
+
+static int psycho_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) > 8) ||
+ ((pbm == &pbm->parent->pbm_A) &&
+ (bus == pbm->pci_first_busno) &&
+ PCI_SLOT(devfn) > 8));
+}
+
+/* PSYCHO PCI configuration space accessors. */
+
+static int psycho_read_byte(struct pci_dev *dev, int where, u8 *value)
+{
+ 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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (psycho_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+ pci_config_read8(addr, value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int psycho_read_word(struct pci_dev *dev, int where, u16 *value)
+{
+ 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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (psycho_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 psycho_read_dword(struct pci_dev *dev, int where, u32 *value)
+{
+ 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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (psycho_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 psycho_write_byte(struct pci_dev *dev, int where, u8 value)
+{
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u8 *addr;
+
+ addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (psycho_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ pci_config_write8(addr, value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int psycho_write_word(struct pci_dev *dev, int where, u16 value)
+{
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u16 *addr;
+
+ addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (psycho_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 psycho_write_dword(struct pci_dev *dev, int where, u32 value)
+{
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u32 *addr;
+
+ addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (psycho_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 psycho_ops = {
+ psycho_read_byte,
+ psycho_read_word,
+ psycho_read_dword,
+ psycho_write_byte,
+ psycho_write_word,
+ psycho_write_dword
+};
+
+/* PSYCHO interrupt mapping support. */
+#define PSYCHO_IMAP_A_SLOT0 0x0c00UL
+#define PSYCHO_IMAP_B_SLOT0 0x0c20UL
+static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
+{
+ unsigned int bus = (ino & 0x10) >> 4;
+ unsigned int slot = (ino & 0x0c) >> 2;
+
+ if (bus == 0)
+ return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
+ else
+ return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
+}
+
+#define PSYCHO_IMAP_SCSI 0x1000UL
+#define PSYCHO_IMAP_ETH 0x1008UL
+#define PSYCHO_IMAP_BPP 0x1010UL
+#define PSYCHO_IMAP_AU_REC 0x1018UL
+#define PSYCHO_IMAP_AU_PLAY 0x1020UL
+#define PSYCHO_IMAP_PFAIL 0x1028UL
+#define PSYCHO_IMAP_KMS 0x1030UL
+#define PSYCHO_IMAP_FLPY 0x1038UL
+#define PSYCHO_IMAP_SHW 0x1040UL
+#define PSYCHO_IMAP_KBD 0x1048UL
+#define PSYCHO_IMAP_MS 0x1050UL
+#define PSYCHO_IMAP_SER 0x1058UL
+#define PSYCHO_IMAP_TIM0 0x1060UL
+#define PSYCHO_IMAP_TIM1 0x1068UL
+#define PSYCHO_IMAP_UE 0x1070UL
+#define PSYCHO_IMAP_CE 0x1078UL
+#define PSYCHO_IMAP_A_ERR 0x1080UL
+#define PSYCHO_IMAP_B_ERR 0x1088UL
+#define PSYCHO_IMAP_PMGMT 0x1090UL
+#define PSYCHO_IMAP_GFX 0x1098UL
+#define PSYCHO_IMAP_EUPA 0x10a0UL
+
+static unsigned long __onboard_imap_off[] = {
+/*0x20*/ PSYCHO_IMAP_SCSI,
+/*0x21*/ PSYCHO_IMAP_ETH,
+/*0x22*/ PSYCHO_IMAP_BPP,
+/*0x23*/ PSYCHO_IMAP_AU_REC,
+/*0x24*/ PSYCHO_IMAP_AU_PLAY,
+/*0x25*/ PSYCHO_IMAP_PFAIL,
+/*0x26*/ PSYCHO_IMAP_KMS,
+/*0x27*/ PSYCHO_IMAP_FLPY,
+/*0x28*/ PSYCHO_IMAP_SHW,
+/*0x29*/ PSYCHO_IMAP_KBD,
+/*0x2a*/ PSYCHO_IMAP_MS,
+/*0x2b*/ PSYCHO_IMAP_SER,
+/*0x2c*/ PSYCHO_IMAP_TIM0,
+/*0x2d*/ PSYCHO_IMAP_TIM1,
+/*0x2e*/ PSYCHO_IMAP_UE,
+/*0x2f*/ PSYCHO_IMAP_CE,
+/*0x30*/ PSYCHO_IMAP_A_ERR,
+/*0x31*/ PSYCHO_IMAP_B_ERR,
+/*0x32*/ PSYCHO_IMAP_PMGMT
+};
+#define PSYCHO_ONBOARD_IRQ_BASE 0x20
+#define PSYCHO_ONBOARD_IRQ_LAST 0x32
+#define psycho_onboard_imap_offset(__ino) \
+ __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
+
+#define PSYCHO_ICLR_A_SLOT0 0x1400UL
+#define PSYCHO_ICLR_SCSI 0x1800UL
+
+#define psycho_iclr_offset(ino) \
+ ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
+ (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
+
+/* PCI PSYCHO INO number to Sparc PIL level. */
+static unsigned char psycho_pil_table[] = {
+/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */
+/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */
+/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */
+/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */
+/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */
+/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */
+/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */
+/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */
+/*0x20*/3, /* SCSI */
+/*0x21*/5, /* Ethernet */
+/*0x22*/8, /* Parallel Port */
+/*0x23*/13, /* Audio Record */
+/*0x24*/14, /* Audio Playback */
+/*0x25*/15, /* PowerFail */
+/*0x26*/3, /* second SCSI */
+/*0x27*/11, /* Floppy */
+/*0x28*/2, /* Spare Hardware */
+/*0x29*/9, /* Keyboard */
+/*0x2a*/4, /* Mouse */
+/*0x2b*/12, /* Serial */
+/*0x2c*/10, /* Timer 0 */
+/*0x2d*/11, /* Timer 1 */
+/*0x2e*/15, /* Uncorrectable ECC */
+/*0x2f*/15, /* Correctable ECC */
+/*0x30*/15, /* PCI Bus A Error */
+/*0x31*/15, /* PCI Bus B Error */
+/*0x32*/1, /* Power Management */
+};
+
+static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
+{
+ int ret;
+
+ ret = psycho_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 psycho_irq_build(struct pci_controller_info *p,
+ struct pci_dev *pdev,
+ unsigned int ino)
+{
+ struct ino_bucket *bucket;
+ volatile unsigned int *imap, *iclr;
+ unsigned long imap_off, iclr_off;
+ int pil, inofixup = 0;
+
+ ino &= PCI_IRQ_INO;
+ if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
+ /* PCI slot */
+ imap_off = psycho_pcislot_imap_offset(ino);
+ } else {
+ /* Onboard device */
+ if (ino > PSYCHO_ONBOARD_IRQ_LAST) {
+ prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
+ prom_halt();
+ }
+ imap_off = psycho_onboard_imap_offset(ino);
+ }
+
+ /* Now build the IRQ bucket. */
+ pil = psycho_ino_to_pil(pdev, ino);
+ imap = (volatile unsigned int *)__va(p->controller_regs + imap_off);
+ imap += 1;
+
+ iclr_off = psycho_iclr_offset(ino);
+ iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off);
+ iclr += 1;
+
+ if ((ino & 0x20) == 0)
+ inofixup = ino & 0x03;
+
+ bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+ bucket->flags |= IBF_PCI;
+
+ return __irq(bucket);
+}
+
+/* PSYCHO error handling support. */
+enum psycho_error_type {
+ UE_ERR, CE_ERR, PCI_ERR
+};
+
+/* Helper function of IOMMU error checking, which checks out
+ * the state of the streaming buffers. The IOMMU lock is
+ * held when this is called.
+ *
+ * For the PCI error case we know which PBM (and thus which
+ * streaming buffer) caused the error, but for the uncorrectable
+ * error case we do not. So we always check both streaming caches.
+ */
+#define PSYCHO_STRBUF_CONTROL_A 0x2800UL
+#define PSYCHO_STRBUF_CONTROL_B 0x4800UL
+#define PSYCHO_STRBUF_CTRL_LPTR 0x00000000000000f0 /* LRU Lock Pointer */
+#define PSYCHO_STRBUF_CTRL_LENAB 0x0000000000000008 /* LRU Lock Enable */
+#define PSYCHO_STRBUF_CTRL_RRDIS 0x0000000000000004 /* Rerun Disable */
+#define PSYCHO_STRBUF_CTRL_DENAB 0x0000000000000002 /* Diagnostic Mode Enable */
+#define PSYCHO_STRBUF_CTRL_ENAB 0x0000000000000001 /* Streaming Buffer Enable */
+#define PSYCHO_STRBUF_FLUSH_A 0x2808UL
+#define PSYCHO_STRBUF_FLUSH_B 0x4808UL
+#define PSYCHO_STRBUF_FSYNC_A 0x2810UL
+#define PSYCHO_STRBUF_FSYNC_B 0x4810UL
+#define PSYCHO_STC_DATA_A 0xb000UL
+#define PSYCHO_STC_DATA_B 0xc000UL
+#define PSYCHO_STC_ERR_A 0xb400UL
+#define PSYCHO_STC_ERR_B 0xc400UL
+#define PSYCHO_STCERR_WRITE 0x0000000000000002 /* Write Error */
+#define PSYCHO_STCERR_READ 0x0000000000000001 /* Read Error */
+#define PSYCHO_STC_TAG_A 0xb800UL
+#define PSYCHO_STC_TAG_B 0xc800UL
+#define PSYCHO_STCTAG_PPN 0x0fffffff00000000 /* Physical Page Number */
+#define PSYCHO_STCTAG_VPN 0x00000000ffffe000 /* Virtual Page Number */
+#define PSYCHO_STCTAG_VALID 0x0000000000000002 /* Valid */
+#define PSYCHO_STCTAG_WRITE 0x0000000000000001 /* Writable */
+#define PSYCHO_STC_LINE_A 0xb900UL
+#define PSYCHO_STC_LINE_B 0xc900UL
+#define PSYCHO_STCLINE_LINDX 0x0000000001e00000 /* LRU Index */
+#define PSYCHO_STCLINE_SPTR 0x00000000001f8000 /* Dirty Data Start Pointer */
+#define PSYCHO_STCLINE_LADDR 0x0000000000007f00 /* Line Address */
+#define PSYCHO_STCLINE_EPTR 0x00000000000000fc /* Dirty Data End Pointer */
+#define PSYCHO_STCLINE_VALID 0x0000000000000002 /* Valid */
+#define PSYCHO_STCLINE_FOFN 0x0000000000000001 /* Fetch Outstanding / Flush Necessary */
+
+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 __psycho_check_one_stc(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm,
+ int is_pbm_a)
+{
+ struct pci_strbuf *strbuf = &pbm->stc;
+ unsigned long regbase = p->controller_regs;
+ unsigned long err_base, tag_base, line_base;
+ u64 control;
+ int i;
+
+ if (is_pbm_a) {
+ err_base = regbase + PSYCHO_STC_ERR_A;
+ tag_base = regbase + PSYCHO_STC_TAG_A;
+ line_base = regbase + PSYCHO_STC_LINE_A;
+ } else {
+ err_base = regbase + PSYCHO_STC_ERR_A;
+ tag_base = regbase + PSYCHO_STC_TAG_A;
+ line_base = regbase + PSYCHO_STC_LINE_A;
+ }
+
+ 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 = psycho_read(strbuf->strbuf_control);
+ psycho_write(strbuf->strbuf_control,
+ (control | PSYCHO_STRBUF_CTRL_DENAB));
+ for (i = 0; i < 128; i++) {
+ unsigned long val;
+
+ val = psycho_read(err_base + (i * 8UL));
+ psycho_write(err_base + (i * 8UL), 0UL);
+ stc_error_buf[i] = val;
+ }
+ for (i = 0; i < 16; i++) {
+ stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL));
+ stc_line_buf[i] = psycho_read(line_base + (i * 8UL));
+ psycho_write(tag_base + (i * 8UL), 0UL);
+ psycho_write(line_base + (i * 8UL), 0UL);
+ }
+
+ /* OK, state is logged, exit diagnostic mode. */
+ psycho_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("PSYCHO%d(PBM%c): STC_ERR(%d)[wr(%d)rd(%d)]\n",
+ p->index,
+ (is_pbm_a ? 'A' : 'B'),
+ j,
+ (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
+ (errval & PSYCHO_STCERR_READ) ? 1 : 0);
+ }
+ }
+ if (saw_error != 0) {
+ unsigned long tagval = stc_tag_buf[i];
+ unsigned long lineval = stc_line_buf[i];
+ printk("PSYCHO%d(PBM%c): STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
+ p->index,
+ (is_pbm_a ? 'A' : 'B'),
+ i,
+ ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
+ (tagval & PSYCHO_STCTAG_VPN),
+ ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
+ ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
+ printk("PSYCHO%d(PBM%c): STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
+ "V(%d)FOFN(%d)]\n",
+ p->index,
+ (is_pbm_a ? 'A' : 'B'),
+ i,
+ ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
+ ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
+ ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
+ ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
+ ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
+ ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
+ }
+ }
+
+ spin_unlock(&stc_buf_lock);
+}
+
+static void __psycho_check_stc_error(struct pci_controller_info *p,
+ unsigned long afsr,
+ unsigned long afar,
+ enum psycho_error_type type)
+{
+ struct pci_pbm_info *pbm;
+
+ pbm = &p->pbm_A;
+ if (pbm->stc.strbuf_enabled)
+ __psycho_check_one_stc(p, pbm, 1);
+
+ pbm = &p->pbm_B;
+ if (pbm->stc.strbuf_enabled)
+ __psycho_check_one_stc(p, pbm, 0);
+}
+
+/* When an Uncorrectable Error or a PCI Error happens, we
+ * interrogate the IOMMU state to see if it is the cause.
+ */
+#define PSYCHO_IOMMU_CONTROL 0x0200UL
+#define PSYCHO_IOMMU_CTRL_RESV 0xfffffffff9000000 /* Reserved */
+#define PSYCHO_IOMMU_CTRL_XLTESTAT 0x0000000006000000 /* Translation Error Status */
+#define PSYCHO_IOMMU_CTRL_XLTEERR 0x0000000001000000 /* Translation Error encountered */
+#define PSYCHO_IOMMU_CTRL_LCKEN 0x0000000000800000 /* Enable translation locking */
+#define PSYCHO_IOMMU_CTRL_LCKPTR 0x0000000000780000 /* Translation lock pointer */
+#define PSYCHO_IOMMU_CTRL_TSBSZ 0x0000000000070000 /* TSB Size */
+#define PSYCHO_IOMMU_TSBSZ_1K 0x0000000000000000 /* TSB Table 1024 8-byte entries */
+#define PSYCHO_IOMMU_TSBSZ_2K 0x0000000000010000 /* TSB Table 2048 8-byte entries */
+#define PSYCHO_IOMMU_TSBSZ_4K 0x0000000000020000 /* TSB Table 4096 8-byte entries */
+#define PSYCHO_IOMMU_TSBSZ_8K 0x0000000000030000 /* TSB Table 8192 8-byte entries */
+#define PSYCHO_IOMMU_TSBSZ_16K 0x0000000000040000 /* TSB Table 16k 8-byte entries */
+#define PSYCHO_IOMMU_TSBSZ_32K 0x0000000000050000 /* TSB Table 32k 8-byte entries */
+#define PSYCHO_IOMMU_TSBSZ_64K 0x0000000000060000 /* TSB Table 64k 8-byte entries */
+#define PSYCHO_IOMMU_TSBSZ_128K 0x0000000000070000 /* TSB Table 128k 8-byte entries */
+#define PSYCHO_IOMMU_CTRL_RESV2 0x000000000000fff8 /* Reserved */
+#define PSYCHO_IOMMU_CTRL_TBWSZ 0x0000000000000004 /* Assumed page size, 0=8k 1=64k */
+#define PSYCHO_IOMMU_CTRL_DENAB 0x0000000000000002 /* Diagnostic mode enable */
+#define PSYCHO_IOMMU_CTRL_ENAB 0x0000000000000001 /* IOMMU Enable */
+#define PSYCHO_IOMMU_TSBBASE 0x0208UL
+#define PSYCHO_IOMMU_FLUSH 0x0210UL
+#define PSYCHO_IOMMU_TAG 0xa580UL
+#define PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
+#define PSYCHO_IOMMU_TAG_ERR (0x1UL << 22UL)
+#define PSYCHO_IOMMU_TAG_WRITE (0x1UL << 21UL)
+#define PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
+#define PSYCHO_IOMMU_TAG_SIZE (0x1UL << 19UL)
+#define PSYCHO_IOMMU_TAG_VPAGE 0x7ffffUL
+#define PSYCHO_IOMMU_DATA 0xa600UL
+#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
+#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
+#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
+static void psycho_check_iommu_error(struct pci_controller_info *p,
+ unsigned long afsr,
+ unsigned long afar,
+ enum psycho_error_type type)
+{
+ unsigned long iommu_tag[16];
+ unsigned long iommu_data[16];
+ unsigned long flags;
+ u64 control;
+ int i;
+
+ spin_lock_irqsave(&p->iommu.lock, flags);
+ control = psycho_read(p->iommu.iommu_control);
+ if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
+ char *type_string;
+
+ /* Clear the error encountered bit. */
+ control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
+ psycho_write(p->iommu.iommu_control, control);
+
+ switch((control & PSYCHO_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("PSYCHO%d: IOMMU Error, type[%s]\n",
+ p->index, 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.
+ */
+ psycho_write(p->iommu.iommu_control,
+ control | PSYCHO_IOMMU_CTRL_DENAB);
+ for (i = 0; i < 16; i++) {
+ unsigned long base = p->controller_regs;
+
+ iommu_tag[i] =
+ psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
+ iommu_data[i] =
+ psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL));
+
+ /* Now clear out the entry. */
+ psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
+ psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
+ }
+
+ /* Leave diagnostic mode. */
+ psycho_write(p->iommu.iommu_control, control);
+
+ for (i = 0; i < 16; i++) {
+ unsigned long tag, data;
+
+ tag = iommu_tag[i];
+ if (!(tag & PSYCHO_IOMMU_TAG_ERR))
+ continue;
+
+ data = iommu_data[i];
+ switch((tag & PSYCHO_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("PSYCHO%d: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
+ p->index, i, type_string,
+ ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
+ ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
+ ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
+ (tag & PSYCHO_IOMMU_TAG_VPAGE) << PAGE_SHIFT);
+ printk("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
+ p->index, i,
+ ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
+ ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
+ (data & PSYCHO_IOMMU_DATA_PPAGE) << PAGE_SHIFT);
+ }
+ }
+ __psycho_check_stc_error(p, afsr, afar, type);
+ spin_unlock_irqrestore(&p->iommu.lock, flags);
+}
+
+/* Uncorrectable Errors. Cause of the error and the address are
+ * recorded in the UE_AFSR and UE_AFAR of PSYCHO. They are errors
+ * relating to UPA interface transactions.
+ */
+#define PSYCHO_UE_AFSR 0x0030UL
+#define PSYCHO_UEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */
+#define PSYCHO_UEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */
+#define PSYCHO_UEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */
+#define PSYCHO_UEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */
+#define PSYCHO_UEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_UEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_UEAFSR_RESV1 0x03ff000000000000 /* Reserved */
+#define PSYCHO_UEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */
+#define PSYCHO_UEAFSR_DOFF 0x00000000e0000000 /* Doubleword Offset */
+#define PSYCHO_UEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */
+#define PSYCHO_UEAFSR_BLK 0x0000000000800000 /* Trans was block operation */
+#define PSYCHO_UEAFSR_RESV2 0x00000000007fffff /* Reserved */
+#define PSYCHO_UE_AFAR 0x0038UL
+
+static void psycho_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 + PSYCHO_UE_AFSR;
+ unsigned long afar_reg = p->controller_regs + PSYCHO_UE_AFAR;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ /* Latch uncorrectable error status. */
+ afar = psycho_read(afar_reg);
+ afsr = psycho_read(afsr_reg);
+
+ /* Clear the primary/secondary error status bits. */
+ error_bits = afsr &
+ (PSYCHO_UEAFSR_PPIO | PSYCHO_UEAFSR_PDRD | PSYCHO_UEAFSR_PDWR |
+ PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR);
+ psycho_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("PSYCHO%d: Uncorrectable Error, primary error type[%s]\n",
+ p->index,
+ (((error_bits & PSYCHO_UEAFSR_PPIO) ?
+ "PIO" :
+ ((error_bits & PSYCHO_UEAFSR_PDRD) ?
+ "DMA Read" :
+ ((error_bits & PSYCHO_UEAFSR_PDWR) ?
+ "DMA Write" : "???")))));
+ printk("PSYCHO%d: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
+ p->index,
+ (afsr & PSYCHO_UEAFSR_BMSK) >> 32UL,
+ (afsr & PSYCHO_UEAFSR_DOFF) >> 29UL,
+ (afsr & PSYCHO_UEAFSR_MID) >> 24UL,
+ ((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0));
+ printk("PSYCHO%d: UE AFAR [%016lx]\n", p->index, afar);
+ printk("PSYCHO%d: UE Secondary errors [", p->index);
+ reported = 0;
+ if (afsr & PSYCHO_UEAFSR_SPIO) {
+ reported++;
+ printk("(PIO)");
+ }
+ if (afsr & PSYCHO_UEAFSR_SDRD) {
+ reported++;
+ printk("(DMA Read)");
+ }
+ if (afsr & PSYCHO_UEAFSR_SDWR) {
+ reported++;
+ printk("(DMA Write)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ /* Interrogate IOMMU for error status. */
+ psycho_check_iommu_error(p, afsr, afar, UE_ERR);
+}
+
+/* Correctable Errors. */
+#define PSYCHO_CE_AFSR 0x0040UL
+#define PSYCHO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */
+#define PSYCHO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */
+#define PSYCHO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */
+#define PSYCHO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */
+#define PSYCHO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */
+#define PSYCHO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */
+#define PSYCHO_CEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */
+#define PSYCHO_CEAFSR_DOFF 0x00000000e0000000 /* Double Offset */
+#define PSYCHO_CEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */
+#define PSYCHO_CEAFSR_BLK 0x0000000000800000 /* Trans was block operation */
+#define PSYCHO_CEAFSR_RESV2 0x00000000007fffff /* Reserved */
+#define PSYCHO_CE_AFAR 0x0040UL
+
+static void psycho_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 + PSYCHO_CE_AFSR;
+ unsigned long afar_reg = p->controller_regs + PSYCHO_CE_AFAR;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ /* Latch error status. */
+ afar = psycho_read(afar_reg);
+ afsr = psycho_read(afsr_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (PSYCHO_CEAFSR_PPIO | PSYCHO_CEAFSR_PDRD | PSYCHO_CEAFSR_PDWR |
+ PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);
+ psycho_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("PSYCHO%d: Correctable Error, primary error type[%s]\n",
+ p->index,
+ (((error_bits & PSYCHO_CEAFSR_PPIO) ?
+ "PIO" :
+ ((error_bits & PSYCHO_CEAFSR_PDRD) ?
+ "DMA Read" :
+ ((error_bits & PSYCHO_CEAFSR_PDWR) ?
+ "DMA Write" : "???")))));
+ printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+ "UPA_MID[%02lx] was_block(%d)\n",
+ p->index,
+ (afsr & PSYCHO_CEAFSR_ESYND) >> 48UL,
+ (afsr & PSYCHO_CEAFSR_BMSK) >> 32UL,
+ (afsr & PSYCHO_CEAFSR_DOFF) >> 29UL,
+ (afsr & PSYCHO_CEAFSR_MID) >> 24UL,
+ ((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0));
+ printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar);
+ printk("PSYCHO%d: CE Secondary errors [", p->index);
+ reported = 0;
+ if (afsr & PSYCHO_CEAFSR_SPIO) {
+ reported++;
+ printk("(PIO)");
+ }
+ if (afsr & PSYCHO_CEAFSR_SDRD) {
+ reported++;
+ printk("(DMA Read)");
+ }
+ if (afsr & PSYCHO_CEAFSR_SDWR) {
+ reported++;
+ printk("(DMA Write)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+}
+
+/* PCI Errors. They are signalled by the PCI bus module since they
+ * are assosciated with a specific bus segment.
+ */
+#define PSYCHO_PCI_AFSR_A 0x2010UL
+#define PSYCHO_PCI_AFSR_B 0x4010UL
+#define PSYCHO_PCIAFSR_PMA 0x8000000000000000 /* Primary Master Abort Error */
+#define PSYCHO_PCIAFSR_PTA 0x4000000000000000 /* Primary Target Abort Error */
+#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000 /* Primary Excessive Retries */
+#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000 /* Primary Parity Error */
+#define PSYCHO_PCIAFSR_SMA 0x0800000000000000 /* Secondary Master Abort Error */
+#define PSYCHO_PCIAFSR_STA 0x0400000000000000 /* Secondary Target Abort Error */
+#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000 /* Secondary Excessive Retries */
+#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000 /* Secondary Parity Error */
+#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000 /* Reserved */
+#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */
+#define PSYCHO_PCIAFSR_BLK 0x0000000080000000 /* Trans was block operation */
+#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000 /* Reserved */
+#define PSYCHO_PCIAFSR_MID 0x000000003e000000 /* MID causing the error */
+#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffff /* Reserved */
+#define PSYCHO_PCI_AFAR_A 0x2018UL
+#define PSYCHO_PCI_AFAR_B 0x4018UL
+
+static void psycho_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;
+ unsigned long afsr, afar, error_bits;
+ int is_pbm_a, reported;
+
+ is_pbm_a = (pbm == &pbm->parent->pbm_A);
+ if (is_pbm_a) {
+ afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_A;
+ afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_A;
+ } else {
+ afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_B;
+ afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_B;
+ }
+
+ /* Latch error status. */
+ afar = psycho_read(afar_reg);
+ afsr = psycho_read(afsr_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
+ PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
+ PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
+ PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
+ psycho_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n",
+ p->index, (is_pbm_a ? 'A' : 'B'),
+ (((error_bits & PSYCHO_PCIAFSR_PMA) ?
+ "Master Abort" :
+ ((error_bits & PSYCHO_PCIAFSR_PTA) ?
+ "Target Abort" :
+ ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
+ "Excessive Retries" :
+ ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
+ "Parity Error" : "???"))))));
+ printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
+ p->index, (is_pbm_a ? 'A' : 'B'),
+ (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
+ (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
+ (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
+ printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n",
+ p->index, (is_pbm_a ? 'A' : 'B'), afar);
+ printk("PSYCHO%d(PBM%c): PCI Secondary errors [",
+ p->index, (is_pbm_a ? 'A' : 'B'));
+ reported = 0;
+ if (afsr & PSYCHO_PCIAFSR_SMA) {
+ reported++;
+ printk("(Master Abort)");
+ }
+ if (afsr & PSYCHO_PCIAFSR_STA) {
+ reported++;
+ printk("(Target Abort)");
+ }
+ if (afsr & PSYCHO_PCIAFSR_SRTRY) {
+ reported++;
+ printk("(Excessive Retries)");
+ }
+ if (afsr & PSYCHO_PCIAFSR_SPERR) {
+ reported++;
+ printk("(Parity Error)");
+ }
+ 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 & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
+ psycho_check_iommu_error(p, afsr, afar, PCI_ERR);
+ pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+ }
+ if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_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 & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
+ pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+}
+
+/* XXX What about PowerFail/PowerManagement??? -DaveM */
+#define PSYCHO_ECC_CTRL 0x0020
+#define PSYCHO_ECCCTRL_EE 0x8000000000000000 /* Enable ECC Checking */
+#define PSYCHO_ECCCTRL_UE 0x4000000000000000 /* Enable UE Interrupts */
+#define PSYCHO_ECCCTRL_CE 0x2000000000000000 /* Enable CE INterrupts */
+#define PSYCHO_UE_INO 0x2e
+#define PSYCHO_CE_INO 0x2f
+#define PSYCHO_PCIERR_A_INO 0x30
+#define PSYCHO_PCIERR_B_INO 0x31
+static void __init psycho_register_error_handlers(struct pci_controller_info *p)
+{
+ 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);
+ if (request_irq(irq, psycho_ue_intr,
+ SA_SHIRQ, "PSYCHO UE", p) < 0) {
+ prom_printf("PSYCHO%d: Cannot register UE interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+
+ irq = psycho_irq_build(p, 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",
+ p->index);
+ prom_halt();
+ }
+
+ irq = psycho_irq_build(p, 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",
+ p->index);
+ prom_halt();
+ }
+
+ irq = psycho_irq_build(p, 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",
+ p->index);
+ prom_halt();
+ }
+
+ /* Enable UE and CE interrupts for controller. */
+ psycho_write(base + PSYCHO_ECC_CTRL,
+ (PSYCHO_ECCCTRL_EE |
+ PSYCHO_ECCCTRL_UE |
+ PSYCHO_ECCCTRL_CE));
+
+ /* Enable PCI Error interrupts and clear error
+ * bits for each PBM.
+ */
+ tmp = psycho_read(base + PSYCHO_PCIA_CTRL);
+ tmp |= (PSYCHO_PCICTRL_SBH_ERR |
+ PSYCHO_PCICTRL_SERR |
+ PSYCHO_PCICTRL_SBH_INT |
+ PSYCHO_PCICTRL_EEN);
+ psycho_write(base + PSYCHO_PCIA_CTRL, tmp);
+
+ tmp = psycho_read(base + PSYCHO_PCIB_CTRL);
+ tmp |= (PSYCHO_PCICTRL_SBH_ERR |
+ PSYCHO_PCICTRL_SERR |
+ PSYCHO_PCICTRL_SBH_INT |
+ PSYCHO_PCICTRL_EEN);
+ psycho_write(base + PSYCHO_PCIB_CTRL, tmp);
+}
+
+/* PSYCHO boot time probing and initialization. */
+static void __init psycho_resource_adjust(struct pci_dev *pdev,
+ struct resource *res,
+ struct resource *root)
+{
+ res->start += root->start;
+ res->end += root->start;
+}
+
+static void __init psycho_base_address_update(struct pci_dev *pdev, int resource)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_pbm_info *pbm = pcp->pbm;
+ struct resource *res = &pdev->resource[resource];
+ struct resource *root;
+ u32 reg;
+ int where, size;
+
+ if (res->flags & IORESOURCE_IO)
+ root = &pbm->io_space;
+ else
+ root = &pbm->mem_space;
+
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ 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);
+}
+
+/* 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 = psycho_pci_config_mkaddr(pbm, orig_busno,
+ 0, PBM_BRIDGE_BUS);
+ pci_config_write8(addr, busno);
+ addr = psycho_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 = psycho_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 = psycho_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 = psycho_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 = psycho_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 = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PBM_BRIDGE_BUS);
+ pci_config_write8(addr, 0xff);
+ addr = psycho_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_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);
+}
+
+static void __init psycho_scan_bus(struct pci_controller_info *p)
+{
+ pbm_bridge_reconfigure(p);
+ 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.
+ */
+ psycho_register_error_handlers(p);
+}
+
+static void __init psycho_iommu_init(struct pci_controller_info *p, int tsbsize)
+{
+ extern int this_is_starfire;
+ extern void *starfire_hookup(int);
+ struct linux_mlist_p1275 *mlist;
+ unsigned long tsbbase, i, n, order;
+ iopte_t *iopte;
+ u64 control;
+
+ /* Setup initial software IOMMU state. */
+ spin_lock_init(&p->iommu.lock);
+ p->iommu.iommu_cur_ctx = 0;
+
+ /* PSYCHO's IOMMU lacks ctx flushing. */
+ p->iommu.iommu_has_ctx_flush = 0;
+
+ /* Register addresses. */
+ p->iommu.iommu_control = p->controller_regs + PSYCHO_IOMMU_CONTROL;
+ p->iommu.iommu_tsbbase = p->controller_regs + PSYCHO_IOMMU_TSBBASE;
+ p->iommu.iommu_flush = p->controller_regs + PSYCHO_IOMMU_FLUSH;
+ p->iommu.iommu_ctxflush = 0;
+
+ /* We use the main control register of PSYCHO as the write
+ * completion register.
+ */
+ p->iommu.write_complete_reg = p->controller_regs + PSYCHO_CONTROL;
+
+ /*
+ * Invalidate TLB Entries.
+ */
+ control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);
+ control |= PSYCHO_IOMMU_CTRL_DENAB;
+ psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
+ for(i = 0; i < 16; i++)
+ psycho_write(p->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
+
+ control &= ~(PSYCHO_IOMMU_CTRL_DENAB);
+ psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
+
+ for(order = 0;; order++)
+ if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
+ break;
+
+ tsbbase = __get_free_pages(GFP_DMA, order);
+ if (!tsbbase) {
+ prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n");
+ prom_halt();
+ }
+ p->iommu.page_table = iopte = (iopte_t *)tsbbase;
+ p->iommu.page_table_sz = (tsbsize * 1024);
+
+ /* Initialize to "none" settings. */
+ for(i = 0; i < PCI_DVMA_HASHSZ; i++) {
+ pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE;
+ pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE;
+ }
+
+ n = 0;
+ mlist = *prom_meminfo()->p1275_totphys;
+ while (mlist) {
+ unsigned long paddr = mlist->start_adr;
+ unsigned long num_bytes = mlist->num_bytes;
+
+ if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET))
+ goto next;
+
+ if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET))
+ num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr;
+
+ /* Align base and length so we map whole hash table sized chunks
+ * at a time (and therefore full 64K IOMMU pages).
+ */
+ paddr &= ~((1UL << 24UL) - 1);
+ num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1);
+
+ /* Move up the base for mappings already created. */
+ while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] !=
+ PCI_DVMA_HASH_NONE) {
+ paddr += (1UL << 24UL);
+ num_bytes -= (1UL << 24UL);
+ if(num_bytes == 0UL)
+ goto next;
+ }
+
+ /* Move down the size for tail mappings already created. */
+ while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] !=
+ PCI_DVMA_HASH_NONE) {
+ num_bytes -= (1UL << 24UL);
+ if(num_bytes == 0UL)
+ goto next;
+ }
+
+ /* Now map the rest. */
+ for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) {
+ iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K |
+ IOPTE_CACHE | IOPTE_WRITE) |
+ (paddr & IOPTE_PAGE));
+
+ if (!(n & 0xff))
+ set_dvma_hash(0x80000000, paddr, (n << 16));
+
+ if (++n > (tsbsize * 1024))
+ goto out;
+
+ paddr += (1 << 16);
+ iopte++;
+ }
+ next:
+ mlist = mlist->theres_more;
+ }
+out:
+ if (mlist) {
+ prom_printf("WARNING: not all physical memory mapped in IOMMU\n");
+ prom_printf("Try booting with mem=xxxM or similar\n");
+ prom_halt();
+ }
+
+ psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase));
+
+ control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);
+ control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ);
+ control |= (PSYCHO_IOMMU_CTRL_TBWSZ | PSYCHO_IOMMU_CTRL_ENAB);
+ switch(tsbsize) {
+ case 8:
+ p->iommu.page_table_map_base = 0xe0000000;
+ control |= PSYCHO_IOMMU_TSBSZ_8K;
+ break;
+ case 16:
+ p->iommu.page_table_map_base = 0xc0000000;
+ control |= PSYCHO_IOMMU_TSBSZ_16K;
+ break;
+ case 32:
+ p->iommu.page_table_map_base = 0x80000000;
+ control |= PSYCHO_IOMMU_TSBSZ_32K;
+ break;
+ default:
+ prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
+ prom_halt();
+ break;
+ }
+ psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
+
+ /* If necessary, hook us up for starfire IRQ translations. */
+ if(this_is_starfire)
+ p->starfire_cookie = starfire_hookup(p->portid);
+ else
+ p->starfire_cookie = NULL;
+}
+
+#define PSYCHO_IRQ_RETRY 0x1a00UL
+#define PSYCHO_PCIA_DIAG 0x2020UL
+#define PSYCHO_PCIB_DIAG 0x4020UL
+#define PSYCHO_PCIDIAG_RESV 0xffffffffffffff80 /* Reserved */
+#define PSYCHO_PCIDIAG_DRETRY 0x0000000000000040 /* Disable retry limit */
+#define PSYCHO_PCIDIAG_DISYNC 0x0000000000000020 /* Disable DMA wr / irq sync */
+#define PSYCHO_PCIDIAG_DDWSYNC 0x0000000000000010 /* Disable DMA wr / PIO rd sync */
+#define PSYCHO_PCIDIAG_IDDPAR 0x0000000000000008 /* Invert DMA data parity */
+#define PSYCHO_PCIDIAG_IPDPAR 0x0000000000000004 /* Invert PIO data parity */
+#define PSYCHO_PCIDIAG_IPAPAR 0x0000000000000002 /* Invert PIO address parity */
+#define PSYCHO_PCIDIAG_LPBACK 0x0000000000000001 /* Enable loopback mode */
+
+static void psycho_controller_hwinit(struct pci_controller_info *p)
+{
+ u64 tmp;
+
+ /* PROM sets the IRQ retry value too low, increase it. */
+ psycho_write(p->controller_regs + PSYCHO_IRQ_RETRY, 0xff);
+
+ /* Enable arbiter for all PCI slots. */
+ tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_CTRL);
+ tmp |= PSYCHO_PCICTRL_AEN;
+ psycho_write(p->controller_regs + PSYCHO_PCIA_CTRL, tmp);
+
+ tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_CTRL);
+ tmp |= PSYCHO_PCICTRL_AEN;
+ psycho_write(p->controller_regs + PSYCHO_PCIB_CTRL, tmp);
+
+ /* Disable DMA write / PIO read synchronization on
+ * both PCI bus segments.
+ * [ U2P Erratum 1243770, STP2223BGA data sheet ]
+ */
+ tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_DIAG);
+ tmp |= PSYCHO_PCIDIAG_DDWSYNC;
+ psycho_write(p->controller_regs + PSYCHO_PCIA_DIAG, tmp);
+
+ tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_DIAG);
+ tmp |= PSYCHO_PCIDIAG_DDWSYNC;
+ psycho_write(p->controller_regs + PSYCHO_PCIB_DIAG, tmp);
+}
+
+static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm)
+{
+ char *name = pbm->name;
+
+ sprintf(name, "PSYCHO%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);
+}
+
+static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm,
+ int is_pbm_a)
+{
+ unsigned long base = p->controller_regs;
+
+ /* Currently we don't even use it. */
+ pbm->stc.strbuf_enabled = 0;
+
+ /* PSYCHO's streaming buffer lacks ctx flushing. */
+ pbm->stc.strbuf_has_ctx_flush = 0;
+
+ if (is_pbm_a) {
+ pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A;
+ pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A;
+ pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A;
+ } else {
+ pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B;
+ pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B;
+ pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B;
+ }
+ pbm->stc.strbuf_ctxflush = 0;
+ pbm->stc.strbuf_ctxmatch_base = 0;
+
+ 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);
+
+#if 0
+ /* And when we do enable it, these are the sorts of things
+ * we'll do.
+ */
+ control = psycho_read(pbm->stc.strbuf_control);
+ control |= PSYCHO_SBUFCTRL_SB_EN;
+ psycho_write(pbm->stc.strbuf_control, control);
+#endif
+}
+
+#define PSYCHO_IOSPACE_A 0x002000000UL
+#define PSYCHO_IOSPACE_B 0x002010000UL
+#define PSYCHO_IOSPACE_SIZE 0x00000ffffUL
+#define PSYCHO_MEMSPACE_A 0x100000000UL
+#define PSYCHO_MEMSPACE_B 0x180000000UL
+#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
+
+static void psycho_pbm_init(struct pci_controller_info *p,
+ int prom_node, int is_pbm_a)
+{
+ unsigned int busrange[2];
+ struct pci_pbm_info *pbm;
+ int err;
+
+ if (is_pbm_a) {
+ pbm = &p->pbm_A;
+ pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_A;
+ pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A;
+ } else {
+ pbm = &p->pbm_B;
+ pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B;
+ pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B;
+ }
+ pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;
+ pbm->io_space.flags = IORESOURCE_IO;
+ pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE;
+ pbm->mem_space.flags = IORESOURCE_MEM;
+ 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("PSYCHO-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("PSYCHO-PBM: Fatal error, no bus-range.\n");
+ prom_halt();
+ }
+ pbm->pci_first_busno = busrange[0];
+ pbm->pci_last_busno = busrange[1];
+
+ psycho_pbm_strbuf_init(p, pbm, is_pbm_a);
+}
+
+#define PSYCHO_CONFIGSPACE 0x001000000UL
+
+void __init psycho_init(int node)
+{
+ struct linux_prom64_registers pr_regs[3];
+ struct pci_controller_info *p;
+ unsigned long flags;
+ u32 upa_portid;
+ int is_pbm_a, err;
+
+ upa_portid = prom_getintdefault(node, "upa-portid", 0xff);
+
+ spin_lock_irqsave(&pci_controller_lock, flags);
+ for(p = pci_controller_root; p; p = p->next) {
+ if (p->portid == upa_portid) {
+ spin_unlock_irqrestore(&pci_controller_lock, flags);
+ is_pbm_a = (p->pbm_A.prom_node == 0);
+ psycho_pbm_init(p, node, is_pbm_a);
+ return;
+ }
+ }
+ spin_unlock_irqrestore(&pci_controller_lock, flags);
+
+ p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+ if (!p) {
+ prom_printf("PSYCHO: Fatal memory allocation error.\n");
+ prom_halt();
+ }
+ memset(p, 0, sizeof(*p));
+
+ spin_lock_irqsave(&pci_controller_lock, flags);
+ p->next = pci_controller_root;
+ pci_controller_root = p;
+ spin_unlock_irqrestore(&pci_controller_lock, flags);
+
+ p->portid = upa_portid;
+ p->index = pci_num_controllers++;
+ p->scan_bus = psycho_scan_bus;
+ p->irq_build = psycho_irq_build;
+ p->base_address_update = psycho_base_address_update;
+ p->resource_adjust = psycho_resource_adjust;
+ p->pci_ops = &psycho_ops;
+
+ err = prom_getproperty(node, "reg",
+ (char *)&pr_regs[0],
+ sizeof(pr_regs));
+ if (err == 0 || err == -1) {
+ prom_printf("PSYCHO: Fatal error, no reg property.\n");
+ prom_halt();
+ }
+
+ p->controller_regs = pr_regs[2].phys_addr;
+ 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);
+
+ /*
+ * Psycho's PCI MEM space is mapped to a 2GB aligned area, so
+ * we need to adjust our MEM space mask.
+ */
+ pci_memspace_mask = 0x7fffffffUL;
+
+ psycho_controller_hwinit(p);
+
+ psycho_iommu_init(p, 32);
+
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+ psycho_pbm_init(p, node, is_pbm_a);
+}
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
new file mode 100644
index 000000000..46a9b31cf
--- /dev/null
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -0,0 +1,1487 @@
+/* $Id: pci_sabre.c,v 1.2 1999/09/05 04:58:06 davem Exp $
+ * pci_sabre.c: Sabre specific PCI controller support.
+ *
+ * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+
+#include <asm/apb.h>
+#include <asm/pbm.h>
+#include <asm/iommu.h>
+#include <asm/irq.h>
+
+#include "pci_impl.h"
+
+/* All SABRE registers are 64-bits. The following accessor
+ * routines are how they are accessed. The REG parameter
+ * is a physical address.
+ */
+#define sabre_read(__reg) \
+({ u64 __ret; \
+ __asm__ __volatile__("ldxa [%1] %2, %0" \
+ : "=r" (__ret) \
+ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory"); \
+ __ret; \
+})
+#define sabre_write(__reg, __val) \
+ __asm__ __volatile__("stxa %0, [%1] %2" \
+ : /* no outputs */ \
+ : "r" (__val), "r" (__reg), \
+ "i" (ASI_PHYS_BYPASS_EC_E))
+
+/* SABRE PCI controller register offsets and definitions. */
+#define SABRE_UE_AFSR 0x0030UL
+#define SABRE_UEAFSR_PDRD 0x4000000000000000UL /* Primary PCI DMA Read */
+#define SABRE_UEAFSR_PDWR 0x2000000000000000UL /* Primary PCI DMA Write */
+#define SABRE_UEAFSR_SDRD 0x0800000000000000UL /* Secondary PCI DMA Read */
+#define SABRE_UEAFSR_SDWR 0x0400000000000000UL /* Secondary PCI DMA Write */
+#define SABRE_UEAFSR_SDTE 0x0200000000000000UL /* Secondary DMA Translation Error */
+#define SABRE_UEAFSR_PDTE 0x0100000000000000UL /* Primary DMA Translation Error */
+#define SABRE_UEAFSR_BMSK 0x0000ffff00000000UL /* Bytemask */
+#define SABRE_UEAFSR_OFF 0x00000000e0000000UL /* Offset (AFAR bits [5:3] */
+#define SABRE_UEAFSR_BLK 0x0000000000800000UL /* Was block operation */
+#define SABRE_UECE_AFAR 0x0038UL
+#define SABRE_CE_AFSR 0x0040UL
+#define SABRE_CEAFSR_PDRD 0x4000000000000000UL /* Primary PCI DMA Read */
+#define SABRE_CEAFSR_PDWR 0x2000000000000000UL /* Primary PCI DMA Write */
+#define SABRE_CEAFSR_SDRD 0x0800000000000000UL /* Secondary PCI DMA Read */
+#define SABRE_CEAFSR_SDWR 0x0400000000000000UL /* Secondary PCI DMA Write */
+#define SABRE_CEAFSR_ESYND 0x00ff000000000000UL /* ECC Syndrome */
+#define SABRE_CEAFSR_BMSK 0x0000ffff00000000UL /* Bytemask */
+#define SABRE_CEAFSR_OFF 0x00000000e0000000UL /* Offset */
+#define SABRE_CEAFSR_BLK 0x0000000000800000UL /* Was block operation */
+#define SABRE_UECE_AFAR_ALIAS 0x0048UL /* Aliases to 0x0038 */
+#define SABRE_IOMMU_CONTROL 0x0200UL
+#define SABRE_IOMMUCTRL_ERRSTS 0x0000000006000000UL /* Error status bits */
+#define SABRE_IOMMUCTRL_ERR 0x0000000001000000UL /* Error present in IOTLB */
+#define SABRE_IOMMUCTRL_LCKEN 0x0000000000800000UL /* IOTLB lock enable */
+#define SABRE_IOMMUCTRL_LCKPTR 0x0000000000780000UL /* IOTLB lock pointer */
+#define SABRE_IOMMUCTRL_TSBSZ 0x0000000000070000UL /* TSB Size */
+#define SABRE_IOMMUCTRL_TBWSZ 0x0000000000000004UL /* TSB assumed page size */
+#define SABRE_IOMMUCTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */
+#define SABRE_IOMMUCTRL_ENAB 0x0000000000000001UL /* IOMMU Enable */
+#define SABRE_IOMMU_TSBBASE 0x0208UL
+#define SABRE_IOMMU_FLUSH 0x0210UL
+#define SABRE_IMAP_A_SLOT0 0x0c00UL
+#define SABRE_IMAP_B_SLOT0 0x0c20UL
+#define SABRE_IMAP_SCSI 0x1000UL
+#define SABRE_IMAP_ETH 0x1008UL
+#define SABRE_IMAP_BPP 0x1010UL
+#define SABRE_IMAP_AU_REC 0x1018UL
+#define SABRE_IMAP_AU_PLAY 0x1020UL
+#define SABRE_IMAP_PFAIL 0x1028UL
+#define SABRE_IMAP_KMS 0x1030UL
+#define SABRE_IMAP_FLPY 0x1038UL
+#define SABRE_IMAP_SHW 0x1040UL
+#define SABRE_IMAP_KBD 0x1048UL
+#define SABRE_IMAP_MS 0x1050UL
+#define SABRE_IMAP_SER 0x1058UL
+#define SABRE_IMAP_UE 0x1070UL
+#define SABRE_IMAP_CE 0x1078UL
+#define SABRE_IMAP_PCIERR 0x1080UL
+#define SABRE_IMAP_GFX 0x1098UL
+#define SABRE_IMAP_EUPA 0x10a0UL
+#define SABRE_ICLR_A_SLOT0 0x1400UL
+#define SABRE_ICLR_B_SLOT0 0x1480UL
+#define SABRE_ICLR_SCSI 0x1800UL
+#define SABRE_ICLR_ETH 0x1808UL
+#define SABRE_ICLR_BPP 0x1810UL
+#define SABRE_ICLR_AU_REC 0x1818UL
+#define SABRE_ICLR_AU_PLAY 0x1820UL
+#define SABRE_ICLR_PFAIL 0x1828UL
+#define SABRE_ICLR_KMS 0x1830UL
+#define SABRE_ICLR_FLPY 0x1838UL
+#define SABRE_ICLR_SHW 0x1840UL
+#define SABRE_ICLR_KBD 0x1848UL
+#define SABRE_ICLR_MS 0x1850UL
+#define SABRE_ICLR_SER 0x1858UL
+#define SABRE_ICLR_UE 0x1870UL
+#define SABRE_ICLR_CE 0x1878UL
+#define SABRE_ICLR_PCIERR 0x1880UL
+#define SABRE_WRSYNC 0x1c20UL
+#define SABRE_PCICTRL 0x2000UL
+#define SABRE_PCICTRL_MRLEN 0x0000001000000000UL /* Use MemoryReadLine for block loads/stores */
+#define SABRE_PCICTRL_SERR 0x0000000400000000UL /* Set when SERR asserted on PCI bus */
+#define SABRE_PCICTRL_ARBPARK 0x0000000000200000UL /* Bus Parking 0=Ultra-IIi 1=prev-bus-owner */
+#define SABRE_PCICTRL_CPUPRIO 0x0000000000100000UL /* Ultra-IIi granted every other bus cycle */
+#define SABRE_PCICTRL_ARBPRIO 0x00000000000f0000UL /* Slot which is granted every other bus cycle */
+#define SABRE_PCICTRL_ERREN 0x0000000000000100UL /* PCI Error Interrupt Enable */
+#define SABRE_PCICTRL_RTRYWE 0x0000000000000080UL /* DMA Flow Control 0=wait-if-possible 1=retry */
+#define SABRE_PCICTRL_AEN 0x000000000000000fUL /* Slot PCI arbitration enables */
+#define SABRE_PIOAFSR 0x2010UL
+#define SABRE_PIOAFSR_PMA 0x8000000000000000UL /* Primary Master Abort */
+#define SABRE_PIOAFSR_PTA 0x4000000000000000UL /* Primary Target Abort */
+#define SABRE_PIOAFSR_PRTRY 0x2000000000000000UL /* Primary Excessive Retries */
+#define SABRE_PIOAFSR_PPERR 0x1000000000000000UL /* Primary Parity Error */
+#define SABRE_PIOAFSR_SMA 0x0800000000000000UL /* Secondary Master Abort */
+#define SABRE_PIOAFSR_STA 0x0400000000000000UL /* Secondary Target Abort */
+#define SABRE_PIOAFSR_SRTRY 0x0200000000000000UL /* Secondary Excessive Retries */
+#define SABRE_PIOAFSR_SPERR 0x0100000000000000UL /* Secondary Parity Error */
+#define SABRE_PIOAFSR_BMSK 0x0000ffff00000000UL /* Byte Mask */
+#define SABRE_PIOAFSR_BLK 0x0000000080000000UL /* Was Block Operation */
+#define SABRE_PIOAFAR 0x2018UL
+#define SABRE_PCIDIAG 0x2020UL
+#define SABRE_PCIDIAG_DRTRY 0x0000000000000040UL /* Disable PIO Retry Limit */
+#define SABRE_PCIDIAG_IPAPAR 0x0000000000000008UL /* Invert PIO Address Parity */
+#define SABRE_PCIDIAG_IPDPAR 0x0000000000000004UL /* Invert PIO Data Parity */
+#define SABRE_PCIDIAG_IDDPAR 0x0000000000000002UL /* Invert DMA Data Parity */
+#define SABRE_PCIDIAG_ELPBK 0x0000000000000001UL /* Loopback Enable - not supported */
+#define SABRE_PCITASR 0x2028UL
+#define SABRE_PCITASR_EF 0x0000000000000080UL /* Respond to 0xe0000000-0xffffffff */
+#define SABRE_PCITASR_CD 0x0000000000000040UL /* Respond to 0xc0000000-0xdfffffff */
+#define SABRE_PCITASR_AB 0x0000000000000020UL /* Respond to 0xa0000000-0xbfffffff */
+#define SABRE_PCITASR_89 0x0000000000000010UL /* Respond to 0x80000000-0x9fffffff */
+#define SABRE_PCITASR_67 0x0000000000000008UL /* Respond to 0x60000000-0x7fffffff */
+#define SABRE_PCITASR_45 0x0000000000000004UL /* Respond to 0x40000000-0x5fffffff */
+#define SABRE_PCITASR_23 0x0000000000000002UL /* Respond to 0x20000000-0x3fffffff */
+#define SABRE_PCITASR_01 0x0000000000000001UL /* Respond to 0x00000000-0x1fffffff */
+#define SABRE_PIOBUF_DIAG 0x5000UL
+#define SABRE_DMABUF_DIAGLO 0x5100UL
+#define SABRE_DMABUF_DIAGHI 0x51c0UL
+#define SABRE_IMAP_GFX_ALIAS 0x6000UL /* Aliases to 0x1098 */
+#define SABRE_IMAP_EUPA_ALIAS 0x8000UL /* Aliases to 0x10a0 */
+#define SABRE_IOMMU_VADIAG 0xa400UL
+#define SABRE_IOMMU_TCDIAG 0xa408UL
+#define SABRE_IOMMU_TAG 0xa580UL
+#define SABRE_IOMMUTAG_ERRSTS 0x0000000001800000UL /* Error status bits */
+#define SABRE_IOMMUTAG_ERR 0x0000000000400000UL /* Error present */
+#define SABRE_IOMMUTAG_WRITE 0x0000000000200000UL /* Page is writable */
+#define SABRE_IOMMUTAG_STREAM 0x0000000000100000UL /* Streamable bit - unused */
+#define SABRE_IOMMUTAG_SIZE 0x0000000000080000UL /* 0=8k 1=16k */
+#define SABRE_IOMMUTAG_VPN 0x000000000007ffffUL /* Virtual Page Number [31:13] */
+#define SABRE_IOMMU_DATA 0xa600UL
+#define SABRE_IOMMUDATA_VALID 0x0000000040000000UL /* Valid */
+#define SABRE_IOMMUDATA_USED 0x0000000020000000UL /* Used (for LRU algorithm) */
+#define SABRE_IOMMUDATA_CACHE 0x0000000010000000UL /* Cacheable */
+#define SABRE_IOMMUDATA_PPN 0x00000000001fffffUL /* Physical Page Number [33:13] */
+#define SABRE_PCI_IRQSTATE 0xa800UL
+#define SABRE_OBIO_IRQSTATE 0xa808UL
+#define SABRE_FFBCFG 0xf000UL
+#define SABRE_FFBCFG_SPRQS 0x000000000f000000 /* Slave P_RQST queue size */
+#define SABRE_FFBCFG_ONEREAD 0x0000000000004000 /* Slave supports one outstanding read */
+#define SABRE_MCCTRL0 0xf010UL
+#define SABRE_MCCTRL0_RENAB 0x0000000080000000 /* Refresh Enable */
+#define SABRE_MCCTRL0_EENAB 0x0000000010000000 /* Enable all ECC functions */
+#define SABRE_MCCTRL0_11BIT 0x0000000000001000 /* Enable 11-bit column addressing */
+#define SABRE_MCCTRL0_DPP 0x0000000000000f00 /* DIMM Pair Present Bits */
+#define SABRE_MCCTRL0_RINTVL 0x00000000000000ff /* Refresh Interval */
+#define SABRE_MCCTRL1 0xf018UL
+#define SABRE_MCCTRL1_AMDC 0x0000000038000000 /* Advance Memdata Clock */
+#define SABRE_MCCTRL1_ARDC 0x0000000007000000 /* Advance DRAM Read Data Clock */
+#define SABRE_MCCTRL1_CSR 0x0000000000e00000 /* CAS to RAS delay for CBR refresh */
+#define SABRE_MCCTRL1_CASRW 0x00000000001c0000 /* CAS length for read/write */
+#define SABRE_MCCTRL1_RCD 0x0000000000038000 /* RAS to CAS delay */
+#define SABRE_MCCTRL1_CP 0x0000000000007000 /* CAS Precharge */
+#define SABRE_MCCTRL1_RP 0x0000000000000e00 /* RAS Precharge */
+#define SABRE_MCCTRL1_RAS 0x00000000000001c0 /* Length of RAS for refresh */
+#define SABRE_MCCTRL1_CASRW2 0x0000000000000038 /* Must be same as CASRW */
+#define SABRE_MCCTRL1_RSC 0x0000000000000007 /* RAS after CAS hold time */
+#define SABRE_RESETCTRL 0xf020UL
+
+#define SABRE_CONFIGSPACE 0x001000000UL
+#define SABRE_IOSPACE 0x002000000UL
+#define SABRE_IOSPACE_SIZE 0x00000ffffUL
+#define SABRE_MEMSPACE 0x100000000UL
+#define SABRE_MEMSPACE_SIZE 0x07fffffffUL
+
+/* UltraSparc-IIi Programmer's Manual, page 325, PCI
+ * configuration space address format:
+ *
+ * 32 24 23 16 15 11 10 8 7 2 1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define SABRE_CONFIG_BASE(PBM) \
+ ((PBM)->parent->config_space | (1UL << 24))
+#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \
+ (((unsigned long)(BUS) << 16) | \
+ ((unsigned long)(DEVFN) << 8) | \
+ ((unsigned long)(REG)))
+
+static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm,
+ unsigned char bus,
+ unsigned int devfn,
+ int where)
+{
+ if (!pbm)
+ return NULL;
+ return (void *)
+ (SABRE_CONFIG_BASE(pbm) |
+ SABRE_CONFIG_ENCODE(bus, devfn, where));
+}
+
+static int sabre_out_of_range(unsigned char devfn)
+{
+ return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
+ ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
+ (PCI_SLOT(devfn) > 1));
+}
+
+static int __sabre_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) > 8) ||
+ ((pbm == &pbm->parent->pbm_A) &&
+ (bus == pbm->pci_first_busno) &&
+ PCI_SLOT(devfn) > 8));
+}
+
+static int __sabre_read_byte(struct pci_dev *dev, int where, u8 *value)
+{
+ 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 = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (__sabre_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+ pci_config_read8(addr, value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int __sabre_read_word(struct pci_dev *dev, int where, u16 *value)
+{
+ 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 = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (__sabre_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 __sabre_read_dword(struct pci_dev *dev, int where, u32 *value)
+{
+ 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 = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (__sabre_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 sabre_read_byte(struct pci_dev *dev, int where, u8 *value)
+{
+ if (dev->bus->number)
+ return __sabre_read_byte(dev, where, value);
+
+ if (sabre_out_of_range(dev->devfn)) {
+ *value = 0xff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ if (where < 8) {
+ u16 tmp;
+
+ __sabre_read_word(dev, where & ~1, &tmp);
+ if (where & 1)
+ *value = tmp >> 8;
+ else
+ *value = tmp & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+ } else
+ return __sabre_read_byte(dev, where, value);
+}
+
+static int sabre_read_word(struct pci_dev *dev, int where, u16 *value)
+{
+ if (dev->bus->number)
+ return __sabre_read_word(dev, where, value);
+
+ if (sabre_out_of_range(dev->devfn)) {
+ *value = 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ if (where < 8)
+ return __sabre_read_word(dev, where, value);
+ else {
+ u8 tmp;
+
+ __sabre_read_byte(dev, where, &tmp);
+ *value = tmp;
+ __sabre_read_byte(dev, where + 1, &tmp);
+ *value |= tmp << 8;
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+static int sabre_read_dword(struct pci_dev *dev, int where, u32 *value)
+{
+ u16 tmp;
+
+ if (dev->bus->number)
+ return __sabre_read_dword(dev, where, value);
+
+ if (sabre_out_of_range(dev->devfn)) {
+ *value = 0xffffffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ sabre_read_word(dev, where, &tmp);
+ *value = tmp;
+ sabre_read_word(dev, where + 2, &tmp);
+ *value |= tmp << 16;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int __sabre_write_byte(struct pci_dev *dev, int where, u8 value)
+{
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u8 *addr;
+
+ addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (__sabre_out_of_range(pbm, bus, devfn))
+ return PCIBIOS_SUCCESSFUL;
+ pci_config_write8(addr, value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int __sabre_write_word(struct pci_dev *dev, int where, u16 value)
+{
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u16 *addr;
+
+ addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (__sabre_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 __sabre_write_dword(struct pci_dev *dev, int where, u32 value)
+{
+ struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+ unsigned char bus = dev->bus->number;
+ unsigned int devfn = dev->devfn;
+ u32 *addr;
+
+ addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ if (__sabre_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 int sabre_write_byte(struct pci_dev *dev, int where, u8 value)
+{
+ if (dev->bus->number)
+ return __sabre_write_byte(dev, where, value);
+
+ if (sabre_out_of_range(dev->devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where < 8) {
+ u16 tmp;
+
+ __sabre_read_word(dev, where & ~1, &tmp);
+ if (where & 1) {
+ value &= 0x00ff;
+ value |= tmp << 8;
+ } else {
+ value &= 0xff00;
+ value |= tmp;
+ }
+ return __sabre_write_word(dev, where & ~1, tmp);
+ } else
+ return __sabre_write_byte(dev, where, value);
+}
+
+static int sabre_write_word(struct pci_dev *dev, int where, u16 value)
+{
+ if (dev->bus->number)
+ return __sabre_write_word(dev, where, value);
+
+ if (sabre_out_of_range(dev->devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (where < 8)
+ return __sabre_write_word(dev, where, value);
+ else {
+ __sabre_write_byte(dev, where, value & 0xff);
+ __sabre_write_byte(dev, where + 1, value >> 8);
+ return PCIBIOS_SUCCESSFUL;
+ }
+}
+
+static int sabre_write_dword(struct pci_dev *dev, int where, u32 value)
+{
+ if (dev->bus->number)
+ return __sabre_write_dword(dev, where, value);
+
+ if (sabre_out_of_range(dev->devfn))
+ return PCIBIOS_SUCCESSFUL;
+
+ sabre_write_word(dev, where, value & 0xffff);
+ sabre_write_word(dev, where + 2, value >> 16);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops sabre_ops = {
+ sabre_read_byte,
+ sabre_read_word,
+ sabre_read_dword,
+ sabre_write_byte,
+ sabre_write_word,
+ sabre_write_dword
+};
+
+static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
+{
+ unsigned int bus = (ino & 0x10) >> 4;
+ unsigned int slot = (ino & 0x0c) >> 2;
+
+ if (bus == 0)
+ return SABRE_IMAP_A_SLOT0 + (slot * 8);
+ else
+ return SABRE_IMAP_B_SLOT0 + (slot * 8);
+}
+
+static unsigned long __onboard_imap_off[] = {
+/*0x20*/ SABRE_IMAP_SCSI,
+/*0x21*/ SABRE_IMAP_ETH,
+/*0x22*/ SABRE_IMAP_BPP,
+/*0x23*/ SABRE_IMAP_AU_REC,
+/*0x24*/ SABRE_IMAP_AU_PLAY,
+/*0x25*/ SABRE_IMAP_PFAIL,
+/*0x26*/ SABRE_IMAP_KMS,
+/*0x27*/ SABRE_IMAP_FLPY,
+/*0x28*/ SABRE_IMAP_SHW,
+/*0x29*/ SABRE_IMAP_KBD,
+/*0x2a*/ SABRE_IMAP_MS,
+/*0x2b*/ SABRE_IMAP_SER,
+/*0x2c*/ 0 /* reserved */,
+/*0x2d*/ 0 /* reserved */,
+/*0x2e*/ SABRE_IMAP_UE,
+/*0x2f*/ SABRE_IMAP_CE,
+/*0x30*/ SABRE_IMAP_PCIERR,
+};
+#define SABRE_ONBOARD_IRQ_BASE 0x20
+#define SABRE_ONBOARD_IRQ_LAST 0x30
+#define sabre_onboard_imap_offset(__ino) \
+ __onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE]
+
+#define sabre_iclr_offset(ino) \
+ ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
+ (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
+
+/* PCI SABRE INO number to Sparc PIL level. */
+static unsigned char sabre_pil_table[] = {
+/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */
+/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */
+/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */
+/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */
+/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */
+/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */
+/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */
+/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */
+/*0x20*/3, /* SCSI */
+/*0x21*/5, /* Ethernet */
+/*0x22*/8, /* Parallel Port */
+/*0x23*/13, /* Audio Record */
+/*0x24*/14, /* Audio Playback */
+/*0x25*/15, /* PowerFail */
+/*0x26*/3, /* second SCSI */
+/*0x27*/11, /* Floppy */
+/*0x28*/2, /* Spare Hardware */
+/*0x29*/9, /* Keyboard */
+/*0x2a*/4, /* Mouse */
+/*0x2b*/12, /* Serial */
+/*0x2c*/10, /* Timer 0 */
+/*0x2d*/11, /* Timer 1 */
+/*0x2e*/15, /* Uncorrectable ECC */
+/*0x2f*/15, /* Correctable ECC */
+/*0x30*/15, /* PCI Bus A Error */
+/*0x31*/15, /* PCI Bus B Error */
+/*0x32*/1, /* Power Management */
+};
+
+static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
+{
+ int ret;
+
+ ret = sabre_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 sabre_irq_build(struct pci_controller_info *p,
+ struct pci_dev *pdev,
+ unsigned int ino)
+{
+ struct ino_bucket *bucket;
+ volatile unsigned int *imap, *iclr;
+ unsigned long imap_off, iclr_off;
+ int pil, inofixup = 0;
+
+ ino &= PCI_IRQ_INO;
+ if (ino < SABRE_ONBOARD_IRQ_BASE) {
+ /* PCI slot */
+ imap_off = sabre_pcislot_imap_offset(ino);
+ } else {
+ /* onboard device */
+ if (ino > SABRE_ONBOARD_IRQ_LAST) {
+ prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino);
+ prom_halt();
+ }
+ imap_off = sabre_onboard_imap_offset(ino);
+ }
+
+ /* Now build the IRQ bucket. */
+ pil = sabre_ino_to_pil(pdev, ino);
+ imap = (volatile unsigned int *)__va(p->controller_regs + imap_off);
+ imap += 1;
+
+ iclr_off = sabre_iclr_offset(ino);
+ iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off);
+ iclr += 1;
+
+ if ((ino & 0x20) == 0)
+ inofixup = ino & 0x03;
+
+ bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+ bucket->flags |= IBF_PCI;
+
+ /* XXX We still need to code up support for this in irq.c
+ * XXX It's easy to code up since only one SIMBA can exist
+ * XXX in a machine and this is where the sync register is. -DaveM
+ */
+ if (pdev) {
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ if (pdev->bus->number != pcp->pbm->pci_first_busno)
+ bucket->flags |= IBF_DMA_SYNC;
+ }
+ return __irq(bucket);
+}
+
+/* SABRE error handling support. */
+static void sabre_check_iommu_error(struct pci_controller_info *p,
+ unsigned long afsr,
+ unsigned long afar)
+{
+ unsigned long iommu_tag[16];
+ unsigned long iommu_data[16];
+ unsigned long flags;
+ u64 control;
+ int i;
+
+ spin_lock_irqsave(&p->iommu.lock, flags);
+ control = sabre_read(p->iommu.iommu_control);
+ if (control & SABRE_IOMMUCTRL_ERR) {
+ char *type_string;
+
+ /* Clear the error encountered bit.
+ * NOTE: On Sabre this is write 1 to clear,
+ * which is different from Psycho.
+ */
+ sabre_write(p->iommu.iommu_control, control);
+ switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) {
+ case 1:
+ type_string = "Invalid Error";
+ break;
+ case 3:
+ type_string = "ECC Error";
+ break;
+ default:
+ type_string = "Unknown";
+ break;
+ };
+ printk("SABRE%d: IOMMU Error, type[%s]\n",
+ p->index, type_string);
+
+ /* Enter diagnostic mode and probe for error'd
+ * entries in the IOTLB.
+ */
+ control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR);
+ sabre_write(p->iommu.iommu_control,
+ (control | SABRE_IOMMUCTRL_DENAB));
+ for (i = 0; i < 16; i++) {
+ unsigned long base = p->controller_regs;
+
+ iommu_tag[i] =
+ sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
+ iommu_data[i] =
+ sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL));
+ sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0);
+ sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0);
+ }
+ sabre_write(p->iommu.iommu_control, control);
+
+ for (i = 0; i < 16; i++) {
+ unsigned long tag, data;
+
+ tag = iommu_tag[i];
+ if (!(tag & SABRE_IOMMUTAG_ERR))
+ continue;
+
+ data = iommu_data[i];
+ switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) {
+ case 1:
+ type_string = "Invalid Error";
+ break;
+ case 3:
+ type_string = "ECC Error";
+ break;
+ default:
+ type_string = "Unknown";
+ break;
+ };
+ printk("SABRE%d: IOMMU TAG(%d)[error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
+ p->index, i, type_string,
+ ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
+ ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
+ ((tag & SABRE_IOMMUTAG_VPN) << PAGE_SHIFT));
+ printk("SABRE%d: IOMMU DATA(%d)[valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
+ p->index, i,
+ ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
+ ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
+ ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
+ ((data & SABRE_IOMMUDATA_PPN) << PAGE_SHIFT));
+ }
+ }
+ spin_unlock_irqrestore(&p->iommu.lock, flags);
+}
+
+static void sabre_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 + SABRE_UE_AFSR;
+ unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ /* Latch uncorrectable error status. */
+ afar = sabre_read(afar_reg);
+ afsr = sabre_read(afsr_reg);
+
+ /* Clear the primary/secondary error status bits. */
+ error_bits = afsr &
+ (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
+ SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
+ SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);
+ sabre_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n",
+ p->index,
+ ((error_bits & SABRE_UEAFSR_PDRD) ?
+ "DMA Read" :
+ ((error_bits & SABRE_UEAFSR_PDWR) ?
+ "DMA Write" : "???")),
+ ((error_bits & SABRE_UEAFSR_PDTE) ?
+ ":Translation Error" : ""));
+ printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
+ p->index,
+ (afsr & SABRE_UEAFSR_BMSK) >> 32UL,
+ (afsr & SABRE_UEAFSR_OFF) >> 29UL,
+ ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0));
+ printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar);
+ printk("SABRE%d: UE Secondary errors [", p->index);
+ reported = 0;
+ if (afsr & SABRE_UEAFSR_SDRD) {
+ reported++;
+ printk("(DMA Read)");
+ }
+ if (afsr & SABRE_UEAFSR_SDWR) {
+ reported++;
+ printk("(DMA Write)");
+ }
+ if (afsr & SABRE_UEAFSR_SDTE) {
+ reported++;
+ printk("(Translation Error)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ /* Interrogate IOMMU for error status. */
+ sabre_check_iommu_error(p, afsr, afar);
+}
+
+static void sabre_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 + SABRE_CE_AFSR;
+ unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ /* Latch error status. */
+ afar = sabre_read(afar_reg);
+ afsr = sabre_read(afsr_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
+ SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);
+ sabre_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("SABRE%d: Correctable Error, primary error type[%s]\n",
+ p->index,
+ ((error_bits & SABRE_CEAFSR_PDRD) ?
+ "DMA Read" :
+ ((error_bits & SABRE_CEAFSR_PDWR) ?
+ "DMA Write" : "???")));
+ printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+ "was_block(%d)\n",
+ p->index,
+ (afsr & SABRE_CEAFSR_ESYND) >> 48UL,
+ (afsr & SABRE_CEAFSR_BMSK) >> 32UL,
+ (afsr & SABRE_CEAFSR_OFF) >> 29UL,
+ ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0));
+ printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar);
+ printk("SABRE%d: CE Secondary errors [", p->index);
+ reported = 0;
+ if (afsr & SABRE_CEAFSR_SDRD) {
+ reported++;
+ printk("(DMA Read)");
+ }
+ if (afsr & SABRE_CEAFSR_SDWR) {
+ reported++;
+ printk("(DMA Write)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+}
+
+static void sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pci_controller_info *p = dev_id;
+ unsigned long afsr_reg, afar_reg;
+ unsigned long afsr, afar, error_bits;
+ int reported;
+
+ afsr_reg = p->controller_regs + SABRE_PIOAFSR;
+ afar_reg = p->controller_regs + SABRE_PIOAFAR;
+
+ /* Latch error status. */
+ afar = sabre_read(afar_reg);
+ afsr = sabre_read(afsr_reg);
+
+ /* Clear primary/secondary error status bits. */
+ error_bits = afsr &
+ (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA |
+ SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR |
+ SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
+ SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
+ sabre_write(afsr_reg, error_bits);
+
+ /* Log the error. */
+ printk("SABRE%d: PCI Error, primary error type[%s]\n",
+ p->index,
+ (((error_bits & SABRE_PIOAFSR_PMA) ?
+ "Master Abort" :
+ ((error_bits & SABRE_PIOAFSR_PTA) ?
+ "Target Abort" :
+ ((error_bits & SABRE_PIOAFSR_PRTRY) ?
+ "Excessive Retries" :
+ ((error_bits & SABRE_PIOAFSR_PPERR) ?
+ "Parity Error" : "???"))))));
+ printk("SABRE%d: bytemask[%04lx] was_block(%d)\n",
+ p->index,
+ (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
+ (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
+ printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar);
+ printk("SABRE%d: PCI Secondary errors [", p->index);
+ reported = 0;
+ if (afsr & SABRE_PIOAFSR_SMA) {
+ reported++;
+ printk("(Master Abort)");
+ }
+ if (afsr & SABRE_PIOAFSR_STA) {
+ reported++;
+ printk("(Target Abort)");
+ }
+ if (afsr & SABRE_PIOAFSR_SRTRY) {
+ reported++;
+ printk("(Excessive Retries)");
+ }
+ if (afsr & SABRE_PIOAFSR_SPERR) {
+ reported++;
+ printk("(Parity Error)");
+ }
+ if (!reported)
+ printk("(none)");
+ printk("]\n");
+
+ /* For the error types shown, scan both PCI buses 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 & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
+ sabre_check_iommu_error(p, afsr, afar);
+ pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
+ pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus);
+ }
+ if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) {
+ pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
+ pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus);
+ }
+ /* For excessive retries, SABRE/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 & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) {
+ pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);
+ pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus);
+ }
+}
+
+/* XXX What about PowerFail/PowerManagement??? -DaveM */
+#define SABRE_UE_INO 0x2e
+#define SABRE_CE_INO 0x2f
+#define SABRE_PCIERR_INO 0x30
+static void __init sabre_register_error_handlers(struct pci_controller_info *p)
+{
+ unsigned long base = p->controller_regs;
+ unsigned long irq, portid = p->portid;
+ u64 tmp;
+
+ /* We clear the error bits in the appropriate AFSR before
+ * registering the handler so that we don't get spurious
+ * interrupts.
+ */
+ sabre_write(base + SABRE_UE_AFSR,
+ (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);
+ if (request_irq(irq, sabre_ue_intr,
+ SA_SHIRQ, "SABRE UE", p) < 0) {
+ prom_printf("SABRE%d: Cannot register UE interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+
+ 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);
+ if (request_irq(irq, sabre_ce_intr,
+ SA_SHIRQ, "SABRE CE", p) < 0) {
+ prom_printf("SABRE%d: Cannot register CE interrupt.\n",
+ p->index);
+ prom_halt();
+ }
+
+ irq = sabre_irq_build(p, 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",
+ p->index);
+ prom_halt();
+ }
+
+ tmp = sabre_read(base + SABRE_PCICTRL);
+ tmp |= SABRE_PCICTRL_ERREN;
+ sabre_write(base + SABRE_PCICTRL, tmp);
+}
+
+static void __init sabre_resource_adjust(struct pci_dev *pdev,
+ struct resource *res,
+ struct resource *root)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_controller_info *p = pcp->pbm->parent;
+ unsigned long base;
+
+ if (res->flags & IORESOURCE_IO)
+ base = p->controller_regs + SABRE_IOSPACE;
+ else
+ base = p->controller_regs + SABRE_MEMSPACE;
+
+ res->start += base;
+ res->end += base;
+}
+
+static void __init sabre_base_address_update(struct pci_dev *pdev, int resource)
+{
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct pci_pbm_info *pbm = pcp->pbm;
+ struct pci_controller_info *p = pbm->parent;
+ struct resource *res = &pdev->resource[resource];
+ unsigned long base;
+ u32 reg;
+ int where, size;
+
+ if (res->flags & IORESOURCE_IO)
+ base = p->controller_regs + SABRE_IOSPACE;
+ else
+ base = p->controller_regs + SABRE_MEMSPACE;
+
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ size = res->end - res->start;
+ pci_read_config_dword(pdev, where, &reg);
+ reg = ((reg & size) |
+ (((u32)(res->start - base)) & ~size));
+ pci_write_config_dword(pdev, where, reg);
+}
+
+static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
+{
+ struct pci_dev *pdev;
+ u32 dword;
+ u16 word;
+
+ for(pdev = pci_devices; pdev; pdev = pdev->next) {
+ if(pdev->vendor == PCI_VENDOR_ID_SUN &&
+ pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
+ sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64);
+ break;
+ }
+ }
+
+ for (pdev = sabre_bus->devices; pdev; pdev = pdev->sibling) {
+ if (pdev->vendor == PCI_VENDOR_ID_SUN &&
+ pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
+ sabre_read_word(pdev, PCI_COMMAND, &word);
+ word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_IO;
+ sabre_write_word(pdev, PCI_COMMAND, word);
+
+ /* Status register bits are "write 1 to clear". */
+ sabre_write_word(pdev, PCI_STATUS, 0xffff);
+ sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff);
+
+ sabre_read_word(pdev, PCI_BRIDGE_CONTROL, &word);
+ word = PCI_BRIDGE_CTL_MASTER_ABORT |
+ PCI_BRIDGE_CTL_SERR |
+ PCI_BRIDGE_CTL_PARITY;
+ sabre_write_word(pdev, PCI_BRIDGE_CONTROL, word);
+
+ sabre_read_dword(pdev, APB_PCI_CONTROL_HIGH, &dword);
+ dword = APB_PCI_CTL_HIGH_SERR |
+ APB_PCI_CTL_HIGH_ARBITER_EN;
+ sabre_write_dword(pdev, APB_PCI_CONTROL_HIGH, dword);
+
+ /* Systems with SIMBA are usually workstations, so
+ * we configure to park to SIMBA not to the previous
+ * bus owner.
+ */
+ sabre_read_dword(pdev, APB_PCI_CONTROL_LOW, &dword);
+ dword = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
+ sabre_write_dword(pdev, APB_PCI_CONTROL_LOW, dword);
+
+ /* Don't mess with the retry limit and PIO/DMA latency
+ * timer settings. But do set primary and secondary
+ * latency timers.
+ */
+ sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64);
+ sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
+ }
+ }
+}
+
+static void __init sabre_scan_bus(struct pci_controller_info *p)
+{
+ static int once = 0;
+ struct pci_bus *sabre_bus, *pbus;
+
+ /* Unlike for PSYCHO, we can only have one SABRE
+ * in a system. Having multiple SABREs is thus
+ * and error, and as a consequence we do not need
+ * to do any bus renumbering but we do have to have
+ * the pci_bus2pbm array setup properly.
+ *
+ * Also note that the SABRE host bridge is hardwired
+ * to live at bus 0.
+ */
+ if (once != 0) {
+ prom_printf("SABRE: Multiple controllers unsupported.\n");
+ prom_halt();
+ }
+ once++;
+
+ /* The pci_bus2pbm table has already been setup in sabre_init. */
+ sabre_bus = pci_scan_bus(p->pci_first_busno,
+ p->pci_ops,
+ &p->pbm_A);
+ apb_init(p, sabre_bus);
+
+ for (pbus = sabre_bus->children; pbus; pbus = pbus->next) {
+ struct pci_pbm_info *pbm;
+
+ if (pbus->number == p->pbm_A.pci_first_busno) {
+ pbm = &p->pbm_A;
+ } else if (pbus->number == p->pbm_B.pci_first_busno) {
+ pbm = &p->pbm_B;
+ } else
+ continue;
+
+ pbus->sysdata = pbm;
+ pbm->pci_bus = pbus;
+ pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node);
+ pci_record_assignments(pbm, pbus);
+ pci_assign_unassigned(pbm, pbus);
+ pci_fixup_irq(pbm, pbus);
+ }
+
+ sabre_register_error_handlers(p);
+}
+
+static void __init sabre_iommu_init(struct pci_controller_info *p,
+ int tsbsize, unsigned long dvma_offset)
+{
+ struct linux_mlist_p1275 *mlist;
+ unsigned long tsbbase, i, n, order;
+ iopte_t *iopte;
+ u64 control;
+
+ /* Invalidate TLB Entries. */
+ control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);
+ control |= IOMMU_CTRL_DENAB;
+ sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
+
+ for(i = 0; i < 16; i++)
+ sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
+
+ control &= ~(IOMMU_CTRL_DENAB);
+ sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
+
+ for(order = 0;; order++)
+ if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
+ break;
+ tsbbase = __get_free_pages(GFP_DMA, order);
+ if (!tsbbase) {
+ prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n");
+ prom_halt();
+ }
+ iopte = (iopte_t *)tsbbase;
+
+ /* Initialize to "none" settings. */
+ for(i = 0; i < PCI_DVMA_HASHSZ; i++) {
+ pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE;
+ pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE;
+ }
+
+ n = 0;
+ mlist = *prom_meminfo()->p1275_totphys;
+ while (mlist) {
+ unsigned long paddr = mlist->start_adr;
+ unsigned long num_bytes = mlist->num_bytes;
+
+ if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET))
+ goto next;
+
+ if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET))
+ num_bytes =
+ (((unsigned long) high_memory) -
+ PAGE_OFFSET) - paddr;
+
+ /* Align base and length so we map whole hash table sized chunks
+ * at a time (and therefore full 64K IOMMU pages).
+ */
+ paddr &= ~((1UL << 24UL) - 1);
+ num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1);
+
+ /* Move up the base for mappings already created. */
+ while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] !=
+ PCI_DVMA_HASH_NONE) {
+ paddr += (1UL << 24UL);
+ num_bytes -= (1UL << 24UL);
+ if(num_bytes == 0UL)
+ goto next;
+ }
+
+ /* Move down the size for tail mappings already created. */
+ while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] !=
+ PCI_DVMA_HASH_NONE) {
+ num_bytes -= (1UL << 24UL);
+ if(num_bytes == 0UL)
+ goto next;
+ }
+
+ /* Now map the rest. */
+ for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) {
+ iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K |
+ IOPTE_CACHE | IOPTE_WRITE) |
+ (paddr & IOPTE_PAGE));
+
+ if (!(n & 0xff))
+ set_dvma_hash(dvma_offset, paddr, (n << 16));
+ if (++n > (tsbsize * 1024))
+ goto out;
+
+ paddr += (1 << 16);
+ iopte++;
+ }
+ next:
+ mlist = mlist->theres_more;
+ }
+out:
+ if (mlist) {
+ prom_printf("WARNING: not all physical memory mapped in IOMMU\n");
+ prom_printf("Try booting with mem=xxxM or similar\n");
+ prom_halt();
+ }
+
+ sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase));
+
+ control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);
+ control &= ~(IOMMU_CTRL_TSBSZ);
+ control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
+ switch(tsbsize) {
+ case 8:
+ control |= IOMMU_TSBSZ_8K;
+ break;
+ case 16:
+ control |= IOMMU_TSBSZ_16K;
+ break;
+ case 32:
+ control |= IOMMU_TSBSZ_32K;
+ break;
+ default:
+ prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
+ prom_halt();
+ break;
+ }
+ sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
+}
+
+static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm)
+{
+ char *name = pbm->name;
+ unsigned long ibase = p->controller_regs + SABRE_IOSPACE;
+ unsigned long mbase = p->controller_regs + SABRE_MEMSPACE;
+ unsigned int devfn;
+ unsigned long first, last, i;
+ u8 *addr, map;
+
+ sprintf(name, "SABRE%d PBM%c",
+ p->index,
+ (pbm == &p->pbm_A ? 'A' : 'B'));
+ pbm->io_space.name = pbm->mem_space.name = name;
+
+ devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1);
+ addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP);
+ map = 0;
+ pci_config_read8(addr, &map);
+
+ first = 8;
+ last = 0;
+ for (i = 0; i < 8; i++) {
+ if ((map & (1 << i)) != 0) {
+ if (first > i)
+ first = i;
+ if (last < i)
+ last = i;
+ }
+ }
+ pbm->io_space.start = ibase + (first << 21UL);
+ pbm->io_space.end = ibase + (last << 21UL) + ((1 << 21UL) - 1);
+ pbm->io_space.flags = IORESOURCE_IO;
+
+ addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP);
+ map = 0;
+ pci_config_read8(addr, &map);
+
+ first = 8;
+ last = 0;
+ for (i = 0; i < 8; i++) {
+ if ((map & (1 << i)) != 0) {
+ if (first > i)
+ first = i;
+ if (last < i)
+ last = i;
+ }
+ }
+ pbm->mem_space.start = mbase + (first << 29UL);
+ pbm->mem_space.end = mbase + (last << 29UL) + ((1 << 29UL) - 1);
+ pbm->mem_space.flags = IORESOURCE_MEM;
+
+ if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
+ prom_printf("Cannot register PBM-%c's IO space.\n",
+ (pbm == &p->pbm_A ? 'A' : 'B'));
+ prom_halt();
+ }
+ if (request_resource(&iomem_resource, &pbm->mem_space) < 0) {
+ prom_printf("Cannot register PBM-%c's MEM space.\n",
+ (pbm == &p->pbm_A ? 'A' : 'B'));
+ prom_halt();
+ }
+}
+
+static void __init sabre_pbm_init(struct pci_controller_info *p, int sabre_node)
+{
+ char namebuf[128];
+ u32 busrange[2];
+ int node;
+
+ node = prom_getchild(sabre_node);
+ while ((node = prom_searchsiblings(node, "pci")) != 0) {
+ struct pci_pbm_info *pbm;
+ int err;
+
+ err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
+ if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
+ goto next_pci;
+
+ err = prom_getproperty(node, "bus-range",
+ (char *)&busrange[0], sizeof(busrange));
+ if (err == 0 || err == -1) {
+ prom_printf("APB: Error, cannot get PCI bus-range.\n");
+ prom_halt();
+ }
+
+ if (busrange[0] == 1)
+ pbm = &p->pbm_B;
+ else
+ pbm = &p->pbm_A;
+ pbm->parent = p;
+ pbm->prom_node = node;
+ pbm->pci_first_busno = busrange[0];
+ pbm->pci_last_busno = busrange[1];
+ for (err = pbm->pci_first_busno;
+ err <= pbm->pci_last_busno;
+ err++)
+ pci_bus2pbm[err] = pbm;
+
+
+ prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name));
+ err = prom_getproperty(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(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(node, "interrupt-map-mask",
+ (char *)&pbm->pbm_intmask,
+ sizeof(pbm->pbm_intmask));
+ if (err == -1) {
+ prom_printf("APB: Fatal error, no interrupt-map-mask.\n");
+ prom_halt();
+ }
+ } else {
+ pbm->num_pbm_intmap = 0;
+ memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
+ }
+
+ pbm_register_toplevel_resources(p, pbm);
+
+ next_pci:
+ node = prom_getsibling(node);
+ if (!node)
+ break;
+ }
+}
+
+void __init sabre_init(int pnode)
+{
+ struct linux_prom64_registers pr_regs[2];
+ struct pci_controller_info *p;
+ unsigned long flags;
+ int tsbsize, err;
+ u32 busrange[2];
+ u32 vdma[2];
+ u32 upa_portid;
+ int bus;
+
+ p = kmalloc(sizeof(*p), GFP_ATOMIC);
+ if (!p) {
+ prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n");
+ prom_halt();
+ }
+
+ upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff);
+
+ memset(p, 0, sizeof(*p));
+
+ spin_lock_irqsave(&pci_controller_lock, flags);
+ p->next = pci_controller_root;
+ pci_controller_root = p;
+ spin_unlock_irqrestore(&pci_controller_lock, flags);
+
+ p->portid = upa_portid;
+ p->index = pci_num_controllers++;
+ p->scan_bus = sabre_scan_bus;
+ p->irq_build = sabre_irq_build;
+ p->base_address_update = sabre_base_address_update;
+ p->resource_adjust = sabre_resource_adjust;
+ p->pci_ops = &sabre_ops;
+
+ /*
+ * Map in SABRE register set and report the presence of this SABRE.
+ */
+ err = prom_getproperty(pnode, "reg",
+ (char *)&pr_regs[0], sizeof(pr_regs));
+ if(err == 0 || err == -1) {
+ prom_printf("SABRE: Error, cannot get U2P registers "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ /*
+ * First REG in property is base of entire SABRE register space.
+ */
+ p->controller_regs = pr_regs[0].phys_addr;
+ printk("PCI: Found SABRE, main regs at %016lx\n", p->controller_regs);
+
+ /* Error interrupts are enabled later after the bus scan. */
+ sabre_write(p->controller_regs + SABRE_PCICTRL,
+ (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR |
+ 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);
+
+ err = prom_getproperty(pnode, "virtual-dma",
+ (char *)&vdma[0], sizeof(vdma));
+ if(err == 0 || err == -1) {
+ prom_printf("SABRE: Error, cannot get virtual-dma property "
+ "from PROM.\n");
+ prom_halt();
+ }
+
+ switch(vdma[1]) {
+ case 0x20000000:
+ tsbsize = 8;
+ break;
+ case 0x40000000:
+ tsbsize = 16;
+ break;
+ case 0x80000000:
+ tsbsize = 32;
+ break;
+ default:
+ prom_printf("SABRE: strange virtual-dma size.\n");
+ prom_halt();
+ }
+
+ sabre_iommu_init(p, tsbsize, vdma[0]);
+
+ printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
+
+ err = prom_getproperty(pnode, "bus-range",
+ (char *)&busrange[0], sizeof(busrange));
+ if(err == 0 || err == -1) {
+ prom_printf("SABRE: Error, cannot get PCI bus-range "
+ " from PROM.\n");
+ prom_halt();
+ }
+
+ p->pci_first_busno = busrange[0];
+ p->pci_last_busno = busrange[1];
+
+ /*
+ * Handle config space reads through any Simba on APB.
+ */
+ for (bus = p->pci_first_busno; bus <= p->pci_last_busno; bus++)
+ pci_bus2pbm[bus] = &p->pbm_A;
+
+ /*
+ * Look for APB underneath.
+ */
+ sabre_pbm_init(p, pnode);
+}
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
new file mode 100644
index 000000000..831011128
--- /dev/null
+++ b/arch/sparc64/kernel/power.c
@@ -0,0 +1,105 @@
+/* $Id: power.c,v 1.4 1999/08/31 18:22:05 davem Exp $
+ * power.c: Power management driver.
+ *
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/delay.h>
+
+#include <asm/ebus.h>
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+#ifdef CONFIG_PCI
+static unsigned long power_reg = 0UL;
+#define POWER_SYSTEM_OFF (1 << 0)
+#define POWER_COURTESY_OFF (1 << 1)
+
+static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
+static int button_pressed = 0;
+
+static void power_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (button_pressed == 0) {
+ wake_up(&powerd_wait);
+ button_pressed = 1;
+ }
+}
+#endif /* CONFIG_PCI */
+
+extern void machine_halt(void);
+
+void machine_power_off(void)
+{
+#ifdef CONFIG_PCI
+ if (power_reg != 0UL) {
+ /* Both register bits seem to have the
+ * same effect, so until I figure out
+ * what the difference is...
+ */
+ writel(POWER_COURTESY_OFF | POWER_SYSTEM_OFF, power_reg);
+ }
+#endif /* CONFIG_PCI */
+ machine_halt();
+}
+
+#ifdef CONFIG_PCI
+static int powerd(void *__unused)
+{
+ static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+ char *argv[] = { "/usr/bin/shutdown", "-h", "now", NULL };
+
+ current->session = 1;
+ current->pgrp = 1;
+ sprintf(current->comm, "powerd");
+
+again:
+ while(button_pressed == 0) {
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ interruptible_sleep_on(&powerd_wait);
+ }
+
+ /* Ok, down we go... */
+ if (execve("/usr/bin/shutdown", argv, envp) < 0) {
+ printk("powerd: shutdown execution failed\n");
+ button_pressed = 0;
+ goto again;
+ }
+ return 0;
+}
+
+void __init power_init(void)
+{
+ struct linux_ebus *ebus;
+ struct linux_ebus_device *edev;
+
+ for_each_ebus(ebus) {
+ for_each_ebusdev(edev, ebus) {
+ if (!strcmp(edev->prom_name, "power"))
+ goto found;
+ }
+ }
+ return;
+
+found:
+ power_reg = edev->resource[0].start;
+ printk("power: Control reg at %016lx ... ", power_reg);
+ if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
+ printk("Failed to start power daemon.\n");
+ return;
+ }
+ printk("powerd running.\n");
+ if (request_irq(edev->irqs[0],
+ power_handler, SA_SHIRQ, "power",
+ (void *) power_reg) < 0)
+ printk("power: Error, cannot register IRQ handler.\n");
+}
+#endif /* CONFIG_PCI */
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index ace0c1dc0..0e0f540b7 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.94 1999/05/27 04:49:30 davem Exp $
+/* $Id: process.c,v 1.100 1999/08/31 04:39:39 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -46,7 +46,7 @@
/*
* the idle loop on a Sparc... ;)
*/
-asmlinkage int sys_idle(void)
+int cpu_idle(void)
{
if (current->pid != 0)
return -EPERM;
@@ -77,7 +77,7 @@ asmlinkage int sys_idle(void)
*/
#define idle_me_harder() (cpu_data[current->processor].idle_volume += 1)
#define unidle_me() (cpu_data[current->processor].idle_volume = 0)
-asmlinkage int cpu_idle(void)
+int cpu_idle(void)
{
current->priority = 0;
current->counter = -100;
@@ -99,15 +99,6 @@ asmlinkage int cpu_idle(void)
}
}
-asmlinkage int sys_idle(void)
-{
- if(current->pid != 0)
- return -EPERM;
-
- cpu_idle();
- return 0;
-}
-
#endif
extern char reboot_command [];
@@ -152,11 +143,6 @@ void machine_restart(char * cmd)
panic("Reboot failed!");
}
-void machine_power_off(void)
-{
- machine_halt();
-}
-
static void show_regwindow32(struct pt_regs *regs)
{
struct reg_window32 *rw;
@@ -189,7 +175,7 @@ static void show_regwindow(struct pt_regs *regs)
struct reg_window r_w;
mm_segment_t old_fs;
- if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) {
+ if ((regs->tstate & TSTATE_PRIV) || !(current->thread.flags & SPARC_FLAG_32BIT)) {
__asm__ __volatile__ ("flushw");
rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS);
if (!(regs->tstate & TSTATE_PRIV)) {
@@ -369,90 +355,96 @@ void show_regs32(struct pt_regs32 *regs)
regs->u_regs[15]);
}
-void show_thread(struct thread_struct *tss)
+void show_thread(struct thread_struct *thread)
{
int i;
#if 0
- printk("kregs: 0x%016lx\n", (unsigned long)tss->kregs);
- show_regs(tss->kregs);
+ printk("kregs: 0x%016lx\n", (unsigned long)thread->kregs);
+ show_regs(thread->kregs);
#endif
- printk("sig_address: 0x%016lx\n", tss->sig_address);
- printk("sig_desc: 0x%016lx\n", tss->sig_desc);
- printk("ksp: 0x%016lx\n", tss->ksp);
+ printk("sig_address: 0x%016lx\n", thread->sig_address);
+ printk("sig_desc: 0x%016lx\n", thread->sig_desc);
+ printk("ksp: 0x%016lx\n", thread->ksp);
- if (tss->w_saved) {
+ if (thread->w_saved) {
for (i = 0; i < NSWINS; i++) {
- if (!tss->rwbuf_stkptrs[i])
+ if (!thread->rwbuf_stkptrs[i])
continue;
printk("reg_window[%d]:\n", i);
- printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]);
+ printk("stack ptr: 0x%016lx\n", thread->rwbuf_stkptrs[i]);
}
- printk("w_saved: 0x%04x\n", tss->w_saved);
+ printk("w_saved: 0x%04x\n", thread->w_saved);
}
- printk("flags: 0x%08x\n", tss->flags);
- printk("current_ds: 0x%x\n", tss->current_ds.seg);
+ printk("flags: 0x%08x\n", thread->flags);
+ printk("current_ds: 0x%x\n", thread->current_ds.seg);
}
/* Free current thread data structures etc.. */
void exit_thread(void)
{
- if (current->tss.utraps) {
- if (current->tss.utraps[0] < 2)
- kfree (current->tss.utraps);
+ struct thread_struct *t = &current->thread;
+
+ if (t->utraps) {
+ if (t->utraps[0] < 2)
+ kfree (t->utraps);
else
- current->tss.utraps[0]--;
+ t->utraps[0]--;
}
/* Turn off performance counters if on. */
- if (current->tss.flags & SPARC_FLAG_PERFCTR) {
- current->tss.user_cntd0 =
- current->tss.user_cntd1 = NULL;
- current->tss.pcr_reg = 0;
- current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ if (t->flags & SPARC_FLAG_PERFCTR) {
+ t->user_cntd0 = t->user_cntd1 = NULL;
+ t->pcr_reg = 0;
+ t->flags &= ~(SPARC_FLAG_PERFCTR);
write_pcr(0);
}
}
void flush_thread(void)
{
- if (!(current->tss.flags & SPARC_FLAG_KTHREAD))
- flush_user_windows();
- current->tss.w_saved = 0;
+ struct thread_struct *t = &current->thread;
+
+ if (current->mm) {
+ if (t->flags & SPARC_FLAG_32BIT) {
+ struct mm_struct *mm = current->mm;
+ pgd_t *pgd0 = &mm->pgd[0];
+ unsigned long pgd_cache;
+
+ if (pgd_none(*pgd0)) {
+ pmd_t *page = get_pmd_fast();
+ if (!page)
+ (void) get_pmd_slow(pgd0, 0);
+ else
+ pgd_set(pgd0, page);
+ }
+ pgd_cache = pgd_val(*pgd0) << 11UL;
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : /* no outputs */
+ : "r" (pgd_cache),
+ "r" (TSB_REG),
+ "i" (ASI_DMMU));
+ }
+ }
+ t->w_saved = 0;
/* Turn off performance counters if on. */
- if (current->tss.flags & SPARC_FLAG_PERFCTR) {
- current->tss.user_cntd0 =
- current->tss.user_cntd1 = NULL;
- current->tss.pcr_reg = 0;
- current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ if (t->flags & SPARC_FLAG_PERFCTR) {
+ t->user_cntd0 = t->user_cntd1 = NULL;
+ t->pcr_reg = 0;
+ t->flags &= ~(SPARC_FLAG_PERFCTR);
write_pcr(0);
}
- /* No new signal delivery by default. */
- current->tss.new_signal = 0;
- current->tss.fpsaved[0] = 0;
+ /* Clear FPU register state. */
+ t->fpsaved[0] = 0;
- /* Now, this task is no longer a kernel thread. */
- current->tss.current_ds = USER_DS;
- if(current->tss.flags & SPARC_FLAG_KTHREAD) {
- current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+ if (t->current_ds.seg != ASI_AIUS)
+ set_fs(USER_DS);
- /* exec_mmap() set context to NO_CONTEXT, here is
- * where we grab a new one.
- */
- activate_context(current);
- }
- if (current->tss.flags & SPARC_FLAG_32BIT)
- __asm__ __volatile__("stxa %%g0, [%0] %1"
- : /* no outputs */
- : "r"(TSB_REG), "i"(ASI_DMMU));
- __cli();
- current->tss.ctx = current->mm->context & 0x3ff;
- spitfire_set_secondary_context (current->tss.ctx);
- __asm__ __volatile__("flush %g6");
- __sti();
+ /* Init new signal delivery disposition. */
+ t->flags &= ~SPARC_FLAG_NEWSIGNALS;
}
/* It's a bit more tricky when 64-bit tasks are involved... */
@@ -460,12 +452,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
{
unsigned long fp, distance, rval;
- /* do_fork() grabs the parent semaphore, we must release it
- * temporarily so we can build the child clone stack frame
- * without deadlocking.
- */
- up(&current->mm->mmap_sem);
- if(!(current->tss.flags & SPARC_FLAG_32BIT)) {
+ if(!(current->thread.flags & SPARC_FLAG_32BIT)) {
csp += STACK_BIAS;
psp += STACK_BIAS;
__get_user(fp, &(((struct reg_window *)psp)->ins[6]));
@@ -482,7 +469,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
rval = (csp - distance);
if(copy_in_user(rval, psp, distance))
rval = 0;
- else if(current->tss.flags & SPARC_FLAG_32BIT) {
+ else if(current->thread.flags & SPARC_FLAG_32BIT) {
if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6])))
rval = 0;
} else {
@@ -492,47 +479,46 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp)
else
rval = rval - STACK_BIAS;
}
- down(&current->mm->mmap_sem);
return rval;
}
/* Standard stuff. */
static inline void shift_window_buffer(int first_win, int last_win,
- struct thread_struct *tp)
+ struct thread_struct *t)
{
int i;
for(i = first_win; i < last_win; i++) {
- tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1];
- memcpy(&tp->reg_window[i], &tp->reg_window[i+1],
+ t->rwbuf_stkptrs[i] = t->rwbuf_stkptrs[i+1];
+ memcpy(&t->reg_window[i], &t->reg_window[i+1],
sizeof(struct reg_window));
}
}
void synchronize_user_stack(void)
{
- struct thread_struct *tp = &current->tss;
+ struct thread_struct *t = &current->thread;
unsigned long window;
flush_user_windows();
- if((window = tp->w_saved) != 0) {
+ if((window = t->w_saved) != 0) {
int winsize = REGWIN_SZ;
int bias = 0;
- if(tp->flags & SPARC_FLAG_32BIT)
+ if(t->flags & SPARC_FLAG_32BIT)
winsize = REGWIN32_SZ;
else
bias = STACK_BIAS;
window -= 1;
do {
- unsigned long sp = (tp->rwbuf_stkptrs[window] + bias);
- struct reg_window *rwin = &tp->reg_window[window];
+ unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
+ struct reg_window *rwin = &t->reg_window[window];
if(!copy_to_user((char *)sp, rwin, winsize)) {
- shift_window_buffer(window, tp->w_saved - 1, tp);
- tp->w_saved--;
+ shift_window_buffer(window, t->w_saved - 1, t);
+ t->w_saved--;
}
} while(window--);
}
@@ -540,28 +526,28 @@ void synchronize_user_stack(void)
void fault_in_user_windows(struct pt_regs *regs)
{
- struct thread_struct *tp = &current->tss;
+ struct thread_struct *t = &current->thread;
unsigned long window;
int winsize = REGWIN_SZ;
int bias = 0;
- if(tp->flags & SPARC_FLAG_32BIT)
+ if(t->flags & SPARC_FLAG_32BIT)
winsize = REGWIN32_SZ;
else
bias = STACK_BIAS;
flush_user_windows();
- window = tp->w_saved;
+ window = t->w_saved;
if(window != 0) {
window -= 1;
do {
- unsigned long sp = (tp->rwbuf_stkptrs[window] + bias);
- struct reg_window *rwin = &tp->reg_window[window];
+ unsigned long sp = (t->rwbuf_stkptrs[window] + bias);
+ struct reg_window *rwin = &t->reg_window[window];
if(copy_to_user((char *)sp, rwin, winsize))
goto barf;
} while(window--);
}
- current->tss.w_saved = 0;
+ t->w_saved = 0;
return;
barf:
do_exit(SIGILL);
@@ -582,65 +568,73 @@ barf:
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
struct task_struct *p, struct pt_regs *regs)
{
+ struct thread_struct *t = &p->thread;
char *child_trap_frame;
/* Calculate offset to stack_frame & pt_regs */
child_trap_frame = ((char *)p) + ((PAGE_SIZE << 1) - (TRACEREG_SZ+REGWIN_SZ));
memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ));
- p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
- p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
- p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
- p->tss.fpsaved[0] = 0;
- p->mm->segments = (void *) 0;
+ t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
+ t->flags |= SPARC_FLAG_NEWCHILD;
+ t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
+ t->cwp = (regs->tstate + 1) & TSTATE_CWP;
+ t->fpsaved[0] = 0;
if(regs->tstate & TSTATE_PRIV) {
/* Special case, if we are spawning a kernel thread from
* a userspace task (via KMOD, NFS, or similar) we must
* disable performance counters in the child because the
* address space and protection realm are changing.
*/
- if (current->tss.flags & SPARC_FLAG_PERFCTR) {
- p->tss.user_cntd0 =
- p->tss.user_cntd1 = NULL;
- p->tss.pcr_reg = 0;
- p->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ if (t->flags & SPARC_FLAG_PERFCTR) {
+ t->user_cntd0 = t->user_cntd1 = NULL;
+ t->pcr_reg = 0;
+ t->flags &= ~(SPARC_FLAG_PERFCTR);
}
- p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
- p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD);
- p->tss.current_ds = KERNEL_DS;
- p->tss.ctx = 0;
- __asm__ __volatile__("flushw");
- memcpy((void *)(p->tss.ksp + STACK_BIAS),
+ t->kregs->u_regs[UREG_FP] = p->thread.ksp;
+ t->current_ds = KERNEL_DS;
+ flush_register_windows();
+ memcpy((void *)(t->ksp + STACK_BIAS),
(void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
sizeof(struct reg_window));
- p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
+ t->kregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
- if(current->tss.flags & SPARC_FLAG_32BIT) {
+ if(t->flags & SPARC_FLAG_32BIT) {
sp &= 0x00000000ffffffffUL;
regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
}
- p->tss.kregs->u_regs[UREG_FP] = sp;
- p->tss.flags = (p->tss.flags & ~SPARC_FLAG_KTHREAD) |
- SPARC_FLAG_NEWCHILD;
- p->tss.current_ds = USER_DS;
- p->tss.ctx = (p->mm->context & 0x3ff);
+ t->kregs->u_regs[UREG_FP] = sp;
+ t->current_ds = USER_DS;
if (sp != regs->u_regs[UREG_FP]) {
unsigned long csp;
csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
if(!csp)
return -EFAULT;
- p->tss.kregs->u_regs[UREG_FP] = csp;
+ t->kregs->u_regs[UREG_FP] = csp;
}
- if (p->tss.utraps)
- p->tss.utraps[0]++;
+ if (t->utraps)
+ t->utraps[0]++;
}
/* Set the return value for the child. */
- p->tss.kregs->u_regs[UREG_I0] = current->pid;
- p->tss.kregs->u_regs[UREG_I1] = 1;
+ t->kregs->u_regs[UREG_I0] = current->pid;
+ t->kregs->u_regs[UREG_I1] = 1;
/* Set the second return value for the parent. */
regs->u_regs[UREG_I1] = 0;
+#if 0
+ printk("\ncopy_thread: c(%p[mm(%p:%p)]) p(%p[mm(%p:%p)])\n",
+ current, current->mm, current->active_mm,
+ p, p->mm, p->active_mm);
+ printk("copy_thread: c MM_ctx(%016lx) MM_pgd(%016lx)\n",
+ (current->mm ? current->mm->context : 0),
+ (current->mm ? pgd_val(current->mm->pgd[0]) : 0));
+ printk("copy_thread: p MM_ctx(%016lx) MM_pgd(%08x)\n",
+ (p->mm ? p->mm->context : 0),
+ (p->mm ? pgd_val(p->mm->pgd[0]) : 0));
+ printk("copy_thread: c->flags(%x) p->flags(%x) ",
+ current->thread.flags, p->thread.flags);
+#endif
return 0;
}
@@ -703,10 +697,10 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->u_dsize &= ~(PAGE_SIZE - 1);
first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
- memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->tss.float_regs[0], (sizeof(unsigned long) * 32));
- dump->fpu.fpstatus.fsr = current->tss.fsr;
+ memcpy(&dump->fpu.fpstatus.fregs.regs[0], &current->thread.float_regs[0], (sizeof(unsigned long) * 32));
+ dump->fpu.fpstatus.fsr = current->thread.fsr;
dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
- dump->sigcode = current->tss.sig_desc;
+ dump->sigcode = current->thread.sig_desc;
#endif
}
@@ -729,9 +723,9 @@ typedef struct {
int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
{
unsigned long *kfpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
- unsigned long fprs = current->tss.fpsaved[0];
+ unsigned long fprs = current->thread.fpsaved[0];
- if ((current->tss.flags & SPARC_FLAG_32BIT) != 0) {
+ if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs;
if (fprs & FPRS_DL)
@@ -745,7 +739,7 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
memset(&fpregs32->pr_q[0], 0,
(sizeof(unsigned int) * 64));
if (fprs & FPRS_FEF) {
- fpregs32->pr_fsr = (unsigned int) current->tss.xfsr[0];
+ fpregs32->pr_fsr = (unsigned int) current->thread.xfsr[0];
fpregs32->pr_en = 1;
} else {
fpregs32->pr_fsr = 0;
@@ -765,8 +759,8 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
memset(&fpregs->pr_regs[16], 0,
sizeof(unsigned int) * 32);
if(fprs & FPRS_FEF) {
- fpregs->pr_fsr = current->tss.xfsr[0];
- fpregs->pr_gsr = current->tss.gsr[0];
+ fpregs->pr_fsr = current->thread.xfsr[0];
+ fpregs->pr_gsr = current->thread.gsr[0];
} else {
fpregs->pr_fsr = fpregs->pr_gsr = 0;
}
@@ -784,6 +778,8 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
int error, base = 0;
char *filename;
+ /* User register window flush is done by entry.S */
+
/* Check for indirect call. */
if(regs->u_regs[UREG_G1] == 0)
base = 1;
@@ -798,8 +794,8 @@ asmlinkage int sparc_execve(struct pt_regs *regs)
putname(filename);
if(!error) {
fprs_write(0);
- current->tss.xfsr[0] = 0;
- current->tss.fpsaved[0] = 0;
+ current->thread.xfsr[0] = 0;
+ current->thread.fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
}
out:
diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c
deleted file mode 100644
index 392ddab55..000000000
--- a/arch/sparc64/kernel/psycho.c
+++ /dev/null
@@ -1,2619 +0,0 @@
-/* $Id: psycho.c,v 1.86 1999/07/01 10:39:43 davem Exp $
- * psycho.c: Ultra/AX U2P PCI controller support.
- *
- * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
- * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-#include <asm/ebus.h>
-#include <asm/sbus.h> /* for sanity check... */
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#undef PROM_DEBUG
-#undef FIXUP_REGS_DEBUG
-#undef FIXUP_IRQ_DEBUG
-#undef FIXUP_VMA_DEBUG
-#undef PCI_COOKIE_DEBUG
-
-#ifdef PROM_DEBUG
-#define dprintf prom_printf
-#else
-#define dprintf printk
-#endif
-
-unsigned long pci_dvma_offset = 0x00000000UL;
-unsigned long pci_dvma_mask = 0xffffffffUL;
-
-#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL
-unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
-unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
-
-#ifndef CONFIG_PCI
-
-int pcibios_present(void)
-{
- return 0;
-}
-
-asmlinkage int sys_pciconfig_read(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- return 0;
-}
-
-asmlinkage int sys_pciconfig_write(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- return 0;
-}
-
-#else
-
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/pci.h>
-
-#include <asm/oplib.h>
-#include <asm/pbm.h>
-#include <asm/apb.h>
-#include <asm/uaccess.h>
-
-#define PSYCHO_REORDER_ONBOARDFIRST 1
-
-struct linux_psycho *psycho_root = NULL;
-int linux_num_psycho = 0;
-static struct linux_pbm_info *bus2pbm[256];
-static int psycho_reorder __initdata = 0;
-
-static int pbm_read_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value);
-static int pbm_read_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value);
-static int pbm_read_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value);
-static int pbm_write_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value);
-static int pbm_write_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value);
-static int pbm_write_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value);
-
-/* This is used to make the scan_bus in the generic PCI code be
- * a nop, as we need to control the actual bus probing sequence.
- * After that we leave it on of course.
- */
-static int pci_probe_enable = 0;
-
-static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr)
-{
- unsigned long dvma_addr = pci_dvma_offset + daddr;
- unsigned long vaddr = (unsigned long)__va(paddr);
-
- pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr;
- pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr;
-}
-
-static void __init psycho_iommu_init(struct linux_psycho *psycho, int tsbsize)
-{
- extern int this_is_starfire;
- extern void *starfire_hookup(int);
- struct linux_mlist_p1275 *mlist;
- unsigned long tsbbase;
- unsigned long control, i, n;
- unsigned long *iopte;
- unsigned long order;
-
- /*
- * Invalidate TLB Entries.
- */
- control = psycho->psycho_regs->iommu_control;
- control |= IOMMU_CTRL_DENAB;
- psycho->psycho_regs->iommu_control = control;
- for(i = 0; i < 16; i++) {
- psycho->psycho_regs->iommu_data[i] = 0;
- }
- control &= ~(IOMMU_CTRL_DENAB);
- psycho->psycho_regs->iommu_control = control;
-
- for(order = 0;; order++) {
- if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
- break;
- }
- tsbbase = __get_free_pages(GFP_DMA, order);
- if (!tsbbase) {
- prom_printf("IOMMU: Error, kmalloc(tsb) failed.\n");
- prom_halt();
- }
- iopte = (unsigned long *)tsbbase;
-
- /* Initialize to "none" settings. */
- for(i = 0; i < PCI_DVMA_HASHSZ; i++) {
- pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE;
- pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE;
- }
-
- n = 0;
- mlist = *prom_meminfo()->p1275_totphys;
- while (mlist) {
- unsigned long paddr = mlist->start_adr;
- unsigned long num_bytes = mlist->num_bytes;
-
- if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET))
- goto next;
-
- if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET))
- num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr;
-
- /* Align base and length so we map whole hash table sized chunks
- * at a time (and therefore full 64K IOMMU pages).
- */
- paddr &= ~((1UL << 24UL) - 1);
- num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1);
-
- /* Move up the base for mappings already created. */
- while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] !=
- PCI_DVMA_HASH_NONE) {
- paddr += (1UL << 24UL);
- num_bytes -= (1UL << 24UL);
- if(num_bytes == 0UL)
- goto next;
- }
-
- /* Move down the size for tail mappings already created. */
- while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] !=
- PCI_DVMA_HASH_NONE) {
- num_bytes -= (1UL << 24UL);
- if(num_bytes == 0UL)
- goto next;
- }
-
- /* Now map the rest. */
- for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) {
- *iopte = (IOPTE_VALID | IOPTE_64K |
- IOPTE_CACHE | IOPTE_WRITE);
- *iopte |= paddr;
-
- if (!(n & 0xff))
- set_dvma_hash(paddr, (n << 16));
-
- if (++n > (tsbsize * 1024))
- goto out;
-
- paddr += (1 << 16);
- iopte++;
- }
- next:
- mlist = mlist->theres_more;
- }
-out:
- if (mlist) {
- prom_printf("WARNING: not all physical memory mapped in IOMMU\n");
- prom_printf("Try booting with mem=xxxM or similar\n");
- prom_halt();
- }
-
- psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase);
-
- control = psycho->psycho_regs->iommu_control;
- control &= ~(IOMMU_CTRL_TSBSZ);
- control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
- switch(tsbsize) {
- case 8:
- pci_dvma_mask = 0x1fffffffUL;
- control |= IOMMU_TSBSZ_8K;
- break;
- case 16:
- pci_dvma_mask = 0x3fffffffUL;
- control |= IOMMU_TSBSZ_16K;
- break;
- case 32:
- pci_dvma_mask = 0x7fffffffUL;
- control |= IOMMU_TSBSZ_32K;
- break;
- default:
- prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
- prom_halt();
- break;
- }
- psycho->psycho_regs->iommu_control = control;
-
- /* If necessary, hook us up for starfire IRQ translations. */
- if(this_is_starfire)
- psycho->starfire_cookie = starfire_hookup(psycho->upa_portid);
- else
- psycho->starfire_cookie = NULL;
-}
-
-extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
-extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm);
-
-/*
- * Poor man's PCI...
- */
-void __init sabre_init(int pnode)
-{
- struct linux_prom64_registers pr_regs[2];
- struct linux_psycho *sabre;
- unsigned long ctrl;
- int tsbsize, node, err;
- u32 busrange[2];
- u32 vdma[2];
- u32 portid;
- int bus;
-
- sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
- if (!sabre) {
- prom_printf("SABRE: Error, kmalloc(sabre) failed.\n");
- prom_halt();
- }
-
- portid = prom_getintdefault(pnode, "upa-portid", 0xff);
-
- memset(sabre, 0, sizeof(*sabre));
-
- sabre->next = psycho_root;
- psycho_root = sabre;
-
- sabre->upa_portid = portid;
- sabre->index = linux_num_psycho++;
-
- /*
- * Map in SABRE register set and report the presence of this SABRE.
- */
- err = prom_getproperty(pnode, "reg",
- (char *)&pr_regs[0], sizeof(pr_regs));
- if(err == 0 || err == -1) {
- prom_printf("SABRE: Error, cannot get U2P registers "
- "from PROM.\n");
- prom_halt();
- }
-
- /*
- * First REG in property is base of entire SABRE register space.
- */
- sabre->psycho_regs =
- sparc_alloc_io((pr_regs[0].phys_addr & 0xffffffff),
- NULL, sizeof(struct psycho_regs),
- "SABRE Registers",
- (pr_regs[0].phys_addr >> 32), 0);
- if(sabre->psycho_regs == NULL) {
- prom_printf("SABRE: Error, cannot map SABRE main registers.\n");
- prom_halt();
- }
-
- printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
- sabre->psycho_regs, sabre->psycho_regs->control);
-#ifdef PROM_DEBUG
- dprintf("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n",
- sabre->psycho_regs, sabre->psycho_regs->control);
-#endif
-
- ctrl = sabre->psycho_regs->pci_a_control;
- ctrl = (1UL << 36) | (1UL << 34) | (1UL << 21) | (1UL << 8) | 0x0fUL;
- sabre->psycho_regs->pci_a_control = ctrl;
-
- /* Now map in PCI config space for entire SABRE. */
- sabre->pci_config_space =
- sparc_alloc_io(((pr_regs[0].phys_addr & 0xffffffff)
- + 0x01000000),
- NULL, 0x01000000,
- "PCI Config Space",
- (pr_regs[0].phys_addr >> 32), 0);
- if(sabre->pci_config_space == NULL) {
- prom_printf("SABRE: Error, cannot map PCI config space.\n");
- prom_halt();
- }
-
- /* Report some more info. */
- printk("SABRE: PCI config space at %p\n", sabre->pci_config_space);
-#ifdef PROM_DEBUG
- dprintf("SABRE: PCI config space at %p\n", sabre->pci_config_space);
-#endif
-
- err = prom_getproperty(pnode, "virtual-dma",
- (char *)&vdma[0], sizeof(vdma));
- if(err == 0 || err == -1) {
- prom_printf("SABRE: Error, cannot get virtual-dma property "
- "from PROM.\n");
- prom_halt();
- }
-
- switch(vdma[1]) {
- case 0x20000000:
- tsbsize = 8;
- break;
- case 0x40000000:
- tsbsize = 16;
- break;
- case 0x80000000:
- tsbsize = 32;
- break;
- default:
- prom_printf("SABRE: strange virtual-dma size.\n");
- prom_halt();
- }
-
- pci_dvma_offset = vdma[0];
- psycho_iommu_init(sabre, tsbsize);
-
- printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
-#ifdef PROM_DEBUG
- dprintf("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
-#endif
-
- err = prom_getproperty(pnode, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if(err == 0 || err == -1) {
- prom_printf("SIMBA: Error, cannot get PCI bus-range "
- " from PROM.\n");
- prom_halt();
- }
-
- sabre->pci_first_busno = busrange[0];
- sabre->pci_last_busno = busrange[1];
- sabre->pci_bus = &pci_root;
-
- /*
- * Handle config space reads through any Simba on APB.
- */
- for (bus = sabre->pci_first_busno; bus <= sabre->pci_last_busno; bus++)
- bus2pbm[bus] = &sabre->pbm_A;
-
- /*
- * Look for APB underneath.
- */
- node = prom_getchild(pnode);
- while ((node = prom_searchsiblings(node, "pci"))) {
- struct linux_pbm_info *pbm;
- char namebuf[128];
-
- err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
- if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
- goto next_pci;
-
- err = prom_getproperty(node, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if(err == 0 || err == -1) {
- prom_printf("SIMBA: Error, cannot get PCI bus-range "
- " from PROM.\n");
- prom_halt();
- }
-
- if (busrange[0] == 1)
- pbm = &sabre->pbm_B;
- else
- pbm = &sabre->pbm_A;
-
- pbm->parent = sabre;
- pbm->IO_assignments = NULL;
- pbm->MEM_assignments = NULL;
- pbm->prom_node = node;
-
- prom_getstring(node, "name", namebuf, sizeof(namebuf));
- strcpy(pbm->prom_name, namebuf);
-
- /* Now the ranges. */
- prom_pbm_ranges_init(pnode, pbm);
- prom_pbm_intmap_init(node, pbm);
-
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
- memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
-
- for (bus = pbm->pci_first_busno;
- bus <= pbm->pci_last_busno; bus++)
- bus2pbm[bus] = pbm;
-
- next_pci:
- node = prom_getsibling(node);
- if (!node)
- break;
- }
-}
-
-static __inline__ int
-apb_present(struct linux_psycho *psycho)
-{
- return psycho->pci_bus ? 1 : 0;
-}
-
-void __init pcibios_init(void)
-{
- struct linux_prom64_registers pr_regs[3];
- struct linux_psycho *psycho;
- char namebuf[128];
- u32 portid;
- int node;
-
- printk("PCI: Probing for controllers.\n");
-#ifdef PROM_DEBUG
- dprintf("PCI: Probing for controllers.\n");
-#endif
-
- node = prom_getchild(prom_root_node);
- while((node = prom_searchsiblings(node, "pci")) != 0) {
- struct linux_psycho *search;
- struct linux_pbm_info *pbm = NULL;
- u32 busrange[2];
- int err, is_pbm_a;
-
- err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
- if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) {
- sabre_init(node);
- goto next_pci;
- }
-
- portid = prom_getintdefault(node, "upa-portid", 0xff);
- for(search = psycho_root; search; search = search->next) {
- if(search->upa_portid == portid) {
- psycho = search;
-
- /* This represents _this_ instance, so it's
- * which ever one does _not_ have the prom node
- * info filled in yet.
- */
- is_pbm_a = (psycho->pbm_A.prom_node == 0);
- goto other_pbm;
- }
- }
-
- psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC);
- if (!psycho) {
- prom_printf("PSYCHO: Error, kmalloc(psycho) failed.\n");
- prom_halt();
- }
- memset(psycho, 0, sizeof(*psycho));
-
- psycho->next = psycho_root;
- psycho_root = psycho;
-
- psycho->upa_portid = portid;
- psycho->index = linux_num_psycho++;
-
- /*
- * Map in PSYCHO register set and report the presence
- * of this PSYCHO.
- */
- err = prom_getproperty(node, "reg",
- (char *)&pr_regs[0], sizeof(pr_regs));
- if(err == 0 || err == -1) {
- prom_printf("PSYCHO: Error, cannot get U2P registers "
- "from PROM.\n");
- prom_halt();
- }
-
- /*
- * Third REG in property is base of entire PSYCHO
- * register space.
- */
- psycho->psycho_regs =
- sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
- NULL, sizeof(struct psycho_regs),
- "PSYCHO Registers",
- (pr_regs[2].phys_addr >> 32), 0);
- if(psycho->psycho_regs == NULL) {
- prom_printf("PSYCHO: Error, cannot map PSYCHO "
- "main registers.\n");
- prom_halt();
- }
-
- printk("PCI: Found PSYCHO, main regs at %p\n",
- psycho->psycho_regs);
-#ifdef PROM_DEBUG
- dprintf("PCI: Found PSYCHO, main regs at %p\n",
- psycho->psycho_regs);
-#endif
-
- psycho->psycho_regs->irq_retry = 0xff;
-
- /* Now map in PCI config space for entire PSYCHO. */
- psycho->pci_config_space =
- sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)
- + 0x01000000),
- NULL, 0x01000000,
- "PCI Config Space",
- (pr_regs[2].phys_addr >> 32), 0);
- if(psycho->pci_config_space == NULL) {
- prom_printf("PSYCHO: Error, cannot map PCI config space.\n");
- prom_halt();
- }
-
- /* Report some more info. */
- printk("PSYCHO: PCI config space at %p\n",
- psycho->pci_config_space);
-#ifdef PROM_DEBUG
- dprintf("PSYCHO: PCI config space at %p\n",
- psycho->pci_config_space);
-#endif
-
- pci_dvma_offset = 0x80000000UL;
- psycho_iommu_init(psycho, 32);
-
- is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
-
- /* Enable arbitration for all PCI slots. */
- psycho->psycho_regs->pci_a_control |= PSYCHO_PCICTRL_AEN;
- psycho->psycho_regs->pci_b_control |= PSYCHO_PCICTRL_AEN;
-
- /* Disable DMA write / PIO rd synchronization on both
- * PCI bus segments.
- */
- psycho->psycho_regs->pci_a_diag |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho->psycho_regs->pci_b_diag |= PSYCHO_PCIDIAG_DDWSYNC;
-
- other_pbm:
- if(is_pbm_a)
- pbm = &psycho->pbm_A;
- else
- pbm = &psycho->pbm_B;
-
- pbm->parent = psycho;
- pbm->IO_assignments = NULL;
- pbm->MEM_assignments = NULL;
- pbm->prom_node = node;
-
- prom_getstring(node, "name", namebuf, sizeof(namebuf));
- strcpy(pbm->prom_name, namebuf);
-
- /* Now the ranges. */
- prom_pbm_ranges_init(node, pbm);
- prom_pbm_intmap_init(node, pbm);
-
- /* Finally grab the pci bus root array for this pbm after
- * having found the bus range existing under it.
- */
- err = prom_getproperty(node, "bus-range",
- (char *)&busrange[0], sizeof(busrange));
- if(err == 0 || err == -1) {
- prom_printf("PSYCHO: Error, cannot get PCI bus range.\n");
- prom_halt();
- }
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
- memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
-
- next_pci:
- node = prom_getsibling(node);
- if(!node)
- break;
- }
-}
-
-int pcibios_present(void)
-{
- return psycho_root != NULL;
-}
-
-static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm,
- unsigned long start,
- unsigned int offset, int io)
-{
- struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
-
- while (vp) {
- if (offset && (vp->offset != offset))
- goto next;
- if (vp->end >= start)
- break;
- next:
- vp = vp->next;
- }
- return vp;
-}
-
-static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new, int io)
-{
- struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments);
-
- if(!vp) {
- new->next = NULL;
- if(io)
- pbm->IO_assignments = new;
- else
- pbm->MEM_assignments = new;
- } else {
- struct pci_vma *prev = NULL;
-
- while(vp && (vp->end < new->end)) {
- prev = vp;
- vp = vp->next;
- }
- new->next = vp;
- if(!prev) {
- if(io)
- pbm->IO_assignments = new;
- else
- pbm->MEM_assignments = new;
- } else {
- prev->next = new;
- }
-
- /* Check for programming errors. */
- if(vp &&
- ((vp->start >= new->start && vp->start < new->end) ||
- (vp->end >= new->start && vp->end < new->end))) {
- prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n",
- io ? "IO" : "MEM");
- prom_printf("pci_add_vma: vp[%016lx:%016lx] "
- "new[%016lx:%016lx]\n",
- vp->start, vp->end,
- new->start, new->end);
- }
- }
-}
-
-static inline struct pci_vma *pci_vma_alloc(void)
-{
- return kmalloc(sizeof(struct pci_vma), GFP_ATOMIC);
-}
-
-static inline struct pcidev_cookie *pci_devcookie_alloc(void)
-{
- return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC);
-}
-
-
-static void __init
-pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus)
-{
- unsigned int devfn, l, class;
- unsigned char hdr_type = 0;
- int is_multi = 0;
-
- for (devfn = 0; devfn < 0xff; ++devfn) {
- if (PCI_FUNC(devfn) != 0 && is_multi == 0) {
- /* not a multi-function device */
- continue;
- }
- pbm_read_config_byte(pbm, bus, devfn,
- PCI_HEADER_TYPE, &hdr_type);
- if (PCI_FUNC(devfn) == 0)
- is_multi = hdr_type & 0x80;
-
- /* Check if there is anything here. */
- pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l);
- if (l == 0xffffffff || l == 0x00000000 ||
- l == 0x0000ffff || l == 0xffff0000) {
- is_multi = 0;
- continue;
- }
-
- /* See if this is a bridge device. */
- pbm_read_config_dword(pbm, bus, devfn,
- PCI_CLASS_REVISION, &class);
-
- if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
- unsigned int buses;
-
- pbm_read_config_dword(pbm, bus, devfn,
- PCI_PRIMARY_BUS, &buses);
-
- /*
- * First reconfigure everything underneath the bridge.
- */
- pbm_reconfigure_bridges(pbm, (buses >> 8) & 0xff);
-
- /*
- * Unconfigure this bridges bus numbers,
- * pci_scan_bus() will fix this up properly.
- */
- buses &= 0xff000000;
- pbm_write_config_dword(pbm, bus, devfn,
- PCI_PRIMARY_BUS, buses);
- }
- }
-}
-
-static void __init pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus)
-{
- unsigned int nbus;
-
- /*
- * First, reconfigure all bridge devices underneath this pbm.
- */
- pbm_reconfigure_bridges(pbm, pbm->pci_first_busno);
-
- /*
- * Now reconfigure the pbm to it's new bus number and set up
- * our bus2pbm mapping for this pbm.
- */
- nbus = pbm->pci_last_busno - pbm->pci_first_busno;
-
- pbm_write_config_byte(pbm, pbm->pci_first_busno, 0, 0x40, bus);
-
- pbm->pci_first_busno = bus;
- pbm_write_config_byte(pbm, bus, 0, 0x41, 0xff);
-
- do {
- bus2pbm[bus++] = pbm;
- } while (nbus--);
-}
-
-static void __init apb_init(struct linux_psycho *sabre)
-{
- struct pci_dev *pdev;
- unsigned short stmp;
- unsigned int itmp;
-
-#if 0
- for(pdev = pci_devices; pdev; pdev = pdev->next) {
- if(pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_SABRE) {
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
- break;
- }
- }
-#endif
- for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) {
- if (pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_SIMBA) {
- pci_read_config_word(pdev, PCI_COMMAND, &stmp);
- stmp |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY |
- PCI_COMMAND_IO;
- pci_write_config_word(pdev, PCI_COMMAND, stmp);
-
- /* Status register bits are "write 1 to clear". */
- pci_write_config_word(pdev, PCI_STATUS, 0xffff);
- pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff);
-
- pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp);
- stmp = PCI_BRIDGE_CTL_MASTER_ABORT |
- PCI_BRIDGE_CTL_SERR |
- PCI_BRIDGE_CTL_PARITY;
- pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp);
-
- pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp);
- itmp = APB_PCI_CTL_HIGH_SERR |
- APB_PCI_CTL_HIGH_ARBITER_EN;
- pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp);
-
- /* Systems with SIMBA are usually workstations, so
- * we configure to park to SIMBA not to the previous
- * bus owner.
- */
- pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp);
- itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f;
- pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp);
-#if 0
- /* Don't mess with the retry limit and PIO/DMA latency
- * timer settings. But do set primary and secondary
- * latency timers.
- */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
- pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64);
-#endif
- }
- }
-}
-
-static void __init sabre_probe(struct linux_psycho *sabre)
-{
- struct pci_bus *pbus = sabre->pci_bus;
- static unsigned char busno = 0;
-
- pbus->number = pbus->secondary = busno;
- pbus->sysdata = sabre;
-
- pbus->subordinate = pci_scan_bus(pbus);
- busno = pbus->subordinate + 1;
-
- for(pbus = pbus->children; pbus; pbus = pbus->next) {
- if (pbus->number == sabre->pbm_A.pci_first_busno)
- memcpy(&sabre->pbm_A.pci_bus, pbus, sizeof(*pbus));
- if (pbus->number == sabre->pbm_B.pci_first_busno)
- memcpy(&sabre->pbm_B.pci_bus, pbus, sizeof(*pbus));
- }
-
- apb_init(sabre);
-}
-
-
-static void __init pbm_probe(struct linux_pbm_info *pbm)
-{
- static struct pci_bus *pchain = NULL;
- struct pci_bus *pbus = &pbm->pci_bus;
- static unsigned char busno = 0;
-
- /* PSYCHO PBM's include child PCI bridges in bus-range property,
- * but we don't scan each of those ourselves, Linux generic PCI
- * probing code will find child bridges and link them into this
- * pbm's root PCI device hierarchy.
- */
-
- pbus->number = pbus->secondary = busno;
- pbus->sysdata = pbm;
-
- pbm_fixup_busno(pbm, busno);
-
- pbus->subordinate = pci_scan_bus(pbus);
-
- /*
- * Set the maximum subordinate bus of this pbm.
- */
- pbm->pci_last_busno = pbus->subordinate;
- pbm_write_config_byte(pbm, busno, 0, 0x41, pbm->pci_last_busno);
-
- busno = pbus->subordinate + 1;
-
- /*
- * Fixup the chain of primary PCI busses.
- */
- if (pchain) {
- pchain->next = &pbm->pci_bus;
- pchain = pchain->next;
- } else {
- pchain = &pci_root;
- memcpy(pchain, &pbm->pci_bus, sizeof(pci_root));
- }
-}
-
-static int __init pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- int pnode)
-{
- struct linux_prom_pci_registers pregs[PROMREG_MAX];
- int node;
- int err;
-
- node = prom_getchild(pnode);
- while (node) {
-
- err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
- if(err != 0 && err != -1) {
- u32 devfn = (pregs[0].phys_hi >> 8) & 0xff;
-
- if(devfn == pdev->devfn)
- return node; /* Match */
- }
-
- node = prom_getsibling(node);
- }
- return 0;
-}
-
-static void __init pdev_cookie_fillin(struct linux_pbm_info *pbm,
- struct pci_dev *pdev, int pnode)
-{
- struct pcidev_cookie *pcp;
- int node;
-
- node = pdev_to_pnode_sibtraverse(pbm, pdev, pnode);
- if(node == 0)
- node = -1;
- pcp = pci_devcookie_alloc();
- pcp->pbm = pbm;
- pcp->prom_node = node;
- pdev->sysdata = pcp;
-#ifdef PCI_COOKIE_DEBUG
- dprintf("pdev_cookie_fillin: pdev [%02x.%02x]: pbm %p, node %x\n",
- pdev->bus->number, pdev->devfn, pbm, node);
-#endif
-}
-
-static void __init fill_in_pbm_cookies(struct pci_bus *pbus,
- struct linux_pbm_info *pbm,
- int node)
-{
- struct pci_dev *pdev;
-
- pbus->sysdata = pbm;
-
-#ifdef PCI_COOKIE_DEBUG
- dprintf("fill_in_pbm_cookies: pbus [%02x]: pbm %p\n",
- pbus->number, pbm);
-#endif
-
- for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
- pdev_cookie_fillin(pbm, pdev, node);
-
- for(pbus = pbus->children; pbus; pbus = pbus->next) {
- struct pcidev_cookie *pcp = pbus->self->sysdata;
- fill_in_pbm_cookies(pbus, pbm, pcp->prom_node);
- }
-}
-
-static void __init sabre_cookie_fillin(struct linux_psycho *sabre)
-{
- struct pci_bus *pbus = sabre->pci_bus;
-
- for(pbus = pbus->children; pbus; pbus = pbus->next) {
- if (pbus->number == sabre->pbm_A.pci_first_busno)
- pdev_cookie_fillin(&sabre->pbm_A, pbus->self,
- sabre->pbm_A.prom_node);
- else if (pbus->number == sabre->pbm_B.pci_first_busno)
- pdev_cookie_fillin(&sabre->pbm_B, pbus->self,
- sabre->pbm_B.prom_node);
- }
-}
-
-/* Walk PROM device tree under PBM, looking for 'assigned-address'
- * properties, and recording them in pci_vma's linked in via
- * PBM->assignments.
- */
-static int __init gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs)
-{
- struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
- int err, iter;
-
- err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng));
- if(err == 0 || err == -1) {
- prom_printf("EBUS: fatal error, no range property.\n");
- prom_halt();
- }
- err = (err / sizeof(struct linux_prom_ebus_ranges));
- for(iter = 0; iter < err; iter++) {
- struct linux_prom_ebus_ranges *ep = &erng[iter];
- struct linux_prom_pci_registers *ap = &aregs[iter];
-
- ap->phys_hi = ep->parent_phys_hi;
- ap->phys_mid = ep->parent_phys_mid;
- ap->phys_lo = ep->parent_phys_lo;
-
- ap->size_hi = 0;
- ap->size_lo = ep->size;
- }
- return err;
-}
-
-static void __init assignment_process(struct linux_pbm_info *pbm, int node)
-{
- struct linux_prom_pci_registers aregs[PROMREG_MAX];
- char pname[256];
- int err, iter, numa;
-
- err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname));
- if (err > 0)
- pname[err] = 0;
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: %s\n", __FUNCTION__, err > 0 ? pname : "???");
-#endif
- if(strcmp(pname, "ebus") == 0) {
- numa = gimme_ebus_assignments(node, &aregs[0]);
- } else {
- err = prom_getproperty(node, "assigned-addresses",
- (char *)&aregs[0], sizeof(aregs));
-
- /* No assignments, nothing to do. */
- if(err == 0 || err == -1)
- return;
-
- numa = (err / sizeof(struct linux_prom_pci_registers));
- }
-
- for(iter = 0; iter < numa; iter++) {
- struct linux_prom_pci_registers *ap = &aregs[iter];
- struct pci_vma *vp;
- int space, breg, io;
-
- space = (ap->phys_hi >> 24) & 3;
- if(space != 1 && space != 2)
- continue;
- io = (space == 1);
-
- breg = (ap->phys_hi & 0xff);
-
- vp = pci_vma_alloc();
-
- /* XXX Means we don't support > 32-bit range of
- * XXX PCI MEM space, PSYCHO/PBM does not support it
- * XXX either due to it's layout so...
- */
- vp->start = ap->phys_lo;
- vp->end = vp->start + ap->size_lo - 1;
- vp->offset = (ap->phys_hi & 0xffffff);
-
- pci_add_vma(pbm, vp, io);
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: BaseReg %02x", pname, breg);
- dprintf(" %s vma [%08x,%08x]\n",
- io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
-#endif
- }
-}
-
-static void __init assignment_walk_siblings(struct linux_pbm_info *pbm, int node)
-{
- while(node) {
- int child = prom_getchild(node);
- if(child)
- assignment_walk_siblings(pbm, child);
-
- assignment_process(pbm, node);
-
- node = prom_getsibling(node);
- }
-}
-
-static inline void record_assignments(struct linux_pbm_info *pbm)
-{
- struct pci_vma *vp;
-
- if (apb_present(pbm->parent)) {
- /*
- * Disallow anything that is not in our IO/MEM map on SIMBA.
- */
- struct pci_bus *pbus = pbm->parent->pci_bus;
- struct pci_dev *pdev;
- unsigned char map;
- int bit;
-
- for (pdev = pbus->devices; pdev; pdev = pdev->sibling) {
- struct pcidev_cookie *pcp = pdev->sysdata;
- if (!pcp)
- continue;
- if (pcp->pbm == pbm)
- break;
- }
-
- if (!pdev) {
- prom_printf("record_assignments: no pdev for PBM\n");
- prom_halt();
- }
-
- pci_read_config_byte(pdev, APB_IO_ADDRESS_MAP, &map);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: IO %02x\n", __FUNCTION__, map);
-#endif
- for (bit = 0; bit < 8; bit++) {
- if (!(map & (1 << bit))) {
- vp = pci_vma_alloc();
- vp->start = (bit << 21);
- vp->end = vp->start + (1 << 21) - 1;
- vp->offset = 0;
- pci_add_vma(pbm, vp, 1);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: IO prealloc vma [%08x,%08x]\n",
- __FUNCTION__, vp->start, vp->end);
-#endif
- }
- }
- pci_read_config_byte(pdev, APB_MEM_ADDRESS_MAP, &map);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: MEM %02x\n", __FUNCTION__, map);
-#endif
- for (bit = 0; bit < 8; bit++) {
- if (!(map & (1 << bit))) {
- vp = pci_vma_alloc();
- vp->start = (bit << 29);
- vp->end = vp->start + (1 << 29) - 1;
- vp->offset = 0;
- pci_add_vma(pbm, vp, 0);
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%s: MEM prealloc vma [%08x,%08x]\n",
- __FUNCTION__, vp->start, vp->end);
-#endif
- }
- }
- }
-
- assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node));
-
- /*
- * Protect ISA IO space from being used.
- */
- vp = pci_find_vma(pbm, 0, 0, 1);
- if (!vp || 0x400 <= vp->start) {
- vp = pci_vma_alloc();
- vp->start = 0;
- vp->end = vp->start + 0x400 - 1;
- vp->offset = 0;
- pci_add_vma(pbm, vp, 1);
- }
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("PROM IO assignments for PBM %s:\n",
- pbm == &pbm->parent->pbm_A ? "A" : "B");
- vp = pbm->IO_assignments;
- while (vp) {
- dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end,
- vp->offset ? "Register" : "Unmapped");
- vp = vp->next;
- }
- dprintf("PROM MEM assignments for PBM %s:\n",
- pbm == &pbm->parent->pbm_A ? "A" : "B");
- vp = pbm->MEM_assignments;
- while (vp) {
- dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end,
- vp->offset ? "Register" : "Unmapped");
- vp = vp->next;
- }
-#endif
-}
-
-static void __init fixup_regs(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *pregs,
- int nregs,
- struct linux_prom_pci_registers *assigned,
- int numaa)
-{
- int preg, rng;
- int IO_seen = 0;
- int MEM_seen = 0;
-
- for(preg = 0; preg < nregs; preg++) {
- struct linux_prom_pci_registers *ap = NULL;
- int bustype = (pregs[preg].phys_hi >> 24) & 0x3;
- int bsreg, brindex;
- unsigned int rtmp;
- u64 pci_addr;
-
- if(bustype == 0) {
- /* Config space cookie, nothing to do. */
- if(preg != 0)
- printk("%s %02x.%02x [%04x,%04x]: "
- "strange, config space not 0\n",
- __FUNCTION__,
- pdev->bus->number, pdev->devfn,
- pdev->vendor, pdev->device);
- continue;
- } else if(bustype == 3) {
- /* XXX add support for this... */
- printk("%s %02x.%02x [%04x,%04x]: "
- "Warning, ignoring 64-bit PCI memory space, "
- "tell Eddie C. Dost (ecd@skynet.be).\n",
- __FUNCTION__,
- pdev->bus->number, pdev->devfn,
- pdev->vendor, pdev->device);
- continue;
- }
-
- bsreg = (pregs[preg].phys_hi & 0xff);
-
- /* Sanity */
- if((bsreg < PCI_BASE_ADDRESS_0) ||
- ((bsreg > (PCI_BASE_ADDRESS_5 + 4)) && (bsreg != PCI_ROM_ADDRESS)) ||
- (bsreg & 3)) {
- printk("%s %02x.%02x [%04x:%04x]: "
- "Warning, ignoring bogus basereg [%x]\n",
- __FUNCTION__, pdev->bus->number, pdev->devfn,
- pdev->vendor, pdev->device, bsreg);
- printk(" PROM reg: %08x.%08x.%08x %08x.%08x\n",
- pregs[preg].phys_hi, pregs[preg].phys_mid,
- pregs[preg].phys_lo, pregs[preg].size_hi,
- pregs[preg].size_lo);
- continue;
- }
-
- brindex = (bsreg - PCI_BASE_ADDRESS_0) >> 2;
- if(numaa) {
- int r;
-
- for(r = 0; r < numaa; r++) {
- int abreg;
-
- abreg = (assigned[r].phys_hi & 0xff);
- if(abreg == bsreg) {
- ap = &assigned[r];
- break;
- }
- }
- }
-
- /* Now construct UPA physical address. */
- pci_addr = (((u64)pregs[preg].phys_mid) << 32UL);
- pci_addr |= (((u64)pregs[preg].phys_lo));
-
- if(ap) {
- pci_addr += ((u64)ap->phys_lo);
- pci_addr += (((u64)ap->phys_mid) << 32UL);
- }
-
- /* Final step, apply PBM range. */
- for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
- struct linux_prom_pci_ranges *rp = &pbm->pbm_ranges[rng];
- int space = (rp->child_phys_hi >> 24) & 3;
-
- if(space == bustype) {
- pci_addr += ((u64)rp->parent_phys_lo);
- pci_addr += (((u64)rp->parent_phys_hi) << 32UL);
- break;
- }
- }
- if(rng == pbm->num_pbm_ranges) {
- /* AIEEE */
- prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n");
- }
- if (bsreg == PCI_ROM_ADDRESS) {
- pdev->rom_address = (unsigned long)__va(pci_addr);
- pdev->rom_address &= ~1UL;
-
- /*
- * Disable access to the ROM.
- */
- pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp);
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp & ~1);
- } else
- pdev->base_address[brindex] = (unsigned long)__va(pci_addr);
-
- /* Preserve I/O space bit. */
- if(bustype == 0x1) {
- pdev->base_address[brindex] |= 1;
- IO_seen = 1;
- } else {
- MEM_seen = 1;
- }
- }
-
- /* Now handle assignments PROM did not take care of. */
- if(nregs) {
- unsigned int rtmp, ridx;
- unsigned int offset, base;
- struct pci_vma *vp;
- u64 pci_addr;
- int breg;
-
- for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) {
- int io;
-
- ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2);
- base = (unsigned int)pdev->base_address[ridx];
-
- if(pdev->base_address[ridx] > PAGE_OFFSET)
- continue;
-
- io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
- base &= ~((io ?
- PCI_BASE_ADDRESS_IO_MASK :
- PCI_BASE_ADDRESS_MEM_MASK));
- offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
- vp = pci_find_vma(pbm, base, offset, io);
- if(!vp || vp->start > base) {
- unsigned int size, new_base;
-
- pci_read_config_dword(pdev, breg, &rtmp);
- pci_write_config_dword(pdev, breg, 0xffffffff);
- pci_read_config_dword(pdev, breg, &size);
- if(io)
- size &= ~1;
- size = (~(size) + 1);
- if(!size)
- continue;
-
- new_base = 0;
- for(vp = pci_find_vma(pbm, new_base, 0, io); ;
- vp = vp->next) {
- if(!vp || new_base + size <= vp->start)
- break;
- new_base = (vp->end + (size - 1)) & ~(size-1);
- }
- if(vp && (new_base + size > vp->start)) {
- prom_printf("PCI: Impossible full %s space.\n",
- (io ? "IO" : "MEM"));
- prom_halt();
- }
- vp = pci_vma_alloc();
- vp->start = new_base;
- vp->end = vp->start + size - 1;
- vp->offset = offset;
-
- pci_add_vma(pbm, vp, io);
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%02x.%02x.%x: BaseReg %02x",
- pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn),
- breg);
- dprintf(" %s vma [%08x,%08x]\n",
- io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end);
-#endif
- rtmp = new_base;
- pci_read_config_dword(pdev, breg, &base);
- if(io)
- rtmp |= (base & ~PCI_BASE_ADDRESS_IO_MASK);
- else
- rtmp |= (base & ~PCI_BASE_ADDRESS_MEM_MASK);
- pci_write_config_dword(pdev, breg, rtmp);
-
- /* Apply PBM ranges and update pci_dev. */
- pci_addr = new_base;
- for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
- struct linux_prom_pci_ranges *rp;
- int rspace;
-
- rp = &pbm->pbm_ranges[rng];
- rspace = (rp->child_phys_hi >> 24) & 3;
- if(io && rspace != 1)
- continue;
- else if(!io && rspace != 2)
- continue;
- pci_addr += ((u64)rp->parent_phys_lo);
- pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
- break;
- }
- if(rng == pbm->num_pbm_ranges) {
- /* AIEEE */
- prom_printf("fixup_doit: YIEEE, cannot find "
- "PBM ranges\n");
- }
- pdev->base_address[ridx] = (unsigned long)__va(pci_addr);
-
- /* Preserve I/O space bit. */
- if(io) {
- pdev->base_address[ridx] |= 1;
- IO_seen = 1;
- } else {
- MEM_seen = 1;
- }
- }
- }
-
- /*
- * Handle PCI_ROM_ADDRESS.
- */
- breg = PCI_ROM_ADDRESS;
- base = (unsigned int)pdev->rom_address;
-
- if(pdev->rom_address > PAGE_OFFSET)
- goto rom_address_done;
-
- base &= PCI_ROM_ADDRESS_MASK;
- offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg;
- vp = pci_find_vma(pbm, base, offset, 0);
- if(!vp || vp->start > base) {
- unsigned int size, new_base;
-
- pci_read_config_dword(pdev, breg, &rtmp);
- pci_write_config_dword(pdev, breg, 0xffffffff);
- pci_read_config_dword(pdev, breg, &size);
- size &= ~1;
- size = (~(size) + 1);
- if(!size)
- goto rom_address_done;
-
- new_base = 0;
- for(vp = pci_find_vma(pbm, new_base, 0, 0); ; vp = vp->next) {
- if(!vp || new_base + size <= vp->start)
- break;
- new_base = (vp->end + (size - 1)) & ~(size-1);
- }
- if(vp && (new_base + size > vp->start)) {
- prom_printf("PCI: Impossible full MEM space.\n");
- prom_halt();
- }
- vp = pci_vma_alloc();
- vp->start = new_base;
- vp->end = vp->start + size - 1;
- vp->offset = offset;
-
- pci_add_vma(pbm, vp, 0);
-
-#ifdef FIXUP_VMA_DEBUG
- dprintf("%02x.%02x.%x: BaseReg %02x",
- pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn),
- breg);
- dprintf(" %s vma [%08x,%08x]\n",
- "ROM", vp->start, vp->end);
-#endif
-
- rtmp = new_base;
- pci_read_config_dword(pdev, breg, &base);
- rtmp &= ~(base & ~PCI_ROM_ADDRESS_MASK);
- pci_write_config_dword(pdev, breg, rtmp);
-
- /* Apply PBM ranges and update pci_dev. */
- pci_addr = new_base;
- for(rng = 0; rng < pbm->num_pbm_ranges; rng++) {
- struct linux_prom_pci_ranges *rp;
- int rspace;
-
- rp = &pbm->pbm_ranges[rng];
- rspace = (rp->child_phys_hi >> 24) & 3;
- if(rspace != 2)
- continue;
- pci_addr += ((u64)rp->parent_phys_lo);
- pci_addr += (((u64)rp->parent_phys_hi)<<32UL);
- break;
- }
- if(rng == pbm->num_pbm_ranges) {
- /* AIEEE */
- prom_printf("fixup_doit: YIEEE, cannot find "
- "PBM ranges\n");
- }
- pdev->rom_address = (unsigned long)__va(pci_addr);
- pdev->rom_address &= ~(base & ~PCI_ROM_ADDRESS_MASK);
- MEM_seen = 1;
- }
- rom_address_done:
-
- }
- if(IO_seen || MEM_seen) {
- unsigned int l;
-
- pci_read_config_dword(pdev, PCI_COMMAND, &l);
-#ifdef FIXUP_REGS_DEBUG
- dprintf("[");
-#endif
- if(IO_seen) {
-#ifdef FIXUP_REGS_DEBUG
- dprintf("IO ");
-#endif
- l |= PCI_COMMAND_IO;
- }
- if(MEM_seen) {
-#ifdef FIXUP_REGS_DEBUG
- dprintf("MEM");
-#endif
- l |= PCI_COMMAND_MEMORY;
- }
-#ifdef FIXUP_REGS_DEBUG
- dprintf("]");
-#endif
- pci_write_config_dword(pdev, PCI_COMMAND, l);
- }
-
-#ifdef FIXUP_REGS_DEBUG
- dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device);
- for(preg = 0; preg < 6; preg++) {
- if(pdev->base_address[preg] != 0)
- dprintf("%d[%016lx] ", preg, pdev->base_address[preg]);
- }
- dprintf("\n");
-#endif
-}
-
-#define imap_offset(__member) \
- ((unsigned long)(&(((struct psycho_regs *)0)->__member)))
-
-static unsigned long __init psycho_pcislot_imap_offset(unsigned long ino)
-{
- unsigned int bus, slot;
-
- bus = (ino & 0x10) >> 4;
- slot = (ino & 0x0c) >> 2;
-
- if(bus == 0) {
- switch(slot) {
- case 0:
- return imap_offset(imap_a_slot0);
- case 1:
- return imap_offset(imap_a_slot1);
- case 2:
- return imap_offset(imap_a_slot2);
- case 3:
- default:
- return imap_offset(imap_a_slot3);
- }
- } else {
- switch(slot) {
- case 0:
- return imap_offset(imap_b_slot0);
- case 1:
- return imap_offset(imap_b_slot1);
- case 2:
- return imap_offset(imap_b_slot2);
- case 3:
- default:
- return imap_offset(imap_b_slot3);
- }
- }
-}
-
-/* Exported for EBUS probing layer. */
-unsigned int __init psycho_irq_build(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int ino)
-{
- unsigned long imap_off;
- int need_dma_sync = 0;
-
- ino &= PSYCHO_IMAP_INO;
-
- /* Compute IMAP register offset, generic IRQ layer figures out
- * the ICLR register address as this is simple given the 32-bit
- * irq number and IMAP register address.
- */
- if((ino & 0x20) == 0)
- imap_off = psycho_pcislot_imap_offset(ino);
- else {
- switch(ino) {
- case 0x20:
- /* Onboard SCSI. */
- imap_off = imap_offset(imap_scsi);
- break;
-
- case 0x21:
- /* Onboard Ethernet (ie. CheerIO/HME) */
- imap_off = imap_offset(imap_eth);
- break;
-
- case 0x22:
- /* Onboard Parallel Port */
- imap_off = imap_offset(imap_bpp);
- break;
-
- case 0x23:
- /* Audio Record */
- imap_off = imap_offset(imap_au_rec);
- break;
-
- case 0x24:
- /* Audio Play */
- imap_off = imap_offset(imap_au_play);
- break;
-
- case 0x25:
- /* Power Fail */
- imap_off = imap_offset(imap_pfail);
- break;
-
- case 0x26:
- /* Onboard KBD/MOUSE/SERIAL */
- imap_off = imap_offset(imap_kms);
- break;
-
- case 0x27:
- /* Floppy (ie. fdthree) */
- imap_off = imap_offset(imap_flpy);
- break;
-
- case 0x28:
- /* Spare HW INT */
- imap_off = imap_offset(imap_shw);
- break;
-
- case 0x29:
- /* Onboard Keyboard (only) */
- imap_off = imap_offset(imap_kbd);
- break;
-
- case 0x2a:
- /* Onboard Mouse (only) */
- imap_off = imap_offset(imap_ms);
- break;
-
- case 0x2b:
- /* Onboard Serial (only) */
- imap_off = imap_offset(imap_ser);
- break;
-
- case 0x2c:
- /* Onboard Timer 0 */
- imap_off = imap_offset(imap_tim0);
- break;
-
- case 0x2d:
- /* Onboard Timer 1 */
- imap_off = imap_offset(imap_tim1);
- break;
-
- case 0x2e:
- /* Psycho UE Interrupt */
- imap_off = imap_offset(imap_ue);
- break;
-
- case 0x2f:
- /* Psycho CE Interrupt */
- imap_off = imap_offset(imap_ce);
- break;
-
- case 0x30:
- /* Psycho PCI A Error Interrupt */
- imap_off = imap_offset(imap_a_err);
- break;
-
- case 0x31:
- /* Psycho PCI B Error Interrupt */
- imap_off = imap_offset(imap_b_err);
- break;
-
- case 0x32:
- /* Power Management */
- imap_off = imap_offset(imap_pmgmt);
- break;
-
- default:
- /* We don't expect anything else.
- */
- prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino);
- prom_halt();
- };
- }
- imap_off -= imap_offset(imap_a_slot0);
-
- if (apb_present(pbm->parent) && (pdev->bus->number != pbm->pci_first_busno)) {
- need_dma_sync = 1;
- }
-
- return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync);
-}
-
-static int __init pbm_intmap_match(struct linux_pbm_info *pbm,
- struct pci_dev *pdev,
- struct linux_prom_pci_registers *preg,
- unsigned int *interrupt)
-{
- struct linux_prom_pci_registers ppreg;
- unsigned int hi, mid, lo, irq;
- int i;
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("pbm_intmap_match: ");
-#endif
- if (!pbm->num_pbm_intmap) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No intmap UPA[%x:%c]\n",
- pbm->parent->upa_portid,
- (pbm == &pbm->parent->pbm_A) ? 'A' : 'B');
-#endif
- return 0;
- }
- /*
- * Underneath a bridge, use register of parent bridge.
- */
- if (pdev->bus->number != pbm->pci_first_busno) {
- struct pcidev_cookie *pcp;
- int node, offset;
- char prom_name[64];
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("UnderBridge, ");
-#endif
- pcp = pdev->bus->self->sysdata;
- if (!pcp) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No bus PCP\n");
-#endif
- goto out;
- }
- node = pcp->prom_node;
-
- i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg));
- if(i == 0 || i == -1) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No reg property.\n");
-#endif
- goto out;
- }
- /*
- * Did PROM know better and assign an interrupt different
- * to #INTA to the device? - We test here for presence of
- * FCODE on the card, in this case we assume PROM has set
- * correct 'interrupts' property, unless it is quadhme.
- */
- pcp = pdev->sysdata;
- if (!pcp) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No dev PCP\n");
-#endif
- goto out;
- }
- node = pcp->prom_node;
-
- offset = prom_getint(node, "fcode-rom-offset");
- prom_getstring(node, "name", prom_name, sizeof(prom_name));
- if (offset == -1 ||
- !strcmp(prom_name, "SUNW,qfe") ||
- !strcmp(prom_name, "qfe")) {
- /*
- * No, use low slot number bits of child as IRQ line.
- */
- *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1;
- }
- preg = &ppreg;
- }
-
- hi = preg->phys_hi & pbm->pbm_intmask.phys_hi;
- mid = preg->phys_mid & pbm->pbm_intmask.phys_mid;
- lo = preg->phys_lo & pbm->pbm_intmask.phys_lo;
- irq = *interrupt & pbm->pbm_intmask.interrupt;
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("intmap_match: [%02x.%02x.%x] key: [%08x.%08x.%08x.%08x] ",
- pdev->bus->number, pdev->devfn >> 3, pdev->devfn & 7,
- hi, mid, lo, irq);
-#endif
- for (i = 0; i < pbm->num_pbm_intmap; i++) {
- if ((pbm->pbm_intmap[i].phys_hi == hi) &&
- (pbm->pbm_intmap[i].phys_mid == mid) &&
- (pbm->pbm_intmap[i].phys_lo == lo) &&
- (pbm->pbm_intmap[i].interrupt == irq)) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("irq: [%08x]", pbm->pbm_intmap[i].cinterrupt);
-#endif
- *interrupt = pbm->pbm_intmap[i].cinterrupt;
- return 1;
- }
- }
-
-out:
- prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ",
- pdev->bus->number, pdev->devfn);
- prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
- preg->phys_hi, preg->phys_mid, preg->phys_lo, *interrupt);
- prom_halt();
-}
-
-static void __init fixup_irq(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *preg,
- int node)
-{
- unsigned int prom_irq, portid = pbm->parent->upa_portid;
- int err;
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("fixup_irq[%04x:%04x]: ", pdev->vendor, pdev->device);
-#endif
- err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq));
- if(err == 0 || err == -1) {
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("No interrupts property.\n");
-#endif
- pdev->irq = 0;
- return;
- }
-
- /* See if fully specified already (ie. for onboard devices like hme) */
- if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) {
- pdev->irq = psycho_irq_build(pbm, pdev, prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("fully specified prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
-#endif
- /* See if onboard device interrupt (i.e. bit 5 set) */
- } else if((prom_irq & PSYCHO_IMAP_INO) & 0x20) {
- pdev->irq = psycho_irq_build(pbm, pdev,
- (pbm->parent->upa_portid << 6)
- | prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("partially specified prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
-#endif
- /* See if we find a matching interrupt-map entry. */
- } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) {
- pdev->irq = psycho_irq_build(pbm, pdev,
- (pbm->parent->upa_portid << 6)
- | prom_irq);
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]",
- prom_irq, pdev->irq);
-#endif
- } else {
- unsigned int bus, slot, line;
-
- bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0;
-
- /* Use the given interrupt property value as the line if it
- * is non-zero and legal. Legal encodings are INTA=1, INTB=2,
- * INTC=3, INTD=4 as per PCI OBP binding spec version 2.1 -DaveM
- */
- if(prom_irq > 0 && prom_irq < 5) {
- line = ((prom_irq - 1) & 3);
- } else {
- unsigned char pci_irq_line;
-
- /* The generic PCI probing layer will read the
- * interrupt line into pdev->irq if the interrupt
- * pin is non-zero, so we have to explicitly fetch
- * the pin here to be certain (the interrupt line is
- * typically left at zero by OBP).
- */
- pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line);
- line = ((pci_irq_line - 1) & 3);
- }
-
- /* Slot determination is only slightly complex. Handle
- * the easy case first.
- */
- if(pdev->bus->number == pbm->pci_first_busno) {
- if(pbm == &pbm->parent->pbm_A)
- slot = (pdev->devfn >> 3) - 1;
- else
- slot = (pdev->devfn >> 3) - 2;
- } else {
- /* Underneath a bridge, use slot number of parent
- * bridge.
- */
- if(pbm == &pbm->parent->pbm_A)
- slot = (pdev->bus->self->devfn >> 3) - 1;
- else
- slot = (pdev->bus->self->devfn >> 3) - 2;
-
- /* Use low slot number bits of child as IRQ line. */
- line = (pdev->devfn >> 3) & 0x03;
- }
- slot = (slot << 2);
-
- pdev->irq = psycho_irq_build(pbm, pdev,
- (((portid << 6) & PSYCHO_IMAP_IGN)
- | (bus | slot | line)));
-
-#ifdef FIXUP_IRQ_DEBUG
- do {
- unsigned char iline, ipin;
-
- pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &ipin);
- pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &iline);
- dprintf("FIXED portid[%x] bus[%x] slot[%x] line[%x] "
- "irq[%x] iline[%x] ipin[%x] prom_irq[%x]",
- portid, bus>>4, slot>>2, line, pdev->irq,
- iline, ipin, prom_irq);
- } while(0);
-#endif
- }
-
- /*
- * Write the INO to config space PCI_INTERRUPT_LINE.
- */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
- pdev->irq & PCI_IRQ_INO);
-
-#ifdef FIXUP_IRQ_DEBUG
- dprintf("\n");
-#endif
-}
-
-static void __init fixup_doit(struct pci_dev *pdev,
- struct linux_pbm_info *pbm,
- struct linux_prom_pci_registers *pregs,
- int nregs,
- int node)
-{
- struct linux_prom_pci_registers assigned[PROMREG_MAX];
- int numaa, err;
-
- /* Get assigned addresses, if any. */
- err = prom_getproperty(node, "assigned-addresses",
- (char *)&assigned[0], sizeof(assigned));
- if(err == 0 || err == -1)
- numaa = 0;
- else
- numaa = (err / sizeof(struct linux_prom_pci_registers));
-
- /* First, scan and fixup base registers. */
- fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa);
-
- /* Next, fixup interrupt numbers. */
- fixup_irq(pdev, pbm, &pregs[0], node);
-}
-
-static void __init fixup_pci_dev(struct pci_dev *pdev,
- struct pci_bus *pbus,
- struct linux_pbm_info *pbm)
-{
- struct linux_prom_pci_registers pregs[PROMREG_MAX];
- struct pcidev_cookie *pcp = pdev->sysdata;
- int node, nregs, err;
-
- /* If this is a PCI bridge, we must program it. */
- if(pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
- unsigned short cmd;
-
- /* First, enable bus mastering. */
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
-
- /* Now, set cache line size to 64-bytes.
- * NOTE: Cache line size is in 32-bit word units.
- */
- pci_write_config_byte(pdev,
- PCI_CACHE_LINE_SIZE,
- (64 / sizeof(u32)));
- }
-
- /* Ignore if this is one of the PBM's, EBUS, or a
- * sub-bridge underneath the PBM. We only need to fixup
- * true devices.
- */
- if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) ||
- (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) ||
- (pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
- (pcp == NULL)) {
- /*
- * Prevent access to PCI_ROM_ADDRESS, in case present
- * as we don't fixup the address.
- */
- if (pdev->rom_address) {
- pci_write_config_dword(pdev, PCI_ROM_ADDRESS, 0);
- pdev->rom_address = 0;
- }
- return;
- }
-
- node = pcp->prom_node;
-
- err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
- if(err == 0 || err == -1) {
- prom_printf("Cannot find REG for pci_dev\n");
- prom_halt();
- }
-
- nregs = (err / sizeof(pregs[0]));
-
- fixup_doit(pdev, pbm, &pregs[0], nregs, node);
-
- /* Enable bus mastering on IDE interfaces. */
- if ((pdev->class >> 8 == PCI_CLASS_STORAGE_IDE)
- && (pdev->class & 0x80)) {
- unsigned short cmd;
-
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
- }
-}
-
-static void __init fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
-{
- struct pci_dev *pdev;
-
- for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
- fixup_pci_dev(pdev, pbus, pbm);
-
- for(pbus = pbus->children; pbus; pbus = pbus->next)
- fixup_pci_bus(pbus, pbm);
-}
-
-static void __init fixup_addr_irq(struct linux_pbm_info *pbm)
-{
- struct pci_bus *pbus = &pbm->pci_bus;
-
- /* Work through top level devices (not bridges, those and their
- * devices are handled specially in the next loop).
- */
- fixup_pci_bus(pbus, pbm);
-}
-
-/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
- * We use OBP for most of this work.
- */
-static void __init psycho_final_fixup(struct linux_psycho *psycho)
-{
- /* Second, fixup base address registers and IRQ lines... */
- if (psycho->pbm_A.parent)
- fixup_addr_irq(&psycho->pbm_A);
- if (psycho->pbm_B.parent)
- fixup_addr_irq(&psycho->pbm_B);
-}
-
-/* Reorder the pci_dev chain, so that onboard devices come first
- and then come the pluggable cards. */
-void __init psycho_reorder_devs(void)
-{
- struct pci_dev **pci_onboard = &pci_devices;
- struct pci_dev **pci_tail = &pci_devices;
- struct pci_dev *pdev = pci_devices, *pci_other = NULL;
-
- while (pdev) {
- if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) {
- if (pci_other) {
- *pci_onboard = pdev;
- pci_onboard = &pdev->next;
- pdev = pdev->next;
- *pci_onboard = pci_other;
- *pci_tail = pdev;
- continue;
- } else
- pci_onboard = &pdev->next;
- } else if (!pci_other)
- pci_other = pdev;
- pci_tail = &pdev->next;
- pdev = pdev->next;
- }
-}
-
-void __init pcibios_fixup(void)
-{
- struct linux_psycho *psycho;
-
- pci_probe_enable = 1;
-
- /* XXX Really this should be per-PSYCHO, but the config space
- * XXX reads and writes give us no way to know which PSYCHO
- * XXX in which the config space reads should occur.
- * XXX
- * XXX Further thought says that we cannot change this generic
- * XXX interface, else we'd break xfree86 and other parts of the
- * XXX kernel (but whats more important is breaking userland for
- * XXX the ix86/Alpha/etc. people). So we should define our own
- * XXX internal extension initially, we can compile our own user
- * XXX apps that need to get at PCI configuration space.
- */
-
- for (psycho = psycho_root; psycho; psycho = psycho->next) {
- /* Probe bus on builtin PCI. */
- if (apb_present(psycho)) {
- sabre_probe(psycho);
- } else {
- /* Probe busses under PBM B. */
- pbm_probe(&psycho->pbm_B);
-
- /* Probe busses under PBM A. */
- pbm_probe(&psycho->pbm_A);
- }
- }
-
- /* Walk all PCI devices found. For each device, and
- * PCI bridge which is not one of the PSYCHO PBM's, fill in the
- * sysdata with a pointer to the PBM (for pci_bus's) or
- * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's).
- */
- for (psycho = psycho_root; psycho; psycho = psycho->next) {
- if (apb_present(psycho))
- sabre_cookie_fillin(psycho);
-
- fill_in_pbm_cookies(&psycho->pbm_A.pci_bus,
- &psycho->pbm_A,
- psycho->pbm_A.prom_node);
- fill_in_pbm_cookies(&psycho->pbm_B.pci_bus,
- &psycho->pbm_B,
- psycho->pbm_B.prom_node);
-
- /* See what OBP has taken care of already. */
- record_assignments(&psycho->pbm_A);
- record_assignments(&psycho->pbm_B);
-
- /* Now, fix it all up. */
- psycho_final_fixup(psycho);
- }
-
- if (psycho_reorder & PSYCHO_REORDER_ONBOARDFIRST)
- psycho_reorder_devs();
-
- return ebus_init();
-}
-
-/* "PCI: The emerging standard..." 8-( */
-volatile int pci_poke_in_progress = 0;
-volatile int pci_poke_faulted = 0;
-
-/* XXX Current PCI support code is broken, it assumes one master PCI config
- * XXX space exists, on Ultra we can have many of them, especially with
- * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
- */
-static void *
-pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus,
- unsigned char devfn, unsigned char where)
-{
- unsigned long ret;
-
- if (!pbm)
- return NULL;
-
- ret = (unsigned long) pbm->parent->pci_config_space;
-
- ret |= (1 << 24);
- ret |= (bus << 16);
- ret |= (devfn << 8);
- ret |= where;
-
- return (void *)ret;
-}
-
-static inline int
-out_of_range(struct linux_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) > 8) ||
- ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) ||
- (pci_probe_enable == 0));
-}
-
-static inline int
-sabre_out_of_range(unsigned char devfn)
-{
- return ((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
- ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
- (PCI_SLOT(devfn) > 1);
-}
-
-static int
-sabre_read_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value)
-{
- if (bus)
- return pbm_read_config_byte(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn)) {
- *value = 0xff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- if (where < 8) {
- unsigned short tmp;
-
- pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
- if (where & 1)
- *value = tmp >> 8;
- else
- *value = tmp & 0xff;
- return PCIBIOS_SUCCESSFUL;
- } else
- return pbm_read_config_byte(pbm, bus, devfn, where, value);
-}
-
-static int
-sabre_read_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value)
-{
- if (bus)
- return pbm_read_config_word(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn)) {
- *value = 0xffff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- if (where < 8)
- return pbm_read_config_word(pbm, bus, devfn, where, value);
- else {
- unsigned char tmp;
-
- pbm_read_config_byte(pbm, bus, devfn, where, &tmp);
- *value = tmp;
- pbm_read_config_byte(pbm, bus, devfn, where + 1, &tmp);
- *value |= tmp << 8;
- return PCIBIOS_SUCCESSFUL;
- }
-}
-
-static int
-sabre_read_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value)
-{
- unsigned short tmp;
-
- if (bus)
- return pbm_read_config_dword(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn)) {
- *value = 0xffffffff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- sabre_read_config_word(pbm, bus, devfn, where, &tmp);
- *value = tmp;
- sabre_read_config_word(pbm, bus, devfn, where + 2, &tmp);
- *value |= tmp << 16;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-sabre_write_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value)
-{
- if (bus)
- return pbm_write_config_byte(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where < 8) {
- unsigned short tmp;
-
- pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp);
- if (where & 1) {
- value &= 0x00ff;
- value |= tmp << 8;
- } else {
- value &= 0xff00;
- value |= tmp;
- }
- return pbm_write_config_word(pbm, bus, devfn, where & ~1, tmp);
- } else
- return pbm_write_config_byte(pbm, bus, devfn, where, value);
-}
-
-static int
-sabre_write_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value)
-{
- if (bus)
- return pbm_write_config_word(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn))
- return PCIBIOS_SUCCESSFUL;
-
- if (where < 8)
- return pbm_write_config_word(pbm, bus, devfn, where, value);
- else {
- pbm_write_config_byte(pbm, bus, devfn, where, value & 0xff);
- pbm_write_config_byte(pbm, bus, devfn, where + 1, value >> 8);
- return PCIBIOS_SUCCESSFUL;
- }
-}
-
-static int
-sabre_write_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value)
-{
- if (bus)
- return pbm_write_config_dword(pbm, bus, devfn, where, value);
-
- if (sabre_out_of_range(devfn))
- return PCIBIOS_SUCCESSFUL;
-
- sabre_write_config_word(pbm, bus, devfn, where, value & 0xffff);
- sabre_write_config_word(pbm, bus, devfn, where + 2, value >> 16);
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_read_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value)
-{
- unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where);
- unsigned int trapped;
- unsigned char byte;
-
- *value = 0xff;
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- pci_poke_in_progress = 1;
- pci_poke_faulted = 0;
- __asm__ __volatile__("membar #Sync\n\t"
- "lduba [%1] %2, %0\n\t"
- "membar #Sync"
- : "=r" (byte)
- : "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- trapped = pci_poke_faulted;
- pci_poke_faulted = 0;
- if(!trapped)
- *value = byte;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_read_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value)
-{
- unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where);
- unsigned int trapped;
- unsigned short word;
-
- *value = 0xffff;
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (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_poke_in_progress = 1;
- pci_poke_faulted = 0;
- __asm__ __volatile__("membar #Sync\n\t"
- "lduha [%1] %2, %0\n\t"
- "membar #Sync"
- : "=r" (word)
- : "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- trapped = pci_poke_faulted;
- pci_poke_faulted = 0;
- if(!trapped)
- *value = word;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_read_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value)
-{
- unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where);
- unsigned int word, trapped;
-
- *value = 0xffffffff;
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (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_poke_in_progress = 1;
- pci_poke_faulted = 0;
- __asm__ __volatile__("membar #Sync\n\t"
- "lduwa [%1] %2, %0\n\t"
- "membar #Sync"
- : "=r" (word)
- : "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- trapped = pci_poke_faulted;
- pci_poke_faulted = 0;
- if(!trapped)
- *value = word;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_write_config_byte(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value)
-{
- unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where);
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- pci_poke_in_progress = 1;
-
- /* Endianness doesn't matter but we have to get the memory
- * barriers in there so...
- */
- __asm__ __volatile__("membar #Sync\n\t"
- "stba %0, [%1] %2\n\t"
- "membar #Sync\n\t"
- : /* no outputs */
- : "r" (value), "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_write_config_word(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value)
-{
- unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where);
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (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_poke_in_progress = 1;
- __asm__ __volatile__("membar #Sync\n\t"
- "stha %0, [%1] %2\n\t"
- "membar #Sync\n\t"
- : /* no outputs */
- : "r" (value), "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pbm_write_config_dword(struct linux_pbm_info *pbm,
- unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value)
-{
- unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where);
-
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (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_poke_in_progress = 1;
- __asm__ __volatile__("membar #Sync\n\t"
- "stwa %0, [%1] %2\n\t"
- "membar #Sync"
- : /* no outputs */
- : "r" (value), "r" (addr), "i" (ASI_PL));
- pci_poke_in_progress = 0;
- return PCIBIOS_SUCCESSFUL;
-}
-
-int pcibios_read_config_byte (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char *value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_read_config_byte(pbm, bus, devfn, where, value);
- return pbm_read_config_byte(pbm, bus, devfn, where, value);
-}
-
-int pcibios_read_config_word (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short *value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_read_config_word(pbm, bus, devfn, where, value);
- return pbm_read_config_word(pbm, bus, devfn, where, value);
-}
-
-int pcibios_read_config_dword (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int *value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_read_config_dword(pbm, bus, devfn, where, value);
- return pbm_read_config_dword(pbm, bus, devfn, where, value);
-}
-
-int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned char value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_write_config_byte(pbm, bus, devfn, where, value);
- return pbm_write_config_byte(pbm, bus, devfn, where, value);
-}
-
-int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned short value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_write_config_word(pbm, bus, devfn, where, value);
- return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value);
-}
-
-int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
- unsigned char where, unsigned int value)
-{
- struct linux_pbm_info *pbm = bus2pbm[bus];
-
- if (pbm && pbm->parent && apb_present(pbm->parent))
- return sabre_write_config_dword(pbm, bus, devfn, where, value);
- return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value);
-}
-
-asmlinkage int sys_pciconfig_read(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- unsigned char ubyte;
- unsigned short ushort;
- unsigned int uint;
- int err = 0;
-
- if(!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- lock_kernel();
- switch(len) {
- case 1:
- pcibios_read_config_byte(bus, dfn, off, &ubyte);
- put_user(ubyte, (unsigned char *)buf);
- break;
- case 2:
- pcibios_read_config_word(bus, dfn, off, &ushort);
- put_user(ushort, (unsigned short *)buf);
- break;
- case 4:
- pcibios_read_config_dword(bus, dfn, off, &uint);
- put_user(uint, (unsigned int *)buf);
- break;
-
- default:
- err = -EINVAL;
- break;
- };
- unlock_kernel();
-
- return err;
-}
-
-asmlinkage int sys_pciconfig_write(unsigned long bus,
- unsigned long dfn,
- unsigned long off,
- unsigned long len,
- unsigned char *buf)
-{
- unsigned char ubyte;
- unsigned short ushort;
- unsigned int uint;
- int err = 0;
-
- if(!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- lock_kernel();
- switch(len) {
- case 1:
- err = get_user(ubyte, (unsigned char *)buf);
- if(err)
- break;
- pcibios_write_config_byte(bus, dfn, off, ubyte);
- break;
-
- case 2:
- err = get_user(ushort, (unsigned short *)buf);
- if(err)
- break;
- pcibios_write_config_byte(bus, dfn, off, ushort);
- break;
-
- case 4:
- err = get_user(uint, (unsigned int *)buf);
- if(err)
- break;
- pcibios_write_config_byte(bus, dfn, off, uint);
- break;
-
- default:
- err = -EINVAL;
- break;
-
- };
- unlock_kernel();
-
- return err;
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-}
-
-char * __init pcibios_setup(char *str)
-{
- if (!strcmp(str, "onboardfirst")) {
- psycho_reorder |= PSYCHO_REORDER_ONBOARDFIRST;
- return NULL;
- }
- if (!strcmp(str, "noreorder")) {
- psycho_reorder = 0;
- return NULL;
- }
- return str;
-}
-
-#endif
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 61a6a6bfa..c582be060 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -52,7 +52,7 @@ static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
static inline void
pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
{
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
if(put_user(value, (unsigned int *)addr))
return pt_error_return(regs, EFAULT);
} else {
@@ -114,7 +114,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned long addr2 = regs->u_regs[UREG_I4];
struct task_struct *child;
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
addr &= 0xffffffffUL;
data &= 0xffffffffUL;
addr2 &= 0xffffffffUL;
@@ -220,7 +220,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
- if(!(child->tss.flags & SPARC_FLAG_32BIT) &&
+ if(!(child->thread.flags & SPARC_FLAG_32BIT) &&
((request == PTRACE_READDATA64) ||
(request == PTRACE_WRITEDATA64) ||
(request == PTRACE_READTEXT64) ||
@@ -242,7 +242,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
int res, copied;
res = -EIO;
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
copied = access_process_vm(child, addr,
&tmp32, sizeof(tmp32), 0);
tmp64 = (unsigned long) tmp32;
@@ -267,7 +267,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
unsigned int tmp32;
int copied, res = -EIO;
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
tmp32 = data;
copied = access_process_vm(child, addr,
&tmp32, sizeof(tmp32), 1);
@@ -289,7 +289,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
case PTRACE_GETREGS: {
struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
- struct pt_regs *cregs = child->tss.kregs;
+ struct pt_regs *cregs = child->thread.kregs;
int rval;
if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
@@ -313,7 +313,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
case PTRACE_GETREGS64: {
struct pt_regs *pregs = (struct pt_regs *) addr;
- struct pt_regs *cregs = child->tss.kregs;
+ struct pt_regs *cregs = child->thread.kregs;
int rval;
if (__put_user(cregs->tstate, (&pregs->tstate)) ||
@@ -337,7 +337,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
case PTRACE_SETREGS: {
struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
- struct pt_regs *cregs = child->tss.kregs;
+ struct pt_regs *cregs = child->thread.kregs;
unsigned int psr, pc, npc, y;
int i;
@@ -370,7 +370,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
case PTRACE_SETREGS64: {
struct pt_regs *pregs = (struct pt_regs *) addr;
- struct pt_regs *cregs = child->tss.kregs;
+ struct pt_regs *cregs = child->thread.kregs;
unsigned long tstate, tpc, tnpc, y;
int i;
@@ -418,7 +418,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (copy_to_user(&fps->regs[0], fpregs,
(32 * sizeof(unsigned int))) ||
- __put_user(child->tss.xfsr[0], (&fps->fsr)) ||
+ __put_user(child->thread.xfsr[0], (&fps->fsr)) ||
__put_user(0, (&fps->fpqd)) ||
__put_user(0, (&fps->flags)) ||
__put_user(0, (&fps->extra)) ||
@@ -439,7 +439,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (copy_to_user(&fps->regs[0], fpregs,
(64 * sizeof(unsigned int))) ||
- __put_user(child->tss.xfsr[0], (&fps->fsr))) {
+ __put_user(child->thread.xfsr[0], (&fps->fsr))) {
pt_error_return(regs, EFAULT);
goto out;
}
@@ -468,11 +468,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
pt_error_return(regs, EFAULT);
goto out;
}
- child->tss.xfsr[0] &= 0xffffffff00000000UL;
- child->tss.xfsr[0] |= fsr;
- if (!(child->tss.fpsaved[0] & FPRS_FEF))
- child->tss.gsr[0] = 0;
- child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
+ child->thread.xfsr[0] &= 0xffffffff00000000UL;
+ child->thread.xfsr[0] |= fsr;
+ if (!(child->thread.fpsaved[0] & FPRS_FEF))
+ child->thread.gsr[0] = 0;
+ child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
pt_succ_return(regs, 0);
goto out;
}
@@ -486,13 +486,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
if (copy_from_user(fpregs, &fps->regs[0],
(64 * sizeof(unsigned int))) ||
- __get_user(child->tss.xfsr[0], (&fps->fsr))) {
+ __get_user(child->thread.xfsr[0], (&fps->fsr))) {
pt_error_return(regs, EFAULT);
goto out;
}
- if (!(child->tss.fpsaved[0] & FPRS_FEF))
- child->tss.gsr[0] = 0;
- child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
+ 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;
}
@@ -538,11 +538,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
goto out;
}
#ifdef DEBUG_PTRACE
- printk ("Original: %016lx %016lx\n", child->tss.kregs->tpc, child->tss.kregs->tnpc);
+ printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc);
printk ("Continuing with %016lx %016lx\n", addr, addr+4);
#endif
- child->tss.kregs->tpc = addr;
- child->tss.kregs->tnpc = addr + 4;
+ child->thread.kregs->tpc = addr;
+ child->thread.kregs->tnpc = addr + 4;
}
if (request == PTRACE_SYSCALL)
@@ -554,8 +554,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
#ifdef DEBUG_PTRACE
printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
child->pid, child->exit_code,
- child->tss.kregs->tpc,
- child->tss.kregs->tnpc);
+ child->thread.kregs->tpc,
+ child->thread.kregs->tnpc);
#endif
wake_up_process(child);
@@ -634,7 +634,7 @@ asmlinkage void syscall_trace(void)
return;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- current->tss.flags ^= MAGIC_CONSTANT;
+ current->thread.flags ^= MAGIC_CONSTANT;
notify_parent(current, SIGCHLD);
schedule();
/*
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 8444bc966..bb6d7398e 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.46 1999/05/25 16:53:20 jj Exp $
+/* $Id: rtrap.S,v 1.47 1999/07/30 09:35:23 davem Exp $
* rtrap.S: Preparing for return from trap on Sparc V9.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -11,6 +11,7 @@
#include <asm/spitfire.h>
#include <asm/head.h>
#include <asm/visasm.h>
+#include <asm/processor.h>
#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ)
@@ -39,13 +40,13 @@ rtrap: sethi %hi(bh_active), %l2
be,pt %icc, to_user
andn %l7, PSTATE_IE, %l7
- ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5
brz,pt %l5, rt_continue
srl %l5, 1, %o0
- add %g6, AOFF_task_tss + AOFF_thread_fpsaved, %l6
+ add %g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6
ldub [%l6 + %o0], %l2
sub %l5, 2, %l5
- add %g6, AOFF_task_tss + AOFF_thread_gsr, %o1
+ add %g6, AOFF_task_thread + AOFF_thread_gsr, %o1
andcc %l2, (FPRS_FEF|FPRS_DU), %g0
be,pt %icc, 2f
and %l2, FPRS_DL, %l6
@@ -55,7 +56,7 @@ rtrap: sethi %hi(bh_active), %l2
rd %fprs, %g5
wr %g5, FPRS_FEF, %fprs
ldub [%o1 + %o0], %g5
- add %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1
+ add %g6, AOFF_task_thread + AOFF_thread_xfsr, %o1
membar #StoreLoad | #LoadLoad
sll %o0, 8, %o2
add %g6, AOFF_task_fpregs, %o3
@@ -71,9 +72,8 @@ rtrap: sethi %hi(bh_active), %l2
ldda [%o4 + %o2] ASI_BLK_P, %f48
1: membar #Sync
ldx [%o1 + %o5], %fsr
-2: stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
-rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
- ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
+2: stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
+rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2
ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3
mov %g6, %o5
@@ -105,10 +105,11 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
wrpr %o2, %g0, %tnpc
brnz,pn %l3, kern_rtt
mov PRIMARY_CONTEXT, %l7
+ ldxa [%l7 + %l7] ASI_DMMU, %l0
stxa %l0, [%l7] ASI_DMMU
flush %o5
- rdpr %wstate, %l1
+ rdpr %wstate, %l1
rdpr %otherwin, %l2
srl %l1, 3, %l1
wrpr %l2, %g0, %canrestore
@@ -116,8 +117,8 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
wrpr %g0, %g0, %otherwin
restore
rdpr %canrestore, %g1
- wrpr %g1, 0x0, %cleanwin
+ wrpr %g1, 0x0, %cleanwin
retry
kern_rtt: restore
retry
@@ -125,8 +126,8 @@ to_user: ldx [%g6 + AOFF_task_need_resched], %l0
wrpr %l7, PSTATE_IE, %pstate
orcc %g0, %l0, %g0
be,a,pt %xcc, check_signal
- lduw [%g6 + AOFF_task_sigpending], %l0
+ lduw [%g6 + AOFF_task_sigpending], %l0
call schedule
nop
lduw [%g6 + AOFF_task_sigpending], %l0
@@ -146,7 +147,7 @@ check_signal: brz,a,pt %l0, check_user_wins
*/
check_user_wins:
wrpr %l7, 0x0, %pstate
- lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
brz,pt %o2, 1f
sethi %hi(TSTATE_PEF), %l6
@@ -162,8 +163,8 @@ check_user_wins:
call rtrap_check
add %sp, STACK_BIAS + REGWIN_SZ, %o0
#endif
- lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l5
- andcc %l5, 0x200, %g0
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %l5
+ andcc %l5, SPARC_FLAG_PERFCTR, %g0
be,pt %xcc, 1f
nop
@@ -172,7 +173,7 @@ check_user_wins:
call update_perfctrs
nop
wrpr %l7, 0x0, %pstate
- lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2
brz,pt %o2, 1f
sethi %hi(TSTATE_PEF), %l6
wrpr %l7, PSTATE_IE, %pstate
@@ -182,14 +183,14 @@ check_user_wins:
1:
andcc %l1, %l6, %g0
be,pt %xcc, rt_continue
- stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
+ stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
rd %fprs, %l5
andcc %l5, FPRS_FEF, %g0
be,a,pn %icc, rt_continue
andn %l1, %l6, %l1
- ba,pt %xcc, rt_continue+4
- lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+ ba,pt %xcc, rt_continue
+ nop
5: wr %g0, FPRS_FEF, %fprs
membar #StoreLoad | #LoadLoad
@@ -201,6 +202,6 @@ check_user_wins:
1: membar #Sync
wr %g0, FPRS_DU, %fprs
ba,pt %xcc, rt_continue
- stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth]
+ stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth]
#undef PTREGS_OFF
diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c
new file mode 100644
index 000000000..f72aeedd6
--- /dev/null
+++ b/arch/sparc64/kernel/semaphore.c
@@ -0,0 +1,129 @@
+/* $Id: semaphore.c,v 1.1 1999/08/30 10:00:50 davem Exp $
+ * Generic semaphore code. Buyer beware. Do your own
+ * specific changes in <asm/semaphore-helper.h>
+ */
+
+#include <linux/sched.h>
+#include <asm/semaphore-helper.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit. ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore. The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+void __up(struct semaphore *sem)
+{
+ wake_one_more(sem);
+ wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function. Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible. This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return. If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR \
+ struct task_struct *tsk = current; \
+ wait_queue_t wait; \
+ init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state) \
+ \
+ \
+ tsk->state = (task_state); \
+ add_wait_queue(&sem->wait, &wait); \
+ \
+ /* \
+ * Ok, we're set up. sem->count is known to be less than zero \
+ * so we must wait. \
+ * \
+ * We can let go the lock for purposes of waiting. \
+ * We re-acquire it after awaking so as to protect \
+ * all semaphore operations. \
+ * \
+ * If "up()" is called before we call waking_non_zero() then \
+ * we will catch it right away. If it is called later then \
+ * we will have to go through a wakeup cycle to catch it. \
+ * \
+ * Multiple waiters contend for the semaphore lock to see \
+ * who gets to gate through and who has to wait some more. \
+ */ \
+ for (;;) {
+
+#define DOWN_TAIL(task_state) \
+ tsk->state = (task_state); \
+ } \
+ tsk->state = TASK_RUNNING; \
+ remove_wait_queue(&sem->wait, &wait);
+
+void __down(struct semaphore * sem)
+{
+ DOWN_VAR
+ DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+ if (waking_non_zero(sem))
+ break;
+ schedule();
+ DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+ int ret = 0;
+ DOWN_VAR
+ DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+ ret = waking_non_zero_interruptible(sem, tsk);
+ if (ret)
+ {
+ if (ret == 1)
+ /* ret != 0 only if we get interrupted -arca */
+ ret = 0;
+ break;
+ }
+ schedule();
+ DOWN_TAIL(TASK_INTERRUPTIBLE)
+ return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+ return waking_non_zero_trylock(sem);
+}
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index d5e980ebf..066850108 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.44 1999/05/28 02:17:29 davem Exp $
+/* $Id: setup.c,v 1.47 1999/08/31 06:54:55 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -135,17 +135,21 @@ int prom_callback(long *args)
* Find process owning ctx, lookup mapping.
*/
struct task_struct *p;
+ struct mm_struct *mm = NULL;
pgd_t *pgdp;
pmd_t *pmdp;
pte_t *ptep;
- for_each_task(p)
- if (p->tss.ctx == ctx)
+ for_each_task(p) {
+ mm = p->mm;
+ if (CTX_HWBITS(mm->context) == ctx)
break;
- if (p->tss.ctx != ctx)
+ }
+ if (!mm ||
+ CTX_HWBITS(mm->context) != ctx)
goto done;
- pgdp = pgd_offset(p->mm, va);
+ pgdp = pgd_offset(mm, va);
if (pgd_none(*pgdp))
goto done;
pmdp = pmd_offset(pgdp, va);
@@ -312,7 +316,7 @@ int obp_system_intr(void)
* Process kernel command line switches that are specific to the
* SPARC or that require special low-level processing.
*/
-__initfunc(static void process_switch(char c))
+static void __init process_switch(char c)
{
switch (c) {
case 'd':
@@ -331,7 +335,7 @@ __initfunc(static void process_switch(char c))
}
}
-__initfunc(static void boot_flags_init(char *commands))
+static void __init boot_flags_init(char *commands)
{
while (*commands) {
/* Move to the start of the next "argument". */
@@ -434,8 +438,8 @@ static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
extern struct consw sun_serial_con;
-__initfunc(void setup_arch(char **cmdline_p,
- unsigned long * memory_start_p, unsigned long * memory_end_p))
+void __init setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
{
extern int serial_console; /* in console.c, of course */
unsigned long lowest_paddr, end_of_phys_memory = 0;
@@ -531,11 +535,10 @@ __initfunc(void setup_arch(char **cmdline_p,
#endif
/* Due to stack alignment restrictions and assumptions... */
- init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
- init_task.mm->mmap->vm_start = PAGE_OFFSET;
- init_task.mm->mmap->vm_end = *memory_end_p;
- init_task.mm->context = (unsigned long) NO_CONTEXT;
- init_task.tss.kregs = &fake_swapper_regs;
+ init_mm.mmap->vm_page_prot = PAGE_SHARED;
+ init_mm.mmap->vm_start = PAGE_OFFSET;
+ init_mm.mmap->vm_end = *memory_end_p;
+ init_task.thread.kregs = &fake_swapper_regs;
#ifdef CONFIG_IP_PNP
if (!ic_set_manually) {
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 247afc77c..672e83493 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.41 1999/06/14 05:23:58 davem Exp $
+/* $Id: signal.c,v 1.45 1999/09/06 08:21:59 jj Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -46,7 +46,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
asmlinkage void sparc64_set_context(struct pt_regs *regs)
{
struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
- struct thread_struct *tp = &current->tss;
+ struct thread_struct *tp = &current->thread;
mc_gregset_t *grp;
unsigned long pc, npc, tstate;
unsigned long fp, i7;
@@ -123,9 +123,9 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
err |= copy_from_user(fpregs+16,
((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
(sizeof(unsigned int) * 32));
- err |= __get_user(current->tss.xfsr[0],
+ err |= __get_user(current->thread.xfsr[0],
&(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
- err |= __get_user(current->tss.gsr[0],
+ err |= __get_user(current->thread.gsr[0],
&(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
regs->tstate &= ~TSTATE_PEF;
}
@@ -141,7 +141,7 @@ do_sigsegv:
asmlinkage void sparc64_get_context(struct pt_regs *regs)
{
struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0];
- struct thread_struct *tp = &current->tss;
+ struct thread_struct *tp = &current->thread;
mc_gregset_t *grp;
mcontext_t *mcp;
unsigned long fp, i7;
@@ -155,7 +155,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
#if 1
fenab = 0; /* IMO get_context is like any other system call, thus modifies FPU state -jj */
#else
- fenab = (current->tss.fpsaved[0] & FPRS_FEF);
+ fenab = (current->thread.fpsaved[0] & FPRS_FEF);
#endif
mcp = &ucp->uc_mcontext;
@@ -205,7 +205,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
unsigned long fprs;
- fprs = current->tss.fpsaved[0];
+ fprs = current->thread.fpsaved[0];
if (fprs & FPRS_DL)
err |= copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
(sizeof(unsigned int) * 32));
@@ -213,8 +213,8 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
err |= copy_to_user(
((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
(sizeof(unsigned int) * 32));
- err |= __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
- err |= __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
+ err |= __put_user(current->thread.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
+ err |= __put_user(current->thread.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
err |= __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
}
if (err)
@@ -226,34 +226,17 @@ do_sigsegv:
do_exit(SIGSEGV);
}
-/*
- * The new signal frame, intended to be used for Linux applications only
- * (we have enough in there to work with clone).
- * All the interesting bits are in the info field.
- */
-
-struct new_signal_frame {
- struct sparc_stackf ss;
- __siginfo_t info;
- __siginfo_fpu_t * fpu_save;
- unsigned int insns [2];
- unsigned long extramask[_NSIG_WORDS-1];
- __siginfo_fpu_t fpu_state;
-};
-
struct rt_signal_frame {
struct sparc_stackf ss;
siginfo_t info;
struct pt_regs regs;
- sigset_t mask;
__siginfo_fpu_t * fpu_save;
- unsigned int insns [2];
stack_t stack;
+ sigset_t mask;
__siginfo_fpu_t fpu_state;
};
/* Align macros */
-#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7)))
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
/*
@@ -265,7 +248,7 @@ asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs)
sigset_t saveset;
#ifdef CONFIG_SPARC32_COMPAT
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
extern asmlinkage void _sigpause32_common(old_sigset_t32,
struct pt_regs *);
_sigpause32_common(set, regs);
@@ -372,65 +355,12 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
if (fprs & FPRS_DU)
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
(sizeof(unsigned int) * 32));
- err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr);
- err |= __get_user(current->tss.gsr[0], &fpu->si_gsr);
- current->tss.fpsaved[0] |= fprs;
+ err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr);
+ err |= __get_user(current->thread.gsr[0], &fpu->si_gsr);
+ current->thread.fpsaved[0] |= fprs;
return err;
}
-void do_sigreturn(struct pt_regs *regs)
-{
- struct new_signal_frame *sf;
- unsigned long tpc, tnpc, tstate;
- __siginfo_fpu_t *fpu_save;
- sigset_t set;
- int err;
-
- synchronize_user_stack ();
- sf = (struct new_signal_frame *)
- (regs->u_regs [UREG_FP] + STACK_BIAS);
-
- /* 1. Make sure we are not getting garbage from the user */
- if (((unsigned long) sf) & 3)
- goto segv;
-
- err = get_user(tpc, &sf->info.si_regs.tpc);
- err |= __get_user(tnpc, &sf->info.si_regs.tnpc);
- err |= ((tpc | tnpc) & 3);
-
- /* 2. Restore the state */
- err |= __get_user(regs->y, &sf->info.si_regs.y);
- err |= __get_user(tstate, &sf->info.si_regs.tstate);
- err |= copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs));
-
- /* User can only change condition codes in %tstate. */
- regs->tstate &= ~(TSTATE_ICC);
- regs->tstate |= (tstate & TSTATE_ICC);
-
- err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state(regs, &sf->fpu_state);
-
- err |= __get_user(set.sig[0], &sf->info.si_mask);
- if (_NSIG_WORDS > 1)
- err |= __copy_from_user(&set.sig[1], &sf->extramask, sizeof(sf->extramask));
-
- if (err)
- goto segv;
-
- regs->tpc = tpc;
- regs->tnpc = tnpc;
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sigmask_lock);
- current->blocked = set;
- recalc_sigpending(current);
- spin_unlock_irq(&current->sigmask_lock);
- return;
-segv:
- send_sig(SIGSEGV, current, 1);
-}
-
void do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_signal_frame *sf;
@@ -503,15 +433,15 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
unsigned long fprs;
int err = 0;
- fprs = current->tss.fpsaved[0];
+ fprs = current->thread.fpsaved[0];
if (fprs & FPRS_DL)
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
(sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
(sizeof(unsigned int) * 32));
- err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr);
- err |= __put_user(current->tss.gsr[0], &fpu->si_gsr);
+ err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr);
+ err |= __put_user(current->thread.gsr[0], &fpu->si_gsr);
err |= __put_user(fprs, &fpu->si_fprs);
return err;
@@ -533,77 +463,6 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, u
}
static inline void
-new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
- int signo, sigset_t *oldset)
-{
- struct new_signal_frame *sf;
- int sigframe_size, err;
-
- /* 1. Make sure everything is clean */
- synchronize_user_stack();
- save_and_clear_fpu();
-
- sigframe_size = NF_ALIGNEDSZ;
-
- if (!(current->tss.fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
-
- sf = (struct new_signal_frame *)get_sigframe(ka, regs, sigframe_size);
-
- if (invalid_frame_pointer (sf, sigframe_size))
- goto sigill;
-
- if (current->tss.w_saved != 0) {
-#ifdef DEBUG_SIGNALS
- printk ("%s[%d]: Invalid user stack frame for "
- "signal delivery.\n", current->comm, current->pid);
-#endif
- goto sigill;
- }
-
- /* 2. Save the current process state */
- err = copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
-
- if (current->tss.fpsaved[0] & FPRS_FEF) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
- } else {
- err |= __put_user(0, &sf->fpu_save);
- }
-
- err |= __put_user(oldset->sig[0], &sf->info.si_mask);
- if (_NSIG_WORDS > 1)
- err |= __copy_to_user(sf->extramask, &oldset->sig[1],
- sizeof(sf->extramask));
-
- err |= copy_in_user((u64 *)sf,
- (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
- sizeof(struct reg_window));
- if (err)
- goto sigsegv;
-
- /* 3. signal handler back-trampoline and parameters */
- regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS;
- regs->u_regs[UREG_I0] = signo;
- regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
-
- /* 5. signal handler */
- regs->tpc = (unsigned long) ka->sa.sa_handler;
- regs->tnpc = (regs->tpc + 4);
-
- /* 4. return to kernel instructions */
- regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
- return;
-
-sigill:
- lock_kernel();
- do_exit(SIGILL);
-sigsegv:
- lock_kernel();
- do_exit(SIGSEGV);
-}
-
-static inline void
setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset, siginfo_t *info)
{
@@ -615,7 +474,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
save_and_clear_fpu();
sigframe_size = RT_ALIGNEDSZ;
- if (!(current->tss.fpsaved[0] & FPRS_FEF))
+ if (!(current->thread.fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct rt_signal_frame *)get_sigframe(ka, regs, sigframe_size);
@@ -623,7 +482,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
if (invalid_frame_pointer (sf, sigframe_size))
goto sigill;
- if (current->tss.w_saved != 0) {
+ if (current->thread.w_saved != 0) {
#ifdef DEBUG_SIGNALS
printk ("%s[%d]: Invalid user stack frame for "
"signal delivery.\n", current->comm, current->pid);
@@ -634,7 +493,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
/* 2. Save the current process state */
err = copy_to_user(&sf->regs, regs, sizeof (*regs));
- if (current->tss.fpsaved[0] & FPRS_FEF) {
+ if (current->thread.fpsaved[0] & FPRS_FEF) {
err |= save_fpu_state(regs, &sf->fpu_state);
err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
} else {
@@ -652,7 +511,12 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
(u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
sizeof(struct reg_window));
- err |= copy_to_user(&sf->info, info, sizeof(siginfo_t));
+ if (info)
+ err |= copy_to_user(&sf->info, info, sizeof(siginfo_t));
+ else {
+ err |= __put_user(signo, &sf->info.si_signo);
+ err |= __put_user(SI_NOINFO, &sf->info.si_code);
+ }
if (err)
goto sigsegv;
@@ -681,10 +545,7 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs)
{
- if(ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(ka, regs, signr, oldset, info);
- else
- new_setup_frame(ka, regs, signr, oldset);
+ setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL);
if(ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
if(!(ka->sa.sa_flags & SA_NOMASK)) {
@@ -785,7 +646,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
oldset = &current->blocked;
#ifdef CONFIG_SPARC32_COMPAT
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *,
unsigned long, int);
return do_signal32(oldset, regs, orig_i0, restart_syscall);
@@ -866,12 +727,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
- if(current->binfmt && current->binfmt->core_dump) {
- lock_kernel();
- if(current->binfmt->core_dump(signr, regs))
- exit_code |= 0x80;
- unlock_kernel();
- }
+ if (do_coredump(signr, regs))
+ exit_code |= 0x80;
#ifdef DEBUG_SIGNALS
/* Very useful to debug the dynamic linker */
printk ("Sig %d going...\n", (int)signr);
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index b1190d244..59388286f 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.48 1999/06/14 05:24:01 davem Exp $
+/* $Id: signal32.c,v 1.50 1999/07/30 09:35:25 davem Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -202,9 +202,9 @@ static inline int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu
err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
- err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr);
- err |= __get_user(current->tss.gsr[0], &fpu->si_gsr);
- current->tss.fpsaved[0] |= fprs;
+ err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr);
+ err |= __get_user(current->thread.gsr[0], &fpu->si_gsr);
+ current->thread.fpsaved[0] |= fprs;
return err;
}
@@ -285,7 +285,7 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
int err;
synchronize_user_stack();
- if (current->tss.new_signal)
+ if (current->thread.flags & SPARC_FLAG_NEWSIGNALS)
return do_new_sigreturn32(regs);
scptr = (struct sigcontext32 *)
@@ -489,20 +489,20 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
err |= __put_user(pc, &sc->sigc_pc);
err |= __put_user(npc, &sc->sigc_npc);
psr = tstate_to_psr (regs->tstate);
- if(current->tss.fpsaved[0] & FPRS_FEF)
+ if(current->thread.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
err |= __put_user(psr, &sc->sigc_psr);
err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
- err |= __put_user(current->tss.w_saved, &sc->sigc_oswins);
+ err |= __put_user(current->thread.w_saved, &sc->sigc_oswins);
#if 0
/* w_saved is not currently used... */
- if(current->tss.w_saved)
- for(window = 0; window < current->tss.w_saved; window++) {
+ if(current->thread.w_saved)
+ for(window = 0; window < current->thread.w_saved; window++) {
sc->sigc_spbuf[window] =
- (char *)current->tss.rwbuf_stkptrs[window];
+ (char *)current->thread.rwbuf_stkptrs[window];
err |= copy_to_user(&sc->sigc_wbuf[window],
- &current->tss.reg_window[window],
+ &current->thread.reg_window[window],
sizeof(struct reg_window));
}
else
@@ -511,15 +511,15 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
(u32 *)(regs->u_regs[UREG_FP]),
sizeof(struct reg_window32));
- current->tss.w_saved = 0; /* So process is allowed to execute. */
+ current->thread.w_saved = 0; /* So process is allowed to execute. */
err |= __put_user(signr, &sframep->sig_num);
if(signr == SIGSEGV ||
signr == SIGILL ||
signr == SIGFPE ||
signr == SIGBUS ||
signr == SIGEMT) {
- err |= __put_user(current->tss.sig_desc, &sframep->sig_code);
- err |= __put_user(current->tss.sig_address, &sframep->sig_address);
+ err |= __put_user(current->thread.sig_desc, &sframep->sig_code);
+ err |= __put_user(current->thread.sig_address, &sframep->sig_address);
} else {
err |= __put_user(0, &sframep->sig_code);
err |= __put_user(0, &sframep->sig_address);
@@ -544,15 +544,15 @@ static inline int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
unsigned long fprs;
int err = 0;
- fprs = current->tss.fpsaved[0];
+ fprs = current->thread.fpsaved[0];
if (fprs & FPRS_DL)
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
(sizeof(unsigned int) * 32));
if (fprs & FPRS_DU)
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
(sizeof(unsigned int) * 32));
- err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr);
- err |= __put_user(current->tss.gsr[0], &fpu->si_gsr);
+ err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr);
+ err |= __put_user(current->thread.gsr[0], &fpu->si_gsr);
err |= __put_user(fprs, &fpu->si_fprs);
return err;
@@ -572,7 +572,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
save_and_clear_fpu();
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->tss.fpsaved[0] & FPRS_FEF))
+ if (!(current->thread.fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct new_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
@@ -585,7 +585,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
goto sigill;
}
- if (current->tss.w_saved != 0) {
+ if (current->thread.w_saved != 0) {
#ifdef DEBUG_SIGNALS
printk ("%s[%d]: Invalid user stack frame for "
"signal delivery.\n", current->comm, current->pid);
@@ -598,7 +598,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
err |= __put_user(regs->y, &sf->info.si_regs.y);
psr = tstate_to_psr (regs->tstate);
- if(current->tss.fpsaved[0] & FPRS_FEF)
+ if(current->thread.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
err |= __put_user(psr, &sf->info.si_regs.psr);
for (i = 0; i < 16; i++)
@@ -738,7 +738,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
err |= __put_user(regs->tpc, &((*gr) [SVR4_PC]));
err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
psr = tstate_to_psr (regs->tstate);
- if(current->tss.fpsaved[0] & FPRS_FEF)
+ if(current->thread.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
err |= __put_user(psr, &((*gr) [SVR4_PSR]));
err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
@@ -760,7 +760,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
err |= __put_user((u32)(long)gw, &mc->gwin);
/* 2. Number of windows to restore at setcontext (): */
- err |= __put_user(current->tss.w_saved, &gw->count);
+ err |= __put_user(current->thread.w_saved, &gw->count);
/* 3. Save each valid window
* Currently, it makes a copy of the windows from the kernel copy.
@@ -774,23 +774,23 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
* to flush the user windows.
*/
#if 0
- for(window = 0; window < current->tss.w_saved; window++) {
+ for(window = 0; window < current->thread.w_saved; window++) {
err |= __put_user((int *) &(gw->win [window]),
(int **)gw->winptr +window );
err |= copy_to_user(&gw->win [window],
- &current->tss.reg_window [window],
+ &current->thread.reg_window [window],
sizeof (svr4_rwindow_t));
err |= __put_user(0, (int *)gw->winptr + window);
}
#endif
/* 4. We just pay attention to the gw->count field on setcontext */
- current->tss.w_saved = 0; /* So process is allowed to execute. */
+ current->thread.w_saved = 0; /* So process is allowed to execute. */
/* Setup the signal information. Solaris expects a bunch of
* information to be passed to the signal handler, we don't provide
* that much currently, should use those that David already
- * is providing with tss.sig_desc
+ * is providing with thread.sig_desc
*/
err |= __put_user(signr, &si->siginfo.signo);
err |= __put_user(SVR4_SINOINFO, &si->siginfo.code);
@@ -837,8 +837,8 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
synchronize_user_stack();
save_and_clear_fpu();
- if (current->tss.w_saved){
- printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved);
+ if (current->thread.w_saved){
+ printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->thread.w_saved);
do_exit (SIGSEGV);
}
err = clear_user(uc, sizeof (*uc));
@@ -863,7 +863,7 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
err |= __put_user(0, &uc->mcontext.greg [SVR4_PSR]);
#else
i = tstate_to_psr(regs->tstate) & ~PSR_EF;
- if (current->tss.fpsaved[0] & FPRS_FEF)
+ if (current->thread.fpsaved[0] & FPRS_FEF)
i |= PSR_EF;
err |= __put_user(i, &uc->mcontext.greg [SVR4_PSR]);
#endif
@@ -890,7 +890,7 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
/* Set the context for a svr4 application, this is Solaris way to sigreturn */
asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
{
- struct thread_struct *tp = &current->tss;
+ struct thread_struct *tp = &current->thread;
svr4_gregset_t *gr;
u32 pc, npc, psr;
sigset_t set;
@@ -990,7 +990,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
save_and_clear_fpu();
sigframe_size = RT_ALIGNEDSZ;
- if (!(current->tss.fpsaved[0] & FPRS_FEF))
+ if (!(current->thread.fpsaved[0] & FPRS_FEF))
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct rt_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
@@ -1003,7 +1003,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
goto sigill;
}
- if (current->tss.w_saved != 0) {
+ if (current->thread.w_saved != 0) {
#ifdef DEBUG_SIGNALS
printk ("%s[%d]: Invalid user stack frame for "
"signal delivery.\n", current->comm, current->pid);
@@ -1016,7 +1016,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
err |= __put_user(regs->tnpc, &sf->regs.npc);
err |= __put_user(regs->y, &sf->regs.y);
psr = tstate_to_psr (regs->tstate);
- if(current->tss.fpsaved[0] & FPRS_FEF)
+ if(current->thread.fpsaved[0] & FPRS_FEF)
psr |= PSR_EF;
err |= __put_user(psr, &sf->regs.psr);
for (i = 0; i < 16; i++)
@@ -1032,6 +1032,42 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
} else {
err |= __put_user(0, &sf->fpu_save);
}
+
+ err = __put_user (info->si_signo, &sf->info.si_signo);
+ err |= __put_user (info->si_errno, &sf->info.si_errno);
+ err |= __put_user (info->si_code, &sf->info.si_code);
+ if (info->si_code < 0)
+ err |= __copy_to_user (sf->info._sifields._pad, info->_sifields._pad, SI_PAD_SIZE);
+ else {
+ i = info->si_signo;
+ if (info->si_code == SI_USER)
+ i = SIGRTMIN;
+ switch (i) {
+ case SIGPOLL:
+ err |= __put_user (info->si_band, &sf->info.si_band);
+ err |= __put_user (info->si_fd, &sf->info.si_fd);
+ break;
+ case SIGCHLD:
+ err |= __put_user (info->si_pid, &sf->info.si_pid);
+ err |= __put_user (info->si_uid, &sf->info.si_uid);
+ err |= __put_user (info->si_status, &sf->info.si_status);
+ err |= __put_user (info->si_utime, &sf->info.si_utime);
+ err |= __put_user (info->si_stime, &sf->info.si_stime);
+ break;
+ case SIGSEGV:
+ case SIGILL:
+ case SIGFPE:
+ case SIGBUS:
+ case SIGEMT:
+ err |= __put_user ((long)info->si_addr, &sf->info.si_addr);
+ err |= __put_user (info->si_trapno, &sf->info.si_trapno);
+ break;
+ default:
+ err |= __put_user (info->si_pid, &sf->info.si_pid);
+ err |= __put_user (info->si_uid, &sf->info.si_uid);
+ break;
+ }
+ }
/* Setup sigaltstack */
err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
@@ -1040,13 +1076,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
switch (_NSIG_WORDS) {
case 4: seta.sig[7] = (oldset->sig[3] >> 32);
- seta.sig[6] = oldset->sig[3];
+ seta.sig[6] = oldset->sig[3];
case 3: seta.sig[5] = (oldset->sig[2] >> 32);
- seta.sig[4] = oldset->sig[2];
+ seta.sig[4] = oldset->sig[2];
case 2: seta.sig[3] = (oldset->sig[1] >> 32);
- seta.sig[2] = oldset->sig[1];
+ seta.sig[2] = oldset->sig[1];
case 1: seta.sig[1] = (oldset->sig[0] >> 32);
- seta.sig[0] = oldset->sig[0];
+ seta.sig[0] = oldset->sig[0];
}
err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t));
@@ -1113,7 +1149,7 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
else {
if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame32(ka, regs, signr, oldset, info);
- else if (current->tss.new_signal)
+ else if (current->thread.flags & SPARC_FLAG_NEWSIGNALS)
new_setup_frame32(ka, regs, signr, oldset);
else
setup_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset);
@@ -1256,13 +1292,13 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
if(signr != SIGCHLD)
continue;
- /* sys_wait4() grabs the master kernel lock, so
- * we need not do so, that sucker should be
- * threaded and would not be that difficult to
- * do anyways.
- */
- while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
- ;
+ /* sys_wait4() grabs the master kernel lock, so
+ * we need not do so, that sucker should be
+ * threaded and would not be that difficult to
+ * do anyways.
+ */
+ while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ ;
continue;
}
if(ka->sa.sa_handler == SIG_DFL) {
@@ -1291,14 +1327,8 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS:
- if(current->binfmt && current->binfmt->core_dump) {
- lock_kernel();
- if(current->binfmt &&
- current->binfmt->core_dump &&
- current->binfmt->core_dump(signr, regs))
- exit_code |= 0x80;
- unlock_kernel();
- }
+ if (do_coredump(signr, regs))
+ exit_code |= 0x80;
#ifdef DEBUG_SIGNALS
/* Very useful to debug dynamic linker problems */
printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
@@ -1318,10 +1348,10 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
{
struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff);
unsigned int ins[8];
-
+
while(rw &&
!(((unsigned long) rw) & 0x3)) {
- copy_from_user(ins, &rw->ins[0], sizeof(ins));
+ copy_from_user(ins, &rw->ins[0], sizeof(ins));
printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
rw = (struct reg_window32 *)(unsigned long)ins[6];
}
@@ -1380,7 +1410,7 @@ asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)
/* Now see if we want to update the new state. */
if (ssptr) {
void *ss_sp;
-
+
if (get_user((long)ss_sp, &ssptr->the_stack))
goto out;
/* If the current stack was set with sigaltstack, don't
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index a0e8f7e69..d1adeb2c7 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -7,13 +7,14 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/spinlock.h>
#include <asm/head.h>
#include <asm/ptrace.h>
@@ -23,7 +24,6 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
-#include <asm/spinlock.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
#include <asm/uaccess.h>
@@ -53,7 +53,7 @@ unsigned long cpu_present_map = 0;
int smp_num_cpus = 1;
int smp_threads_ready = 0;
-__initfunc(void smp_setup(char *str, int *ints))
+void __init smp_setup(char *str, int *ints)
{
/* XXX implement me XXX */
}
@@ -83,7 +83,7 @@ int smp_bogo(char *buf)
return len;
}
-__initfunc(void smp_store_cpu_info(int id))
+void __init smp_store_cpu_info(int id)
{
int i;
@@ -103,7 +103,7 @@ __initfunc(void smp_store_cpu_info(int id))
cpu_data[id].irq_worklists[i] = 0;
}
-__initfunc(void smp_commence(void))
+void __init smp_commence(void)
{
}
@@ -115,7 +115,7 @@ static volatile unsigned long callin_flag = 0;
extern void inherit_locked_prom_mappings(int save_p);
extern void cpu_probe(void);
-__initfunc(void smp_callin(void))
+void __init smp_callin(void)
{
int cpuid = hard_smp_processor_id();
@@ -151,13 +151,17 @@ __initfunc(void smp_callin(void))
/* Clear this or we will die instantly when we
* schedule back to this idler...
*/
- current->tss.flags &= ~(SPARC_FLAG_NEWCHILD);
+ current->thread.flags &= ~(SPARC_FLAG_NEWCHILD);
+
+ /* Attach to the address space of init_task. */
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
while(!smp_processors_ready)
membar("#LoadLoad");
}
-extern int cpu_idle(void *unused);
+extern int cpu_idle(void);
extern void init_IRQ(void);
void initialize_secondary(void)
@@ -169,7 +173,7 @@ int start_secondary(void *unused)
trap_init();
init_IRQ();
smp_callin();
- return cpu_idle(NULL);
+ return cpu_idle();
}
void cpu_panic(void)
@@ -188,7 +192,7 @@ extern unsigned long smp_trampoline;
*/
static struct task_struct *cpu_new_task = NULL;
-__initfunc(void smp_boot_cpus(void))
+void __init smp_boot_cpus(void)
{
int cpucount = 0, i;
@@ -216,9 +220,17 @@ __initfunc(void smp_boot_cpus(void))
entry += phys_base - KERNBASE;
cookie += phys_base - KERNBASE;
kernel_thread(start_secondary, NULL, CLONE_PID);
- p = task[++cpucount];
+ cpucount++;
+
+ p = init_task.prev_task;
+ init_tasks[cpucount] = p;
+
p->processor = i;
p->has_cpu = 1; /* we schedule the first task manually */
+
+ del_from_runqueue(p);
+ unhash_process(p);
+
callin_flag = 0;
for (no = 0; no < linux_num_cpus; no++)
if (linux_cpus[no].mid == i)
@@ -384,6 +396,9 @@ void smp_flush_tlb_all(void)
* are flush_tlb_*() routines, and these run after flush_cache_*()
* which performs the flushw.
*
+ * XXX I diked out the fancy flush avoidance code for the
+ * XXX swapping cases for now until the new MM code stabilizes. -DaveM
+ *
* The SMP TLB coherency scheme we use works as follows:
*
* 1) mm->cpu_vm_mask is a bit mask of which cpus an address
@@ -395,16 +410,16 @@ void smp_flush_tlb_all(void)
* cross calls.
*
* One invariant is that when a cpu switches to a process, and
- * that processes tsk->mm->cpu_vm_mask does not have the current
- * cpu's bit set, that tlb context is flushed locally.
+ * that processes tsk->active_mm->cpu_vm_mask does not have the
+ * current cpu's bit set, that tlb context is flushed locally.
*
* If the address space is non-shared (ie. mm->count == 1) we avoid
* cross calls when we want to flush the currently running process's
* tlb state. This is done by clearing all cpu bits except the current
- * processor's in current->mm->cpu_vm_mask and performing the flush
- * locally only. This will force any subsequent cpus which run this
- * task to flush the context from the local tlb if the process migrates
- * to another cpu (again).
+ * processor's in current->active_mm->cpu_vm_mask and performing the
+ * flush locally only. This will force any subsequent cpus which run
+ * this task to flush the context from the local tlb if the process
+ * migrates to another cpu (again).
*
* 3) For shared address spaces (threads) and swapping we bite the
* bullet for most cases and perform the cross call.
@@ -422,13 +437,13 @@ void smp_flush_tlb_all(void)
*/
void smp_flush_tlb_mm(struct mm_struct *mm)
{
- u32 ctx = mm->context & 0x3ff;
+ u32 ctx = CTX_HWBITS(mm->context);
- if(mm == current->mm && atomic_read(&mm->count) == 1) {
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- mm->cpu_vm_mask = (1UL << smp_processor_id());
+ if (mm == current->active_mm &&
+ atomic_read(&mm->mm_users) == 1 &&
+ (mm->cpu_vm_mask == (1UL << smp_processor_id())))
goto local_flush_and_out;
- }
+
smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
local_flush_and_out:
@@ -438,15 +453,15 @@ local_flush_and_out:
void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
- u32 ctx = mm->context & 0x3ff;
+ u32 ctx = CTX_HWBITS(mm->context);
start &= PAGE_MASK;
end &= PAGE_MASK;
- if(mm == current->mm && atomic_read(&mm->count) == 1) {
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- mm->cpu_vm_mask = (1UL << smp_processor_id());
+ if(mm == current->active_mm &&
+ atomic_read(&mm->mm_users) == 1 &&
+ (mm->cpu_vm_mask == (1UL << smp_processor_id())))
goto local_flush_and_out;
- }
+
smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
local_flush_and_out:
@@ -455,30 +470,15 @@ local_flush_and_out:
void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
{
- u32 ctx = mm->context & 0x3ff;
+ u32 ctx = CTX_HWBITS(mm->context);
page &= PAGE_MASK;
- if(mm == current->mm && atomic_read(&mm->count) == 1) {
- if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
- mm->cpu_vm_mask = (1UL << smp_processor_id());
+ if(mm == current->active_mm &&
+ atomic_read(&mm->mm_users) == 1 &&
+ (mm->cpu_vm_mask == (1UL << smp_processor_id()))) {
goto local_flush_and_out;
- } else {
- /* Try to handle two special cases to avoid cross calls
- * in common scenerios where we are swapping process
- * pages out.
- */
- if(((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK) ||
- (mm->cpu_vm_mask == 0)) {
- /* A dead context cannot ever become "alive" until
- * a task switch is done to it.
- */
- return; /* It's dead, nothing to do. */
- }
- if(mm->cpu_vm_mask == (1UL << smp_processor_id())) {
- __flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
- return; /* Only local flush is necessary. */
- }
}
+
smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
local_flush_and_out:
@@ -547,10 +547,18 @@ void smp_penguin_jailcell(void)
atomic_dec(&smp_capture_registry);
}
-static inline void sparc64_do_profile(unsigned long pc)
+static inline void sparc64_do_profile(unsigned long pc, unsigned long g3)
{
if (prof_buffer && current->pid) {
extern int _stext;
+ extern int rwlock_impl_begin, rwlock_impl_end;
+ extern int atomic_impl_begin, atomic_impl_end;
+
+ if ((pc >= (unsigned long) &rwlock_impl_begin &&
+ pc < (unsigned long) &rwlock_impl_end) ||
+ (pc >= (unsigned long) &atomic_impl_begin &&
+ pc < (unsigned long) &atomic_impl_end))
+ pc = g3;
pc -= (unsigned long) &_stext;
pc >>= prof_shift;
@@ -589,7 +597,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
clear_softint((1UL << 0));
do {
if(!user)
- sparc64_do_profile(regs->tpc);
+ sparc64_do_profile(regs->tpc, regs->u_regs[UREG_G3]);
if(!--prof_counter(cpu))
{
if (cpu == boot_cpu_id) {
@@ -647,7 +655,7 @@ do { hardirq_enter(cpu); \
} while (tick >= compare);
}
-__initfunc(static void smp_setup_percpu_timer(void))
+static void __init smp_setup_percpu_timer(void)
{
int cpu = smp_processor_id();
@@ -661,7 +669,7 @@ __initfunc(static void smp_setup_percpu_timer(void))
: "g1");
}
-__initfunc(void smp_tick_init(void))
+void __init smp_tick_init(void)
{
int i;
@@ -707,7 +715,7 @@ static inline unsigned long find_flush_base(unsigned long size)
cycles_t cacheflush_time;
-__initfunc(static void smp_tune_scheduling (void))
+static void __init smp_tune_scheduling (void)
{
unsigned long flush_base, flags, *p;
unsigned int ecache_size;
@@ -775,7 +783,8 @@ __initfunc(static void smp_tune_scheduling (void))
(int) cacheflush_time);
}
-int __init setup_profiling_timer(unsigned int multiplier)
+/* /proc/profile writes can call this, don't __init it please. */
+int setup_profiling_timer(unsigned int multiplier)
{
unsigned long flags;
int i;
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 91277fc4a..e57b8d6f7 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.60 1999/07/03 22:11:12 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.64 1999/09/05 09:33:38 ecd Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -190,10 +190,9 @@ EXPORT_SYMBOL(dma_chain);
#endif
#if CONFIG_PCI
EXPORT_SYMBOL(ebus_chain);
-EXPORT_SYMBOL(pci_dvma_offset);
-EXPORT_SYMBOL(pci_dvma_mask);
EXPORT_SYMBOL(pci_dvma_v2p_hash);
EXPORT_SYMBOL(pci_dvma_p2v_hash);
+EXPORT_SYMBOL(pci_memspace_mask);
EXPORT_SYMBOL(empty_zero_page);
EXPORT_SYMBOL(outsb);
EXPORT_SYMBOL(outsw);
@@ -215,7 +214,6 @@ EXPORT_SYMBOL(die_if_kernel);
/* Kernel thread creation. */
EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(init_mm);
/* prom symbols */
EXPORT_SYMBOL(idprom);
diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
index 38f33ecd6..805dce338 100644
--- a/arch/sparc64/kernel/starfire.c
+++ b/arch/sparc64/kernel/starfire.c
@@ -1,4 +1,4 @@
-/* $Id: starfire.c,v 1.2 1998/12/09 18:53:11 davem Exp $
+/* $Id: starfire.c,v 1.3 1999/08/30 10:01:13 davem Exp $
* starfire.c: Starfire/E10000 support.
*
* Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
@@ -43,7 +43,7 @@ void starfire_check(void)
int starfire_hard_smp_processor_id(void)
{
- return *((unsigned int *) __va(0x1fff40000d0));
+ return *((volatile unsigned int *) __va(0x1fff40000d0));
}
/* Each Starfire board has 32 registers which perform translation
@@ -52,8 +52,8 @@ int starfire_hard_smp_processor_id(void)
* bits than in all previous Sun5 systems.
*/
struct starfire_irqinfo {
- unsigned int *imap_slots[32];
- unsigned int *tregs[32];
+ volatile unsigned int *imap_slots[32];
+ volatile unsigned int *tregs[32];
struct starfire_irqinfo *next;
int upaid, hwmid;
};
@@ -80,7 +80,7 @@ void *starfire_hookup(int upaid)
treg_base += 0x200UL;
for(i = 0; i < 32; i++) {
p->imap_slots[i] = NULL;
- p->tregs[i] = __va(treg_base + (i * 0x10));
+ p->tregs[i] = (volatile unsigned int *)__va(treg_base + (i * 0x10));
}
p->upaid = upaid;
p->next = sflist;
@@ -89,7 +89,7 @@ void *starfire_hookup(int upaid)
return (void *) p;
}
-unsigned int starfire_translate(unsigned int *imap,
+unsigned int starfire_translate(volatile unsigned int *imap,
unsigned int upaid)
{
struct starfire_irqinfo *p;
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 4906cea93..4e87819d4 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.27 1999/06/02 12:06:34 jj Exp $
+/* $Id: sys_sparc.c,v 1.29 1999/08/04 07:04:10 jj Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -41,7 +41,9 @@ extern asmlinkage unsigned long sys_brk(unsigned long brk);
asmlinkage unsigned long sparc_brk(unsigned long brk)
{
- if(brk >= 0x80000000000UL) /* VM hole */
+ if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) ||
+ (brk - current->mm->brk > 0x80000000000UL &&
+ brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */
return current->mm->brk;
return sys_brk(brk);
}
@@ -170,7 +172,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
}
retval = -EINVAL;
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
if (len > 0xf0000000UL || addr > 0xf0000000UL - len)
goto out_putf;
} else {
@@ -178,7 +180,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
(addr < 0x80000000000UL &&
addr > 0x80000000000UL-len))
goto out_putf;
- if (addr >= 0x80000000000ULL && addr < 0xfffff80000000000UL) {
+ if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) {
/* VM hole */
retval = current->mm->brk;
goto out_putf;
@@ -281,40 +283,40 @@ asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p,
return -EINVAL;
if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) {
if (old_p) {
- if (!current->tss.utraps)
+ if (!current->thread.utraps)
put_user_ret(NULL, old_p, -EFAULT);
else
- put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
+ put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
}
if (old_d)
put_user_ret(NULL, old_d, -EFAULT);
return 0;
}
lock_kernel();
- if (!current->tss.utraps) {
- current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
- if (!current->tss.utraps) return -ENOMEM;
- current->tss.utraps[0] = 1;
- memset(current->tss.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
+ if (!current->thread.utraps) {
+ current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
+ if (!current->thread.utraps) return -ENOMEM;
+ current->thread.utraps[0] = 1;
+ memset(current->thread.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long));
} else {
- if ((utrap_handler_t)current->tss.utraps[type] != new_p && current->tss.utraps[0] > 1) {
- long *p = current->tss.utraps;
+ if ((utrap_handler_t)current->thread.utraps[type] != new_p && current->thread.utraps[0] > 1) {
+ long *p = current->thread.utraps;
- current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
- if (!current->tss.utraps) {
- current->tss.utraps = p;
+ current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL);
+ if (!current->thread.utraps) {
+ current->thread.utraps = p;
return -ENOMEM;
}
p[0]--;
- current->tss.utraps[0] = 1;
- memcpy(current->tss.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
+ current->thread.utraps[0] = 1;
+ memcpy(current->thread.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long));
}
}
if (old_p)
- put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT);
+ put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT);
if (old_d)
put_user_ret(NULL, old_d, -EFAULT);
- current->tss.utraps[type] = (long)new_p;
+ current->thread.utraps[type] = (long)new_p;
unlock_kernel();
return 0;
}
@@ -363,10 +365,10 @@ update_perfctrs(void)
unsigned long pic, tmp;
read_pic(pic);
- tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
- __put_user(tmp, current->tss.user_cntd0);
- tmp = (current->tss.kernel_cntd1 += (pic >> 32));
- __put_user(tmp, current->tss.user_cntd1);
+ tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
+ __put_user(tmp, current->thread.user_cntd0);
+ tmp = (current->thread.kernel_cntd1 += (pic >> 32));
+ __put_user(tmp, current->thread.user_cntd1);
reset_pic();
}
@@ -377,24 +379,24 @@ sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long ar
switch(opcode) {
case PERFCTR_ON:
- current->tss.pcr_reg = arg2;
- current->tss.user_cntd0 = (u64 *) arg0;
- current->tss.user_cntd1 = (u64 *) arg1;
- current->tss.kernel_cntd0 =
- current->tss.kernel_cntd1 = 0;
+ current->thread.pcr_reg = arg2;
+ current->thread.user_cntd0 = (u64 *) arg0;
+ current->thread.user_cntd1 = (u64 *) arg1;
+ current->thread.kernel_cntd0 =
+ current->thread.kernel_cntd1 = 0;
write_pcr(arg2);
reset_pic();
- current->tss.flags |= SPARC_FLAG_PERFCTR;
+ current->thread.flags |= SPARC_FLAG_PERFCTR;
break;
case PERFCTR_OFF:
err = -EINVAL;
- if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) {
- current->tss.user_cntd0 =
- current->tss.user_cntd1 = NULL;
- current->tss.pcr_reg = 0;
+ if ((current->thread.flags & SPARC_FLAG_PERFCTR) != 0) {
+ current->thread.user_cntd0 =
+ current->thread.user_cntd1 = NULL;
+ current->thread.pcr_reg = 0;
write_pcr(0);
- current->tss.flags &= ~(SPARC_FLAG_PERFCTR);
+ current->thread.flags &= ~(SPARC_FLAG_PERFCTR);
err = 0;
}
break;
@@ -402,50 +404,50 @@ sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long ar
case PERFCTR_READ: {
unsigned long pic, tmp;
- if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
err = -EINVAL;
break;
}
read_pic(pic);
- tmp = (current->tss.kernel_cntd0 += (unsigned int)pic);
- err |= __put_user(tmp, current->tss.user_cntd0);
- tmp = (current->tss.kernel_cntd1 += (pic >> 32));
- err |= __put_user(tmp, current->tss.user_cntd1);
+ tmp = (current->thread.kernel_cntd0 += (unsigned int)pic);
+ err |= __put_user(tmp, current->thread.user_cntd0);
+ tmp = (current->thread.kernel_cntd1 += (pic >> 32));
+ err |= __put_user(tmp, current->thread.user_cntd1);
reset_pic();
break;
}
case PERFCTR_CLRPIC:
- if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
err = -EINVAL;
break;
}
- current->tss.kernel_cntd0 =
- current->tss.kernel_cntd1 = 0;
+ current->thread.kernel_cntd0 =
+ current->thread.kernel_cntd1 = 0;
reset_pic();
break;
case PERFCTR_SETPCR: {
u64 *user_pcr = (u64 *)arg0;
- if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
err = -EINVAL;
break;
}
- err |= __get_user(current->tss.pcr_reg, user_pcr);
- write_pcr(current->tss.pcr_reg);
- current->tss.kernel_cntd0 =
- current->tss.kernel_cntd1 = 0;
+ err |= __get_user(current->thread.pcr_reg, user_pcr);
+ write_pcr(current->thread.pcr_reg);
+ current->thread.kernel_cntd0 =
+ current->thread.kernel_cntd1 = 0;
reset_pic();
break;
}
case PERFCTR_GETPCR: {
u64 *user_pcr = (u64 *)arg0;
- if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) {
+ if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) {
err = -EINVAL;
break;
}
- err |= __put_user(current->tss.pcr_reg, user_pcr);
+ err |= __put_user(current->thread.pcr_reg, user_pcr);
break;
}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 0e42e2c32..a1e0f26dd 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.109 1999/06/03 07:11:31 davem Exp $
+/* $Id: sys_sparc32.c,v 1.118 1999/08/30 10:01:15 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -1663,85 +1663,6 @@ asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize
return ret;
}
-siginfo_t32 *
-siginfo64to32(siginfo_t32 *d, siginfo_t *s)
-{
- memset (&d, 0, sizeof(siginfo_t32));
- d->si_signo = s->si_signo;
- d->si_errno = s->si_errno;
- d->si_code = s->si_code;
- if (s->si_signo >= SIGRTMIN) {
- d->si_pid = s->si_pid;
- d->si_uid = s->si_uid;
- /* XXX: Ouch, how to find this out??? */
- d->si_int = s->si_int;
- } else switch (s->si_signo) {
- /* XXX: What about POSIX1.b timers */
- case SIGCHLD:
- d->si_pid = s->si_pid;
- d->si_status = s->si_status;
- d->si_utime = s->si_utime;
- d->si_stime = s->si_stime;
- break;
- case SIGSEGV:
- case SIGBUS:
- case SIGFPE:
- case SIGILL:
- d->si_addr = (long)(s->si_addr);
- /* XXX: Do we need to translate this from sparc64 to sparc32 traps? */
- d->si_trapno = s->si_trapno;
- break;
- case SIGPOLL:
- d->si_band = s->si_band;
- d->si_fd = s->si_fd;
- break;
- default:
- d->si_pid = s->si_pid;
- d->si_uid = s->si_uid;
- break;
- }
- return d;
-}
-
-siginfo_t *
-siginfo32to64(siginfo_t *d, siginfo_t32 *s)
-{
- d->si_signo = s->si_signo;
- d->si_errno = s->si_errno;
- d->si_code = s->si_code;
- if (s->si_signo >= SIGRTMIN) {
- d->si_pid = s->si_pid;
- d->si_uid = s->si_uid;
- /* XXX: Ouch, how to find this out??? */
- d->si_int = s->si_int;
- } else switch (s->si_signo) {
- /* XXX: What about POSIX1.b timers */
- case SIGCHLD:
- d->si_pid = s->si_pid;
- d->si_status = s->si_status;
- d->si_utime = s->si_utime;
- d->si_stime = s->si_stime;
- break;
- case SIGSEGV:
- case SIGBUS:
- case SIGFPE:
- case SIGILL:
- d->si_addr = (void *)A(s->si_addr);
- /* XXX: Do we need to translate this from sparc32 to sparc64 traps? */
- d->si_trapno = s->si_trapno;
- break;
- case SIGPOLL:
- d->si_band = s->si_band;
- d->si_fd = s->si_fd;
- break;
- default:
- d->si_pid = s->si_pid;
- d->si_uid = s->si_uid;
- break;
- }
- return d;
-}
-
extern asmlinkage int
sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
const struct timespec *uts, size_t sigsetsize);
@@ -1753,10 +1674,9 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
sigset_t s;
sigset_t32 s32;
struct timespec t;
- int ret;
+ int ret, err, i;
mm_segment_t old_fs = get_fs();
siginfo_t info;
- siginfo_t32 info32;
if (copy_from_user (&s32, uthese, sizeof(sigset_t32)))
return -EFAULT;
@@ -1776,8 +1696,43 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
set_fs (old_fs);
if (ret >= 0 && uinfo) {
- if (copy_to_user (uinfo, siginfo64to32(&info32, &info), sizeof(siginfo_t32)))
- return -EFAULT;
+ err = put_user (info.si_signo, &uinfo->si_signo);
+ err |= __put_user (info.si_errno, &uinfo->si_errno);
+ err |= __put_user (info.si_code, &uinfo->si_code);
+ if (info.si_code < 0)
+ err |= __copy_to_user (uinfo->_sifields._pad, info._sifields._pad, SI_PAD_SIZE);
+ else {
+ i = info.si_signo;
+ if (info.si_code == SI_USER)
+ i = SIGRTMIN;
+ switch (i) {
+ case SIGPOLL:
+ err |= __put_user (info.si_band, &uinfo->si_band);
+ err |= __put_user (info.si_fd, &uinfo->si_fd);
+ break;
+ case SIGCHLD:
+ err |= __put_user (info.si_pid, &uinfo->si_pid);
+ err |= __put_user (info.si_uid, &uinfo->si_uid);
+ err |= __put_user (info.si_status, &uinfo->si_status);
+ err |= __put_user (info.si_utime, &uinfo->si_utime);
+ err |= __put_user (info.si_stime, &uinfo->si_stime);
+ break;
+ case SIGSEGV:
+ case SIGILL:
+ case SIGFPE:
+ case SIGBUS:
+ case SIGEMT:
+ err |= __put_user ((long)info.si_addr, &uinfo->si_addr);
+ err |= __put_user (info.si_trapno, &uinfo->si_trapno);
+ break;
+ default:
+ err |= __put_user (info.si_pid, &uinfo->si_pid);
+ err |= __put_user (info.si_uid, &uinfo->si_uid);
+ break;
+ }
+ }
+ if (err)
+ ret = -EFAULT;
}
return ret;
}
@@ -1789,14 +1744,12 @@ asmlinkage int
sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
{
siginfo_t info;
- siginfo_t32 info32;
int ret;
mm_segment_t old_fs = get_fs();
- if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32)))
+ if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
+ copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
return -EFAULT;
- /* XXX: Is this correct? */
- siginfo32to64(&info, &info32);
set_fs (KERNEL_DS);
ret = sys_rt_sigqueueinfo(pid, sig, &info);
set_fs (old_fs);
@@ -2659,7 +2612,7 @@ asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old
int ret;
if(sig < 0) {
- current->tss.new_signal = 1;
+ current->thread.flags |= SPARC_FLAG_NEWSIGNALS;
sig = -sig;
}
@@ -2703,7 +2656,7 @@ sys32_rt_sigaction(int sig, struct sigaction32 *act, struct sigaction32 *oact,
/* All tasks which use RT signals (effectively) use
* new style signals.
*/
- current->tss.new_signal = 1;
+ current->thread.flags |= SPARC_FLAG_NEWSIGNALS;
if (act) {
new_ka.ka_restorer = restorer;
@@ -2883,6 +2836,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
int error, base = 0;
char *filename;
+ /* User register window flush is done by entry.S */
+
/* Check for indirect call. */
if((u32)regs->u_regs[UREG_G1] == 0)
base = 1;
@@ -2899,8 +2854,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
if(!error) {
fprs_write(0);
- current->tss.xfsr[0] = 0;
- current->tss.fpsaved[0] = 0;
+ current->thread.xfsr[0] = 0;
+ current->thread.fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
}
out:
@@ -3786,7 +3741,7 @@ asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf,
}
-extern asmlinkage int sys_personality(unsigned long);
+extern asmlinkage long sys_personality(unsigned long);
asmlinkage int sys32_personality(unsigned long personality)
{
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 156d1d8ee..0f0c2a536 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.26 1999/06/09 08:23:54 davem Exp $
+/* $Id: sys_sunos32.c,v 1.31 1999/08/30 10:01:19 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -557,9 +557,9 @@ asmlinkage int sunos_nosys(void)
struct pt_regs *regs;
lock_kernel();
- regs = current->tss.kregs;
- current->tss.sig_address = regs->tpc;
- current->tss.sig_desc = regs->u_regs[UREG_G1];
+ regs = current->thread.kregs;
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = regs->u_regs[UREG_G1];
send_sig(SIGSYS, current, 1);
printk("Process makes ni_syscall number %d, register dump:\n",
(int) regs->u_regs[UREG_G1]);
@@ -981,10 +981,6 @@ extern asmlinkage s32 sunos_sysconf (int name)
return ret;
}
-extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg);
-extern asmlinkage int sys_semget (key_t key, int nsems, int semflg);
-extern asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops);
-
asmlinkage int sunos_semsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 ptr)
{
union semun arg4;
@@ -1119,13 +1115,6 @@ static inline int sunos_msgbuf_put(struct msgbuf32 *user, struct msgbuf *kern, i
return 0;
}
-extern asmlinkage int sys_msgget (key_t key, int msgflg);
-extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp,
- size_t msgsz, long msgtyp, int msgflg);
-extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp,
- size_t msgsz, int msgflg);
-extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
-
asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
struct sparc_stackf32 *sp;
@@ -1159,7 +1148,7 @@ asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
if(!kmbuf)
break;
sp = (struct sparc_stackf32 *)
- (current->tss.kregs->u_regs[UREG_FP] & 0xffffffffUL);
+ (current->thread.kregs->u_regs[UREG_FP] & 0xffffffffUL);
if(get_user(arg5, &sp->xxargs[0])) {
rval = -EFAULT;
break;
@@ -1242,11 +1231,6 @@ static inline int sunos_shmid_put(struct shmid_ds32 *user,
return 0;
}
-extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
-extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
-extern asmlinkage int sys_shmdt (char *shmaddr);
-extern asmlinkage int sys_shmget (key_t key, int size, int shmflg);
-
asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3)
{
struct shmid_ds ksds;
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index e99ae0532..06a827db2 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.54 1999/06/02 12:06:31 jj Exp $
+/* $Id: systbls.S,v 1.56 1999/07/31 00:06:17 davem Exp $
* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
@@ -59,7 +59,7 @@ sys_call_table32:
.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
.word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo
+/*210*/ .word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo
.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
/*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
@@ -112,15 +112,15 @@ sys_call_table:
.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
/*190*/ .word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
-/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+/*200*/ .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
.word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
- .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+/*210*/ .word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+ .word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/ .word sys_nis_syscall, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
/*230*/ .word sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 0b72e6e0b..60d5e4a5f 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.20 1999/03/15 22:13:40 davem Exp $
+/* $Id: time.c,v 1.22 1999/08/30 10:01:22 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -33,9 +33,9 @@
extern rwlock_t xtime_lock;
-struct mostek48t02 *mstk48t02_regs = 0;
-static struct mostek48t08 *mstk48t08_regs = 0;
-static struct mostek48t59 *mstk48t59_regs = 0;
+unsigned long mstk48t02_regs = 0UL;
+static unsigned long mstk48t08_regs = 0UL;
+static unsigned long mstk48t59_regs = 0UL;
static int set_rtc_mmss(unsigned long);
@@ -47,7 +47,7 @@ static int set_rtc_mmss(unsigned long);
*/
unsigned long timer_tick_offset;
static unsigned long timer_tick_compare;
-static unsigned long timer_ticks_per_usec;
+static unsigned long timer_ticks_per_usec_quotient;
static __inline__ void timer_check_rtc(void)
{
@@ -146,17 +146,25 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon,
/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
static void __init kick_start_clock(void)
{
- register struct mostek48t02 *regs = mstk48t02_regs;
- unsigned char sec;
+ unsigned long regs = mstk48t02_regs;
+ u8 sec, tmp;
int i, count;
prom_printf("CLOCK: Clock was stopped. Kick start ");
/* Turn on the kick start bit to start the oscillator. */
- regs->creg |= MSTK_CREG_WRITE;
- regs->sec &= ~MSTK_STOP;
- regs->hour |= MSTK_KICK_START;
- regs->creg &= ~MSTK_CREG_WRITE;
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+ tmp = mostek_read(regs + MOSTEK_SEC);
+ tmp &= ~MSTK_STOP;
+ mostek_write(regs + MOSTEK_SEC, tmp);
+ tmp = mostek_read(regs + MOSTEK_HOUR);
+ tmp |= MSTK_KICK_START;
+ mostek_write(regs + MOSTEK_HOUR, tmp);
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
/* Delay to allow the clock oscillator to start. */
sec = MSTK_REG_SEC(regs);
@@ -165,13 +173,17 @@ static void __init kick_start_clock(void)
for (count = 0; count < 100000; count++)
/* nothing */ ;
prom_printf(".");
- sec = regs->sec;
+ sec = MSTK_REG_SEC(regs);
}
prom_printf("\n");
/* Turn off kick start and set a "valid" time and date. */
- regs->creg |= MSTK_CREG_WRITE;
- regs->hour &= ~MSTK_KICK_START;
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+ tmp = mostek_read(regs + MOSTEK_HOUR);
+ tmp &= ~MSTK_KICK_START;
+ mostek_write(regs + MOSTEK_HOUR, tmp);
MSTK_SET_REG_SEC(regs,0);
MSTK_SET_REG_MIN(regs,0);
MSTK_SET_REG_HOUR(regs,0);
@@ -179,14 +191,24 @@ static void __init kick_start_clock(void)
MSTK_SET_REG_DOM(regs,1);
MSTK_SET_REG_MONTH(regs,8);
MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
- regs->creg &= ~MSTK_CREG_WRITE;
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
/* Ensure the kick start bit is off. If it isn't, turn it off. */
- while (regs->hour & MSTK_KICK_START) {
+ while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) {
prom_printf("CLOCK: Kick start still on!\n");
- regs->creg |= MSTK_CREG_WRITE;
- regs->hour &= ~MSTK_KICK_START;
- regs->creg &= ~MSTK_CREG_WRITE;
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+
+ tmp = mostek_read(regs + MOSTEK_HOUR);
+ tmp &= ~MSTK_KICK_START;
+ mostek_write(regs + MOSTEK_HOUR, tmp);
+
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
}
prom_printf("CLOCK: Kick start procedure successful.\n");
@@ -195,13 +217,13 @@ static void __init kick_start_clock(void)
/* Return nonzero if the clock chip battery is low. */
static int __init has_low_battery(void)
{
- register struct mostek48t02 *regs = mstk48t02_regs;
- unsigned char data1, data2;
+ unsigned long regs = mstk48t02_regs;
+ u8 data1, data2;
- data1 = regs->eeprom[0]; /* Read some data. */
- regs->eeprom[0] = ~data1; /* Write back the complement. */
- data2 = regs->eeprom[0]; /* Read back the complement. */
- regs->eeprom[0] = data1; /* Restore the original value. */
+ data1 = mostek_read(regs + MOSTEK_EEPROM); /* Read some data. */
+ mostek_write(regs + MOSTEK_EEPROM, ~data1); /* Write back the complement. */
+ data2 = mostek_read(regs + MOSTEK_EEPROM); /* Read back the complement. */
+ mostek_write(regs + MOSTEK_EEPROM, data1); /* Restore original value. */
return (data1 == data2); /* Was the write blocked? */
}
@@ -211,17 +233,20 @@ static int __init has_low_battery(void)
static void __init set_system_time(void)
{
unsigned int year, mon, day, hour, min, sec;
- struct mostek48t02 *mregs;
+ unsigned long mregs = mstk48t02_regs;
+ u8 tmp;
do_get_fast_time = do_gettimeofday;
- mregs = mstk48t02_regs;
if(!mregs) {
prom_printf("Something wrong, clock regs not mapped yet.\n");
prom_halt();
}
- mregs->creg |= MSTK_CREG_READ;
+ 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);
@@ -230,7 +255,10 @@ static void __init set_system_time(void)
year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
- mregs->creg &= ~MSTK_CREG_READ;
+
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
}
void __init clock_probe(void)
@@ -315,19 +343,8 @@ void __init clock_probe(void)
prom_halt();
}
- if (check_region(edev->base_address[0],
- sizeof(struct mostek48t59))) {
- prom_printf("%s: Can't get region %lx, %d\n",
- __FUNCTION__, edev->base_address[0],
- sizeof(struct mostek48t59));
- prom_halt();
- }
- request_region(edev->base_address[0],
- sizeof(struct mostek48t59), "clock");
-
- mstk48t59_regs = (struct mostek48t59 *)
- edev->base_address[0];
- mstk48t02_regs = &mstk48t59_regs->regs;
+ mstk48t59_regs = edev->resource[0].start;
+ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
break;
}
#endif
@@ -338,22 +355,16 @@ void __init clock_probe(void)
}
if(model[5] == '0' && model[6] == '2') {
- mstk48t02_regs = (struct mostek48t02 *)
- sparc_alloc_io(clk_reg[0].phys_addr,
- (void *) 0, sizeof(*mstk48t02_regs),
- "clock", clk_reg[0].which_io, 0x0);
+ mstk48t02_regs = (((u64)clk_reg[0].phys_addr) |
+ (((u64)clk_reg[0].which_io)<<32UL));
} else if(model[5] == '0' && model[6] == '8') {
- mstk48t08_regs = (struct mostek48t08 *)
- sparc_alloc_io(clk_reg[0].phys_addr,
- (void *) 0, sizeof(*mstk48t08_regs),
- "clock", clk_reg[0].which_io, 0x0);
- mstk48t02_regs = &mstk48t08_regs->regs;
+ mstk48t08_regs = (((u64)clk_reg[0].phys_addr) |
+ (((u64)clk_reg[0].which_io)<<32UL));
+ mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
} else {
- mstk48t59_regs = (struct mostek48t59 *)
- sparc_alloc_io(clk_reg[0].phys_addr,
- (void *) 0, sizeof(*mstk48t59_regs),
- "clock", clk_reg[0].which_io, 0x0);
- mstk48t02_regs = &mstk48t59_regs->regs;
+ mstk48t59_regs = (((u64)clk_reg[0].phys_addr) |
+ (((u64)clk_reg[0].which_io)<<32UL));
+ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
break;
}
@@ -363,7 +374,7 @@ void __init clock_probe(void)
prom_printf("NVRAM: Low battery voltage!\n");
/* Kick start the clock if it is completely stopped. */
- if (mstk48t02_regs->sec & MSTK_STOP)
+ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
kick_start_clock();
set_system_time();
@@ -392,7 +403,7 @@ void __init time_init(void)
init_timers(timer_interrupt, &clock);
timer_tick_offset = clock / HZ;
- timer_ticks_per_usec = clock / 1000000;
+ timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
}
static __inline__ unsigned long do_gettimeoffset(void)
@@ -408,7 +419,7 @@ static __inline__ unsigned long do_gettimeoffset(void)
: "r" (timer_tick_offset), "r" (timer_tick_compare)
: "g1", "g2");
- return ticks / timer_ticks_per_usec;
+ return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
}
/* This need not obtain the xtime_lock as it is coded in
@@ -431,24 +442,22 @@ void do_gettimeofday(struct timeval *tv)
or %g2, %lo(xtime), %g2
or %g1, %lo(timer_tick_compare), %g1
1: ldda [%g2] 0x24, %o4
- membar #LoadLoad | #MemIssue
rd %tick, %o1
ldx [%g1], %g7
- membar #LoadLoad | #MemIssue
ldda [%g2] 0x24, %o2
- membar #LoadLoad
xor %o4, %o2, %o2
xor %o5, %o3, %o3
orcc %o2, %o3, %g0
bne,pn %xcc, 1b
sethi %hi(lost_ticks), %o2
- sethi %hi(timer_ticks_per_usec), %o3
+ sethi %hi(timer_ticks_per_usec_quotient), %o3
ldx [%o2 + %lo(lost_ticks)], %o2
add %g3, %o1, %o1
- ldx [%o3 + %lo(timer_ticks_per_usec)], %o3
+ ldx [%o3 + %lo(timer_ticks_per_usec_quotient)], %o3
sub %o1, %g7, %o1
+ mulx %o3, %o1, %o1
brz,pt %o2, 1f
- udivx %o1, %o3, %o1
+ srlx %o1, 32, %o1
sethi %hi(10000), %g2
or %g2, %lo(10000), %g2
add %o1, %g2, %o1
@@ -487,16 +496,23 @@ void do_settimeofday(struct timeval *tv)
static int set_rtc_mmss(unsigned long nowtime)
{
int real_seconds, real_minutes, mostek_minutes;
- struct mostek48t02 *regs = mstk48t02_regs;
+ unsigned long regs = mstk48t02_regs;
+ u8 tmp;
/* Not having a register set can lead to trouble. */
if (!regs)
return -1;
/* Read the current RTC minutes. */
- regs->creg |= MSTK_CREG_READ;
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_READ;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+
mostek_minutes = MSTK_REG_MIN(regs);
- regs->creg &= ~MSTK_CREG_READ;
+
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_READ;
+ mostek_write(regs + MOSTEK_CREG, tmp);
/*
* since we're only adjusting minutes and seconds,
@@ -511,10 +527,16 @@ static int set_rtc_mmss(unsigned long nowtime)
real_minutes %= 60;
if (abs(real_minutes - mostek_minutes) < 30) {
- regs->creg |= MSTK_CREG_WRITE;
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+
MSTK_SET_REG_SEC(regs,real_seconds);
MSTK_SET_REG_MIN(regs,real_minutes);
- regs->creg &= ~MSTK_CREG_WRITE;
+
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
} else
return -1;
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 0dd40b538..fba910a55 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -1,9 +1,11 @@
-/* $Id: trampoline.S,v 1.9 1999/05/25 16:53:12 jj Exp $
+/* $Id: trampoline.S,v 1.10 1999/09/10 10:40:48 davem Exp $
* trampoline.S: Jump start slave processors on sparc64.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
+
#include <asm/head.h>
#include <asm/asi.h>
#include <asm/lsu.h>
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 86ee5b661..f4f2287df 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.60 1999/06/02 19:19:55 jj Exp $
+/* $Id: traps.c,v 1.62 1999/08/31 19:25:35 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -147,12 +147,12 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs)
if(i)
printk(",");
if(!sdp->arg_is_string[i]) {
- if (current->tss.flags & SPARC_FLAG_32BIT)
+ if (current->thread.flags & SPARC_FLAG_32BIT)
printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]);
else
printk("%016lx", regs->u_regs[UREG_I0 + i]);
} else {
- if (current->tss.flags & SPARC_FLAG_32BIT)
+ if (current->thread.flags & SPARC_FLAG_32BIT)
strncpy_from_user(scall_strbuf,
(char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff),
512);
@@ -178,7 +178,7 @@ unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
}
#endif /* SYSCALL_TRACING */
-#if 0
+#if 1
void rtrap_check(struct pt_regs *regs)
{
register unsigned long pgd_phys asm("o1");
@@ -219,7 +219,7 @@ void rtrap_check(struct pt_regs *regs)
if((pgd_phys != __pa(current->mm->pgd)) ||
((pgd_cache != 0) &&
- (pgd_cache != pgd_val(current->mm->pgd[0]))) ||
+ (pgd_cache != pgd_val(current->mm->pgd[0])<<11UL)) ||
(g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) ||
#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
@@ -228,18 +228,17 @@ void rtrap_check(struct pt_regs *regs)
#undef KERN_LOWBITS
((ctx != (current->mm->context & 0x3ff)) ||
(ctx == 0) ||
- (current->tss.ctx != ctx))) {
+ (CTX_HWBITS(current->mm->context) != ctx))) {
printk("SHIT[%s:%d]: "
- "(PP[%016lx] CACH[%016lx] CTX[%x] g1g3[%016lx] g2[%016lx]) ",
+ "(PP[%016lx] CACH[%016lx] CTX[%lx] g1g3[%016lx] g2[%016lx]) ",
current->comm, current->pid,
pgd_phys, pgd_cache, ctx, g1_or_g3, g2);
printk("SHIT[%s:%d]: "
- "[PP[%016lx] CACH[%016lx] CTX[%x:%x]] PC[%016lx:%016lx]\n",
+ "[PP[%016lx] CACH[%016lx] CTX[%lx]] PC[%016lx:%016lx]\n",
current->comm, current->pid,
__pa(current->mm->pgd),
pgd_val(current->mm->pgd[0]),
current->mm->context & 0x3ff,
- current->tss.ctx,
regs->tpc, regs->tnpc);
show_regs(regs);
#if 1
@@ -262,8 +261,8 @@ void bad_trap (struct pt_regs *regs, long lvl)
}
if (regs->tstate & TSTATE_PRIV)
die_if_kernel ("Kernel bad trap", regs);
- current->tss.sig_desc = SUBSIG_BADTRAP(lvl - 0x100);
- current->tss.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_BADTRAP(lvl - 0x100);
+ current->thread.sig_address = regs->tpc;
force_sig(SIGILL, current);
unlock_kernel ();
}
@@ -289,8 +288,8 @@ void instruction_access_exception (struct pt_regs *regs,
#endif
die_if_kernel("Iax", regs);
}
- current->tss.sig_desc = SUBSIG_ILLINST;
- current->tss.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_ILLINST;
+ current->thread.sig_address = regs->tpc;
force_sig(SIGILL, current);
unlock_kernel();
}
@@ -396,14 +395,132 @@ void do_iae(struct pt_regs *regs)
unlock_kernel();
}
+static char ecc_syndrome_table[] = {
+ 0x4c, 0x40, 0x41, 0x48, 0x42, 0x48, 0x48, 0x49,
+ 0x43, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4a,
+ 0x44, 0x48, 0x48, 0x20, 0x48, 0x39, 0x4b, 0x48,
+ 0x48, 0x25, 0x31, 0x48, 0x28, 0x48, 0x48, 0x2c,
+ 0x45, 0x48, 0x48, 0x21, 0x48, 0x3d, 0x04, 0x48,
+ 0x48, 0x4b, 0x35, 0x48, 0x2d, 0x48, 0x48, 0x29,
+ 0x48, 0x00, 0x01, 0x48, 0x0a, 0x48, 0x48, 0x4b,
+ 0x0f, 0x48, 0x48, 0x4b, 0x48, 0x49, 0x49, 0x48,
+ 0x46, 0x48, 0x48, 0x2a, 0x48, 0x3b, 0x27, 0x48,
+ 0x48, 0x4b, 0x33, 0x48, 0x22, 0x48, 0x48, 0x2e,
+ 0x48, 0x19, 0x1d, 0x48, 0x1b, 0x4a, 0x48, 0x4b,
+ 0x1f, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
+ 0x48, 0x4b, 0x24, 0x48, 0x07, 0x48, 0x48, 0x36,
+ 0x4b, 0x48, 0x48, 0x3e, 0x48, 0x30, 0x38, 0x48,
+ 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x16, 0x48,
+ 0x48, 0x12, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
+ 0x47, 0x48, 0x48, 0x2f, 0x48, 0x3f, 0x4b, 0x48,
+ 0x48, 0x06, 0x37, 0x48, 0x23, 0x48, 0x48, 0x2b,
+ 0x48, 0x05, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x32,
+ 0x26, 0x48, 0x48, 0x3a, 0x48, 0x34, 0x3c, 0x48,
+ 0x48, 0x11, 0x15, 0x48, 0x13, 0x4a, 0x48, 0x4b,
+ 0x17, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
+ 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x1e, 0x48,
+ 0x48, 0x1a, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
+ 0x48, 0x08, 0x0d, 0x48, 0x02, 0x48, 0x48, 0x49,
+ 0x03, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x4b, 0x48,
+ 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x10, 0x48,
+ 0x48, 0x14, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
+ 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x18, 0x48,
+ 0x48, 0x1c, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
+ 0x4a, 0x0c, 0x09, 0x48, 0x0e, 0x48, 0x48, 0x4b,
+ 0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
+};
+
+/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status
+ * in the following format. The AFAR is left as is, with
+ * reserved bits cleared, and is a raw 40-bit physical
+ * address.
+ */
+#define CE_STATUS_UDBH_UE (1UL << (43 + 9))
+#define CE_STATUS_UDBH_CE (1UL << (43 + 8))
+#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43)
+#define CE_STATUS_UDBH_SHIFT 43
+#define CE_STATUS_UDBL_UE (1UL << (33 + 9))
+#define CE_STATUS_UDBL_CE (1UL << (33 + 8))
+#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33)
+#define CE_STATUS_UDBL_SHIFT 33
+#define CE_STATUS_AFSR_MASK (0x1ffffffffUL)
+#define CE_STATUS_AFSR_ME (1UL << 32)
+#define CE_STATUS_AFSR_PRIV (1UL << 31)
+#define CE_STATUS_AFSR_ISAP (1UL << 30)
+#define CE_STATUS_AFSR_ETP (1UL << 29)
+#define CE_STATUS_AFSR_IVUE (1UL << 28)
+#define CE_STATUS_AFSR_TO (1UL << 27)
+#define CE_STATUS_AFSR_BERR (1UL << 26)
+#define CE_STATUS_AFSR_LDP (1UL << 25)
+#define CE_STATUS_AFSR_CP (1UL << 24)
+#define CE_STATUS_AFSR_WP (1UL << 23)
+#define CE_STATUS_AFSR_EDP (1UL << 22)
+#define CE_STATUS_AFSR_UE (1UL << 21)
+#define CE_STATUS_AFSR_CE (1UL << 20)
+#define CE_STATUS_AFSR_ETS (0xfUL << 16)
+#define CE_STATUS_AFSR_ETS_SHIFT 16
+#define CE_STATUS_AFSR_PSYND (0xffffUL << 0)
+#define CE_STATUS_AFSR_PSYND_SHIFT 0
+
+/* Layout of Ecache TAG Parity Syndrome of AFSR */
+#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */
+#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */
+#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */
+#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */
+
+static char *syndrome_unknown = "<Unknown>";
+
+asmlinkage void cee_log(unsigned long ce_status,
+ unsigned long afar,
+ struct pt_regs *regs)
+{
+ char memmod_str[64];
+ char *p;
+ unsigned short scode, udb_reg;
+
+ printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
+ "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n",
+ smp_processor_id(),
+ (ce_status & CE_STATUS_AFSR_MASK),
+ afar,
+ ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL),
+ ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL));
+
+ udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL);
+ if (udb_reg & (1 << 8)) {
+ scode = ecc_syndrome_table[udb_reg & 0xff];
+ if (prom_getunumber(scode, afar,
+ memmod_str, sizeof(memmod_str)) == -1)
+ p = syndrome_unknown;
+ else
+ p = memmod_str;
+ printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] "
+ "Memory Module \"%s\"\n",
+ smp_processor_id(), scode, p);
+ }
+
+ udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL);
+ if (udb_reg & (1 << 8)) {
+ scode = ecc_syndrome_table[udb_reg & 0xff];
+ if (prom_getunumber(scode, afar,
+ memmod_str, sizeof(memmod_str)) == -1)
+ p = syndrome_unknown;
+ else
+ p = memmod_str;
+ printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] "
+ "Memory Module \"%s\"\n",
+ smp_processor_id(), scode, p);
+ }
+}
+
void do_fpe_common(struct pt_regs *regs)
{
if(regs->tstate & TSTATE_PRIV) {
regs->tpc = regs->tnpc;
regs->tnpc += 4;
} else {
- current->tss.sig_address = regs->tpc;
- current->tss.sig_desc = SUBSIG_FPERROR;
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_FPERROR;
send_sig(SIGFPE, current, 1);
}
}
@@ -411,7 +528,7 @@ void do_fpe_common(struct pt_regs *regs)
void do_fpieee(struct pt_regs *regs)
{
#ifdef DEBUG_FPU
- printk("fpieee %016lx\n", current->tss.xfsr[0]);
+ printk("fpieee %016lx\n", current->thread.xfsr[0]);
#endif
do_fpe_common(regs);
}
@@ -423,7 +540,7 @@ void do_fpother(struct pt_regs *regs)
struct fpustate *f = FPUSTATE;
int ret = 0;
- switch ((current->tss.xfsr[0] & 0x1c000)) {
+ switch ((current->thread.xfsr[0] & 0x1c000)) {
case (2 << 14): /* unfinished_FPop */
case (3 << 14): /* unimplemented_FPop */
ret = do_mathemu(regs, f);
@@ -431,7 +548,7 @@ void do_fpother(struct pt_regs *regs)
}
if (ret) return;
#ifdef DEBUG_FPU
- printk("fpother %016lx\n", current->tss.xfsr[0]);
+ printk("fpother %016lx\n", current->thread.xfsr[0]);
#endif
do_fpe_common(regs);
}
@@ -440,8 +557,8 @@ void do_tof(struct pt_regs *regs)
{
if(regs->tstate & TSTATE_PRIV)
die_if_kernel("Penguin overflow trap from kernel mode", regs);
- current->tss.sig_address = regs->tpc;
- current->tss.sig_desc = SUBSIG_TAG; /* as good as any */
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_TAG; /* as good as any */
send_sig(SIGEMT, current, 1);
}
@@ -540,7 +657,7 @@ void do_illegal_instruction(struct pt_regs *regs)
if(tstate & TSTATE_PRIV)
die_if_kernel("Kernel illegal instruction", regs);
- if(current->tss.flags & SPARC_FLAG_32BIT)
+ if(current->thread.flags & SPARC_FLAG_32BIT)
pc = (u32)pc;
if (get_user(insn, (u32 *)pc) != -EFAULT) {
if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ {
@@ -551,8 +668,8 @@ void do_illegal_instruction(struct pt_regs *regs)
return;
}
}
- current->tss.sig_address = pc;
- current->tss.sig_desc = SUBSIG_ILLINST;
+ current->thread.sig_address = pc;
+ current->thread.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
}
@@ -565,23 +682,23 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo
return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr);
} else {
- current->tss.sig_address = regs->tpc;
- current->tss.sig_desc = SUBSIG_PRIVINST;
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGBUS, current, 1);
}
}
void do_privop(struct pt_regs *regs)
{
- current->tss.sig_address = regs->tpc;
- current->tss.sig_desc = SUBSIG_PRIVINST;
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
}
void do_privact(struct pt_regs *regs)
{
- current->tss.sig_address = regs->tpc;
- current->tss.sig_desc = SUBSIG_PRIVINST;
+ current->thread.sig_address = regs->tpc;
+ current->thread.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
}
@@ -590,8 +707,8 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
{
if(tstate & TSTATE_PRIV)
die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
- current->tss.sig_address = pc;
- current->tss.sig_desc = SUBSIG_PRIVINST;
+ current->thread.sig_address = pc;
+ current->thread.sig_desc = SUBSIG_PRIVINST;
send_sig(SIGILL, current, 1);
}
@@ -727,4 +844,11 @@ void cache_flush_trap(struct pt_regs *regs)
void trap_init(void)
{
+ /* Attach to the address space of init_task. */
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+
+ /* NOTE: Other cpus have this done as they are started
+ * up on SMP.
+ */
}
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index 3a9fdf4d2..b378756c0 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.28 1999/03/29 12:38:10 jj Exp $
+/* $Id: ttable.S,v 1.29 1999/08/31 19:25:37 davem Exp $
* ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -57,7 +57,7 @@ tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f)
tl0_ivec: TRAP_IVEC
tl0_paw: TRAP(do_paw)
tl0_vaw: TRAP(do_vaw)
-tl0_cee: TRAP(do_cee)
+tl0_cee: TRAP_NOSAVE(cee_trap)
tl0_iamiss:
#include "itlb_base.S"
tl0_damiss:
@@ -202,7 +202,7 @@ tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f)
tl1_ivec: TRAP_IVEC
tl1_paw: TRAPTL1(do_paw_tl1)
tl1_vaw: TRAPTL1(do_vaw_tl1)
-tl1_cee: TRAPTL1(do_cee_tl1)
+tl1_cee: TRAPTL1_CEE
tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67)
tl1_damiss:
#include "dtlb_backend.S"
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 3b813f415..792334336 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.16 1999/05/25 16:53:15 jj Exp $
+/* $Id: unaligned.c,v 1.18 1999/08/02 08:39:44 davem Exp $
* unaligned.c: Unaligned load/store trap handling with special
* cases for the kernel to do them more quickly.
*
@@ -70,7 +70,7 @@ static inline int decode_access_size(unsigned int insn)
return 2;
else {
printk("Impossible unaligned trap. insn=%08x\n", insn);
- die_if_kernel("Byte sized unaligned access?!?!", current->tss.kregs);
+ die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs);
}
}
@@ -117,7 +117,7 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
struct reg_window *win;
win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
value = win->locals[reg - 16];
- } else if (current->tss.flags & SPARC_FLAG_32BIT) {
+ } else if (current->thread.flags & SPARC_FLAG_32BIT) {
struct reg_window32 *win32;
win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
get_user(value, &win32->locals[reg - 16]);
@@ -137,7 +137,7 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
struct reg_window *win;
win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
return &win->locals[reg - 16];
- } else if (current->tss.flags & SPARC_FLAG_32BIT) {
+ } else if (current->thread.flags & SPARC_FLAG_32BIT) {
struct reg_window32 *win32;
win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
return (unsigned long *)&win32->locals[reg - 16];
@@ -164,10 +164,10 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs,
}
}
-/* This is just to make gcc think panic does return... */
-static void unaligned_panic(char *str)
+/* This is just to make gcc think die_if_kernel does return... */
+static void unaligned_panic(char *str, struct pt_regs *regs)
{
- panic(str);
+ die_if_kernel(str, regs);
}
#define do_integer_load(dest_reg, size, saddr, is_signed, asi, errh) ({ \
@@ -380,7 +380,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
if(!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n",
regs->tpc);
- unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store.");
+ unaligned_panic("Kernel does fpu/atomic unaligned load/store.", regs);
__asm__ __volatile__ ("\n"
"kernel_unaligned_trap_fault:\n\t"
@@ -453,7 +453,7 @@ int handle_popc(u32 insn, struct pt_regs *regs)
if (rd)
regs->u_regs[rd] = ret;
} else {
- if (current->tss.flags & SPARC_FLAG_32BIT) {
+ if (current->thread.flags & SPARC_FLAG_32BIT) {
struct reg_window32 *win32;
win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
put_user(ret, &win32->locals[rd - 16]);
@@ -480,9 +480,9 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
int flag = (freg < 32) ? FPRS_DL : FPRS_DU;
save_and_clear_fpu();
- current->tss.xfsr[0] &= ~0x1c000;
+ current->thread.xfsr[0] &= ~0x1c000;
if (freg & 3) {
- current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
+ current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
do_fpother(regs);
return 0;
}
@@ -490,7 +490,7 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
/* STQ */
u64 first = 0, second = 0;
- if (current->tss.fpsaved[0] & flag) {
+ if (current->thread.fpsaved[0] & flag) {
first = *(u64 *)&f->regs[freg];
second = *(u64 *)&f->regs[freg+2];
}
@@ -565,18 +565,18 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs)
break;
}
}
- if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
- current->tss.fpsaved[0] = FPRS_FEF;
- current->tss.gsr[0] = 0;
+ if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
+ current->thread.fpsaved[0] = FPRS_FEF;
+ current->thread.gsr[0] = 0;
}
- if (!(current->tss.fpsaved[0] & flag)) {
+ if (!(current->thread.fpsaved[0] & flag)) {
if (freg < 32)
memset(f->regs, 0, 32*sizeof(u32));
else
memset(f->regs+32, 0, 32*sizeof(u32));
}
memcpy(f->regs + freg, data, size * 4);
- current->tss.fpsaved[0] |= flag;
+ current->thread.fpsaved[0] |= flag;
}
advance(regs);
return 1;
@@ -609,7 +609,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
if(tstate & TSTATE_PRIV)
die_if_kernel("lddfmna from kernel", regs);
- if(current->tss.flags & SPARC_FLAG_32BIT)
+ if(current->thread.flags & SPARC_FLAG_32BIT)
pc = (u32)pc;
if (get_user(insn, (u32 *)pc) != -EFAULT) {
asi = sfsr >> 16;
@@ -629,18 +629,18 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
if (asi & 0x8) /* Little */
value = __swab64p(&value);
flag = (freg < 32) ? FPRS_DL : FPRS_DU;
- if (!(current->tss.fpsaved[0] & FPRS_FEF)) {
- current->tss.fpsaved[0] = FPRS_FEF;
- current->tss.gsr[0] = 0;
+ if (!(current->thread.fpsaved[0] & FPRS_FEF)) {
+ current->thread.fpsaved[0] = FPRS_FEF;
+ current->thread.gsr[0] = 0;
}
- if (!(current->tss.fpsaved[0] & flag)) {
+ if (!(current->thread.fpsaved[0] & flag)) {
if (freg < 32)
memset(f->regs, 0, 32*sizeof(u32));
else
memset(f->regs+32, 0, 32*sizeof(u32));
}
*(u64 *)(f->regs + freg) = value;
- current->tss.fpsaved[0] |= flag;
+ current->thread.fpsaved[0] |= flag;
} else {
daex: data_access_exception(regs);
return;
@@ -661,7 +661,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
if(tstate & TSTATE_PRIV)
die_if_kernel("stdfmna from kernel", regs);
- if(current->tss.flags & SPARC_FLAG_32BIT)
+ if(current->thread.flags & SPARC_FLAG_32BIT)
pc = (u32)pc;
if (get_user(insn, (u32 *)pc) != -EFAULT) {
freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20);
@@ -672,7 +672,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
(asi < ASI_P))
goto daex;
save_and_clear_fpu();
- if (current->tss.fpsaved[0] & flag)
+ if (current->thread.fpsaved[0] & flag)
value = *(u64 *)&f->regs[freg];
switch (asi) {
case ASI_P:
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S
index 5bf82db59..67653fef1 100644
--- a/arch/sparc64/kernel/winfixup.S
+++ b/arch/sparc64/kernel/winfixup.S
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.27 1998/09/25 01:09:14 davem Exp $
+/* $Id: winfixup.S,v 1.28 1999/07/30 09:35:34 davem Exp $
*
* winfixup.S: Handle cases where user stack pointer is found to be bogus.
*
@@ -95,56 +95,56 @@ fill_fixup:
* do not touch %g7 or %g2 so we handle the two cases fine.
*/
spill_fixup:
- lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
andcc %g1, SPARC_FLAG_32BIT, %g0
- lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
sll %g1, 3, %g3
add %g6, %g3, %g3
- stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ stx %sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
sll %g1, 7, %g3
bne,pt %xcc, 1f
add %g6, %g3, %g3
- stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
- stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-
- stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
- stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
- stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
- stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
- stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
- stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
- stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
-
- stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
- stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
- stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
- stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
- stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+ stx %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+
+ stx %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+ stx %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+ stx %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
+
+ stx %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+ stx %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
+ stx %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
b,pt %xcc, 2f
- stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
-1: stw %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-
- stw %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04]
- stw %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
- stw %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c]
- stw %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
- stw %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14]
- stw %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
- stw %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c]
- stw %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-
- stw %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24]
- stw %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
- stw %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c]
- stw %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- stw %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34]
- stw %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
- stw %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c]
+ stx %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
+1: stw %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+
+ stw %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x04]
+ stw %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+ stw %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x0c]
+ stw %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+ stw %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x14]
+ stw %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+ stw %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x1c]
+ stw %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+
+ stw %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x24]
+ stw %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+ stw %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x2c]
+ stw %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+ stw %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x34]
+ stw %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+ stw %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x3c]
2: add %g1, 1, %g1
- sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+ stb %g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
rdpr %tstate, %g1
andcc %g1, TSTATE_PRIV, %g0
saved
@@ -208,47 +208,47 @@ fill_fixup_mna:
b,pt %xcc, rtrap
nop ! yes, the nop is correct
spill_fixup_mna:
- lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
andcc %g1, SPARC_FLAG_32BIT, %g0
- lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
sll %g1, 3, %g3
add %g6, %g3, %g3
- stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ stx %sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
sll %g1, 7, %g3
bne,pt %xcc, 1f
add %g6, %g3, %g3
- stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
- stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
- stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
- stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
- stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-
- stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
- stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
- stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
- stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
- stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
- stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
- stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
-
- stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
- stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
- stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+ stx %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+ stx %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+
+ stx %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+ stx %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
+ stx %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+
+ stx %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
+ stx %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
+ stx %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
b,pt %xcc, 2f
add %g1, 1, %g1
-1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
- std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
- std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-
- std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
- std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
- std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
- std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+1: std %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+ std %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+ std %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+
+ std %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+ std %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+ std %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+ std %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+ std %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
add %g1, 1, %g1
-2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+2: stb %g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
rdpr %tstate, %g1
andcc %g1, TSTATE_PRIV, %g0
@@ -315,47 +315,47 @@ fill_fixup_dax:
b,pt %xcc, rtrap
nop ! yes, the nop is correct
spill_fixup_dax:
- lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %g1
andcc %g1, SPARC_FLAG_32BIT, %g0
- lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+ ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1
sll %g1, 3, %g3
add %g6, %g3, %g3
- stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+ stx %sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs]
sll %g1, 7, %g3
bne,pt %xcc, 1f
add %g6, %g3, %g3
- stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
- stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
- stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
- stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
- stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-
- stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
- stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
- stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
- stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
- stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
- stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
- stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
-
- stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
- stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
- stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+ stx %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+ stx %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+ stx %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+ stx %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+ stx %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+
+ stx %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+ stx %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+ stx %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
+ stx %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40]
+ stx %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48]
+ stx %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50]
+ stx %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58]
+ stx %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60]
+
+ stx %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68]
+ stx %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70]
+ stx %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78]
b,pt %xcc, 2f
add %g1, 1, %g1
-1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
- std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
- std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-
- std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
- std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
- std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
- std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
- std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+1: std %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00]
+ std %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08]
+ std %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10]
+
+ std %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18]
+ std %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20]
+ std %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28]
+ std %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30]
+ std %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38]
add %g1, 1, %g1
-2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+2: stb %g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]
rdpr %tstate, %g1
andcc %g1, TSTATE_PRIV, %g0