From e075cd7001634c9984950488d9201fcf896dca27 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Mon, 21 Nov 2011 06:43:26 +0000 Subject: powerpc/mpic: Remove extra semicolon. The patch below removes an extra semicolon. Signed-off-by: Justin P. Mattock CC: linuxppc-dev@lists.ozlabs.org CC: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 8c7e8528e7c4..b3fa3d7d4ab6 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -901,7 +901,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) if (vold != vnew) mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew); - return IRQ_SET_MASK_OK_NOCOPY;; + return IRQ_SET_MASK_OK_NOCOPY; } void mpic_set_vector(unsigned int virq, unsigned int vector) -- cgit v1.2.3 From 8bf41568969e003c3d5410124e27bbdce7852e1b Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:27:59 +0000 Subject: powerpc: Consolidate mpic_alloc() OF address translation Instead of using the open-coded "reg" property lookup and address translation in mpic_alloc(), directly call of_address_to_resource(). This includes various workarounds for special cases which the naive of_address_translate() does not. Afterwards it is possible to remove the copiously copy-pasted calls to of_address_translate() from the 85xx/86xx/powermac platforms. Signed-off-by: Kyle Moffett Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Grant Likely Cc: Kumar Gala Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 61 ++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index b3fa3d7d4ab6..8f24c6e8f535 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1142,7 +1142,24 @@ struct mpic * __init mpic_alloc(struct device_node *node, const char *vers; int i; int intvec_top; - u64 paddr = phys_addr; + + /* + * If no phyiscal address was specified then all of the phyiscal + * addressing parameters must come from the device-tree. + */ + if (!phys_addr) { + BUG_ON(!node); + + /* Check if it is DCR-based */ + if (of_get_property(node, "dcr-reg", NULL)) { + flags |= MPIC_USES_DCR; + } else { + struct resource r; + if (of_address_to_resource(node, 0, &r)) + return NULL; + phys_addr = r.start; + } + } mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); if (mpic == NULL) @@ -1224,35 +1241,25 @@ struct mpic * __init mpic_alloc(struct device_node *node, #endif /* default register type */ - mpic->reg_type = (flags & MPIC_BIG_ENDIAN) ? - mpic_access_mmio_be : mpic_access_mmio_le; - - /* If no physical address is passed in, a device-node is mandatory */ - BUG_ON(paddr == 0 && node == NULL); + if (flags & MPIC_BIG_ENDIAN) + mpic->reg_type = mpic_access_mmio_be; + else + mpic->reg_type = mpic_access_mmio_le; - /* If no physical address passed in, check if it's dcr based */ - if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL) { + /* + * An MPIC with a "dcr-reg" property must be accessed that way, but + * only if the kernel includes DCR support. + */ #ifdef CONFIG_PPC_DCR - mpic->flags |= MPIC_USES_DCR; + if (flags & MPIC_USES_DCR) mpic->reg_type = mpic_access_dcr; #else - BUG(); -#endif /* CONFIG_PPC_DCR */ - } - - /* If the MPIC is not DCR based, and no physical address was passed - * in, try to obtain one - */ - if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) { - const u32 *reg = of_get_property(node, "reg", NULL); - BUG_ON(reg == NULL); - paddr = of_translate_address(node, reg); - BUG_ON(paddr == OF_BAD_ADDR); - } + BUG_ON(flags & MPIC_USES_DCR); +#endif /* Map the global registers */ - mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); - mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); + mpic_map(mpic, node, phys_addr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); + mpic_map(mpic, node, phys_addr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); /* Reset */ @@ -1307,7 +1314,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, for_each_possible_cpu(i) { unsigned int cpu = get_hard_smp_processor_id(i); - mpic_map(mpic, node, paddr, &mpic->cpuregs[cpu], + mpic_map(mpic, node, phys_addr, &mpic->cpuregs[cpu], MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), 0x1000); } @@ -1315,7 +1322,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Initialize main ISU if none provided */ if (mpic->isu_size == 0) { mpic->isu_size = mpic->num_sources; - mpic_map(mpic, node, paddr, &mpic->isus[0], + mpic_map(mpic, node, phys_addr, &mpic->isus[0], MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); } mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); @@ -1347,7 +1354,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, } printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," " max %d CPUs\n", - name, vers, (unsigned long long)paddr, num_possible_cpus()); + name, vers, (unsigned long long)phys_addr, num_possible_cpus()); printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, mpic->isu_shift, mpic->isu_mask); -- cgit v1.2.3 From 5bdb6f2e5833c1c3e5ea21a2050fe0fada3a4a1d Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:00 +0000 Subject: powerpc/mpic: Assume a device-node was passed in mpic_alloc() All of the existing callers of mpic_alloc() pass in a non-NULL device-node pointer, so the checks for a NULL device-node may be removed. Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 50 +++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 8f24c6e8f535..59564dcaab14 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1137,19 +1137,17 @@ struct mpic * __init mpic_alloc(struct device_node *node, unsigned int irq_count, const char *name) { - struct mpic *mpic; - u32 greg_feature; - const char *vers; - int i; - int intvec_top; + int i, psize, intvec_top; + struct mpic *mpic; + u32 greg_feature; + const char *vers; + const u32 *psrc; - /* - * If no phyiscal address was specified then all of the phyiscal - * addressing parameters must come from the device-tree. - */ - if (!phys_addr) { - BUG_ON(!node); + /* This code assumes that a non-NULL device node is passed in */ + BUG_ON(!node); + /* Pick the physical address from the device tree if unspecified */ + if (!phys_addr) { /* Check if it is DCR-based */ if (of_get_property(node, "dcr-reg", NULL)) { flags |= MPIC_USES_DCR; @@ -1211,28 +1209,22 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->spurious_vec = intvec_top; /* Check for "big-endian" in device-tree */ - if (node && of_get_property(node, "big-endian", NULL) != NULL) + if (of_get_property(node, "big-endian", NULL) != NULL) mpic->flags |= MPIC_BIG_ENDIAN; - if (node && of_device_is_compatible(node, "fsl,mpic")) + if (of_device_is_compatible(node, "fsl,mpic")) mpic->flags |= MPIC_FSL; /* Look for protected sources */ - if (node) { - int psize; - unsigned int bits, mapsize; - const u32 *psrc = - of_get_property(node, "protected-sources", &psize); - if (psrc) { - psize /= 4; - bits = intvec_top + 1; - mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long); - mpic->protected = kzalloc(mapsize, GFP_KERNEL); - BUG_ON(mpic->protected == NULL); - for (i = 0; i < psize; i++) { - if (psrc[i] > intvec_top) - continue; - __set_bit(psrc[i], mpic->protected); - } + psrc = of_get_property(node, "protected-sources", &psize); + if (psrc) { + /* Allocate a bitmap with one bit per interrupt */ + unsigned int mapsize = BITS_TO_LONGS(intvec_top + 1); + mpic->protected = kzalloc(mapsize*sizeof(long), GFP_KERNEL); + BUG_ON(mpic->protected == NULL); + for (i = 0; i < psize/sizeof(u32); i++) { + if (psrc[i] > intvec_top) + continue; + __set_bit(psrc[i], mpic->protected); } } -- cgit v1.2.3 From e7a98675caf272a11dc1012c7a8c6c00cab09f5b Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:01 +0000 Subject: powerpc/mpic: Save computed phys_addr for board-specific code The MPIC code can already perform an automatic OF address translation step as part of mpic_alloc(), but several boards need to use that base address when they perform mpic_assign_isu(). The easiest solution is to save the computed physical address into the "struct mpic" for later use by the board code. Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 59564dcaab14..ef721c30f479 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1164,6 +1164,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, return NULL; mpic->name = name; + mpic->paddr = phys_addr; mpic->hc_irq = mpic_irq_chip; mpic->hc_irq.name = name; @@ -1250,8 +1251,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, #endif /* Map the global registers */ - mpic_map(mpic, node, phys_addr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); - mpic_map(mpic, node, phys_addr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); + mpic_map(mpic, node, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); + mpic_map(mpic, node, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); /* Reset */ @@ -1306,7 +1307,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, for_each_possible_cpu(i) { unsigned int cpu = get_hard_smp_processor_id(i); - mpic_map(mpic, node, phys_addr, &mpic->cpuregs[cpu], + mpic_map(mpic, node, mpic->paddr, &mpic->cpuregs[cpu], MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), 0x1000); } @@ -1314,7 +1315,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Initialize main ISU if none provided */ if (mpic->isu_size == 0) { mpic->isu_size = mpic->num_sources; - mpic_map(mpic, node, phys_addr, &mpic->isus[0], + mpic_map(mpic, node, mpic->paddr, &mpic->isus[0], MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); } mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); @@ -1346,7 +1347,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, } printk(KERN_INFO "mpic: Setting up MPIC \"%s\" version %s at %llx," " max %d CPUs\n", - name, vers, (unsigned long long)phys_addr, num_possible_cpus()); + name, vers, (unsigned long long)mpic->paddr, num_possible_cpus()); printk(KERN_INFO "mpic: ISU size: %d, shift: %d, mask: %x\n", mpic->isu_size, mpic->isu_shift, mpic->isu_mask); -- cgit v1.2.3 From 996983b75cebb1bc1c2c545f20336f24ebfa17af Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:02 +0000 Subject: powerpc/mpic: Search for open-pic device-tree node if NULL Almost all PowerPC platforms use a standard "open-pic" device node so the mpic_alloc() function now accepts NULL for the device-node. This will cause it to perform a default search with of_find_matching_node(). Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index ef721c30f479..bb72a6266480 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1143,8 +1143,24 @@ struct mpic * __init mpic_alloc(struct device_node *node, const char *vers; const u32 *psrc; - /* This code assumes that a non-NULL device node is passed in */ - BUG_ON(!node); + /* Default MPIC search parameters */ + static const struct of_device_id __initconst mpic_device_id[] = { + { .type = "open-pic", }, + { .compatible = "open-pic", }, + {}, + }; + + /* + * If we were not passed a device-tree node, then perform the default + * search for standardized a standardized OpenPIC. + */ + if (node) { + node = of_node_get(node); + } else { + node = of_find_matching_node(NULL, mpic_device_id); + if (!node) + return NULL; + } /* Pick the physical address from the device tree if unspecified */ if (!phys_addr) { @@ -1154,14 +1170,14 @@ struct mpic * __init mpic_alloc(struct device_node *node, } else { struct resource r; if (of_address_to_resource(node, 0, &r)) - return NULL; + goto err_of_node_put; phys_addr = r.start; } } mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); if (mpic == NULL) - return NULL; + goto err_of_node_put; mpic->name = name; mpic->paddr = phys_addr; @@ -1325,6 +1341,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, isu_size ? isu_size : mpic->num_sources, &mpic_host_ops, flags & MPIC_LARGE_VECTORS ? 2048 : 256); + + /* + * FIXME: The code leaks the MPIC object and mappings here; this + * is very unlikely to fail but it ought to be fixed anyways. + */ if (mpic->irqhost == NULL) return NULL; @@ -1359,7 +1380,12 @@ struct mpic * __init mpic_alloc(struct device_node *node, irq_set_default_host(mpic->irqhost); } + of_node_put(node); return mpic; + +err_of_node_put: + of_node_put(node); + return NULL; } void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, -- cgit v1.2.3 From be8bec56dfac0574c4c08a50cd37e09bea941e3f Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:03 +0000 Subject: powerpc/mpic: Invert the meaning of MPIC_PRIMARY It turns out that there are only 2 in-tree platforms which use MPICs which are not "primary": IBM Cell and PowerMac. To reduce the complexity of the typical board setup code, invert the MPIC_PRIMARY bit into MPIC_SECONDARY. Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index bb72a6266480..6d42ad1491a9 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -154,7 +154,7 @@ static inline unsigned int mpic_processor_id(struct mpic *mpic) { unsigned int cpu = 0; - if (mpic->flags & MPIC_PRIMARY) + if (!(mpic->flags & MPIC_SECONDARY)) cpu = hard_smp_processor_id(); return cpu; @@ -990,7 +990,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, #ifdef CONFIG_SMP else if (hw >= mpic->ipi_vecs[0]) { - WARN_ON(!(mpic->flags & MPIC_PRIMARY)); + WARN_ON(mpic->flags & MPIC_SECONDARY); DBG("mpic: mapping as IPI\n"); irq_set_chip_data(virq, mpic); @@ -1001,7 +1001,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, #endif /* CONFIG_SMP */ if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) { - WARN_ON(!(mpic->flags & MPIC_PRIMARY)); + WARN_ON(mpic->flags & MPIC_SECONDARY); DBG("mpic: mapping as timer\n"); irq_set_chip_data(virq, mpic); @@ -1184,12 +1184,12 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->hc_irq = mpic_irq_chip; mpic->hc_irq.name = name; - if (flags & MPIC_PRIMARY) + if (!(flags & MPIC_SECONDARY)) mpic->hc_irq.irq_set_affinity = mpic_set_affinity; #ifdef CONFIG_MPIC_U3_HT_IRQS mpic->hc_ht_irq = mpic_irq_ht_chip; mpic->hc_ht_irq.name = name; - if (flags & MPIC_PRIMARY) + if (!(flags & MPIC_SECONDARY)) mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; #endif /* CONFIG_MPIC_U3_HT_IRQS */ @@ -1375,7 +1375,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->next = mpics; mpics = mpic; - if (flags & MPIC_PRIMARY) { + if (!(flags & MPIC_SECONDARY)) { mpic_primary = mpic; irq_set_default_host(mpic->irqhost); } @@ -1450,7 +1450,7 @@ void __init mpic_init(struct mpic *mpic) /* Do the HT PIC fixups on U3 broken mpic */ DBG("MPIC flags: %x\n", mpic->flags); - if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) { + if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { mpic_scan_ht_pics(mpic); mpic_u3msi_init(mpic); } -- cgit v1.2.3 From e62b760179506531bf6d0c522c0def0f84847eb7 Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:04 +0000 Subject: powerpc/mpic: Don't open-code dcr_resource_start Don't open-code the OpenFirmware "dcr-reg" property lookup trying to map DCR resources. This makes the code a bit easier to read. Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 6d42ad1491a9..1e7584bb62c0 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -319,11 +319,8 @@ static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node, struct mpic_reg_bank *rb, unsigned int offset, unsigned int size) { - const u32 *dbasep; - - dbasep = of_get_property(node, "dcr-reg", NULL); - - rb->dhost = dcr_map(node, *dbasep + offset, size); + phys_addr_t phys_addr = dcr_resource_start(node, 0); + rb->dhost = dcr_map(mpic->node, phys_addr + offset, size); BUG_ON(!DCR_MAP_OK(rb->dhost)); } -- cgit v1.2.3 From c579bc766a84a57c31d7b41276ffa9545a34ee1b Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:05 +0000 Subject: powerpc/mpic: Put "pic-no-reset" test back into the MPIC code There's not really any reason to have this one-liner in a separate static inline function, given that all the other similar tests are already in the alloc_mpic() code. Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 1e7584bb62c0..3240bbabc2f9 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1118,11 +1118,6 @@ static struct irq_host_ops mpic_host_ops = { .xlate = mpic_host_xlate, }; -static int mpic_reset_prohibited(struct device_node *node) -{ - return node && of_get_property(node, "pic-no-reset", NULL); -} - /* * Exported functions */ @@ -1272,7 +1267,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* When using a device-node, reset requests are only honored if the MPIC * is allowed to reset. */ - if (mpic_reset_prohibited(node)) + if (of_get_property(node, "pic-no-reset", NULL)) mpic->flags |= MPIC_NO_RESET; if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { -- cgit v1.2.3 From c51242e7080d2265761de309cdea222d7e27bdfe Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:06 +0000 Subject: powerpc/mpic: Cache the device-tree node in "struct mpic" Store the node pointer in the MPIC during initialization so that all of the later operational code can just reuse the cached pointer. Signed-off-by: Kyle Moffett Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 3240bbabc2f9..76110608543a 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -315,26 +315,25 @@ static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, } #ifdef CONFIG_PPC_DCR -static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node, - struct mpic_reg_bank *rb, +static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, unsigned int offset, unsigned int size) { - phys_addr_t phys_addr = dcr_resource_start(node, 0); + phys_addr_t phys_addr = dcr_resource_start(mpic->node, 0); rb->dhost = dcr_map(mpic->node, phys_addr + offset, size); BUG_ON(!DCR_MAP_OK(rb->dhost)); } -static inline void mpic_map(struct mpic *mpic, struct device_node *node, +static inline void mpic_map(struct mpic *mpic, phys_addr_t phys_addr, struct mpic_reg_bank *rb, unsigned int offset, unsigned int size) { if (mpic->flags & MPIC_USES_DCR) - _mpic_map_dcr(mpic, node, rb, offset, size); + _mpic_map_dcr(mpic, rb, offset, size); else _mpic_map_mmio(mpic, phys_addr, rb, offset, size); } #else /* CONFIG_PPC_DCR */ -#define mpic_map(m,n,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) +#define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) #endif /* !CONFIG_PPC_DCR */ @@ -1172,6 +1171,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, goto err_of_node_put; mpic->name = name; + mpic->node = node; mpic->paddr = phys_addr; mpic->hc_irq = mpic_irq_chip; @@ -1218,13 +1218,13 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->spurious_vec = intvec_top; /* Check for "big-endian" in device-tree */ - if (of_get_property(node, "big-endian", NULL) != NULL) + if (of_get_property(mpic->node, "big-endian", NULL) != NULL) mpic->flags |= MPIC_BIG_ENDIAN; - if (of_device_is_compatible(node, "fsl,mpic")) + if (of_device_is_compatible(mpic->node, "fsl,mpic")) mpic->flags |= MPIC_FSL; /* Look for protected sources */ - psrc = of_get_property(node, "protected-sources", &psize); + psrc = of_get_property(mpic->node, "protected-sources", &psize); if (psrc) { /* Allocate a bitmap with one bit per interrupt */ unsigned int mapsize = BITS_TO_LONGS(intvec_top + 1); @@ -1259,15 +1259,15 @@ struct mpic * __init mpic_alloc(struct device_node *node, #endif /* Map the global registers */ - mpic_map(mpic, node, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); - mpic_map(mpic, node, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); + mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); + mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); /* Reset */ /* When using a device-node, reset requests are only honored if the MPIC * is allowed to reset. */ - if (of_get_property(node, "pic-no-reset", NULL)) + if (of_get_property(mpic->node, "pic-no-reset", NULL)) mpic->flags |= MPIC_NO_RESET; if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { @@ -1315,7 +1315,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, for_each_possible_cpu(i) { unsigned int cpu = get_hard_smp_processor_id(i); - mpic_map(mpic, node, mpic->paddr, &mpic->cpuregs[cpu], + mpic_map(mpic, mpic->paddr, &mpic->cpuregs[cpu], MPIC_INFO(CPU_BASE) + cpu * MPIC_INFO(CPU_STRIDE), 0x1000); } @@ -1323,13 +1323,13 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Initialize main ISU if none provided */ if (mpic->isu_size == 0) { mpic->isu_size = mpic->num_sources; - mpic_map(mpic, node, mpic->paddr, &mpic->isus[0], + mpic_map(mpic, mpic->paddr, &mpic->isus[0], MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); } mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); mpic->isu_mask = (1 << mpic->isu_shift) - 1; - mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, + mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR, isu_size ? isu_size : mpic->num_sources, &mpic_host_ops, flags & MPIC_LARGE_VECTORS ? 2048 : 256); @@ -1372,7 +1372,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, irq_set_default_host(mpic->irqhost); } - of_node_put(node); return mpic; err_of_node_put: @@ -1387,7 +1386,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, BUG_ON(isu_num >= MPIC_MAX_ISU); - mpic_map(mpic, mpic->irqhost->of_node, + mpic_map(mpic, paddr, &mpic->isus[isu_num], 0, MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); -- cgit v1.2.3 From 09dc34a95bfbc6062e1e7de0b96175480924aea8 Mon Sep 17 00:00:00 2001 From: Kyle Moffett Date: Fri, 2 Dec 2011 06:28:07 +0000 Subject: powerpc/mpic: Add in-core support for cascaded MPICs 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 Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/sysdev/mpic.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/sysdev/mpic.c') diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 76110608543a..4e9ccb1015de 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -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, @@ -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); @@ -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) -- cgit v1.2.3