summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile1
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c4
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c1
-rw-r--r--arch/sparc64/kernel/central.c4
-rw-r--r--arch/sparc64/kernel/chmc.c3
-rw-r--r--arch/sparc64/kernel/ebus.c8
-rw-r--r--arch/sparc64/kernel/entry.S30
-rw-r--r--arch/sparc64/kernel/head.S8
-rw-r--r--arch/sparc64/kernel/isa.c20
-rw-r--r--arch/sparc64/kernel/kprobes.c91
-rw-r--r--arch/sparc64/kernel/of_device.c45
-rw-r--r--arch/sparc64/kernel/pci.c9
-rw-r--r--arch/sparc64/kernel/pci_common.c29
-rw-r--r--arch/sparc64/kernel/pci_iommu.c2
-rw-r--r--arch/sparc64/kernel/pci_sabre.c23
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c16
-rw-r--r--arch/sparc64/kernel/prom.c51
-rw-r--r--arch/sparc64/kernel/ptrace.c5
-rw-r--r--arch/sparc64/kernel/rtrap.S23
-rw-r--r--arch/sparc64/kernel/setup.c2
-rw-r--r--arch/sparc64/kernel/stacktrace.c41
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S20
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c4
-rw-r--r--arch/sparc64/kernel/systbls.S8
-rw-r--r--arch/sparc64/kernel/traps.c38
-rw-r--r--arch/sparc64/kernel/unaligned.c44
-rw-r--r--arch/sparc64/kernel/visemul.c6
-rw-r--r--arch/sparc64/kernel/vmlinux.lds.S9
28 files changed, 348 insertions, 197 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index e1eabebaed39..eff0c01d3579 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -14,6 +14,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
visemul.o prom.o of_device.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index d7caa60a0074..f205fc7cbcd0 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -209,7 +209,7 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) ||
N_TRSIZE(ex) || N_DRSIZE(ex) ||
- bprm->file->f_dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
+ bprm->file->f_path.dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) {
return -ENOEXEC;
}
@@ -349,7 +349,7 @@ static int load_aout32_library(struct file *file)
int retval;
struct exec ex;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
retval = -ENOEXEC;
error = kernel_read(file, 0, (char *) &ex, sizeof(ex));
diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
index a98f3ae175a3..9ad84ff10a17 100644
--- a/arch/sparc64/kernel/binfmt_elf32.c
+++ b/arch/sparc64/kernel/binfmt_elf32.c
@@ -141,7 +141,6 @@ cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
value->tv_sec = jiffies / HZ;
}
-#define elf_addr_t u32
#undef start_thread
#define start_thread start_thread32
#define init_elf_binfmt init_elf32_binfmt
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index b66336db00ee..e724c54af029 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -126,6 +126,10 @@ static void probe_other_fhcs(void)
int board;
u32 tmp;
+ if (dp->parent &&
+ dp->parent->parent != NULL)
+ continue;
+
fhc = (struct linux_fhc *)
central_alloc_bootmem(sizeof(struct linux_fhc));
if (fhc == NULL)
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c
index 259f37e516f5..9699abeb9907 100644
--- a/arch/sparc64/kernel/chmc.c
+++ b/arch/sparc64/kernel/chmc.c
@@ -341,7 +341,7 @@ static void fetch_decode_regs(struct mctrl_info *mp)
static int init_one_mctrl(struct device_node *dp)
{
- struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+ struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
int portid = of_getintprop_default(dp, "portid", -1);
struct linux_prom64_registers *regs;
void *pval;
@@ -349,7 +349,6 @@ static int init_one_mctrl(struct device_node *dp)
if (!mp)
return -1;
- memset(mp, 0, sizeof(*mp));
if (portid == -1)
goto fail;
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 2df25c2b4071..35bf895fdeee 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -389,12 +389,12 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
- strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
+ sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
/* Register with core */
if (of_device_register(&dev->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- dev->ofdev.dev.bus_id);
+ dp->path_component_name);
dp = dp->child;
if (dp) {
@@ -494,12 +494,12 @@ void __init ebus_init(void)
ebus->ofdev.node = dp;
ebus->ofdev.dev.parent = &pdev->dev;
ebus->ofdev.dev.bus = &ebus_bus_type;
- strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
+ sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
/* Register with core */
if (of_device_register(&ebus->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
- ebus->ofdev.dev.bus_id);
+ dp->path_component_name);
child = dp->child;
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 0aaa35fc5a9c..c15a3edcb826 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -22,11 +22,10 @@
#include <asm/auxio.h>
#include <asm/sfafsr.h>
#include <asm/pil.h>
+#include <asm/unistd.h>
#define curptr g6
-#define NR_SYSCALLS 300 /* Each OS is different... */
-
.text
.align 32
@@ -598,7 +597,12 @@ __spitfire_cee_trap_continue:
1: ba,pt %xcc, etrap_irq
rd %pc, %g7
-2: mov %l4, %o1
+2:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
mov %l5, %o2
call spitfire_access_error
add %sp, PTREGS_OFF, %o0
@@ -825,6 +829,10 @@ do_cheetah_plus_data_parity:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov 0x0, %o0
call cheetah_plus_parity_error
add %sp, PTREGS_OFF, %o1
@@ -856,6 +864,10 @@ do_cheetah_plus_insn_parity:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov 0x1, %o0
call cheetah_plus_parity_error
add %sp, PTREGS_OFF, %o1
@@ -1184,6 +1196,10 @@ c_fast_ecc:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov %l4, %o1
mov %l5, %o2
call cheetah_fecc_handler
@@ -1212,6 +1228,10 @@ c_cee:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov %l4, %o1
mov %l5, %o2
call cheetah_cee_handler
@@ -1240,6 +1260,10 @@ c_deferred:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
mov %l4, %o1
mov %l5, %o2
call cheetah_deferred_handler
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index c8e9dc9d68a9..03ffaf895a22 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -489,6 +489,14 @@ tlb_fixup_done:
call __bzero
sub %o1, %o0, %o1
+#ifdef CONFIG_LOCKDEP
+ /* We have this call this super early, as even prom_init can grab
+ * spinlocks and thus call into the lockdep code.
+ */
+ call lockdep_init
+ nop
+#endif
+
mov %l6, %o1 ! OpenPROM stack
call prom_init
mov %l7, %o0 ! OpenPROM cif handler
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 0f3aec72ef5f..ad1c4f55420f 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -72,14 +72,12 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
- isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
+ isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
fatal_err("cannot allocate child isa_dev");
prom_halt();
}
- memset(isa_dev, 0, sizeof(*isa_dev));
-
/* Link it in to parent. */
isa_dev->next = parent_isa_dev->child;
parent_isa_dev->child = isa_dev;
@@ -104,23 +102,21 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
- isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
+ isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
return;
}
- memset(isa_dev, 0, sizeof(*isa_dev));
-
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
isa_dev->ofdev.dev.bus = &isa_bus_type;
- strcpy(isa_dev->ofdev.dev.bus_id, dp->path_component_name);
+ sprintf(isa_dev->ofdev.dev.bus_id, "isa[%08x]", dp->node);
/* Register with core */
if (of_device_register(&isa_dev->ofdev) != 0) {
printk(KERN_DEBUG "isa: device registration error for %s!\n",
- isa_dev->ofdev.dev.bus_id);
+ dp->path_component_name);
kfree(isa_dev);
goto next_sibling;
}
@@ -180,23 +176,21 @@ void __init isa_init(void)
pbm = pdev_cookie->pbm;
dp = pdev_cookie->prom_node;
- isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
+ isa_br = kzalloc(sizeof(*isa_br), GFP_KERNEL);
if (!isa_br) {
printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
return;
}
- memset(isa_br, 0, sizeof(*isa_br));
-
isa_br->ofdev.node = dp;
isa_br->ofdev.dev.parent = &pdev->dev;
isa_br->ofdev.dev.bus = &isa_bus_type;
- strcpy(isa_br->ofdev.dev.bus_id, dp->path_component_name);
+ sprintf(isa_br->ofdev.dev.bus_id, "isa%d", index);
/* Register with core */
if (of_device_register(&isa_br->ofdev) != 0) {
printk(KERN_DEBUG "isa: device registration error for %s!\n",
- isa_br->ofdev.dev.bus_id);
+ dp->path_component_name);
kfree(isa_br);
return;
}
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index 8e75ed762fd8..ae221f0d4a6f 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -45,7 +45,11 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
p->ainsn.insn[0] = *p->addr;
+ flushi(&p->ainsn.insn[0]);
+
p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
+ flushi(&p->ainsn.insn[1]);
+
p->opcode = *p->addr;
return 0;
}
@@ -185,16 +189,19 @@ no_kprobe:
/* If INSN is a relative control transfer instruction,
* return the corrected branch destination value.
*
- * The original INSN location was REAL_PC, it actually
- * executed at PC and produced destination address NPC.
+ * regs->tpc and regs->tnpc still hold the values of the
+ * program counters at the time of trap due to the execution
+ * of the BREAKPOINT_INSTRUCTION_2 at p->ainsn.insn[1]
+ *
*/
-static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
- unsigned long pc,
- unsigned long npc)
+static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p,
+ struct pt_regs *regs)
{
+ unsigned long real_pc = (unsigned long) p->addr;
+
/* Branch not taken, no mods necessary. */
- if (npc == pc + 0x4UL)
- return real_pc + 0x4UL;
+ if (regs->tnpc == regs->tpc + 0x4UL)
+ return real_pc + 0x8UL;
/* The three cases are call, branch w/prediction,
* and traditional branch.
@@ -202,14 +209,21 @@ static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
if ((insn & 0xc0000000) == 0x40000000 ||
(insn & 0xc1c00000) == 0x00400000 ||
(insn & 0xc1c00000) == 0x00800000) {
+ unsigned long ainsn_addr;
+
+ ainsn_addr = (unsigned long) &p->ainsn.insn[0];
+
/* The instruction did all the work for us
* already, just apply the offset to the correct
* instruction location.
*/
- return (real_pc + (npc - pc));
+ return (real_pc + (regs->tnpc - ainsn_addr));
}
- return real_pc + 0x4UL;
+ /* It is jmpl or some other absolute PC modification instruction,
+ * leave NPC as-is.
+ */
+ return regs->tnpc;
}
/* If INSN is an instruction which writes it's PC location
@@ -220,12 +234,12 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
{
unsigned long *slot = NULL;
- /* Simplest cast is call, which always uses %o7 */
+ /* Simplest case is 'call', which always uses %o7 */
if ((insn & 0xc0000000) == 0x40000000) {
slot = &regs->u_regs[UREG_I7];
}
- /* Jmpl encodes the register inside of the opcode */
+ /* 'jmpl' encodes the register inside of the opcode */
if ((insn & 0xc1f80000) == 0x81c00000) {
unsigned long rd = ((insn >> 25) & 0x1f);
@@ -247,11 +261,11 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
/*
* Called after single-stepping. p->addr is the address of the
- * instruction whose first byte has been replaced by the breakpoint
+ * instruction which has been replaced by the breakpoint
* instruction. To avoid the SMP problems that can occur when we
* temporarily put back the original opcode to single-step, we
* single-stepped a copy of the instruction. The address of this
- * copy is p->ainsn.insn.
+ * copy is &p->ainsn.insn[0].
*
* This function prepares to return from the post-single-step
* breakpoint trap.
@@ -261,11 +275,11 @@ static void __kprobes resume_execution(struct kprobe *p,
{
u32 insn = p->ainsn.insn[0];
+ regs->tnpc = relbranch_fixup(insn, p, regs);
+
+ /* This assignment must occur after relbranch_fixup() */
regs->tpc = kcb->kprobe_orig_tnpc;
- regs->tnpc = relbranch_fixup(insn,
- (unsigned long) p->addr,
- (unsigned long) &p->ainsn.insn[0],
- regs->tnpc);
+
retpc_fixup(regs, insn, (unsigned long) p->addr);
regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
@@ -430,17 +444,8 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
struct jprobe *jp = container_of(p, struct jprobe, kp);
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
- kcb->jprobe_saved_regs_location = regs;
memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs));
- /* Save a whole stack frame, this gets arguments
- * pushed onto the stack after using up all the
- * arg registers.
- */
- memcpy(&(kcb->jprobe_saved_stack),
- (char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
- sizeof(kcb->jprobe_saved_stack));
-
regs->tpc = (unsigned long) jp->entry;
regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
regs->tstate |= TSTATE_PIL;
@@ -450,10 +455,19 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
void __kprobes jprobe_return(void)
{
- __asm__ __volatile__(
- ".globl jprobe_return_trap_instruction\n"
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ register unsigned long orig_fp asm("g1");
+
+ orig_fp = kcb->jprobe_saved_regs.u_regs[UREG_FP];
+ __asm__ __volatile__("\n"
+"1: cmp %%sp, %0\n\t"
+ "blu,a,pt %%xcc, 1b\n\t"
+ " restore\n\t"
+ ".globl jprobe_return_trap_instruction\n"
"jprobe_return_trap_instruction:\n\t"
- "ta 0x70");
+ "ta 0x70"
+ : /* no outputs */
+ : "r" (orig_fp));
}
extern void jprobe_return_trap_instruction(void);
@@ -466,26 +480,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
if (addr == (u32 *) jprobe_return_trap_instruction) {
- if (kcb->jprobe_saved_regs_location != regs) {
- printk("JPROBE: Current regs (%p) does not match "
- "saved regs (%p).\n",
- regs, kcb->jprobe_saved_regs_location);
- printk("JPROBE: Saved registers\n");
- __show_regs(kcb->jprobe_saved_regs_location);
- printk("JPROBE: Current registers\n");
- __show_regs(regs);
- BUG();
- }
- /* Restore old register state. Do pt_regs
- * first so that UREG_FP is the original one for
- * the stack frame restore.
- */
memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs));
-
- memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS),
- &(kcb->jprobe_saved_stack),
- sizeof(kcb->jprobe_saved_stack));
-
preempt_enable_no_resched();
return 1;
}
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index d822c7c18e1f..cec0eceae552 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -131,8 +131,13 @@ static int of_device_resume(struct device * dev)
void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
{
unsigned long ret = res->start + offset;
+ struct resource *r;
- if (!request_region(ret, size, name))
+ if (res->flags & IORESOURCE_MEM)
+ r = request_mem_region(ret, size, name);
+ else
+ r = request_region(ret, size, name);
+ if (!r)
ret = 0;
return (void __iomem *) ret;
@@ -397,16 +402,22 @@ static void of_bus_sbus_count_cells(struct device_node *child,
*sizec = 1;
}
-static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- return of_bus_default_map(addr, range, na, ns, pna);
-}
-
-static unsigned int of_bus_sbus_get_flags(u32 *addr)
+/*
+ * FHC/Central bus specific translator.
+ *
+ * This is just needed to hard-code the address and size cell
+ * counts. 'fhc' and 'central' nodes lack the #address-cells and
+ * #size-cells properties, and if you walk to the root on such
+ * Enterprise boxes all you'll get is a #size-cells of 2 which is
+ * not what we want to use.
+ */
+static int of_bus_fhc_match(struct device_node *np)
{
- return IORESOURCE_MEM;
+ return !strcmp(np->name, "fhc") ||
+ !strcmp(np->name, "central");
}
+#define of_bus_fhc_count_cells of_bus_sbus_count_cells
/*
* Array of bus specific translators
@@ -428,8 +439,17 @@ static struct of_bus of_busses[] = {
.addr_prop_name = "reg",
.match = of_bus_sbus_match,
.count_cells = of_bus_sbus_count_cells,
- .map = of_bus_sbus_map,
- .get_flags = of_bus_sbus_get_flags,
+ .map = of_bus_default_map,
+ .get_flags = of_bus_default_get_flags,
+ },
+ /* FHC */
+ {
+ .name = "fhc",
+ .addr_prop_name = "reg",
+ .match = of_bus_fhc_match,
+ .count_cells = of_bus_fhc_count_cells,
+ .map = of_bus_default_map,
+ .get_flags = of_bus_default_get_flags,
},
/* Default */
{
@@ -841,7 +861,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
if (!parent)
strcpy(op->dev.bus_id, "root");
else
- sprintf(op->dev.bus_id, "%s@%08x", dp->name, dp->node);
+ sprintf(op->dev.bus_id, "%08x", dp->node);
if (of_device_register(op)) {
printk("%s: Could not register of device.\n",
@@ -987,10 +1007,9 @@ struct of_device* of_platform_device_create(struct device_node *np,
{
struct of_device *dev;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->dev.parent = parent;
dev->dev.bus = bus;
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index e02f01b644af..dfc41cd4bb5d 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -646,13 +646,4 @@ int pci_domain_nr(struct pci_bus *pbus)
}
EXPORT_SYMBOL(pci_domain_nr);
-int pcibios_prep_mwi(struct pci_dev *dev)
-{
- /* We set correct PCI_CACHE_LINE_SIZE register values for every
- * device probed on this platform. So there is nothing to check
- * and this always succeeds.
- */
- return 0;
-}
-
#endif /* !(CONFIG_PCI) */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 7a59cc72c844..827ae30aa497 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -330,19 +330,6 @@ __init get_device_resource(struct linux_prom_pci_registers *ap,
return res;
}
-static int __init pdev_resource_collisions_expected(struct pci_dev *pdev)
-{
- if (pdev->vendor != PCI_VENDOR_ID_SUN)
- return 0;
-
- if (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS ||
- pdev->device == PCI_DEVICE_ID_SUN_RIO_1394 ||
- pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
- return 1;
-
- return 0;
-}
-
static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
struct pci_dev *pdev)
{
@@ -400,19 +387,23 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
pbm->parent->resource_adjust(pdev, res, root);
if (request_resource(root, res) < 0) {
+ int rnum;
+
/* OK, there is some conflict. But this is fine
* since we'll reassign it in the fixup pass.
*
- * We notify the user that OBP made an error if it
- * is a case we don't expect.
+ * Do not print the warning for ROM resources
+ * as such a conflict is quite common and
+ * harmless as the ROM bar is disabled.
*/
- if (!pdev_resource_collisions_expected(pdev)) {
- printk(KERN_ERR "PCI: Address space collision on region %ld "
+ rnum = (res - &pdev->resource[0]);
+ if (rnum != PCI_ROM_RESOURCE)
+ printk(KERN_ERR "PCI: Resource collision, "
+ "region %d "
"[%016lx:%016lx] of device %s\n",
- (res - &pdev->resource[0]),
+ rnum,
res->start, res->end,
pci_name(pdev));
- }
}
}
}
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 82e5455134c6..2e7f1427088a 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -281,7 +281,7 @@ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu,
spin_lock_irqsave(&iommu->lock, flags);
- free_npages(iommu, dvma, npages);
+ free_npages(iommu, dvma - iommu->page_table_map_base, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 6ec569828c29..94bb681f2323 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1196,7 +1196,7 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p,
&pbm->mem_space);
}
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin)
+static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end)
{
struct pci_pbm_info *pbm;
struct device_node *node;
@@ -1261,6 +1261,8 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
node = node->sibling;
}
if (simbas_found == 0) {
+ struct resource *rp;
+
/* No APBs underneath, probably this is a hummingbird
* system.
*/
@@ -1302,8 +1304,10 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL;
pbm->io_space.flags = IORESOURCE_IO;
- pbm->mem_space.start = p->pbm_A.controller_regs + SABRE_MEMSPACE;
- pbm->mem_space.end = pbm->mem_space.start + (unsigned long)dma_begin - 1UL;
+ pbm->mem_space.start =
+ (p->pbm_A.controller_regs + SABRE_MEMSPACE);
+ pbm->mem_space.end =
+ (pbm->mem_space.start + ((1UL << 32UL) - 1UL));
pbm->mem_space.flags = IORESOURCE_MEM;
if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
@@ -1315,6 +1319,17 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
prom_halt();
}
+ rp = kmalloc(sizeof(*rp), GFP_KERNEL);
+ if (!rp) {
+ prom_printf("Cannot allocate IOMMU resource.\n");
+ prom_halt();
+ }
+ rp->name = "IOMMU";
+ rp->start = pbm->mem_space.start + (unsigned long) dma_start;
+ rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL;
+ rp->flags = IORESOURCE_BUSY;
+ request_resource(&pbm->mem_space, rp);
+
pci_register_legacy_regions(&pbm->io_space,
&pbm->mem_space);
}
@@ -1450,5 +1465,5 @@ void sabre_init(struct device_node *dp, char *model_name)
/*
* Look for APB underneath.
*/
- sabre_pbm_init(p, dp, vdma[0]);
+ sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]);
}
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 03ad4c06758e..6b04794b7a97 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -798,7 +798,7 @@ static struct pci_ops pci_sun4v_ops = {
static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
{
- struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL);
+ struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (!cookie) {
prom_printf("%s: Critical allocation failure.\n", pbm->name);
@@ -806,7 +806,6 @@ static void pbm_scan_bus(struct pci_controller_info *p,
}
/* All we care about is the PBM. */
- memset(cookie, 0, sizeof(*cookie));
cookie->pbm = pbm;
pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm);
@@ -1048,12 +1047,11 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
/* Allocate and initialize the free area map. */
sz = num_tsb_entries / 8;
sz = (sz + 7UL) & ~7UL;
- iommu->arena.map = kmalloc(sz, GFP_KERNEL);
+ iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) {
prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
prom_halt();
}
- memset(iommu->arena.map, 0, sz);
iommu->arena.limit = num_tsb_entries;
sz = probe_existing_entries(pbm, iommu);
@@ -1164,24 +1162,20 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
per_cpu(pci_iommu_batch, i).pglist = (u64 *) page;
}
- p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+ p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p)
goto fatal_memory_error;
- memset(p, 0, sizeof(*p));
-
- iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
- memset(iommu, 0, sizeof(*iommu));
p->pbm_A.iommu = iommu;
- iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
- memset(iommu, 0, sizeof(*iommu));
p->pbm_B.iommu = iommu;
p->next = pci_controller_root;
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index e21cd6afa709..0917c24c4f08 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -793,7 +793,7 @@ static unsigned int schizo_irq_build(struct device_node *dp,
return virt_irq;
}
-static void schizo_irq_trans_init(struct device_node *dp)
+static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
{
struct linux_prom64_registers *regs;
struct schizo_irq_data *irq_data;
@@ -807,11 +807,24 @@ static void schizo_irq_trans_init(struct device_node *dp)
dp->irq_trans->data = irq_data;
irq_data->pbm_regs = regs[0].phys_addr;
- irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
+ if (is_tomatillo)
+ irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
+ else
+ irq_data->sync_reg = 0UL;
irq_data->portid = of_getintprop_default(dp, "portid", 0);
irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
}
+static void schizo_irq_trans_init(struct device_node *dp)
+{
+ __schizo_irq_trans_init(dp, 0);
+}
+
+static void tomatillo_irq_trans_init(struct device_node *dp)
+{
+ __schizo_irq_trans_init(dp, 1);
+}
+
static unsigned int pci_sun4v_irq_build(struct device_node *dp,
unsigned int devino,
void *_data)
@@ -1050,8 +1063,8 @@ static struct irq_trans pci_irq_trans_table[] = {
{ "pci108e,8001", schizo_irq_trans_init },
{ "SUNW,schizo+", schizo_irq_trans_init },
{ "pci108e,8002", schizo_irq_trans_init },
- { "SUNW,tomatillo", schizo_irq_trans_init },
- { "pci108e,a801", schizo_irq_trans_init },
+ { "SUNW,tomatillo", tomatillo_irq_trans_init },
+ { "pci108e,a801", tomatillo_irq_trans_init },
{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
};
#endif
@@ -1079,23 +1092,22 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp)
static void irq_trans_init(struct device_node *dp)
{
- const char *model;
#ifdef CONFIG_PCI
+ const char *model;
int i;
#endif
+#ifdef CONFIG_PCI
model = of_get_property(dp, "model", NULL);
if (!model)
model = of_get_property(dp, "compatible", NULL);
- if (!model)
- return;
-
-#ifdef CONFIG_PCI
- for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
- struct irq_trans *t = &pci_irq_trans_table[i];
+ if (model) {
+ for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
+ struct irq_trans *t = &pci_irq_trans_table[i];
- if (!strcmp(model, t->name))
- return t->init(dp);
+ if (!strcmp(model, t->name))
+ return t->init(dp);
+ }
}
#endif
#ifdef CONFIG_SBUS
@@ -1103,8 +1115,9 @@ static void irq_trans_init(struct device_node *dp)
!strcmp(dp->name, "sbi"))
return sbus_irq_trans_init(dp);
#endif
- if (!strcmp(dp->name, "central"))
- return central_irq_trans_init(dp->child);
+ if (!strcmp(dp->name, "fhc") &&
+ !strcmp(dp->parent->name, "central"))
+ return central_irq_trans_init(dp);
if (!strcmp(dp->name, "virtual-devices"))
return sun4v_vdev_irq_trans_init(dp);
}
@@ -1516,7 +1529,7 @@ static char * __init get_one_property(phandle node, const char *name)
return buf;
}
-static struct device_node * __init create_node(phandle node)
+static struct device_node * __init create_node(phandle node, struct device_node *parent)
{
struct device_node *dp;
@@ -1525,6 +1538,7 @@ static struct device_node * __init create_node(phandle node)
dp = prom_early_alloc(sizeof(*dp));
dp->unique_id = unique_id++;
+ dp->parent = parent;
kref_init(&dp->kref);
@@ -1543,12 +1557,11 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
{
struct device_node *dp;
- dp = create_node(node);
+ dp = create_node(node, parent);
if (dp) {
*(*nextp) = dp;
*nextp = &dp->allnext;
- dp->parent = parent;
dp->path_component_name = build_path_component(dp);
dp->full_name = build_full_name(dp);
@@ -1564,7 +1577,7 @@ void __init prom_build_devicetree(void)
{
struct device_node **nextp;
- allnodes = create_node(prom_root_node);
+ allnodes = create_node(prom_root_node, NULL);
allnodes->path_component_name = "";
allnodes->full_name = "/";
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index d31975e6d6f6..81111a12f0a8 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -202,7 +202,10 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
#endif
if (request == PTRACE_TRACEME) {
ret = ptrace_traceme();
- pt_succ_return(regs, 0);
+ if (ret < 0)
+ pt_error_return(regs, -ret);
+ else
+ pt_succ_return(regs, 0);
goto out;
}
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S
index 3522cd66f3bb..079d18a11d24 100644
--- a/arch/sparc64/kernel/rtrap.S
+++ b/arch/sparc64/kernel/rtrap.S
@@ -165,14 +165,26 @@ rtrap:
__handle_softirq_continue:
rtrap_xcall:
sethi %hi(0xf << 20), %l4
- andcc %l1, TSTATE_PRIV, %l3
and %l1, %l4, %l4
+ andn %l1, %l4, %l1
+ srl %l4, 20, %l4
+#ifdef CONFIG_TRACE_IRQFLAGS
+ brnz,pn %l4, rtrap_no_irq_enable
+ nop
+ call trace_hardirqs_on
+ nop
+ wrpr %l4, %pil
+rtrap_no_irq_enable:
+#endif
+ andcc %l1, TSTATE_PRIV, %l3
bne,pn %icc, to_kernel
- andn %l1, %l4, %l1
+ nop
/* We must hold IRQs off and atomically test schedule+signal
* state, then hold them off all the way back to userspace.
- * If we are returning to kernel, none of this matters.
+ * If we are returning to kernel, none of this matters. Note
+ * that we are disabling interrupts via PSTATE_IE, not using
+ * %pil.
*
* If we do not do this, there is a window where we would do
* the tests, later the signal/resched event arrives but we do
@@ -256,7 +268,6 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
ld [%sp + PTREGS_OFF + PT_V9_Y], %o3
wr %o3, %g0, %y
- srl %l4, 20, %l4
wrpr %l4, 0x0, %pil
wrpr %g0, 0x1, %tl
wrpr %l1, %g0, %tstate
@@ -374,8 +385,8 @@ to_kernel:
ldx [%g6 + TI_FLAGS], %l5
andcc %l5, _TIF_NEED_RESCHED, %g0
be,pt %xcc, kern_fpucheck
- srl %l4, 20, %l5
- cmp %l5, 0
+ nop
+ cmp %l4, 0
bne,pn %xcc, kern_fpucheck
sethi %hi(PREEMPT_ACTIVE), %l6
stw %l6, [%g6 + TI_PRE_COUNT]
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index cc8ad480a204..bf033b31d437 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -74,7 +74,6 @@ prom_console_write(struct console *con, const char *s, unsigned n)
unsigned int boot_flags = 0;
#define BOOTME_DEBUG 0x1
-#define BOOTME_SINGLE 0x2
/* Exported for mm/init.c:paging_init. */
unsigned long cmdline_memory_size = 0;
@@ -102,7 +101,6 @@ static void __init process_switch(char c)
boot_flags |= BOOTME_DEBUG;
break;
case 's':
- boot_flags |= BOOTME_SINGLE;
break;
case 'h':
prom_printf("boot_flags_init: Halt!\n");
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
new file mode 100644
index 000000000000..c4d15f2762b9
--- /dev/null
+++ b/arch/sparc64/kernel/stacktrace.c
@@ -0,0 +1,41 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <asm/ptrace.h>
+
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+ unsigned long ksp, fp, thread_base;
+ struct thread_info *tp;
+
+ if (!task)
+ task = current;
+ tp = task_thread_info(task);
+ if (task == current) {
+ flushw_all();
+ __asm__ __volatile__(
+ "mov %%fp, %0"
+ : "=r" (ksp)
+ );
+ } else
+ ksp = tp->ksp;
+
+ fp = ksp + STACK_BIAS;
+ thread_base = (unsigned long) tp;
+ do {
+ struct reg_window *rw;
+
+ /* Bogus frame pointer? */
+ if (fp < (thread_base + sizeof(struct thread_info)) ||
+ fp >= (thread_base + THREAD_SIZE))
+ break;
+
+ rw = (struct reg_window *) fp;
+ if (trace->skip > 0)
+ trace->skip--;
+ else
+ trace->entries[trace->nr_entries++] = rw->ins[7];
+
+ fp = rw->ins[6] + STACK_BIAS;
+ } while (trace->nr_entries < trace->max_entries);
+}
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index 49703c3c5769..405855dd886b 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -190,7 +190,10 @@ sun4v_res_mondo:
mov %g1, %g4
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
/* Log the event. */
add %sp, PTREGS_OFF, %o0
call sun4v_resum_error
@@ -216,7 +219,10 @@ sun4v_res_mondo_queue_full:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
call sun4v_resum_overflow
add %sp, PTREGS_OFF, %o0
@@ -295,7 +301,10 @@ sun4v_nonres_mondo:
mov %g1, %g4
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
/* Log the event. */
add %sp, PTREGS_OFF, %o0
call sun4v_nonresum_error
@@ -321,7 +330,10 @@ sun4v_nonres_mondo_queue_full:
wrpr %g0, 15, %pil
ba,pt %xcc, etrap_irq
rd %pc, %g7
-
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
call sun4v_nonresum_overflow
add %sp, PTREGS_OFF, %o0
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 7da72d3b322a..4446f66590fa 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -83,7 +83,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
file = fget(fd);
if (!file)
goto out;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
if (imajor(inode) == MEM_MAJOR && iminor(inode) == 5) {
flags |= MAP_ANONYMOUS;
fput(file);
@@ -615,7 +615,7 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
if (!file)
return 0;
- inode = file->f_dentry->d_inode;
+ inode = file->f_path.dentry->d_inode;
socket = SOCKET_I(inode);
local.sin_family = AF_INET;
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 419a63fca172..9a8026797ac0 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -79,7 +79,7 @@ sys_call_table32:
.word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64
/*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
-/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list
+/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages
#endif /* CONFIG_COMPAT */
@@ -149,7 +149,7 @@ sys_call_table:
.word sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64
/*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat
.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
-/*300*/ .word sys_set_robust_list, sys_get_robust_list
+/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages
#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -262,5 +262,7 @@ sunos_sys_table:
/*290*/ .word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys, sunos_nosys, sunos_nosys
- .word sunos_nosys, sunos_nosys, sunos_nosys
+ .word sunos_nosys
+/*300*/ .word sunos_nosys, sunos_nosys, sunos_nosys
+
#endif
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 68420e2dad0e..ad67784292db 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -10,7 +10,7 @@
*/
#include <linux/module.h>
-#include <linux/sched.h> /* for jiffies */
+#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/kallsyms.h>
#include <linux/signal.h>
@@ -87,6 +87,7 @@ static void dump_tl1_traplog(struct tl1_traplog *p)
i + 1,
p->trapstack[i].tstate, p->trapstack[i].tpc,
p->trapstack[i].tnpc, p->trapstack[i].tt);
+ print_symbol("TRAPLOG: TPC<%s>\n", p->trapstack[i].tpc);
}
}
@@ -1134,6 +1135,9 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in
printk("%s" "ERROR(%d): TPC[%lx] TNPC[%lx] O7[%lx] TSTATE[%lx]\n",
(recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
regs->tpc, regs->tnpc, regs->u_regs[UREG_I7], regs->tstate);
+ printk("%s" "ERROR(%d): ",
+ (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id());
+ print_symbol("TPC<%s>\n", regs->tpc);
printk("%s" "ERROR(%d): M_SYND(%lx), E_SYND(%lx)%s%s\n",
(recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
(afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT,
@@ -1741,6 +1745,7 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs)
smp_processor_id(),
(type & 0x1) ? 'I' : 'D',
regs->tpc);
+ print_symbol(KERN_EMERG "TPC<%s>\n", regs->tpc);
panic("Irrecoverable Cheetah+ parity error.");
}
@@ -1748,6 +1753,7 @@ void cheetah_plus_parity_error(int type, struct pt_regs *regs)
smp_processor_id(),
(type & 0x1) ? 'I' : 'D',
regs->tpc);
+ print_symbol(KERN_WARNING "TPC<%s>\n", regs->tpc);
}
struct sun4v_error_entry {
@@ -1867,6 +1873,16 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
put_cpu();
+ if (ent->err_type == SUN4V_ERR_TYPE_WARNING_RES) {
+ /* If err_type is 0x4, it's a powerdown request. Do
+ * not do the usual resumable error log because that
+ * makes it look like some abnormal error.
+ */
+ printk(KERN_INFO "Power down request...\n");
+ kill_cad_pid(SIGINT, 1);
+ return;
+ }
+
sun4v_log_error(regs, &local_copy, cpu,
KERN_ERR "RESUMABLE ERROR",
&sun4v_resum_oflow_cnt);
@@ -1946,6 +1962,7 @@ void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n",
regs->tpc, tl);
+ print_symbol(KERN_EMERG "SUN4V-ITLB: TPC<%s>\n", regs->tpc);
printk(KERN_EMERG "SUN4V-ITLB: vaddr[%lx] ctx[%lx] "
"pte[%lx] error[%lx]\n",
sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx,
@@ -1966,6 +1983,7 @@ void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n",
regs->tpc, tl);
+ print_symbol(KERN_EMERG "SUN4V-DTLB: TPC<%s>\n", regs->tpc);
printk(KERN_EMERG "SUN4V-DTLB: vaddr[%lx] ctx[%lx] "
"pte[%lx] error[%lx]\n",
sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx,
@@ -2253,8 +2271,12 @@ void die_if_kernel(char *str, struct pt_regs *regs)
do_exit(SIGSEGV);
}
+#define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19))
+#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
+
extern int handle_popc(u32 insn, struct pt_regs *regs);
extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
+extern int vis_emul(struct pt_regs *, unsigned int);
void do_illegal_instruction(struct pt_regs *regs)
{
@@ -2279,10 +2301,18 @@ void do_illegal_instruction(struct pt_regs *regs)
if (handle_ldf_stq(insn, regs))
return;
} else if (tlb_type == hypervisor) {
- extern int vis_emul(struct pt_regs *, unsigned int);
+ if ((insn & VIS_OPCODE_MASK) == VIS_OPCODE_VAL) {
+ if (!vis_emul(regs, insn))
+ return;
+ } else {
+ struct fpustate *f = FPUSTATE;
- if (!vis_emul(regs, insn))
- return;
+ /* XXX maybe verify XFSR bits like
+ * XXX do_fpother() does?
+ */
+ if (do_mathemu(regs, f))
+ return;
+ }
}
}
info.si_signo = SIGILL;
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index a9b765271b85..bc18d480dd1c 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -243,7 +243,7 @@ static inline int ok_for_kernel(unsigned int insn)
return !floating_point_load_or_store_p(insn);
}
-static void kernel_mna_trap_fault(void)
+static void kernel_mna_trap_fault(int fixup_tstate_asi)
{
struct pt_regs *regs = current_thread_info()->kern_una_regs;
unsigned int insn = current_thread_info()->kern_una_insn;
@@ -274,18 +274,15 @@ static void kernel_mna_trap_fault(void)
regs->tpc = entry->fixup;
regs->tnpc = regs->tpc + 4;
- regs->tstate &= ~TSTATE_ASI;
- regs->tstate |= (ASI_AIUS << 24UL);
+ if (fixup_tstate_asi) {
+ regs->tstate &= ~TSTATE_ASI;
+ regs->tstate |= (ASI_AIUS << 24UL);
+ }
}
-asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+static void log_unaligned(struct pt_regs *regs)
{
static unsigned long count, last_time;
- enum direction dir = decode_direction(insn);
- int size = decode_access_size(insn);
-
- current_thread_info()->kern_una_regs = regs;
- current_thread_info()->kern_una_insn = insn;
if (jiffies - last_time > 5 * HZ)
count = 0;
@@ -295,6 +292,28 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
printk("Kernel unaligned access at TPC[%lx] ", regs->tpc);
print_symbol("%s\n", regs->tpc);
}
+}
+
+asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
+{
+ enum direction dir = decode_direction(insn);
+ int size = decode_access_size(insn);
+ int orig_asi, asi;
+
+ current_thread_info()->kern_una_regs = regs;
+ current_thread_info()->kern_una_insn = insn;
+
+ orig_asi = asi = decode_asi(insn, regs);
+
+ /* If this is a {get,put}_user() on an unaligned userspace pointer,
+ * just signal a fault and do not log the event.
+ */
+ if (asi == ASI_AIUS) {
+ kernel_mna_trap_fault(0);
+ return;
+ }
+
+ log_unaligned(regs);
if (!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel "
@@ -302,10 +321,10 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
unaligned_panic("Kernel does fpu/atomic "
"unaligned load/store.", regs);
- kernel_mna_trap_fault();
+ kernel_mna_trap_fault(0);
} else {
unsigned long addr, *reg_addr;
- int orig_asi, asi, err;
+ int err;
addr = compute_effective_address(regs, insn,
((insn >> 25) & 0x1f));
@@ -315,7 +334,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
regs->tpc, dirstrings[dir], addr, size,
regs->u_regs[UREG_RETPC]);
#endif
- orig_asi = asi = decode_asi(insn, regs);
switch (asi) {
case ASI_NL:
case ASI_AIUPL:
@@ -365,7 +383,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
/* Not reached... */
}
if (unlikely(err))
- kernel_mna_trap_fault();
+ kernel_mna_trap_fault(1);
else
advance(regs);
}
diff --git a/arch/sparc64/kernel/visemul.c b/arch/sparc64/kernel/visemul.c
index 84fedaa38aae..c3fd64706b53 100644
--- a/arch/sparc64/kernel/visemul.c
+++ b/arch/sparc64/kernel/visemul.c
@@ -128,9 +128,6 @@
/* 001001100 - Permute bytes as specified by GSR.MASK */
#define BSHUFFLE_OPF 0x04c
-#define VIS_OPCODE_MASK ((0x3 << 30) | (0x3f << 19))
-#define VIS_OPCODE_VAL ((0x2 << 30) | (0x36 << 19))
-
#define VIS_OPF_SHIFT 5
#define VIS_OPF_MASK (0x1ff << VIS_OPF_SHIFT)
@@ -810,9 +807,6 @@ int vis_emul(struct pt_regs *regs, unsigned int insn)
if (get_user(insn, (u32 __user *) pc))
return -EFAULT;
- if ((insn & VIS_OPCODE_MASK) != VIS_OPCODE_VAL)
- return -EINVAL;
-
opf = (insn & VIS_OPF_MASK) >> VIS_OPF_SHIFT;
switch (opf) {
default:
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index b097379a49a8..4a6063f33e7a 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -13,6 +13,7 @@ SECTIONS
. = 0x4000;
.text 0x0000000000404000 :
{
+ _text = .;
*(.text)
SCHED_TEXT
LOCK_TEXT
@@ -57,13 +58,7 @@ SECTIONS
__setup_end = .;
__initcall_start = .;
.initcall.init : {
- *(.initcall1.init)
- *(.initcall2.init)
- *(.initcall3.init)
- *(.initcall4.init)
- *(.initcall5.init)
- *(.initcall6.init)
- *(.initcall7.init)
+ INITCALLS
}
__initcall_end = .;
__con_initcall_start = .;