aboutsummaryrefslogtreecommitdiff
path: root/arch/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/Kconfig1
-rw-r--r--arch/sparc64/kernel/irq.c59
-rw-r--r--arch/sparc64/kernel/kstack.h60
-rw-r--r--arch/sparc64/kernel/of_device.c29
-rw-r--r--arch/sparc64/kernel/pci.c2
-rw-r--r--arch/sparc64/kernel/pci_psycho.c14
-rw-r--r--arch/sparc64/kernel/process.c27
-rw-r--r--arch/sparc64/kernel/prom.c104
-rw-r--r--arch/sparc64/kernel/ptrace.c8
-rw-r--r--arch/sparc64/kernel/smp.c18
-rw-r--r--arch/sparc64/kernel/stacktrace.c13
-rw-r--r--arch/sparc64/kernel/traps.c10
-rw-r--r--arch/sparc64/lib/mcount.S39
-rw-r--r--arch/sparc64/mm/init.c43
-rw-r--r--arch/sparc64/mm/ultra.S2
15 files changed, 248 insertions, 181 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 923a98959fa7..36b4b7ab9cfb 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -231,6 +231,7 @@ endmenu
config NUMA
bool "NUMA support"
+ depends on SMP
config NODES_SHIFT
int
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index ba43d85e8dde..7495bc774685 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/linkage.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
@@ -682,10 +683,32 @@ void ack_bad_irq(unsigned int virt_irq)
ino, virt_irq);
}
+void *hardirq_stack[NR_CPUS];
+void *softirq_stack[NR_CPUS];
+
+static __attribute__((always_inline)) void *set_hardirq_stack(void)
+{
+ void *orig_sp, *sp = hardirq_stack[smp_processor_id()];
+
+ __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp));
+ if (orig_sp < sp ||
+ orig_sp > (sp + THREAD_SIZE)) {
+ sp += THREAD_SIZE - 192 - STACK_BIAS;
+ __asm__ __volatile__("mov %0, %%sp" : : "r" (sp));
+ }
+
+ return orig_sp;
+}
+static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
+{
+ __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
+}
+
void handler_irq(int irq, struct pt_regs *regs)
{
unsigned long pstate, bucket_pa;
struct pt_regs *old_regs;
+ void *orig_sp;
clear_softint(1 << irq);
@@ -703,6 +726,8 @@ void handler_irq(int irq, struct pt_regs *regs)
"i" (PSTATE_IE)
: "memory");
+ orig_sp = set_hardirq_stack();
+
while (bucket_pa) {
struct irq_desc *desc;
unsigned long next_pa;
@@ -719,10 +744,38 @@ void handler_irq(int irq, struct pt_regs *regs)
bucket_pa = next_pa;
}
+ restore_hardirq_stack(orig_sp);
+
irq_exit();
set_irq_regs(old_regs);
}
+void do_softirq(void)
+{
+ unsigned long flags;
+
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+
+ if (local_softirq_pending()) {
+ void *orig_sp, *sp = softirq_stack[smp_processor_id()];
+
+ sp += THREAD_SIZE - 192 - STACK_BIAS;
+
+ __asm__ __volatile__("mov %%sp, %0\n\t"
+ "mov %1, %%sp"
+ : "=&r" (orig_sp)
+ : "r" (sp));
+ __do_softirq();
+ __asm__ __volatile__("mov %0, %%sp"
+ : : "r" (orig_sp));
+ }
+
+ local_irq_restore(flags);
+}
+
#ifdef CONFIG_HOTPLUG_CPU
void fixup_irqs(void)
{
@@ -740,6 +793,8 @@ void fixup_irqs(void)
}
spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
}
+
+ tick_ops->disable_irq();
}
#endif
@@ -812,7 +867,7 @@ static void kill_prom_timer(void)
: "g1", "g2");
}
-void init_irqwork_curcpu(void)
+void notrace init_irqwork_curcpu(void)
{
int cpu = hard_smp_processor_id();
@@ -843,7 +898,7 @@ static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type
}
}
-void __cpuinit sun4v_register_mondo_queues(int this_cpu)
+void __cpuinit notrace sun4v_register_mondo_queues(int this_cpu)
{
struct trap_per_cpu *tb = &trap_block[this_cpu];
diff --git a/arch/sparc64/kernel/kstack.h b/arch/sparc64/kernel/kstack.h
new file mode 100644
index 000000000000..4248d969272f
--- /dev/null
+++ b/arch/sparc64/kernel/kstack.h
@@ -0,0 +1,60 @@
+#ifndef _KSTACK_H
+#define _KSTACK_H
+
+#include <linux/thread_info.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+/* SP must be STACK_BIAS adjusted already. */
+static inline bool kstack_valid(struct thread_info *tp, unsigned long sp)
+{
+ unsigned long base = (unsigned long) tp;
+
+ if (sp >= (base + sizeof(struct thread_info)) &&
+ sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+ return true;
+
+ if (hardirq_stack[tp->cpu]) {
+ base = (unsigned long) hardirq_stack[tp->cpu];
+ if (sp >= base &&
+ sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+ return true;
+ base = (unsigned long) softirq_stack[tp->cpu];
+ if (sp >= base &&
+ sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+ return true;
+ }
+ return false;
+}
+
+/* Does "regs" point to a valid pt_regs trap frame? */
+static inline bool kstack_is_trap_frame(struct thread_info *tp, struct pt_regs *regs)
+{
+ unsigned long base = (unsigned long) tp;
+ unsigned long addr = (unsigned long) regs;
+
+ if (addr >= base &&
+ addr <= (base + THREAD_SIZE - sizeof(*regs)))
+ goto check_magic;
+
+ if (hardirq_stack[tp->cpu]) {
+ base = (unsigned long) hardirq_stack[tp->cpu];
+ if (addr >= base &&
+ addr <= (base + THREAD_SIZE - sizeof(*regs)))
+ goto check_magic;
+ base = (unsigned long) softirq_stack[tp->cpu];
+ if (addr >= base &&
+ addr <= (base + THREAD_SIZE - sizeof(*regs)))
+ goto check_magic;
+ }
+ return false;
+
+check_magic:
+ if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC)
+ return true;
+ return false;
+
+}
+
+#endif /* _KSTACK_H */
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index f8b50cbf4bf7..100ebd527499 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -96,7 +96,7 @@ struct of_bus {
int *addrc, int *sizec);
int (*map)(u32 *addr, const u32 *range,
int na, int ns, int pna);
- unsigned int (*get_flags)(const u32 *addr);
+ unsigned long (*get_flags)(const u32 *addr, unsigned long);
};
/*
@@ -156,8 +156,10 @@ static int of_bus_default_map(u32 *addr, const u32 *range,
return 0;
}
-static unsigned int of_bus_default_get_flags(const u32 *addr)
+static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
{
+ if (flags)
+ return flags;
return IORESOURCE_MEM;
}
@@ -167,7 +169,7 @@ static unsigned int of_bus_default_get_flags(const u32 *addr)
static int of_bus_pci_match(struct device_node *np)
{
- if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+ if (!strcmp(np->name, "pci")) {
const char *model = of_get_property(np, "model", NULL);
if (model && !strcmp(model, "SUNW,simba"))
@@ -198,7 +200,7 @@ static int of_bus_simba_match(struct device_node *np)
/* Treat PCI busses lacking ranges property just like
* simba.
*/
- if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+ if (!strcmp(np->name, "pci")) {
if (!of_find_property(np, "ranges", NULL))
return 1;
}
@@ -249,17 +251,21 @@ static int of_bus_pci_map(u32 *addr, const u32 *range,
return 0;
}
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
+static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)
{
- unsigned int flags = 0;
u32 w = addr[0];
+ /* For PCI, we override whatever child busses may have used. */
+ flags = 0;
switch((w >> 24) & 0x03) {
case 0x01:
flags |= IORESOURCE_IO;
+ break;
+
case 0x02: /* 32 bits */
case 0x03: /* 64 bits */
flags |= IORESOURCE_MEM;
+ break;
}
if (w & 0x40000000)
flags |= IORESOURCE_PREFETCH;
@@ -423,7 +429,7 @@ static int __init use_1to1_mapping(struct device_node *pp)
* it lacks a ranges property, and this will include
* cases like Simba.
*/
- if (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex"))
+ if (!strcmp(pp->name, "pci"))
return 0;
return 1;
@@ -478,10 +484,10 @@ static void __init build_device_resources(struct of_device *op,
int pna, pns;
size = of_read_addr(reg + na, ns);
- flags = bus->get_flags(reg);
-
memcpy(addr, reg, na * 4);
+ flags = bus->get_flags(addr, 0);
+
if (use_1to1_mapping(pp)) {
result = of_read_addr(addr, na);
goto build_res;
@@ -506,6 +512,8 @@ static void __init build_device_resources(struct of_device *op,
dna, dns, pna))
break;
+ flags = pbus->get_flags(addr, flags);
+
dna = pna;
dns = pns;
dbus = pbus;
@@ -706,8 +714,7 @@ static unsigned int __init build_one_device_irq(struct of_device *op,
break;
}
} else {
- if (!strcmp(pp->type, "pci") ||
- !strcmp(pp->type, "pciex")) {
+ if (!strcmp(pp->name, "pci")) {
unsigned int this_orig_irq = irq;
irq = pci_irq_swizzle(dp, pp, irq);
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 55096195458f..80dad76f8b81 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -425,7 +425,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
dev->current_state = 4; /* unknown power state */
dev->error_state = pci_channel_io_normal;
- if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
+ if (!strcmp(node->name, "pci")) {
/* a PCI-PCI bridge */
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
dev->rom_base_reg = PCI_ROM_ADDRESS1;
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index ef5fe29202c2..f85b6bebb0be 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -575,7 +575,7 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm
{
unsigned long csr_reg, csr, csr_error_bits;
irqreturn_t ret = IRQ_NONE;
- u16 stat;
+ u16 stat, *addr;
if (is_pbm_a) {
csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
@@ -597,7 +597,9 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm
printk("%s: PCI SERR signal asserted.\n", pbm->name);
ret = IRQ_HANDLED;
}
- pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat);
+ addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+ 0, PCI_STATUS);
+ pci_config_read16(addr, &stat);
if (stat & (PCI_STATUS_PARITY |
PCI_STATUS_SIG_TARGET_ABORT |
PCI_STATUS_REC_TARGET_ABORT |
@@ -605,7 +607,7 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm
PCI_STATUS_SIG_SYSTEM_ERROR)) {
printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
pbm->name, stat);
- pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff);
+ pci_config_write16(addr, 0xffff);
ret = IRQ_HANDLED;
}
return ret;
@@ -744,16 +746,16 @@ static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
* the second will just error out since we do not pass in
* IRQF_SHARED.
*/
- err = request_irq(op->irqs[1], psycho_ue_intr, 0,
+ err = request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED,
"PSYCHO_UE", pbm);
- err = request_irq(op->irqs[2], psycho_ce_intr, 0,
+ err = request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED,
"PSYCHO_CE", pbm);
/* This one, however, ought not to fail. We can just warn
* about it since the system can still operate properly even
* if this fails.
*/
- err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
+ err = request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
"PSYCHO_PCIERR", pbm);
if (err)
printk(KERN_WARNING "%s: Could not register PCIERR, "
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 7f5debdc5fed..15f4178592e7 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -52,6 +52,8 @@
#include <asm/irq_regs.h>
#include <asm/smp.h>
+#include "kstack.h"
+
static void sparc64_yield(int cpu)
{
if (tlb_type != hypervisor)
@@ -235,19 +237,6 @@ void show_regs(struct pt_regs *regs)
struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
static DEFINE_SPINLOCK(global_reg_snapshot_lock);
-static bool kstack_valid(struct thread_info *tp, struct reg_window *rw)
-{
- unsigned long thread_base, fp;
-
- thread_base = (unsigned long) tp;
- fp = (unsigned long) rw;
-
- if (fp < (thread_base + sizeof(struct thread_info)) ||
- fp >= (thread_base + THREAD_SIZE))
- return false;
- return true;
-}
-
static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
int this_cpu)
{
@@ -264,11 +253,11 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
rw = (struct reg_window *)
(regs->u_regs[UREG_FP] + STACK_BIAS);
- if (kstack_valid(tp, rw)) {
+ if (kstack_valid(tp, (unsigned long) rw)) {
global_reg_snapshot[this_cpu].i7 = rw->ins[7];
rw = (struct reg_window *)
(rw->ins[6] + STACK_BIAS);
- if (kstack_valid(tp, rw))
+ if (kstack_valid(tp, (unsigned long) rw))
global_reg_snapshot[this_cpu].rpc = rw->ins[7];
}
} else {
@@ -828,7 +817,7 @@ out:
unsigned long get_wchan(struct task_struct *task)
{
unsigned long pc, fp, bias = 0;
- unsigned long thread_info_base;
+ struct thread_info *tp;
struct reg_window *rw;
unsigned long ret = 0;
int count = 0;
@@ -837,14 +826,12 @@ unsigned long get_wchan(struct task_struct *task)
task->state == TASK_RUNNING)
goto out;
- thread_info_base = (unsigned long) task_stack_page(task);
+ tp = task_thread_info(task);
bias = STACK_BIAS;
fp = task_thread_info(task)->ksp + bias;
do {
- /* Bogus frame pointer? */
- if (fp < (thread_info_base + sizeof(struct thread_info)) ||
- fp >= (thread_info_base + THREAD_SIZE))
+ if (!kstack_valid(tp, fp))
break;
rw = (struct reg_window *) fp;
pc = rw->ins[7];
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 3c048ac4e638..7151513f156e 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -156,55 +156,11 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
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 __psycho_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,
-/*0x33*/ PSYCHO_IMAP_GFX,
-/*0x34*/ PSYCHO_IMAP_EUPA,
-};
+#define PSYCHO_OBIO_IMAP_BASE 0x1000UL
+
#define PSYCHO_ONBOARD_IRQ_BASE 0x20
-#define PSYCHO_ONBOARD_IRQ_LAST 0x34
#define psycho_onboard_imap_offset(__ino) \
- __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
+ (PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
#define PSYCHO_ICLR_A_SLOT0 0x1400UL
#define PSYCHO_ICLR_SCSI 0x1800UL
@@ -228,10 +184,6 @@ static unsigned int psycho_irq_build(struct device_node *dp,
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);
}
@@ -318,23 +270,6 @@ static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
#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
@@ -364,33 +299,10 @@ static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
return SABRE_IMAP_B_SLOT0 + (slot * 8);
}
-static unsigned long __sabre_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,
-/*0x31*/ 0 /* reserved */,
-/*0x32*/ 0 /* reserved */,
-/*0x33*/ SABRE_IMAP_GFX,
-/*0x34*/ SABRE_IMAP_EUPA,
-};
-#define SABRE_ONBOARD_IRQ_BASE 0x20
-#define SABRE_ONBOARD_IRQ_LAST 0x30
+#define SABRE_OBIO_IMAP_BASE 0x1000UL
+#define SABRE_ONBOARD_IRQ_BASE 0x20
#define sabre_onboard_imap_offset(__ino) \
- __sabre_onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE]
+ (SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
#define sabre_iclr_offset(ino) \
((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \
@@ -453,10 +365,6 @@ static unsigned int sabre_irq_build(struct device_node *dp,
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);
}
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index bd578cc4856d..10306e476e38 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -443,7 +443,7 @@ static const struct user_regset sparc64_regsets[] = {
*/
[REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS,
- .n = 36 * sizeof(u64),
+ .n = 36,
.size = sizeof(u64), .align = sizeof(u64),
.get = genregs64_get, .set = genregs64_set
},
@@ -455,7 +455,7 @@ static const struct user_regset sparc64_regsets[] = {
*/
[REGSET_FP] = {
.core_note_type = NT_PRFPREG,
- .n = 35 * sizeof(u64),
+ .n = 35,
.size = sizeof(u64), .align = sizeof(u64),
.get = fpregs64_get, .set = fpregs64_set
},
@@ -801,7 +801,7 @@ static const struct user_regset sparc32_regsets[] = {
*/
[REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS,
- .n = 38 * sizeof(u32),
+ .n = 38,
.size = sizeof(u32), .align = sizeof(u32),
.get = genregs32_get, .set = genregs32_set
},
@@ -817,7 +817,7 @@ static const struct user_regset sparc32_regsets[] = {
*/
[REGSET_FP] = {
.core_note_type = NT_PRFPREG,
- .n = 99 * sizeof(u32),
+ .n = 99,
.size = sizeof(u32), .align = sizeof(u32),
.get = fpregs32_get, .set = fpregs32_set
},
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 27b81775a4de..2be166c544ca 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -80,8 +80,6 @@ void smp_bogo(struct seq_file *m)
i, cpu_data(i).clock_tick);
}
-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
-
extern void setup_sparc64_timer(void);
static volatile unsigned long callin_flag = 0;
@@ -120,9 +118,9 @@ void __cpuinit smp_callin(void)
while (!cpu_isset(cpuid, smp_commenced_mask))
rmb();
- spin_lock(&call_lock);
+ ipi_call_lock();
cpu_set(cpuid, cpu_online_map);
- spin_unlock(&call_lock);
+ ipi_call_unlock();
/* idle thread is expected to have preempt disabled */
preempt_disable();
@@ -858,9 +856,7 @@ void smp_tsb_sync(struct mm_struct *mm)
extern unsigned long xcall_flush_tlb_mm;
extern unsigned long xcall_flush_tlb_pending;
extern unsigned long xcall_flush_tlb_kernel_range;
-#ifdef CONFIG_MAGIC_SYSRQ
extern unsigned long xcall_fetch_glob_regs;
-#endif
extern unsigned long xcall_receive_signal;
extern unsigned long xcall_new_mmu_context_version;
#ifdef CONFIG_KGDB
@@ -1005,12 +1001,10 @@ void kgdb_roundup_cpus(unsigned long flags)
}
#endif
-#ifdef CONFIG_MAGIC_SYSRQ
void smp_fetch_global_regs(void)
{
smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0);
}
-#endif
/* We know that the window frames of the user have been flushed
* to the stack before we get here because all callers of us
@@ -1309,10 +1303,6 @@ int __cpu_disable(void)
c->core_id = 0;
c->proc_id = -1;
- spin_lock(&call_lock);
- cpu_clear(cpu, cpu_online_map);
- spin_unlock(&call_lock);
-
smp_wmb();
/* Make sure no interrupts point to this cpu. */
@@ -1322,6 +1312,10 @@ int __cpu_disable(void)
mdelay(1);
local_irq_disable();
+ ipi_call_lock();
+ cpu_clear(cpu, cpu_online_map);
+ ipi_call_unlock();
+
return 0;
}
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
index e9d7f0660f2e..4e21d4a57d3b 100644
--- a/arch/sparc64/kernel/stacktrace.c
+++ b/arch/sparc64/kernel/stacktrace.c
@@ -5,10 +5,12 @@
#include <asm/ptrace.h>
#include <asm/stacktrace.h>
+#include "kstack.h"
+
void save_stack_trace(struct stack_trace *trace)
{
- unsigned long ksp, fp, thread_base;
struct thread_info *tp = task_thread_info(current);
+ unsigned long ksp, fp;
stack_trace_flush();
@@ -18,23 +20,18 @@ void save_stack_trace(struct stack_trace *trace)
);
fp = ksp + STACK_BIAS;
- thread_base = (unsigned long) tp;
do {
struct sparc_stackf *sf;
struct pt_regs *regs;
unsigned long pc;
- /* Bogus frame pointer? */
- if (fp < (thread_base + sizeof(struct thread_info)) ||
- fp > (thread_base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+ if (!kstack_valid(tp, fp))
break;
sf = (struct sparc_stackf *) fp;
regs = (struct pt_regs *) (sf + 1);
- if (((unsigned long)regs <=
- (thread_base + THREAD_SIZE - sizeof(*regs))) &&
- (regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
+ if (kstack_is_trap_frame(tp, regs)) {
if (!(regs->tstate & TSTATE_PRIV))
break;
pc = regs->tpc;
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 404e8561e2d0..c824df13f589 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/smp.h>
@@ -39,6 +40,7 @@
#include <asm/prom.h>
#include "entry.h"
+#include "kstack.h"
/* When an irrecoverable trap occurs at tl > 0, the trap entry
* code logs the trap state registers at every level in the trap
@@ -2115,14 +2117,12 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
struct pt_regs *regs;
unsigned long pc;
- /* Bogus frame pointer? */
- if (fp < (thread_base + sizeof(struct thread_info)) ||
- fp >= (thread_base + THREAD_SIZE))
+ if (!kstack_valid(tp, fp))
break;
sf = (struct sparc_stackf *) fp;
regs = (struct pt_regs *) (sf + 1);
- if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) {
+ if (kstack_is_trap_frame(tp, regs)) {
if (!(regs->tstate & TSTATE_PRIV))
break;
pc = regs->tpc;
@@ -2454,7 +2454,7 @@ struct trap_per_cpu trap_block[NR_CPUS];
/* This can get invoked before sched_init() so play it super safe
* and use hard_smp_processor_id().
*/
-void init_cur_cpu_trap(struct thread_info *t)
+void notrace init_cur_cpu_trap(struct thread_info *t)
{
int cpu = hard_smp_processor_id();
struct trap_per_cpu *p = &trap_block[cpu];
diff --git a/arch/sparc64/lib/mcount.S b/arch/sparc64/lib/mcount.S
index 7735a7a60533..fad90ddb3a28 100644
--- a/arch/sparc64/lib/mcount.S
+++ b/arch/sparc64/lib/mcount.S
@@ -48,12 +48,45 @@ mcount:
sub %g3, STACK_BIAS, %g3
cmp %sp, %g3
bg,pt %xcc, 1f
- sethi %hi(panicstring), %g3
+ nop
+ lduh [%g6 + TI_CPU], %g1
+ sethi %hi(hardirq_stack), %g3
+ or %g3, %lo(hardirq_stack), %g3
+ sllx %g1, 3, %g1
+ ldx [%g3 + %g1], %g7
+ sub %g7, STACK_BIAS, %g7
+ cmp %sp, %g7
+ bleu,pt %xcc, 2f
+ sethi %hi(THREAD_SIZE), %g3
+ add %g7, %g3, %g7
+ cmp %sp, %g7
+ blu,pn %xcc, 1f
+2: sethi %hi(softirq_stack), %g3
+ or %g3, %lo(softirq_stack), %g3
+ ldx [%g3 + %g1], %g7
+ cmp %sp, %g7
+ bleu,pt %xcc, 2f
+ sethi %hi(THREAD_SIZE), %g3
+ add %g7, %g3, %g7
+ cmp %sp, %g7
+ blu,pn %xcc, 1f
+ nop
+ /* If we are already on ovstack, don't hop onto it
+ * again, we are already trying to output the stack overflow
+ * message.
+ */
sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough
or %g7, %lo(ovstack), %g7
- add %g7, OVSTACKSIZE, %g7
+ add %g7, OVSTACKSIZE, %g3
+ sub %g3, STACK_BIAS + 192, %g3
sub %g7, STACK_BIAS, %g7
- mov %g7, %sp
+ cmp %sp, %g7
+ blu,pn %xcc, 2f
+ cmp %sp, %g3
+ bleu,pn %xcc, 1f
+ nop
+2: mov %g3, %sp
+ sethi %hi(panicstring), %g3
call prom_printf
or %g3, %lo(panicstring), %o0
call prom_halt
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 4e821b3ecb03..a41df7bef035 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -49,6 +49,7 @@
#include <asm/sstate.h>
#include <asm/mdesc.h>
#include <asm/cpudata.h>
+#include <asm/irq.h>
#define MAX_PHYS_ADDRESS (1UL << 42UL)
#define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL)
@@ -795,6 +796,9 @@ static unsigned long nid_range(unsigned long start, unsigned long end,
start += PAGE_SIZE;
}
+ if (start > end)
+ start = end;
+
return start;
}
#else
@@ -1722,8 +1726,7 @@ void __init paging_init(void)
find_ramdisk(phys_base);
- if (cmdline_memory_size)
- lmb_enforce_memory_limit(phys_base + cmdline_memory_size);
+ lmb_enforce_memory_limit(cmdline_memory_size);
lmb_analyze();
lmb_dump_all();
@@ -1771,6 +1774,16 @@ void __init paging_init(void)
if (tlb_type == hypervisor)
sun4v_mdesc_init();
+ /* Once the OF device tree and MDESC have been setup, we know
+ * the list of possible cpus. Therefore we can allocate the
+ * IRQ stacks.
+ */
+ for_each_possible_cpu(i) {
+ /* XXX Use node local allocations... XXX */
+ softirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+ hardirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+ }
+
/* Setup bootmem... */
last_valid_pfn = end_pfn = bootmem_init(phys_base);
@@ -1830,7 +1843,7 @@ static int pavail_rescan_ents __initdata;
* memory list again, and make sure it provides at least as much
* memory as 'pavail' does.
*/
-static void setup_valid_addr_bitmap_from_pavail(void)
+static void __init setup_valid_addr_bitmap_from_pavail(void)
{
int i;
@@ -1950,6 +1963,15 @@ void __init mem_init(void)
void free_initmem(void)
{
unsigned long addr, initend;
+ int do_free = 1;
+
+ /* If the physical memory maps were trimmed by kernel command
+ * line options, don't even try freeing this initmem stuff up.
+ * The kernel image could have been in the trimmed out region
+ * and if so the freeing below will free invalid page structs.
+ */
+ if (cmdline_memory_size)
+ do_free = 0;
/*
* The init section is aligned to 8k in vmlinux.lds. Page align for >8k pagesizes.
@@ -1964,13 +1986,16 @@ void free_initmem(void)
((unsigned long) __va(kern_base)) -
((unsigned long) KERNBASE));
memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- p = virt_to_page(page);
- ClearPageReserved(p);
- init_page_count(p);
- __free_page(p);
- num_physpages++;
- totalram_pages++;
+ if (do_free) {
+ p = virt_to_page(page);
+
+ ClearPageReserved(p);
+ init_page_count(p);
+ __free_page(p);
+ num_physpages++;
+ totalram_pages++;
+ }
}
}
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index ff1dc44d363e..86773e89dc1b 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -480,7 +480,6 @@ xcall_sync_tick:
b rtrap_xcall
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
-#ifdef CONFIG_MAGIC_SYSRQ
.globl xcall_fetch_glob_regs
xcall_fetch_glob_regs:
sethi %hi(global_reg_snapshot), %g1
@@ -511,7 +510,6 @@ xcall_fetch_glob_regs:
membar #StoreStore
stx %g3, [%g1 + GR_SNAP_THREAD]
retry
-#endif /* CONFIG_MAGIC_SYSRQ */
#ifdef DCACHE_ALIASING_POSSIBLE
.align 32