GIC Changes
v2 cover GIC Changes
From: Abhijeet Dharmapurikar <[email protected]>
Few fixes and improvements to arch/arm/common/gic.c file.
Changes in v2
Russell indicated that there could be an on chip inteverter on some interrupt lines and hence there is no way to enforce correct edge rising/falling or level high/low configuration. The change to introduce set_type callback is dropped.
Also the change to configure SPI's and PPI's as level/edge depending on the flow_type argument passed in gic_dist_init is dropped.
As per Catalin's suggestion all the interrupts reported by gic are disabled. This way we initialize and disable all the unused interrupts. The iterator,i in the gic_dist_init is still prevented from exceeding NR_IRQS.
As per Ben Dook's suggestion 'gic:...' is changed to 'GIC:...' in title.
Thanks for all your inputs. Please let me know if further changes are required.
Abhijeet Dharmapurikar (4):
GIC: Disable unused interrupts
GIC: Prevent gic from crossing NR_IRQS
GIC: Add callback for mask_ack
GIC: Dont disable INT in ack callback
arch/arm/common/gic.c | 56 +++++++++++++++++++++++++++++++++--------------- 1 files changed, 38 insertions(+), 18 deletions(-)
PATCH v2 1/4 GIC: Disable unused interrupts
From: Abhijeet Dharmapurikar <[email protected]>
Disable all interrupts of a gic in distributor initialization function. This way interrupts beyond NR_IRQS stay disabled.
--- arch/arm/common/gic.c | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-)
arch/arm/common/gic.c +8 -4
@@ -175,6 +175,11 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)set_irq_chained_handler (irq, gic_handle_cascade_irq); } +/* +* In case of multiple cascaded GICs, order calls to gic_dist_init with +* ascending irq_start +*/ +void __init gic_dist_init (unsigned int gic_nr,void __iomem *base,unsigned int irq_start) {
@@ -200,11 +205,10 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,/* * The GIC only supports up to 1020 interrupt sources. -* Limit this to either the architected maximum, or the -* platform maximum. +* Limit this to either the architected maximum */ -if (max_irq >max (1020 ,NR_IRQS )) - max_irq =max (1020 ,NR_IRQS ); +if (max_irq >1020 ) + max_irq =1020 ;/* * Set all global interrupts to be level triggered, active low.
Signature · 1 line
1.5.6.3
PATCH v2 2/4 GIC: Prevent gic from crossing NR_IRQS
In reply to [email protected]From: Abhijeet Dharmapurikar <[email protected]>
Prevent gic code from initializing interrupts beyon NR_IRQS.
--- arch/arm/common/gic.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
arch/arm/common/gic.c +2 -1
@@ -237,7 +237,8 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,/* * Setup the Linux IRQ subsystem. */ -for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) { +for (i = irq_start; + i <NR_IRQS && i < gic_data[gic_nr].irq_offset + max_irq; i++) {set_irq_chip (i, &gic_chip);set_irq_chip_data (i, &gic_data[gic_nr]);set_irq_handler (i, handle_level_irq);
Signature · 1 line
1.5.6.3
PATCH v2 3/4 GIC: Add callback for mask_ack
In reply to [email protected]From: Abhijeet Dharmapurikar <[email protected]>
Add gic_mask_ack for faster processing of interrupts.
--- arch/arm/common/gic.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-)
arch/arm/common/gic.c +10 -0
@@ -108,6 +108,15 @@ static void gic_unmask_irq(unsigned int irq)spin_unlock (&irq_controller_lock); } +static void gic_mask_ack_irq (unsigned int irq) +{ +u32 mask =1 << (irq %32 ); +spin_lock (&irq_controller_lock); +writel (mask,gic_dist_base (irq) +GIC_DIST_ENABLE_CLEAR + (gic_irq (irq) /32 ) *4 ); +writel (gic_irq (irq),gic_cpu_base (irq) +GIC_CPU_EOI ); +spin_unlock (&irq_controller_lock); +} +#ifdef CONFIG_SMP static int gic_set_cpu (unsigned int irq,const struct cpumask *mask_val) {
@@ -160,6 +169,7 @@ static struct irq_chip gic_chip = { .name = "GIC", .ack = gic_ack_irq, .mask = gic_mask_irq, + .mask_ack = gic_mask_ack_irq, .unmask = gic_unmask_irq, #ifdef CONFIG_SMP .set_affinity = gic_set_cpu,
Signature · 1 line
1.5.6.3
PATCH v2 4/4 GIC: Dont disable INT in ack callback
In reply to [email protected]From: Abhijeet Dharmapurikar <[email protected]>
Unless gic_ack_irq is called from __do_IRQ, interrupt should not be disabled in the ack function. Disabling the interrupt causes handle_edge_irq to never enable it again.
--- arch/arm/common/gic.c | 31 ++++++++++++++++++------------- 1 files changed, 18 insertions(+), 13 deletions(-)
arch/arm/common/gic.c +18 -13
@@ -67,25 +67,30 @@ static inline unsigned int gic_irq(unsigned int irq)/* * Routines to acknowledge, disable and enable interrupts -* -* Linux assumes that when we're done with an interrupt we need to -* unmask it, in the same way we need to unmask an interrupt when -* we first enable it. -* -* The GIC has a separate notion of "end of interrupt" to re-enable -* an interrupt after handling, in order to support hardware -* prioritisation. -* -* We can make the GIC behave in the way that Linux expects by making -* our "acknowledge" routine disable the interrupt, then mark it as -* complete. */ static void gic_ack_irq (unsigned int irq) { -u32 mask =1 << (irq %32 );spin_lock (&irq_controller_lock); + +#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ +u32 mask =1 << (irq %32 ); + +/* +* Linux assumes that when we're done with an interrupt we need to +* unmask it, in the same way we need to unmask an interrupt when +* we first enable it. +* +* The GIC has a separate notion of "end of interrupt" to re-enable +* an interrupt after handling, in order to support hardware +* prioritisation. +* +* We can make the GIC behave in the way that Linux expects by making +* our "acknowledge" routine disable the interrupt, then mark it as +* complete. +*/ writel (mask,gic_dist_base (irq) +GIC_DIST_ENABLE_CLEAR + (gic_irq (irq) /32 ) *4 ); +#endif writel (gic_irq (irq),gic_cpu_base (irq) +GIC_CPU_EOI );spin_unlock (&irq_controller_lock); }
Signature · 1 line
1.5.6.3