Hi,
On Wed, Jun 29, 2011 at 12:04:55PM +0300, Tero Kristo wrote:
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index 96a7624..89cf027 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -880,20 +824,35 @@ static int __init omap3_pm_init(void)
> /* XXX prcm_setup_regs needs to be before enabling hw
> * supervised mode for powerdomains */
> prcm_setup_regs();
> + ret = omap_prcm_irq_init();
> + if (ret) {
> + pr_err("omap_prcm_irq_init() failed with %d\n", ret);
> + goto err_prcm_irq_init;
> + }
> +
> + prcm_wkup_irq = omap_prcm_event_to_irq("wkup");
> + prcm_io_irq = omap_prcm_event_to_irq("io");
> +
> + ret = request_irq(prcm_wkup_irq, _prcm_int_handle_wakeup,
> + IRQF_NO_SUSPEND | IRQF_DISABLED, "prcm_wkup", NULL);
does this _have_ to be all in hardirq context ?
> - ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
> - (irq_handler_t)prcm_interrupt_handler,
> - IRQF_DISABLED, "prcm", NULL);
> if (ret) {
> - printk(KERN_ERR "request_irq failed to register for 0x%x\n",
> - INT_34XX_PRCM_MPU_IRQ);
> - goto err1;
> + printk(KERN_ERR "Failed to request prcm_wkup irq\n");
> + goto err_prcm_wkup;
> + }
> +
> + ret = request_irq(prcm_io_irq, _prcm_int_handle_wakeup,
> + IRQF_NO_SUSPEND | IRQF_DISABLED, "prcm_io", NULL);
same here...
> diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
> index 6be1438..794e451 100644
> --- a/arch/arm/mach-omap2/prcm.c
> +++ b/arch/arm/mach-omap2/prcm.c
> @@ -23,6 +23,8 @@
> #include <linux/clk.h>
> #include <linux/io.h>
> #include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/slab.h>
>
> #include <mach/system.h>
> #include <plat/common.h>
> @@ -45,6 +47,167 @@ void __iomem *cm2_base;
>
> #define MAX_MODULE_ENABLE_WAIT 100000
>
> +/* Setup for the interrupt handling based on used platform */
> +static struct omap_prcm_irq_setup *irq_setup;
you can set this is irq_chip data, then you can:
> +static void prcm_irq_ack(struct irq_data *data)
> +{
struct omap_prcm_irq_setup *irq_setup =
irq_data_get_irq_chip_data(data)
unsigned int prcm_irq = data->irq - irq_setup->base;
irq_setup->ack_event(prcm_irq);
> +}
ditto to all other operations.
> +static struct irq_chip_generic *prcm_irq_chips[OMAP_PRCM_MAX_NR_PENDING_REG];
can't you allocate this dynamically ???
> +/*
> + * PRCM Interrupt Handler
> + *
> + * The PRM_IRQSTATUS_MPU register indicates if there are any pending
> + * interrupts from the PRCM for the MPU. These bits must be cleared in
> + * order to clear the PRCM interrupt. The PRCM interrupt handler is
> + * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
> + * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
> + * register indicates that a wake-up event is pending for the MPU and
> + * this bit can only be cleared if the all the wake-up events latched
> + * in the various PM_WKST_x registers have been cleared. The interrupt
> + * handler is implemented using a do-while loop so that if a wake-up
> + * event occurred during the processing of the prcm interrupt handler
> + * (setting a bit in the corresponding PM_WKST_x register and thus
> + * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
> + * this would be handled.
> + */
> +static void prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
> +{
> + unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
> + struct irq_chip *chip = irq_desc_get_chip(desc);
> +
> + /*
> + * Loop until all pending irqs are handled, since
> + * generic_handle_irq(), called by prcm_irq_handle_virtirqs()
> + * can cause new irqs to come
> + */
> + while (1) {
> + unsigned int virtirq;
> +
> + chip->irq_ack(&desc->irq_data);
> +
> + memset(pending, 0, sizeof(pending));
> + irq_setup->pending_events(pending);
> +
> + /* No bit set, then all IRQs are handled */
> + if (find_first_bit(pending, OMAP_PRCM_NR_IRQS)
> + >= OMAP_PRCM_NR_IRQS) {
> + chip->irq_unmask(&desc->irq_data);
> + break;
> + }
> +
> + /*
> + * Loop on all currently pending irqs so that new irqs
> + * cannot starve previously pending irqs
> + */
> + for_each_set_bit(virtirq, pending, OMAP_PRCM_NR_IRQS)
> + generic_handle_irq(OMAP_PRCM_IRQ_BASE + virtirq);
if you use nested IRQ threads, you could be using
handle_nested_irq(irq);
> + chip->irq_unmask(&desc->irq_data);
> + }
> +}
> +
> +/*
> + * Given a PRCM event name, returns the corresponding IRQ on which the
> + * handler should be registered.
> + */
> +int omap_prcm_event_to_irq(const char *name)
> +{
> + int i;
> +
> + for (i = 0; i < irq_setup->num_irqs; i++)
> + if (!strcmp(irq_setup->irqs[i].name, name))
> + return OMAP_PRCM_IRQ_BASE + irq_setup->irqs[i].offset;
> +
> + return -ENOENT;
> +}
> +
> +/*
> + * Prepare the array of PRCM events corresponding to the current SoC,
> + * and set-up the chained interrupt handler mechanism.
> + */
> +int __init omap_prcm_irq_init(void)
> +{
> + int i;
> + struct irq_chip_generic *gc;
> + struct irq_chip_type *ct;
> + u32 mask[2] = { 0, 0 };
> + int offset;
> + int max_irq = 0;
> +
> + for (i = 0; i < irq_setup->num_irqs; i++)
how about using irq_alloc_descs() ?? Then we can make use of Sparse IRQ
numbers and avoid passing irq_base/irq_end and adding that weird ifdef
hackery to get NR_IRQS right.
> diff --git a/arch/arm/plat-omap/include/plat/irqs.h
> b/arch/arm/plat-omap/include/plat/irqs.h
> index 5a25098..23b9680 100644
> --- a/arch/arm/plat-omap/include/plat/irqs.h
> +++ b/arch/arm/plat-omap/include/plat/irqs.h
> @@ -366,7 +366,14 @@
> #define OMAP_MAX_GPIO_LINES 192
> #define IH_GPIO_BASE (128 + IH2_BASE)
> #define IH_MPUIO_BASE (OMAP_MAX_GPIO_LINES + IH_GPIO_BASE)
> -#define OMAP_IRQ_END (IH_MPUIO_BASE + 16)
> +#define OMAP_MPUIO_IRQ_END (IH_MPUIO_BASE + 16)
> +
> +/* 64 IRQs for the PRCM (32 are needed on OMAP3, 64 on OMAP4) */
> +#define OMAP_PRCM_IRQ_BASE (OMAP_MPUIO_IRQ_END)
> +#define OMAP_PRCM_NR_IRQS 64
> +#define OMAP_PRCM_IRQ_END (OMAP_PRCM_IRQ_BASE + OMAP_PRCM_NR_IRQS)
> +
> +#define OMAP_IRQ_END (OMAP_PRCM_IRQ_END)
this is unnecessary with Sparse IRQ numbers and IMHO we should aim for
that. See the very simple conversion that I sent for the very old retu
driver [1] and [2] and you'll see that with time, we could get rid of
NR_IRQS altogether.
--
balbi
signature.asc
Description: Digital signature
