diff mbox

[v2,1/5] irqchip: add support for Marvell Orion SoCs

Message ID alpine.LFD.2.02.1305031514230.2886@ionos (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Gleixner May 3, 2013, 2:09 p.m. UTC
On Fri, 3 May 2013, Sebastian Hesselbarth wrote:
> On 05/03/13 14:55, Russell King - ARM Linux wrote:
> > This is where it starts to get tricky, because I can't see how you'd
> > merge the irq_alloc_generic_chip() and irq_setup_generic_chip() with
> > this.  Maybe you don't need to do anything here and just do all that
> > in orion_of_init() instead?  But then you seem to need to know the
> > virq range before hand, and I can't see how that's known.  Maybe Thomas
> > can provide some enlightenment about how the gc irqchip stuff works
> > with the irq domain stuff...
> 
> Exactly, and that is what I am looking into right now. But hell, I am
> not an expert in linux irq yet. Moreover, I am not even sure if it is
> okay to rely on irqdomain or at least irq_data->hw_irq at all.

Here is a solution to that problem.

1) It adds a mask field to irq_data so we dont have to compute the
   mask over and over

2) For compability with existing users it populates the mask with 
   1 << (d->irq - gc->irq_base)

3) It gives you the option to disable that mask setup or let it
   generate from d->hwirq

I'm still looking into a way how to proper support the generic chip /
linear domain mapping in the setup path. Will send you a draft patch
to play with later.

Thanks,

	tglx

Comments

Thomas Gleixner May 3, 2013, 9:50 p.m. UTC | #1
The ongoing device tree support for ARM is creating new irq chip
drivers in drivers/irqchip/ in a frenzy. Quite some of them are
ripping out the generic irq chip implementation from arch/arm/* and
just creating the same mess of duplicated code again, which was
cleaned up with the generic irq chip implementation with a lot of
effort. Sigh!

I already prodded a few people in reviews to tackle that issue with no
outcome. Even more sigh!

Poor Sebastian triggered me into rant mode, but he ad hoc
volunteered to give it a try. YAY!

Though he asked for a bit of kickstart help. So I squeezed out a few
spare cycles and implemented the basics as far as I think that they
should work.

The following series contains the missing bits and pieces including a
somehow forgotten and now slightly modified series from Gerlando
adding support for irq chips which need separate mask caches for
different chip (control flow) types.

At the moment this supports only linear irq domains, but it could be
extended to other types as well if the need arises. Though the ARM
chips are pretty much all about linear domains AFAICT.

It also lacks support for removing an irq domain at the moment, but
that should be rather trivial to fix.

The last patch in the series is a blind conversion of the irq-sun4i
irq chip driver, completely untested and not even compiled. I just
added it for demonstration purposes. As Russell expected, there is a
lot of consolidation potential. The changelog of that patch is:

 1 file changed, 29 insertions(+), 71 deletions(-)

The preparing series has

 4 files changed, 294 insertions(+), 50 deletions(-)

So for removing 42 lines in a single driver the core grows 244 lines
including header changes and comments. Convert 6 drivers and we are
more than even because we get the benefit of sharing and therefor
exposing the same code to broader testing and utilization.

We have already 11 of those candidates in drivers/irqchips and new
ones are knocking on the door.

There might be even more consolidation potential, but I leave that to the
DT/irq domain experts.


WARNING: It's compile tested only. So if you find bugs you can keep
them and fix them yourself :)


Thanks,

	tglx
---
 drivers/irqchip/irq-sun4i.c |  100 ++++-----------
 include/linux/irq.h         |   45 ++++++-
 include/linux/irqdomain.h   |   12 +
 kernel/irq/generic-chip.c   |  281 +++++++++++++++++++++++++++++++++++++-------
 kernel/irq/irqdomain.c      |    6 
 5 files changed, 323 insertions(+), 121 deletions(-)
Uwe Kleine-König May 6, 2013, 9:48 a.m. UTC | #2
Hello,

On Fri, May 03, 2013 at 09:50:43PM -0000, Thomas Gleixner wrote:
> The ongoing device tree support for ARM is creating new irq chip
> drivers in drivers/irqchip/ in a frenzy. Quite some of them are
> ripping out the generic irq chip implementation from arch/arm/* and
> just creating the same mess of duplicated code again, which was
> cleaned up with the generic irq chip implementation with a lot of
> effort. Sigh!
> 
> I already prodded a few people in reviews to tackle that issue with no
> outcome. Even more sigh!
> 
> Poor Sebastian triggered me into rant mode, but he ad hoc
> volunteered to give it a try. YAY!
> 
> Though he asked for a bit of kickstart help. So I squeezed out a few
> spare cycles and implemented the basics as far as I think that they
> should work.
> 
> The following series contains the missing bits and pieces including a
> somehow forgotten and now slightly modified series from Gerlando
> adding support for irq chips which need separate mask caches for
> different chip (control flow) types.
> 
> At the moment this supports only linear irq domains, but it could be
> extended to other types as well if the need arises. Though the ARM
> chips are pretty much all about linear domains AFAICT.
Is there a tree/set of patches that have already fixed the issues
pointed out by Russell and Sebastian? I'd like to use it to get forward
with my nvic patch and want to avert double work and merging different
approaches.

Best regards
Uwe
Thomas Gleixner May 6, 2013, 2:30 p.m. UTC | #3
Changes vs. V1:

	- Fixed the generic chip pointer thinko (Sebastian Hesselbarth)

	- Proper support for mask cache

	- Read mask hardware only for the first map of an generic chip
          instance

	- sun4i prefix irq functions proper  

Thanks,

	tglx
Gerlando Falauto Oct. 1, 2013, 3:27 p.m. UTC | #4
Hi Thomas, Sebastian,

I see these changes made it to 3.11.
AFAICT though, 3.10.9 still has the original bug (the one that got me to 
write the patch for handling separate mask registers) and I am bit 
confused as to how to integrate that back into 3.10 (or any previous 
affected kernels, as they deserve a fix as well!).

The way I understand it, any mainstream patch would be based on this 
work, which is not available on previous kernels. And I guess 
backporting the whole thing would be overkill.
So I believe the only way to fix it on older kernels would be to write 
one (or more) minimal version-specific patch series.
But then I wonder: would that be acceptable material for linux-stable?

Please correct me if I'm totally wrong here. I'm willing to help & test 
but I need directions.

Thanks,
Gerlando

On 05/06/2013 04:30 PM, Thomas Gleixner wrote:
> Changes vs. V1:
>
> 	- Fixed the generic chip pointer thinko (Sebastian Hesselbarth)
>
> 	- Proper support for mask cache
>
> 	- Read mask hardware only for the first map of an generic chip
>            instance
>
> 	- sun4i prefix irq functions proper
>
> Thanks,
>
> 	tglx
>
>
diff mbox

Patch

Index: linux-2.6/include/linux/irq.h
===================================================================
--- linux-2.6.orig/include/linux/irq.h
+++ linux-2.6/include/linux/irq.h
@@ -119,6 +119,7 @@  struct irq_domain;
 
 /**
  * struct irq_data - per irq and irq chip data passed down to chip functions
+ * @mask:		precomputed bitmask for accessing the chip registers
  * @irq:		interrupt number
  * @hwirq:		hardware interrupt number, local to the interrupt domain
  * @node:		node index useful for balancing
@@ -138,6 +139,7 @@  struct irq_domain;
  * irq_data.
  */
 struct irq_data {
+	u32			mask;
 	unsigned int		irq;
 	unsigned long		hwirq;
 	unsigned int		node;
@@ -700,10 +702,14 @@  struct irq_chip_generic {
  * @IRQ_GC_INIT_NESTED_LOCK:	Set the lock class of the irqs to nested for
  *				irq chips which need to call irq_set_wake() on
  *				the parent irq. Usually GPIO implementations
+ * @IRQ_GC_NO_MASK:		Do not calculate irq_data->mask
+ * @IRQ_GC_MASK_FROM_HWIRQ:	Calculate irq_data->mask from the hwirq number
  */
 enum irq_gc_flags {
 	IRQ_GC_INIT_MASK_CACHE		= 1 << 0,
 	IRQ_GC_INIT_NESTED_LOCK		= 1 << 1,
+	IRQ_GC_NO_MASK			= 1 << 2,
+	IRQ_GC_MASK_FROM_HWIRQ		= 1 << 4,
 };
 
 /* Generic chip callback functions */
Index: linux-2.6/kernel/irq/generic-chip.c
===================================================================
--- linux-2.6.orig/kernel/irq/generic-chip.c
+++ linux-2.6/kernel/irq/generic-chip.c
@@ -39,7 +39,7 @@  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);
-	u32 mask = 1 << (d->irq - gc->irq_base);
+	u32 mask = d->mask;
 
 	irq_gc_lock(gc);
 	irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable);
