In the ACPI 5.1 version of the spec, the struct for the GICC subtable
(struct acpi_madt_generic_interrupt) of the MADT is 76 bytes long; in
ACPI 6.0, the struct is 80 bytes long. But, there is only one definition
in ACPICA for this struct -- and that is the 6.0 version. Hence, when
BAD_MADT_ENTRY() compares the struct size to the length in the GICC
subtable, it fails if 5.1 structs are in use, and there are systems in
the wild that have them.
Note that this was found in linux-next and these patches apply against
that tree and the arm64 kernel tree; 4.1 does not appear to have this
problem since it still has the 5.1 struct definition.
Though there is precedent in ia64 code for ignoring the changes in size,
this patch set instead verifies correctness. The first patch adds the
BAD_MADT_GICC_ENTRY() macro to check the GICC subtable only, accounting
for the difference in specification versions that are possible. The
second patch replaces BAD_MADT_ENTRY usage with the BAD_MADT_GICC_ENTRY
macro in arm64 code, which is currently the only architecture affected.
The BAD_MADT_ENTRY() will continue to work as is for all other MADT
subtables.
I have tested these patches on an APM Mustang with version 1.15 firmware,
where the problem was found, and they fix the problem -- i.e., the system
will boot with either Linux 4.1 or linux-next kernels using the same ACPI
5.1 compatible firmware.
Changes for v4:
-- Reword the cover letter to reflect smaller patch set
-- Simplify BAD_MADT_GICC_ENTRY to the minimum needed; this removed
the need for the first patch containing version number macros (Rafael)
-- Simplify determining the GICC subtable length (Catalin)
Changes for v3:
-- Modified the macros for using spec version numbers in order
to make them clearer (Rafael, Hanjun)
-- Moved the definition of the BAD_MADT_GICC_ENTRY macro to an
arm64-specific header file since only this architecture uses
the GICC subtable (Rafael)
-- Added Reviewed-by (Hanjun) and Acked-by (Will) tags to 3/3, the
only unchanged patch; other tags could be applied but the patches
have changed.
-- Added Fixes: tag to patches
Changes for v2:
-- Replace magic constants with proper defines (Lorenzo)
-- Minor syntax clean-up noted by checkpatch
-- Send out CCs properly this time
-- Minor clean-up of the paragraphs in this cover letter
Al Stone (2):
ACPI / ARM64: add BAD_MADT_GICC_ENTRY() macro
ACPI / ARM64 : use the new BAD_MADT_GICC_ENTRY macro
arch/arm64/include/asm/acpi.h | 8 ++++++++
arch/arm64/kernel/smp.c | 2 +-
drivers/irqchip/irq-gic.c | 2 +-
3 files changed, 10 insertions(+), 2 deletions(-)
--
2.4.3
As we use the acpi_irq_domain as the global pointer to the acpi core
irq domain, which lead to multi places referring it and the way is not
scalable, so introduce a struct gsi_cfg_data to abstract the gsi data
for the irqchips then match the irq domain with the gsi.
For a ACPI based irqchip for example a GICD, it defines System Vector
Base in the GICD entry, which means the global system interrupt number
where this GIC Distributor’s interrupt inputs start, then we can get
the irq number supported by reading the register for this GICD, so we
can explictly get the gsi's associated irqdomain if the gsi is within
the range of gsi supported by this GICD.
For ACPI device in DSDT, it using another mapping of device and hwirq
number than DT, in DT, we using the interrupt parent property to get
the device node of irqchip, that's why we need the matching function
that match the device node with the one associated with the irqdomain.
For ACPI, we only can get the gsi which the device is using, no interrupt
parent will be used, that because gsi is a flat hwirq number which is
unique in the system, then we can get its associated irq domain as I said
above, which can be without the token pointer matching the interrupt
controller.
the code is arch independent, it also can be expanted for x86 for multi
ioapics.
Signed-off-by: Hanjun Guo <hanjun.guo(a)linaro.org>
---
drivers/acpi/gsi.c | 51 ++++++++++++++++++++++++++++++++++++++------
drivers/irqchip/irq-gic-v3.c | 4 +++-
drivers/irqchip/irq-gic.c | 7 +++++-
include/linux/acpi.h | 10 ++++++++-
4 files changed, 62 insertions(+), 10 deletions(-)
diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c
index 02c8408..7867ec2 100644
--- a/drivers/acpi/gsi.c
+++ b/drivers/acpi/gsi.c
@@ -15,11 +15,44 @@
enum acpi_irq_model_id acpi_irq_model;
-static struct irq_domain *acpi_irq_domain __read_mostly;
+static LIST_HEAD(gsi_cfg_data_list);
+static DEFINE_MUTEX(gsi_mutex);
-void set_acpi_irq_domain(struct irq_domain *domain)
+int gsi_cfg_data_add(struct irq_domain *domain, u32 gsi_base, u32 gsi_end)
{
- acpi_irq_domain = domain;
+ struct gsi_cfg_data *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->domain = domain;
+ data->gsi_base = gsi_base;
+ data->gsi_base = gsi_base;
+
+ mutex_lock(&gsi_mutex);
+ list_add(&data->list, &gsi_cfg_data_list);
+ mutex_unlock(&gsi_mutex);
+
+ return 0;
+}
+
+/* Find irqdomain with GSI (hwirq number) */
+static struct irq_domain *acpi_find_irqdomain(u32 gsi)
+{
+ struct gsi_cfg_data *data;
+ struct irq_domain *domain = NULL;
+
+ mutex_lock(&gsi_mutex);
+ list_for_each_entry(data, &gsi_cfg_data_list, list) {
+ if (gsi >= data->gsi_base && gsi <= data->gsi_end) {
+ domain = data->domain;
+ break;
+ }
+ }
+ mutex_unlock(&gsi_mutex);
+
+ return domain;
}
static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity)
@@ -53,7 +86,9 @@ static unsigned int acpi_gsi_get_irq_type(int trigger, int polarity)
*/
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
- *irq = irq_find_mapping(acpi_irq_domain, gsi);
+ struct irq_domain *domain = acpi_find_irqdomain(gsi);
+
+ *irq = irq_find_mapping(domain, gsi);
/*
* *irq == 0 means no mapping, that should
* be reported as a failure
@@ -77,12 +112,13 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
{
int irq;
unsigned int irq_type = acpi_gsi_get_irq_type(trigger, polarity);
+ struct irq_domain *domain = acpi_find_irqdomain(gsi);
- irq = irq_find_mapping(acpi_irq_domain, gsi);
+ irq = irq_find_mapping(domain, gsi);
if (irq > 0)
return irq;
- irq = irq_domain_alloc_irqs(acpi_irq_domain, 1, dev_to_node(dev),
+ irq = irq_domain_alloc_irqs(domain, 1, dev_to_node(dev),
&gsi);
if (irq <= 0)
return -EINVAL;
@@ -101,7 +137,8 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi);
*/
void acpi_unregister_gsi(u32 gsi)
{
- int irq = irq_find_mapping(acpi_irq_domain, gsi);
+ struct irq_domain *domain = acpi_find_irqdomain(gsi);
+ int irq = irq_find_mapping(domain, gsi);
irq_dispose_mapping(irq);
}
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index a11c020..5c53af6 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -947,6 +947,7 @@ static LIST_HEAD(redist_list);
static struct redist_region *redist_regs __initdata;
static u32 nr_redist_regions __initdata;
static phys_addr_t dist_phy_base __initdata;
+u32 gsi_base __initdata;
static int __init
gic_acpi_register_redist(u64 phys_base, u64 size)
@@ -1014,6 +1015,7 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
if (BAD_MADT_ENTRY(dist, end))
return -EINVAL;
+ gsi_base = dist->global_irq_base;
dist_phy_base = dist->base_address;
return 0;
}
@@ -1168,7 +1170,7 @@ init_base:
if (err)
goto out_release_redist;
- set_acpi_irq_domain(gic_data.domain);
+ gsi_cfg_data_add(gic_data.domain, gsi_base, gsi_base + gic_data.irq_nr);
return 0;
out_release_redist:
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 7f943ef..62e0640 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1051,6 +1051,7 @@ IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
#ifdef CONFIG_ACPI
static phys_addr_t dist_phy_base, cpu_phy_base __initdata;
+u32 gsi_base __initdata;
static int __init
gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
@@ -1089,6 +1090,7 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
if (BAD_MADT_ENTRY(dist, end))
return -EINVAL;
+ gsi_base = dist->global_irq_base;
dist_phy_base = dist->base_address;
return 0;
}
@@ -1139,7 +1141,10 @@ gic_v2_acpi_init(struct acpi_table_header *table)
}
gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL);
- set_acpi_irq_domain(gic_data[0].domain);
+
+ /* since we have only one GICD, we can safely use gic_data[0] here */
+ gsi_cfg_data_add(gic_data[0].domain, gsi_base,
+ gsi_base + gic_data[0].gic_irqs);
acpi_irq_model = ACPI_IRQ_MODEL_GIC;
return 0;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 6de4b0e..093d60e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -223,7 +223,15 @@ void acpi_unregister_gsi (u32 gsi);
#ifdef CONFIG_ACPI_GENERIC_GSI
struct irq_domain;
-void set_acpi_irq_domain(struct irq_domain *domain);
+
+struct gsi_cfg_data {
+ struct list_head list;
+ u32 gsi_base;
+ u32 gsi_end;
+ struct irq_domain *domain;
+};
+
+int gsi_cfg_data_add(struct irq_domain *domain, u32 gsi_base, u32 gsi_end);
#endif
struct pci_dev;
--
1.9.1
In the ACPI 5.1 version of the spec, the struct for the GICC subtable
(struct acpi_madt_generic_interrupt) of the MADT is 76 bytes long; in
ACPI 6.0, the struct is 80 bytes long. But, there is only one definition
in ACPICA for this struct -- and that is the 6.0 version. Hence, when
BAD_MADT_ENTRY() compares the struct size to the length in the GICC
subtable, it fails if 5.1 structs are in use, and there are systems in
the wild that have them.
Note that this was found in linux-next and these patches apply against
that tree and the arm64 kernel tree; 4.1-rc8 does not appear to have this
problem since it still has the 5.1 struct definition.
Even though there is precendent in ia64 code for ignoring the changes in
size, this patch set instead tries to verify correctness. The first patch
in the set adds macros for easily using the ACPI spec version. The second
patch adds the BAD_MADT_GICC_ENTRY() macro that uses the version macros to
check the GICC subtable only, accounting for the difference in specification
versions that are possible. The final patch replaces BAD_MADT_ENTRY usage
with the BAD_MADT_GICC_ENTRY macro in arm64 code, which is currently the
only architecture affected. The BAD_MADT_ENTRY() will continue to work as
is for all other MADT subtables.
I have tested these patches on an APM Mustang with version 1.15 firmware,
where the problem was found, and they fix the problem.
Changes for v3:
-- Modified the macros for using spec version numbers in order
to make them clearer (Rafael, Hanjun)
-- Moved the definition of the BAD_MADT_GICC_ENTRY macro to an
arm64-specific header file since only this architecture uses
the GICC subtable (Rafael)
-- Added Reviewed-by (Hanjun) and Acked-by (Will) tags to 3/3, the
only unchanged patch; other tags could be applied but the patches
have changed.
-- Added Fixes: tag to patches
Changes for v2:
-- Replace magic constants with proper defines (Lorenzo)
-- Minor syntax clean-up noted by checkpatch
-- Send out CCs properly this time
-- Minor clean-up of the paragraphs in this cover letter
Al Stone (3):
ACPI : introduce macros for using the ACPI specification version
ACPI / ARM64: add BAD_MADT_GICC_ENTRY() macro
ACPI / ARM64 : use the new BAD_MADT_GICC_ENTRY macro
arch/arm64/include/asm/acpi.h | 11 +++++++++++
arch/arm64/kernel/smp.c | 2 +-
drivers/irqchip/irq-gic.c | 2 +-
include/linux/acpi.h | 10 ++++++++++
4 files changed, 23 insertions(+), 2 deletions(-)
--
2.4.3
Hi Guys,
I guess its time to put this to bed now that Roys patch has made it
into acpica-tools and FWTS has been fixed to work without /dev/mem.
I produced the patch to expose these three tables from the kernel.
BUT, is there actually a user for this? My gut feeling is no and they
really contain little of interest anyway.
Does anyone actually have a use for the patch that makes it worth
sending upstream?
Graeme
In the ACPI 5.1 version of the spec, the struct for the GICC subtable
(struct acpi_madt_generic_interrupt) of the MADT is 76 bytes long; in
ACPI 6.0, the struct is 80 bytes long. But, there is only one definition
in ACPICA for this struct -- and that is the 6.0 version. Hence, when
BAD_MADT_ENTRY() compares the struct size to the length in the GICC
subtable, it fails if 5.1 structs are in use, and there are systems in
the wild that have them.
Note that this was found in linux-next and these patches apply against
that tree and the arm64 kernel tree; 4.1-rc8 does not appear to have this
problem since it still has the 5.1 struct definition.
Even though there is precendent in ia64 code for ignoring the changes in
size, this patch set instead tries to verify correctness. The first patch
in the set adds macros for easily using the ACPI spec version. The second
patch adds the BAD_MADT_GICC_ENTRY() macro that uses the version macros to
check the GICC subtable only, accounting for the difference in specification
versions that are possible. The final patch replaces BAD_MADT_ENTRY usage
with the BAD_MADT_GICC_ENTRY macro in arm64 code, which is currently the
only architecture affected. The BAD_MADT_ENTRY() will continue to work as
is for all other MADT subtables.
I have tested these patches on an APM Mustang with version 1.15 firmware,
where the problem was found, and they fix the problem.
Changes for v2:
-- Replace magic constants with proper defines (Lorenzo)
-- Minor syntax clean-up noted by checkpatch
-- Send out CCs properly this time
-- Minor clean-up of the paragraphs in this cover letter
Al Stone (3):
ACPI : introduce macros for using the ACPI specification version
ACPI: add BAD_MADT_GICC_ENTRY() macro
ACPI / ARM64 : use the new BAD_MADT_GICC_ENTRY macro
arch/arm64/kernel/smp.c | 2 +-
drivers/irqchip/irq-gic.c | 2 +-
include/linux/acpi.h | 15 +++++++++++++++
3 files changed, 17 insertions(+), 2 deletions(-)
--
2.4.0