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
85}85}
86IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",86IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
87 ar79_cpu_intc_of_init);87 ar79_cpu_intc_of_init);
88
89void __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
929static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,929static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
930 unsigned int nr_irqs, void *arg)930 unsigned int nr_irqs, void *arg)
931{931{
932 u32 device_id, event_id_base, lpi;
933 struct gicv5_its_dev *its_dev;932 struct gicv5_its_dev *its_dev;
933 u32 device_id, event_id_base;
934 msi_alloc_info_t *info = arg;934 msi_alloc_info_t *info = arg;
935 irq_hw_number_t hwirq;935 irq_hw_number_t hwirq;
936 struct irq_data *irqd;936 struct irq_data *irqd;
937 int ret, i;937 int ret, i;
938 938
939 its_dev = info->scratchpad[0].ptr;939 its_dev = info->scratchpad[0].ptr;
940 device_id = its_dev->device_id;
940 941
941 ret = gicv5_its_alloc_eventid(its_dev, info, nr_irqs, &event_id_base);942 ret = gicv5_its_alloc_eventid(its_dev, info, nr_irqs, &event_id_base);
942 if (ret)943 if (ret)
@@ -946,22 +947,11 @@ static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int vi · 3 unmodified lines
946 if (ret)947 if (ret)
947 goto out_eventid;948 goto out_eventid;
948 949
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;
950 953
951 for (i = 0; i < nr_irqs; i++) {954 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
965 /*955 /*
966 * Store eventid and deviceid into the hwirq for later use.956 * Store eventid and deviceid into the hwirq for later use.
967 *957 *
@@ -980,13 +970,6 @@ static int gicv5_its_irq_domain_alloc(struct irq_domain *domain, unsigned int vi · 12 unmodified lines
980 970
981 return 0;971 return 0;
982 972
983out_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 }
990out_eventid:973out_eventid:
991 gicv5_its_free_eventid(its_dev, event_id_base, nr_irqs);974 gicv5_its_free_eventid(its_dev, event_id_base, nr_irqs);
992 return ret;975 return ret;
@@ -1009,15 +992,14 @@ static void gicv5_its_irq_domain_free(struct irq_domain *domain, unsigned int vi · 16 unmodified lines
1009 bitmap_release_region(its_dev->event_map, event_id_base,992 bitmap_release_region(its_dev->event_map, event_id_base,
1010 get_count_order(nr_irqs));993 get_count_order(nr_irqs));
1011 994
1012 /* Hierarchically free irq data */
1013 for (i = 0; i < nr_irqs; i++) {995 for (i = 0; i < nr_irqs; i++) {
1014 d = irq_domain_get_irq_data(domain, virq + i);996 d = irq_domain_get_irq_data(domain, virq + i);
1015
1016 gicv5_free_lpi(d->parent_data->hwirq);
1017 irq_domain_reset_irq_data(d);997 irq_domain_reset_irq_data(d);
1018 irq_domain_free_irqs_parent(domain, virq + i, 1);
1019 }998 }
1020 999
1000 /* Hierarchically free irq data */
1001 irq_domain_free_irqs_parent(domain, virq, nr_irqs);
1002
1021 gicv5_its_syncr(its, its_dev);1003 gicv5_its_syncr(its, its_dev);
1022 gicv5_irs_syncr();1004 gicv5_irs_syncr();
1023}1005}
drivers/irqchip/irq-gic-v5.c+52−46
@@ -59,16 +59,6 @@ static void release_lpi(u32 lpi) · 58 unmodified lines
59 ida_free(&lpi_ida, lpi);59 ida_free(&lpi_ida, lpi);
60}60}
61 61
62int gicv5_alloc_lpi(void)
63{
64 return alloc_lpi();
65}
66
67void gicv5_free_lpi(u32 lpi)
68{
69 release_lpi(lpi);
70}
71
72static void gicv5_ppi_priority_init(void)62static void gicv5_ppi_priority_init(void)
73{63{
74 write_sysreg_s(REPEAT_BYTE(GICV5_IRQ_PRI_MI), SYS_ICC_PPI_PRIORITYR0_EL1);64 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
806 gicv5_lpi_irq_write_pending_state(d, false);796 gicv5_lpi_irq_write_pending_state(d, false);
807}797}
808 798
799static 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
809static int gicv5_irq_lpi_domain_alloc(struct irq_domain *domain, unsigned int virq,814static int gicv5_irq_lpi_domain_alloc(struct irq_domain *domain, unsigned int virq,
810 unsigned int nr_irqs, void *arg)815 unsigned int nr_irqs, void *arg)
811{816{
812 irq_hw_number_t hwirq;817 irq_hw_number_t hwirq;
813 struct irq_data *irqd;818 struct irq_data *irqd;
814 u32 *lpi = arg;819 unsigned int i;
815 int ret;820 int ret;
816 821
817 if (WARN_ON_ONCE(nr_irqs != 1))822 for (i = 0; i < nr_irqs; i++) {
818 return -EINVAL;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 }
819 834
820 hwirq = *lpi;835 irqd = irq_domain_get_irq_data(domain, virq + i);
821 836
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);
823 840
824 irq_domain_set_info(domain, virq, hwirq, &gicv5_lpi_irq_chip, NULL,841 gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI);
825 handle_fasteoi_irq, NULL, NULL);842 gicv5_lpi_config_reset(irqd);
826 irqd_set_single_target(irqd);843 }
827 844
828 ret = gicv5_irs_iste_alloc(hwirq);845 return 0;
829 if (ret < 0)
830 return ret;
831 846
832 gicv5_hwirq_init(hwirq, GICV5_IRQ_PRI_MI, GICV5_HWIRQ_TYPE_LPI);847out_free_lpis:
833 gicv5_lpi_config_reset(irqd);848 if (i)
849 gicv5_irq_lpi_domain_free(domain, virq, i);
834 850
835 return 0;851 return ret;
836}852}
837 853
838static const struct irq_domain_ops gicv5_irq_lpi_domain_ops = {854static const struct irq_domain_ops gicv5_irq_lpi_domain_ops = {
839 .alloc = gicv5_irq_lpi_domain_alloc,855 .alloc = gicv5_irq_lpi_domain_alloc,
840 .free = gicv5_irq_domain_free,856 .free = gicv5_irq_lpi_domain_free,
841};857};
842 858
843void __init gicv5_init_lpi_domain(void)859void __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
858 unsigned int nr_irqs, void *arg)874 unsigned int nr_irqs, void *arg)
859{875{
860 struct irq_data *irqd;876 struct irq_data *irqd;
861 int ret, i;877 int ret;
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;
870 878
871 ret = irq_domain_alloc_irqs_parent(domain, virq + i, 1, &lpi);879 ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
872 if (ret) {880 if (ret)
873 gicv5_free_lpi(lpi);881 return ret;
874 return ret;
875 }
876 882
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);
878 885
879 irq_domain_set_hwirq_and_chip(domain, virq + i, i,886 irq_domain_set_hwirq_and_chip(domain, virq, i,
880 &gicv5_ipi_irq_chip, NULL);887 &gicv5_ipi_irq_chip, NULL);
881 888
882 irqd_set_single_target(irqd);889 irqd_set_single_target(irqd);
883 890
884 irq_set_handler(virq + i, handle_percpu_irq);891 irq_set_handler(virq, handle_percpu_irq);
885 }892 }
886 893
887 return 0;894 return 0;
@@ -899,12 +906,11 @@ static void gicv5_irq_ipi_domain_free(struct irq_domain *domain, unsigned int vi · 11 unmodified lines
899 if (!d)906 if (!d)
900 return;907 return;
901 908
902 gicv5_free_lpi(d->parent_data->hwirq);
903
904 irq_set_handler(virq + i, NULL);909 irq_set_handler(virq + i, NULL);
905 irq_domain_reset_irq_data(d);910 irq_domain_reset_irq_data(d);
906 irq_domain_free_irqs_parent(domain, virq + i, 1);
907 }911 }
912
913 irq_domain_free_irqs_parent(domain, virq, nr_irqs);
908}914}
909 915
910static const struct irq_domain_ops gicv5_irq_ipi_domain_ops = {916static 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
415 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))415 if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
416 val |= BIT(ctl->params->edge_single_offset + idx);416 val |= BIT(ctl->params->edge_single_offset + idx);
417 417
418 meson_gpio_irq_update_bits(ctl, params->edge_pol_reg,418 meson_gpio_irq_update_bits(ctl, REG_EDGE_POL, BIT(idx) | BIT(12 + idx), val);
419 BIT(idx) | BIT(12 + idx), val);
420 return 0;419 return 0;
421};420};
422 421
drivers/irqchip/irq-riscv-imsic-early.c+2−0
@@ -158,6 +158,8 @@ static int imsic_dying_cpu(unsigned int cpu) · 157 unmodified lines
158 /* Cleanup IPIs */158 /* Cleanup IPIs */
159 imsic_ipi_dying_cpu();159 imsic_ipi_dying_cpu();
160 160
161 imsic_local_sync_all(false);
162
161 /* Mark per-CPU IMSIC state as offline */163 /* Mark per-CPU IMSIC state as offline */
162 imsic_state_offline();164 imsic_state_offline();
163 165
include/linux/irqchip/arm-gic-v5.h+0−3
@@ -425,9 +425,6 @@ struct gicv5_its_itt_cfg { · 424 unmodified lines
425void gicv5_init_lpis(u32 max);425void gicv5_init_lpis(u32 max);
426void gicv5_deinit_lpis(void);426void gicv5_deinit_lpis(void);
427 427
428int gicv5_alloc_lpi(void);
429void gicv5_free_lpi(u32 lpi);
430
431void __init gicv5_its_of_probe(struct device_node *parent);428void __init gicv5_its_of_probe(struct device_node *parent);
432void __init gicv5_its_acpi_probe(void);429void __init gicv5_its_acpi_probe(void);
433#endif430#endif
kernel/irq/chip.c+7−2
@@ -14,6 +14,7 @@ · 13 unmodified lines
14#include <linux/interrupt.h>14#include <linux/interrupt.h>
15#include <linux/kernel_stat.h>15#include <linux/kernel_stat.h>
16#include <linux/irqdomain.h>16#include <linux/irqdomain.h>
17#include <linux/preempt.h>
17#include <linux/random.h>18#include <linux/random.h>
18 19
19#include <trace/events/irq.h>20#include <trace/events/irq.h>
@@ -893,7 +894,10 @@ void handle_percpu_irq(struct irq_desc *desc) · 873 unmodified lines
893 *894 *
894 * action->percpu_dev_id is a pointer to percpu variables which895 * action->percpu_dev_id is a pointer to percpu variables which
895 * contain the real device id for the cpu on which this handler is896 * contain the real device id for the cpu on which this handler is
896 * called897 * called.
898 *
899 * May be used for NMI interrupt lines, and so may be called in IRQ or NMI
900 * context.
897 */901 */
898void handle_percpu_devid_irq(struct irq_desc *desc)902void handle_percpu_devid_irq(struct irq_desc *desc)
899{903{
@@ -930,7 +934,8 @@ void handle_percpu_devid_irq(struct irq_desc *desc) · 30 unmodified lines
930 enabled ? " and unmasked" : "", irq, cpu);934 enabled ? " and unmasked" : "", irq, cpu);
931 }935 }
932 936
933 add_interrupt_randomness(irq);937 if (!in_nmi())
938 add_interrupt_randomness(irq);
934 939
935 if (chip->irq_eoi)940 if (chip->irq_eoi)
936 chip->irq_eoi(&desc->irq_data);941 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
292 !arch_irq_work_has_interrupt()) {292 !arch_irq_work_has_interrupt()) {
293 rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work),293 rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work),
294 TASK_UNINTERRUPTIBLE);294 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();
295 return;301 return;
296 }302 }
297 303
@@ -302,6 +308,7 @@ EXPORT_SYMBOL_GPL(irq_work_sync); · 4 unmodified lines
302 308
303static void run_irq_workd(unsigned int cpu)309static void run_irq_workd(unsigned int cpu)
304{310{
311 guard(rcu)();
305 irq_work_run_list(this_cpu_ptr(&lazy_list));312 irq_work_run_list(this_cpu_ptr(&lazy_list));
306}313}
307 314