diff options
-rw-r--r-- | Documentation/admin-guide/kernel-parameters.txt | 8 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt | 22 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt | 78 | ||||
-rw-r--r-- | arch/arm/include/asm/arch_gicv3.h | 47 | ||||
-rw-r--r-- | arch/arm64/include/asm/arch_gicv3.h | 5 | ||||
-rw-r--r-- | drivers/irqchip/Kconfig | 14 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-common.c | 9 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 267 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 99 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic.c | 44 | ||||
-rw-r--r-- | drivers/irqchip/irq-mscc-ocelot.c | 118 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-intc-irqpin.c | 40 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-irqc.c | 30 | ||||
-rw-r--r-- | drivers/irqchip/qcom-pdc.c | 311 | ||||
-rw-r--r-- | include/linux/irqchip/arm-gic-v3.h | 4 |
16 files changed, 956 insertions, 142 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 1d1d53f85ddd..60130231db3b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt | |||
@@ -1743,6 +1743,14 @@ | |||
1743 | of a GICv2 controller even if the memory range | 1743 | of a GICv2 controller even if the memory range |
1744 | exposed by the device tree is too small. | 1744 | exposed by the device tree is too small. |
1745 | 1745 | ||
1746 | irqchip.gicv3_nolpi= | ||
1747 | [ARM, ARM64] | ||
1748 | Force the kernel to ignore the availability of | ||
1749 | LPIs (and by consequence ITSs). Intended for system | ||
1750 | that use the kernel as a bootloader, and thus want | ||
1751 | to let secondary kernels in charge of setting up | ||
1752 | LPIs. | ||
1753 | |||
1746 | irqfixup [HW] | 1754 | irqfixup [HW] |
1747 | When an interrupt is not handled search all handlers | 1755 | When an interrupt is not handled search all handlers |
1748 | for it. Intended to get systems with badly broken | 1756 | for it. Intended to get systems with badly broken |
diff --git a/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt new file mode 100644 index 000000000000..b47a8a02b17b --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt | |||
@@ -0,0 +1,22 @@ | |||
1 | Microsemi Ocelot SoC ICPU Interrupt Controller | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible : should be "mscc,ocelot-icpu-intr" | ||
6 | - reg : Specifies base physical address and size of the registers. | ||
7 | - interrupt-controller : Identifies the node as an interrupt controller | ||
8 | - #interrupt-cells : Specifies the number of cells needed to encode an | ||
9 | interrupt source. The value shall be 1. | ||
10 | - interrupt-parent : phandle of the CPU interrupt controller. | ||
11 | - interrupts : Specifies the CPU interrupt the controller is connected to. | ||
12 | |||
13 | Example: | ||
14 | |||
15 | intc: interrupt-controller@70000070 { | ||
16 | compatible = "mscc,ocelot-icpu-intr"; | ||
17 | reg = <0x70000070 0x70>; | ||
18 | #interrupt-cells = <1>; | ||
19 | interrupt-controller; | ||
20 | interrupt-parent = <&cpuintc>; | ||
21 | interrupts = <2>; | ||
22 | }; | ||
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt new file mode 100644 index 000000000000..0b2c97ddb520 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt | |||
@@ -0,0 +1,78 @@ | |||
1 | PDC interrupt controller | ||
2 | |||
3 | Qualcomm Technologies Inc. SoCs based on the RPM Hardened architecture have a | ||
4 | Power Domain Controller (PDC) that is on always-on domain. In addition to | ||
5 | providing power control for the power domains, the hardware also has an | ||
6 | interrupt controller that can be used to help detect edge low interrupts as | ||
7 | well detect interrupts when the GIC is non-operational. | ||
8 | |||
9 | GIC is parent interrupt controller at the highest level. Platform interrupt | ||
10 | controller PDC is next in hierarchy, followed by others. Drivers requiring | ||
11 | wakeup capabilities of their device interrupts routed through the PDC, must | ||
12 | specify PDC as their interrupt controller and request the PDC port associated | ||
13 | with the GIC interrupt. See example below. | ||
14 | |||
15 | Properties: | ||
16 | |||
17 | - compatible: | ||
18 | Usage: required | ||
19 | Value type: <string> | ||
20 | Definition: Should contain "qcom,<soc>-pdc" | ||
21 | - "qcom,sdm845-pdc": For SDM845 | ||
22 | |||
23 | - reg: | ||
24 | Usage: required | ||
25 | Value type: <prop-encoded-array> | ||
26 | Definition: Specifies the base physical address for PDC hardware. | ||
27 | |||
28 | - interrupt-cells: | ||
29 | Usage: required | ||
30 | Value type: <u32> | ||
31 | Definition: Specifies the number of cells needed to encode an interrupt | ||
32 | source. | ||
33 | Must be 2. | ||
34 | The first element of the tuple is the PDC pin for the | ||
35 | interrupt. | ||
36 | The second element is the trigger type. | ||
37 | |||
38 | - interrupt-parent: | ||
39 | Usage: required | ||
40 | Value type: <phandle> | ||
41 | Definition: Specifies the interrupt parent necessary for hierarchical | ||
42 | domain to operate. | ||
43 | |||
44 | - interrupt-controller: | ||
45 | Usage: required | ||
46 | Value type: <bool> | ||
47 | Definition: Identifies the node as an interrupt controller. | ||
48 | |||
49 | - qcom,pdc-ranges: | ||
50 | Usage: required | ||
51 | Value type: <u32 array> | ||
52 | Definition: Specifies the PDC pin offset and the number of PDC ports. | ||
53 | The tuples indicates the valid mapping of valid PDC ports | ||
54 | and their hwirq mapping. | ||
55 | The first element of the tuple is the starting PDC port. | ||
56 | The second element is the GIC hwirq number for the PDC port. | ||
57 | The third element is the number of interrupts in sequence. | ||
58 | |||
59 | Example: | ||
60 | |||
61 | pdc: interrupt-controller@b220000 { | ||
62 | compatible = "qcom,sdm845-pdc"; | ||
63 | reg = <0xb220000 0x30000>; | ||
64 | qcom,pdc-ranges = <0 512 94>, <94 641 15>, <115 662 7>; | ||
65 | #interrupt-cells = <2>; | ||
66 | interrupt-parent = <&intc>; | ||
67 | interrupt-controller; | ||
68 | }; | ||
69 | |||
70 | DT binding of a device that wants to use the GIC SPI 514 as a wakeup | ||
71 | interrupt, must do - | ||
72 | |||
73 | wake-device { | ||
74 | interrupts-extended = <&pdc 2 IRQ_TYPE_LEVEL_HIGH>; | ||
75 | }; | ||
76 | |||
77 | In this case interrupt 514 would be mapped to port 2 on the PDC as defined by | ||
78 | the qcom,pdc-ranges property. | ||
diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h index 1070044f5c3f..0bd530702118 100644 --- a/arch/arm/include/asm/arch_gicv3.h +++ b/arch/arm/include/asm/arch_gicv3.h | |||
@@ -35,6 +35,18 @@ | |||
35 | #define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) | 35 | #define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) |
36 | #define ICC_BPR1 __ACCESS_CP15(c12, 0, c12, 3) | 36 | #define ICC_BPR1 __ACCESS_CP15(c12, 0, c12, 3) |
37 | 37 | ||
38 | #define __ICC_AP0Rx(x) __ACCESS_CP15(c12, 0, c8, 4 | x) | ||
39 | #define ICC_AP0R0 __ICC_AP0Rx(0) | ||
40 | #define ICC_AP0R1 __ICC_AP0Rx(1) | ||
41 | #define ICC_AP0R2 __ICC_AP0Rx(2) | ||
42 | #define ICC_AP0R3 __ICC_AP0Rx(3) | ||
43 | |||
44 | #define __ICC_AP1Rx(x) __ACCESS_CP15(c12, 0, c9, x) | ||
45 | #define ICC_AP1R0 __ICC_AP1Rx(0) | ||
46 | #define ICC_AP1R1 __ICC_AP1Rx(1) | ||
47 | #define ICC_AP1R2 __ICC_AP1Rx(2) | ||
48 | #define ICC_AP1R3 __ICC_AP1Rx(3) | ||
49 | |||
38 | #define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) | 50 | #define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) |
39 | 51 | ||
40 | #define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) | 52 | #define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) |
@@ -86,17 +98,17 @@ | |||
86 | #define ICH_LRC14 __LRC8(6) | 98 | #define ICH_LRC14 __LRC8(6) |
87 | #define ICH_LRC15 __LRC8(7) | 99 | #define ICH_LRC15 __LRC8(7) |
88 | 100 | ||
89 | #define __AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x) | 101 | #define __ICH_AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x) |
90 | #define ICH_AP0R0 __AP0Rx(0) | 102 | #define ICH_AP0R0 __ICH_AP0Rx(0) |
91 | #define ICH_AP0R1 __AP0Rx(1) | 103 | #define ICH_AP0R1 __ICH_AP0Rx(1) |
92 | #define ICH_AP0R2 __AP0Rx(2) | 104 | #define ICH_AP0R2 __ICH_AP0Rx(2) |
93 | #define ICH_AP0R3 __AP0Rx(3) | 105 | #define ICH_AP0R3 __ICH_AP0Rx(3) |
94 | 106 | ||
95 | #define __AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x) | 107 | #define __ICH_AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x) |
96 | #define ICH_AP1R0 __AP1Rx(0) | 108 | #define ICH_AP1R0 __ICH_AP1Rx(0) |
97 | #define ICH_AP1R1 __AP1Rx(1) | 109 | #define ICH_AP1R1 __ICH_AP1Rx(1) |
98 | #define ICH_AP1R2 __AP1Rx(2) | 110 | #define ICH_AP1R2 __ICH_AP1Rx(2) |
99 | #define ICH_AP1R3 __AP1Rx(3) | 111 | #define ICH_AP1R3 __ICH_AP1Rx(3) |
100 | 112 | ||
101 | /* A32-to-A64 mappings used by VGIC save/restore */ | 113 | /* A32-to-A64 mappings used by VGIC save/restore */ |
102 | 114 | ||
@@ -125,6 +137,16 @@ static inline u64 read_ ## a64(void) \ | |||
125 | return val; \ | 137 | return val; \ |
126 | } | 138 | } |
127 | 139 | ||
140 | CPUIF_MAP(ICC_PMR, ICC_PMR_EL1) | ||
141 | CPUIF_MAP(ICC_AP0R0, ICC_AP0R0_EL1) | ||
142 | CPUIF_MAP(ICC_AP0R1, ICC_AP0R1_EL1) | ||
143 | CPUIF_MAP(ICC_AP0R2, ICC_AP0R2_EL1) | ||
144 | CPUIF_MAP(ICC_AP0R3, ICC_AP0R3_EL1) | ||
145 | CPUIF_MAP(ICC_AP1R0, ICC_AP1R0_EL1) | ||
146 | CPUIF_MAP(ICC_AP1R1, ICC_AP1R1_EL1) | ||
147 | CPUIF_MAP(ICC_AP1R2, ICC_AP1R2_EL1) | ||
148 | CPUIF_MAP(ICC_AP1R3, ICC_AP1R3_EL1) | ||
149 | |||
128 | CPUIF_MAP(ICH_HCR, ICH_HCR_EL2) | 150 | CPUIF_MAP(ICH_HCR, ICH_HCR_EL2) |
129 | CPUIF_MAP(ICH_VTR, ICH_VTR_EL2) | 151 | CPUIF_MAP(ICH_VTR, ICH_VTR_EL2) |
130 | CPUIF_MAP(ICH_MISR, ICH_MISR_EL2) | 152 | CPUIF_MAP(ICH_MISR, ICH_MISR_EL2) |
@@ -185,11 +207,6 @@ static inline u32 gic_read_iar(void) | |||
185 | return irqstat; | 207 | return irqstat; |
186 | } | 208 | } |
187 | 209 | ||
188 | static inline void gic_write_pmr(u32 val) | ||
189 | { | ||
190 | write_sysreg(val, ICC_PMR); | ||
191 | } | ||
192 | |||
193 | static inline void gic_write_ctlr(u32 val) | 210 | static inline void gic_write_ctlr(u32 val) |
194 | { | 211 | { |
195 | write_sysreg(val, ICC_CTLR); | 212 | write_sysreg(val, ICC_CTLR); |
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index 9becba9ab392..e278f94df0c9 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h | |||
@@ -76,11 +76,6 @@ static inline u64 gic_read_iar_cavium_thunderx(void) | |||
76 | return irqstat; | 76 | return irqstat; |
77 | } | 77 | } |
78 | 78 | ||
79 | static inline void gic_write_pmr(u32 val) | ||
80 | { | ||
81 | write_sysreg_s(val, SYS_ICC_PMR_EL1); | ||
82 | } | ||
83 | |||
84 | static inline void gic_write_ctlr(u32 val) | 79 | static inline void gic_write_ctlr(u32 val) |
85 | { | 80 | { |
86 | write_sysreg_s(val, SYS_ICC_CTLR_EL1); | 81 | write_sysreg_s(val, SYS_ICC_CTLR_EL1); |
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d913aec85109..60d5982d8234 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -286,6 +286,11 @@ config IRQ_MXS | |||
286 | select IRQ_DOMAIN | 286 | select IRQ_DOMAIN |
287 | select STMP_DEVICE | 287 | select STMP_DEVICE |
288 | 288 | ||
289 | config MSCC_OCELOT_IRQ | ||
290 | bool | ||
291 | select IRQ_DOMAIN | ||
292 | select GENERIC_IRQ_CHIP | ||
293 | |||
289 | config MVEBU_GICP | 294 | config MVEBU_GICP |
290 | bool | 295 | bool |
291 | 296 | ||
@@ -351,4 +356,13 @@ config GOLDFISH_PIC | |||
351 | Say yes here to enable Goldfish interrupt controller driver used | 356 | Say yes here to enable Goldfish interrupt controller driver used |
352 | for Goldfish based virtual platforms. | 357 | for Goldfish based virtual platforms. |
353 | 358 | ||
359 | config QCOM_PDC | ||
360 | bool "QCOM PDC" | ||
361 | depends on ARCH_QCOM | ||
362 | select IRQ_DOMAIN | ||
363 | select IRQ_DOMAIN_HIERARCHY | ||
364 | help | ||
365 | Power Domain Controller driver to manage and configure wakeup | ||
366 | IRQs for Qualcomm Technologies Inc (QTI) mobile chips. | ||
367 | |||
354 | endmenu | 368 | endmenu |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index d27e3e3619e0..935868c3292e 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -72,6 +72,7 @@ obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o | |||
72 | obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o | 72 | obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o |
73 | obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o | 73 | obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o |
74 | obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o | 74 | obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o |
75 | obj-$(CONFIG_MSCC_OCELOT_IRQ) += irq-mscc-ocelot.o | ||
75 | obj-$(CONFIG_MVEBU_GICP) += irq-mvebu-gicp.o | 76 | obj-$(CONFIG_MVEBU_GICP) += irq-mvebu-gicp.o |
76 | obj-$(CONFIG_MVEBU_ICU) += irq-mvebu-icu.o | 77 | obj-$(CONFIG_MVEBU_ICU) += irq-mvebu-icu.o |
77 | obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o | 78 | obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o |
@@ -85,3 +86,4 @@ obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o | |||
85 | obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o | 86 | obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o |
86 | obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o | 87 | obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o |
87 | obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o | 88 | obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o |
89 | obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o | ||
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 30017df5b54c..01e673c680cd 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c | |||
@@ -21,6 +21,8 @@ | |||
21 | 21 | ||
22 | #include "irq-gic-common.h" | 22 | #include "irq-gic-common.h" |
23 | 23 | ||
24 | static DEFINE_RAW_SPINLOCK(irq_controller_lock); | ||
25 | |||
24 | static const struct gic_kvm_info *gic_kvm_info; | 26 | static const struct gic_kvm_info *gic_kvm_info; |
25 | 27 | ||
26 | const struct gic_kvm_info *gic_get_kvm_info(void) | 28 | const struct gic_kvm_info *gic_get_kvm_info(void) |
@@ -53,11 +55,13 @@ int gic_configure_irq(unsigned int irq, unsigned int type, | |||
53 | u32 confoff = (irq / 16) * 4; | 55 | u32 confoff = (irq / 16) * 4; |
54 | u32 val, oldval; | 56 | u32 val, oldval; |
55 | int ret = 0; | 57 | int ret = 0; |
58 | unsigned long flags; | ||
56 | 59 | ||
57 | /* | 60 | /* |
58 | * Read current configuration register, and insert the config | 61 | * Read current configuration register, and insert the config |
59 | * for "irq", depending on "type". | 62 | * for "irq", depending on "type". |
60 | */ | 63 | */ |
64 | raw_spin_lock_irqsave(&irq_controller_lock, flags); | ||
61 | val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); | 65 | val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); |
62 | if (type & IRQ_TYPE_LEVEL_MASK) | 66 | if (type & IRQ_TYPE_LEVEL_MASK) |
63 | val &= ~confmask; | 67 | val &= ~confmask; |
@@ -65,8 +69,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, | |||
65 | val |= confmask; | 69 | val |= confmask; |
66 | 70 | ||
67 | /* If the current configuration is the same, then we are done */ | 71 | /* If the current configuration is the same, then we are done */ |
68 | if (val == oldval) | 72 | if (val == oldval) { |
73 | raw_spin_unlock_irqrestore(&irq_controller_lock, flags); | ||
69 | return 0; | 74 | return 0; |
75 | } | ||
70 | 76 | ||
71 | /* | 77 | /* |
72 | * Write back the new configuration, and possibly re-enable | 78 | * Write back the new configuration, and possibly re-enable |
@@ -84,6 +90,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, | |||
84 | pr_warn("GIC: PPI%d is secure or misconfigured\n", | 90 | pr_warn("GIC: PPI%d is secure or misconfigured\n", |
85 | irq - 16); | 91 | irq - 16); |
86 | } | 92 | } |
93 | raw_spin_unlock_irqrestore(&irq_controller_lock, flags); | ||
87 | 94 | ||
88 | if (sync_access) | 95 | if (sync_access) |
89 | sync_access(); | 96 | sync_access(); |
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1d3056f53747..cb952c073d77 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/of_platform.h> | 33 | #include <linux/of_platform.h> |
34 | #include <linux/percpu.h> | 34 | #include <linux/percpu.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/syscore_ops.h> | ||
36 | 37 | ||
37 | #include <linux/irqchip.h> | 38 | #include <linux/irqchip.h> |
38 | #include <linux/irqchip/arm-gic-v3.h> | 39 | #include <linux/irqchip/arm-gic-v3.h> |
@@ -46,6 +47,7 @@ | |||
46 | #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) | 47 | #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) |
47 | #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) | 48 | #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) |
48 | #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) | 49 | #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) |
50 | #define ITS_FLAGS_SAVE_SUSPEND_STATE (1ULL << 3) | ||
49 | 51 | ||
50 | #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) | 52 | #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) |
51 | 53 | ||
@@ -101,6 +103,8 @@ struct its_node { | |||
101 | struct its_collection *collections; | 103 | struct its_collection *collections; |
102 | struct fwnode_handle *fwnode_handle; | 104 | struct fwnode_handle *fwnode_handle; |
103 | u64 (*get_msi_base)(struct its_device *its_dev); | 105 | u64 (*get_msi_base)(struct its_device *its_dev); |
106 | u64 cbaser_save; | ||
107 | u32 ctlr_save; | ||
104 | struct list_head its_device_list; | 108 | struct list_head its_device_list; |
105 | u64 flags; | 109 | u64 flags; |
106 | unsigned long list_nr; | 110 | unsigned long list_nr; |
@@ -1875,16 +1879,6 @@ static void its_cpu_init_lpis(void) | |||
1875 | gic_data_rdist()->pend_page = pend_page; | 1879 | gic_data_rdist()->pend_page = pend_page; |
1876 | } | 1880 | } |
1877 | 1881 | ||
1878 | /* Disable LPIs */ | ||
1879 | val = readl_relaxed(rbase + GICR_CTLR); | ||
1880 | val &= ~GICR_CTLR_ENABLE_LPIS; | ||
1881 | writel_relaxed(val, rbase + GICR_CTLR); | ||
1882 | |||
1883 | /* | ||
1884 | * Make sure any change to the table is observable by the GIC. | ||
1885 | */ | ||
1886 | dsb(sy); | ||
1887 | |||
1888 | /* set PROPBASE */ | 1882 | /* set PROPBASE */ |
1889 | val = (page_to_phys(gic_rdists->prop_page) | | 1883 | val = (page_to_phys(gic_rdists->prop_page) | |
1890 | GICR_PROPBASER_InnerShareable | | 1884 | GICR_PROPBASER_InnerShareable | |
@@ -1938,52 +1932,53 @@ static void its_cpu_init_lpis(void) | |||
1938 | dsb(sy); | 1932 | dsb(sy); |
1939 | } | 1933 | } |
1940 | 1934 | ||
1941 | static void its_cpu_init_collection(void) | 1935 | static void its_cpu_init_collection(struct its_node *its) |
1942 | { | 1936 | { |
1943 | struct its_node *its; | 1937 | int cpu = smp_processor_id(); |
1944 | int cpu; | 1938 | u64 target; |
1945 | |||
1946 | spin_lock(&its_lock); | ||
1947 | cpu = smp_processor_id(); | ||
1948 | |||
1949 | list_for_each_entry(its, &its_nodes, entry) { | ||
1950 | u64 target; | ||
1951 | 1939 | ||
1952 | /* avoid cross node collections and its mapping */ | 1940 | /* avoid cross node collections and its mapping */ |
1953 | if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { | 1941 | if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { |
1954 | struct device_node *cpu_node; | 1942 | struct device_node *cpu_node; |
1955 | 1943 | ||
1956 | cpu_node = of_get_cpu_node(cpu, NULL); | 1944 | cpu_node = of_get_cpu_node(cpu, NULL); |
1957 | if (its->numa_node != NUMA_NO_NODE && | 1945 | if (its->numa_node != NUMA_NO_NODE && |
1958 | its->numa_node != of_node_to_nid(cpu_node)) | 1946 | its->numa_node != of_node_to_nid(cpu_node)) |
1959 | continue; | 1947 | return; |
1960 | } | 1948 | } |
1961 | 1949 | ||
1950 | /* | ||
1951 | * We now have to bind each collection to its target | ||
1952 | * redistributor. | ||
1953 | */ | ||
1954 | if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) { | ||
1962 | /* | 1955 | /* |
1963 | * We now have to bind each collection to its target | 1956 | * This ITS wants the physical address of the |
1964 | * redistributor. | 1957 | * redistributor. |
1965 | */ | 1958 | */ |
1966 | if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) { | 1959 | target = gic_data_rdist()->phys_base; |
1967 | /* | 1960 | } else { |
1968 | * This ITS wants the physical address of the | 1961 | /* This ITS wants a linear CPU number. */ |
1969 | * redistributor. | 1962 | target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER); |
1970 | */ | 1963 | target = GICR_TYPER_CPU_NUMBER(target) << 16; |
1971 | target = gic_data_rdist()->phys_base; | 1964 | } |
1972 | } else { | ||
1973 | /* | ||
1974 | * This ITS wants a linear CPU number. | ||
1975 | */ | ||
1976 | target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER); | ||
1977 | target = GICR_TYPER_CPU_NUMBER(target) << 16; | ||
1978 | } | ||
1979 | 1965 | ||
1980 | /* Perform collection mapping */ | 1966 | /* Perform collection mapping */ |
1981 | its->collections[cpu].target_address = target; | 1967 | its->collections[cpu].target_address = target; |
1982 | its->collections[cpu].col_id = cpu; | 1968 | its->collections[cpu].col_id = cpu; |
1983 | 1969 | ||
1984 | its_send_mapc(its, &its->collections[cpu], 1); | 1970 | its_send_mapc(its, &its->collections[cpu], 1); |
1985 | its_send_invall(its, &its->collections[cpu]); | 1971 | its_send_invall(its, &its->collections[cpu]); |
1986 | } | 1972 | } |
1973 | |||
1974 | static void its_cpu_init_collections(void) | ||
1975 | { | ||
1976 | struct its_node *its; | ||
1977 | |||
1978 | spin_lock(&its_lock); | ||
1979 | |||
1980 | list_for_each_entry(its, &its_nodes, entry) | ||
1981 | its_cpu_init_collection(its); | ||
1987 | 1982 | ||
1988 | spin_unlock(&its_lock); | 1983 | spin_unlock(&its_lock); |
1989 | } | 1984 | } |
@@ -3042,6 +3037,113 @@ static void its_enable_quirks(struct its_node *its) | |||
3042 | gic_enable_quirks(iidr, its_quirks, its); | 3037 | gic_enable_quirks(iidr, its_quirks, its); |
3043 | } | 3038 | } |
3044 | 3039 | ||
3040 | static int its_save_disable(void) | ||
3041 | { | ||
3042 | struct its_node *its; | ||
3043 | int err = 0; | ||
3044 | |||
3045 | spin_lock(&its_lock); | ||
3046 | list_for_each_entry(its, &its_nodes, entry) { | ||
3047 | void __iomem *base; | ||
3048 | |||
3049 | if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) | ||
3050 | continue; | ||
3051 | |||
3052 | base = its->base; | ||
3053 | its->ctlr_save = readl_relaxed(base + GITS_CTLR); | ||
3054 | err = its_force_quiescent(base); | ||
3055 | if (err) { | ||
3056 | pr_err("ITS@%pa: failed to quiesce: %d\n", | ||
3057 | &its->phys_base, err); | ||
3058 | writel_relaxed(its->ctlr_save, base + GITS_CTLR); | ||
3059 | goto err; | ||
3060 | } | ||
3061 | |||
3062 | its->cbaser_save = gits_read_cbaser(base + GITS_CBASER); | ||
3063 | } | ||
3064 | |||
3065 | err: | ||
3066 | if (err) { | ||
3067 | list_for_each_entry_continue_reverse(its, &its_nodes, entry) { | ||
3068 | void __iomem *base; | ||
3069 | |||
3070 | if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) | ||
3071 | continue; | ||
3072 | |||
3073 | base = its->base; | ||
3074 | writel_relaxed(its->ctlr_save, base + GITS_CTLR); | ||
3075 | } | ||
3076 | } | ||
3077 | spin_unlock(&its_lock); | ||
3078 | |||
3079 | return err; | ||
3080 | } | ||
3081 | |||
3082 | static void its_restore_enable(void) | ||
3083 | { | ||
3084 | struct its_node *its; | ||
3085 | int ret; | ||
3086 | |||
3087 | spin_lock(&its_lock); | ||
3088 | list_for_each_entry(its, &its_nodes, entry) { | ||
3089 | void __iomem *base; | ||
3090 | int i; | ||
3091 | |||
3092 | if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE)) | ||
3093 | continue; | ||
3094 | |||
3095 | base = its->base; | ||
3096 | |||
3097 | /* | ||
3098 | * Make sure that the ITS is disabled. If it fails to quiesce, | ||
3099 | * don't restore it since writing to CBASER or BASER<n> | ||
3100 | * registers is undefined according to the GIC v3 ITS | ||
3101 | * Specification. | ||
3102 | */ | ||
3103 | ret = its_force_quiescent(base); | ||
3104 | if (ret) { | ||
3105 | pr_err("ITS@%pa: failed to quiesce on resume: %d\n", | ||
3106 | &its->phys_base, ret); | ||
3107 | continue; | ||
3108 | } | ||
3109 | |||
3110 | gits_write_cbaser(its->cbaser_save, base + GITS_CBASER); | ||
3111 | |||
3112 | /* | ||
3113 | * Writing CBASER resets CREADR to 0, so make CWRITER and | ||
3114 | * cmd_write line up with it. | ||
3115 | */ | ||
3116 | its->cmd_write = its->cmd_base; | ||
3117 | gits_write_cwriter(0, base + GITS_CWRITER); | ||
3118 | |||
3119 | /* Restore GITS_BASER from the value cache. */ | ||
3120 | for (i = 0; i < GITS_BASER_NR_REGS; i++) { | ||
3121 | struct its_baser *baser = &its->tables[i]; | ||
3122 | |||
3123 | if (!(baser->val & GITS_BASER_VALID)) | ||
3124 | continue; | ||
3125 | |||
3126 | its_write_baser(its, baser, baser->val); | ||
3127 | } | ||
3128 | writel_relaxed(its->ctlr_save, base + GITS_CTLR); | ||
3129 | |||
3130 | /* | ||
3131 | * Reinit the collection if it's stored in the ITS. This is | ||
3132 | * indicated by the col_id being less than the HCC field. | ||
3133 | * CID < HCC as specified in the GIC v3 Documentation. | ||
3134 | */ | ||
3135 | if (its->collections[smp_processor_id()].col_id < | ||
3136 | GITS_TYPER_HCC(gic_read_typer(base + GITS_TYPER))) | ||
3137 | its_cpu_init_collection(its); | ||
3138 | } | ||
3139 | spin_unlock(&its_lock); | ||
3140 | } | ||
3141 | |||
3142 | static struct syscore_ops its_syscore_ops = { | ||
3143 | .suspend = its_save_disable, | ||
3144 | .resume = its_restore_enable, | ||
3145 | }; | ||
3146 | |||
3045 | static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) | 3147 | static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) |
3046 | { | 3148 | { |
3047 | struct irq_domain *inner_domain; | 3149 | struct irq_domain *inner_domain; |
@@ -3261,6 +3363,9 @@ static int __init its_probe_one(struct resource *res, | |||
3261 | ctlr |= GITS_CTLR_ImDe; | 3363 | ctlr |= GITS_CTLR_ImDe; |
3262 | writel_relaxed(ctlr, its->base + GITS_CTLR); | 3364 | writel_relaxed(ctlr, its->base + GITS_CTLR); |
3263 | 3365 | ||
3366 | if (GITS_TYPER_HCC(typer)) | ||
3367 | its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE; | ||
3368 | |||
3264 | err = its_init_domain(handle, its); | 3369 | err = its_init_domain(handle, its); |
3265 | if (err) | 3370 | if (err) |
3266 | goto out_free_tables; | 3371 | goto out_free_tables; |
@@ -3288,15 +3393,71 @@ static bool gic_rdists_supports_plpis(void) | |||
3288 | return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS); | 3393 | return !!(gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS); |
3289 | } | 3394 | } |
3290 | 3395 | ||
3396 | static int redist_disable_lpis(void) | ||
3397 | { | ||
3398 | void __iomem *rbase = gic_data_rdist_rd_base(); | ||
3399 | u64 timeout = USEC_PER_SEC; | ||
3400 | u64 val; | ||
3401 | |||
3402 | if (!gic_rdists_supports_plpis()) { | ||
3403 | pr_info("CPU%d: LPIs not supported\n", smp_processor_id()); | ||
3404 | return -ENXIO; | ||
3405 | } | ||
3406 | |||
3407 | val = readl_relaxed(rbase + GICR_CTLR); | ||
3408 | if (!(val & GICR_CTLR_ENABLE_LPIS)) | ||
3409 | return 0; | ||
3410 | |||
3411 | pr_warn("CPU%d: Booted with LPIs enabled, memory probably corrupted\n", | ||
3412 | smp_processor_id()); | ||
3413 | add_taint(TAINT_CRAP, LOCKDEP_STILL_OK); | ||
3414 | |||
3415 | /* Disable LPIs */ | ||
3416 | val &= ~GICR_CTLR_ENABLE_LPIS; | ||
3417 | writel_relaxed(val, rbase + GICR_CTLR); | ||
3418 | |||
3419 | /* Make sure any change to GICR_CTLR is observable by the GIC */ | ||
3420 | dsb(sy); | ||
3421 | |||
3422 | /* | ||
3423 | * Software must observe RWP==0 after clearing GICR_CTLR.EnableLPIs | ||
3424 | * from 1 to 0 before programming GICR_PEND{PROP}BASER registers. | ||
3425 | * Error out if we time out waiting for RWP to clear. | ||
3426 | */ | ||
3427 | while (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_RWP) { | ||
3428 | if (!timeout) { | ||
3429 | pr_err("CPU%d: Timeout while disabling LPIs\n", | ||
3430 | smp_processor_id()); | ||
3431 | return -ETIMEDOUT; | ||
3432 | } | ||
3433 | udelay(1); | ||
3434 | timeout--; | ||
3435 | } | ||
3436 | |||
3437 | /* | ||
3438 | * After it has been written to 1, it is IMPLEMENTATION | ||
3439 | * DEFINED whether GICR_CTLR.EnableLPI becomes RES1 or can be | ||
3440 | * cleared to 0. Error out if clearing the bit failed. | ||
3441 | */ | ||
3442 | if (readl_relaxed(rbase + GICR_CTLR) & GICR_CTLR_ENABLE_LPIS) { | ||
3443 | pr_err("CPU%d: Failed to disable LPIs\n", smp_processor_id()); | ||
3444 | return -EBUSY; | ||
3445 | } | ||
3446 | |||
3447 | return 0; | ||
3448 | } | ||
3449 | |||
3291 | int its_cpu_init(void) | 3450 | int its_cpu_init(void) |
3292 | { | 3451 | { |
3293 | if (!list_empty(&its_nodes)) { | 3452 | if (!list_empty(&its_nodes)) { |
3294 | if (!gic_rdists_supports_plpis()) { | 3453 | int ret; |
3295 | pr_info("CPU%d: LPIs not supported\n", smp_processor_id()); | 3454 | |
3296 | return -ENXIO; | 3455 | ret = redist_disable_lpis(); |
3297 | } | 3456 | if (ret) |
3457 | return ret; | ||
3458 | |||
3298 | its_cpu_init_lpis(); | 3459 | its_cpu_init_lpis(); |
3299 | its_cpu_init_collection(); | 3460 | its_cpu_init_collections(); |
3300 | } | 3461 | } |
3301 | 3462 | ||
3302 | return 0; | 3463 | return 0; |
@@ -3517,5 +3678,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, | |||
3517 | } | 3678 | } |
3518 | } | 3679 | } |
3519 | 3680 | ||
3681 | register_syscore_ops(&its_syscore_ops); | ||
3682 | |||
3520 | return 0; | 3683 | return 0; |
3521 | } | 3684 | } |
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d99cc07903ec..e5d101418390 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c | |||
@@ -61,7 +61,7 @@ struct gic_chip_data { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | static struct gic_chip_data gic_data __read_mostly; | 63 | static struct gic_chip_data gic_data __read_mostly; |
64 | static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE; | 64 | static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); |
65 | 65 | ||
66 | static struct gic_kvm_info gic_v3_kvm_info; | 66 | static struct gic_kvm_info gic_v3_kvm_info; |
67 | static DEFINE_PER_CPU(bool, has_rss); | 67 | static DEFINE_PER_CPU(bool, has_rss); |
@@ -354,7 +354,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs | |||
354 | if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { | 354 | if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { |
355 | int err; | 355 | int err; |
356 | 356 | ||
357 | if (static_key_true(&supports_deactivate)) | 357 | if (static_branch_likely(&supports_deactivate_key)) |
358 | gic_write_eoir(irqnr); | 358 | gic_write_eoir(irqnr); |
359 | else | 359 | else |
360 | isb(); | 360 | isb(); |
@@ -362,7 +362,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs | |||
362 | err = handle_domain_irq(gic_data.domain, irqnr, regs); | 362 | err = handle_domain_irq(gic_data.domain, irqnr, regs); |
363 | if (err) { | 363 | if (err) { |
364 | WARN_ONCE(true, "Unexpected interrupt received!\n"); | 364 | WARN_ONCE(true, "Unexpected interrupt received!\n"); |
365 | if (static_key_true(&supports_deactivate)) { | 365 | if (static_branch_likely(&supports_deactivate_key)) { |
366 | if (irqnr < 8192) | 366 | if (irqnr < 8192) |
367 | gic_write_dir(irqnr); | 367 | gic_write_dir(irqnr); |
368 | } else { | 368 | } else { |
@@ -373,7 +373,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs | |||
373 | } | 373 | } |
374 | if (irqnr < 16) { | 374 | if (irqnr < 16) { |
375 | gic_write_eoir(irqnr); | 375 | gic_write_eoir(irqnr); |
376 | if (static_key_true(&supports_deactivate)) | 376 | if (static_branch_likely(&supports_deactivate_key)) |
377 | gic_write_dir(irqnr); | 377 | gic_write_dir(irqnr); |
378 | #ifdef CONFIG_SMP | 378 | #ifdef CONFIG_SMP |
379 | /* | 379 | /* |
@@ -532,6 +532,8 @@ static void gic_cpu_sys_reg_init(void) | |||
532 | int i, cpu = smp_processor_id(); | 532 | int i, cpu = smp_processor_id(); |
533 | u64 mpidr = cpu_logical_map(cpu); | 533 | u64 mpidr = cpu_logical_map(cpu); |
534 | u64 need_rss = MPIDR_RS(mpidr); | 534 | u64 need_rss = MPIDR_RS(mpidr); |
535 | bool group0; | ||
536 | u32 val, pribits; | ||
535 | 537 | ||
536 | /* | 538 | /* |
537 | * Need to check that the SRE bit has actually been set. If | 539 | * Need to check that the SRE bit has actually been set. If |
@@ -543,8 +545,28 @@ static void gic_cpu_sys_reg_init(void) | |||
543 | if (!gic_enable_sre()) | 545 | if (!gic_enable_sre()) |
544 | pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); | 546 | pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); |
545 | 547 | ||
548 | pribits = gic_read_ctlr(); | ||
549 | pribits &= ICC_CTLR_EL1_PRI_BITS_MASK; | ||
550 | pribits >>= ICC_CTLR_EL1_PRI_BITS_SHIFT; | ||
551 | pribits++; | ||
552 | |||
553 | /* | ||
554 | * Let's find out if Group0 is under control of EL3 or not by | ||
555 | * setting the highest possible, non-zero priority in PMR. | ||
556 | * | ||
557 | * If SCR_EL3.FIQ is set, the priority gets shifted down in | ||
558 | * order for the CPU interface to set bit 7, and keep the | ||
559 | * actual priority in the non-secure range. In the process, it | ||
560 | * looses the least significant bit and the actual priority | ||
561 | * becomes 0x80. Reading it back returns 0, indicating that | ||
562 | * we're don't have access to Group0. | ||
563 | */ | ||
564 | write_gicreg(BIT(8 - pribits), ICC_PMR_EL1); | ||
565 | val = read_gicreg(ICC_PMR_EL1); | ||
566 | group0 = val != 0; | ||
567 | |||
546 | /* Set priority mask register */ | 568 | /* Set priority mask register */ |
547 | gic_write_pmr(DEFAULT_PMR_VALUE); | 569 | write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1); |
548 | 570 | ||
549 | /* | 571 | /* |
550 | * Some firmwares hand over to the kernel with the BPR changed from | 572 | * Some firmwares hand over to the kernel with the BPR changed from |
@@ -554,7 +576,7 @@ static void gic_cpu_sys_reg_init(void) | |||
554 | */ | 576 | */ |
555 | gic_write_bpr1(0); | 577 | gic_write_bpr1(0); |
556 | 578 | ||
557 | if (static_key_true(&supports_deactivate)) { | 579 | if (static_branch_likely(&supports_deactivate_key)) { |
558 | /* EOI drops priority only (mode 1) */ | 580 | /* EOI drops priority only (mode 1) */ |
559 | gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop); | 581 | gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop); |
560 | } else { | 582 | } else { |
@@ -562,6 +584,37 @@ static void gic_cpu_sys_reg_init(void) | |||
562 | gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); | 584 | gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); |
563 | } | 585 | } |
564 | 586 | ||
587 | /* Always whack Group0 before Group1 */ | ||
588 | if (group0) { | ||
589 | switch(pribits) { | ||
590 | case 8: | ||
591 | case 7: | ||
592 | write_gicreg(0, ICC_AP0R3_EL1); | ||
593 | write_gicreg(0, ICC_AP0R2_EL1); | ||
594 | case 6: | ||
595 | write_gicreg(0, ICC_AP0R1_EL1); | ||
596 | case 5: | ||
597 | case 4: | ||
598 | write_gicreg(0, ICC_AP0R0_EL1); | ||
599 | } | ||
600 | |||
601 | isb(); | ||
602 | } | ||
603 | |||
604 | switch(pribits) { | ||
605 | case 8: | ||
606 | case 7: | ||
607 | write_gicreg(0, ICC_AP1R3_EL1); | ||
608 | write_gicreg(0, ICC_AP1R2_EL1); | ||
609 | case 6: | ||
610 | write_gicreg(0, ICC_AP1R1_EL1); | ||
611 | case 5: | ||
612 | case 4: | ||
613 | write_gicreg(0, ICC_AP1R0_EL1); | ||
614 | } | ||
615 | |||
616 | isb(); | ||
617 | |||
565 | /* ... and let's hit the road... */ | 618 | /* ... and let's hit the road... */ |
566 | gic_write_grpen1(1); | 619 | gic_write_grpen1(1); |
567 | 620 | ||
@@ -590,9 +643,17 @@ static void gic_cpu_sys_reg_init(void) | |||
590 | pr_crit_once("RSS is required but GICD doesn't support it\n"); | 643 | pr_crit_once("RSS is required but GICD doesn't support it\n"); |
591 | } | 644 | } |
592 | 645 | ||
646 | static bool gicv3_nolpi; | ||
647 | |||
648 | static int __init gicv3_nolpi_cfg(char *buf) | ||
649 | { | ||
650 | return strtobool(buf, &gicv3_nolpi); | ||
651 | } | ||
652 | early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg); | ||
653 | |||
593 | static int gic_dist_supports_lpis(void) | 654 | static int gic_dist_supports_lpis(void) |
594 | { | 655 | { |
595 | return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS); | 656 | return !!(readl_relaxed(gic_data.dist_base + GICD_TYPER) & GICD_TYPER_LPIS) && !gicv3_nolpi; |
596 | } | 657 | } |
597 | 658 | ||
598 | static void gic_cpu_init(void) | 659 | static void gic_cpu_init(void) |
@@ -823,7 +884,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, | |||
823 | { | 884 | { |
824 | struct irq_chip *chip = &gic_chip; | 885 | struct irq_chip *chip = &gic_chip; |
825 | 886 | ||
826 | if (static_key_true(&supports_deactivate)) | 887 | if (static_branch_likely(&supports_deactivate_key)) |
827 | chip = &gic_eoimode1_chip; | 888 | chip = &gic_eoimode1_chip; |
828 | 889 | ||
829 | /* SGIs are private to the core kernel */ | 890 | /* SGIs are private to the core kernel */ |
@@ -861,6 +922,8 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, | |||
861 | return 0; | 922 | return 0; |
862 | } | 923 | } |
863 | 924 | ||
925 | #define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) | ||
926 | |||
864 | static int gic_irq_domain_translate(struct irq_domain *d, | 927 | static int gic_irq_domain_translate(struct irq_domain *d, |
865 | struct irq_fwspec *fwspec, | 928 | struct irq_fwspec *fwspec, |
866 | unsigned long *hwirq, | 929 | unsigned long *hwirq, |
@@ -875,6 +938,7 @@ static int gic_irq_domain_translate(struct irq_domain *d, | |||
875 | *hwirq = fwspec->param[1] + 32; | 938 | *hwirq = fwspec->param[1] + 32; |
876 | break; | 939 | break; |
877 | case 1: /* PPI */ | 940 | case 1: /* PPI */ |
941 | case GIC_IRQ_TYPE_PARTITION: | ||
878 | *hwirq = fwspec->param[1] + 16; | 942 | *hwirq = fwspec->param[1] + 16; |
879 | break; | 943 | break; |
880 | case GIC_IRQ_TYPE_LPI: /* LPI */ | 944 | case GIC_IRQ_TYPE_LPI: /* LPI */ |
@@ -885,6 +949,13 @@ static int gic_irq_domain_translate(struct irq_domain *d, | |||
885 | } | 949 | } |
886 | 950 | ||
887 | *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; | 951 | *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; |
952 | |||
953 | /* | ||
954 | * Make it clear that broken DTs are... broken. | ||
955 | * Partitionned PPIs are an unfortunate exception. | ||
956 | */ | ||
957 | WARN_ON(*type == IRQ_TYPE_NONE && | ||
958 | fwspec->param[0] != GIC_IRQ_TYPE_PARTITION); | ||
888 | return 0; | 959 | return 0; |
889 | } | 960 | } |
890 | 961 | ||
@@ -894,6 +965,8 @@ static int gic_irq_domain_translate(struct irq_domain *d, | |||
894 | 965 | ||
895 | *hwirq = fwspec->param[0]; | 966 | *hwirq = fwspec->param[0]; |
896 | *type = fwspec->param[1]; | 967 | *type = fwspec->param[1]; |
968 | |||
969 | WARN_ON(*type == IRQ_TYPE_NONE); | ||
897 | return 0; | 970 | return 0; |
898 | } | 971 | } |
899 | 972 | ||
@@ -1002,9 +1075,9 @@ static int __init gic_init_bases(void __iomem *dist_base, | |||
1002 | int err; | 1075 | int err; |
1003 | 1076 | ||
1004 | if (!is_hyp_mode_available()) | 1077 | if (!is_hyp_mode_available()) |
1005 | static_key_slow_dec(&supports_deactivate); | 1078 | static_branch_disable(&supports_deactivate_key); |
1006 | 1079 | ||
1007 | if (static_key_true(&supports_deactivate)) | 1080 | if (static_branch_likely(&supports_deactivate_key)) |
1008 | pr_info("GIC: Using split EOI/Deactivate mode\n"); | 1081 | pr_info("GIC: Using split EOI/Deactivate mode\n"); |
1009 | 1082 | ||
1010 | gic_data.fwnode = handle; | 1083 | gic_data.fwnode = handle; |
@@ -1140,7 +1213,7 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) | |||
1140 | .fwnode = gic_data.fwnode, | 1213 | .fwnode = gic_data.fwnode, |
1141 | .param_count = 3, | 1214 | .param_count = 3, |
1142 | .param = { | 1215 | .param = { |
1143 | [0] = 1, | 1216 | [0] = GIC_IRQ_TYPE_PARTITION, |
1144 | [1] = i, | 1217 | [1] = i, |
1145 | [2] = IRQ_TYPE_NONE, | 1218 | [2] = IRQ_TYPE_NONE, |
1146 | }, | 1219 | }, |
@@ -1239,7 +1312,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare | |||
1239 | 1312 | ||
1240 | gic_populate_ppi_partitions(node); | 1313 | gic_populate_ppi_partitions(node); |
1241 | 1314 | ||
1242 | if (static_key_true(&supports_deactivate)) | 1315 | if (static_branch_likely(&supports_deactivate_key)) |
1243 | gic_of_setup_kvm_info(node); | 1316 | gic_of_setup_kvm_info(node); |
1244 | return 0; | 1317 | return 0; |
1245 | 1318 | ||
@@ -1541,7 +1614,7 @@ gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end) | |||
1541 | 1614 | ||
1542 | acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); | 1615 | acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); |
1543 | 1616 | ||
1544 | if (static_key_true(&supports_deactivate)) | 1617 | if (static_branch_likely(&supports_deactivate_key)) |
1545 | gic_acpi_setup_kvm_info(); | 1618 | gic_acpi_setup_kvm_info(); |
1546 | 1619 | ||
1547 | return 0; | 1620 | return 0; |
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 121af5cf688f..ced10c44b68a 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c | |||
@@ -121,7 +121,7 @@ static DEFINE_RAW_SPINLOCK(cpu_map_lock); | |||
121 | #define NR_GIC_CPU_IF 8 | 121 | #define NR_GIC_CPU_IF 8 |
122 | static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly; | 122 | static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly; |
123 | 123 | ||
124 | static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE; | 124 | static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); |
125 | 125 | ||
126 | static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly; | 126 | static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly; |
127 | 127 | ||
@@ -361,7 +361,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) | |||
361 | irqnr = irqstat & GICC_IAR_INT_ID_MASK; | 361 | irqnr = irqstat & GICC_IAR_INT_ID_MASK; |
362 | 362 | ||
363 | if (likely(irqnr > 15 && irqnr < 1020)) { | 363 | if (likely(irqnr > 15 && irqnr < 1020)) { |
364 | if (static_key_true(&supports_deactivate)) | 364 | if (static_branch_likely(&supports_deactivate_key)) |
365 | writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); | 365 | writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); |
366 | isb(); | 366 | isb(); |
367 | handle_domain_irq(gic->domain, irqnr, regs); | 367 | handle_domain_irq(gic->domain, irqnr, regs); |
@@ -369,7 +369,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) | |||
369 | } | 369 | } |
370 | if (irqnr < 16) { | 370 | if (irqnr < 16) { |
371 | writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); | 371 | writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); |
372 | if (static_key_true(&supports_deactivate)) | 372 | if (static_branch_likely(&supports_deactivate_key)) |
373 | writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE); | 373 | writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE); |
374 | #ifdef CONFIG_SMP | 374 | #ifdef CONFIG_SMP |
375 | /* | 375 | /* |
@@ -453,15 +453,26 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic) | |||
453 | return mask; | 453 | return mask; |
454 | } | 454 | } |
455 | 455 | ||
456 | static bool gic_check_gicv2(void __iomem *base) | ||
457 | { | ||
458 | u32 val = readl_relaxed(base + GIC_CPU_IDENT); | ||
459 | return (val & 0xff0fff) == 0x02043B; | ||
460 | } | ||
461 | |||
456 | static void gic_cpu_if_up(struct gic_chip_data *gic) | 462 | static void gic_cpu_if_up(struct gic_chip_data *gic) |
457 | { | 463 | { |
458 | void __iomem *cpu_base = gic_data_cpu_base(gic); | 464 | void __iomem *cpu_base = gic_data_cpu_base(gic); |
459 | u32 bypass = 0; | 465 | u32 bypass = 0; |
460 | u32 mode = 0; | 466 | u32 mode = 0; |
467 | int i; | ||
461 | 468 | ||
462 | if (gic == &gic_data[0] && static_key_true(&supports_deactivate)) | 469 | if (gic == &gic_data[0] && static_branch_likely(&supports_deactivate_key)) |
463 | mode = GIC_CPU_CTRL_EOImodeNS; | 470 | mode = GIC_CPU_CTRL_EOImodeNS; |
464 | 471 | ||
472 | if (gic_check_gicv2(cpu_base)) | ||
473 | for (i = 0; i < 4; i++) | ||
474 | writel_relaxed(0, cpu_base + GIC_CPU_ACTIVEPRIO + i * 4); | ||
475 | |||
465 | /* | 476 | /* |
466 | * Preserve bypass disable bits to be written back later | 477 | * Preserve bypass disable bits to be written back later |
467 | */ | 478 | */ |
@@ -1000,6 +1011,9 @@ static int gic_irq_domain_translate(struct irq_domain *d, | |||
1000 | *hwirq += 16; | 1011 | *hwirq += 16; |
1001 | 1012 | ||
1002 | *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; | 1013 | *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; |
1014 | |||
1015 | /* Make it clear that broken DTs are... broken */ | ||
1016 | WARN_ON(*type == IRQ_TYPE_NONE); | ||
1003 | return 0; | 1017 | return 0; |
1004 | } | 1018 | } |
1005 | 1019 | ||
@@ -1009,6 +1023,8 @@ static int gic_irq_domain_translate(struct irq_domain *d, | |||
1009 | 1023 | ||
1010 | *hwirq = fwspec->param[0]; | 1024 | *hwirq = fwspec->param[0]; |
1011 | *type = fwspec->param[1]; | 1025 | *type = fwspec->param[1]; |
1026 | |||
1027 | WARN_ON(*type == IRQ_TYPE_NONE); | ||
1012 | return 0; | 1028 | return 0; |
1013 | } | 1029 | } |
1014 | 1030 | ||
@@ -1203,11 +1219,11 @@ static int __init __gic_init_bases(struct gic_chip_data *gic, | |||
1203 | "irqchip/arm/gic:starting", | 1219 | "irqchip/arm/gic:starting", |
1204 | gic_starting_cpu, NULL); | 1220 | gic_starting_cpu, NULL); |
1205 | set_handle_irq(gic_handle_irq); | 1221 | set_handle_irq(gic_handle_irq); |
1206 | if (static_key_true(&supports_deactivate)) | 1222 | if (static_branch_likely(&supports_deactivate_key)) |
1207 | pr_info("GIC: Using split EOI/Deactivate mode\n"); | 1223 | pr_info("GIC: Using split EOI/Deactivate mode\n"); |
1208 | } | 1224 | } |
1209 | 1225 | ||
1210 | if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) { | 1226 | if (static_branch_likely(&supports_deactivate_key) && gic == &gic_data[0]) { |
1211 | name = kasprintf(GFP_KERNEL, "GICv2"); | 1227 | name = kasprintf(GFP_KERNEL, "GICv2"); |
1212 | gic_init_chip(gic, NULL, name, true); | 1228 | gic_init_chip(gic, NULL, name, true); |
1213 | } else { | 1229 | } else { |
@@ -1234,7 +1250,7 @@ void __init gic_init(unsigned int gic_nr, int irq_start, | |||
1234 | * Non-DT/ACPI systems won't run a hypervisor, so let's not | 1250 | * Non-DT/ACPI systems won't run a hypervisor, so let's not |
1235 | * bother with these... | 1251 | * bother with these... |
1236 | */ | 1252 | */ |
1237 | static_key_slow_dec(&supports_deactivate); | 1253 | static_branch_disable(&supports_deactivate_key); |
1238 | 1254 | ||
1239 | gic = &gic_data[gic_nr]; | 1255 | gic = &gic_data[gic_nr]; |
1240 | gic->raw_dist_base = dist_base; | 1256 | gic->raw_dist_base = dist_base; |
@@ -1264,12 +1280,6 @@ static int __init gicv2_force_probe_cfg(char *buf) | |||
1264 | } | 1280 | } |
1265 | early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg); | 1281 | early_param("irqchip.gicv2_force_probe", gicv2_force_probe_cfg); |
1266 | 1282 | ||
1267 | static bool gic_check_gicv2(void __iomem *base) | ||
1268 | { | ||
1269 | u32 val = readl_relaxed(base + GIC_CPU_IDENT); | ||
1270 | return (val & 0xff0fff) == 0x02043B; | ||
1271 | } | ||
1272 | |||
1273 | static bool gic_check_eoimode(struct device_node *node, void __iomem **base) | 1283 | static bool gic_check_eoimode(struct device_node *node, void __iomem **base) |
1274 | { | 1284 | { |
1275 | struct resource cpuif_res; | 1285 | struct resource cpuif_res; |
@@ -1420,7 +1430,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) | |||
1420 | if (ret) | 1430 | if (ret) |
1421 | return; | 1431 | return; |
1422 | 1432 | ||
1423 | if (static_key_true(&supports_deactivate)) | 1433 | if (static_branch_likely(&supports_deactivate_key)) |
1424 | gic_set_kvm_info(&gic_v2_kvm_info); | 1434 | gic_set_kvm_info(&gic_v2_kvm_info); |
1425 | } | 1435 | } |
1426 | 1436 | ||
@@ -1447,7 +1457,7 @@ gic_of_init(struct device_node *node, struct device_node *parent) | |||
1447 | * or the CPU interface is too small. | 1457 | * or the CPU interface is too small. |
1448 | */ | 1458 | */ |
1449 | if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base)) | 1459 | if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base)) |
1450 | static_key_slow_dec(&supports_deactivate); | 1460 | static_branch_disable(&supports_deactivate_key); |
1451 | 1461 | ||
1452 | ret = __gic_init_bases(gic, -1, &node->fwnode); | 1462 | ret = __gic_init_bases(gic, -1, &node->fwnode); |
1453 | if (ret) { | 1463 | if (ret) { |
@@ -1628,7 +1638,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, | |||
1628 | * interface will always be the right size. | 1638 | * interface will always be the right size. |
1629 | */ | 1639 | */ |
1630 | if (!is_hyp_mode_available()) | 1640 | if (!is_hyp_mode_available()) |
1631 | static_key_slow_dec(&supports_deactivate); | 1641 | static_branch_disable(&supports_deactivate_key); |
1632 | 1642 | ||
1633 | /* | 1643 | /* |
1634 | * Initialize GIC instance zero (no multi-GIC support). | 1644 | * Initialize GIC instance zero (no multi-GIC support). |
@@ -1653,7 +1663,7 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, | |||
1653 | if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) | 1663 | if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) |
1654 | gicv2m_init(NULL, gic_data[0].domain); | 1664 | gicv2m_init(NULL, gic_data[0].domain); |
1655 | 1665 | ||
1656 | if (static_key_true(&supports_deactivate)) | 1666 | if (static_branch_likely(&supports_deactivate_key)) |
1657 | gic_acpi_setup_kvm_info(); | 1667 | gic_acpi_setup_kvm_info(); |
1658 | 1668 | ||
1659 | return 0; | 1669 | return 0; |
diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c new file mode 100644 index 000000000000..b63e40c00a02 --- /dev/null +++ b/drivers/irqchip/irq-mscc-ocelot.c | |||
@@ -0,0 +1,118 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | /* | ||
3 | * Microsemi Ocelot IRQ controller driver | ||
4 | * | ||
5 | * Copyright (c) 2017 Microsemi Corporation | ||
6 | */ | ||
7 | #include <linux/bitops.h> | ||
8 | #include <linux/irq.h> | ||
9 | #include <linux/of_address.h> | ||
10 | #include <linux/of_irq.h> | ||
11 | #include <linux/irqchip.h> | ||
12 | #include <linux/irqchip/chained_irq.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | |||
15 | #define ICPU_CFG_INTR_INTR_STICKY 0x10 | ||
16 | #define ICPU_CFG_INTR_INTR_ENA 0x18 | ||
17 | #define ICPU_CFG_INTR_INTR_ENA_CLR 0x1c | ||
18 | #define ICPU_CFG_INTR_INTR_ENA_SET 0x20 | ||
19 | #define ICPU_CFG_INTR_DST_INTR_IDENT(x) (0x38 + 0x4 * (x)) | ||
20 | #define ICPU_CFG_INTR_INTR_TRIGGER(x) (0x5c + 0x4 * (x)) | ||
21 | |||
22 | #define OCELOT_NR_IRQ 24 | ||
23 | |||
24 | static void ocelot_irq_unmask(struct irq_data *data) | ||
25 | { | ||
26 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); | ||
27 | struct irq_chip_type *ct = irq_data_get_chip_type(data); | ||
28 | unsigned int mask = data->mask; | ||
29 | u32 val; | ||
30 | |||
31 | irq_gc_lock(gc); | ||
32 | val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(0)) | | ||
33 | irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(1)); | ||
34 | if (!(val & mask)) | ||
35 | irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_STICKY); | ||
36 | |||
37 | *ct->mask_cache &= ~mask; | ||
38 | irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_ENA_SET); | ||
39 | irq_gc_unlock(gc); | ||
40 | } | ||
41 | |||
42 | static void ocelot_irq_handler(struct irq_desc *desc) | ||
43 | { | ||
44 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
45 | struct irq_domain *d = irq_desc_get_handler_data(desc); | ||
46 | struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); | ||
47 | u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(0)); | ||
48 | |||
49 | chained_irq_enter(chip, desc); | ||
50 | |||
51 | while (reg) { | ||
52 | u32 hwirq = __fls(reg); | ||
53 | |||
54 | generic_handle_irq(irq_find_mapping(d, hwirq)); | ||
55 | reg &= ~(BIT(hwirq)); | ||
56 | } | ||
57 | |||
58 | chained_irq_exit(chip, desc); | ||
59 | } | ||
60 | |||
61 | static int __init ocelot_irq_init(struct device_node *node, | ||
62 | struct device_node *parent) | ||
63 | { | ||
64 | struct irq_domain *domain; | ||
65 | struct irq_chip_generic *gc; | ||
66 | int parent_irq, ret; | ||
67 | |||
68 | parent_irq = irq_of_parse_and_map(node, 0); | ||
69 | if (!parent_irq) | ||
70 | return -EINVAL; | ||
71 | |||
72 | domain = irq_domain_add_linear(node, OCELOT_NR_IRQ, | ||
73 | &irq_generic_chip_ops, NULL); | ||
74 | if (!domain) { | ||
75 | pr_err("%s: unable to add irq domain\n", node->name); | ||
76 | return -ENOMEM; | ||
77 | } | ||
78 | |||
79 | ret = irq_alloc_domain_generic_chips(domain, OCELOT_NR_IRQ, 1, | ||
80 | "icpu", handle_level_irq, | ||
81 | 0, 0, 0); | ||
82 | if (ret) { | ||
83 | pr_err("%s: unable to alloc irq domain gc\n", node->name); | ||
84 | goto err_domain_remove; | ||
85 | } | ||
86 | |||
87 | gc = irq_get_domain_generic_chip(domain, 0); | ||
88 | gc->reg_base = of_iomap(node, 0); | ||
89 | if (!gc->reg_base) { | ||
90 | pr_err("%s: unable to map resource\n", node->name); | ||
91 | ret = -ENOMEM; | ||
92 | goto err_gc_free; | ||
93 | } | ||
94 | |||
95 | gc->chip_types[0].regs.ack = ICPU_CFG_INTR_INTR_STICKY; | ||
96 | gc->chip_types[0].regs.mask = ICPU_CFG_INTR_INTR_ENA_CLR; | ||
97 | gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; | ||
98 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; | ||
99 | gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask; | ||
100 | |||
101 | /* Mask and ack all interrupts */ | ||
102 | irq_reg_writel(gc, 0, ICPU_CFG_INTR_INTR_ENA); | ||
103 | irq_reg_writel(gc, 0xffffffff, ICPU_CFG_INTR_INTR_STICKY); | ||
104 | |||
105 | irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler, | ||
106 | domain); | ||
107 | |||
108 | return 0; | ||
109 | |||
110 | err_gc_free: | ||
111 | irq_free_generic_chip(gc); | ||
112 | |||
113 | err_domain_remove: | ||
114 | irq_domain_remove(domain); | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init); | ||
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index cee59fe1321c..c6e6c9e9137a 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c | |||
@@ -17,7 +17,6 @@ | |||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/init.h> | 20 | #include <linux/init.h> |
22 | #include <linux/of.h> | 21 | #include <linux/of.h> |
23 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
@@ -78,16 +77,14 @@ struct intc_irqpin_priv { | |||
78 | struct platform_device *pdev; | 77 | struct platform_device *pdev; |
79 | struct irq_chip irq_chip; | 78 | struct irq_chip irq_chip; |
80 | struct irq_domain *irq_domain; | 79 | struct irq_domain *irq_domain; |
81 | struct clk *clk; | 80 | atomic_t wakeup_path; |
82 | unsigned shared_irqs:1; | 81 | unsigned shared_irqs:1; |
83 | unsigned needs_clk:1; | ||
84 | u8 shared_irq_mask; | 82 | u8 shared_irq_mask; |
85 | }; | 83 | }; |
86 | 84 | ||
87 | struct intc_irqpin_config { | 85 | struct intc_irqpin_config { |
88 | unsigned int irlm_bit; | 86 | unsigned int irlm_bit; |
89 | unsigned needs_irlm:1; | 87 | unsigned needs_irlm:1; |
90 | unsigned needs_clk:1; | ||
91 | }; | 88 | }; |
92 | 89 | ||
93 | static unsigned long intc_irqpin_read32(void __iomem *iomem) | 90 | static unsigned long intc_irqpin_read32(void __iomem *iomem) |
@@ -287,14 +284,10 @@ static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on) | |||
287 | int hw_irq = irqd_to_hwirq(d); | 284 | int hw_irq = irqd_to_hwirq(d); |
288 | 285 | ||
289 | irq_set_irq_wake(p->irq[hw_irq].requested_irq, on); | 286 | irq_set_irq_wake(p->irq[hw_irq].requested_irq, on); |
290 | |||
291 | if (!p->clk) | ||
292 | return 0; | ||
293 | |||
294 | if (on) | 287 | if (on) |
295 | clk_enable(p->clk); | 288 | atomic_inc(&p->wakeup_path); |
296 | else | 289 | else |
297 | clk_disable(p->clk); | 290 | atomic_dec(&p->wakeup_path); |
298 | 291 | ||
299 | return 0; | 292 | return 0; |
300 | } | 293 | } |
@@ -369,12 +362,10 @@ static const struct irq_domain_ops intc_irqpin_irq_domain_ops = { | |||
369 | static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = { | 362 | static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = { |
370 | .irlm_bit = 23, /* ICR0.IRLM0 */ | 363 | .irlm_bit = 23, /* ICR0.IRLM0 */ |
371 | .needs_irlm = 1, | 364 | .needs_irlm = 1, |
372 | .needs_clk = 0, | ||
373 | }; | 365 | }; |
374 | 366 | ||
375 | static const struct intc_irqpin_config intc_irqpin_rmobile = { | 367 | static const struct intc_irqpin_config intc_irqpin_rmobile = { |
376 | .needs_irlm = 0, | 368 | .needs_irlm = 0, |
377 | .needs_clk = 1, | ||
378 | }; | 369 | }; |
379 | 370 | ||
380 | static const struct of_device_id intc_irqpin_dt_ids[] = { | 371 | static const struct of_device_id intc_irqpin_dt_ids[] = { |
@@ -426,18 +417,6 @@ static int intc_irqpin_probe(struct platform_device *pdev) | |||
426 | platform_set_drvdata(pdev, p); | 417 | platform_set_drvdata(pdev, p); |
427 | 418 | ||
428 | config = of_device_get_match_data(dev); | 419 | config = of_device_get_match_data(dev); |
429 | if (config) | ||
430 | p->needs_clk = config->needs_clk; | ||
431 | |||
432 | p->clk = devm_clk_get(dev, NULL); | ||
433 | if (IS_ERR(p->clk)) { | ||
434 | if (p->needs_clk) { | ||
435 | dev_err(dev, "unable to get clock\n"); | ||
436 | ret = PTR_ERR(p->clk); | ||
437 | goto err0; | ||
438 | } | ||
439 | p->clk = NULL; | ||
440 | } | ||
441 | 420 | ||
442 | pm_runtime_enable(dev); | 421 | pm_runtime_enable(dev); |
443 | pm_runtime_get_sync(dev); | 422 | pm_runtime_get_sync(dev); |
@@ -606,12 +585,25 @@ static int intc_irqpin_remove(struct platform_device *pdev) | |||
606 | return 0; | 585 | return 0; |
607 | } | 586 | } |
608 | 587 | ||
588 | static int __maybe_unused intc_irqpin_suspend(struct device *dev) | ||
589 | { | ||
590 | struct intc_irqpin_priv *p = dev_get_drvdata(dev); | ||
591 | |||
592 | if (atomic_read(&p->wakeup_path)) | ||
593 | device_set_wakeup_path(dev); | ||
594 | |||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); | ||
599 | |||
609 | static struct platform_driver intc_irqpin_device_driver = { | 600 | static struct platform_driver intc_irqpin_device_driver = { |
610 | .probe = intc_irqpin_probe, | 601 | .probe = intc_irqpin_probe, |
611 | .remove = intc_irqpin_remove, | 602 | .remove = intc_irqpin_remove, |
612 | .driver = { | 603 | .driver = { |
613 | .name = "renesas_intc_irqpin", | 604 | .name = "renesas_intc_irqpin", |
614 | .of_match_table = intc_irqpin_dt_ids, | 605 | .of_match_table = intc_irqpin_dt_ids, |
606 | .pm = &intc_irqpin_pm_ops, | ||
615 | } | 607 | } |
616 | }; | 608 | }; |
617 | 609 | ||
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 52304b139aa4..a4f11124024d 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c | |||
@@ -17,7 +17,6 @@ | |||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/init.h> | 20 | #include <linux/init.h> |
22 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
23 | #include <linux/spinlock.h> | 22 | #include <linux/spinlock.h> |
@@ -64,7 +63,7 @@ struct irqc_priv { | |||
64 | struct platform_device *pdev; | 63 | struct platform_device *pdev; |
65 | struct irq_chip_generic *gc; | 64 | struct irq_chip_generic *gc; |
66 | struct irq_domain *irq_domain; | 65 | struct irq_domain *irq_domain; |
67 | struct clk *clk; | 66 | atomic_t wakeup_path; |
68 | }; | 67 | }; |
69 | 68 | ||
70 | static struct irqc_priv *irq_data_to_priv(struct irq_data *data) | 69 | static struct irqc_priv *irq_data_to_priv(struct irq_data *data) |
@@ -111,14 +110,10 @@ static int irqc_irq_set_wake(struct irq_data *d, unsigned int on) | |||
111 | int hw_irq = irqd_to_hwirq(d); | 110 | int hw_irq = irqd_to_hwirq(d); |
112 | 111 | ||
113 | irq_set_irq_wake(p->irq[hw_irq].requested_irq, on); | 112 | irq_set_irq_wake(p->irq[hw_irq].requested_irq, on); |
114 | |||
115 | if (!p->clk) | ||
116 | return 0; | ||
117 | |||
118 | if (on) | 113 | if (on) |
119 | clk_enable(p->clk); | 114 | atomic_inc(&p->wakeup_path); |
120 | else | 115 | else |
121 | clk_disable(p->clk); | 116 | atomic_dec(&p->wakeup_path); |
122 | 117 | ||
123 | return 0; | 118 | return 0; |
124 | } | 119 | } |
@@ -159,12 +154,6 @@ static int irqc_probe(struct platform_device *pdev) | |||
159 | p->pdev = pdev; | 154 | p->pdev = pdev; |
160 | platform_set_drvdata(pdev, p); | 155 | platform_set_drvdata(pdev, p); |
161 | 156 | ||
162 | p->clk = devm_clk_get(&pdev->dev, NULL); | ||
163 | if (IS_ERR(p->clk)) { | ||
164 | dev_warn(&pdev->dev, "unable to get clock\n"); | ||
165 | p->clk = NULL; | ||
166 | } | ||
167 | |||
168 | pm_runtime_enable(&pdev->dev); | 157 | pm_runtime_enable(&pdev->dev); |
169 | pm_runtime_get_sync(&pdev->dev); | 158 | pm_runtime_get_sync(&pdev->dev); |
170 | 159 | ||
@@ -276,6 +265,18 @@ static int irqc_remove(struct platform_device *pdev) | |||
276 | return 0; | 265 | return 0; |
277 | } | 266 | } |
278 | 267 | ||
268 | static int __maybe_unused irqc_suspend(struct device *dev) | ||
269 | { | ||
270 | struct irqc_priv *p = dev_get_drvdata(dev); | ||
271 | |||
272 | if (atomic_read(&p->wakeup_path)) | ||
273 | device_set_wakeup_path(dev); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static SIMPLE_DEV_PM_OPS(irqc_pm_ops, irqc_suspend, NULL); | ||
279 | |||
279 | static const struct of_device_id irqc_dt_ids[] = { | 280 | static const struct of_device_id irqc_dt_ids[] = { |
280 | { .compatible = "renesas,irqc", }, | 281 | { .compatible = "renesas,irqc", }, |
281 | {}, | 282 | {}, |
@@ -288,6 +289,7 @@ static struct platform_driver irqc_device_driver = { | |||
288 | .driver = { | 289 | .driver = { |
289 | .name = "renesas_irqc", | 290 | .name = "renesas_irqc", |
290 | .of_match_table = irqc_dt_ids, | 291 | .of_match_table = irqc_dt_ids, |
292 | .pm = &irqc_pm_ops, | ||
291 | } | 293 | } |
292 | }; | 294 | }; |
293 | 295 | ||
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c new file mode 100644 index 000000000000..b1b47a40a278 --- /dev/null +++ b/drivers/irqchip/qcom-pdc.c | |||
@@ -0,0 +1,311 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. | ||
4 | */ | ||
5 | |||
6 | #include <linux/err.h> | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/irq.h> | ||
9 | #include <linux/irqchip.h> | ||
10 | #include <linux/irqdomain.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/of.h> | ||
14 | #include <linux/of_address.h> | ||
15 | #include <linux/of_device.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/types.h> | ||
20 | |||
21 | #define PDC_MAX_IRQS 126 | ||
22 | |||
23 | #define CLEAR_INTR(reg, intr) (reg & ~(1 << intr)) | ||
24 | #define ENABLE_INTR(reg, intr) (reg | (1 << intr)) | ||
25 | |||
26 | #define IRQ_ENABLE_BANK 0x10 | ||
27 | #define IRQ_i_CFG 0x110 | ||
28 | |||
29 | struct pdc_pin_region { | ||
30 | u32 pin_base; | ||
31 | u32 parent_base; | ||
32 | u32 cnt; | ||
33 | }; | ||
34 | |||
35 | static DEFINE_RAW_SPINLOCK(pdc_lock); | ||
36 | static void __iomem *pdc_base; | ||
37 | static struct pdc_pin_region *pdc_region; | ||
38 | static int pdc_region_cnt; | ||
39 | |||
40 | static void pdc_reg_write(int reg, u32 i, u32 val) | ||
41 | { | ||
42 | writel_relaxed(val, pdc_base + reg + i * sizeof(u32)); | ||
43 | } | ||
44 | |||
45 | static u32 pdc_reg_read(int reg, u32 i) | ||
46 | { | ||
47 | return readl_relaxed(pdc_base + reg + i * sizeof(u32)); | ||
48 | } | ||
49 | |||
50 | static void pdc_enable_intr(struct irq_data *d, bool on) | ||
51 | { | ||
52 | int pin_out = d->hwirq; | ||
53 | u32 index, mask; | ||
54 | u32 enable; | ||
55 | |||
56 | index = pin_out / 32; | ||
57 | mask = pin_out % 32; | ||
58 | |||
59 | raw_spin_lock(&pdc_lock); | ||
60 | enable = pdc_reg_read(IRQ_ENABLE_BANK, index); | ||
61 | enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask); | ||
62 | pdc_reg_write(IRQ_ENABLE_BANK, index, enable); | ||
63 | raw_spin_unlock(&pdc_lock); | ||
64 | } | ||
65 | |||
66 | static void qcom_pdc_gic_mask(struct irq_data *d) | ||
67 | { | ||
68 | pdc_enable_intr(d, false); | ||
69 | irq_chip_mask_parent(d); | ||
70 | } | ||
71 | |||
72 | static void qcom_pdc_gic_unmask(struct irq_data *d) | ||
73 | { | ||
74 | pdc_enable_intr(d, true); | ||
75 | irq_chip_unmask_parent(d); | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * GIC does not handle falling edge or active low. To allow falling edge and | ||
80 | * active low interrupts to be handled at GIC, PDC has an inverter that inverts | ||
81 | * falling edge into a rising edge and active low into an active high. | ||
82 | * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to | ||
83 | * set as per the table below. | ||
84 | * Level sensitive active low LOW | ||
85 | * Rising edge sensitive NOT USED | ||
86 | * Falling edge sensitive LOW | ||
87 | * Dual Edge sensitive NOT USED | ||
88 | * Level sensitive active High HIGH | ||
89 | * Falling Edge sensitive NOT USED | ||
90 | * Rising edge sensitive HIGH | ||
91 | * Dual Edge sensitive HIGH | ||
92 | */ | ||
93 | enum pdc_irq_config_bits { | ||
94 | PDC_LEVEL_LOW = 0b000, | ||
95 | PDC_EDGE_FALLING = 0b010, | ||
96 | PDC_LEVEL_HIGH = 0b100, | ||
97 | PDC_EDGE_RISING = 0b110, | ||
98 | PDC_EDGE_DUAL = 0b111, | ||
99 | }; | ||
100 | |||
101 | /** | ||
102 | * qcom_pdc_gic_set_type: Configure PDC for the interrupt | ||
103 | * | ||
104 | * @d: the interrupt data | ||
105 | * @type: the interrupt type | ||
106 | * | ||
107 | * If @type is edge triggered, forward that as Rising edge as PDC | ||
108 | * takes care of converting falling edge to rising edge signal | ||
109 | * If @type is level, then forward that as level high as PDC | ||
110 | * takes care of converting falling edge to rising edge signal | ||
111 | */ | ||
112 | static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) | ||
113 | { | ||
114 | int pin_out = d->hwirq; | ||
115 | enum pdc_irq_config_bits pdc_type; | ||
116 | |||
117 | switch (type) { | ||
118 | case IRQ_TYPE_EDGE_RISING: | ||
119 | pdc_type = PDC_EDGE_RISING; | ||
120 | break; | ||
121 | case IRQ_TYPE_EDGE_FALLING: | ||
122 | pdc_type = PDC_EDGE_FALLING; | ||
123 | type = IRQ_TYPE_EDGE_RISING; | ||
124 | break; | ||
125 | case IRQ_TYPE_EDGE_BOTH: | ||
126 | pdc_type = PDC_EDGE_DUAL; | ||
127 | break; | ||
128 | case IRQ_TYPE_LEVEL_HIGH: | ||
129 | pdc_type = PDC_LEVEL_HIGH; | ||
130 | break; | ||
131 | case IRQ_TYPE_LEVEL_LOW: | ||
132 | pdc_type = PDC_LEVEL_LOW; | ||
133 | type = IRQ_TYPE_LEVEL_HIGH; | ||
134 | break; | ||
135 | default: | ||
136 | WARN_ON(1); | ||
137 | return -EINVAL; | ||
138 | } | ||
139 | |||
140 | pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type); | ||
141 | |||
142 | return irq_chip_set_type_parent(d, type); | ||
143 | } | ||
144 | |||
145 | static struct irq_chip qcom_pdc_gic_chip = { | ||
146 | .name = "PDC", | ||
147 | .irq_eoi = irq_chip_eoi_parent, | ||
148 | .irq_mask = qcom_pdc_gic_mask, | ||
149 | .irq_unmask = qcom_pdc_gic_unmask, | ||
150 | .irq_retrigger = irq_chip_retrigger_hierarchy, | ||
151 | .irq_set_type = qcom_pdc_gic_set_type, | ||
152 | .flags = IRQCHIP_MASK_ON_SUSPEND | | ||
153 | IRQCHIP_SET_TYPE_MASKED | | ||
154 | IRQCHIP_SKIP_SET_WAKE, | ||
155 | .irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent, | ||
156 | .irq_set_affinity = irq_chip_set_affinity_parent, | ||
157 | }; | ||
158 | |||
159 | static irq_hw_number_t get_parent_hwirq(int pin) | ||
160 | { | ||
161 | int i; | ||
162 | struct pdc_pin_region *region; | ||
163 | |||
164 | for (i = 0; i < pdc_region_cnt; i++) { | ||
165 | region = &pdc_region[i]; | ||
166 | if (pin >= region->pin_base && | ||
167 | pin < region->pin_base + region->cnt) | ||
168 | return (region->parent_base + pin - region->pin_base); | ||
169 | } | ||
170 | |||
171 | WARN_ON(1); | ||
172 | return ~0UL; | ||
173 | } | ||
174 | |||
175 | static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec, | ||
176 | unsigned long *hwirq, unsigned int *type) | ||
177 | { | ||
178 | if (is_of_node(fwspec->fwnode)) { | ||
179 | if (fwspec->param_count != 2) | ||
180 | return -EINVAL; | ||
181 | |||
182 | *hwirq = fwspec->param[0]; | ||
183 | *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq, | ||
191 | unsigned int nr_irqs, void *data) | ||
192 | { | ||
193 | struct irq_fwspec *fwspec = data; | ||
194 | struct irq_fwspec parent_fwspec; | ||
195 | irq_hw_number_t hwirq, parent_hwirq; | ||
196 | unsigned int type; | ||
197 | int ret; | ||
198 | |||
199 | ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type); | ||
200 | if (ret) | ||
201 | return -EINVAL; | ||
202 | |||
203 | parent_hwirq = get_parent_hwirq(hwirq); | ||
204 | if (parent_hwirq == ~0UL) | ||
205 | return -EINVAL; | ||
206 | |||
207 | ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, | ||
208 | &qcom_pdc_gic_chip, NULL); | ||
209 | if (ret) | ||
210 | return ret; | ||
211 | |||
212 | if (type & IRQ_TYPE_EDGE_BOTH) | ||
213 | type = IRQ_TYPE_EDGE_RISING; | ||
214 | |||
215 | if (type & IRQ_TYPE_LEVEL_MASK) | ||
216 | type = IRQ_TYPE_LEVEL_HIGH; | ||
217 | |||
218 | parent_fwspec.fwnode = domain->parent->fwnode; | ||
219 | parent_fwspec.param_count = 3; | ||
220 | parent_fwspec.param[0] = 0; | ||
221 | parent_fwspec.param[1] = parent_hwirq; | ||
222 | parent_fwspec.param[2] = type; | ||
223 | |||
224 | return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, | ||
225 | &parent_fwspec); | ||
226 | } | ||
227 | |||
228 | static const struct irq_domain_ops qcom_pdc_ops = { | ||
229 | .translate = qcom_pdc_translate, | ||
230 | .alloc = qcom_pdc_alloc, | ||
231 | .free = irq_domain_free_irqs_common, | ||
232 | }; | ||
233 | |||
234 | static int pdc_setup_pin_mapping(struct device_node *np) | ||
235 | { | ||
236 | int ret, n; | ||
237 | |||
238 | n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32)); | ||
239 | if (n <= 0 || n % 3) | ||
240 | return -EINVAL; | ||
241 | |||
242 | pdc_region_cnt = n / 3; | ||
243 | pdc_region = kcalloc(pdc_region_cnt, sizeof(*pdc_region), GFP_KERNEL); | ||
244 | if (!pdc_region) { | ||
245 | pdc_region_cnt = 0; | ||
246 | return -ENOMEM; | ||
247 | } | ||
248 | |||
249 | for (n = 0; n < pdc_region_cnt; n++) { | ||
250 | ret = of_property_read_u32_index(np, "qcom,pdc-ranges", | ||
251 | n * 3 + 0, | ||
252 | &pdc_region[n].pin_base); | ||
253 | if (ret) | ||
254 | return ret; | ||
255 | ret = of_property_read_u32_index(np, "qcom,pdc-ranges", | ||
256 | n * 3 + 1, | ||
257 | &pdc_region[n].parent_base); | ||
258 | if (ret) | ||
259 | return ret; | ||
260 | ret = of_property_read_u32_index(np, "qcom,pdc-ranges", | ||
261 | n * 3 + 2, | ||
262 | &pdc_region[n].cnt); | ||
263 | if (ret) | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int qcom_pdc_init(struct device_node *node, struct device_node *parent) | ||
271 | { | ||
272 | struct irq_domain *parent_domain, *pdc_domain; | ||
273 | int ret; | ||
274 | |||
275 | pdc_base = of_iomap(node, 0); | ||
276 | if (!pdc_base) { | ||
277 | pr_err("%pOF: unable to map PDC registers\n", node); | ||
278 | return -ENXIO; | ||
279 | } | ||
280 | |||
281 | parent_domain = irq_find_host(parent); | ||
282 | if (!parent_domain) { | ||
283 | pr_err("%pOF: unable to find PDC's parent domain\n", node); | ||
284 | ret = -ENXIO; | ||
285 | goto fail; | ||
286 | } | ||
287 | |||
288 | ret = pdc_setup_pin_mapping(node); | ||
289 | if (ret) { | ||
290 | pr_err("%pOF: failed to init PDC pin-hwirq mapping\n", node); | ||
291 | goto fail; | ||
292 | } | ||
293 | |||
294 | pdc_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_IRQS, | ||
295 | of_fwnode_handle(node), | ||
296 | &qcom_pdc_ops, NULL); | ||
297 | if (!pdc_domain) { | ||
298 | pr_err("%pOF: GIC domain add failed\n", node); | ||
299 | ret = -ENOMEM; | ||
300 | goto fail; | ||
301 | } | ||
302 | |||
303 | return 0; | ||
304 | |||
305 | fail: | ||
306 | kfree(pdc_region); | ||
307 | iounmap(pdc_base); | ||
308 | return ret; | ||
309 | } | ||
310 | |||
311 | IRQCHIP_DECLARE(pdc_sdm845, "qcom,sdm845-pdc", qcom_pdc_init); | ||
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index c00c4c33e432..5988473e4abf 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h | |||
@@ -106,6 +106,7 @@ | |||
106 | #define GICR_PIDR2 GICD_PIDR2 | 106 | #define GICR_PIDR2 GICD_PIDR2 |
107 | 107 | ||
108 | #define GICR_CTLR_ENABLE_LPIS (1UL << 0) | 108 | #define GICR_CTLR_ENABLE_LPIS (1UL << 0) |
109 | #define GICR_CTLR_RWP (1UL << 3) | ||
109 | 110 | ||
110 | #define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) | 111 | #define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) |
111 | 112 | ||
@@ -312,7 +313,8 @@ | |||
312 | #define GITS_TYPER_DEVBITS_SHIFT 13 | 313 | #define GITS_TYPER_DEVBITS_SHIFT 13 |
313 | #define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) | 314 | #define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) |
314 | #define GITS_TYPER_PTA (1UL << 19) | 315 | #define GITS_TYPER_PTA (1UL << 19) |
315 | #define GITS_TYPER_HWCOLLCNT_SHIFT 24 | 316 | #define GITS_TYPER_HCC_SHIFT 24 |
317 | #define GITS_TYPER_HCC(r) (((r) >> GITS_TYPER_HCC_SHIFT) & 0xff) | ||
316 | #define GITS_TYPER_VMOVP (1ULL << 37) | 318 | #define GITS_TYPER_VMOVP (1ULL << 37) |
317 | 319 | ||
318 | #define GITS_IIDR_REV_SHIFT 12 | 320 | #define GITS_IIDR_REV_SHIFT 12 |