On Wed, Jun 29, 2011 at 07:53:19PM +0300, Felipe Balbi wrote: > 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. [1] http://marc.info/?l=linux-omap&m=130934802215308&w=2 [2] http://marc.info/?l=linux-omap&m=130934804515353&w=2 -- balbi
Attachment:
signature.asc
Description: Digital signature