diff options
| -rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 73 | ||||
| -rw-r--r-- | include/linux/irqchip/arm-gic-v3.h | 15 |
2 files changed, 59 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; |
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 03a4ea37ba86..040615a48bf5 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h | |||
| @@ -49,6 +49,10 @@ | |||
| 49 | #define GICD_CTLR_ENABLE_G1A (1U << 1) | 49 | #define GICD_CTLR_ENABLE_G1A (1U << 1) |
| 50 | #define GICD_CTLR_ENABLE_G1 (1U << 0) | 50 | #define GICD_CTLR_ENABLE_G1 (1U << 0) |
| 51 | 51 | ||
| 52 | #define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) | ||
| 53 | #define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) | ||
| 54 | #define GICD_TYPER_LPIS (1U << 17) | ||
| 55 | |||
| 52 | #define GICD_IROUTER_SPI_MODE_ONE (0U << 31) | 56 | #define GICD_IROUTER_SPI_MODE_ONE (0U << 31) |
| 53 | #define GICD_IROUTER_SPI_MODE_ANY (1U << 31) | 57 | #define GICD_IROUTER_SPI_MODE_ANY (1U << 31) |
| 54 | 58 | ||
| @@ -189,6 +193,17 @@ | |||
| 189 | 193 | ||
| 190 | #include <linux/stringify.h> | 194 | #include <linux/stringify.h> |
| 191 | 195 | ||
| 196 | struct rdists { | ||
| 197 | struct { | ||
| 198 | void __iomem *rd_base; | ||
| 199 | struct page *pend_page; | ||
| 200 | phys_addr_t phys_base; | ||
| 201 | } __percpu *rdist; | ||
| 202 | struct page *prop_page; | ||
| 203 | int id_bits; | ||
| 204 | u64 flags; | ||
| 205 | }; | ||
| 206 | |||
| 192 | static inline void gic_write_eoir(u64 irq) | 207 | static inline void gic_write_eoir(u64 irq) |
| 193 | { | 208 | { |
| 194 | asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" (irq)); | 209 | asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" (irq)); |
