Skip to content

Commit f112eea

Browse files
committed
Merge tag 'irq-urgent-2025-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq fixes from Ingo Molnar: "Fix miscellaneous irqchip bugs" * tag 'irq-urgent-2025-02-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: irqchip/qcom-pdc: Workaround hardware register bug on X1E80100 irqchip/jcore-aic, clocksource/drivers/jcore: Fix jcore-pit interrupt request irqchip/gic-v3: Fix rk3399 workaround when secure interrupts are enabled
2 parents cd59f1d + e9a48ea commit f112eea

File tree

4 files changed

+119
-18
lines changed

4 files changed

+119
-18
lines changed

drivers/clocksource/jcore-pit.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ static int jcore_pit_local_init(unsigned cpu)
114114
pit->periodic_delta = DIV_ROUND_CLOSEST(NSEC_PER_SEC, HZ * buspd);
115115

116116
clockevents_config_and_register(&pit->ced, freq, 1, ULONG_MAX);
117+
enable_percpu_irq(pit->ced.irq, IRQ_TYPE_NONE);
118+
119+
return 0;
120+
}
121+
122+
static int jcore_pit_local_teardown(unsigned cpu)
123+
{
124+
struct jcore_pit *pit = this_cpu_ptr(jcore_pit_percpu);
125+
126+
pr_info("Local J-Core PIT teardown on cpu %u\n", cpu);
127+
128+
disable_percpu_irq(pit->ced.irq);
117129

118130
return 0;
119131
}
@@ -168,6 +180,7 @@ static int __init jcore_pit_init(struct device_node *node)
168180
return -ENOMEM;
169181
}
170182

183+
irq_set_percpu_devid(pit_irq);
171184
err = request_percpu_irq(pit_irq, jcore_timer_interrupt,
172185
"jcore_pit", jcore_pit_percpu);
173186
if (err) {
@@ -237,7 +250,7 @@ static int __init jcore_pit_init(struct device_node *node)
237250

238251
cpuhp_setup_state(CPUHP_AP_JCORE_TIMER_STARTING,
239252
"clockevents/jcore:starting",
240-
jcore_pit_local_init, NULL);
253+
jcore_pit_local_init, jcore_pit_local_teardown);
241254

242255
return 0;
243256
}

drivers/irqchip/irq-gic-v3.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ static u8 dist_prio_nmi __ro_after_init = GICV3_PRIO_NMI;
4444
#define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0)
4545
#define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1)
4646
#define FLAGS_WORKAROUND_ASR_ERRATUM_8601001 (1ULL << 2)
47+
#define FLAGS_WORKAROUND_INSECURE (1ULL << 3)
4748

4849
#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
4950

@@ -83,6 +84,8 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
8384
#define GIC_LINE_NR min(GICD_TYPER_SPIS(gic_data.rdists.gicd_typer), 1020U)
8485
#define GIC_ESPI_NR GICD_TYPER_ESPIS(gic_data.rdists.gicd_typer)
8586

