Skip to content

Commit

Permalink
[POWERPC] Use the genirq framework
Browse files Browse the repository at this point in the history
This adapts the generic powerpc interrupt handling code, and all of
the platforms except for the embedded 6xx machines, to use the new
genirq framework.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Jul 3, 2006
1 parent 5a43a06 commit b9e5b4e
Show file tree
Hide file tree
Showing 17 changed files with 673 additions and 616 deletions.
30 changes: 12 additions & 18 deletions arch/powerpc/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,27 @@
#endif

int __irq_offset_value;
#ifdef CONFIG_PPC32
EXPORT_SYMBOL(__irq_offset_value);
#endif

static int ppc_spurious_interrupts;

#ifdef CONFIG_PPC32
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
EXPORT_SYMBOL(__irq_offset_value);
atomic_t ppc_n_lost_interrupts;

#ifndef CONFIG_PPC_MERGE
#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
atomic_t ppc_n_lost_interrupts;
#endif

#ifdef CONFIG_TAU_INT
extern int tau_initialized;
extern int tau_interrupts(int);
#endif
#endif /* CONFIG_PPC32 */

#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE)
extern atomic_t ipi_recv;
extern atomic_t ipi_sent;
#endif
#endif /* CONFIG_PPC32 */

#ifdef CONFIG_PPC64
EXPORT_SYMBOL(irq_desc);
Expand Down Expand Up @@ -219,15 +218,19 @@ void do_IRQ(struct pt_regs *regs)
curtp = current_thread_info();
irqtp = hardirq_ctx[smp_processor_id()];
if (curtp != irqtp) {
struct irq_desc *desc = irq_desc + irq;
void *handler = desc->handle_irq;
if (handler == NULL)
handler = &__do_IRQ;
irqtp->task = curtp->task;
irqtp->flags = 0;
call___do_IRQ(irq, regs, irqtp);
call_handle_irq(irq, desc, regs, irqtp, handler);
irqtp->task = NULL;
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);
} else
#endif
__do_IRQ(irq, regs);
generic_handle_irq(irq, regs);
} else if (irq != -2)
/* That's not SMP safe ... but who cares ? */
ppc_spurious_interrupts++;
Expand All @@ -245,15 +248,6 @@ void do_IRQ(struct pt_regs *regs)

void __init init_IRQ(void)
{
#ifdef CONFIG_PPC64
static int once = 0;

if (once)
return;

once++;

#endif
ppc_md.init_IRQ();
#ifdef CONFIG_PPC64
irq_ctx_init();
Expand Down
10 changes: 6 additions & 4 deletions arch/powerpc/kernel/misc_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ _GLOBAL(call_do_softirq)
mtlr r0
blr

_GLOBAL(call___do_IRQ)
_GLOBAL(call_handle_irq)
ld r8,0(r7)
mflr r0
std r0,16(r1)
stdu r1,THREAD_SIZE-112(r5)
mr r1,r5
bl .__do_IRQ
mtctr r8
stdu r1,THREAD_SIZE-112(r6)
mr r1,r6
bctrl
ld r1,0(r1)
ld r0,16(r1)
mtlr r0
Expand Down
111 changes: 56 additions & 55 deletions arch/powerpc/platforms/cell/interrupt.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,64 +37,51 @@
struct iic {
struct cbe_iic_thread_regs __iomem *regs;
u8 target_id;
u8 eoi_stack[16];
int eoi_ptr;
};

static DEFINE_PER_CPU(struct iic, iic);

void iic_local_enable(void)
static void iic_mask(unsigned int irq)
{
struct iic *iic = &__get_cpu_var(iic);
u64 tmp;

/*
* There seems to be a bug that is present in DD2.x CPUs
* and still only partially fixed in DD3.1.
* This bug causes a value written to the priority register
* not to make it there, resulting in a system hang unless we
* write it again.
* Masking with 0xf0 is done because the Cell BE does not
* implement the lower four bits of the interrupt priority,
* they always read back as zeroes, although future CPUs
* might implement different bits.
*/
do {
out_be64(&iic->regs->prio, 0xff);
tmp = in_be64(&iic->regs->prio);
} while ((tmp & 0xf0) != 0xf0);
}

void iic_local_disable(void)
{
out_be64(&__get_cpu_var(iic).regs->prio, 0x0);
}

static unsigned int iic_startup(unsigned int irq)
{
return 0;
}

static void iic_enable(unsigned int irq)
{
iic_local_enable();
}

static void iic_disable(unsigned int irq)
static void iic_unmask(unsigned int irq)
{
}

static void iic_end(unsigned int irq)
static void iic_eoi(unsigned int irq)
{
iic_local_enable();
struct iic *iic = &__get_cpu_var(iic);
out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]);
BUG_ON(iic->eoi_ptr < 0);
}

