Skip to content

Commit

Permalink
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/benh/powerpc

Pull powerpc fixes from Ben Herrenschmidt:
 "Here are a few things for -rc2, this time it's all written by me so it
  can only be perfect .... right ? :)

  So we have the fix to call irq_enter/exit on the irq stack we've been
  discussing, plus a cleanup on top to remove an unused (and broken)
  stack limit tracking feature (well, make it 32-bit only in fact where
  it is used and works properly).

  Then we have two things that I wrote over the last couple of days and
  made the executive decision to include just because I can (and I'm
  sure you won't object .... right ?).

  They fix a couple of annoying and long standing "issues":

   - We had separate zImages for when booting via Open Firmware vs.
     booting via a flat device-tree, while it's trivial to make one that
     deals with both

   - We wasted a ton of cycles spinning secondary CPUs uselessly at boot
     instead of starting them when needed on pseries, thus contributing
     significantly to global warming"

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  powerpc/pseries: Do not start secondaries in Open Firmware
  powerpc/zImage: make the "OF" wrapper support ePAPR boot
  powerpc: Remove ksp_limit on ppc64
  powerpc/irq: Run softirqs off the top of the irq stack
  • Loading branch information
Linus Torvalds committed Sep 25, 2013
2 parents 654fdd0 + dbe78b4 commit 06367d5
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 94 deletions.
4 changes: 2 additions & 2 deletions arch/powerpc/boot/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c
src-wlib-$(CONFIG_PPC_82xx) += pq2.c fsl-soc.c planetcore.c
src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c

src-plat-y := of.c
src-plat-y := of.c epapr.c
src-plat-$(CONFIG_40x) += fixed-head.S ep405.c cuboot-hotfoot.c \
treeboot-walnut.c cuboot-acadia.c \
cuboot-kilauea.c simpleboot.c \
Expand All @@ -97,7 +97,7 @@ src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \
prpmc2800.c
src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c
src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c
src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c
src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c

src-wlib := $(sort $(src-wlib-y))
src-plat := $(sort $(src-plat-y))
Expand Down
9 changes: 9 additions & 0 deletions arch/powerpc/boot/epapr-wrapper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extern void epapr_platform_init(unsigned long r3, unsigned long r4,
unsigned long r5, unsigned long r6,
unsigned long r7);

void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
epapr_platform_init(r3, r4, r5, r6, r7);
}
4 changes: 2 additions & 2 deletions arch/powerpc/boot/epapr.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ static void platform_fixups(void)
fdt_addr, fdt_totalsize((void *)fdt_addr), ima_size);
}

void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
void epapr_platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
epapr_magic = r6;
ima_size = r7;
Expand Down
16 changes: 15 additions & 1 deletion arch/powerpc/boot/of.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

static unsigned long claim_base;

void epapr_platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7);

static void *of_try_claim(unsigned long size)
{
unsigned long addr = 0;
Expand Down Expand Up @@ -61,7 +64,7 @@ static void of_image_hdr(const void *hdr)
}
}

void platform_init(unsigned long a1, unsigned long a2, void *promptr)
static void of_platform_init(unsigned long a1, unsigned long a2, void *promptr)
{
platform_ops.image_hdr = of_image_hdr;
platform_ops.malloc = of_try_claim;
Expand All @@ -81,3 +84,14 @@ void platform_init(unsigned long a1, unsigned long a2, void *promptr)
loader_info.initrd_size = a2;
}
}

void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
/* Detect OF vs. ePAPR boot */
if (r5)
of_platform_init(r3, r4, (void *)r5);
else
epapr_platform_init(r3, r4, r5, r6, r7);
}

9 changes: 5 additions & 4 deletions arch/powerpc/boot/wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,18 @@ make_space=y

case "$platform" in
pseries)
platformo=$object/of.o
platformo="$object/of.o $object/epapr.o"
link_address='0x4000000'
;;
maple)
platformo=$object/of.o
platformo="$object/of.o $object/epapr.o"
link_address='0x400000'
;;
pmac|chrp)
platformo=$object/of.o
platformo="$object/of.o $object/epapr.o"
;;
coff)
platformo="$object/crt0.o $object/of.o"
platformo="$object/crt0.o $object/of.o $object/epapr.o"
lds=$object/zImage.coff.lds
link_address='0x500000'
pie=
Expand Down Expand Up @@ -253,6 +253,7 @@ treeboot-iss4xx-mpic)
platformo="$object/treeboot-iss4xx.o"
;;
epapr)
platformo="$object/epapr.o $object/epapr-wrapper.o"
link_address='0x20000000'
pie=-pie
;;
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/include/asm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ extern struct thread_info *softirq_ctx[NR_CPUS];