87+
static bool nmi_support_forbidden;
88+
8689
/*
8790
* There are 16 SGIs, though we only actually use 8 in Linux. The other 8 SGIs
8891
* are potentially stolen by the secure side. Some code, especially code dealing
@@ -163,21 +166,27 @@ static void __init gic_prio_init(void)
163166
{
164167
bool ds;
165168

166-
ds = gic_dist_security_disabled();
167-
if (!ds) {
168-
u32 val;
169-
170-
val = readl_relaxed(gic_data.dist_base + GICD_CTLR);
171-
val |= GICD_CTLR_DS;
172-
writel_relaxed(val, gic_data.dist_base + GICD_CTLR);
169+
cpus_have_group0 = gic_has_group0();
173170

174-
ds = gic_dist_security_disabled();
175-
if (ds)
176-
pr_warn("Broken GIC integration, security disabled");
171+
ds = gic_dist_security_disabled();
172+
if ((gic_data.flags & FLAGS_WORKAROUND_INSECURE) && !ds) {
173+
if (cpus_have_group0) {
174+
u32 val;
175+
176+
val = readl_relaxed(gic_data.dist_base + GICD_CTLR);
177+
val |= GICD_CTLR_DS;
178+
writel_relaxed(val, gic_data.dist_base + GICD_CTLR);
179+
180+
ds = gic_dist_security_disabled();
181+
if (ds)
182+
pr_warn("Broken GIC integration, security disabled\n");
183+
} else {
184+
pr_warn("Broken GIC integration, pNMI forbidden\n");
185+
nmi_support_forbidden = true;
186+
}
177187
}
178188

179189
cpus_have_security_disabled = ds;
180-
cpus_have_group0 = gic_has_group0();
181190

182191
/*
183192
* How priority values are used by the GIC depends on two things:
@@ -209,7 +218,7 @@ static void __init gic_prio_init(void)
209218
* be in the non-secure range, we program the non-secure values into
210219
* the distributor to match the PMR values we want.
211220
*/
212-
if (cpus_have_group0 & !cpus_have_security_disabled) {
221+
if (cpus_have_group0 && !cpus_have_security_disabled) {
213222
dist_prio_irq = __gicv3_prio_to_ns(dist_prio_irq);
214223
dist_prio_nmi = __gicv3_prio_to_ns(dist_prio_nmi);
215224
}
@@ -1922,6 +1931,18 @@ static bool gic_enable_quirk_arm64_2941627(void *data)
19221931
return true;
19231932
}
19241933

