diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2019-06-16 18:40:01 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2019-06-16 18:40:01 -0400 |
commit | a52548dd0491a544558e971cd5963501e1a2024d (patch) | |
tree | cdac94b5ac88a2896ecffe1fe48f2452edd1cc22 | |
parent | fb4e0592654adb31bc6f3a738d6499b816a655d6 (diff) | |
parent | a050fa5476d418fc16b25abe168b3d38ba11e13c (diff) |
Merge tag 'irqchip-5.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/urgent
Pull irqchip fixes for 5.2 from Marc Zyngier:
- CSky mpintc: allow interrupts to be broadcast
- TI sci-inta: fix error handling
- MIPS GIC: Fix local interrupt mapping
- ITS: Fix command queue wrapping
-rw-r--r-- | arch/mips/include/asm/mips-gic.h | 30 | ||||
-rw-r--r-- | drivers/irqchip/irq-csky-mpintc.c | 15 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 35 | ||||
-rw-r--r-- | drivers/irqchip/irq-mips-gic.c | 4 | ||||
-rw-r--r-- | drivers/irqchip/irq-ti-sci-inta.c | 4 |
5 files changed, 71 insertions, 17 deletions
diff --git a/arch/mips/include/asm/mips-gic.h b/arch/mips/include/asm/mips-gic.h index 558059a8f218..0277b56157af 100644 --- a/arch/mips/include/asm/mips-gic.h +++ b/arch/mips/include/asm/mips-gic.h | |||
@@ -315,6 +315,36 @@ static inline bool mips_gic_present(void) | |||
315 | } | 315 | } |
316 | 316 | ||
317 | /** | 317 | /** |
318 | * mips_gic_vx_map_reg() - Return GIC_Vx_<intr>_MAP register offset | ||
319 | * @intr: A GIC local interrupt | ||
320 | * | ||
321 | * Determine the index of the GIC_VL_<intr>_MAP or GIC_VO_<intr>_MAP register | ||
322 | * within the block of GIC map registers. This is almost the same as the order | ||
323 | * of interrupts in the pending & mask registers, as used by enum | ||
324 | * mips_gic_local_interrupt, but moves the FDC interrupt & thus offsets the | ||
325 | * interrupts after it... | ||
326 | * | ||
327 | * Return: The map register index corresponding to @intr. | ||
328 | * | ||
329 | * The return value is suitable for use with the (read|write)_gic_v[lo]_map | ||
330 | * accessor functions. | ||
331 | */ | ||
332 | static inline unsigned int | ||
333 | mips_gic_vx_map_reg(enum mips_gic_local_interrupt intr) | ||
334 | { | ||
335 | /* WD, Compare & Timer are 1:1 */ | ||
336 | if (intr <= GIC_LOCAL_INT_TIMER) | ||
337 | return intr; | ||
338 | |||
339 | /* FDC moves to after Timer... */ | ||
340 | if (intr == GIC_LOCAL_INT_FDC) | ||
341 | return GIC_LOCAL_INT_TIMER + 1; | ||
342 | |||
343 | /* As a result everything else is offset by 1 */ | ||
344 | return intr + 1; | ||
345 | } | ||
346 | |||
347 | /** | ||
318 | * gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq | 348 | * gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq |
319 | * | 349 | * |
320 | * Determine the virq number to use for the coprocessor 0 count/compare | 350 | * Determine the virq number to use for the coprocessor 0 count/compare |
diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c index c67c961ab6cc..a4c1aacba1ff 100644 --- a/drivers/irqchip/irq-csky-mpintc.c +++ b/drivers/irqchip/irq-csky-mpintc.c | |||
@@ -89,8 +89,19 @@ static int csky_irq_set_affinity(struct irq_data *d, | |||
89 | if (cpu >= nr_cpu_ids) | 89 | if (cpu >= nr_cpu_ids) |
90 | return -EINVAL; | 90 | return -EINVAL; |
91 | 91 | ||
92 | /* Enable interrupt destination */ | 92 | /* |
93 | cpu |= BIT(31); | 93 | * The csky,mpintc could support auto irq deliver, but it only |
94 | * could deliver external irq to one cpu or all cpus. So it | ||
95 | * doesn't support deliver external irq to a group of cpus | ||
96 | * with cpu_mask. | ||
97 | * SO we only use auto deliver mode when affinity mask_val is | ||
98 | * equal to cpu_present_mask. | ||
99 | * | ||
100 | */ | ||
101 | if (cpumask_equal(mask_val, cpu_present_mask)) | ||
102 | cpu = 0; | ||
103 | else | ||
104 | cpu |= BIT(31); | ||
94 | 105 | ||
95 | writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset); | 106 | writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset); |
96 | 107 | ||
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1e364d3ad9c5..f0523916232d 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c | |||
@@ -744,32 +744,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd) | |||
744 | } | 744 | } |
745 | 745 | ||
746 | static int its_wait_for_range_completion(struct its_node *its, | 746 | static int its_wait_for_range_completion(struct its_node *its, |
747 | struct its_cmd_block *from, | 747 | u64 prev_idx, |
748 | struct its_cmd_block *to) | 748 | struct its_cmd_block *to) |
749 | { | 749 | { |
750 | u64 rd_idx, from_idx, to_idx; | 750 | u64 rd_idx, to_idx, linear_idx; |
751 | u32 count = 1000000; /* 1s! */ | 751 | u32 count = 1000000; /* 1s! */ |
752 | 752 | ||
753 | from_idx = its_cmd_ptr_to_offset(its, from); | 753 | /* Linearize to_idx if the command set has wrapped around */ |
754 | to_idx = its_cmd_ptr_to_offset(its, to); | 754 | to_idx = its_cmd_ptr_to_offset(its, to); |
755 | if (to_idx < prev_idx) | ||
756 | to_idx += ITS_CMD_QUEUE_SZ; | ||
757 | |||
758 | linear_idx = prev_idx; | ||
755 | 759 | ||
756 | while (1) { | 760 | while (1) { |
761 | s64 delta; | ||
762 | |||
757 | rd_idx = readl_relaxed(its->base + GITS_CREADR); | 763 | rd_idx = readl_relaxed(its->base + GITS_CREADR); |
758 | 764 | ||
759 | /* Direct case */ | 765 | /* |
760 | if (from_idx < to_idx && rd_idx >= to_idx) | 766 | * Compute the read pointer progress, taking the |
761 | break; | 767 | * potential wrap-around into account. |
768 | */ | ||
769 | delta = rd_idx - prev_idx; | ||
770 | if (rd_idx < prev_idx) | ||
771 | delta += ITS_CMD_QUEUE_SZ; | ||
762 | 772 | ||
763 | /* Wrapped case */ | 773 | linear_idx += delta; |
764 | if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx) | 774 | if (linear_idx >= to_idx) |
765 | break; | 775 | break; |
766 | 776 | ||
767 | count--; | 777 | count--; |
768 | if (!count) { | 778 | if (!count) { |
769 | pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n", | 779 | pr_err_ratelimited("ITS queue timeout (%llu %llu)\n", |
770 | from_idx, to_idx, rd_idx); | 780 | to_idx, linear_idx); |
771 | return -1; | 781 | return -1; |
772 | } | 782 | } |
783 | prev_idx = rd_idx; | ||
773 | cpu_relax(); | 784 | cpu_relax(); |
774 | udelay(1); | 785 | udelay(1); |
775 | } | 786 | } |
@@ -786,6 +797,7 @@ void name(struct its_node *its, \ | |||
786 | struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \ | 797 | struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \ |
787 | synctype *sync_obj; \ | 798 | synctype *sync_obj; \ |
788 | unsigned long flags; \ | 799 | unsigned long flags; \ |
800 | u64 rd_idx; \ | ||
789 | \ | 801 | \ |
790 | raw_spin_lock_irqsave(&its->lock, flags); \ | 802 | raw_spin_lock_irqsave(&its->lock, flags); \ |
791 | \ | 803 | \ |
@@ -807,10 +819,11 @@ void name(struct its_node *its, \ | |||
807 | } \ | 819 | } \ |
808 | \ | 820 | \ |
809 | post: \ | 821 | post: \ |
822 | rd_idx = readl_relaxed(its->base + GITS_CREADR); \ | ||
810 | next_cmd = its_post_commands(its); \ | 823 | next_cmd = its_post_commands(its); \ |
811 | raw_spin_unlock_irqrestore(&its->lock, flags); \ | 824 | raw_spin_unlock_irqrestore(&its->lock, flags); \ |
812 | \ | 825 | \ |
813 | if (its_wait_for_range_completion(its, cmd, next_cmd)) \ | 826 | if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \ |
814 | pr_err_ratelimited("ITS cmd %ps failed\n", builder); \ | 827 | pr_err_ratelimited("ITS cmd %ps failed\n", builder); \ |
815 | } | 828 | } |
816 | 829 | ||
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index d32268cc1174..f3985469c221 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c | |||
@@ -388,7 +388,7 @@ static void gic_all_vpes_irq_cpu_online(struct irq_data *d) | |||
388 | intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); | 388 | intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); |
389 | cd = irq_data_get_irq_chip_data(d); | 389 | cd = irq_data_get_irq_chip_data(d); |
390 | 390 | ||
391 | write_gic_vl_map(intr, cd->map); | 391 | write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map); |
392 | if (cd->mask) | 392 | if (cd->mask) |
393 | write_gic_vl_smask(BIT(intr)); | 393 | write_gic_vl_smask(BIT(intr)); |
394 | } | 394 | } |
@@ -517,7 +517,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, | |||
517 | spin_lock_irqsave(&gic_lock, flags); | 517 | spin_lock_irqsave(&gic_lock, flags); |
518 | for_each_online_cpu(cpu) { | 518 | for_each_online_cpu(cpu) { |
519 | write_gic_vl_other(mips_cm_vp_id(cpu)); | 519 | write_gic_vl_other(mips_cm_vp_id(cpu)); |
520 | write_gic_vo_map(intr, map); | 520 | write_gic_vo_map(mips_gic_vx_map_reg(intr), map); |
521 | } | 521 | } |
522 | spin_unlock_irqrestore(&gic_lock, flags); | 522 | spin_unlock_irqrestore(&gic_lock, flags); |
523 | 523 | ||
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index 011b60a49e3f..ef4d625d2d80 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c | |||
@@ -159,9 +159,9 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom | |||
159 | parent_fwspec.param[1] = vint_desc->vint_id; | 159 | parent_fwspec.param[1] = vint_desc->vint_id; |
160 | 160 | ||
161 | parent_virq = irq_create_fwspec_mapping(&parent_fwspec); | 161 | parent_virq = irq_create_fwspec_mapping(&parent_fwspec); |
162 | if (parent_virq <= 0) { | 162 | if (parent_virq == 0) { |
163 | kfree(vint_desc); | 163 | kfree(vint_desc); |
164 | return ERR_PTR(parent_virq); | 164 | return ERR_PTR(-EINVAL); |
165 | } | 165 | } |
166 | vint_desc->parent_virq = parent_virq; | 166 | vint_desc->parent_virq = parent_virq; |
167 | 167 | ||