aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2019-02-07 15:12:40 -0500
committerThomas Gleixner <tglx@linutronix.de>2019-02-07 15:12:40 -0500
commit8087f407364d50d5c3ac8e39365548351e2859f2 (patch)
tree49826fed88a84e0b36cd517d1953b7292e4b896a
parent37b144df8099465bf8d08296d8b424c77fd9b0ac (diff)
parent56841070ccc87b463ac037d2d1f2beb8e5e35f0c (diff)
Merge tag 'irqchip-5.0-3' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/urgent
Pull irqchip updates from Marc Zyngier: - Another GICv3 ITS fix for devices sharing the same DevID - Don't return invalid data on exhaustion of the GICv3 LPI pool - Fix a GICv3 field decoding bug leading to memory over-allocation - Init GICv4 at boot time instead of lazy init - Fix interrupt masking on PJ4
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c101
-rw-r--r--drivers/irqchip/irq-mmp.c6
-rw-r--r--include/linux/irqchip/arm-gic-v3.h2
3 files changed, 85 insertions, 24 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 7f2a45445b00..c3aba3fc818d 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -97,9 +97,14 @@ struct its_device;
97 * The ITS structure - contains most of the infrastructure, with the 97 * The ITS structure - contains most of the infrastructure, with the
98 * top-level MSI domain, the command queue, the collections, and the 98 * top-level MSI domain, the command queue, the collections, and the
99 * list of devices writing to it. 99 * list of devices writing to it.
100 *
101 * dev_alloc_lock has to be taken for device allocations, while the
102 * spinlock must be taken to parse data structures such as the device
103 * list.
100 */ 104 */
101struct its_node { 105struct its_node {
102 raw_spinlock_t lock; 106 raw_spinlock_t lock;
107 struct mutex dev_alloc_lock;
103 struct list_head entry; 108 struct list_head entry;
104 void __iomem *base; 109 void __iomem *base;
105 phys_addr_t phys_base; 110 phys_addr_t phys_base;
@@ -156,6 +161,7 @@ struct its_device {
156 void *itt; 161 void *itt;
157 u32 nr_ites; 162 u32 nr_ites;
158 u32 device_id; 163 u32 device_id;
164 bool shared;
159}; 165};
160 166
161static struct { 167static struct {
@@ -1580,6 +1586,9 @@ static unsigned long *its_lpi_alloc(int nr_irqs, u32 *base, int *nr_ids)
1580 nr_irqs /= 2; 1586 nr_irqs /= 2;
1581 } while (nr_irqs > 0); 1587 } while (nr_irqs > 0);
1582 1588
1589 if (!nr_irqs)
1590 err = -ENOSPC;
1591
1583 if (err) 1592 if (err)
1584 goto out; 1593 goto out;
1585 1594
@@ -2059,6 +2068,29 @@ static int __init allocate_lpi_tables(void)
2059 return 0; 2068 return 0;
2060} 2069}
2061 2070
2071static u64 its_clear_vpend_valid(void __iomem *vlpi_base)
2072{
2073 u32 count = 1000000; /* 1s! */
2074 bool clean;
2075 u64 val;
2076
2077 val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2078 val &= ~GICR_VPENDBASER_Valid;
2079 gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
2080
2081 do {
2082 val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2083 clean = !(val & GICR_VPENDBASER_Dirty);
2084 if (!clean) {
2085 count--;
2086 cpu_relax();
2087 udelay(1);
2088 }
2089 } while (!clean && count);
2090
2091 return val;
2092}
2093
2062static void its_cpu_init_lpis(void) 2094static void its_cpu_init_lpis(void)
2063{ 2095{
2064 void __iomem *rbase = gic_data_rdist_rd_base(); 2096 void __iomem *rbase = gic_data_rdist_rd_base();
@@ -2144,6 +2176,30 @@ static void its_cpu_init_lpis(void)
2144 val |= GICR_CTLR_ENABLE_LPIS; 2176 val |= GICR_CTLR_ENABLE_LPIS;
2145 writel_relaxed(val, rbase + GICR_CTLR); 2177 writel_relaxed(val, rbase + GICR_CTLR);
2146 2178
2179 if (gic_rdists->has_vlpis) {
2180 void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
2181
2182 /*
2183 * It's possible for CPU to receive VLPIs before it is
2184 * sheduled as a vPE, especially for the first CPU, and the
2185 * VLPI with INTID larger than 2^(IDbits+1) will be considered
2186 * as out of range and dropped by GIC.
2187 * So we initialize IDbits to known value to avoid VLPI drop.
2188 */
2189 val = (LPI_NRBITS - 1) & GICR_VPROPBASER_IDBITS_MASK;
2190 pr_debug("GICv4: CPU%d: Init IDbits to 0x%llx for GICR_VPROPBASER\n",
2191 smp_processor_id(), val);
2192 gits_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
2193
2194 /*
2195 * Also clear Valid bit of GICR_VPENDBASER, in case some
2196 * ancient programming gets left in and has possibility of
2197 * corrupting memory.
2198 */
2199 val = its_clear_vpend_valid(vlpi_base);
2200 WARN_ON(val & GICR_VPENDBASER_Dirty);
2201 }
2202
2147 /* Make sure the GIC has seen the above */ 2203 /* Make sure the GIC has seen the above */
2148 dsb(sy); 2204 dsb(sy);
2149out: 2205out:
@@ -2422,6 +2478,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
2422 struct its_device *its_dev; 2478 struct its_device *its_dev;
2423 struct msi_domain_info *msi_info; 2479 struct msi_domain_info *msi_info;
2424 u32 dev_id; 2480 u32 dev_id;
2481 int err = 0;
2425 2482
2426 /* 2483 /*
2427 * We ignore "dev" entierely, and rely on the dev_id that has 2484 * We ignore "dev" entierely, and rely on the dev_id that has
@@ -2444,6 +2501,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
2444 return -EINVAL; 2501 return -EINVAL;
2445 } 2502 }
2446 2503
2504 mutex_lock(&its->dev_alloc_lock);
2447 its_dev = its_find_device(its, dev_id); 2505 its_dev = its_find_device(its, dev_id);
2448 if (its_dev) { 2506 if (its_dev) {
2449 /* 2507 /*
@@ -2451,18 +2509,22 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
2451 * another alias (PCI bridge of some sort). No need to 2509 * another alias (PCI bridge of some sort). No need to
2452 * create the device. 2510 * create the device.
2453 */ 2511 */
2512 its_dev->shared = true;
2454 pr_debug("Reusing ITT for devID %x\n", dev_id); 2513 pr_debug("Reusing ITT for devID %x\n", dev_id);
2455 goto out; 2514 goto out;
2456 } 2515 }
2457 2516
2458 its_dev = its_create_device(its, dev_id, nvec, true); 2517 its_dev = its_create_device(its, dev_id, nvec, true);
2459 if (!its_dev) 2518 if (!its_dev) {
2460 return -ENOMEM; 2519 err = -ENOMEM;
2520 goto out;
2521 }
2461 2522
2462 pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec)); 2523 pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec));
2463out: 2524out:
2525 mutex_unlock(&its->dev_alloc_lock);
2464 info->scratchpad[0].ptr = its_dev; 2526 info->scratchpad[0].ptr = its_dev;
2465 return 0; 2527 return err;
2466} 2528}
2467 2529
2468static struct msi_domain_ops its_msi_domain_ops = { 2530static struct msi_domain_ops its_msi_domain_ops = {
@@ -2566,6 +2628,7 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
2566{ 2628{
2567 struct irq_data *d = irq_domain_get_irq_data(domain, virq); 2629 struct irq_data *d = irq_domain_get_irq_data(domain, virq);
2568 struct its_device *its_dev = irq_data_get_irq_chip_data(d); 2630 struct its_device *its_dev = irq_data_get_irq_chip_data(d);
2631 struct its_node *its = its_dev->its;
2569 int i; 2632 int i;
2570 2633
2571 for (i = 0; i < nr_irqs; i++) { 2634 for (i = 0; i < nr_irqs; i++) {
@@ -2580,8 +2643,14 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
2580 irq_domain_reset_irq_data(data); 2643 irq_domain_reset_irq_data(data);
2581 } 2644 }
2582 2645
2583 /* If all interrupts have been freed, start mopping the floor */ 2646 mutex_lock(&its->dev_alloc_lock);
2584 if (bitmap_empty(its_dev->event_map.lpi_map, 2647
2648 /*
2649 * If all interrupts have been freed, start mopping the
2650 * floor. This is conditionned on the device not being shared.
2651 */
2652 if (!its_dev->shared &&
2653 bitmap_empty(its_dev->event_map.lpi_map,
2585 its_dev->event_map.nr_lpis)) { 2654 its_dev->event_map.nr_lpis)) {
2586 its_lpi_free(its_dev->event_map.lpi_map, 2655 its_lpi_free(its_dev->event_map.lpi_map,
2587 its_dev->event_map.lpi_base, 2656 its_dev->event_map.lpi_base,
@@ -2593,6 +2662,8 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
2593 its_free_device(its_dev); 2662 its_free_device(its_dev);
2594 } 2663 }
2595 2664
2665 mutex_unlock(&its->dev_alloc_lock);
2666
2596 irq_domain_free_irqs_parent(domain, virq, nr_irqs); 2667 irq_domain_free_irqs_parent(domain, virq, nr_irqs);
2597} 2668}
2598 2669
@@ -2755,26 +2826,11 @@ static void its_vpe_schedule(struct its_vpe *vpe)
2755static void its_vpe_deschedule(struct its_vpe *vpe) 2826static void its_vpe_deschedule(struct its_vpe *vpe)
2756{ 2827{
2757 void __iomem *vlpi_base = gic_data_rdist_vlpi_base(); 2828 void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
2758 u32 count = 1000000; /* 1s! */
2759 bool clean;
2760 u64 val; 2829 u64 val;
2761 2830
2762 /* We're being scheduled out */ 2831 val = its_clear_vpend_valid(vlpi_base);
2763 val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2764 val &= ~GICR_VPENDBASER_Valid;
2765 gits_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);
2766
2767 do {
2768 val = gits_read_vpendbaser(vlpi_base + GICR_VPENDBASER);
2769 clean = !(val & GICR_VPENDBASER_Dirty);
2770 if (!clean) {
2771 count--;
2772 cpu_relax();
2773 udelay(1);
2774 }
2775 } while (!clean && count);
2776 2832
2777 if (unlikely(!clean && !count)) { 2833 if (unlikely(val & GICR_VPENDBASER_Dirty)) {
2778 pr_err_ratelimited("ITS virtual pending table not cleaning\n"); 2834 pr_err_ratelimited("ITS virtual pending table not cleaning\n");
2779 vpe->idai = false; 2835 vpe->idai = false;
2780 vpe->pending_last = true; 2836 vpe->pending_last = true;
@@ -3517,6 +3573,7 @@ static int __init its_probe_one(struct resource *res,
3517 } 3573 }
3518 3574
3519 raw_spin_lock_init(&its->lock); 3575 raw_spin_lock_init(&its->lock);
3576 mutex_init(&its->dev_alloc_lock);
3520 INIT_LIST_HEAD(&its->entry); 3577 INIT_LIST_HEAD(&its->entry);
3521 INIT_LIST_HEAD(&its->its_device_list); 3578 INIT_LIST_HEAD(&its->its_device_list);
3522 typer = gic_read_typer(its_base + GITS_TYPER); 3579 typer = gic_read_typer(its_base + GITS_TYPER);
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 25f32e1d7764..3496b61a312a 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -34,6 +34,9 @@
34#define SEL_INT_PENDING (1 << 6) 34#define SEL_INT_PENDING (1 << 6)
35#define SEL_INT_NUM_MASK 0x3f 35#define SEL_INT_NUM_MASK 0x3f
36 36
37#define MMP2_ICU_INT_ROUTE_PJ4_IRQ (1 << 5)
38#define MMP2_ICU_INT_ROUTE_PJ4_FIQ (1 << 6)
39
37struct icu_chip_data { 40struct icu_chip_data {
38 int nr_irqs; 41 int nr_irqs;
39 unsigned int virq_base; 42 unsigned int virq_base;
@@ -190,7 +193,8 @@ static const struct mmp_intc_conf mmp_conf = {
190static const struct mmp_intc_conf mmp2_conf = { 193static const struct mmp_intc_conf mmp2_conf = {
191 .conf_enable = 0x20, 194 .conf_enable = 0x20,
192 .conf_disable = 0x0, 195 .conf_disable = 0x0,
193 .conf_mask = 0x7f, 196 .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ |
197 MMP2_ICU_INT_ROUTE_PJ4_FIQ,
194}; 198};
195 199
196static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) 200static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 071b4cbdf010..c848a7cc502e 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -319,7 +319,7 @@
319#define GITS_TYPER_PLPIS (1UL << 0) 319#define GITS_TYPER_PLPIS (1UL << 0)
320#define GITS_TYPER_VLPIS (1UL << 1) 320#define GITS_TYPER_VLPIS (1UL << 1)
321#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4 321#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4
322#define GITS_TYPER_ITT_ENTRY_SIZE(r) ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0x1f) + 1) 322#define GITS_TYPER_ITT_ENTRY_SIZE(r) ((((r) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) & 0xf) + 1)
323#define GITS_TYPER_IDBITS_SHIFT 8 323#define GITS_TYPER_IDBITS_SHIFT 8
324#define GITS_TYPER_DEVBITS_SHIFT 13 324#define GITS_TYPER_DEVBITS_SHIFT 13
325#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) 325#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)