1934+
static bool gic_enable_quirk_rk3399(void *data)
1935+
{
1936+
struct gic_chip_data *d = data;
1937+
1938+
if (of_machine_is_compatible("rockchip,rk3399")) {
1939+
d->flags |= FLAGS_WORKAROUND_INSECURE;
1940+
return true;
1941+
}
1942+
1943+
return false;
1944+
}
1945+
19251946
static bool rd_set_non_coherent(void *data)
19261947
{
19271948
struct gic_chip_data *d = data;
@@ -1996,6 +2017,12 @@ static const struct gic_quirk gic_quirks[] = {
19962017
.property = "dma-noncoherent",
19972018
.init = rd_set_non_coherent,
19982019
},
2020+
{
2021+
.desc = "GICv3: Insecure RK3399 integration",
2022+
.iidr = 0x0000043b,
2023+
.mask = 0xff000fff,
2024+
.init = gic_enable_quirk_rk3399,
2025+
},
19992026
{
20002027
}
20012028
};
@@ -2004,7 +2031,7 @@ static void gic_enable_nmi_support(void)
20042031
{
20052032
int i;
20062033

2007-
if (!gic_prio_masking_enabled())
2034+
if (!gic_prio_masking_enabled() || nmi_support_forbidden)
20082035
return;
20092036

20102037
rdist_nmi_refs = kcalloc(gic_data.ppi_nr + SGI_NR,

drivers/irqchip/irq-jcore-aic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static struct irq_chip jcore_aic;
3838
static void handle_jcore_irq(struct irq_desc *desc)
3939
{
4040
if (irqd_is_per_cpu(irq_desc_get_irq_data(desc)))
41-
handle_percpu_irq(desc);
41+
handle_percpu_devid_irq(desc);
4242
else
4343
handle_simple_irq(desc);
4444
}

drivers/irqchip/qcom-pdc.c

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
#include <linux/types.h>
2222

2323
#define PDC_MAX_GPIO_IRQS 256
24+
#define PDC_DRV_OFFSET 0x10000
2425

2526
/* Valid only on HW version < 3.2 */
2627
#define IRQ_ENABLE_BANK 0x10
28+
#define IRQ_ENABLE_BANK_MAX (IRQ_ENABLE_BANK + BITS_TO_BYTES(PDC_MAX_GPIO_IRQS))
2729
#define IRQ_i_CFG 0x110
2830

2931
/* Valid only on HW version >= 3.2 */
@@ -46,20 +48,55 @@ struct pdc_pin_region {
4648

4749
static DEFINE_RAW_SPINLOCK(pdc_lock);
4850
static void __iomem *pdc_base;
51+
static void __iomem *pdc_prev_base;
4952
static struct pdc_pin_region *pdc_region;
5053
static int pdc_region_cnt;
5154
static unsigned int pdc_version;
55+
static bool pdc_x1e_quirk;
56+
57+
static void pdc_base_reg_write(void __iomem *base, int reg, u32 i, u32 val)
58+
{
59+
writel_relaxed(val, base + reg + i * sizeof(u32));
60+
}
5261

5362
static void pdc_reg_write(int reg, u32 i, u32 val)
5463
{
55-
writel_relaxed(val, pdc_base + reg + i * sizeof(u32));
64+
pdc_base_reg_write(pdc_base, reg, i, val);
5665
}
5766

5867
static u32 pdc_reg_read(int reg, u32 i)
5968
{
6069
return readl_relaxed(pdc_base + reg + i * sizeof(u32));
6170
}
6271

72+
static void pdc_x1e_irq_enable_write(u32 bank, u32 enable)
73+
{
74+
void __iomem *base;
75+
76+
/* Remap the write access to work around a hardware bug on X1E */
77+
switch (bank) {
78+
case 0 ... 1:
79+
/* Use previous DRV (client) region and shift to bank 3-4 */
80+
base = pdc_prev_base;
81+
bank += 3;
82+
break;
83+
case 2 ... 4:
84+
/* Use our own region and shift to bank 0-2 */
85+
base = pdc_base;
86+
bank -= 2;
87+
break;
88+
case 5:
89+
/* No fixup required for bank 5 */
90+
base = pdc_base;
91+
break;
92+
default:
93+
WARN_ON(1);
94+
return;
95+
}
96+
97+
pdc_base_reg_write(base, IRQ_ENABLE_BANK, bank, enable);
98+
}
99+
63100
static void __pdc_enable_intr(int pin_out, bool on)
64101
{
65102
unsigned long enable;
@@ -72,7 +109,11 @@ static void __pdc_enable_intr(int pin_out, bool on)
72109

73110
enable = pdc_reg_read(IRQ_ENABLE_BANK, index);
74111
__assign_bit(mask, &enable, on);
75-
pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
112+
113+
if (pdc_x1e_quirk)
114+
pdc_x1e_irq_enable_write(index, enable);
115+
else
116+
pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
76117
} else {
77118
enable = pdc_reg_read(IRQ_i_CFG, pin_out);
78119
__assign_bit(IRQ_i_CFG_IRQ_ENABLE, &enable, on);
@@ -324,10 +365,29 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
324365
if (res_size > resource_size(&res))
325366
pr_warn("%pOF: invalid reg size, please fix DT\n", node);
326367

368+
/*
369+
* PDC has multiple DRV regions, each one provides the same set of
370+
* registers for a particular client in the system. Due to a hardware
371+
* bug on X1E, some writes to the IRQ_ENABLE_BANK register must be
372+
* issued inside the previous region. This region belongs to
373+
* a different client and is not described in the device tree. Map the
374+
* region with the expected offset to preserve support for old DTs.
375+
*/
376+
if (of_device_is_compatible(node, "qcom,x1e80100-pdc")) {
377+
pdc_prev_base = ioremap(res.start - PDC_DRV_OFFSET, IRQ_ENABLE_BANK_MAX);
378+
if (!pdc_prev_base) {
379+
pr_err("%pOF: unable to map previous PDC DRV region\n", node);
380+
return -ENXIO;
381+
}
382+
383+
pdc_x1e_quirk = true;
384+
}
385+
327386
pdc_base = ioremap(res.start, res_size);
328387
if (!pdc_base) {
329388
pr_err("%pOF: unable to map PDC registers\n", node);
330-
return -ENXIO;
389+
ret = -ENXIO;
390+
goto fail;
331391
}
332392

333393
pdc_version = pdc_reg_read(PDC_VERSION_REG, 0);
@@ -363,6 +423,7 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
363423
fail:
364424
kfree(pdc_region);
365425
iounmap(pdc_base);
426+
iounmap(pdc_prev_base);
366427
return ret;
367428
}
368429

0 commit comments

Comments
 (0)