aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2015-03-24 13:58:51 -0400
committerWill Deacon <will.deacon@arm.com>2015-03-26 11:13:09 -0400
commitd8f4f161e31f3ee9768467344e6cc31a0b9d9249 (patch)
tree428ed2902d784abc052f8160d1f6b3a21849b248
parent33757ded074918eb49243968a82e7c9ec2d71720 (diff)
ACPI: move arm64 GSI IRQ model to generic GSI IRQ layer
The code deployed to implement GSI linux IRQ numbers mapping on arm64 turns out to be generic enough so that it can be moved to ACPI core code along with its respective config option ACPI_GENERIC_GSI selectable on architectures that can reuse the same code. Current ACPI IRQ mapping code is not integrated in the kernel IRQ domain infrastructure, in particular there is no way to look-up the IRQ domain associated with a particular interrupt controller, so this first version of GSI generic code carries out the GSI<->IRQ mapping relying on the IRQ default domain which is supposed to be always set on a specific architecture in case the domain structure passed to irq_create/find_mapping() functions is missing. This patch moves the arm64 acpi functions that implement the gsi mappings: acpi_gsi_to_irq() acpi_register_gsi() acpi_unregister_gsi() to ACPI core code. Since the generic GSI<->domain mapping is based on IRQ domains, it can be extended as soon as a way to map an interrupt controller to an IRQ domain is implemented for ACPI in the IRQ domain layer. x86 and ia64 code for GSI mappings cannot rely on the generic GSI layer at present for legacy reasons, so they do not select the ACPI_GENERIC_GSI config options and keep relying on their arch specific GSI mapping layer. Cc: Jiang Liu <jiang.liu@linux.intel.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Acked-by: Hanjun Guo <hanjun.guo@linaro.org> Acked-by: Will Deacon <will.deacon@arm.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/kernel/acpi.c73
-rw-r--r--drivers/acpi/Kconfig3
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/gsi.c105
-rw-r--r--drivers/irqchip/irq-gic.c2
6 files changed, 112 insertions, 73 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index e5aa081b4845..0659db374731 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,5 +1,6 @@
1config ARM64 1config ARM64
2 def_bool y 2 def_bool y
3 select ACPI_GENERIC_GSI if ACPI
3 select ACPI_REDUCED_HARDWARE_ONLY if ACPI 4 select ACPI_REDUCED_HARDWARE_ONLY if ACPI
4 select ARCH_BINFMT_ELF_RANDOMIZE_PIE 5 select ARCH_BINFMT_ELF_RANDOMIZE_PIE
5 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 6 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index fe9d8f0df4a3..a70f7141c0f6 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -76,12 +76,6 @@ static int __init dt_scan_depth1_nodes(unsigned long node,
76} 76}
77 77
78/* 78/*
79 * Since we're on ARM, the default interrupt routing model
80 * clearly has to be GIC.
81 */
82enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC;
83
84/*
85 * __acpi_map_table() will be called before page_init(), so early_ioremap() 79 * __acpi_map_table() will be called before page_init(), so early_ioremap()
86 * or early_memremap() should be called here to for ACPI table mapping. 80 * or early_memremap() should be called here to for ACPI table mapping.
87 */ 81 */
@@ -224,73 +218,6 @@ void __init acpi_init_cpus(void)
224 pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); 218 pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus);
225} 219}
226 220
227int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
228{
229 *irq = irq_find_mapping(NULL, gsi);
230
231 return 0;
232}
233EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
234
235/*
236 * success: return IRQ number (>0)
237 * failure: return =< 0
238 */
239int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
240{
241 unsigned int irq;
242 unsigned int irq_type;
243
244 /*
245 * ACPI have no bindings to indicate SPI or PPI, so we
246 * use different mappings from DT in ACPI.
247 *
248 * For FDT
249 * PPI interrupt: in the range [0, 15];
250 * SPI interrupt: in the range [0, 987];
251 *
252 * For ACPI, GSI should be unique so using
253 * the hwirq directly for the mapping:
254 * PPI interrupt: in the range [16, 31];
255 * SPI interrupt: in the range [32, 1019];
256 */
257
258 if (trigger == ACPI_EDGE_SENSITIVE &&
259 polarity == ACPI_ACTIVE_LOW)
260 irq_type = IRQ_TYPE_EDGE_FALLING;
261 else if (trigger == ACPI_EDGE_SENSITIVE &&
262 polarity == ACPI_ACTIVE_HIGH)
263 irq_type = IRQ_TYPE_EDGE_RISING;
264 else if (trigger == ACPI_LEVEL_SENSITIVE &&
265 polarity == ACPI_ACTIVE_LOW)
266 irq_type = IRQ_TYPE_LEVEL_LOW;
267 else if (trigger == ACPI_LEVEL_SENSITIVE &&
268 polarity == ACPI_ACTIVE_HIGH)
269 irq_type = IRQ_TYPE_LEVEL_HIGH;
270 else
271 irq_type = IRQ_TYPE_NONE;
272
273 /*
274 * Since only one GIC is supported in ACPI 5.0, we can
275 * create mapping refer to the default domain
276 */
277 irq = irq_create_mapping(NULL, gsi);
278 if (!irq)
279 return irq;
280
281 /* Set irq type if specified and different than the current one */
282 if (irq_type != IRQ_TYPE_NONE &&
283 irq_type != irq_get_trigger_type(irq))
284 irq_set_irq_type(irq, irq_type);
285 return irq;
286}
287EXPORT_SYMBOL_GPL(acpi_register_gsi);
288
289void acpi_unregister_gsi(u32 gsi)
290{
291}
292EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
293
294static int __init acpi_parse_fadt(struct acpi_table_header *table) 221static int __init acpi_parse_fadt(struct acpi_table_header *table)
295{ 222{
296 struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; 223 struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index a8f531e2b97c..ab2cbb51c6aa 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -48,6 +48,9 @@ config ACPI_LEGACY_TABLES_LOOKUP
48config ARCH_MIGHT_HAVE_ACPI_PDC 48config ARCH_MIGHT_HAVE_ACPI_PDC
49 bool 49 bool
50 50
51config ACPI_GENERIC_GSI
52 bool
53
51config ACPI_SYSTEM_POWER_STATES_SUPPORT 54config ACPI_SYSTEM_POWER_STATES_SUPPORT
52 bool 55 bool
53 56
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index db153c6a75d7..8a063e276530 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -56,6 +56,7 @@ ifdef CONFIG_ACPI_VIDEO
56acpi-y += video_detect.o 56acpi-y += video_detect.o
57endif 57endif
58acpi-y += acpi_lpat.o 58acpi-y += acpi_lpat.o
59acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
59 60
60# These are (potentially) separate modules 61# These are (potentially) separate modules
61 62
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c
new file mode 100644
index 000000000000..38208f2d0e69
--- /dev/null
+++ b/drivers/acpi/gsi.c
@@ -0,0 +1,105 @@
1/*
2 * ACPI GSI IRQ layer
3 *
4 * Copyright (C) 2015 ARM Ltd.
5 * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/acpi.h>
12#include <linux/irq.h>
13#include <linux/irqdomain.h>
14
15enum acpi_irq_model_id acpi_irq_model;
16
17static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity)
18{
19 switch (polarity) {
20 case ACPI_ACTIVE_LOW:
21 return trigger == ACPI_EDGE_SENSITIVE ?
22 IRQ_TYPE_EDGE_FALLING :
23 IRQ_TYPE_LEVEL_LOW;
24 case ACPI_ACTIVE_HIGH:
25 return trigger == ACPI_EDGE_SENSITIVE ?
26 IRQ_TYPE_EDGE_RISING :
27 IRQ_TYPE_LEVEL_HIGH;
28 case ACPI_ACTIVE_BOTH:
29 if (trigger == ACPI_EDGE_SENSITIVE)
30 return IRQ_TYPE_EDGE_BOTH;
31 default:
32 return IRQ_TYPE_NONE;
33 }
34}
35
36/**
37 * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI
38 * @gsi: GSI IRQ number to map
39 * @irq: pointer where linux IRQ number is stored
40 *
41 * irq location updated with irq value [>0 on success, 0 on failure]
42 *
43 * Returns: linux IRQ number on success (>0)
44 * -EINVAL on failure
45 */
46int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
47{
48 /*
49 * Only default domain is supported at present, always find
50 * the mapping corresponding to default domain by passing NULL
51 * as irq_domain parameter
52 */
53 *irq = irq_find_mapping(NULL, gsi);
54 /*
55 * *irq == 0 means no mapping, that should
56 * be reported as a failure
57 */
58 return (*irq > 0) ? *irq : -EINVAL;
59}
60EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
61
62/**
63 * acpi_register_gsi() - Map a GSI to a linux IRQ number
64 * @dev: device for which IRQ has to be mapped
65 * @gsi: GSI IRQ number
66 * @trigger: trigger type of the GSI number to be mapped
67 * @polarity: polarity of the GSI to be mapped
68 *
69 * Returns: a valid linux IRQ number on success
70 * -EINVAL on failure
71 */
72int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
73 int polarity)
74{
75 unsigned int irq;
76 unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
77
78 /*
79 * There is no way at present to look-up the IRQ domain on ACPI,
80 * hence always create mapping referring to the default domain
81 * by passing NULL as irq_domain parameter
82 */
83 irq = irq_create_mapping(NULL, gsi);
84 if (!irq)
85 return -EINVAL;
86
87 /* Set irq type if specified and different than the current one */
88 if (irq_type != IRQ_TYPE_NONE &&
89 irq_type != irq_get_trigger_type(irq))
90 irq_set_irq_type(irq, irq_type);
91 return irq;
92}
93EXPORT_SYMBOL_GPL(acpi_register_gsi);
94
95/**
96 * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping
97 * @gsi: GSI IRQ number
98 */
99void acpi_unregister_gsi(u32 gsi)
100{
101 int irq = irq_find_mapping(NULL, gsi);
102
103 irq_dispose_mapping(irq);
104}
105EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d15a36a93c52..f1efb53faebc 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1189,6 +1189,8 @@ gic_v2_acpi_init(struct acpi_table_header *table)
1189 */ 1189 */
1190 gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); 1190 gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL);
1191 irq_set_default_host(gic_data[0].domain); 1191 irq_set_default_host(gic_data[0].domain);
1192
1193 acpi_irq_model = ACPI_IRQ_MODEL_GIC;
1192 return 0; 1194 return 0;
1193} 1195}
1194#endif 1196#endif