diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 101 | ||||
| -rw-r--r-- | drivers/irqchip/irq-mmp.c | 6 |
2 files changed, 84 insertions, 23 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 | */ |
| 101 | struct its_node { | 105 | struct 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 | ||
| 161 | static struct { | 167 | static 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 | ||
| 2071 | static 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 | |||
| 2062 | static void its_cpu_init_lpis(void) | 2094 | static 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); |
| 2149 | out: | 2205 | out: |
| @@ -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)); |
| 2463 | out: | 2524 | out: |
| 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 | ||
| 2468 | static struct msi_domain_ops its_msi_domain_ops = { | 2530 | static 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) | |||
| 2755 | static void its_vpe_deschedule(struct its_vpe *vpe) | 2826 | static 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 | |||
| 37 | struct icu_chip_data { | 40 | struct 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 = { | |||
| 190 | static const struct mmp_intc_conf mmp2_conf = { | 193 | static 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 | ||
| 196 | static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) | 200 | static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) |
