Hi Hanjun,
On 26 June 2015 at 09:51, Hanjun Guo hanjun.guo@linaro.org wrote:
On systems supporting GICv3 and above, the field of GICR Base Address holds the 64-bit physical address of the associated Redistributor if the GIC Redistributors are not in the always-on power domain, so instead of init GICR regions via GIC redistributor stricture, init it with GICR base address in GICC structures.
Unless I misunderstand, I think you want the opposite statement. i.e. If the redists are in always power-on domain, then the base addresses should be in GICR structs and not in GICC.
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org
drivers/irqchip/irq-gic-acpi.c | 34 ++++++- drivers/irqchip/irq-gic-v3.c | 181 ++++++++++++++++++++++++++++++++--- include/linux/irqchip/arm-gic-acpi.h | 2 + 3 files changed, 200 insertions(+), 17 deletions(-)
diff --git a/drivers/irqchip/irq-gic-acpi.c b/drivers/irqchip/irq-gic-acpi.c index 236bba5..732efa0 100644 --- a/drivers/irqchip/irq-gic-acpi.c +++ b/drivers/irqchip/irq-gic-acpi.c @@ -21,6 +21,11 @@ static u8 gic_version __initdata = ACPI_MADT_GIC_VERSION_NONE;
static phys_addr_t dist_phy_base __initdata;
+u8 __init acpi_gic_version(void) +{
return gic_version;
+}
static int __init acpi_gic_parse_distributor(struct acpi_subtable_header *header, const unsigned long end) @@ -38,6 +43,27 @@ acpi_gic_parse_distributor(struct acpi_subtable_header *header, }
static int __init +gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
const unsigned long end)
+{
struct acpi_madt_generic_interrupt *gicc;
gicc = (struct acpi_madt_generic_interrupt *)header;
if (BAD_MADT_ENTRY(gicc, end))
return -EINVAL;
/*
*If GICC is enabled but no gicr base address, which means GICR is
* not presented via GICC
*/
if ((gicc->flags & ACPI_MADT_ENABLED) && !gicc->gicr_base_address)
return -ENODEV;
return 0;
+}
+static int __init match_gic_redist(struct acpi_subtable_header *header, const unsigned long end) { return 0; @@ -54,8 +80,12 @@ static bool __init acpi_gic_redist_is_present(void) /* has at least one GIC redistributor entry */ if (count > 0) return true;
else
return false;
/* else try to find GICR base in GICC entries */
count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
gic_acpi_parse_madt_gicc, 0);
return count > 0;
}
static int __init acpi_gic_version_init(void) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index a1c4c74..755c940 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -389,9 +389,8 @@ static void __init gic_dist_init(void) writeq_relaxed(affinity, base + GICD_IROUTER + i * 8); }
-static int gic_populate_rdist(void) +static int gic_populate_rdist_with_regions(u64 mpidr) {
u64 mpidr = cpu_logical_map(smp_processor_id()); u64 typer; u32 aff; int i;
@@ -439,6 +438,33 @@ static int gic_populate_rdist(void) } while (!(typer & GICR_TYPER_LAST)); }
return -ENODEV;
+}
+#ifdef CONFIG_ACPI +/*
- Populate redist when GIC redistributor address is presented in ACPI
- MADT GICC entries
- */
+static int gic_populate_rdist_with_gicr_base(u64 mpidr); +#else +static inline int gic_populate_rdist_with_gicr_base(u64 mpidr) +{
return -ENODEV;
+} +#endif +static int gic_populate_rdist(void) +{
u64 mpidr = cpu_logical_map(smp_processor_id());
if (!gic_data.nr_redist_regions) {
if (!gic_populate_rdist_with_gicr_base(mpidr))
return 0;
} else {
if (!gic_populate_rdist_with_regions(mpidr))
return 0;
}
/* We couldn't even deal with ourselves... */ WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n", smp_processor_id(), (unsigned long long)mpidr);
@@ -906,6 +932,16 @@ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); #endif
#ifdef CONFIG_ACPI
+struct acpi_gicc_redist {
struct list_head list;
u64 mpidr;
phys_addr_t phys_base;
void __iomem *redist_base;
+};
+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; @@ -938,6 +974,17 @@ gic_acpi_register_redist(u64 phys_base, u64 size) return 0; }
+static void __init +gic_acpi_release_redist_regions(void) +{
int i;
for (i = 0; i < nr_redist_regions; i++)
if (redist_regs[i].redist_base)
iounmap(redist_regs[i].redist_base);
kfree(redist_regs);
+}
static int __init gic_acpi_parse_madt_redist(struct acpi_subtable_header *header, const unsigned long end) @@ -970,10 +1017,98 @@ gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, }
static int __init -gic_v3_acpi_init(struct acpi_table_header *table) +gic_acpi_add_gicc_redist(phys_addr_t phys_base, u64 mpidr) {
int count, i, err = 0;
struct acpi_gicc_redist *redist;
redist = kzalloc(sizeof(*redist), GFP_KERNEL);
if (!redist)
return -ENOMEM;
redist->mpidr = mpidr;
redist->phys_base = phys_base;
if (acpi_gic_version() == ACPI_MADT_GIC_VERSION_V3)
/* RD_base + SGI_base */
redist->redist_base = ioremap(phys_base, 2 * SZ_64K);
else
/*
* RD_base + SGI_base + VLPI_base,
* we don't map reserved page as it's buggy to access it
*/
redist->redist_base = ioremap(phys_base, 3 * SZ_64K);
This will break things in the gic_populate_rdist() loop for the case where there is only one rdist entry per CPU and each entry is not delimited by the LAST bit in the GICR_TYPER. This is possible when the hardware only sets the LAST bit for the last rdist entry. In such a case, the __iomem *ptr in the loop will increment endlessly until it triggers some kind of illegal memory read.
Need to think some more, but 2 options come to mind:
- Figure a way to allocate contiguous memory for all rdist_regions. You already do that in GICR case: gic_acpi_register_redist().
- Find a way to break the loop in gic_populate_rdist() if the hardware doesn't have the LAST bit set. If we know number of entries in each rdist region this could be possible.
Cheers, Ashwin.