History

Merge tag 'irq-urgent-2026-05-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull IRQ fixes from Ingo Molnar: - Fix use-after-free in irq_work_single() on PREEMPT_RT (Jiayuan Chen) - Don't call add_interrupt_randomness() for NMIs in handle_percpu_devid_irq() (Mark Rutland) - Remove unused function in the ath79-cpu irqchip driver causing LKP CI build warnings (Rosen Penev) - Fix IRQ allocation/teardown leakage regressions in the GICv5 irqchip driver (Sascha Bischoff) - Fix an IRQ trigger type regression in the Meson S4 SoC irqchip driver (Xianwei Zhao) - Fix CPU offlining regression in the RiscV IMSIC irqchip driver (Yong-Xuan Wang) * tag 'irq-urgent-2026-05-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: irq_work: Fix use-after-free in irq_work_single() on PREEMPT_RT irqchip/riscv-imsic: Clear interrupt move state during CPU offlining irqchip/meson-gpio: Use the correct register in meson_s4_gpio_irq_set_type() irqchip/ath79-cpu: Remove unused function genirq/chip: Don't call add_interrupt_randomness() for NMIs irqchip/gic-v5: Allocate ITS parent LPIs as a range irqchip/gic-v5: Support range allocation for LPIs irqchip/gic-v5: Move LPI allocation into the LPI domain

Linus Torvalds committed 6 months ago

Commit ec296eb2 parents f7c7994 91840be8 files · +77 −86Browse files

Unified · Split

8 files
  1. drivers/irqchip/irq-ath79-cpu.c +0 −7
  2. drivers/irqchip/irq-gic-v5-its.c +8 −26
  3. drivers/irqchip/irq-gic-v5.c +52 −46
  4. drivers/irqchip/irq-meson-gpio.c +1 −2
  5. drivers/irqchip/irq-riscv-imsic-early.c +2 −0
  6. include/linux/irqchip/arm-gic-v5.h +0 −3
  7. kernel/irq/chip.c +7 −2
  8. kernel/irq_work.c +7 −0
