diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2014-11-24 09:35:10 -0500 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-11-26 10:55:12 -0500 |
commit | f5c1434c217fd72ac0d24d3142d09e49a3d4e72e (patch) | |
tree | aecaafc7fe456cd46d2b6764ca7fcb870a3f4de6 /drivers/irqchip | |
parent | 443acc4f37f61e343f3577dc28d7e7fd8b499465 (diff) |
irqchip: GICv3: rework redistributor structure
The basic GICv3 driver has almost no use for the redistributor
(other than the basic per-CPU interrupts), but the ITS needs
a lot more from them.
As such, rework the set of data structures. The behaviour of the
GICv3 driver is otherwise unaffected.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Link: https://lkml.kernel.org/r/1416839720-18400-4-git-send-email-marc.zyngier@arm.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 4cb355aff3c6..43e57da0d80e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c | |||
@@ -34,20 +34,25 @@ | |||
34 | #include "irq-gic-common.h" | 34 | #include "irq-gic-common.h" |
35 | #include "irqchip.h" | 35 | #include "irqchip.h" |
36 | 36 | ||
37 | struct redist_region { | ||
38 | void __iomem *redist_base; | ||
39 | phys_addr_t phys_base; | ||
40 | }; | ||
41 | |||
37 | struct gic_chip_data { | 42 | struct gic_chip_data { |
38 | void __iomem *dist_base; | 43 | void __iomem *dist_base; |
39 | void __iomem **redist_base; | 44 | struct redist_region *redist_regions; |
40 | void __iomem * __percpu *rdist; | 45 | struct rdists rdists; |
41 | struct irq_domain *domain; | 46 | struct irq_domain *domain; |
42 | u64 redist_stride; | 47 | u64 redist_stride; |
43 | u32 redist_regions; | 48 | u32 nr_redist_regions; |
44 | unsigned int irq_nr; | 49 | unsigned int irq_nr; |
45 | }; | 50 | }; |
46 | 51 | ||
47 | static struct gic_chip_data gic_data __read_mostly; | 52 | static struct gic_chip_data gic_data __read_mostly; |
48 | 53 | ||
49 | #define gic_data_rdist() (this_cpu_ptr(gic_data.rdist)) | 54 | #define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist)) |
50 | #define gic_data_rdist_rd_base() (*gic_data_rdist()) | 55 | #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) |
51 | #define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K) | 56 | #define gic_data_rdist_sgi_base() (gic_data_rdist_rd_base() + SZ_64K) |
52 | 57 | ||
53 | /* Our default, arbitrary priority value. Linux only uses one anyway. */ | 58 | /* Our default, arbitrary priority value. Linux only uses one anyway. */ |
@@ -333,8 +338,8 @@ static int gic_populate_rdist(void) | |||
333 | MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | | 338 | MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | |
334 | MPIDR_AFFINITY_LEVEL(mpidr, 0)); | 339 | MPIDR_AFFINITY_LEVEL(mpidr, 0)); |
335 | 340 | ||
336 | for (i = 0; i < gic_data.redist_regions; i++) { | 341 | for (i = 0; i < gic_data.nr_redist_regions; i++) { |
337 | void __iomem *ptr = gic_data.redist_base[i]; | 342 | void __iomem *ptr = gic_data.redist_regions[i].redist_base; |
338 | u32 reg; | 343 | u32 reg; |
339 | 344 | ||
340 | reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK; | 345 | reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK; |
@@ -347,10 +352,13 @@ static int gic_populate_rdist(void) | |||
347 | do { | 352 | do { |
348 | typer = readq_relaxed(ptr + GICR_TYPER); | 353 | typer = readq_relaxed(ptr + GICR_TYPER); |
349 | if ((typer >> 32) == aff) { | 354 | if ((typer >> 32) == aff) { |
355 | u64 offset = ptr - gic_data.redist_regions[i].redist_base; | ||
350 | gic_data_rdist_rd_base() = ptr; | 356 | gic_data_rdist_rd_base() = ptr; |
351 | pr_info("CPU%d: found redistributor %llx @%p\n", | 357 | gic_data_rdist()->phys_base = gic_data.redist_regions[i].phys_base + offset; |
358 | pr_info("CPU%d: found redistributor %llx region %d:%pa\n", | ||
352 | smp_processor_id(), | 359 | smp_processor_id(), |
353 | (unsigned long long)mpidr, ptr); | 360 | (unsigned long long)mpidr, |
361 | i, &gic_data_rdist()->phys_base); | ||
354 | return 0; | 362 | return 0; |
355 | } | 363 | } |
356 | 364 | ||
@@ -673,9 +681,10 @@ static const struct irq_domain_ops gic_irq_domain_ops = { | |||
673 | static int __init gic_of_init(struct device_node *node, struct device_node *parent) | 681 | static int __init gic_of_init(struct device_node *node, struct device_node *parent) |
674 | { | 682 | { |
675 | void __iomem *dist_base; | 683 | void __iomem *dist_base; |
676 | void __iomem **redist_base; | 684 | struct redist_region *rdist_regs; |
677 | u64 redist_stride; | 685 | u64 redist_stride; |
678 | u32 redist_regions; | 686 | u32 nr_redist_regions; |
687 | u32 typer; | ||
679 | u32 reg; | 688 | u32 reg; |
680 | int gic_irqs; | 689 | int gic_irqs; |
681 | int err; | 690 | int err; |
@@ -696,48 +705,54 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare | |||
696 | goto out_unmap_dist; | 705 | goto out_unmap_dist; |
697 | } | 706 | } |
698 | 707 | ||
699 | if (of_property_read_u32(node, "#redistributor-regions", &redist_regions)) | 708 | if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions)) |
700 | redist_regions = 1; | 709 | nr_redist_regions = 1; |
701 | 710 | ||
702 | redist_base = kzalloc(sizeof(*redist_base) * redist_regions, GFP_KERNEL); | 711 | rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL); |
703 | if (!redist_base) { | 712 | if (!rdist_regs) { |
704 | err = -ENOMEM; | 713 | err = -ENOMEM; |
705 | goto out_unmap_dist; | 714 | goto out_unmap_dist; |
706 | } | 715 | } |
707 | 716 | ||
708 | for (i = 0; i < redist_regions; i++) { | 717 | for (i = 0; i < nr_redist_regions; i++) { |
709 | redist_base[i] = of_iomap(node, 1 + i); | 718 | struct resource res; |
710 | if (!redist_base[i]) { | 719 | int ret; |
720 | |||
721 | ret = of_address_to_resource(node, 1 + i, &res); | ||
722 | rdist_regs[i].redist_base = of_iomap(node, 1 + i); | ||
723 | if (ret || !rdist_regs[i].redist_base) { | ||
711 | pr_err("%s: couldn't map region %d\n", | 724 | pr_err("%s: couldn't map region %d\n", |
712 | node->full_name, i); | 725 | node->full_name, i); |
713 | err = -ENODEV; | 726 | err = -ENODEV; |
714 | goto out_unmap_rdist; | 727 | goto out_unmap_rdist; |
715 | } | 728 | } |
729 | rdist_regs[i].phys_base = res.start; | ||
716 | } | 730 | } |
717 | 731 | ||
718 | if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) | 732 | if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) |
719 | redist_stride = 0; | 733 | redist_stride = 0; |
720 | 734 | ||
721 | gic_data.dist_base = dist_base; | 735 | gic_data.dist_base = dist_base; |
722 | gic_data.redist_base = redist_base; | 736 | gic_data.redist_regions = rdist_regs; |
723 | gic_data.redist_regions = redist_regions; | 737 | gic_data.nr_redist_regions = nr_redist_regions; |
724 | gic_data.redist_stride = redist_stride; | 738 | gic_data.redist_stride = redist_stride; |
725 | 739 | ||
726 | /* | 740 | /* |
727 | * Find out how many interrupts are supported. | 741 | * Find out how many interrupts are supported. |
728 | * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) | 742 | * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) |
729 | */ | 743 | */ |
730 | gic_irqs = readl_relaxed(gic_data.dist_base + GICD_TYPER) & 0x1f; | 744 | typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); |
731 | gic_irqs = (gic_irqs + 1) * 32; | 745 | gic_data.rdists.id_bits = GICD_TYPER_ID_BITS(typer); |
746 | gic_irqs = GICD_TYPER_IRQS(typer); | ||
732 | if (gic_irqs > 1020) | 747 | if (gic_irqs > 1020) |
733 | gic_irqs = 1020; | 748 | gic_irqs = 1020; |
734 | gic_data.irq_nr = gic_irqs; | 749 | gic_data.irq_nr = gic_irqs; |
735 | 750 | ||
736 | gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops, | 751 | gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops, |
737 | &gic_data); | 752 | &gic_data); |
738 | gic_data.rdist = alloc_percpu(typeof(*gic_data.rdist)); | 753 | gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); |
739 | 754 | ||
740 | if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdist)) { | 755 | if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { |
741 | err = -ENOMEM; | 756 | err = -ENOMEM; |
742 | goto out_free; | 757 | goto out_free; |
743 | } | 758 | } |
@@ -754,12 +769,12 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare | |||
754 | out_free: | 769 | out_free: |
755 | if (gic_data.domain) | 770 | if (gic_data.domain) |
756 | irq_domain_remove(gic_data.domain); | 771 | irq_domain_remove(gic_data.domain); |
757 | free_percpu(gic_data.rdist); | 772 | free_percpu(gic_data.rdists.rdist); |
758 | out_unmap_rdist: | 773 | out_unmap_rdist: |
759 | for (i = 0; i < redist_regions; i++) | 774 | for (i = 0; i < nr_redist_regions; i++) |
760 | if (redist_base[i]) | 775 | if (rdist_regs[i].redist_base) |
761 | iounmap(redist_base[i]); | 776 | iounmap(rdist_regs[i].redist_base); |
762 | kfree(redist_base); | 777 | kfree(rdist_regs); |
763 | out_unmap_dist: | 778 | out_unmap_dist: |
764 | iounmap(dist_base); | 779 | iounmap(dist_base); |
765 | return err; | 780 | return err; |