* [PATCH 1/2] gic: Add functions to save and restore gic state
@ 2010-10-01 2:48 Colin Cross
2010-10-01 2:48 ` [PATCH 2/2] gic: Export irq chip functions Colin Cross
2010-10-05 14:04 ` [PATCH 1/2] gic: Add functions to save and restore gic state Linus Walleij
0 siblings, 2 replies; 5+ messages in thread
From: Colin Cross @ 2010-10-01 2:48 UTC (permalink / raw)
To: linux-arm-kernel
on systems with idle states which power-gate the logic including
the gic, such as tegra, the gic distributor needs to be shut down
and restored on entry and exit from the architecture idle code
Change-Id: I17603f5ac70d65c05587d0647cce3ba87675e117
Original-author: Gary King <gking@nvidia.com>
Signed-off-by: Gary King <gking@nvidia.com>
Signed-off-by: Colin Cross <ccross@android.com>
---
arch/arm/common/gic.c | 123 ++++++++++++++++++++++++++++++++--
arch/arm/include/asm/hardware/gic.h | 4 +
2 files changed, 119 insertions(+), 8 deletions(-)
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 7dfa9a8..cfbe8b1 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -39,6 +39,13 @@ struct gic_chip_data {
unsigned int irq_offset;
void __iomem *dist_base;
void __iomem *cpu_base;
+#ifdef CONFIG_PM
+ u32 saved_enable[DIV_ROUND_UP(1020, 32)];
+ u32 saved_conf[DIV_ROUND_UP(1020, 16)];
+ u32 saved_pri[DIV_ROUND_UP(1020, 4)];
+ u32 saved_target[DIV_ROUND_UP(1020, 4)];
+#endif
+ unsigned int max_irq;
};
#ifndef MAX_GIC_NR
@@ -221,21 +228,15 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
set_irq_chained_handler(irq, gic_handle_cascade_irq);
}
-void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
- unsigned int irq_start)
+static unsigned int _gic_dist_init(unsigned int gic_nr)
{
unsigned int max_irq, i;
+ void __iomem *base = gic_data[gic_nr].dist_base;
u32 cpumask = 1 << smp_processor_id();
- if (gic_nr >= MAX_GIC_NR)
- BUG();
-
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
- gic_data[gic_nr].dist_base = base;
- gic_data[gic_nr].irq_offset = (irq_start - 1) & ~31;
-
writel(0, base + GIC_DIST_CTRL);
/*
@@ -276,6 +277,96 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
for (i = 0; i < max_irq; i += 32)
writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+ return max_irq;
+}
+
+static void _gic_dist_exit(unsigned int gic_nr)
+{
+ writel(0, gic_data[gic_nr].dist_base + GIC_DIST_CTRL);
+}
+
+#ifdef CONFIG_PM
+void gic_dist_save(unsigned int gic_nr)
+{
+ unsigned int max_irq = gic_data[gic_nr].max_irq;
+ void __iomem *dist_base = gic_data[gic_nr].dist_base;
+ int i;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ _gic_dist_exit(gic_nr);
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 16); i++)
+ gic_data[gic_nr].saved_conf[i] =
+ readl(dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
+ gic_data[gic_nr].saved_pri[i] =
+ readl(dist_base + GIC_DIST_PRI + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
+ gic_data[gic_nr].saved_target[i] =
+ readl(dist_base + GIC_DIST_TARGET + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 32); i++)
+ gic_data[gic_nr].saved_enable[i] =
+ readl(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+}
+
+void gic_dist_restore(unsigned int gic_nr)
+{
+ unsigned int max_irq;
+ unsigned int i;
+ void __iomem *dist_base;
+ void __iomem *cpu_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ _gic_dist_init(gic_nr);
+
+ max_irq = gic_data[gic_nr].max_irq;
+ dist_base = gic_data[gic_nr].dist_base;
+ cpu_base = gic_data[gic_nr].cpu_base;
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 16); i++)
+ writel(gic_data[gic_nr].saved_conf[i],
+ dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
+ writel(gic_data[gic_nr].saved_pri[i],
+ dist_base + GIC_DIST_PRI + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
+ writel(gic_data[gic_nr].saved_target[i],
+ dist_base + GIC_DIST_TARGET + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(max_irq, 32); i++)
+ writel(gic_data[gic_nr].saved_enable[i],
+ dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ writel(1, dist_base + GIC_DIST_CTRL);
+ writel(0xf0, cpu_base + GIC_CPU_PRIMASK);
+ writel(1, cpu_base + GIC_CPU_CTRL);
+}
+#endif
+
+void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
+ unsigned int irq_start)
+{
+ unsigned int max_irq;
+ unsigned int i;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_data[gic_nr].dist_base = base;
+ gic_data[gic_nr].irq_offset = (irq_start - 1) & ~31;
+
+ max_irq = _gic_dist_init(gic_nr);
+ gic_data[gic_nr].max_irq = max_irq;
+
/*
* Setup the Linux IRQ subsystem.
*/
@@ -289,6 +380,14 @@ void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
writel(1, base + GIC_DIST_CTRL);
}
+void gic_dist_exit(unsigned int gic_nr)
+{
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ _gic_dist_exit(gic_nr);
+}
+
void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
{
if (gic_nr >= MAX_GIC_NR)
@@ -300,6 +399,14 @@ void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
writel(1, base + GIC_CPU_CTRL);
}
+void gic_cpu_exit(unsigned int gic_nr)
+{
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ writel(0, gic_data[gic_nr].cpu_base + GIC_CPU_CTRL);
+}
+
#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 7f34333..0a198b0 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -34,7 +34,11 @@
#ifndef __ASSEMBLY__
void gic_dist_init(unsigned int gic_nr, void __iomem *base, unsigned int irq_start);
+void gic_dist_save(unsigned int gic_nr);
+void gic_dist_restore(unsigned int gic_nr);
+void gic_dist_exit(unsigned int gic_nr);
void gic_cpu_init(unsigned int gic_nr, void __iomem *base);
+void gic_cpu_exit(unsigned int gic_nr);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/2] gic: Export irq chip functions
2010-10-01 2:48 [PATCH 1/2] gic: Add functions to save and restore gic state Colin Cross
@ 2010-10-01 2:48 ` Colin Cross
2010-10-02 18:03 ` Linus Walleij
2010-10-05 14:04 ` [PATCH 1/2] gic: Add functions to save and restore gic state Linus Walleij
1 sibling, 1 reply; 5+ messages in thread
From: Colin Cross @ 2010-10-01 2:48 UTC (permalink / raw)
To: linux-arm-kernel
Some systems combine the GIC with an external interrupt controller.
On these systems it may be necessary to update both the GIC registers
and the external controller's registers to control IRQ behavior.
Export the irq chip functions so that these systems can define a
custom irq chip that calls into the GIC handlers.
Change-Id: I17fc4440fa2c91cc63004abf69c8e872b55c83c6
Signed-off-by: Colin Cross <ccross@android.com>
---
arch/arm/common/gic.c | 10 +++++-----
arch/arm/include/asm/hardware/gic.h | 8 ++++++++
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index cfbe8b1..48a70af 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -87,7 +87,7 @@ static inline unsigned int gic_irq(unsigned int irq)
* our "acknowledge" routine disable the interrupt, then mark it as
* complete.
*/
-static void gic_ack_irq(unsigned int irq)
+void gic_ack_irq(unsigned int irq)
{
u32 mask = 1 << (irq % 32);
@@ -97,7 +97,7 @@ static void gic_ack_irq(unsigned int irq)
spin_unlock(&irq_controller_lock);
}
-static void gic_mask_irq(unsigned int irq)
+void gic_mask_irq(unsigned int irq)
{
u32 mask = 1 << (irq % 32);
@@ -106,7 +106,7 @@ static void gic_mask_irq(unsigned int irq)
spin_unlock(&irq_controller_lock);
}
-static void gic_unmask_irq(unsigned int irq)
+void gic_unmask_irq(unsigned int irq)
{
u32 mask = 1 << (irq % 32);
@@ -115,7 +115,7 @@ static void gic_unmask_irq(unsigned int irq)
spin_unlock(&irq_controller_lock);
}
-static int gic_set_type(unsigned int irq, unsigned int type)
+int gic_set_type(unsigned int irq, unsigned int type)
{
void __iomem *base = gic_dist_base(irq);
unsigned int gicirq = gic_irq(irq);
@@ -161,7 +161,7 @@ static int gic_set_type(unsigned int irq, unsigned int type)
}
#ifdef CONFIG_SMP
-static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
+int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
{
void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3);
unsigned int shift = (irq % 4) * 8;
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 0a198b0..5fd0ff2 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -41,6 +41,14 @@ void gic_cpu_init(unsigned int gic_nr, void __iomem *base);
void gic_cpu_exit(unsigned int gic_nr);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
+
+void gic_ack_irq(unsigned int irq);
+void gic_mask_irq(unsigned int irq);
+void gic_unmask_irq(unsigned int irq);
+int gic_set_type(unsigned int irq, unsigned int type);
+#ifdef CONFIG_SMP
+int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val);
+#endif
#endif
#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 1/2] gic: Add functions to save and restore gic state
2010-10-01 2:48 [PATCH 1/2] gic: Add functions to save and restore gic state Colin Cross
2010-10-01 2:48 ` [PATCH 2/2] gic: Export irq chip functions Colin Cross
@ 2010-10-05 14:04 ` Linus Walleij
1 sibling, 0 replies; 5+ messages in thread
From: Linus Walleij @ 2010-10-05 14:04 UTC (permalink / raw)
To: linux-arm-kernel
Colin Cross wrote:
> on systems with idle states which power-gate the logic including
> the gic, such as tegra, the gic distributor needs to be shut down
> and restored on entry and exit from the architecture idle code
Nice!
> +
> +#ifdef CONFIG_PM
> +void gic_dist_save(unsigned int gic_nr)
> +{
> + unsigned int max_irq = gic_data[gic_nr].max_irq;
> + void __iomem *dist_base = gic_data[gic_nr].dist_base;
> + int i;
> +
> + if (gic_nr >= MAX_GIC_NR)
> + BUG();
> +
> + _gic_dist_exit(gic_nr);
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 16); i++)
> + gic_data[gic_nr].saved_conf[i] =
> + readl(dist_base + GIC_DIST_CONFIG + i * 4);
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
> + gic_data[gic_nr].saved_pri[i] =
> + readl(dist_base + GIC_DIST_PRI + i * 4);
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
> + gic_data[gic_nr].saved_target[i] =
> + readl(dist_base + GIC_DIST_TARGET + i * 4);
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 32); i++)
> + gic_data[gic_nr].saved_enable[i] =
> + readl(dist_base + GIC_DIST_ENABLE_SET + i * 4);
> +}
> +
> +void gic_dist_restore(unsigned int gic_nr)
> +{
> + unsigned int max_irq;
> + unsigned int i;
> + void __iomem *dist_base;
> + void __iomem *cpu_base;
> +
> + if (gic_nr >= MAX_GIC_NR)
> + BUG();
> +
> + _gic_dist_init(gic_nr);
> +
> + max_irq = gic_data[gic_nr].max_irq;
> + dist_base = gic_data[gic_nr].dist_base;
> + cpu_base = gic_data[gic_nr].cpu_base;
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 16); i++)
> + writel(gic_data[gic_nr].saved_conf[i],
> + dist_base + GIC_DIST_CONFIG + i * 4);
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
> + writel(gic_data[gic_nr].saved_pri[i],
> + dist_base + GIC_DIST_PRI + i * 4);
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 4); i++)
> + writel(gic_data[gic_nr].saved_target[i],
> + dist_base + GIC_DIST_TARGET + i * 4);
> +
> + for (i = 0; i < DIV_ROUND_UP(max_irq, 32); i++)
> + writel(gic_data[gic_nr].saved_enable[i],
> + dist_base + GIC_DIST_ENABLE_SET + i * 4);
> +
> + writel(1, dist_base + GIC_DIST_CTRL);
> + writel(0xf0, cpu_base + GIC_CPU_PRIMASK);
> + writel(1, cpu_base + GIC_CPU_CTRL);
> +}
> +#endif
For gic_dist_save()/gic_dist_restore() can you write some
comment to each function about the implicit semantics for
calling them?
If I *guess* correctly gic_dist_save() must be called in
something like a platform idle function after disabling all
IRQs but before sleeping, conversely gic_dist_restort()
must be called after sleeping but before re-enabling the
IRQs.
Apart from that it looks good to me so with this
simple comment-fix it's:
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-10-05 14:04 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-01 2:48 [PATCH 1/2] gic: Add functions to save and restore gic state Colin Cross
2010-10-01 2:48 ` [PATCH 2/2] gic: Export irq chip functions Colin Cross
2010-10-02 18:03 ` Linus Walleij
2010-10-02 20:21 ` Colin Cross
2010-10-05 14:04 ` [PATCH 1/2] gic: Add functions to save and restore gic state Linus Walleij
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).