Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'irq-drivers-2025-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq driver updates from Thomas Gleixner:

- Support for hard indices on RISC-V. The hart index identifies a hart
(core) within a specific interrupt domain in RISC-V's Priviledged
Architecture.

- Rework of the RISC-V MSI driver

This moves the driver over to the generic MSI library and solves the
affinity problem of unmaskable PCI/MSI controllers. Unmaskable
PCI/MSI controllers are prone to lose interrupts when the MSI message
is updated to change the affinity because the message write consists
of three 32-bit subsequent writes, which update address and data. As
these writes are non-atomic versus the device raising an interrupt,
the device can observe a half written update and issue an interrupt
on the wrong vector. This is mitiated by a carefully orchestrated
step by step update and the observation of an eventually pending
interrupt on the CPU which issues the update. The algorithm follows
the well established method of the X86 MSI driver.

- A new driver for the RISC-V Sophgo SG2042 MSI controller

- Overhaul of the Renesas RZQ2L driver

Simplification of the probe function by using devm_*() mechanisms,
which avoid the endless list of error prone gotos in the failure
paths.

- Expand the Renesas RZV2H driver to support RZ/G3E SoCs

- A workaround for Rockchip 3568002 erratum in the GIC-V3 driver to
ensure that the addressing is limited to the lower 32-bit of the
physical address space.

- Add support for the Allwinner AS23 NMI controller

- Expand the IMX irqsteer driver to handle up to 960 input interrupts

- The usual small updates, cleanups and device tree changes

* tag 'irq-drivers-2025-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (40 commits)
irqchip/imx-irqsteer: Support up to 960 input interrupts
irqchip/sunxi-nmi: Support Allwinner A523 NMI controller
dt-bindings: irq: sun7i-nmi: Document the Allwinner A523 NMI controller
irqchip/davinci-cp-intc: Remove public header
irqchip/renesas-rzv2h: Add RZ/G3E support
irqchip/renesas-rzv2h: Update macros ICU_TSSR_TSSEL_{MASK,PREP}
irqchip/renesas-rzv2h: Update TSSR_TIEN macro
irqchip/renesas-rzv2h: Add field_width to struct rzv2h_hw_info
irqchip/renesas-rzv2h: Add max_tssel to struct rzv2h_hw_info
irqchip/renesas-rzv2h: Add struct rzv2h_hw_info with t_offs variable
irqchip/renesas-rzv2h: Use devm_pm_runtime_enable()
irqchip/renesas-rzv2h: Use devm_reset_control_get_exclusive_deasserted()
irqchip/renesas-rzv2h: Simplify rzv2h_icu_init()
irqchip/renesas-rzv2h: Drop irqchip from struct rzv2h_icu_priv
irqchip/renesas-rzv2h: Fix wrong variable usage in rzv2h_tint_set_type()
dt-bindings: interrupt-controller: renesas,rzv2h-icu: Document RZ/G3E SoC
riscv: sophgo: dts: Add msi controller for SG2042
irqchip: Add the Sophgo SG2042 MSI interrupt controller
dt-bindings: interrupt-controller: Add Sophgo SG2042 MSI
arm64: dts: rockchip: rk356x: Move PCIe MSI to use GIC ITS instead of MBI
...