@@ -57,7 +57,7 @@  void irq_gc_mask_disable_reg(struct irq_
 void irq_gc_mask_set_bit(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << (d->irq - gc->irq_base);
+	u32 mask = d->mask;
 
 	irq_gc_lock(gc);
 	gc->mask_cache |= mask;
@@ -75,7 +75,7 @@  void irq_gc_mask_set_bit(struct irq_data
 void irq_gc_mask_clr_bit(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << (d->irq - gc->irq_base);
+	u32 mask = d->mask;
 
 	irq_gc_lock(gc);
 	gc->mask_cache &= ~mask;
@@ -93,7 +93,7 @@  void irq_gc_mask_clr_bit(struct irq_data
 void irq_gc_unmask_enable_reg(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << (d->irq - gc->irq_base);
+	u32 mask = d->mask;
 
 	irq_gc_lock(gc);
 	irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable);
@@ -108,7 +108,7 @@  void irq_gc_unmask_enable_reg(struct irq
 void irq_gc_ack_set_bit(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << (d->irq - gc->irq_base);
+	u32 mask = d->mask;
 
 	irq_gc_lock(gc);
 	irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
@@ -122,7 +122,7 @@  void irq_gc_ack_set_bit(struct irq_data 
 void irq_gc_ack_clr_bit(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-	u32 mask = ~(1 << (d->irq - gc->irq_base));
+	u32 mask = ~d->mask;
 
 	irq_gc_lock(gc);
 	irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack);
@@ -136,7 +136,7 @@  void irq_gc_ack_clr_bit(struct irq_data 
 void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << (d->irq - gc->irq_base);
+	u32 mask = d->mask;
 
 	irq_gc_lock(gc);
 	irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask);
@@ -151,7 +151,7 @@  void irq_gc_mask_disable_reg_and_ack(str
 void irq_gc_eoi(struct irq_data *d)
 {
 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << (d->irq - gc->irq_base);
+	u32 mask = d->mask;
 
 	irq_gc_lock(gc);
 	irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi);
@@ -169,7 +169,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;
@@ -254,6 +254,15 @@  void irq_setup_generic_chip(struct irq_c
 		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);
+			u32 mask;
+
+			if (flags & IRQ_GC_MASK_FROM_HWIRQ)
+				d->mask = 1 << (d->hwirq % 32);
+			else
+				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);