Skip to content

Commit

Permalink
powerpc/mpic: Add in-core support for cascaded MPICs
Browse files Browse the repository at this point in the history
The Cell and PowerMac platforms use virtually identical cascaded-IRQ
setup code, so just merge it into the core.  Ideally this code would
trigger automatically when an MPIC device-node specifies an "interrupts"
property, perhaps even enabling MPIC_SECONDARY along the way.

Unfortunately, Benjamin Herrenschmidt has had bad experiences in the
past with the quality of Apple PowerMac device-trees, so to be safe we
will only try to parse out an IRQ if the MPIC_SECONDARY flag is set by
the caller.

Signed-off-by: Kyle Moffett <Kyle.D.Moffett@boeing.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Kyle Moffett authored and Benjamin Herrenschmidt committed Dec 7, 2011
1 parent c51242e commit 09dc34a
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 56 deletions.
23 changes: 0 additions & 23 deletions arch/powerpc/platforms/cell/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,24 +184,10 @@ static int __init cell_publish_devices(void)
}
machine_subsys_initcall(cell, cell_publish_devices);

static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mpic *mpic = irq_desc_get_handler_data(desc);
unsigned int virq;

virq = mpic_get_one_irq(mpic);
if (virq != NO_IRQ)
generic_handle_irq(virq);

chip->irq_eoi(&desc->irq_data);
}

static void __init mpic_init_IRQ(void)
{
struct device_node *dn;
struct mpic *mpic;
unsigned int virq;

for (dn = NULL;
(dn = of_find_node_by_name(dn, "interrupt-controller"));) {
Expand All @@ -215,15 +201,6 @@ static void __init mpic_init_IRQ(void)
if (mpic == NULL)
continue;
mpic_init(mpic);

virq = irq_of_parse_and_map(dn, 0);
if (virq == NO_IRQ)
continue;

printk(KERN_INFO "%s : hooking up to IRQ %d\n",
dn->full_name, virq);
irq_set_handler_data(virq, mpic);
irq_set_chained_handler(virq, cell_mpic_cascade);
}
}

Expand Down
36 changes: 5 additions & 31 deletions arch/powerpc/platforms/powermac/pic.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,18 +464,6 @@ int of_irq_map_oldworld(struct device_node *device, int index,
}
#endif /* CONFIG_PPC32 */

static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mpic *mpic = irq_desc_get_handler_data(desc);
unsigned int cascade_irq = mpic_get_one_irq(mpic);

if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);

chip->irq_eoi(&desc->irq_data);
}

static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
{
#if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
Expand Down Expand Up @@ -526,7 +514,6 @@ static int __init pmac_pic_probe_mpic(void)
{
struct mpic *mpic1, *mpic2;
struct device_node *np, *master = NULL, *slave = NULL;
unsigned int cascade;

/* We can have up to 2 MPICs cascaded */
for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
Expand Down Expand Up @@ -562,27 +549,14 @@ static int __init pmac_pic_probe_mpic(void)

of_node_put(master);

/* No slave, let's go out */
if (slave == NULL)
return 0;

/* Get/Map slave interrupt */
cascade = irq_of_parse_and_map(slave, 0);
if (cascade == NO_IRQ) {
printk(KERN_ERR "Failed to map cascade IRQ\n");
return 0;
}

mpic2 = pmac_setup_one_mpic(slave, 0);
if (mpic2 == NULL) {
printk(KERN_ERR "Failed to setup slave MPIC\n");
/* Set up a cascaded controller, if present */
if (slave) {
mpic2 = pmac_setup_one_mpic(slave, 0);
if (mpic2 == NULL)
printk(KERN_ERR "Failed to setup slave MPIC\n");
of_node_put(slave);
return 0;
}
irq_set_handler_data(cascade, mpic2);
irq_set_chained_handler(cascade, pmac_u3_cascade);

of_node_put(slave);
return 0;
}

Expand Down
30 changes: 28 additions & 2 deletions arch/powerpc/sysdev/mpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,22 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
return 0;
}

/* IRQ handler for a secondary MPIC cascaded from another IRQ controller */
static void mpic_cascade(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mpic *mpic = irq_desc_get_handler_data(desc);
unsigned int virq;

BUG_ON(!(mpic->flags & MPIC_SECONDARY));

virq = mpic_get_one_irq(mpic);
if (virq != NO_IRQ)
generic_handle_irq(virq);

chip->irq_eoi(&desc->irq_data);
}

static struct irq_host_ops mpic_host_ops = {
.match = mpic_host_match,
.map = mpic_host_map,
Expand Down Expand Up @@ -1402,8 +1418,7 @@ void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count)

void __init mpic_init(struct mpic *mpic)
{
int i;
int cpu;
int i, cpu;

BUG_ON(mpic->num_sources == 0);

Expand Down Expand Up @@ -1488,6 +1503,17 @@ void __init mpic_init(struct mpic *mpic)
GFP_KERNEL);
BUG_ON(mpic->save_data == NULL);
#endif

/* Check if this MPIC is chained from a parent interrupt controller */
if (mpic->flags & MPIC_SECONDARY) {
int virq = irq_of_parse_and_map(mpic->node, 0);
if (virq != NO_IRQ) {
printk(KERN_INFO "%s: hooking up to IRQ %d\n",
mpic->node->full_name, virq);
irq_set_handler_data(virq, mpic);
irq_set_chained_handler(virq, &mpic_cascade);
}
}
}

void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
Expand Down

0 comments on commit 09dc34a

Please sign in to comment.