+1047 -497
+2
Documentation/arch/arm64/silicon-errata.rst
··· 284 284 +----------------+-----------------+-----------------+-----------------------------+ 285 285 | Rockchip | RK3588 | #3588001 | ROCKCHIP_ERRATUM_3588001 | 286 286 +----------------+-----------------+-----------------+-----------------------------+ 287 + | Rockchip | RK3568 | #3568002 | ROCKCHIP_ERRATUM_3568002 | 288 + +----------------+-----------------+-----------------+-----------------------------+ 287 289 +----------------+-----------------+-----------------+-----------------------------+ 288 290 | Fujitsu | A64FX | E#010001 | FUJITSU_ERRATUM_010001 | 289 291 +----------------+-----------------+-----------------+-----------------------------+
+1
Documentation/devicetree/bindings/interrupt-controller/allwinner,sun7i-a20-sc-nmi.yaml
··· 26 26 deprecated: true 27 27 - const: allwinner,sun7i-a20-sc-nmi 28 28 - const: allwinner,sun9i-a80-nmi 29 + - const: allwinner,sun55i-a523-nmi 29 30 - items: 30 31 - enum: 31 32 - allwinner,sun8i-v3s-nmi
+4 -2
Documentation/devicetree/bindings/interrupt-controller/renesas,rzv2h-icu.yaml
··· 4 4 $id: http://devicetree.org/schemas/interrupt-controller/renesas,rzv2h-icu.yaml# 5 5 $schema: http://devicetree.org/meta-schemas/core.yaml# 6 6 7 - title: Renesas RZ/V2H(P) Interrupt Control Unit 7 + title: Renesas RZ/{G3E,V2H(P)} Interrupt Control Unit 8 8 9 9 maintainers: 10 10 - Fabrizio Castro <fabrizio.castro.jz@renesas.com> ··· 20 20 21 21 properties: 22 22 compatible: 23 - const: renesas,r9a09g057-icu # RZ/V2H(P) 23 + enum: 24 + - renesas,r9a09g047-icu # RZ/G3E 25 + - renesas,r9a09g057-icu # RZ/V2H(P) 24 26 25 27 '#interrupt-cells': 26 28 description: The first cell is the SPI number of the NMI or the
+8
Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
··· 91 91 Firmware must configure interrupt delegation registers based on 92 92 interrupt delegation list. 93 93 94 + riscv,hart-indexes: 95 + $ref: /schemas/types.yaml#/definitions/uint32-array 96 + minItems: 1 97 + maxItems: 16384 98 + description: 99 + A list of hart indexes that APLIC should use to address each hart 100 + that is mentioned in the "interrupts-extended" 101 + 94 102 dependencies: 95 103 riscv,delegation: [ "riscv,children" ] 96 104
+61
Documentation/devicetree/bindings/interrupt-controller/sophgo,sg2042-msi.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/interrupt-controller/sophgo,sg2042-msi.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Sophgo SG2042 MSI Controller 8 + 9 + maintainers: 10 + - Chen Wang <unicorn_wang@outlook.com> 11 + 12 + description: 13 + This interrupt controller is in Sophgo SG2042 for transforming interrupts from 14 + PCIe MSI to PLIC interrupts. 15 + 16 + allOf: 17 + - $ref: /schemas/interrupt-controller/msi-controller.yaml# 18 + 19 + properties: 20 + compatible: 21 + const: sophgo,sg2042-msi 22 + 23 + reg: 24 + items: 25 + - description: clear register 26 + - description: msi doorbell address 27 + 28 + reg-names: 29 + items: 30 + - const: clr 31 + - const: doorbell 32 + 33 + msi-controller: true 34 + 35 + msi-ranges: 36 + maxItems: 1 37 + 38 + "#msi-cells": 39 + const: 0 40 + 41 + required: 42 + - compatible 43 + - reg 44 + - reg-names 45 + - msi-controller 46 + - msi-ranges 47 + - "#msi-cells" 48 + 49 + unevaluatedProperties: false 50 + 51 + examples: 52 + - | 53 + #include <dt-bindings/interrupt-controller/irq.h> 54 + msi-controller@30000000 { 55 + compatible = "sophgo,sg2042-msi"; 56 + reg = <0x30000000 0x4>, <0x30000008 0x4>; 57 + reg-names = "clr", "doorbell"; 58 + msi-controller; 59 + #msi-cells = <0>; 60 + msi-ranges = <&plic 64 IRQ_TYPE_LEVEL_HIGH 32>; 61 + };
-1
arch/arm/mach-davinci/da830.c
··· 11 11 #include <linux/gpio.h> 12 12 #include <linux/init.h> 13 13 #include <linux/io.h> 14 - #include <linux/irqchip/irq-davinci-cp-intc.h> 15 14 16 15 #include <clocksource/timer-davinci.h> 17 16
+9
arch/arm64/Kconfig
··· 1302 1302 1303 1303 If unsure, say Y. 1304 1304 1305 + config ROCKCHIP_ERRATUM_3568002 1306 + bool "Rockchip 3568002: GIC600 can not access physical addresses higher than 4GB" 1307 + default y 1308 + help 1309 + The Rockchip RK3566 and RK3568 GIC600 SoC integrations have AXI 1310 + addressing limited to the first 32bit of physical address space. 1311 + 1312 + If unsure, say Y. 1313 + 1305 1314 config ROCKCHIP_ERRATUM_3588001 1306 1315 bool "Rockchip 3588001: GIC600 can not support shareability attributes" 1307 1316 default y
+13 -1
arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
··· 284 284 mbi-alias = <0x0 0xfd410000>; 285 285 mbi-ranges = <296 24>; 286 286 msi-controller; 287 + ranges; 288 + #address-cells = <2>; 289 + #size-cells = <2>; 290 + dma-noncoherent; 291 + 292 + its: msi-controller@fd440000 { 293 + compatible = "arm,gic-v3-its"; 294 + reg = <0x0 0xfd440000 0 0x20000>; 295 + dma-noncoherent; 296 + msi-controller; 297 + #msi-cells = <1>; 298 + }; 287 299 }; 288 300 289 301 usb_host0_ehci: usb@fd800000 { ··· 969 957 num-ib-windows = <6>; 970 958 num-ob-windows = <2>; 971 959 max-link-speed = <2>; 972 - msi-map = <0x0 &gic 0x0 0x1000>; 960 + msi-map = <0x0 &its 0x0 0x1000>; 973 961 num-lanes = <1>; 974 962 phys = <&combphy2 PHY_TYPE_PCIE>; 975 963 phy-names = "pcie-phy";
+1
arch/riscv/Kconfig
··· 111 111 select GENERIC_IRQ_SHOW 112 112 select GENERIC_IRQ_SHOW_LEVEL 113 113 select GENERIC_LIB_DEVMEM_IS_ALLOWED 114 + select GENERIC_PENDING_IRQ if SMP 114 115 select GENERIC_PCI_IOMAP 115 116 select GENERIC_PTDUMP if MMU 116 117 select GENERIC_SCHED_CLOCK
+10
arch/riscv/boot/dts/sophgo/sg2042.dtsi
··· 173 173 #clock-cells = <1>; 174 174 }; 175 175 176 + msi: msi-controller@7030010304 { 177 + compatible = "sophgo,sg2042-msi"; 178 + reg = <0x70 0x30010304 0x0 0x4>, 179 + <0x70 0x30010300 0x0 0x4>; 180 + reg-names = "clr", "doorbell"; 181 + msi-controller; 182 + #msi-cells = <0>; 183 + msi-ranges = <&intc 64 IRQ_TYPE_LEVEL_HIGH 32>; 184 + }; 185 + 176 186 rpgate: clock-controller@7030010368 { 177 187 compatible = "sophgo,sg2042-rpgate"; 178 188 reg = <0x70 0x30010368 0x0 0x98>;
+108 -123
arch/x86/kernel/apic/vector.c
··· 888 888 return err ? err : IRQ_SET_MASK_OK; 889 889 } 890 890 891 + static void free_moved_vector(struct apic_chip_data *apicd) 892 + { 893 + unsigned int vector = apicd->prev_vector; 894 + unsigned int cpu = apicd->prev_cpu; 895 + bool managed = apicd->is_managed; 896 + 897 + /* 898 + * Managed interrupts are usually not migrated away 899 + * from an online CPU, but CPU isolation 'managed_irq' 900 + * can make that happen. 901 + * 1) Activation does not take the isolation into account 902 + * to keep the code simple 903 + * 2) Migration away from an isolated CPU can happen when 904 + * a non-isolated CPU which is in the calculated 905 + * affinity mask comes online. 906 + */ 907 + trace_vector_free_moved(apicd->irq, cpu, vector, managed); 908 + irq_matrix_free(vector_matrix, cpu, vector, managed); 909 + per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; 910 + hlist_del_init(&apicd->clist); 911 + apicd->prev_vector = 0; 912 + apicd->move_in_progress = 0; 913 + } 914 + 915 + /* 916 + * Called from fixup_irqs() with @desc->lock held and interrupts disabled. 917 + */ 918 + static void apic_force_complete_move(struct irq_data *irqd) 919 + { 920 + unsigned int cpu = smp_processor_id(); 921 + struct apic_chip_data *apicd; 922 + unsigned int vector; 923 + 924 + guard(raw_spinlock)(&vector_lock); 925 + apicd = apic_chip_data(irqd); 926 + if (!apicd) 927 + return; 928 + 929 + /* 930 + * If prev_vector is empty or the descriptor is neither currently 931 + * nor previously on the outgoing CPU no action required. 932 + */ 933 + vector = apicd->prev_vector; 934 + if (!vector || (apicd->cpu != cpu && apicd->prev_cpu != cpu)) 935 + return; 936 + 937 + /* 938 + * This is tricky. If the cleanup of the old vector has not been 939 + * done yet, then the following setaffinity call will fail with 940 + * -EBUSY. This can leave the interrupt in a stale state. 941 + * 942 + * All CPUs are stuck in stop machine with interrupts disabled so 943 + * calling __irq_complete_move() would be completely pointless. 944 + * 945 + * 1) The interrupt is in move_in_progress state. That means that we 946 + * have not seen an interrupt since the io_apic was reprogrammed to 947 + * the new vector. 948 + * 949 + * 2) The interrupt has fired on the new vector, but the cleanup IPIs 950 + * have not been processed yet. 951 + */ 952 + if (apicd->move_in_progress) { 953 + /* 954 + * In theory there is a race: 955 + * 956 + * set_ioapic(new_vector) <-- Interrupt is raised before update 957 + * is effective, i.e. it's raised on 958 + * the old vector. 959 + * 960 + * So if the target cpu cannot handle that interrupt before 961 + * the old vector is cleaned up, we get a spurious interrupt 962 + * and in the worst case the ioapic irq line becomes stale. 963 + * 964 + * But in case of cpu hotplug this should be a non issue 965 + * because if the affinity update happens right before all 966 + * cpus rendezvous in stop machine, there is no way that the 967 + * interrupt can be blocked on the target cpu because all cpus 968 + * loops first with interrupts enabled in stop machine, so the 969 + * old vector is not yet cleaned up when the interrupt fires. 970 + * 971 + * So the only way to run into this issue is if the delivery 972 + * of the interrupt on the apic/system bus would be delayed 973 + * beyond the point where the target cpu disables interrupts 974 + * in stop machine. I doubt that it can happen, but at least 975 + * there is a theoretical chance. Virtualization might be 976 + * able to expose this, but AFAICT the IOAPIC emulation is not 977 + * as stupid as the real hardware. 978 + * 979 + * Anyway, there is nothing we can do about that at this point 980 + * w/o refactoring the whole fixup_irq() business completely. 981 + * We print at least the irq number and the old vector number, 982 + * so we have the necessary information when a problem in that 983 + * area arises. 984 + */ 985 + pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n", 986 + irqd->irq, vector); 987 + } 988 + free_moved_vector(apicd); 989 + } 990 + 891 991 #else 892 - # define apic_set_affinity NULL 992 + # define apic_set_affinity NULL 993 + # define apic_force_complete_move NULL 893 994 #endif 894 995 895 996 static int apic_retrigger_irq(struct irq_data *irqd) ··· 1024 923 } 1025 924 1026 925 static struct irq_chip lapic_controller = { 1027 - .name = "APIC", 1028 - .irq_ack = apic_ack_edge, 1029 - .irq_set_affinity = apic_set_affinity, 1030 - .irq_compose_msi_msg = x86_vector_msi_compose_msg, 1031 - .irq_retrigger = apic_retrigger_irq, 926 + .name = "APIC", 927 + .irq_ack = apic_ack_edge, 928 + .irq_set_affinity = apic_set_affinity, 929 + .irq_compose_msi_msg = x86_vector_msi_compose_msg, 930 + .irq_force_complete_move = apic_force_complete_move, 931 + .irq_retrigger = apic_retrigger_irq, 1032 932 }; 1033 933 1034 934 #ifdef CONFIG_SMP 1035 - 1036 - static void free_moved_vector(struct apic_chip_data *apicd) 1037 - { 1038 - unsigned int vector = apicd->prev_vector; 1039 - unsigned int cpu = apicd->prev_cpu; 1040 - bool managed = apicd->is_managed; 1041 - 1042 - /* 1043 - * Managed interrupts are usually not migrated away 1044 - * from an online CPU, but CPU isolation 'managed_irq' 1045 - * can make that happen. 1046 - * 1) Activation does not take the isolation into account 1047 - * to keep the code simple 1048 - * 2) Migration away from an isolated CPU can happen when 1049 - * a non-isolated CPU which is in the calculated 1050 - * affinity mask comes online. 1051 - */ 1052 - trace_vector_free_moved(apicd->irq, cpu, vector, managed); 1053 - irq_matrix_free(vector_matrix, cpu, vector, managed); 1054 - per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED; 1055 - hlist_del_init(&apicd->clist); 1056 - apicd->prev_vector = 0; 1057 - apicd->move_in_progress = 0; 1058 - } 1059 935 1060 936 static void __vector_cleanup(struct vector_cleanup *cl, bool check_irr) 1061 937 { ··· 1144 1066 */ 1145 1067 if (apicd->cpu == smp_processor_id()) 1146 1068 __vector_schedule_cleanup(apicd); 1147 - } 1148 - 1149 - /* 1150 - * Called from fixup_irqs() with @desc->lock held and interrupts disabled. 1151 - */ 1152 - void irq_force_complete_move(struct irq_desc *desc) 1153 - { 1154 - unsigned int cpu = smp_processor_id(); 1155 - struct apic_chip_data *apicd; 1156 - struct irq_data *irqd; 1157 - unsigned int vector; 1158 - 1159 - /* 1160 - * The function is called for all descriptors regardless of which 1161 - * irqdomain they belong to. For example if an IRQ is provided by 1162 - * an irq_chip as part of a GPIO driver, the chip data for that 1163 - * descriptor is specific to the irq_chip in question. 1164 - * 1165 - * Check first that the chip_data is what we expect 1166 - * (apic_chip_data) before touching it any further. 1167 - */ 1168 - irqd = irq_domain_get_irq_data(x86_vector_domain, 1169 - irq_desc_get_irq(desc)); 1170 - if (!irqd) 1171 - return; 1172 - 1173 - raw_spin_lock(&vector_lock); 1174 - apicd = apic_chip_data(irqd); 1175 - if (!apicd) 1176 - goto unlock; 1177 - 1178 - /* 1179 - * If prev_vector is empty or the descriptor is neither currently 1180 - * nor previously on the outgoing CPU no action required. 1181 - */ 1182 - vector = apicd->prev_vector; 1183 - if (!vector || (apicd->cpu != cpu && apicd->prev_cpu != cpu)) 1184 - goto unlock; 1185 - 1186 - /* 1187 - * This is tricky. If the cleanup of the old vector has not been 1188 - * done yet, then the following setaffinity call will fail with 1189 - * -EBUSY. This can leave the interrupt in a stale state. 1190 - * 1191 - * All CPUs are stuck in stop machine with interrupts disabled so 1192 - * calling __irq_complete_move() would be completely pointless. 1193 - * 1194 - * 1) The interrupt is in move_in_progress state. That means that we 1195 - * have not seen an interrupt since the io_apic was reprogrammed to 1196 - * the new vector. 1197 - * 1198 - * 2) The interrupt has fired on the new vector, but the cleanup IPIs 1199 - * have not been processed yet. 1200 - */ 1201 - if (apicd->move_in_progress) { 1202 - /* 1203 - * In theory there is a race: 1204 - * 1205 - * set_ioapic(new_vector) <-- Interrupt is raised before update 1206 - * is effective, i.e. it's raised on 1207 - * the old vector. 1208 - * 1209 - * So if the target cpu cannot handle that interrupt before 1210 - * the old vector is cleaned up, we get a spurious interrupt 1211 - * and in the worst case the ioapic irq line becomes stale. 1212 - * 1213 - * But in case of cpu hotplug this should be a non issue 1214 - * because if the affinity update happens right before all 1215 - * cpus rendezvous in stop machine, there is no way that the 1216 - * interrupt can be blocked on the target cpu because all cpus 1217 - * loops first with interrupts enabled in stop machine, so the 1218 - * old vector is not yet cleaned up when the interrupt fires. 1219 - * 1220 - * So the only way to run into this issue is if the delivery 1221 - * of the interrupt on the apic/system bus would be delayed 1222 - * beyond the point where the target cpu disables interrupts 1223 - * in stop machine. I doubt that it can happen, but at least 1224 - * there is a theoretical chance. Virtualization might be 1225 - * able to expose this, but AFAICT the IOAPIC emulation is not 1226 - * as stupid as the real hardware. 1227 - * 1228 - * Anyway, there is nothing we can do about that at this point 1229 - * w/o refactoring the whole fixup_irq() business completely. 1230 - * We print at least the irq number and the old vector number, 1231 - * so we have the necessary information when a problem in that 1232 - * area arises. 1233 - */ 1234 - pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n", 1235 - irqd->irq, vector); 1236 - } 1237 - free_moved_vector(apicd); 1238 - unlock: 1239 - raw_spin_unlock(&vector_lock); 1240 1069 } 1241 1070 1242 1071 #ifdef CONFIG_HOTPLUG_CPU
+13 -7
drivers/irqchip/Kconfig
··· 590 590 select IRQ_DOMAIN_HIERARCHY 591 591 select GENERIC_IRQ_MATRIX_ALLOCATOR 592 592 select GENERIC_MSI_IRQ 593 - 594 - config RISCV_IMSIC_PCI 595 - bool 596 - depends on RISCV_IMSIC 597 - depends on PCI 598 - depends on PCI_MSI 599 - default RISCV_IMSIC 593 + select IRQ_MSI_LIB 600 594 601 595 config SIFIVE_PLIC 602 596 bool ··· 745 751 select IRQ_DOMAIN_HIERARCHY 746 752 help 747 753 Support for Microchip External Interrupt Controller. 754 + 755 + config SOPHGO_SG2042_MSI 756 + bool "Sophgo SG2042 MSI Controller" 757 + depends on ARCH_SOPHGO || COMPILE_TEST 758 + depends on PCI 759 + select IRQ_DOMAIN_HIERARCHY 760 + select IRQ_MSI_LIB 761 + select PCI_MSI 762 + help 763 + Support for the Sophgo SG2042 MSI Controller. 764 + This on-chip interrupt controller enables MSI sources to be 765 + routed to the primary PLIC controller on SoC. 748 766 749 767 config SUNPLUS_SP7021_INTC 750 768 bool "Sunplus SP7021 interrupt controller" if COMPILE_TEST
+1
drivers/irqchip/Makefile
··· 128 128 obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o 129 129 obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o 130 130 obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o 131 + obj-$(CONFIG_SOPHGO_SG2042_MSI) += irq-sg2042-msi.o 131 132 obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o
+21 -36
drivers/irqchip/irq-davinci-cp-intc.c
··· 11 11 #include <linux/init.h> 12 12 #include <linux/irq.h> 13 13 #include <linux/irqchip.h> 14 - #include <linux/irqchip/irq-davinci-cp-intc.h> 15 14 #include <linux/irqdomain.h> 16 15 #include <linux/io.h> 17 16 #include <linux/of.h> ··· 153 154 .xlate = irq_domain_xlate_onetwocell, 154 155 }; 155 156 156 - static int __init 157 - davinci_cp_intc_do_init(const struct davinci_cp_intc_config *config, 158 - struct device_node *node) 157 + static int __init davinci_cp_intc_do_init(struct resource *res, unsigned int num_irqs, 158 + struct device_node *node) 159 159 { 160 - unsigned int num_regs = BITS_TO_LONGS(config->num_irqs); 160 + unsigned int num_regs = BITS_TO_LONGS(num_irqs); 161 161 int offset, irq_base; 162 162 void __iomem *req; 163 163 164 - req = request_mem_region(config->reg.start, 165 - resource_size(&config->reg), 166 - "davinci-cp-intc"); 164 + req = request_mem_region(res->start, resource_size(res), "davinci-cp-intc"); 167 165 if (!req) { 168 166 pr_err("%s: register range busy\n", __func__); 169 167 return -EBUSY; 170 168 } 171 169 172 - davinci_cp_intc_base = ioremap(config->reg.start, 173 - resource_size(&config->reg)); 170 + davinci_cp_intc_base = ioremap(res->start, resource_size(res)); 174 171 if (!davinci_cp_intc_base) { 175 172 pr_err("%s: unable to ioremap register range\n", __func__); 176 173 return -EINVAL; ··· 179 184 180 185 /* Disable system interrupts */ 181 186 for (offset = 0; offset < num_regs; offset++) 182 - davinci_cp_intc_write(~0, 183 - DAVINCI_CP_INTC_SYS_ENABLE_CLR(offset)); 187 + davinci_cp_intc_write(~0, DAVINCI_CP_INTC_SYS_ENABLE_CLR(offset)); 184 188 185 189 /* Set to normal mode, no nesting, no priority hold */ 186 190 davinci_cp_intc_write(0, DAVINCI_CP_INTC_CTRL); ··· 187 193 188 194 /* Clear system interrupt status */ 189 195 for (offset = 0; offset < num_regs; offset++) 190 - davinci_cp_intc_write(~0, 191 - DAVINCI_CP_INTC_SYS_STAT_CLR(offset)); 196 + davinci_cp_intc_write(~0, DAVINCI_CP_INTC_SYS_STAT_CLR(offset)); 192 197 193 198 /* Enable nIRQ (what about nFIQ?) */ 194 199 davinci_cp_intc_write(1, DAVINCI_CP_INTC_HOST_ENABLE_IDX_SET); 195 200 201 + /* 4 channels per register */ 202 + num_regs = (num_irqs + 3) >> 2; 196 203 /* Default all priorities to channel 7. */ 197 - num_regs = (config->num_irqs + 3) >> 2; /* 4 channels per register */ 198 204 for (offset = 0; offset < num_regs; offset++) 199 - davinci_cp_intc_write(0x07070707, 200 - DAVINCI_CP_INTC_CHAN_MAP(offset)); 205 + davinci_cp_intc_write(0x07070707, DAVINCI_CP_INTC_CHAN_MAP(offset)); 201 206 202 - irq_base = irq_alloc_descs(-1, 0, config->num_irqs, 0); 207 + irq_base = irq_alloc_descs(-1, 0, num_irqs, 0); 203 208 if (irq_base < 0) { 204 - pr_err("%s: unable to allocate interrupt descriptors: %d\n", 205 - __func__, irq_base); 209 + pr_err("%s: unable to allocate interrupt descriptors: %d\n", __func__, irq_base); 206 210 return irq_base; 207 211 } 208 212 209 - davinci_cp_intc_irq_domain = irq_domain_add_legacy( 210 - node, config->num_irqs, irq_base, 0, 211 - &davinci_cp_intc_irq_domain_ops, NULL); 213 + davinci_cp_intc_irq_domain = irq_domain_add_legacy(node, num_irqs, irq_base, 0, 214 + &davinci_cp_intc_irq_domain_ops, NULL); 212 215 213 216 if (!davinci_cp_intc_irq_domain) { 214 217 pr_err("%s: unable to create an interrupt domain\n", __func__); ··· 220 229 return 0; 221 230 } 222 231 223 - int __init davinci_cp_intc_init(const struct davinci_cp_intc_config *config) 224 - { 225 - return davinci_cp_intc_do_init(config, NULL); 226 - } 227 - 228 232 static int __init davinci_cp_intc_of_init(struct device_node *node, 229 233 struct device_node *parent) 230 234 { 231 - struct davinci_cp_intc_config config = { }; 235 + unsigned int num_irqs; 236 + struct resource res; 232 237 int ret; 233 238 234 - ret = of_address_to_resource(node, 0, &config.reg); 239 + ret = of_address_to_resource(node, 0, &res); 235 240 if (ret) { 236 - pr_err("%s: unable to get the register range from device-tree\n", 237 - __func__); 241 + pr_err("%s: unable to get the register range from device-tree\n", __func__); 238 242 return ret; 239 243 } 240 244 241 - ret = of_property_read_u32(node, "ti,intc-size", &config.num_irqs); 245 + ret = of_property_read_u32(node, "ti,intc-size", &num_irqs); 242 246 if (ret) { 243 - pr_err("%s: unable to read the 'ti,intc-size' property\n", 244 - __func__); 247 + pr_err("%s: unable to read the 'ti,intc-size' property\n", __func__); 245 248 return ret; 246 249 } 247 250 248 - return davinci_cp_intc_do_init(&config, node); 251 + return davinci_cp_intc_do_init(&res, num_irqs, node); 249 252 } 250 253 IRQCHIP_DECLARE(cp_intc, "ti,cp-intc", davinci_cp_intc_of_init);
+1
drivers/irqchip/irq-gic-v2m.c
··· 255 255 static struct msi_parent_ops gicv2m_msi_parent_ops = { 256 256 .supported_flags = GICV2M_MSI_FLAGS_SUPPORTED, 257 257 .required_flags = GICV2M_MSI_FLAGS_REQUIRED, 258 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 258 259 .bus_select_token = DOMAIN_BUS_NEXUS, 259 260 .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, 260 261 .prefix = "GICv2m-",
+1
drivers/irqchip/irq-gic-v3-its-msi-parent.c
··· 203 203 const struct msi_parent_ops gic_v3_its_msi_parent_ops = { 204 204 .supported_flags = ITS_MSI_FLAGS_SUPPORTED, 205 205 .required_flags = ITS_MSI_FLAGS_REQUIRED, 206 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 206 207 .bus_select_token = DOMAIN_BUS_NEXUS, 207 208 .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, 208 209 .prefix = "ITS-",
+22 -1
drivers/irqchip/irq-gic-v3-its.c
··· 205 205 #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) 206 206 #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) 207 207 208 + static gfp_t gfp_flags_quirk; 209 + 208 210 static struct page *its_alloc_pages_node(int node, gfp_t gfp, 209 211 unsigned int order) 210 212 { 211 213 struct page *page; 212 214 int ret = 0; 213 215 214 - page = alloc_pages_node(node, gfp, order); 216 + page = alloc_pages_node(node, gfp | gfp_flags_quirk, order); 215 217 216 218 if (!page) 217 219 return NULL; ··· 4889 4887 return true; 4890 4888 } 4891 4889 4890 + static bool __maybe_unused its_enable_rk3568002(void *data) 4891 + { 4892 + if (!of_machine_is_compatible("rockchip,rk3566") && 4893 + !of_machine_is_compatible("rockchip,rk3568")) 4894 + return false; 4895 + 4896 + gfp_flags_quirk |= GFP_DMA32; 4897 + 4898 + return true; 4899 + } 4900 + 4892 4901 static const struct gic_quirk its_quirks[] = { 4893 4902 #ifdef CONFIG_CAVIUM_ERRATUM_22375 4894 4903 { ··· 4967 4954 .property = "dma-noncoherent", 4968 4955 .init = its_set_non_coherent, 4969 4956 }, 4957 + #ifdef CONFIG_ROCKCHIP_ERRATUM_3568002 4958 + { 4959 + .desc = "ITS: Rockchip erratum RK3568002", 4960 + .iidr = 0x0201743b, 4961 + .mask = 0xffffffff, 4962 + .init = its_enable_rk3568002, 4963 + }, 4964 + #endif 4970 4965 { 4971 4966 } 4972 4967 };
+1
drivers/irqchip/irq-gic-v3-mbi.c
··· 201 201 static const struct msi_parent_ops gic_v3_mbi_msi_parent_ops = { 202 202 .supported_flags = MBI_MSI_FLAGS_SUPPORTED, 203 203 .required_flags = MBI_MSI_FLAGS_REQUIRED, 204 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 204 205 .bus_select_token = DOMAIN_BUS_NEXUS, 205 206 .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, 206 207 .prefix = "MBI-",
+8 -6
drivers/irqchip/irq-imx-irqsteer.c
··· 24 24 #define CHAN_MINTDIS(t) (CTRL_STRIDE_OFF(t, 3) + 0x4) 25 25 #define CHAN_MASTRSTAT(t) (CTRL_STRIDE_OFF(t, 3) + 0x8) 26 26 27 - #define CHAN_MAX_OUTPUT_INT 0x8 27 + #define CHAN_MAX_OUTPUT_INT 0xF 28 28 29 29 struct irqsteer_data { 30 30 void __iomem *regs; ··· 228 228 229 229 for (i = 0; i < data->irq_count; i++) { 230 230 data->irq[i] = irq_of_parse_and_map(np, i); 231 - if (!data->irq[i]) { 232 - ret = -EINVAL; 233 - goto out; 234 - } 231 + if (!data->irq[i]) 232 + break; 235 233 236 234 irq_set_chained_handler_and_data(data->irq[i], 237 235 imx_irqsteer_irq_handler, ··· 252 254 struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev); 253 255 int i; 254 256 255 - for (i = 0; i < irqsteer_data->irq_count; i++) 257 + for (i = 0; i < irqsteer_data->irq_count; i++) { 258 + if (!irqsteer_data->irq[i]) 259 + break; 260 + 256 261 irq_set_chained_handler_and_data(irqsteer_data->irq[i], 257 262 NULL, NULL); 263 + } 258 264 259 265 irq_domain_remove(irqsteer_data->domain); 260 266
+1
drivers/irqchip/irq-imx-mu-msi.c
··· 214 214 static const struct msi_parent_ops imx_mu_msi_parent_ops = { 215 215 .supported_flags = IMX_MU_MSI_FLAGS_SUPPORTED, 216 216 .required_flags = IMX_MU_MSI_FLAGS_REQUIRED, 217 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 217 218 .bus_select_token = DOMAIN_BUS_NEXUS, 218 219 .bus_select_mask = MATCH_PLATFORM_MSI, 219 220 .prefix = "MU-MSI-",
+1
drivers/irqchip/irq-loongson-pch-msi.c
··· 146 146 static struct msi_parent_ops pch_msi_parent_ops = { 147 147 .required_flags = PCH_MSI_FLAGS_REQUIRED, 148 148 .supported_flags = PCH_MSI_FLAGS_SUPPORTED, 149 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 149 150 .bus_select_mask = MATCH_PCI_MSI, 150 151 .bus_select_token = DOMAIN_BUS_NEXUS, 151 152 .prefix = "PCH-",
+6 -5
drivers/irqchip/irq-msi-lib.c
··· 28 28 struct msi_domain_info *info) 29 29 { 30 30 const struct msi_parent_ops *pops = real_parent->msi_parent_ops; 31 + struct irq_chip *chip = info->chip; 31 32 u32 required_flags; 32 33 33 34 /* Parent ops available? */ ··· 93 92 info->flags |= required_flags; 94 93 95 94 /* Chip updates for all child bus types */ 96 - if (!info->chip->irq_eoi) 97 - info->chip->irq_eoi = irq_chip_eoi_parent; 98 - if (!info->chip->irq_ack) 99 - info->chip->irq_ack = irq_chip_ack_parent; 95 + if (!chip->irq_eoi && (pops->chip_flags & MSI_CHIP_FLAG_SET_EOI)) 96 + chip->irq_eoi = irq_chip_eoi_parent; 97 + if (!chip->irq_ack && (pops->chip_flags & MSI_CHIP_FLAG_SET_ACK)) 98 + chip->irq_ack = irq_chip_ack_parent; 100 99 101 100 /* 102 101 * The device MSI domain can never have a set affinity callback. It ··· 106 105 * device MSI domain aside of mask/unmask which is provided e.g. by 107 106 * PCI/MSI device domains. 108 107 */ 109 - info->chip->irq_set_affinity = msi_domain_set_affinity; 108 + chip->irq_set_affinity = msi_domain_set_affinity; 110 109 return true; 111 110 } 112 111 EXPORT_SYMBOL_GPL(msi_lib_init_dev_msi_info);
+1
drivers/irqchip/irq-mvebu-gicp.c
··· 161 161 static const struct msi_parent_ops gicp_msi_parent_ops = { 162 162 .supported_flags = GICP_MSI_FLAGS_SUPPORTED, 163 163 .required_flags = GICP_MSI_FLAGS_REQUIRED, 164 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 164 165 .bus_select_token = DOMAIN_BUS_GENERIC_MSI, 165 166 .bus_select_mask = MATCH_PLATFORM_MSI, 166 167 .prefix = "GICP-",
+1
drivers/irqchip/irq-mvebu-odmi.c
··· 157 157 static const struct msi_parent_ops odmi_msi_parent_ops = { 158 158 .supported_flags = ODMI_MSI_FLAGS_SUPPORTED, 159 159 .required_flags = ODMI_MSI_FLAGS_REQUIRED, 160 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 160 161 .bus_select_token = DOMAIN_BUS_GENERIC_MSI, 161 162 .bus_select_mask = MATCH_PLATFORM_MSI, 162 163 .prefix = "ODMI-",
+1
drivers/irqchip/irq-mvebu-sei.c
··· 356 356 static const struct msi_parent_ops sei_msi_parent_ops = { 357 357 .supported_flags = SEI_MSI_FLAGS_SUPPORTED, 358 358 .required_flags = SEI_MSI_FLAGS_REQUIRED, 359 + .chip_flags = MSI_CHIP_FLAG_SET_EOI | MSI_CHIP_FLAG_SET_ACK, 359 360 .bus_select_mask = MATCH_PLATFORM_MSI, 360 361 .bus_select_token = DOMAIN_BUS_GENERIC_MSI, 361 362 .prefix = "SEI-",
+19 -34
drivers/irqchip/irq-renesas-rzg2l.c
··· 541 541 return -ENODEV; 542 542 543 543 parent_domain = irq_find_host(parent); 544 - if (!parent_domain) { 545 - dev_err(&pdev->dev, "cannot find parent domain\n"); 546 - return -ENODEV; 547 - } 544 + if (!parent_domain) 545 + return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n"); 548 546 549 - rzg2l_irqc_data = devm_kzalloc(&pdev->dev, sizeof(*rzg2l_irqc_data), GFP_KERNEL); 547 + rzg2l_irqc_data = devm_kzalloc(dev, sizeof(*rzg2l_irqc_data), GFP_KERNEL); 550 548 if (!rzg2l_irqc_data) 551 549 return -ENOMEM; 552 550 553 551 rzg2l_irqc_data->irqchip = irq_chip; 554 552 555 - rzg2l_irqc_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); 553 + rzg2l_irqc_data->base = devm_of_iomap(dev, dev->of_node, 0, NULL); 556 554 if (IS_ERR(rzg2l_irqc_data->base)) 557 555 return PTR_ERR(rzg2l_irqc_data->base); 558 556 559 557 ret = rzg2l_irqc_parse_interrupts(rzg2l_irqc_data, node); 560 - if (ret) { 561 - dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret); 562 - return ret; 558 + if (ret) 559 + return dev_err_probe(dev, ret, "cannot parse interrupts: %d\n", ret); 560 + 561 + resetn = devm_reset_control_get_exclusive_deasserted(dev, NULL); 562 + if (IS_ERR(resetn)) { 563 + return dev_err_probe(dev, PTR_ERR(resetn), 564 + "failed to acquire deasserted reset: %d\n", ret); 563 565 } 564 566 565 - resetn = devm_reset_control_get_exclusive(&pdev->dev, NULL); 566 - if (IS_ERR(resetn)) 567 - return PTR_ERR(resetn); 567 + ret = devm_pm_runtime_enable(dev); 568 + if (ret) 569 + return dev_err_probe(dev, ret, "devm_pm_runtime_enable failed: %d\n", ret); 568 570 569 - ret = reset_control_deassert(resetn); 570 - if (ret) { 571 - dev_err(&pdev->dev, "failed to deassert resetn pin, %d\n", ret); 572 - return ret; 573 - } 574 - 575 - pm_runtime_enable(&pdev->dev); 576 - ret = pm_runtime_resume_and_get(&pdev->dev); 577 - if (ret < 0) { 578 - dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret); 579 - goto pm_disable; 580 - } 571 + ret = pm_runtime_resume_and_get(dev); 572 + if (ret) 573 + return dev_err_probe(dev, ret, "pm_runtime_resume_and_get failed: %d\n", ret); 581 574 582 575 raw_spin_lock_init(&rzg2l_irqc_data->lock); 583 576 ··· 578 585 node, &rzg2l_irqc_domain_ops, 579 586 rzg2l_irqc_data); 580 587 if (!irq_domain) { 581 - dev_err(&pdev->dev, "failed to add irq domain\n"); 582 - ret = -ENOMEM; 583 - goto pm_put; 588 + pm_runtime_put(dev); 589 + return dev_err_probe(dev, -ENOMEM, "failed to add irq domain\n"); 584 590 } 585 591 586 592 register_syscore_ops(&rzg2l_irqc_syscore_ops); ··· 596 604 dev = NULL; 597 605 598 606 return 0; 599 - 600 - pm_put: 601 - pm_runtime_put(&pdev->dev); 602 - pm_disable: 603 - pm_runtime_disable(&pdev->dev); 604 - reset_control_assert(resetn); 605 - return ret; 606 607 } 607 608 608 609 static int __init rzg2l_irqc_init(struct device_node *node,
+139 -59
drivers/irqchip/irq-renesas-rzv2h.c
··· 64 64 #define ICU_TINT_LEVEL_HIGH 2 65 65 #define ICU_TINT_LEVEL_LOW 3 66 66 67 - #define ICU_TSSR_K(tint_nr) ((tint_nr) / 4) 68 - #define ICU_TSSR_TSSEL_N(tint_nr) ((tint_nr) % 4) 69 - #define ICU_TSSR_TSSEL_PREP(tssel, n) ((tssel) << ((n) * 8)) 70 - #define ICU_TSSR_TSSEL_MASK(n) ICU_TSSR_TSSEL_PREP(0x7F, n) 71 - #define ICU_TSSR_TIEN(n) (BIT(7) << ((n) * 8)) 67 + #define ICU_TSSR_TSSEL_PREP(tssel, n, field_width) ((tssel) << ((n) * (field_width))) 68 + #define ICU_TSSR_TSSEL_MASK(n, field_width) \ 69 + ({\ 70 + typeof(field_width) (_field_width) = (field_width); \ 71 + ICU_TSSR_TSSEL_PREP((GENMASK(((_field_width) - 2), 0)), (n), _field_width); \ 72 + }) 73 + 74 + #define ICU_TSSR_TIEN(n, field_width) \ 75 + ({\ 76 + typeof(field_width) (_field_width) = (field_width); \ 77 + BIT((_field_width) - 1) << ((n) * (_field_width)); \ 78 + }) 72 79 73 80 #define ICU_TITSR_K(tint_nr) ((tint_nr) / 16) 74 81 #define ICU_TITSR_TITSEL_N(tint_nr) ((tint_nr) % 16) ··· 85 78 86 79 #define ICU_TINT_EXTRACT_HWIRQ(x) FIELD_GET(GENMASK(15, 0), (x)) 87 80 #define ICU_TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x)) 88 - #define ICU_PB5_TINT 0x55 81 + #define ICU_RZG3E_TINT_OFFSET 0x800 82 + #define ICU_RZG3E_TSSEL_MAX_VAL 0x8c 83 + #define ICU_RZV2H_TSSEL_MAX_VAL 0x55 84 + 85 + /** 86 + * struct rzv2h_hw_info - Interrupt Control Unit controller hardware info structure. 87 + * @tssel_lut: TINT lookup table 88 + * @t_offs: TINT offset 89 + * @max_tssel: TSSEL max value 90 + * @field_width: TSSR field width 91 + */ 92 + struct rzv2h_hw_info { 93 + const u8 *tssel_lut; 94 + u16 t_offs; 95 + u8 max_tssel; 96 + u8 field_width; 97 + }; 89 98 90 99 /** 91 100 * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure. 92 101 * @base: Controller's base address 93 - * @irqchip: Pointer to struct irq_chip 94 102 * @fwspec: IRQ firmware specific data 95 103 * @lock: Lock to serialize access to hardware registers 104 + * @info: Pointer to struct rzv2h_hw_info 96 105 */ 97 106 struct rzv2h_icu_priv { 98 107 void __iomem *base; 99 - const struct irq_chip *irqchip; 100 108 struct irq_fwspec fwspec[ICU_NUM_IRQ]; 101 109 raw_spinlock_t lock; 110 + const struct rzv2h_hw_info *info; 102 111 }; 103 112 104 113 static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data) ··· 134 111 tintirq_nr = hw_irq - ICU_TINT_START; 135 112 bit = BIT(tintirq_nr); 136 113 if (!irqd_is_level_type(d)) 137 - writel_relaxed(bit, priv->base + ICU_TSCLR); 114 + writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR); 138 115 } else if (hw_irq >= ICU_IRQ_START) { 139 116 tintirq_nr = hw_irq - ICU_IRQ_START; 140 117 bit = BIT(tintirq_nr); ··· 153 130 struct rzv2h_icu_priv *priv = irq_data_to_priv(d); 154 131 unsigned int hw_irq = irqd_to_hwirq(d); 155 132 u32 tint_nr, tssel_n, k, tssr; 133 + u8 nr_tint; 156 134 157 135 if (hw_irq < ICU_TINT_START) 158 136 return; 159 137 160 138 tint_nr = hw_irq - ICU_TINT_START; 161 - k = ICU_TSSR_K(tint_nr); 162 - tssel_n = ICU_TSSR_TSSEL_N(tint_nr); 139 + nr_tint = 32 / priv->info->field_width; 140 + k = tint_nr / nr_tint; 141 + tssel_n = tint_nr % nr_tint; 163 142 164 143 guard(raw_spinlock)(&priv->lock); 165 - tssr = readl_relaxed(priv->base + ICU_TSSR(k)); 144 + tssr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TSSR(k)); 166 145 if (enable) 167 - tssr |= ICU_TSSR_TIEN(tssel_n); 146 + tssr |= ICU_TSSR_TIEN(tssel_n, priv->info->field_width); 168 147 else 169 - tssr &= ~ICU_TSSR_TIEN(tssel_n); 170 - writel_relaxed(tssr, priv->base + ICU_TSSR(k)); 148 + tssr &= ~ICU_TSSR_TIEN(tssel_n, priv->info->field_width); 149 + writel_relaxed(tssr, priv->base + priv->info->t_offs + ICU_TSSR(k)); 171 150 } 172 151 173 152 static void rzv2h_icu_irq_disable(struct irq_data *d) ··· 272 247 u32 bit = BIT(tint_nr); 273 248 int k = tint_nr / 16; 274 249 275 - tsctr = readl_relaxed(priv->base + ICU_TSCTR); 276 - titsr = readl_relaxed(priv->base + ICU_TITSR(k)); 250 + tsctr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TSCTR); 251 + titsr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TITSR(k)); 277 252 titsel = ICU_TITSR_TITSEL_GET(titsr, titsel_n); 278 253 279 254 /* ··· 282 257 */ 283 258 if ((tsctr & bit) && ((titsel == ICU_TINT_EDGE_RISING) || 284 259 (titsel == ICU_TINT_EDGE_FALLING))) 285 - writel_relaxed(bit, priv->base + ICU_TSCLR); 260 + writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR); 286 261 } 287 262 288 263 static int rzv2h_tint_set_type(struct irq_data *d, unsigned int type) ··· 293 268 unsigned int hwirq; 294 269 u32 tint, sense; 295 270 int tint_nr; 271 + u8 nr_tint; 296 272 297 273 switch (type & IRQ_TYPE_SENSE_MASK) { 298 274 case IRQ_TYPE_LEVEL_LOW: ··· 316 290 return -EINVAL; 317 291 } 318 292 293 + priv = irq_data_to_priv(d); 319 294 tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d); 320 - if (tint > ICU_PB5_TINT) 295 + if (tint > priv->info->max_tssel) 321 296 return -EINVAL; 322 297 323 - priv = irq_data_to_priv(d); 324 - hwirq = irqd_to_hwirq(d); 298 + if (priv->info->tssel_lut) 299 + tint = priv->info->tssel_lut[tint]; 325 300 301 + hwirq = irqd_to_hwirq(d); 326 302 tint_nr = hwirq - ICU_TINT_START; 327 303 328 - tssr_k = ICU_TSSR_K(tint_nr); 329 - tssel_n = ICU_TSSR_TSSEL_N(tint_nr); 304 + nr_tint = 32 / priv->info->field_width; 305 + tssr_k = tint_nr / nr_tint; 306 + tssel_n = tint_nr % nr_tint; 307 + tien = ICU_TSSR_TIEN(tssel_n, priv->info->field_width); 330 308 331 309 titsr_k = ICU_TITSR_K(tint_nr); 332 310 titsel_n = ICU_TITSR_TITSEL_N(tint_nr); 333 - tien = ICU_TSSR_TIEN(titsel_n); 334 311 335 312 guard(raw_spinlock)(&priv->lock); 336 313 337 - tssr = readl_relaxed(priv->base + ICU_TSSR(tssr_k)); 338 - tssr &= ~(ICU_TSSR_TSSEL_MASK(tssel_n) | tien); 339 - tssr |= ICU_TSSR_TSSEL_PREP(tint, tssel_n); 314 + tssr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TSSR(tssr_k)); 315 + tssr &= ~(ICU_TSSR_TSSEL_MASK(tssel_n, priv->info->field_width) | tien); 316 + tssr |= ICU_TSSR_TSSEL_PREP(tint, tssel_n, priv->info->field_width); 340 317 341 - writel_relaxed(tssr, priv->base + ICU_TSSR(tssr_k)); 318 + writel_relaxed(tssr, priv->base + priv->info->t_offs + ICU_TSSR(tssr_k)); 342 319 343 - titsr = readl_relaxed(priv->base + ICU_TITSR(titsr_k)); 320 + titsr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TITSR(titsr_k)); 344 321 titsr &= ~ICU_TITSR_TITSEL_MASK(titsel_n); 345 322 titsr |= ICU_TITSR_TITSEL_PREP(sense, titsel_n); 346 323 347 - writel_relaxed(titsr, priv->base + ICU_TITSR(titsr_k)); 324 + writel_relaxed(titsr, priv->base + priv->info->t_offs + ICU_TITSR(titsr_k)); 348 325 349 326 rzv2h_clear_tint_int(priv, hwirq); 350 327 351 - writel_relaxed(tssr | tien, priv->base + ICU_TSSR(tssr_k)); 328 + writel_relaxed(tssr | tien, priv->base + priv->info->t_offs + ICU_TSSR(tssr_k)); 352 329 353 330 return 0; 354 331 } ··· 419 390 if (hwirq > (ICU_NUM_IRQ - 1)) 420 391 return -EINVAL; 421 392 422 - ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, priv->irqchip, 393 + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &rzv2h_icu_chip, 423 394 (void *)(uintptr_t)tint); 424 395 if (ret) 425 396 return ret; ··· 450 421 return 0; 451 422 } 452 423 453 - static int rzv2h_icu_init(struct device_node *node, struct device_node *parent) 424 + static void rzv2h_icu_put_device(void *data) 425 + { 426 + put_device(data); 427 + } 428 + 429 + static int rzv2h_icu_init_common(struct device_node *node, struct device_node *parent, 430 + const struct rzv2h_hw_info *hw_info) 454 431 { 455 432 struct irq_domain *irq_domain, *parent_domain; 456 433 struct rzv2h_icu_priv *rzv2h_icu_data; ··· 468 433 if (!pdev) 469 434 return -ENODEV; 470 435 436 + ret = devm_add_action_or_reset(&pdev->dev, rzv2h_icu_put_device, 437 + &pdev->dev); 438 + if (ret < 0) 439 + return ret; 440 + 471 441 parent_domain = irq_find_host(parent); 472 442 if (!parent_domain) { 473 443 dev_err(&pdev->dev, "cannot find parent domain\n"); 474 - ret = -ENODEV; 475 - goto put_dev; 444 + return -ENODEV; 476 445 } 477 446 478 447 rzv2h_icu_data = devm_kzalloc(&pdev->dev, sizeof(*rzv2h_icu_data), GFP_KERNEL); 479 - if (!rzv2h_icu_data) { 480 - ret = -ENOMEM; 481 - goto put_dev; 482 - } 483 - 484 - rzv2h_icu_data->irqchip = &rzv2h_icu_chip; 448 + if (!rzv2h_icu_data) 449 + return -ENOMEM; 485 450 486 451 rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); 487 - if (IS_ERR(rzv2h_icu_data->base)) { 488 - ret = PTR_ERR(rzv2h_icu_data->base); 489 - goto put_dev; 490 - } 452 + if (IS_ERR(rzv2h_icu_data->base)) 453 + return PTR_ERR(rzv2h_icu_data->base); 491 454 492 455 ret = rzv2h_icu_parse_interrupts(rzv2h_icu_data, node); 493 456 if (ret) { 494 457 dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret); 495 - goto put_dev; 458 + return ret; 496 459 } 497 460 498 - resetn = devm_reset_control_get_exclusive(&pdev->dev, NULL); 461 + resetn = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL); 499 462 if (IS_ERR(resetn)) { 500 463 ret = PTR_ERR(resetn); 501 - goto put_dev; 464 + dev_err(&pdev->dev, "failed to acquire deasserted reset: %d\n", ret); 465 + return ret; 502 466 } 503 467 504 - ret = reset_control_deassert(resetn); 505 - if (ret) { 506 - dev_err(&pdev->dev, "failed to deassert resetn pin, %d\n", ret); 507 - goto put_dev; 468 + ret = devm_pm_runtime_enable(&pdev->dev); 469 + if (ret < 0) { 470 + dev_err(&pdev->dev, "devm_pm_runtime_enable failed, %d\n", ret); 471 + return ret; 508 472 } 509 473 510 - pm_runtime_enable(&pdev->dev); 511 474 ret = pm_runtime_resume_and_get(&pdev->dev); 512 475 if (ret < 0) { 513 476 dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret); 514 - goto pm_disable; 477 + return ret; 515 478 } 516 479 517 480 raw_spin_lock_init(&rzv2h_icu_data->lock); ··· 522 489 goto pm_put; 523 490 } 524 491 492 + rzv2h_icu_data->info = hw_info; 493 + 525 494 /* 526 495 * coccicheck complains about a missing put_device call before returning, but it's a false 527 496 * positive. We still need &pdev->dev after successfully returning from this function. ··· 532 497 533 498 pm_put: 534 499 pm_runtime_put(&pdev->dev); 535 - pm_disable: 536 - pm_runtime_disable(&pdev->dev); 537 - reset_control_assert(resetn); 538 - put_dev: 539 - put_device(&pdev->dev); 540 500 541 501 return ret; 542 502 } 543 503 504 + /* Mapping based on port index on Table 4.2-6 and TSSEL bits on Table 4.6-4 */ 505 + static const u8 rzg3e_tssel_lut[] = { 506 + 81, 82, 83, 84, 85, 86, 87, 88, /* P00-P07 */ 507 + 89, 90, 91, 92, 93, 94, 95, 96, /* P10-P17 */ 508 + 111, 112, /* P20-P21 */ 509 + 97, 98, 99, 100, 101, 102, 103, 104, /* P30-P37 */ 510 + 105, 106, 107, 108, 109, 110, /* P40-P45 */ 511 + 113, 114, 115, 116, 117, 118, 119, /* P50-P56 */ 512 + 120, 121, 122, 123, 124, 125, 126, /* P60-P66 */ 513 + 127, 128, 129, 130, 131, 132, 133, 134, /* P70-P77 */ 514 + 135, 136, 137, 138, 139, 140, /* P80-P85 */ 515 + 43, 44, 45, 46, 47, 48, 49, 50, /* PA0-PA7 */ 516 + 51, 52, 53, 54, 55, 56, 57, 58, /* PB0-PB7 */ 517 + 59, 60, 61, /* PC0-PC2 */ 518 + 62, 63, 64, 65, 66, 67, 68, 69, /* PD0-PD7 */ 519 + 70, 71, 72, 73, 74, 75, 76, 77, /* PE0-PE7 */ 520 + 78, 79, 80, /* PF0-PF2 */ 521 + 25, 26, 27, 28, 29, 30, 31, 32, /* PG0-PG7 */ 522 + 33, 34, 35, 36, 37, 38, /* PH0-PH5 */ 523 + 4, 5, 6, 7, 8, /* PJ0-PJ4 */ 524 + 39, 40, 41, 42, /* PK0-PK3 */ 525 + 9, 10, 11, 12, 21, 22, 23, 24, /* PL0-PL7 */ 526 + 13, 14, 15, 16, 17, 18, 19, 20, /* PM0-PM7 */ 527 + 0, 1, 2, 3 /* PS0-PS3 */ 528 + }; 529 + 530 + static const struct rzv2h_hw_info rzg3e_hw_params = { 531 + .tssel_lut = rzg3e_tssel_lut, 532 + .t_offs = ICU_RZG3E_TINT_OFFSET, 533 + .max_tssel = ICU_RZG3E_TSSEL_MAX_VAL, 534 + .field_width = 16, 535 + }; 536 + 537 + static const struct rzv2h_hw_info rzv2h_hw_params = { 538 + .t_offs = 0, 539 + .max_tssel = ICU_RZV2H_TSSEL_MAX_VAL, 540 + .field_width = 8, 541 + }; 542 + 543 + static int rzg3e_icu_init(struct device_node *node, struct device_node *parent) 544 + { 545 + return rzv2h_icu_init_common(node, parent, &rzg3e_hw_params); 546 + } 547 + 548 + static int rzv2h_icu_init(struct device_node *node, struct device_node *parent) 549 + { 550 + return rzv2h_icu_init_common(node, parent, &rzv2h_hw_params); 551 + } 552 + 544 553 IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu) 554 + IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_init) 545 555 IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init) 546 556 IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu) 547 557 MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
+21 -3
drivers/irqchip/irq-riscv-aplic-direct.c
··· 31 31 }; 32 32 33 33 struct aplic_idc { 34 - unsigned int hart_index; 34 + u32 hart_index; 35 35 void __iomem *regs; 36 36 struct aplic_direct *direct; 37 37 }; ··· 219 219 return 0; 220 220 } 221 221 222 + static int aplic_direct_get_hart_index(struct device *dev, u32 logical_index, 223 + u32 *hart_index) 224 + { 225 + const char *prop_hart_index = "riscv,hart-indexes"; 226 + struct device_node *np = to_of_node(dev->fwnode); 227 + 228 + if (!np || !of_property_present(np, prop_hart_index)) { 229 + *hart_index = logical_index; 230 + return 0; 231 + } 232 + 233 + return of_property_read_u32_index(np, prop_hart_index, logical_index, hart_index); 234 + } 235 + 222 236 int aplic_direct_setup(struct device *dev, void __iomem *regs) 223 237 { 224 238 int i, j, rc, cpu, current_cpu, setup_count = 0; ··· 279 265 cpumask_set_cpu(cpu, &direct->lmask); 280 266 281 267 idc = per_cpu_ptr(&aplic_idcs, cpu); 282 - idc->hart_index = i; 283 - idc->regs = priv->regs + APLIC_IDC_BASE + i * APLIC_IDC_SIZE; 268 + rc = aplic_direct_get_hart_index(dev, i, &idc->hart_index); 269 + if (rc) { 270 + dev_warn(dev, "hart index not found for IDC%d\n", i); 271 + continue; 272 + } 273 + idc->regs = priv->regs + APLIC_IDC_BASE + idc->hart_index * APLIC_IDC_SIZE; 284 274 idc->direct = direct; 285 275 286 276 aplic_idc_set_delivery(idc, true);
+9 -5
drivers/irqchip/irq-riscv-imsic-early.c
··· 73 73 static void imsic_handle_irq(struct irq_desc *desc) 74 74 { 75 75 struct irq_chip *chip = irq_desc_get_chip(desc); 76 - int err, cpu = smp_processor_id(); 76 + int cpu = smp_processor_id(); 77 77 struct imsic_vector *vec; 78 78 unsigned long local_id; 79 + 80 + /* 81 + * Process pending local synchronization instead of waiting 82 + * for per-CPU local timer to expire. 83 + */ 84 + imsic_local_sync_all(false); 79 85 80 86 chained_irq_enter(chip, desc); 81 87 ··· 103 97 continue; 104 98 } 105 99 106 - err = generic_handle_domain_irq(imsic->base_domain, vec->hwirq); 107 - if (unlikely(err)) 108 - pr_warn_ratelimited("hwirq 0x%x mapping not found\n", vec->hwirq); 100 + generic_handle_irq(vec->irq); 109 101 } 110 102 111 103 chained_irq_exit(chip, desc); ··· 124 120 * Interrupts identities might have been enabled/disabled while 125 121 * this CPU was not running so sync-up local enable/disable state. 126 122 */ 127 - imsic_local_sync_all(); 123 + imsic_local_sync_all(true); 128 124 129 125 /* Enable local interrupt delivery */ 130 126 imsic_local_delivery(true);
+105 -110
drivers/irqchip/irq-riscv-imsic-platform.c
··· 20 20 #include <linux/spinlock.h> 21 21 #include <linux/smp.h> 22 22 23 + #include "irq-msi-lib.h" 23 24 #include "irq-riscv-imsic-state.h" 24 25 25 26 static bool imsic_cpu_page_phys(unsigned int cpu, unsigned int guest_index, ··· 64 63 return 0; 65 64 } 66 65 66 + static void imsic_irq_ack(struct irq_data *d) 67 + { 68 + irq_move_irq(d); 69 + } 70 + 67 71 static void imsic_irq_compose_vector_msg(struct imsic_vector *vec, struct msi_msg *msg) 68 72 { 69 73 phys_addr_t msi_addr; ··· 102 96 bool force) 103 97 { 104 98 struct imsic_vector *old_vec, *new_vec; 105 - struct irq_data *pd = d->parent_data; 99 + struct imsic_vector tmp_vec; 106 100 107 - old_vec = irq_data_get_irq_chip_data(pd); 101 + /* 102 + * Requirements for the downstream irqdomains (or devices): 103 + * 104 + * 1) Downstream irqdomains (or devices) with atomic MSI update can 105 + * happily do imsic_irq_set_affinity() in the process-context on 106 + * any CPU so the irqchip of such irqdomains must not set the 107 + * IRQCHIP_MOVE_DEFERRED flag. 108 + * 109 + * 2) Downstream irqdomains (or devices) with non-atomic MSI update 110 + * must use imsic_irq_set_affinity() in nterrupt-context upon 111 + * the next device interrupt so the irqchip of such irqdomains 112 + * must set the IRQCHIP_MOVE_DEFERRED flag. 113 + */ 114 + 115 + old_vec = irq_data_get_irq_chip_data(d); 108 116 if (WARN_ON(!old_vec)) 109 117 return -ENOENT; 110 118 ··· 131 111 return -EBUSY; 132 112 133 113 /* Get a new vector on the desired set of CPUs */ 134 - new_vec = imsic_vector_alloc(old_vec->hwirq, mask_val); 114 + new_vec = imsic_vector_alloc(old_vec->irq, mask_val); 135 115 if (!new_vec) 136 116 return -ENOSPC; 137 117 118 + /* 119 + * Device having non-atomic MSI update might see an intermediate 120 + * state when changing target IMSIC vector from one CPU to another. 121 + * 122 + * To avoid losing interrupt to such intermediate state, do the 123 + * following (just like x86 APIC): 124 + * 125 + * 1) First write a temporary IMSIC vector to the device which 126 + * has MSI address same as the old IMSIC vector but MSI data 127 + * matches the new IMSIC vector. 128 + * 129 + * 2) Next write the new IMSIC vector to the device. 130 + * 131 + * Based on the above, __imsic_local_sync() must check pending 132 + * status of both old MSI data and new MSI data on the old CPU. 133 + */ 134 + if (!irq_can_move_in_process_context(d) && 135 + new_vec->local_id != old_vec->local_id) { 136 + /* Setup temporary vector */ 137 + tmp_vec.cpu = old_vec->cpu; 138 + tmp_vec.local_id = new_vec->local_id; 139 + 140 + /* Point device to the temporary vector */ 141 + imsic_msi_update_msg(irq_get_irq_data(d->irq), &tmp_vec); 142 + } 143 + 138 144 /* Point device to the new vector */ 139 - imsic_msi_update_msg(d, new_vec); 145 + imsic_msi_update_msg(irq_get_irq_data(d->irq), new_vec); 140 146 141 147 /* Update irq descriptors with the new vector */ 142 - pd->chip_data = new_vec; 148 + d->chip_data = new_vec; 143 149 144 - /* Update effective affinity of parent irq data */ 145 - irq_data_update_effective_affinity(pd, cpumask_of(new_vec->cpu)); 150 + /* Update effective affinity */ 151 + irq_data_update_effective_affinity(d, cpumask_of(new_vec->cpu)); 146 152 147 153 /* Move state of the old vector to the new vector */ 148 154 imsic_vector_move(old_vec, new_vec); 149 155 150 156 return IRQ_SET_MASK_OK_DONE; 151 157 } 158 + 159 + static void imsic_irq_force_complete_move(struct irq_data *d) 160 + { 161 + struct imsic_vector *mvec, *vec = irq_data_get_irq_chip_data(d); 162 + unsigned int cpu = smp_processor_id(); 163 + 164 + if (WARN_ON(!vec)) 165 + return; 166 + 167 + /* Do nothing if there is no in-flight move */ 168 + mvec = imsic_vector_get_move(vec); 169 + if (!mvec) 170 + return; 171 + 172 + /* Do nothing if the old IMSIC vector does not belong to current CPU */ 173 + if (mvec->cpu != cpu) 174 + return; 175 + 176 + /* 177 + * The best we can do is force cleanup the old IMSIC vector. 178 + * 179 + * The challenges over here are same as x86 vector domain so 180 + * refer to the comments in irq_force_complete_move() function 181 + * implemented at arch/x86/kernel/apic/vector.c. 182 + */ 183 + 184 + /* Force cleanup in-flight move */ 185 + pr_info("IRQ fixup: irq %d move in progress, old vector cpu %d local_id %d\n", 186 + d->irq, mvec->cpu, mvec->local_id); 187 + imsic_vector_force_move_cleanup(vec); 188 + } 152 189 #endif 153 190 154 191 static struct irq_chip imsic_irq_base_chip = { 155 - .name = "IMSIC", 156 - .irq_mask = imsic_irq_mask, 157 - .irq_unmask = imsic_irq_unmask, 158 - .irq_retrigger = imsic_irq_retrigger, 159 - .irq_compose_msi_msg = imsic_irq_compose_msg, 160 - .flags = IRQCHIP_SKIP_SET_WAKE | 161 - IRQCHIP_MASK_ON_SUSPEND, 192 + .name = "IMSIC", 193 + .irq_mask = imsic_irq_mask, 194 + .irq_unmask = imsic_irq_unmask, 195 + #ifdef CONFIG_SMP 196 + .irq_set_affinity = imsic_irq_set_affinity, 197 + .irq_force_complete_move = imsic_irq_force_complete_move, 198 + #endif 199 + .irq_retrigger = imsic_irq_retrigger, 200 + .irq_ack = imsic_irq_ack, 201 + .irq_compose_msi_msg = imsic_irq_compose_msg, 202 + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, 162 203 }; 163 204 164 205 static int imsic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ··· 236 155 return -ENOSPC; 237 156 238 157 irq_domain_set_info(domain, virq, virq, &imsic_irq_base_chip, vec, 239 - handle_simple_irq, NULL, NULL); 158 + handle_edge_irq, NULL, NULL); 240 159 irq_set_noprobe(virq); 241 160 irq_set_affinity(virq, cpu_online_mask); 242 161 irq_data_update_effective_affinity(irq_get_irq_data(virq), cpumask_of(vec->cpu)); ··· 251 170 252 171 imsic_vector_free(irq_data_get_irq_chip_data(d)); 253 172 irq_domain_free_irqs_parent(domain, virq, nr_irqs); 254 - } 255 - 256 - static int imsic_irq_domain_select(struct irq_domain *domain, struct irq_fwspec *fwspec, 257 - enum irq_domain_bus_token bus_token) 258 - { 259 - const struct msi_parent_ops *ops = domain->msi_parent_ops; 260 - u32 busmask = BIT(bus_token); 261 - 262 - if (fwspec->fwnode != domain->fwnode || fwspec->param_count != 0) 263 - return 0; 264 - 265 - /* Handle pure domain searches */ 266 - if (bus_token == ops->bus_select_token) 267 - return 1; 268 - 269 - return !!(ops->bus_select_mask & busmask); 270 173 } 271 174 272 175 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS ··· 269 204 static const struct irq_domain_ops imsic_base_domain_ops = { 270 205 .alloc = imsic_irq_domain_alloc, 271 206 .free = imsic_irq_domain_free, 272 - .select = imsic_irq_domain_select, 207 + .select = msi_lib_irq_domain_select, 273 208 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS 274 209 .debug_show = imsic_irq_debug_show, 275 210 #endif 276 211 }; 277 212 278 - #ifdef CONFIG_RISCV_IMSIC_PCI 279 - 280 - static void imsic_pci_mask_irq(struct irq_data *d) 213 + static bool imsic_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 214 + struct irq_domain *real_parent, struct msi_domain_info *info) 281 215 { 282 - pci_msi_mask_irq(d); 283 - irq_chip_mask_parent(d); 284 - } 285 - 286 - static void imsic_pci_unmask_irq(struct irq_data *d) 287 - { 288 - irq_chip_unmask_parent(d); 289 - pci_msi_unmask_irq(d); 290 - } 291 - 292 - #define MATCH_PCI_MSI BIT(DOMAIN_BUS_PCI_MSI) 293 - 294 - #else 295 - 296 - #define MATCH_PCI_MSI 0 297 - 298 - #endif 299 - 300 - static bool imsic_init_dev_msi_info(struct device *dev, 301 - struct irq_domain *domain, 302 - struct irq_domain *real_parent, 303 - struct msi_domain_info *info) 304 - { 305 - const struct msi_parent_ops *pops = real_parent->msi_parent_ops; 306 - 307 - /* MSI parent domain specific settings */ 308 - switch (real_parent->bus_token) { 309 - case DOMAIN_BUS_NEXUS: 310 - if (WARN_ON_ONCE(domain != real_parent)) 311 - return false; 312 - #ifdef CONFIG_SMP 313 - info->chip->irq_set_affinity = imsic_irq_set_affinity; 314 - #endif 315 - break; 316 - default: 317 - WARN_ON_ONCE(1); 216 + if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info)) 318 217 return false; 319 - } 320 218 321 - /* Is the target supported? */ 322 219 switch (info->bus_token) { 323 - #ifdef CONFIG_RISCV_IMSIC_PCI 324 220 case DOMAIN_BUS_PCI_DEVICE_MSI: 325 221 case DOMAIN_BUS_PCI_DEVICE_MSIX: 326 - info->chip->irq_mask = imsic_pci_mask_irq; 327 - info->chip->irq_unmask = imsic_pci_unmask_irq; 328 - break; 329 - #endif 330 - case DOMAIN_BUS_DEVICE_MSI: 331 - /* 332 - * Per-device MSI should never have any MSI feature bits 333 - * set. It's sole purpose is to create a dumb interrupt 334 - * chip which has a device specific irq_write_msi_msg() 335 - * callback. 336 - */ 337 - if (WARN_ON_ONCE(info->flags)) 338 - return false; 339 - 340 - /* Core managed MSI descriptors */ 341 - info->flags |= MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | 342 - MSI_FLAG_FREE_MSI_DESCS; 343 - break; 344 - case DOMAIN_BUS_WIRED_TO_MSI: 222 + info->chip->flags |= IRQCHIP_MOVE_DEFERRED; 345 223 break; 346 224 default: 347 - WARN_ON_ONCE(1); 348 - return false; 225 + break; 349 226 } 350 - 351 - /* Use hierarchial chip operations re-trigger */ 352 - info->chip->irq_retrigger = irq_chip_retrigger_hierarchy; 353 - 354 - /* 355 - * Mask out the domain specific MSI feature flags which are not 356 - * supported by the real parent. 357 - */ 358 - info->flags &= pops->supported_flags; 359 - 360 - /* Enforce the required flags */ 361 - info->flags |= pops->required_flags; 362 227 363 228 return true; 364 229 } 365 - 366 - #define MATCH_PLATFORM_MSI BIT(DOMAIN_BUS_PLATFORM_MSI) 367 230 368 231 static const struct msi_parent_ops imsic_msi_parent_ops = { 369 232 .supported_flags = MSI_GENERIC_FLAGS_MASK | 370 233 MSI_FLAG_PCI_MSIX, 371 234 .required_flags = MSI_FLAG_USE_DEF_DOM_OPS | 372 - MSI_FLAG_USE_DEF_CHIP_OPS, 235 + MSI_FLAG_USE_DEF_CHIP_OPS | 236 + MSI_FLAG_PCI_MSI_MASK_PARENT, 237 + .chip_flags = MSI_CHIP_FLAG_SET_ACK, 373 238 .bus_select_token = DOMAIN_BUS_NEXUS, 374 239 .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI, 375 240 .init_dev_msi_info = imsic_init_dev_msi_info,
+114 -37
drivers/irqchip/irq-riscv-imsic-state.c
··· 124 124 } 125 125 } 126 126 127 - static void __imsic_local_sync(struct imsic_local_priv *lpriv) 127 + static bool __imsic_local_sync(struct imsic_local_priv *lpriv) 128 128 { 129 - struct imsic_local_config *mlocal; 130 - struct imsic_vector *vec, *mvec; 129 + struct imsic_local_config *tlocal, *mlocal; 130 + struct imsic_vector *vec, *tvec, *mvec; 131 + bool ret = true; 131 132 int i; 132 133 133 134 lockdep_assert_held(&lpriv->lock); ··· 144 143 __imsic_id_clear_enable(i); 145 144 146 145 /* 147 - * If the ID was being moved to a new ID on some other CPU 148 - * then we can get a MSI during the movement so check the 149 - * ID pending bit and re-trigger the new ID on other CPU 150 - * using MMIO write. 146 + * Clear the previous vector pointer of the new vector only 147 + * after the movement is complete on the old CPU. 151 148 */ 152 - mvec = READ_ONCE(vec->move); 153 - WRITE_ONCE(vec->move, NULL); 154 - if (mvec && mvec != vec) { 155 - if (__imsic_id_read_clear_pending(i)) { 149 + mvec = READ_ONCE(vec->move_prev); 150 + if (mvec) { 151 + /* 152 + * If the old vector has not been updated then 153 + * try again in the next sync-up call. 154 + */ 155 + if (READ_ONCE(mvec->move_next)) { 156 + ret = false; 157 + continue; 158 + } 159 + 160 + WRITE_ONCE(vec->move_prev, NULL); 161 + } 162 + 163 + /* 164 + * If a vector was being moved to a new vector on some other 165 + * CPU then we can get a MSI during the movement so check the 166 + * ID pending bit and re-trigger the new ID on other CPU using 167 + * MMIO write. 168 + */ 169 + mvec = READ_ONCE(vec->move_next); 170 + if (mvec) { 171 + /* 172 + * Devices having non-atomic MSI update might see 173 + * an intermediate state so check both old ID and 174 + * new ID for pending interrupts. 175 + * 176 + * For details, see imsic_irq_set_affinity(). 177 + */ 178 + tvec = vec->local_id == mvec->local_id ? 179 + NULL : &lpriv->vectors[mvec->local_id]; 180 + 181 + if (tvec && !irq_can_move_in_process_context(irq_get_irq_data(vec->irq)) && 182 + __imsic_id_read_clear_pending(tvec->local_id)) { 183 + /* Retrigger temporary vector if it was already in-use */ 184 + if (READ_ONCE(tvec->enable)) { 185 + tlocal = per_cpu_ptr(imsic->global.local, tvec->cpu); 186 + writel_relaxed(tvec->local_id, tlocal->msi_va); 187 + } 188 + 156 189 mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu); 157 190 writel_relaxed(mvec->local_id, mlocal->msi_va); 158 191 } 159 192 160 - imsic_vector_free(&lpriv->vectors[i]); 193 + if (__imsic_id_read_clear_pending(vec->local_id)) { 194 + mlocal = per_cpu_ptr(imsic->global.local, mvec->cpu); 195 + writel_relaxed(mvec->local_id, mlocal->msi_va); 196 + } 197 + 198 + WRITE_ONCE(vec->move_next, NULL); 199 + imsic_vector_free(vec); 161 200 } 162 201 163 202 skip: 164 203 bitmap_clear(lpriv->dirty_bitmap, i, 1); 165 204 } 205 + 206 + return ret; 166 207 } 167 208 168 - void imsic_local_sync_all(void) 209 + #ifdef CONFIG_SMP 210 + static void __imsic_local_timer_start(struct imsic_local_priv *lpriv) 211 + { 212 + lockdep_assert_held(&lpriv->lock); 213 + 214 + if (!timer_pending(&lpriv->timer)) { 215 + lpriv->timer.expires = jiffies + 1; 216 + add_timer_on(&lpriv->timer, smp_processor_id()); 217 + } 218 + } 219 + #else 220 + static inline void __imsic_local_timer_start(struct imsic_local_priv *lpriv) 221 + { 222 + } 223 + #endif 224 + 225 + void imsic_local_sync_all(bool force_all) 169 226 { 170 227 struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv); 171 228 unsigned long flags; 172 229 173 230 raw_spin_lock_irqsave(&lpriv->lock, flags); 174 - bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1); 175 - __imsic_local_sync(lpriv); 231 + 232 + if (force_all) 233 + bitmap_fill(lpriv->dirty_bitmap, imsic->global.nr_ids + 1); 234 + if (!__imsic_local_sync(lpriv)) 235 + __imsic_local_timer_start(lpriv); 236 + 176 237 raw_spin_unlock_irqrestore(&lpriv->lock, flags); 177 238 } 178 239 ··· 253 190 #ifdef CONFIG_SMP 254 191 static void imsic_local_timer_callback(struct timer_list *timer) 255 192 { 256 - struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv); 257 - unsigned long flags; 258 - 259 - raw_spin_lock_irqsave(&lpriv->lock, flags); 260 - __imsic_local_sync(lpriv); 261 - raw_spin_unlock_irqrestore(&lpriv->lock, flags); 193 + imsic_local_sync_all(false); 262 194 } 263 195 264 196 static void __imsic_remote_sync(struct imsic_local_priv *lpriv, unsigned int cpu) ··· 274 216 */ 275 217 if (cpu_online(cpu)) { 276 218 if (cpu == smp_processor_id()) { 277 - __imsic_local_sync(lpriv); 278 - return; 219 + if (__imsic_local_sync(lpriv)) 220 + return; 279 221 } 280 222 281 - if (!timer_pending(&lpriv->timer)) { 282 - lpriv->timer.expires = jiffies + 1; 283 - add_timer_on(&lpriv->timer, cpu); 284 - } 223 + __imsic_local_timer_start(lpriv); 285 224 } 286 225 } 287 226 #else ··· 333 278 raw_spin_unlock(&lpriv->lock); 334 279 } 335 280 336 - static bool imsic_vector_move_update(struct imsic_local_priv *lpriv, struct imsic_vector *vec, 337 - bool new_enable, struct imsic_vector *new_move) 281 + void imsic_vector_force_move_cleanup(struct imsic_vector *vec) 282 + { 283 + struct imsic_local_priv *lpriv; 284 + struct imsic_vector *mvec; 285 + unsigned long flags; 286 + 287 + lpriv = per_cpu_ptr(imsic->lpriv, vec->cpu); 288 + raw_spin_lock_irqsave(&lpriv->lock, flags); 289 + 290 + mvec = READ_ONCE(vec->move_prev); 291 + WRITE_ONCE(vec->move_prev, NULL); 292 + if (mvec) 293 + imsic_vector_free(mvec); 294 + 295 + raw_spin_unlock_irqrestore(&lpriv->lock, flags); 296 + } 297 + 298 + static bool imsic_vector_move_update(struct imsic_local_priv *lpriv, 299 + struct imsic_vector *vec, bool is_old_vec, 300 + bool new_enable, struct imsic_vector *move_vec) 338 301 { 339 302 unsigned long flags; 340 303 bool enabled; ··· 362 289 /* Update enable and move details */ 363 290 enabled = READ_ONCE(vec->enable); 364 291 WRITE_ONCE(vec->enable, new_enable); 365 - WRITE_ONCE(vec->move, new_move); 292 + if (is_old_vec) 293 + WRITE_ONCE(vec->move_next, move_vec); 294 + else 295 + WRITE_ONCE(vec->move_prev, move_vec); 366 296 367 297 /* Mark the vector as dirty and synchronize */ 368 298 bitmap_set(lpriv->dirty_bitmap, vec->local_id, 1); ··· 398 322 * interrupt on the old vector while device was being moved 399 323 * to the new vector. 400 324 */ 401 - enabled = imsic_vector_move_update(old_lpriv, old_vec, false, new_vec); 402 - imsic_vector_move_update(new_lpriv, new_vec, enabled, new_vec); 325 + enabled = imsic_vector_move_update(old_lpriv, old_vec, true, false, new_vec); 326 + imsic_vector_move_update(new_lpriv, new_vec, false, enabled, old_vec); 403 327 } 404 328 405 329 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS ··· 444 368 return &lpriv->vectors[local_id]; 445 369 } 446 370 447 - struct imsic_vector *imsic_vector_alloc(unsigned int hwirq, const struct cpumask *mask) 371 + struct imsic_vector *imsic_vector_alloc(unsigned int irq, const struct cpumask *mask) 448 372 { 449 373 struct imsic_vector *vec = NULL; 450 374 struct imsic_local_priv *lpriv; ··· 460 384 461 385 lpriv = per_cpu_ptr(imsic->lpriv, cpu); 462 386 vec = &lpriv->vectors[local_id]; 463 - vec->hwirq = hwirq; 387 + vec->irq = irq; 464 388 vec->enable = false; 465 - vec->move = NULL; 389 + vec->move_next = NULL; 390 + vec->move_prev = NULL; 466 391 467 392 return vec; 468 393 } ··· 473 396 unsigned long flags; 474 397 475 398 raw_spin_lock_irqsave(&imsic->matrix_lock, flags); 476 - vec->hwirq = UINT_MAX; 399 + vec->irq = 0; 477 400 irq_matrix_free(imsic->matrix, vec->cpu, vec->local_id, false); 478 401 raw_spin_unlock_irqrestore(&imsic->matrix_lock, flags); 479 402 } ··· 532 455 vec = &lpriv->vectors[i]; 533 456 vec->cpu = cpu; 534 457 vec->local_id = i; 535 - vec->hwirq = UINT_MAX; 458 + vec->irq = 0; 536 459 } 537 460 } 538 461
+7 -5
drivers/irqchip/irq-riscv-imsic-state.h
··· 20 20 unsigned int cpu; 21 21 unsigned int local_id; 22 22 /* Details saved by driver in the vector */ 23 - unsigned int hwirq; 23 + unsigned int irq; 24 24 /* Details accessed using local lock held */ 25 25 bool enable; 26 - struct imsic_vector *move; 26 + struct imsic_vector *move_next; 27 + struct imsic_vector *move_prev; 27 28 }; 28 29 29 30 struct imsic_local_priv { ··· 75 74 __imsic_eix_update(id, 1, false, false); 76 75 } 77 76 78 - void imsic_local_sync_all(void); 77 + void imsic_local_sync_all(bool force_all); 79 78 void imsic_local_delivery(bool enable); 80 79 81 80 void imsic_vector_mask(struct imsic_vector *vec); ··· 88 87 89 88 static inline struct imsic_vector *imsic_vector_get_move(struct imsic_vector *vec) 90 89 { 91 - return READ_ONCE(vec->move); 90 + return READ_ONCE(vec->move_prev); 92 91 } 93 92 93 + void imsic_vector_force_move_cleanup(struct imsic_vector *vec); 94 94 void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_vec); 95 95 96 96 struct imsic_vector *imsic_vector_from_local_id(unsigned int cpu, unsigned int local_id); 97 97 98 - struct imsic_vector *imsic_vector_alloc(unsigned int hwirq, const struct cpumask *mask); 98 + struct imsic_vector *imsic_vector_alloc(unsigned int irq, const struct cpumask *mask); 99 99 void imsic_vector_free(struct imsic_vector *vector); 100 100 101 101 void imsic_vector_debug_show(struct seq_file *m, struct imsic_vector *vec, int ind);
+249
drivers/irqchip/irq-sg2042-msi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * SG2042 MSI Controller 4 + * 5 + * Copyright (C) 2024 Sophgo Technology Inc. 6 + * Copyright (C) 2024 Chen Wang <unicorn_wang@outlook.com> 7 + */ 8 + 9 + #include <linux/cleanup.h> 10 + #include <linux/io.h> 11 + #include <linux/irq.h> 12 + #include <linux/irqdomain.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/msi.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/property.h> 18 + #include <linux/slab.h> 19 + 20 + #include "irq-msi-lib.h" 21 + 22 + #define SG2042_MAX_MSI_VECTOR 32 23 + 24 + struct sg2042_msi_chipdata { 25 + void __iomem *reg_clr; // clear reg, see TRM, 10.1.33, GP_INTR0_CLR 26 + 27 + phys_addr_t doorbell_addr; // see TRM, 10.1.32, GP_INTR0_SET 28 + 29 + u32 irq_first; // The vector number that MSIs starts 30 + u32 num_irqs; // The number of vectors for MSIs 31 + 32 + DECLARE_BITMAP(msi_map, SG2042_MAX_MSI_VECTOR); 33 + struct mutex msi_map_lock; // lock for msi_map 34 + }; 35 + 36 + static int sg2042_msi_allocate_hwirq(struct sg2042_msi_chipdata *data, int num_req) 37 + { 38 + int first; 39 + 40 + guard(mutex)(&data->msi_map_lock); 41 + first = bitmap_find_free_region(data->msi_map, data->num_irqs, 42 + get_count_order(num_req)); 43 + return first >= 0 ? first : -ENOSPC; 44 + } 45 + 46 + static void sg2042_msi_free_hwirq(struct sg2042_msi_chipdata *data, int hwirq, int num_req) 47 + { 48 + guard(mutex)(&data->msi_map_lock); 49 + bitmap_release_region(data->msi_map, hwirq, get_count_order(num_req)); 50 + } 51 + 52 + static void sg2042_msi_irq_ack(struct irq_data *d) 53 + { 54 + struct sg2042_msi_chipdata *data = irq_data_get_irq_chip_data(d); 55 + int bit_off = d->hwirq; 56 + 57 + writel(1 << bit_off, data->reg_clr); 58 + 59 + irq_chip_ack_parent(d); 60 + } 61 + 62 + static void sg2042_msi_irq_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) 63 + { 64 + struct sg2042_msi_chipdata *data = irq_data_get_irq_chip_data(d); 65 + 66 + msg->address_hi = upper_32_bits(data->doorbell_addr); 67 + msg->address_lo = lower_32_bits(data->doorbell_addr); 68 + msg->data = 1 << d->hwirq; 69 + } 70 + 71 + static const struct irq_chip sg2042_msi_middle_irq_chip = { 72 + .name = "SG2042 MSI", 73 + .irq_ack = sg2042_msi_irq_ack, 74 + .irq_mask = irq_chip_mask_parent, 75 + .irq_unmask = irq_chip_unmask_parent, 76 + #ifdef CONFIG_SMP 77 + .irq_set_affinity = irq_chip_set_affinity_parent, 78 + #endif 79 + .irq_compose_msi_msg = sg2042_msi_irq_compose_msi_msg, 80 + }; 81 + 82 + static int sg2042_msi_parent_domain_alloc(struct irq_domain *domain, unsigned int virq, int hwirq) 83 + { 84 + struct sg2042_msi_chipdata *data = domain->host_data; 85 + struct irq_fwspec fwspec; 86 + struct irq_data *d; 87 + int ret; 88 + 89 + fwspec.fwnode = domain->parent->fwnode; 90 + fwspec.param_count = 2; 91 + fwspec.param[0] = data->irq_first + hwirq; 92 + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; 93 + 94 + ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); 95 + if (ret) 96 + return ret; 97 + 98 + d = irq_domain_get_irq_data(domain->parent, virq); 99 + return d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); 100 + } 101 + 102 + static int sg2042_msi_middle_domain_alloc(struct irq_domain *domain, unsigned int virq, 103 + unsigned int nr_irqs, void *args) 104 + { 105 + struct sg2042_msi_chipdata *data = domain->host_data; 106 + int hwirq, err, i; 107 + 108 + hwirq = sg2042_msi_allocate_hwirq(data, nr_irqs); 109 + if (hwirq < 0) 110 + return hwirq; 111 + 112 + for (i = 0; i < nr_irqs; i++) { 113 + err = sg2042_msi_parent_domain_alloc(domain, virq + i, hwirq + i); 114 + if (err) 115 + goto err_hwirq; 116 + 117 + irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, 118 + &sg2042_msi_middle_irq_chip, data); 119 + } 120 + 121 + return 0; 122 + 123 + err_hwirq: 124 + sg2042_msi_free_hwirq(data, hwirq, nr_irqs); 125 + irq_domain_free_irqs_parent(domain, virq, i); 126 + 127 + return err; 128 + } 129 + 130 + static void sg2042_msi_middle_domain_free(struct irq_domain *domain, unsigned int virq, 131 + unsigned int nr_irqs) 132 + { 133 + struct irq_data *d = irq_domain_get_irq_data(domain, virq); 134 + struct sg2042_msi_chipdata *data = irq_data_get_irq_chip_data(d); 135 + 136 + irq_domain_free_irqs_parent(domain, virq, nr_irqs); 137 + sg2042_msi_free_hwirq(data, d->hwirq, nr_irqs); 138 + } 139 + 140 + static const struct irq_domain_ops sg2042_msi_middle_domain_ops = { 141 + .alloc = sg2042_msi_middle_domain_alloc, 142 + .free = sg2042_msi_middle_domain_free, 143 + .select = msi_lib_irq_domain_select, 144 + }; 145 + 146 + #define SG2042_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ 147 + MSI_FLAG_USE_DEF_CHIP_OPS) 148 + 149 + #define SG2042_MSI_FLAGS_SUPPORTED MSI_GENERIC_FLAGS_MASK 150 + 151 + static const struct msi_parent_ops sg2042_msi_parent_ops = { 152 + .required_flags = SG2042_MSI_FLAGS_REQUIRED, 153 + .supported_flags = SG2042_MSI_FLAGS_SUPPORTED, 154 + .bus_select_mask = MATCH_PCI_MSI, 155 + .bus_select_token = DOMAIN_BUS_NEXUS, 156 + .prefix = "SG2042-", 157 + .init_dev_msi_info = msi_lib_init_dev_msi_info, 158 + }; 159 + 160 + static int sg2042_msi_init_domains(struct sg2042_msi_chipdata *data, 161 + struct irq_domain *plic_domain, struct device *dev) 162 + { 163 + struct fwnode_handle *fwnode = dev_fwnode(dev); 164 + struct irq_domain *middle_domain; 165 + 166 + middle_domain = irq_domain_create_hierarchy(plic_domain, 0, data->num_irqs, fwnode, 167 + &sg2042_msi_middle_domain_ops, data); 168 + if (!middle_domain) { 169 + pr_err("Failed to create the MSI middle domain\n"); 170 + return -ENOMEM; 171 + } 172 + 173 + irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS); 174 + 175 + middle_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; 176 + middle_domain->msi_parent_ops = &sg2042_msi_parent_ops; 177 + 178 + return 0; 179 + } 180 + 181 + static int sg2042_msi_probe(struct platform_device *pdev) 182 + { 183 + struct fwnode_reference_args args = { }; 184 + struct sg2042_msi_chipdata *data; 185 + struct device *dev = &pdev->dev; 186 + struct irq_domain *plic_domain; 187 + struct resource *res; 188 + int ret; 189 + 190 + data = devm_kzalloc(dev, sizeof(struct sg2042_msi_chipdata), GFP_KERNEL); 191 + if (!data) 192 + return -ENOMEM; 193 + 194 + data->reg_clr = devm_platform_ioremap_resource_byname(pdev, "clr"); 195 + if (IS_ERR(data->reg_clr)) { 196 + dev_err(dev, "Failed to map clear register\n"); 197 + return PTR_ERR(data->reg_clr); 198 + } 199 + 200 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "doorbell"); 201 + if (!res) { 202 + dev_err(dev, "Failed get resource from set\n"); 203 + return -EINVAL; 204 + } 205 + data->doorbell_addr = res->start; 206 + 207 + ret = fwnode_property_get_reference_args(dev_fwnode(dev), "msi-ranges", 208 + "#interrupt-cells", 0, 0, &args); 209 + if (ret) { 210 + dev_err(dev, "Unable to parse MSI vec base\n"); 211 + return ret; 212 + } 213 + fwnode_handle_put(args.fwnode); 214 + 215 + ret = fwnode_property_get_reference_args(dev_fwnode(dev), "msi-ranges", NULL, 216 + args.nargs + 1, 0, &args); 217 + if (ret) { 218 + dev_err(dev, "Unable to parse MSI vec number\n"); 219 + return ret; 220 + } 221 + 222 + plic_domain = irq_find_matching_fwnode(args.fwnode, DOMAIN_BUS_ANY); 223 + fwnode_handle_put(args.fwnode); 224 + if (!plic_domain) { 225 + pr_err("Failed to find the PLIC domain\n"); 226 + return -ENXIO; 227 + } 228 + 229 + data->irq_first = (u32)args.args[0]; 230 + data->num_irqs = (u32)args.args[args.nargs - 1]; 231 + 232 + mutex_init(&data->msi_map_lock); 233 + 234 + return sg2042_msi_init_domains(data, plic_domain, dev); 235 + } 236 + 237 + static const struct of_device_id sg2042_msi_of_match[] = { 238 + { .compatible = "sophgo,sg2042-msi" }, 239 + { } 240 + }; 241 + 242 + static struct platform_driver sg2042_msi_driver = { 243 + .driver = { 244 + .name = "sg2042-msi", 245 + .of_match_table = sg2042_msi_of_match, 246 + }, 247 + .probe = sg2042_msi_probe, 248 + }; 249 + builtin_platform_driver(sg2042_msi_driver);
+50 -35
drivers/irqchip/irq-sunxi-nmi.c
··· 48 48 SUNXI_SRC_TYPE_EDGE_RISING, 49 49 }; 50 50 51 - struct sunxi_sc_nmi_reg_offs { 52 - u32 ctrl; 53 - u32 pend; 54 - u32 enable; 51 + struct sunxi_sc_nmi_data { 52 + struct { 53 + u32 ctrl; 54 + u32 pend; 55 + u32 enable; 56 + } reg_offs; 57 + u32 enable_val; 55 58 }; 56 59 57 - static const struct sunxi_sc_nmi_reg_offs sun6i_reg_offs __initconst = { 58 - .ctrl = SUN6I_NMI_CTRL, 59 - .pend = SUN6I_NMI_PENDING, 60 - .enable = SUN6I_NMI_ENABLE, 60 + static const struct sunxi_sc_nmi_data sun6i_data __initconst = { 61 + .reg_offs.ctrl = SUN6I_NMI_CTRL, 62 + .reg_offs.pend = SUN6I_NMI_PENDING, 63 + .reg_offs.enable = SUN6I_NMI_ENABLE, 61 64 }; 62 65 63 - static const struct sunxi_sc_nmi_reg_offs sun7i_reg_offs __initconst = { 64 - .ctrl = SUN7I_NMI_CTRL, 65 - .pend = SUN7I_NMI_PENDING, 66 - .enable = SUN7I_NMI_ENABLE, 66 + static const struct sunxi_sc_nmi_data sun7i_data __initconst = { 67 + .reg_offs.ctrl = SUN7I_NMI_CTRL, 68 + .reg_offs.pend = SUN7I_NMI_PENDING, 69 + .reg_offs.enable = SUN7I_NMI_ENABLE, 67 70 }; 68 71 69 - static const struct sunxi_sc_nmi_reg_offs sun9i_reg_offs __initconst = { 70 - .ctrl = SUN9I_NMI_CTRL, 71 - .pend = SUN9I_NMI_PENDING, 72 - .enable = SUN9I_NMI_ENABLE, 72 + static const struct sunxi_sc_nmi_data sun9i_data __initconst = { 73 + .reg_offs.ctrl = SUN9I_NMI_CTRL, 74 + .reg_offs.pend = SUN9I_NMI_PENDING, 75 + .reg_offs.enable = SUN9I_NMI_ENABLE, 73 76 }; 74 77 75 - static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off, 76 - u32 val) 78 + static const struct sunxi_sc_nmi_data sun55i_a523_data __initconst = { 79 + .reg_offs.ctrl = SUN9I_NMI_CTRL, 80 + .reg_offs.pend = SUN9I_NMI_PENDING, 81 + .reg_offs.enable = SUN9I_NMI_ENABLE, 82 + .enable_val = BIT(31), 83 + }; 84 + 85 + static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off, u32 val) 77 86 { 78 87 irq_reg_writel(gc, val, off); 79 88 } ··· 152 143 } 153 144 154 145 static int __init sunxi_sc_nmi_irq_init(struct device_node *node, 155 - const struct sunxi_sc_nmi_reg_offs *reg_offs) 146 + const struct sunxi_sc_nmi_data *data) 156 147 { 157 - struct irq_domain *domain; 148 + unsigned int irq, clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; 158 149 struct irq_chip_generic *gc; 159 - unsigned int irq; 160 - unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; 150 + struct irq_domain *domain; 161 151 int ret; 162 - 163 152 164 153 domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL); 165 154 if (!domain) { ··· 193 186 gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; 194 187 gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit; 195 188 gc->chip_types[0].chip.irq_set_type = sunxi_sc_nmi_set_type; 196 - gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED | 189 + gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | 190 + IRQCHIP_EOI_IF_HANDLED | 197 191 IRQCHIP_SKIP_SET_WAKE; 198 - gc->chip_types[0].regs.ack = reg_offs->pend; 199 - gc->chip_types[0].regs.mask = reg_offs->enable; 200 - gc->chip_types[0].regs.type = reg_offs->ctrl; 192 + gc->chip_types[0].regs.ack = data->reg_offs.pend; 193 + gc->chip_types[0].regs.mask = data->reg_offs.enable; 194 + gc->chip_types[0].regs.type = data->reg_offs.ctrl; 201 195 202 196 gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; 203 197 gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit; 204 198 gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; 205 199 gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; 206 200 gc->chip_types[1].chip.irq_set_type = sunxi_sc_nmi_set_type; 207 - gc->chip_types[1].regs.ack = reg_offs->pend; 208 - gc->chip_types[1].regs.mask = reg_offs->enable; 209 - gc->chip_types[1].regs.type = reg_offs->ctrl; 201 + gc->chip_types[1].regs.ack = data->reg_offs.pend; 202 + gc->chip_types[1].regs.mask = data->reg_offs.enable; 203 + gc->chip_types[1].regs.type = data->reg_offs.ctrl; 210 204 gc->chip_types[1].handler = handle_edge_irq; 211 205 212 206 /* Disable any active interrupts */ 213 - sunxi_sc_nmi_write(gc, reg_offs->enable, 0); 207 + sunxi_sc_nmi_write(gc, data->reg_offs.enable, data->enable_val); 214 208 215 209 /* Clear any pending NMI interrupts */ 216 - sunxi_sc_nmi_write(gc, reg_offs->pend, SUNXI_NMI_IRQ_BIT); 210 + sunxi_sc_nmi_write(gc, data->reg_offs.pend, SUNXI_NMI_IRQ_BIT); 217 211 218 212 irq_set_chained_handler_and_data(irq, sunxi_sc_nmi_handle_irq, domain); 219 213 ··· 229 221 static int __init sun6i_sc_nmi_irq_init(struct device_node *node, 230 222 struct device_node *parent) 231 223 { 232 - return sunxi_sc_nmi_irq_init(node, &sun6i_reg_offs); 224 + return sunxi_sc_nmi_irq_init(node, &sun6i_data); 233 225 } 234 226 IRQCHIP_DECLARE(sun6i_sc_nmi, "allwinner,sun6i-a31-sc-nmi", sun6i_sc_nmi_irq_init); 235 227 236 228 static int __init sun7i_sc_nmi_irq_init(struct device_node *node, 237 229 struct device_node *parent) 238 230 { 239 - return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs); 231 + return sunxi_sc_nmi_irq_init(node, &sun7i_data); 240 232 } 241 233 IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init); 242 234 243 235 static int __init sun9i_nmi_irq_init(struct device_node *node, 244 236 struct device_node *parent) 245 237 { 246 - return sunxi_sc_nmi_irq_init(node, &sun9i_reg_offs); 238 + return sunxi_sc_nmi_irq_init(node, &sun9i_data); 247 239 } 248 240 IRQCHIP_DECLARE(sun9i_nmi, "allwinner,sun9i-a80-nmi", sun9i_nmi_irq_init); 241 + 242 + static int __init sun55i_nmi_irq_init(struct device_node *node, 243 + struct device_node *parent) 244 + { 245 + return sunxi_sc_nmi_irq_init(node, &sun55i_a523_data); 246 + } 247 + IRQCHIP_DECLARE(sun55i_nmi, "allwinner,sun55i-a523-nmi", sun55i_nmi_irq_init);
+5 -2
include/linux/irq.h
··· 486 486 * @ipi_send_mask: send an IPI to destination cpus in cpumask 487 487 * @irq_nmi_setup: function called from core code before enabling an NMI 488 488 * @irq_nmi_teardown: function called from core code after disabling an NMI 489 + * @irq_force_complete_move: optional function to force complete pending irq move 489 490 * @flags: chip specific flags 490 491 */ 491 492 struct irq_chip { ··· 537 536 538 537 int (*irq_nmi_setup)(struct irq_data *data); 539 538 void (*irq_nmi_teardown)(struct irq_data *data); 539 + 540 + void (*irq_force_complete_move)(struct irq_data *data); 540 541 541 542 unsigned long flags; 542 543 }; ··· 615 612 #endif 616 613 617 614 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) 615 + bool irq_can_move_in_process_context(struct irq_data *data); 618 616 void __irq_move_irq(struct irq_data *data); 619 617 static inline void irq_move_irq(struct irq_data *data) 620 618 { ··· 623 619 __irq_move_irq(data); 624 620 } 625 621 void irq_move_masked_irq(struct irq_data *data); 626 - void irq_force_complete_move(struct irq_desc *desc); 627 622 #else 623 + static inline bool irq_can_move_in_process_context(struct irq_data *data) { return true; } 628 624 static inline void irq_move_irq(struct irq_data *data) { } 629 625 static inline void irq_move_masked_irq(struct irq_data *data) { } 630 - static inline void irq_force_complete_move(struct irq_desc *desc) { } 631 626 #endif 632 627 633 628 extern int no_irq_affinity;
-25
include/linux/irqchip/irq-davinci-cp-intc.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 - /* 3 - * Copyright (C) 2019 Texas Instruments 4 - */ 5 - 6 - #ifndef _LINUX_IRQ_DAVINCI_CP_INTC_ 7 - #define _LINUX_IRQ_DAVINCI_CP_INTC_ 8 - 9 - #include <linux/ioport.h> 10 - 11 - /** 12 - * struct davinci_cp_intc_config - configuration data for davinci-cp-intc 13 - * driver. 14 - * 15 - * @reg: register range to map 16 - * @num_irqs: number of HW interrupts supported by the controller 17 - */ 18 - struct davinci_cp_intc_config { 19 - struct resource reg; 20 - unsigned int num_irqs; 21 - }; 22 - 23 - int davinci_cp_intc_init(const struct davinci_cp_intc_config *config); 24 - 25 - #endif /* _LINUX_IRQ_DAVINCI_CP_INTC_ */
+11
include/linux/msi.h
··· 560 560 MSI_FLAG_NO_AFFINITY = (1 << 21), 561 561 }; 562 562 563 + /* 564 + * Flags for msi_parent_ops::chip_flags 565 + */ 566 + enum { 567 + MSI_CHIP_FLAG_SET_EOI = (1 << 0), 568 + MSI_CHIP_FLAG_SET_ACK = (1 << 1), 569 + }; 570 + 563 571 /** 564 572 * struct msi_parent_ops - MSI parent domain callbacks and configuration info 565 573 * 566 574 * @supported_flags: Required: The supported MSI flags of the parent domain 567 575 * @required_flags: Optional: The required MSI flags of the parent MSI domain 576 + * @chip_flags: Optional: Select MSI chip callbacks to update with defaults 577 + * in msi_lib_init_dev_msi_info(). 568 578 * @bus_select_token: Optional: The bus token of the real parent domain for 569 579 * irq_domain::select() 570 580 * @bus_select_mask: Optional: A mask of supported BUS_DOMAINs for ··· 587 577 struct msi_parent_ops { 588 578 u32 supported_flags; 589 579 u32 required_flags; 580 + u32 chip_flags; 590 581 u32 bus_select_token; 591 582 u32 bus_select_mask; 592 583 const char *prefix;
+2
kernel/irq/internals.h
··· 433 433 return desc->pending_mask; 434 434 } 435 435 bool irq_fixup_move_pending(struct irq_desc *desc, bool force_clear); 436 + void irq_force_complete_move(struct irq_desc *desc); 436 437 #else /* CONFIG_GENERIC_PENDING_IRQ */ 437 438 static inline bool irq_can_move_pcntxt(struct irq_data *data) 438 439 { ··· 459 458 { 460 459 return false; 461 460 } 461 + static inline void irq_force_complete_move(struct irq_desc *desc) { } 462 462 #endif /* !CONFIG_GENERIC_PENDING_IRQ */ 463 463 464 464 #if !defined(CONFIG_IRQ_DOMAIN) || !defined(CONFIG_IRQ_DOMAIN_HIERARCHY)
+20
kernel/irq/migration.c
··· 35 35 return true; 36 36 } 37 37 38 + void irq_force_complete_move(struct irq_desc *desc) 39 + { 40 + for (struct irq_data *d = irq_desc_get_irq_data(desc); d; d = d->parent_data) { 41 + if (d->chip && d->chip->irq_force_complete_move) { 42 + d->chip->irq_force_complete_move(d); 43 + return; 44 + } 45 + } 46 + } 47 + 38 48 void irq_move_masked_irq(struct irq_data *idata) 39 49 { 40 50 struct irq_desc *desc = irq_data_to_desc(idata); ··· 126 116 irq_move_masked_irq(idata); 127 117 if (!masked) 128 118 idata->chip->irq_unmask(idata); 119 + } 120 + 121 + bool irq_can_move_in_process_context(struct irq_data *data) 122 + { 123 + /* 124 + * Get the top level irq_data in the hierarchy, which is optimized 125 + * away when CONFIG_IRQ_DOMAIN_HIERARCHY is disabled. 126 + */ 127 + data = irq_desc_get_irq_data(irq_data_to_desc(data)); 128 + return irq_can_move_pcntxt(data); 129 129 }