extern void irq_ctx_init(void);
extern void call_do_softirq(struct thread_info *tp);
extern int call_handle_irq(int irq, void *p1,
struct thread_info *tp, void *func);
extern void call_do_irq(struct pt_regs *regs, struct thread_info *tp);
extern void do_IRQ(struct pt_regs *regs);
extern void __do_irq(struct pt_regs *regs);

int irq_choose_cpu(const struct cpumask *mask);

Expand Down
4 changes: 1 addition & 3 deletions arch/powerpc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,6 @@ typedef struct {

struct thread_struct {
unsigned long ksp; /* Kernel stack pointer */
unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */

#ifdef CONFIG_PPC64
unsigned long ksp_vsid;
#endif
Expand All @@ -162,6 +160,7 @@ struct thread_struct {
#endif
#ifdef CONFIG_PPC32
void *pgdir; /* root of page-table tree */
unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */
#endif
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
/*
Expand Down Expand Up @@ -321,7 +320,6 @@ struct thread_struct {
#else
#define INIT_THREAD { \
.ksp = INIT_SP, \
.ksp_limit = INIT_SP_LIMIT, \
.regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
.fs = KERNEL_DS, \
.fpr = {{0}}, \
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ int main(void)
DEFINE(TASKTHREADPPR, offsetof(struct task_struct, thread.ppr));
#else
DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(THREAD_INFO_GAP, _ALIGN_UP(sizeof(struct thread_info), 16));
DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
#endif /* CONFIG_PPC64 */

DEFINE(KSP, offsetof(struct thread_struct, ksp));
DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
#ifdef CONFIG_BOOKE
DEFINE(THREAD_NORMSAVES, offsetof(struct thread_struct, normsave[0]));
Expand Down
100 changes: 44 additions & 56 deletions arch/powerpc/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,50 +441,6 @@ void migrate_irqs(void)
}
#endif

static inline void handle_one_irq(unsigned int irq)
{
struct thread_info *curtp, *irqtp;
unsigned long saved_sp_limit;
struct irq_desc *desc;

desc = irq_to_desc(irq);
if (!desc)
return;

/* Switch to the irq stack to handle this */
curtp = current_thread_info();
irqtp = hardirq_ctx[smp_processor_id()];

if (curtp == irqtp) {
/* We're already on the irq stack, just handle it */
desc->handle_irq(irq, desc);
return;
}

saved_sp_limit = current->thread.ksp_limit;

irqtp->task = curtp->task;
irqtp->flags = 0;

/* Copy the softirq bits in preempt_count so that the
* softirq checks work in the hardirq context. */
irqtp->preempt_count = (irqtp->preempt_count & ~SOFTIRQ_MASK) |
(curtp->preempt_count & SOFTIRQ_MASK);

current->thread.ksp_limit = (unsigned long)irqtp +
_ALIGN_UP(sizeof(struct thread_info), 16);

call_handle_irq(irq, desc, irqtp, desc->handle_irq);
current->thread.ksp_limit = saved_sp_limit;
irqtp->task = NULL;

/* Set any flag that may have been set on the
* alternate stack
*/
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);
}

static inline void check_stack_overflow(void)
{
#ifdef CONFIG_DEBUG_STACKOVERFLOW
Expand All @@ -501,9 +457,9 @@ static inline void check_stack_overflow(void)
#endif
}

void do_IRQ(struct pt_regs *regs)
void __do_irq(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
struct irq_desc *desc;
unsigned int irq;

irq_enter();
Expand All @@ -519,18 +475,56 @@ void do_IRQ(struct pt_regs *regs)
*/
irq = ppc_md.get_irq();

/* We can hard enable interrupts now */
/* We can hard enable interrupts now to allow perf interrupts */
may_hard_irq_enable();

/* And finally process it */
if (irq != NO_IRQ)
handle_one_irq(irq);
else
if (unlikely(irq == NO_IRQ))
__get_cpu_var(irq_stat).spurious_irqs++;
else {
desc = irq_to_desc(irq);
if (likely(desc))
desc->handle_irq(irq, desc);
}

trace_irq_exit(regs);

irq_exit();
}

void do_IRQ(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
struct thread_info *curtp, *irqtp;

/* Switch to the irq stack to handle this */
curtp = current_thread_info();
irqtp = hardirq_ctx[raw_smp_processor_id()];

/* Already there ? */
if (unlikely(curtp == irqtp)) {
__do_irq(regs);
set_irq_regs(old_regs);
return;
}

/* Prepare the thread_info in the irq stack */
irqtp->task = curtp->task;
irqtp->flags = 0;

/* Copy the preempt_count so that the [soft]irq checks work. */
irqtp->preempt_count = curtp->preempt_count;

/* Switch stack and call */
call_do_irq(regs, irqtp);

/* Restore stack limit */
irqtp->task = NULL;

/* Copy back updates to the thread_info */
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);

set_irq_regs(old_regs);
}