static struct hw_interrupt_type iic_pic = {
static struct irq_chip iic_chip = {
.typename = " CELL-IIC ",
.startup = iic_startup,
.enable = iic_enable,
.disable = iic_disable,
.end = iic_end,
.mask = iic_mask,
.unmask = iic_unmask,
.eoi = iic_eoi,
};

/* XXX All of this has to be reworked completely. We need to assign a real
* interrupt numbers to the external interrupts and remove all the hard coded
* interrupt maps (rely on the device-tree whenever possible).
*
* Basically, my scheme is to define the "pendings" bits to be the HW interrupt
* number (ignoring the data and flags here). That means we can sort-of split
* external sources based on priority, and we can use request_irq() on pretty
* much anything.
*
* For spider or axon, they have their own interrupt space. spider will just have
* local "hardward" interrupts 0...xx * node stride. The node stride is not
* necessary (separate interrupt chips will have separate HW number space), but
* will allow to be compatible with existing device-trees.
*
* All of thise little world will get a standard remapping scheme to map those HW
* numbers into the linux flat irq number space.
*/
static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
{
int irq;
Expand All @@ -118,9 +105,10 @@ static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
*/
if (pending.class != 2)
break;
irq = IIC_EXT_OFFSET
+ spider_get_irq(node)
+ node * IIC_NODE_STRIDE;
/* TODO: We might want to silently ignore cascade interrupts
* when no cascade handler exist yet
*/
irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
break;
case 0x01 ... 0x04:
case 0x07 ... 0x0a:
Expand Down Expand Up @@ -152,6 +140,8 @@ int iic_get_irq(struct pt_regs *regs)
iic = &__get_cpu_var(iic);
*(unsigned long *) &pending =
in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
BUG_ON(iic->eoi_ptr > 15);

irq = -1;
if (pending.flags & CBE_IIC_IRQ_VALID) {
Expand All @@ -172,7 +162,7 @@ int iic_get_irq(struct pt_regs *regs)

/* hardcoded part to be compatible with older firmware */

static int setup_iic_hardcoded(void)
static int __init setup_iic_hardcoded(void)
{
struct device_node *np;
int nodeid, cpu;
Expand Down Expand Up @@ -207,12 +197,13 @@ static int setup_iic_hardcoded(void)
printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
iic->eoi_stack[0] = 0xff;
}

return 0;
}

static int setup_iic(void)
static int __init setup_iic(void)
{
struct device_node *dn;
unsigned long *regs;
Expand Down Expand Up @@ -248,11 +239,14 @@ static int setup_iic(void)
iic = &per_cpu(iic, np[0]);
iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
iic->eoi_stack[0] = 0xff;
printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);

iic = &per_cpu(iic, np[1]);
iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
iic->eoi_stack[0] = 0xff;

printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);

found++;
Expand Down Expand Up @@ -304,10 +298,10 @@ static void iic_request_ipi(int ipi, const char *name)
int irq;

irq = iic_ipi_to_irq(ipi);

/* IPIs are marked IRQF_DISABLED as they must run with irqs
* disabled */
get_irq_desc(irq)->chip = &iic_pic;
get_irq_desc(irq)->status |= IRQ_PER_CPU;
set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
}

Expand All @@ -321,20 +315,26 @@ void iic_request_IPIs(void)
}
#endif /* CONFIG_SMP */

static void iic_setup_spe_handlers(void)
static void __init iic_setup_builtin_handlers(void)
{
int be, isrc;

/* Assume two threads per BE are present */
/* XXX FIXME: Assume two threads per BE are present */
for (be=0; be < num_present_cpus() / 2; be++) {
int irq;

/* setup SPE chip and handlers */
for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
get_irq_desc(irq)->chip = &iic_pic;
irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
}
/* setup cascade chip */
irq = IIC_EXT_CASCADE + be * IIC_NODE_STRIDE;
set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
}
}

void iic_init_IRQ(void)
void __init iic_init_IRQ(void)
{
int cpu, irq_offset;
struct iic *iic;
Expand All @@ -348,5 +348,6 @@ void iic_init_IRQ(void)
if (iic->regs)
out_be64(&iic->regs->prio, 0xff);
}
iic_setup_spe_handlers();
iic_setup_builtin_handlers();

}
4 changes: 1 addition & 3 deletions arch/powerpc/platforms/cell/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

enum {
IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */
IIC_EXT_CASCADE = 0x20, /* There is no interrupt 32 on spider */
IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */
IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */
IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */
Expand All @@ -51,13 +52,10 @@ extern int iic_get_irq(struct pt_regs *regs);
extern void iic_cause_IPI(int cpu, int mesg);
extern void iic_request_IPIs(void);
extern void iic_setup_cpu(void);
extern void iic_local_enable(void);
extern void iic_local_disable(void);

extern u8 iic_get_target_id(int cpu);

extern void spider_init_IRQ(void);
extern int spider_get_irq(int node);

#endif
#endif /* ASM_CELL_PIC_H */
12 changes: 9 additions & 3 deletions arch/powerpc/platforms/cell/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,14 @@ static void cell_progress(char *s, unsigned short hex)
printk("*** %04x : %s\n", hex, s ? s : "");
}

static void __init cell_init_irq(void)
{
iic_init_IRQ();
spider_init_IRQ();
}

static void __init cell_setup_arch(void)
{
ppc_md.init_IRQ = iic_init_IRQ;
ppc_md.get_irq = iic_get_irq;
#ifdef CONFIG_SPU_BASE
spu_priv1_ops = &spu_priv1_mmio_ops;
#endif
Expand All @@ -109,7 +113,6 @@ static void __init cell_setup_arch(void)
/* Find and initialize PCI host bridges */
init_pci_config_tokens();
find_and_init_phbs();
spider_init_IRQ();
cbe_pervasive_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
Expand Down Expand Up @@ -174,6 +177,9 @@ define_machine(cell) {
.calibrate_decr = generic_calibrate_decr,
.check_legacy_ioport = cell_check_legacy_ioport,
.progress = cell_progress,
.init_IRQ = cell_init_irq,
.get_irq = iic_get_irq,

#ifdef CONFIG_KEXEC
.machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare,
Expand Down
Loading

0 comments on commit b9e5b4e

Please sign in to comment.