From cfeaa93f8a13ae9117ae20933a38a406de80849e Mon Sep 17 00:00:00 2001 From: Gerlando Falauto Date: Mon, 6 May 2013 14:30:17 +0000 Subject: genirq: Generic chip: Remove the local cur_regs() function Since we already have an irq_data_get_chip_type() function which returns a pointer to irq_chip_type, use that instead of cur_regs(). Signed-off-by: Gerlando Falauto Cc: Andrew Lunn Cc: Joey Oravec Cc: Lennert Buytenhek Cc: Russell King - ARM Linux Cc: Jason Gunthorpe Cc: Holger Brunck Cc: Ezequiel Garcia Acked-by: Grant Likely Cc: Sebastian Hesselbarth Cc: Jason Cooper Cc: Arnd Bergmann Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: Ben Dooks Cc: Gregory Clement Cc: Simon Guinot Cc: linux-arm-kernel@lists.infradead.org Cc: Thomas Petazzoni Cc: Jean-Francois Moine Cc: Nicolas Pitre Cc: Rob Landley Cc: Maxime Ripard Link: http://lkml.kernel.org/r/20130506142539.010164766@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index c89295a8f668..0e6ba789056c 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -16,11 +16,6 @@ static LIST_HEAD(gc_list); static DEFINE_RAW_SPINLOCK(gc_lock); -static inline struct irq_chip_regs *cur_regs(struct irq_data *d) -{ - return &container_of(d->chip, struct irq_chip_type, chip)->regs; -} - /** * irq_gc_noop - NOOP function * @d: irq_data @@ -39,10 +34,11 @@ void irq_gc_noop(struct irq_data *d) void irq_gc_mask_disable_reg(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable); + irq_reg_writel(mask, gc->reg_base + ct->regs.disable); gc->mask_cache &= ~mask; irq_gc_unlock(gc); } @@ -57,11 +53,12 @@ void irq_gc_mask_disable_reg(struct irq_data *d) void irq_gc_mask_set_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); gc->mask_cache |= mask; - irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); + irq_reg_writel(gc->mask_cache, gc->reg_base + ct->regs.mask); irq_gc_unlock(gc); } @@ -75,11 +72,12 @@ void irq_gc_mask_set_bit(struct irq_data *d) void irq_gc_mask_clr_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); gc->mask_cache &= ~mask; - irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); + irq_reg_writel(gc->mask_cache, gc->reg_base + ct->regs.mask); irq_gc_unlock(gc); } @@ -93,10 +91,11 @@ void irq_gc_mask_clr_bit(struct irq_data *d) void irq_gc_unmask_enable_reg(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable); + irq_reg_writel(mask, gc->reg_base + ct->regs.enable); gc->mask_cache |= mask; irq_gc_unlock(gc); } @@ -108,10 +107,11 @@ void irq_gc_unmask_enable_reg(struct irq_data *d) void irq_gc_ack_set_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); + irq_reg_writel(mask, gc->reg_base + ct->regs.ack); irq_gc_unlock(gc); } @@ -122,10 +122,11 @@ void irq_gc_ack_set_bit(struct irq_data *d) void irq_gc_ack_clr_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = ~(1 << (d->irq - gc->irq_base)); irq_gc_lock(gc); - irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); + irq_reg_writel(mask, gc->reg_base + ct->regs.ack); irq_gc_unlock(gc); } @@ -136,11 +137,12 @@ void irq_gc_ack_clr_bit(struct irq_data *d) void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask); - irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); + irq_reg_writel(mask, gc->reg_base + ct->regs.mask); + irq_reg_writel(mask, gc->reg_base + ct->regs.ack); irq_gc_unlock(gc); } @@ -151,10 +153,11 @@ void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) void irq_gc_eoi(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi); + irq_reg_writel(mask, gc->reg_base + ct->regs.eoi); irq_gc_unlock(gc); } -- cgit v1.2.3 From 899f0e66fff36ebb6dd6a83af9aa631f6cb7e0dc Mon Sep 17 00:00:00 2001 From: Gerlando Falauto Date: Mon, 6 May 2013 14:30:19 +0000 Subject: genirq: Generic chip: Add support for per chip type mask cache Today the same interrupt mask cache (stored within struct irq_chip_generic) is shared between all the irq_chip_type instances. As there are instances where each irq_chip_type uses a distinct mask register (as it is the case for Orion SoCs), sharing a single mask cache may be incorrect. So add a distinct pointer for each irq_chip_type, which for now points to the original mask register within irq_chip_generic. So no functional changes here. [ tglx: Minor cosmetic tweaks ] Reported-by: Joey Oravec Signed-off-by: Simon Guinot Signed-off-by: Holger Brunck Signed-off-by: Gerlando Falauto Cc: Andrew Lunn Cc: Lennert Buytenhek Cc: Russell King - ARM Linux Cc: Jason Gunthorpe Cc: Holger Brunck Cc: Ezequiel Garcia Acked-by: Grant Likely Cc: Sebastian Hesselbarth Cc: Jason Cooper Cc: Arnd Bergmann Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: Ben Dooks Cc: Gregory Clement Cc: Simon Guinot Cc: linux-arm-kernel@lists.infradead.org Cc: Thomas Petazzoni Cc: Jean-Francois Moine Cc: Nicolas Pitre Cc: Rob Landley Cc: Maxime Ripard Link: http://lkml.kernel.org/r/20130506142539.082226607@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 0e6ba789056c..113d9ebfe0aa 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -39,7 +39,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d) irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.disable); - gc->mask_cache &= ~mask; + *ct->mask_cache &= ~mask; irq_gc_unlock(gc); } @@ -57,8 +57,8 @@ void irq_gc_mask_set_bit(struct irq_data *d) u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - gc->mask_cache |= mask; - irq_reg_writel(gc->mask_cache, gc->reg_base + ct->regs.mask); + *ct->mask_cache |= mask; + irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); irq_gc_unlock(gc); } @@ -76,8 +76,8 @@ void irq_gc_mask_clr_bit(struct irq_data *d) u32 mask = 1 << (d->irq - gc->irq_base); irq_gc_lock(gc); - gc->mask_cache &= ~mask; - irq_reg_writel(gc->mask_cache, gc->reg_base + ct->regs.mask); + *ct->mask_cache &= ~mask; + irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); irq_gc_unlock(gc); } @@ -96,7 +96,7 @@ void irq_gc_unmask_enable_reg(struct irq_data *d) irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.enable); - gc->mask_cache |= mask; + *ct->mask_cache |= mask; irq_gc_unlock(gc); } @@ -250,6 +250,10 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, if (flags & IRQ_GC_INIT_MASK_CACHE) gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); + /* Initialize mask cache pointer */ + for (i = 0; i < gc->num_ct; i++) + ct[i].mask_cache = &gc->mask_cache; + for (i = gc->irq_base; msk; msk >>= 1, i++) { if (!(msk & 0x01)) continue; -- cgit v1.2.3 From af80b0fed67261dcba2ce2406db1d553d07cbe75 Mon Sep 17 00:00:00 2001 From: Gerlando Falauto Date: Mon, 6 May 2013 14:30:21 +0000 Subject: genirq: Generic chip: Handle separate mask registers There are cases where all irq_chip_type instances have separate mask registers, making a shared mask register cache unsuitable for the purpose. Introduce a new flag IRQ_GC_MASK_CACHE_PER_TYPE. If set, point the per chip mask pointer to the per chip private mask cache instead. [ tglx: Simplified code, renamed flag and massaged changelog ] Signed-off-by: Gerlando Falauto Cc: Andrew Lunn Cc: Joey Oravec Cc: Lennert Buytenhek Cc: Russell King - ARM Linux Cc: Jason Gunthorpe Cc: Holger Brunck Cc: Ezequiel Garcia Acked-by: Grant Likely Cc: Sebastian Hesselbarth Cc: Jason Cooper Cc: Arnd Bergmann Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: Ben Dooks Cc: Gregory Clement Cc: Simon Guinot Cc: linux-arm-kernel@lists.infradead.org Cc: Thomas Petazzoni Cc: Jean-Francois Moine Cc: Nicolas Pitre Cc: Rob Landley Cc: Maxime Ripard Link: http://lkml.kernel.org/r/20130506142539.152569748@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 113d9ebfe0aa..da2a94191fc5 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -241,18 +241,21 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, { struct irq_chip_type *ct = gc->chip_types; unsigned int i; + u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask; raw_spin_lock(&gc_lock); list_add_tail(&gc->list, &gc_list); raw_spin_unlock(&gc_lock); - /* Init mask cache ? */ - if (flags & IRQ_GC_INIT_MASK_CACHE) - gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); - - /* Initialize mask cache pointer */ - for (i = 0; i < gc->num_ct; i++) - ct[i].mask_cache = &gc->mask_cache; + for (i = 0; i < gc->num_ct; i++) { + if (flags & IRQ_GC_MASK_CACHE_PER_TYPE) { + mskptr = &ct[i].mask_cache_priv; + mskreg = ct[i].regs.mask; + } + ct[i].mask_cache = mskptr; + if (flags & IRQ_GC_INIT_MASK_CACHE) + *mskptr = irq_reg_readl(gc->reg_base + mskreg); + } for (i = gc->irq_base; msk; msk >>= 1, i++) { if (!(msk & 0x01)) -- cgit v1.2.3 From 966dc736b819999cd2d3a6408d47d33b579f7d56 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 May 2013 14:30:22 +0000 Subject: genirq: Generic chip: Cache per irq bit mask Cache the per irq bit mask instead of recalculating it over and over. Signed-off-by: Thomas Gleixner Cc: Thomas Petazzoni Cc: Andrew Lunn Cc: Russell King - ARM Linux Cc: Jason Cooper Cc: Arnd Bergmann Cc: Jean-Francois Moine Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: Jason Gunthorpe Cc: Gregory Clement Cc: Gerlando Falauto Cc: Rob Landley Acked-by: Grant Likely Cc: Maxime Ripard Cc: Ezequiel Garcia Cc: linux-arm-kernel@lists.infradead.org Cc: Sebastian Hesselbarth Link: http://lkml.kernel.org/r/20130506142539.227119865@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index da2a94191fc5..957155cebbac 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -35,7 +35,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.disable); @@ -54,7 +54,7 @@ void irq_gc_mask_set_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; irq_gc_lock(gc); *ct->mask_cache |= mask; @@ -73,7 +73,7 @@ void irq_gc_mask_clr_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; irq_gc_lock(gc); *ct->mask_cache &= ~mask; @@ -92,7 +92,7 @@ void irq_gc_unmask_enable_reg(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.enable); @@ -108,7 +108,7 @@ void irq_gc_ack_set_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.ack); @@ -123,7 +123,7 @@ void irq_gc_ack_clr_bit(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = ~(1 << (d->irq - gc->irq_base)); + u32 mask = ~d->mask; irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.ack); @@ -138,7 +138,7 @@ void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.mask); @@ -154,7 +154,7 @@ void irq_gc_eoi(struct irq_data *d) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct irq_chip_type *ct = irq_data_get_chip_type(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; irq_gc_lock(gc); irq_reg_writel(mask, gc->reg_base + ct->regs.eoi); @@ -172,7 +172,7 @@ void irq_gc_eoi(struct irq_data *d) int irq_gc_set_wake(struct irq_data *d, unsigned int on) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - u32 mask = 1 << (d->irq - gc->irq_base); + u32 mask = d->mask; if (!(mask & gc->wake_enabled)) return -EINVAL; @@ -264,6 +264,11 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, if (flags & IRQ_GC_INIT_NESTED_LOCK) irq_set_lockdep_class(i, &irq_nested_lock_class); + if (!(flags & IRQ_GC_NO_MASK)) { + struct irq_data *d = irq_get_irq_data(i); + + d->mask = 1 << (i - gc->irq_base); + } irq_set_chip_and_handler(i, &ct->chip, ct->handler); irq_set_chip_data(i, gc); irq_modify_status(i, clr, set); -- cgit v1.2.3 From d0051816e619f8f082582bec07ffa51bdb4f2104 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 May 2013 14:30:24 +0000 Subject: genirq: irqchip: Add a mask calculation function Some chips have weird bit mask access patterns instead of the linear you expect. Allow them to calculate the cached mask themself. Signed-off-by: Thomas Gleixner Cc: Thomas Petazzoni Cc: Andrew Lunn Cc: Russell King - ARM Linux Cc: Jason Cooper Cc: Arnd Bergmann Cc: Jean-Francois Moine Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: Jason Gunthorpe Cc: Gregory Clement Cc: Gerlando Falauto Cc: Rob Landley Acked-by: Grant Likely Cc: Maxime Ripard Cc: Ezequiel Garcia Cc: linux-arm-kernel@lists.infradead.org Cc: Sebastian Hesselbarth Link: http://lkml.kernel.org/r/20130506142539.302898834@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 957155cebbac..5068fe3ae1af 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -240,6 +240,7 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, unsigned int set) { struct irq_chip_type *ct = gc->chip_types; + struct irq_chip *chip = &ct->chip; unsigned int i; u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask; @@ -267,9 +268,12 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, if (!(flags & IRQ_GC_NO_MASK)) { struct irq_data *d = irq_get_irq_data(i); - d->mask = 1 << (i - gc->irq_base); + if (chip->irq_calc_mask) + chip->irq_calc_mask(d); + else + d->mask = 1 << (i - gc->irq_base); } - irq_set_chip_and_handler(i, &ct->chip, ct->handler); + irq_set_chip_and_handler(i, chip, ct->handler); irq_set_chip_data(i, gc); irq_modify_status(i, clr, set); } -- cgit v1.2.3 From 3528d82b684680b72fa31881c8c572c5a98b51de Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 May 2013 14:30:25 +0000 Subject: genirq: Generic chip: Split out code into separate functions Preparatory patch for linear interrupt domains. Signed-off-by: Thomas Gleixner Cc: Thomas Petazzoni Cc: Andrew Lunn Cc: Russell King - ARM Linux Cc: Jason Cooper Cc: Arnd Bergmann Cc: Jean-Francois Moine Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: Jason Gunthorpe Cc: Gregory Clement Cc: Gerlando Falauto Cc: Rob Landley Acked-by: Grant Likely Cc: Maxime Ripard Cc: Ezequiel Garcia Cc: linux-arm-kernel@lists.infradead.org Cc: Sebastian Hesselbarth Link: http://lkml.kernel.org/r/20130506142539.377017672@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 50 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 5068fe3ae1af..3deb3333d53e 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -186,6 +186,19 @@ int irq_gc_set_wake(struct irq_data *d, unsigned int on) return 0; } +static void +irq_init_generic_chip(struct irq_chip_generic *gc, const char *name, + int num_ct, unsigned int irq_base, + void __iomem *reg_base, irq_flow_handler_t handler) +{ + raw_spin_lock_init(&gc->lock); + gc->num_ct = num_ct; + gc->irq_base = irq_base; + gc->reg_base = reg_base; + gc->chip_types->chip.name = name; + gc->chip_types->handler = handler; +} + /** * irq_alloc_generic_chip - Allocate a generic chip and initialize it * @name: Name of the irq chip @@ -206,17 +219,31 @@ irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, gc = kzalloc(sz, GFP_KERNEL); if (gc) { - raw_spin_lock_init(&gc->lock); - gc->num_ct = num_ct; - gc->irq_base = irq_base; - gc->reg_base = reg_base; - gc->chip_types->chip.name = name; - gc->chip_types->handler = handler; + irq_init_generic_chip(gc, name, num_ct, irq_base, reg_base, + handler); } return gc; } EXPORT_SYMBOL_GPL(irq_alloc_generic_chip); +static void +irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags) +{ + struct irq_chip_type *ct = gc->chip_types; + u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask; + int i; + + for (i = 0; i < gc->num_ct; i++) { + if (flags & IRQ_GC_MASK_CACHE_PER_TYPE) { + mskptr = &ct[i].mask_cache_priv; + mskreg = ct[i].regs.mask; + } + ct[i].mask_cache = mskptr; + if (flags & IRQ_GC_INIT_MASK_CACHE) + *mskptr = irq_reg_readl(gc->reg_base + mskreg); + } +} + /* * Separate lockdep class for interrupt chip which can nest irq_desc * lock. @@ -242,21 +269,12 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, struct irq_chip_type *ct = gc->chip_types; struct irq_chip *chip = &ct->chip; unsigned int i; - u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask; raw_spin_lock(&gc_lock); list_add_tail(&gc->list, &gc_list); raw_spin_unlock(&gc_lock); - for (i = 0; i < gc->num_ct; i++) { - if (flags & IRQ_GC_MASK_CACHE_PER_TYPE) { - mskptr = &ct[i].mask_cache_priv; - mskreg = ct[i].regs.mask; - } - ct[i].mask_cache = mskptr; - if (flags & IRQ_GC_INIT_MASK_CACHE) - *mskptr = irq_reg_readl(gc->reg_base + mskreg); - } + irq_gc_init_mask_cache(gc, flags); for (i = gc->irq_base; msk; msk >>= 1, i++) { if (!(msk & 0x01)) -- cgit v1.2.3 From 088f40b7b027dad6519712ff224a5798dd62a204 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 May 2013 14:30:27 +0000 Subject: genirq: Generic chip: Add linear irq domain support Provide infrastructure for irq chip implementations which work on linear irq domains. - Interface to allocate multiple generic chips which are associated to the irq domain. - Interface to get the generic chip pointer for a particular hardware interrupt in the domain. - irq domain mapping function to install the chip for a particular interrupt. Note: This lacks a removal function for now. [ Sebastian Hesselbarth: Mask cache and pointer math fixups ] Signed-off-by: Thomas Gleixner Cc: Thomas Petazzoni Cc: Andrew Lunn Cc: Russell King - ARM Linux Cc: Jason Cooper Cc: Arnd Bergmann Cc: Jean-Francois Moine Cc: devicetree-discuss@lists.ozlabs.org Cc: Rob Herring Cc: Jason Gunthorpe Cc: Gregory Clement Cc: Gerlando Falauto Cc: Rob Landley Acked-by: Grant Likely Cc: Maxime Ripard Cc: Ezequiel Garcia Cc: linux-arm-kernel@lists.infradead.org Cc: Sebastian Hesselbarth Link: http://lkml.kernel.org/r/20130506142539.450634298@linutronix.de Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 187 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 6 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 3deb3333d53e..8743d62fded7 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -244,12 +245,156 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags) } } +/** + * irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain + * @d: irq domain for which to allocate chips + * @irqs_per_chip: Number of interrupts each chip handles + * @num_ct: Number of irq_chip_type instances associated with this + * @name: Name of the irq chip + * @handler: Default flow handler associated with these chips + * @clr: IRQ_* bits to clear in the mapping function + * @set: IRQ_* bits to set in the mapping function + */ +int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, + int num_ct, const char *name, + irq_flow_handler_t handler, + unsigned int clr, unsigned int set, + enum irq_gc_flags gcflags) +{ + struct irq_domain_chip_generic *dgc; + struct irq_chip_generic *gc; + int numchips, sz, i; + unsigned long flags; + void *tmp; + + if (d->gc) + return -EBUSY; + + if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR) + return -EINVAL; + + numchips = d->revmap_data.linear.size / irqs_per_chip; + if (!numchips) + return -EINVAL; + + /* Allocate a pointer, generic chip and chiptypes for each chip */ + sz = sizeof(*dgc) + numchips * sizeof(gc); + sz += numchips * (sizeof(*gc) + num_ct * sizeof(struct irq_chip_type)); + + tmp = dgc = kzalloc(sz, GFP_KERNEL); + if (!dgc) + return -ENOMEM; + dgc->irqs_per_chip = irqs_per_chip; + dgc->num_chips = numchips; + dgc->irq_flags_to_set = set; + dgc->irq_flags_to_clear = clr; + dgc->gc_flags = gcflags; + d->gc = dgc; + + /* Calc pointer to the first generic chip */ + tmp += sizeof(*dgc) + numchips * sizeof(gc); + for (i = 0; i < numchips; i++) { + /* Store the pointer to the generic chip */ + dgc->gc[i] = gc = tmp; + irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip, + NULL, handler); + gc->domain = d; + raw_spin_lock_irqsave(&gc_lock, flags); + list_add_tail(&gc->list, &gc_list); + raw_spin_unlock_irqrestore(&gc_lock, flags); + /* Calc pointer to the next generic chip */ + tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); + } + return 0; +} +EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips); + +/** + * irq_get_domain_generic_chip - Get a pointer to the generic chip of a hw_irq + * @d: irq domain pointer + * @hw_irq: Hardware interrupt number + */ +struct irq_chip_generic * +irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq) +{ + struct irq_domain_chip_generic *dgc = d->gc; + int idx; + + if (!dgc) + return NULL; + idx = hw_irq / dgc->irqs_per_chip; + if (idx >= dgc->num_chips) + return NULL; + return dgc->gc[idx]; +} +EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip); + /* * Separate lockdep class for interrupt chip which can nest irq_desc * lock. */ static struct lock_class_key irq_nested_lock_class; +/** + * irq_map_generic_chip - Map a generic chip for an irq domain + */ +static int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw_irq) +{ + struct irq_data *data = irq_get_irq_data(virq); + struct irq_domain_chip_generic *dgc = d->gc; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + struct irq_chip *chip; + unsigned long flags; + int idx; + + if (!d->gc) + return -ENODEV; + + idx = hw_irq / dgc->irqs_per_chip; + if (idx >= dgc->num_chips) + return -EINVAL; + gc = dgc->gc[idx]; + + idx = hw_irq % dgc->irqs_per_chip; + + if (test_bit(idx, &gc->installed)) + return -EBUSY; + + ct = gc->chip_types; + chip = &ct->chip; + + /* We only init the cache for the first mapping of a generic chip */ + if (!gc->installed) { + raw_spin_lock_irqsave(&gc->lock, flags); + irq_gc_init_mask_cache(gc, dgc->gc_flags); + raw_spin_unlock_irqrestore(&gc->lock, flags); + } + + /* Mark the interrupt as installed */ + set_bit(idx, &gc->installed); + + if (dgc->gc_flags & IRQ_GC_INIT_NESTED_LOCK) + irq_set_lockdep_class(virq, &irq_nested_lock_class); + + if (chip->irq_calc_mask) + chip->irq_calc_mask(data); + else + data->mask = 1 << idx; + + irq_set_chip_and_handler(virq, chip, ct->handler); + irq_set_chip_data(virq, gc); + irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set); + return 0; +} + +struct irq_domain_ops irq_generic_chip_ops = { + .map = irq_map_generic_chip, + .xlate = irq_domain_xlate_onetwocell, +}; +EXPORT_SYMBOL_GPL(irq_generic_chip_ops); + /** * irq_setup_generic_chip - Setup a range of interrupts with a generic chip * @gc: Generic irq chip holding all data @@ -354,6 +499,24 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, } EXPORT_SYMBOL_GPL(irq_remove_generic_chip); +static struct irq_data *irq_gc_get_irq_data(struct irq_chip_generic *gc) +{ + unsigned int virq; + + if (!gc->domain) + return irq_get_irq_data(gc->irq_base); + + /* + * We don't know which of the irqs has been actually + * installed. Use the first one. + */ + if (!gc->installed) + return NULL; + + virq = irq_find_mapping(gc->domain, gc->irq_base + __ffs(gc->installed)); + return virq ? irq_get_irq_data(virq) : NULL; +} + #ifdef CONFIG_PM static int irq_gc_suspend(void) { @@ -362,8 +525,12 @@ static int irq_gc_suspend(void) list_for_each_entry(gc, &gc_list, list) { struct irq_chip_type *ct = gc->chip_types; - if (ct->chip.irq_suspend) - ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base)); + if (ct->chip.irq_suspend) { + struct irq_data *data = irq_gc_get_irq_data(gc); + + if (data) + ct->chip.irq_suspend(data); + } } return 0; } @@ -375,8 +542,12 @@ static void irq_gc_resume(void) list_for_each_entry(gc, &gc_list, list) { struct irq_chip_type *ct = gc->chip_types; - if (ct->chip.irq_resume) - ct->chip.irq_resume(irq_get_irq_data(gc->irq_base)); + if (ct->chip.irq_resume) { + struct irq_data *data = irq_gc_get_irq_data(gc); + + if (data) + ct->chip.irq_resume(data); + } } } #else @@ -391,8 +562,12 @@ static void irq_gc_shutdown(void) list_for_each_entry(gc, &gc_list, list) { struct irq_chip_type *ct = gc->chip_types; - if (ct->chip.irq_pm_shutdown) - ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base)); + if (ct->chip.irq_pm_shutdown) { + struct irq_data *data = irq_gc_get_irq_data(gc); + + if (data) + ct->chip.irq_pm_shutdown(data); + } } } -- cgit v1.2.3 From e8bd834f73714378ef110a64287db1b77033c8da Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 29 May 2013 03:10:52 +0100 Subject: genirq: irqchip: Add mask to block out invalid irqs Some controllers have irqs that aren't wired up and must never be used. For the generic chip attached to an irq_domain this provides a mask that can be used to block out particular irqs so that they never get mapped. Signed-off-by: Grant Likely Link: http://lkml.kernel.org/r/1369793454-19197-2-git-send-email-grant.likely@linaro.org Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 8743d62fded7..95575d8d5392 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -359,6 +359,9 @@ static int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, idx = hw_irq % dgc->irqs_per_chip; + if (test_bit(idx, &gc->unused)) + return -ENOTSUPP; + if (test_bit(idx, &gc->installed)) return -EBUSY; -- cgit v1.2.3 From 0bb4afb45dd1add73ca643a865daa38716aeff0c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 6 Jun 2013 14:23:30 +0100 Subject: irqdomain: Add a name field This patch adds a name field to the irq_domain structure to help mere mortals understand the mappings between irq domains and virqs. It also converts a number of places that have open-coded some kind of fudging an irqdomain name to use the new field. This means a more consistent display of names in irq domain log messages and debugfs output. Signed-off-by: Grant Likely --- kernel/irq/generic-chip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 95575d8d5392..ca98cc5d6308 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -305,6 +305,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, /* Calc pointer to the next generic chip */ tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); } + d->name = name; return 0; } EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips); -- cgit v1.2.3 From 1aa0dd94ca07df818cf14588c9031ab1d7fd84d3 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sat, 8 Jun 2013 12:03:59 +0100 Subject: irqdomain: Eliminate revmap type The NOMAP irq_domain type is only used by a handful of interrupt controllers and it unnecessarily complicates the code by adding special cases on how to look up mappings and different revmap functions are used for each type which need to validate the correct type is passed to it before performing the reverse map. Eliminating the revmap_type and making a single reverse mapping function simplifies the code. It also shouldn't be any slower than having separate revmap functions because the type of the revmap needed to be checked anyway. The linear and tree revmap types were already merged in a previous patch. This patch rolls the NOMAP or direct mapping behaviour into the same domain code making is possible for an irq domain to do any mapping type; linear, tree or direct; and that the mapping will be transparent to the interrupt controller driver. With this change, direct mappings will get stored in the linear or tree mapping for consistency. Reverse mapping from the hwirq to virq will go through the normal lookup process. However, any controller using a direct mapping can take advantage of knowing that hwirq==virq for any mapped interrupts skip doing a revmap lookup when handling IRQs. Signed-off-by: Grant Likely --- kernel/irq/generic-chip.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index ca98cc5d6308..4b011064e146 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -270,10 +270,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, if (d->gc) return -EBUSY; - if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR) - return -EINVAL; - - numchips = d->revmap_data.linear.size / irqs_per_chip; + numchips = d->revmap_size / irqs_per_chip; if (!numchips) return -EINVAL; -- cgit v1.2.3 From 37074c5a1b9979d05b9effc7634385fc0fa7ccc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Jun 2013 14:24:12 +0200 Subject: irq/generic-chip: fix a few kernel-doc entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- kernel/irq/generic-chip.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index c89295a8f668..b34e7267b817 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -48,7 +48,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d) } /** - * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register + * irq_gc_mask_set_bit - Mask irq via setting bit in mask register * @d: irq_data * * Chip has a single mask register. Values of this register are cached @@ -66,7 +66,7 @@ void irq_gc_mask_set_bit(struct irq_data *d) } /** - * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register + * irq_gc_mask_clr_bit - Mask chip via clearing bit in mask register * @d: irq_data * * Chip has a single mask register. Values of this register are cached @@ -130,7 +130,7 @@ void irq_gc_ack_clr_bit(struct irq_data *d) } /** - * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt + * irq_gc_mask_disable_reg_and_ack - Mask and ack pending interrupt * @d: irq_data */ void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) -- cgit v1.2.3 From 6fff8314046276331314ae32cea34c6d11c440d2 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 18 Jun 2013 15:08:33 +0100 Subject: genirq: Irqchip: document gcflags arg of irq_alloc_domain_generic_chips Commit 088f40b7b027dad6519712ff224a5798dd62a204 ("genirq: Generic chip: Add linear irq domain support") missed kerneldoc for the gcflags argument of irq_alloc_domain_generic_chips(). Add it now. Signed-off-by: James Hogan Acked-by: Grant Likely Link: http://lkml.kernel.org/r/1371564513-4327-1-git-send-email-james.hogan@imgtec.com Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 95575d8d5392..a746a8f54dae 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -254,6 +254,7 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags) * @handler: Default flow handler associated with these chips * @clr: IRQ_* bits to clear in the mapping function * @set: IRQ_* bits to set in the mapping function + * @gcflags: Generic chip specific setup flags */ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, int num_ct, const char *name, -- cgit v1.2.3 From d55f0cc4c9a70e3105f1e813ab5f221a65ac2ec3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 28 Jun 2013 00:23:09 -0300 Subject: genirq: generic-chip: Export some irq_gc_ functions When building imx_v6_v7_defconfig with imx-drm drivers selected as modules, we get the following build errors: ERROR: "irq_gc_mask_clr_bit" [drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.ko] undefined! ERROR: "irq_gc_mask_set_bit" [drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.ko] undefined! ERROR: "irq_gc_ack_set_bit" [drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.ko] undefined! Export the required functions to avoid this problem. Signed-off-by: Fabio Estevam Cc: shawn.guo@linaro.org Cc: kernel@pengutronix.de Link: http://lkml.kernel.org/r/1372389789-7048-1-git-send-email-festevam@gmail.com Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index a746a8f54dae..76ea748324f5 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -62,6 +62,7 @@ void irq_gc_mask_set_bit(struct irq_data *d) irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); irq_gc_unlock(gc); } +EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit); /** * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register @@ -81,6 +82,7 @@ void irq_gc_mask_clr_bit(struct irq_data *d) irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); irq_gc_unlock(gc); } +EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit); /** * irq_gc_unmask_enable_reg - Unmask chip via enable register @@ -115,6 +117,7 @@ void irq_gc_ack_set_bit(struct irq_data *d) irq_reg_writel(mask, gc->reg_base + ct->regs.ack); irq_gc_unlock(gc); } +EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit); /** * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit -- cgit v1.2.3 From ccc414f83914178c7ab04ac4d4f0331fe4c37231 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 28 Jun 2013 11:45:15 +0200 Subject: genirq: Add the generic chip to the genirq docbook Signed-off-by: Thomas Gleixner Cc: Randy Dunlap --- kernel/irq/generic-chip.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 76ea748324f5..1c39eccc1eaf 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -45,7 +45,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d) } /** - * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register + * irq_gc_mask_set_bit - Mask chip via setting bit in mask register * @d: irq_data * * Chip has a single mask register. Values of this register are cached @@ -65,7 +65,7 @@ void irq_gc_mask_set_bit(struct irq_data *d) EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit); /** - * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register + * irq_gc_mask_clr_bit - Mask chip via clearing bit in mask register * @d: irq_data * * Chip has a single mask register. Values of this register are cached @@ -167,7 +167,8 @@ void irq_gc_eoi(struct irq_data *d) /** * irq_gc_set_wake - Set/clr wake bit for an interrupt - * @d: irq_data + * @d: irq_data + * @on: Indicates whether the wake bit should be set or cleared * * For chips where the wake from suspend functionality is not * configured in a separate register and the wakeup active state is @@ -339,7 +340,7 @@ EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip); */ static struct lock_class_key irq_nested_lock_class; -/** +/* * irq_map_generic_chip - Map a generic chip for an irq domain */ static int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, @@ -454,7 +455,7 @@ EXPORT_SYMBOL_GPL(irq_setup_generic_chip); /** * irq_setup_alt_chip - Switch to alternative chip * @d: irq_data for this interrupt - * @type Flow type to be initialized + * @type: Flow type to be initialized * * Only to be called from chip->irq_set_type() callbacks. */ -- cgit v1.2.3 From 002fca5df168922103a2bb52748f9984e6de80b2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 5 Jul 2013 17:13:12 +0800 Subject: genirq: generic chip: Use DIV_ROUND_UP to calculate numchips The number of interrupts in a domain may be not divisible by the number of interrupts each chip handles. Integer division may truncate the result, thus use DIV_ROUND_UP to count numchips. Seems all users of irq_alloc_domain_generic_chips() in current code do not have this issue. I just found the issue while reading the code. Signed-off-by: Axel Lin Cc: Grant Likely Cc: Tony Lindgren Cc: Arnd Bergmann Link: http://lkml.kernel.org/r/1373015592.18252.2.camel@phoenix Signed-off-by: Thomas Gleixner --- kernel/irq/generic-chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel/irq/generic-chip.c') diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 1c39eccc1eaf..2f274f30b7e2 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -278,7 +278,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR) return -EINVAL; - numchips = d->revmap_data.linear.size / irqs_per_chip; + numchips = DIV_ROUND_UP(d->revmap_data.linear.size, irqs_per_chip); if (!numchips) return -EINVAL; -- cgit v1.2.3