|
@@ -34,20 +34,25 @@
|
|
|
#include "irq-gic-common.h"
|
|
|
#include "irqchip.h"
|
|
|
|
|
|
+struct redist_region {
|
|
|
+ void __iomem *redist_base;
|
|
|
+ phys_addr_t phys_base;
|
|
|
+};
|
|
|
+
|
|
|
struct gic_chip_data {
|
|
|
void __iomem *dist_base;
|
|
|
- void __iomem **redist_base;
|
|
|
- void __iomem * __percpu *rdist;
|
|
|
+ struct redist_region *redist_regions;
|
|
|
+ struct rdists rdists;
|
|
|
struct irq_domain *domain;
|
|
|
u64 redist_stride;
|
|
|
- u32 redist_regions;
|
|
|
+ u32 nr_redist_regions;
|
|
|
unsigned int irq_nr;
|
|
|
};
|
|
|
|
|
|
static struct gic_chip_data gic_data __read_mostly;
|
|
|
|
|
|
-#define gic_data_rdist() (this_cpu_ptr(gic_data.rdist))
|
|
|
-#define gic_data_rdist_rd_base() (*gic_data_rdist())
|
|
|
+#define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist))
|
|
|
+#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
|
|
|
#define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K)
|
|
|
|
|
|
/* Our default, arbitrary priority value. Linux only uses one anyway. */
|
|
@@ -333,8 +338,8 @@ static int gic_populate_rdist(void)
|
|
|
MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
|
|
|
MPIDR_AFFINITY_LEVEL(mpidr, 0));
|
|
|
|
|
|
- for (i = 0; i < gic_data.redist_regions; i++) {
|
|
|
- void __iomem *ptr = gic_data.redist_base[i];
|
|
|
+ for (i = 0; i < gic_data.nr_redist_regions; i++) {
|
|
|
+ void __iomem *ptr = gic_data.redist_regions[i].redist_base;
|
|
|
u32 reg;
|
|
|
|
|
|
reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
|
|
@@ -347,10 +352,13 @@ static int gic_populate_rdist(void)
|
|
|
do {
|
|
|
typer = readq_relaxed(ptr + GICR_TYPER);
|
|
|
if ((typer >> 32) == aff) {
|
|
|
+ u64 offset = ptr - gic_data.redist_regions[i].redist_base;
|
|
|
gic_data_rdist_rd_base() = ptr;
|
|
|
- pr_info("CPU%d: found redistributor %llx @%p\n",
|
|
|
+ gic_data_rdist()->phys_base = gic_data.redist_regions[i].phys_base + offset;
|
|
|
+ pr_info("CPU%d: found redistributor %llx region %d:%pa\n",
|
|
|
smp_processor_id(),
|
|
|
- (unsigned long long)mpidr, ptr);
|
|
|
+ (unsigned long long)mpidr,
|
|
|
+ i, &gic_data_rdist()->phys_base);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -673,9 +681,10 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
|
|
|
static int __init gic_of_init(struct device_node *node, struct device_node *parent)
|
|
|
{
|
|
|
void __iomem *dist_base;
|
|
|
- void __iomem **redist_base;
|
|
|
+ struct redist_region *rdist_regs;
|
|
|
u64 redist_stride;
|
|
|
- u32 redist_regions;
|
|
|
+ u32 nr_redist_regions;
|
|
|
+ u32 typer;
|
|
|
u32 reg;
|
|
|
int gic_irqs;
|
|
|
int err;
|
|
@@ -696,48 +705,54 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
|
|
|
goto out_unmap_dist;
|
|
|
}
|
|
|
|
|
|
- if (of_property_read_u32(node, "#redistributor-regions", &redist_regions))
|
|
|
- redist_regions = 1;
|
|
|
+ if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
|
|
|
+ nr_redist_regions = 1;
|
|
|
|
|
|
- redist_base = kzalloc(sizeof(*redist_base) * redist_regions, GFP_KERNEL);
|
|
|
- if (!redist_base) {
|
|
|
+ rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL);
|
|
|
+ if (!rdist_regs) {
|
|
|
err = -ENOMEM;
|
|
|
goto out_unmap_dist;
|
|
|
}
|
|
|
|
|
|
- for (i = 0; i < redist_regions; i++) {
|
|
|
- redist_base[i] = of_iomap(node, 1 + i);
|
|
|
- if (!redist_base[i]) {
|
|
|
+ for (i = 0; i < nr_redist_regions; i++) {
|
|
|
+ struct resource res;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = of_address_to_resource(node, 1 + i, &res);
|
|
|
+ rdist_regs[i].redist_base = of_iomap(node, 1 + i);
|
|
|
+ if (ret || !rdist_regs[i].redist_base) {
|
|
|
pr_err("%s: couldn't map region %d\n",
|
|
|
node->full_name, i);
|
|
|
err = -ENODEV;
|
|
|
goto out_unmap_rdist;
|
|
|
}
|
|
|
+ rdist_regs[i].phys_base = res.start;
|
|
|
}
|
|
|
|
|
|
if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
|
|
|
redist_stride = 0;
|
|
|
|
|
|
gic_data.dist_base = dist_base;
|
|
|
- gic_data.redist_base = redist_base;
|
|
|
- gic_data.redist_regions = redist_regions;
|
|
|
+ gic_data.redist_regions = rdist_regs;
|
|
|
+ gic_data.nr_redist_regions = nr_redist_regions;
|
|
|
gic_data.redist_stride = redist_stride;
|
|
|
|
|
|
/*
|
|
|
* Find out how many interrupts are supported.
|
|
|
* The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
|
|
|
*/
|
|
|
- gic_irqs = readl_relaxed(gic_data.dist_base + GICD_TYPER) & 0x1f;
|
|
|
- gic_irqs = (gic_irqs + 1) * 32;
|
|
|
+ typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
|
|
|
+ gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer);
|
|
|
+ gic_irqs = GICD_TYPER_IRQS(typer);
|
|
|
if (gic_irqs > 1020)
|
|
|
gic_irqs = 1020;
|
|
|
gic_data.irq_nr = gic_irqs;
|
|
|
|
|
|
gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
|
|
|
&gic_data);
|
|
|
- gic_data.rdist = alloc_percpu(typeof(*gic_data.rdist));
|
|
|
+ gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
|
|
|
|
|
|
- if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdist)) {
|
|
|
+ if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
|
|
|
err = -ENOMEM;
|
|
|
goto out_free;
|
|
|
}
|
|
@@ -754,12 +769,12 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
|
|
|
out_free:
|
|
|
if (gic_data.domain)
|
|
|
irq_domain_remove(gic_data.domain);
|
|
|
- free_percpu(gic_data.rdist);
|
|
|
+ free_percpu(gic_data.rdists.rdist);
|
|
|
out_unmap_rdist:
|
|
|
- for (i = 0; i < redist_regions; i++)
|
|
|
- if (redist_base[i])
|
|
|
- iounmap(redist_base[i]);
|
|
|
- kfree(redist_base);
|
|
|
+ for (i = 0; i < nr_redist_regions; i++)
|
|
|
+ if (rdist_regs[i].redist_base)
|
|
|
+ iounmap(rdist_regs[i].redist_base);
|
|
|
+ kfree(rdist_regs);
|
|
|
out_unmap_dist:
|
|
|
iounmap(dist_base);
|
|
|
return err;
|