Expand Down Expand Up @@ -592,28 +586,22 @@ void irq_ctx_init(void)
memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
tp = softirq_ctx[i];
tp->cpu = i;
tp->preempt_count = 0;

memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
tp = hardirq_ctx[i];
tp->cpu = i;
tp->preempt_count = HARDIRQ_OFFSET;
}
}

static inline void do_softirq_onstack(void)
{
struct thread_info *curtp, *irqtp;
unsigned long saved_sp_limit = current->thread.ksp_limit;

curtp = current_thread_info();
irqtp = softirq_ctx[smp_processor_id()];
irqtp->task = curtp->task;
irqtp->flags = 0;
current->thread.ksp_limit = (unsigned long)irqtp +
_ALIGN_UP(sizeof(struct thread_info), 16);
call_do_softirq(irqtp);
current->thread.ksp_limit = saved_sp_limit;
irqtp->task = NULL;

/* Set any flag that may have been set on the
Expand Down
25 changes: 20 additions & 5 deletions arch/powerpc/kernel/misc_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,41 @@

.text

/*
* We store the saved ksp_limit in the unused part
* of the STACK_FRAME_OVERHEAD
*/
_GLOBAL(call_do_softirq)
mflr r0
stw r0,4(r1)
lwz r10,THREAD+KSP_LIMIT(r2)
addi r11,r3,THREAD_INFO_GAP
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
mr r1,r3
stw r10,8(r1)
stw r11,THREAD+KSP_LIMIT(r2)
bl __do_softirq
lwz r10,8(r1)
lwz r1,0(r1)
lwz r0,4(r1)
stw r10,THREAD+KSP_LIMIT(r2)
mtlr r0
blr

_GLOBAL(call_handle_irq)
_GLOBAL(call_do_irq)
mflr r0
stw r0,4(r1)
mtctr r6
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
mr r1,r5
bctrl
lwz r10,THREAD+KSP_LIMIT(r2)
addi r11,r3,THREAD_INFO_GAP
stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
mr r1,r4
stw r10,8(r1)
stw r11,THREAD+KSP_LIMIT(r2)
bl __do_irq
lwz r10,8(r1)
lwz r1,0(r1)
lwz r0,4(r1)
stw r10,THREAD+KSP_LIMIT(r2)
mtlr r0
blr

Expand Down
10 changes: 4 additions & 6 deletions arch/powerpc/kernel/misc_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,12 @@ _GLOBAL(call_do_softirq)
mtlr r0
blr

_GLOBAL(call_handle_irq)
ld r8,0(r6)
_GLOBAL(call_do_irq)
mflr r0
std r0,16(r1)
mtctr r8
stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
mr r1,r5
bctrl
stdu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
mr r1,r4
bl .__do_irq
ld r1,0(r1)
ld r0,16(r1)
mtlr r0
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -1000,9 +1000,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
kregs = (struct pt_regs *) sp;
sp -= STACK_FRAME_OVERHEAD;
p->thread.ksp = sp;
#ifdef CONFIG_PPC32
p->thread.ksp_limit = (unsigned long)task_stack_page(p) +
_ALIGN_UP(sizeof(struct thread_info), 16);

#endif
#ifdef CONFIG_HAVE_HW_BREAKPOINT
p->thread.ptrace_bps[0] = NULL;
#endif
Expand Down
Loading

0 comments on commit 06367d5

Please sign in to comment.