drivers/irqchip/irq-ath79-cpu.c+0−7
@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init( · 84 unmodified lines
8585 }
8686 IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
8787 ar79_cpu_intc_of_init);
88−
89−void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3)
90−{
91− irq_wb_chan[2] = irq_wb_chan2;
92− irq_wb_chan[3] = irq_wb_chan3;
93− mips_cpu_irq_init();
94−}
drivers/irqchip/irq-gic-v5-its.c+8−26
@@ -929,14 +929,15 @@ static void gicv5_its_free_eventid(struct gicv5_its_dev *its_dev, u32 event_id_b · 928 unmodified lines
929929 static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
930930 unsigned int nr_irqs, void *arg)
931931 {
932− u32 device_id, event_id_base, lpi;
933932 struct gicv5_its_dev *its_dev;
933+ u32 device_id, event_id_base;
934934 msi_alloc_info_t *info = arg;
935935 irq_hw_number_t hwirq;
936936 struct irq_data *irqd;
937937 int ret, i;
938938
939939 its_dev = info->scratchpad[0].ptr;
940+ device_id = its_dev->device_id;
940941
941942 ret = gicv5_its_alloc_eventid(its_dev, info, nr_irqs, &event_id_base);
942943 if (ret)
@@ -946,22 +947,11 @@ static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int vi · 3 unmodified lines
946947 if (ret)
947948 goto out_eventid;
948949
949− device_id = its_dev->device_id;
950+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, NULL);
951+ if (ret)
952+ goto out_eventid;
950953
951954 for (i = 0; i < nr_irqs; i++) {
952− ret = gicv5_alloc_lpi();
953− if (ret < 0) {
954− pr_debug("Failed to find free LPI!\n");
955− goto out_free_irqs;
956− }
957− lpi = ret;
958−
959− ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &lpi);
960− if (ret) {
961− gicv5_free_lpi(lpi);
962− goto out_free_irqs;
963− }
964−
965955 /*
966956 * Store eventid and deviceid into the hwirq for later use.
967957 *
@@ -980,13 +970,6 @@ static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int vi · 12 unmodified lines
980970
981971 return 0;
982972
983−out_free_irqs:
984− while (--i >= 0) {
985− irqd = irq_domain_get_irq_data(domain, virq + i);
986− gicv5_free_lpi(irqd->parent_data->hwirq);
987− irq_domain_reset_irq_data(irqd);
988− irq_domain_free_irqs_parent(domain, virq + i, 1);
989− }
990973 out_eventid:
991974 gicv5_its_free_eventid(its_dev, event_id_base, nr_irqs);
992975 return ret;
@@ -1009,15 +992,14 @@ static void gicv5_its_irq_domain_free(struct irq_domain *domain, unsigned int vi · 16 unmodified lines
1009992 bitmap_release_region(its_dev->event_map, event_id_base,
1010993 get_count_order(nr_irqs));
1011994
1012− /* Hierarchically free irq data */
1013995 for (i = 0; i < nr_irqs; i++) {
1014996 d = irq_domain_get_irq_data(domain, virq + i);
1015−
1016− gicv5_free_lpi(d->parent_data->hwirq);
1017997 irq_domain_reset_irq_data(d);
1018− irq_domain_free_irqs_parent(domain, virq + i, 1);
1019998 }
1020999
1000+ /* Hierarchically free irq data */
1001+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
1002+
10211003 gicv5_its_syncr(its, its_dev);
10221004 gicv5_irs_syncr();
10231005 }
drivers/irqchip/irq-gic-v5.c+52−46
@@ -59,16 +59,6 @@ static void release_lpi(u32 lpi) · 58 unmodified lines
5959 ida_free(&lpi_ida, lpi);
6060 }
6161
62−int gicv5_alloc_lpi(void)
63−{
64− return alloc_lpi();
65−}
66−
67−void gicv5_free_lpi(u32 lpi)
68−{
69− release_lpi(lpi);
70−}
71−
7262 static void gicv5_ppi_priority_init(void)
7363 {
7464 write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_PRI_MI), SYS_ICC_PPI_PRIORITYR0_EL1);
@@ -806,38 +796,64 @@ static void gicv5_lpi_config_reset(struct irq_data *d) · 731 unmodified lines
806796 gicv5_lpi_irq_write_pending_state(d, false);
807797 }
808798
799+static void gicv5_irq_lpi_domain_free(struct irq_domain *domain, unsigned int virq,
800+ unsigned int nr_irqs)
801+{
802+ struct irq_data *d;
803+
804+ for (unsigned int i = 0; i < nr_irqs; i++, virq++) {
805+ d = irq_domain_get_irq_data(domain, virq);
806+
807+ release_lpi(d->hwirq);
808+
809+ irq_set_handler(virq, NULL);
810+ irq_domain_reset_irq_data(d);
811+ }
812+}
813+
809814 static int gicv5_irq_lpi_domain_alloc(struct irq_domain *domain, unsigned int virq,
810815 unsigned int nr_irqs, void *arg)
811816 {
812817 irq_hw_number_t hwirq;
813818 struct irq_data *irqd;
814− u32 *lpi = arg;
819+ unsigned int i;
815820 int ret;
816821
817− if (WARN_ON_ONCE(nr_irqs != 1))
818− return -EINVAL;
822+ for (i = 0; i < nr_irqs; i++) {
823+ ret = alloc_lpi();
824+ if (ret < 0)
825+ goto out_free_lpis;
826+ hwirq = ret;
827+
828+ ret = gicv5_irs_iste_alloc(hwirq);
829+ if (ret < 0) {
830+ /* Undo partial state first, then clean up the rest */
831+ release_lpi(hwirq);
832+ goto out_free_lpis;
833+ }
819834
820− hwirq = *lpi;
835+ irqd = irq_domain_get_irq_data(domain, virq + i);
821836
822− irqd = irq_domain_get_irq_data(domain, virq);
837+ irq_domain_set_info(domain, virq + i, hwirq, &gicv5_lpi_irq_chip,
838+ NULL, handle_fasteoi_irq, NULL, NULL);
839+ irqd_set_single_target(irqd);
823840
824− irq_domain_set_info(domain, virq, hwirq, &gicv5_lpi_irq_chip, NULL,
825− handle_fasteoi_irq, NULL, NULL);
826− irqd_set_single_target(irqd);
841+ gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI);
842+ gicv5_lpi_config_reset(irqd);
843+ }
827844
828− ret = gicv5_irs_iste_alloc(hwirq);
829− if (ret < 0)
830− return ret;
845+ return 0;
831846
832− gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI);
833− gicv5_lpi_config_reset(irqd);
847+out_free_lpis:
848+ if (i)
849+ gicv5_irq_lpi_domain_free(domain, virq, i);
834850
835− return 0;
851+ return ret;
836852 }
837853
838854 static const struct irq_domain_ops gicv5_irq_lpi_domain_ops = {
839855 .alloc = gicv5_irq_lpi_domain_alloc,
840− .free = gicv5_irq_domain_free,
856+ .free = gicv5_irq_lpi_domain_free,
841857 };
842858
843859 void __init gicv5_init_lpi_domain(void)
@@ -858,30 +874,21 @@ static int gicv5_irq_ipi_domain_alloc(struct irq_domain *domain, unsigned int vi · 14 unmodified lines
858874 unsigned int nr_irqs, void *arg)
859875 {
860876 struct irq_data *irqd;
861− int ret, i;
862− u32 lpi;
863−
864− for (i = 0; i < nr_irqs; i++) {
865− ret = gicv5_alloc_lpi();
866− if (ret < 0)
867− return ret;
868−
869− lpi = ret;
877+ int ret;
870878
871− ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &lpi);
872− if (ret) {
873− gicv5_free_lpi(lpi);
874− return ret;
875− }
879+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
880+ if (ret)
881+ return ret;
876882
877− irqd = irq_domain_get_irq_data(domain, virq + i);
883+ for (unsigned int i = 0; i < nr_irqs; i++, virq++) {
884+ irqd = irq_domain_get_irq_data(domain, virq);
878885
879− irq_domain_set_hwirq_and_chip(domain, virq + i, i,
880− &gicv5_ipi_irq_chip, NULL);
886+ irq_domain_set_hwirq_and_chip(domain, virq, i,
887+ &gicv5_ipi_irq_chip, NULL);
881888
882889 irqd_set_single_target(irqd);
883890
884− irq_set_handler(virq + i, handle_percpu_irq);
891+ irq_set_handler(virq, handle_percpu_irq);
885892 }
886893
887894 return 0;
@@ -899,12 +906,11 @@ static void gicv5_irq_ipi_domain_free(struct irq_domain *domain, unsigned int vi · 11 unmodified lines
899906 if (!d)
900907 return;
901908
902− gicv5_free_lpi(d->parent_data->hwirq);
903−
904909 irq_set_handler(virq + i, NULL);
905910 irq_domain_reset_irq_data(d);
906− irq_domain_free_irqs_parent(domain, virq + i, 1);
907911 }
912+
913+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
908914 }
909915
910916 static const struct irq_domain_ops gicv5_irq_ipi_domain_ops = {
drivers/irqchip/irq-meson-gpio.c+1−2
@@ -415,8 +415,7 @@ static int meson_s4_gpio_irq_set_type(struct meson_gpio_irq_controller *ctl, · 414 unmodified lines
415415 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
416416 val |= BIT(ctl->params->edge_single_offset + idx);
417417
418− meson_gpio_irq_update_bits(ctl, params->edge_pol_reg,
419− BIT(idx) | BIT(12 + idx), val);
418+ meson_gpio_irq_update_bits(ctl, REG_EDGE_POL, BIT(idx) | BIT(12 + idx), val);
420419 return 0;
421420 };
422421
drivers/irqchip/irq-riscv-imsic-early.c+2−0
@@ -158,6 +158,8 @@ static int imsic_dying_cpu(unsigned int cpu) · 157 unmodified lines
158158 /* Cleanup IPIs */
159159 imsic_ipi_dying_cpu();
160160
161+ imsic_local_sync_all(false);
162+
161163 /* Mark per-CPU IMSIC state as offline */
162164 imsic_state_offline();
163165
include/linux/irqchip/arm-gic-v5.h+0−3
@@ -425,9 +425,6 @@ struct gicv5_its_itt_cfg { · 424 unmodified lines
425425 void gicv5_init_lpis(u32 max);
426426 void gicv5_deinit_lpis(void);
427427
428−int gicv5_alloc_lpi(void);
429−void gicv5_free_lpi(u32 lpi);
430−
431428 void __init gicv5_its_of_probe(struct device_node *parent);
432429 void __init gicv5_its_acpi_probe(void);
433430 #endif
kernel/irq/chip.c+7−2
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <linux/interrupt.h>
1515 #include <linux/kernel_stat.h>
1616 #include <linux/irqdomain.h>
17+#include <linux/preempt.h>
1718 #include <linux/random.h>
1819
1920 #include <trace/events/irq.h>
@@ -893,7 +894,10 @@ void handle_percpu_irq(struct irq_desc *desc) · 873 unmodified lines
893894 *
894895 * action->percpu_dev_id is a pointer to percpu variables which
895896 * contain the real device id for the cpu on which this handler is
896− * called
897+ * called.
898+ *
899+ * May be used for NMI interrupt lines, and so may be called in IRQ or NMI
900+ * context.
897901 */
898902 void handle_percpu_devid_irq(struct irq_desc *desc)
899903 {
@@ -930,7 +934,8 @@ void handle_percpu_devid_irq(struct irq_desc *desc) · 30 unmodified lines
930934 enabled ? " and unmasked" : "", irq, cpu);
931935 }
932936
933− add_interrupt_randomness(irq);
937+ if (!in_nmi())
938+ add_interrupt_randomness(irq);
934939
935940 if (chip->irq_eoi)
936941 chip->irq_eoi(&desc->irq_data);
kernel/irq_work.c+7−0
@@ -292,6 +292,12 @@ void irq_work_sync(struct irq_work *work) · 291 unmodified lines
292292 !arch_irq_work_has_interrupt()) {
293293 rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work),
294294 TASK_UNINTERRUPTIBLE);
295+ /*
296+ * Ensure irq_work_single() does not access @work
297+ * after removing IRQ_WORK_BUSY. It is always
298+ * accessed within a RCU-read section.
299+ */
300+ synchronize_rcu();
295301 return;
296302 }
297303
@@ -302,6 +308,7 @@ EXPORT_SYMBOL_GPL(irq_work_sync); · 4 unmodified lines
302308
303309 static void run_irq_workd(unsigned int cpu)
304310 {
311+ guard(rcu)();
305312 irq_work_run_list(this_cpu_ptr(&lazy_list));
306313 }
307314