Skip to content

Commit b22bfea

Browse files
committed
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Ingo Molnar: "Most of the IRQ subsystem changes in this cycle were irq-chip driver updates: - Qualcomm PDC wakeup interrupt support - Layerscape external IRQ support - Broadcom bcm7038 PM and wakeup support - Ingenic driver cleanup and modernization - GICv3 ITS preparation for GICv4.1 updates - GICv4 fixes There's also the series from Frederic Weisbecker that fixes memory ordering bugs for the irq-work logic, whose primary fix is to turn work->irq_work.flags into an atomic variable and then convert the complex (and buggy) atomic_cmpxchg() loop in irq_work_claim() into a much simpler atomic_fetch_or() call. There are also various smaller cleanups" * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (44 commits) pinctrl/sdm845: Add PDC wakeup interrupt map for GPIOs pinctrl/msm: Setup GPIO chip in hierarchy irqchip/qcom-pdc: Add irqchip set/get state calls irqchip/qcom-pdc: Add irqdomain for wakeup capable GPIOs irqchip/qcom-pdc: Do not toggle IRQ_ENABLE during mask/unmask irqchip/qcom-pdc: Update max PDC interrupts of/irq: Document properties for wakeup interrupt parent genirq: Introduce irq_chip_get/set_parent_state calls irqdomain: Add bus token DOMAIN_BUS_WAKEUP genirq: Fix function documentation of __irq_alloc_descs() irq_work: Fix IRQ_WORK_BUSY bit clearing irqchip/ti-sci-inta: Use ERR_CAST inlined function instead of ERR_PTR(PTR_ERR(...)) irq_work: Slightly simplify IRQ_WORK_PENDING clearing irq_work: Fix irq_work_claim() memory ordering irq_work: Convert flags to atomic_t irqchip: Ingenic: Add process for more than one irq at the same time. irqchip: ingenic: Alloc generic chips from IRQ domain irqchip: ingenic: Get virq number from IRQ domain irqchip: ingenic: Error out if IRQ domain creation failed irqchip: ingenic: Drop redundant irq_suspend / irq_resume functions ...
2 parents 2dff2a1 + 407e62f commit b22bfea

File tree

30 files changed

+1065
-188
lines changed

30 files changed

+1065
-188
lines changed

Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ Required properties:
3131
- interrupts: specifies the interrupt line(s) in the interrupt-parent controller
3232
node; valid values depend on the type of parent interrupt controller
3333

34+
Optional properties:
35+
36+
- brcm,irq-can-wake: If present, this means the L1 controller can be used as a
37+
wakeup source for system suspend/resume.
38+
39+
Optional properties:
40+
41+
- brcm,int-fwd-mask: if present, a bit mask to indicate which interrupts
42+
have already been configured by the firmware and should be left unmanaged.
43+
This should have one 32-bit word per status/set/clear/mask group.
44+
3445
If multiple reg ranges and interrupt-parent entries are present on an SMP
3546
system, the driver will allow IRQ SMP affinity to be set up through the
3647
/proc/irq/ interface. In the simplest possible configuration, only one
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
* Freescale Layerscape external IRQs
2+
3+
Some Layerscape SOCs (LS1021A, LS1043A, LS1046A) support inverting
4+
the polarity of certain external interrupt lines.
5+
6+
The device node must be a child of the node representing the
7+
Supplemental Configuration Unit (SCFG).
8+
9+
Required properties:
10+
- compatible: should be "fsl,<soc-name>-extirq", e.g. "fsl,ls1021a-extirq".
11+
- #interrupt-cells: Must be 2. The first element is the index of the
12+
external interrupt line. The second element is the trigger type.
13+
- #address-cells: Must be 0.
14+
- interrupt-controller: Identifies the node as an interrupt controller
15+
- reg: Specifies the Interrupt Polarity Control Register (INTPCR) in
16+
the SCFG.
17+
- interrupt-map: Specifies the mapping from external interrupts to GIC
18+
interrupts.
19+
- interrupt-map-mask: Must be <0xffffffff 0>.
20+
21+
Example:
22+
scfg: scfg@1570000 {
23+
compatible = "fsl,ls1021a-scfg", "syscon";
24+
reg = <0x0 0x1570000 0x0 0x10000>;
25+
big-endian;
26+
#address-cells = <1>;
27+
#size-cells = <1>;
28+
ranges = <0x0 0x0 0x1570000 0x10000>;
29+
30+
extirq: interrupt-controller@1ac {
31+
compatible = "fsl,ls1021a-extirq";
32+
#interrupt-cells = <2>;
33+
#address-cells = <0>;
34+
interrupt-controller;
35+
reg = <0x1ac 4>;
36+
interrupt-map =
37+
<0 0 &gic GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
38+
<1 0 &gic GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>,
39+
<2 0 &gic GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>,
40+
<3 0 &gic GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
41+
<4 0 &gic GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
42+
<5 0 &gic GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
43+
interrupt-map-mask = <0xffffffff 0x0>;
44+
};
45+
};
46+
47+
48+
interrupts-extended = <&gic GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
49+
<&extirq 1 IRQ_TYPE_LEVEL_LOW>;

Documentation/devicetree/bindings/interrupt-controller/interrupts.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,15 @@ commonly used:
108108
sensitivity = <7>;
109109
};
110110
};
111+
112+
3) Interrupt wakeup parent
113+
--------------------------
114+
115+
Some interrupt controllers in a SoC, are always powered on and have a select
116+
interrupts routed to them, so that they can wakeup the SoC from suspend. These
117+
interrupt controllers do not fall into the category of a parent interrupt
118+
controller and can be specified by the "wakeup-parent" property and contain a
119+
single phandle referring to the wakeup capable interrupt controller.
120+
121+
Example:
122+
wakeup-parent = <&pdc_intc>;

Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ Properties:
1717
- compatible:
1818
Usage: required
1919
Value type: <string>
20-
Definition: Should contain "qcom,<soc>-pdc"
20+
Definition: Should contain "qcom,<soc>-pdc" and "qcom,pdc"
21+
- "qcom,sc7180-pdc": For SC7180
2122
- "qcom,sdm845-pdc": For SDM845
2223

2324
- reg:

arch/arm/include/asm/arch_gicv3.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ static inline u64 __gic_readq_nonatomic(const volatile void __iomem *addr)
333333
* GITS_VPENDBASER - the Valid bit must be cleared before changing
334334
* anything else.
335335
*/
336-
static inline void gits_write_vpendbaser(u64 val, void * __iomem addr)
336+
static inline void gits_write_vpendbaser(u64 val, void __iomem *addr)
337337
{
338338
u32 tmp;
339339

drivers/irqchip/Kconfig

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@ config MVEBU_PIC
370370
config MVEBU_SEI
371371
bool
372372

373+
config LS_EXTIRQ
374+
def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
375+
select MFD_SYSCON
376+
373377
config LS_SCFG_MSI
374378
def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
375379
depends on PCI && PCI_MSI
@@ -483,8 +487,6 @@ config TI_SCI_INTA_IRQCHIP
483487
If you wish to use interrupt aggregator irq resources managed by the
484488
TI System Controller, say Y here. Otherwise, say N.
485489

486-
endmenu
487-
488490
config SIFIVE_PLIC
489491
bool "SiFive Platform-Level Interrupt Controller"
490492
depends on RISCV
@@ -496,3 +498,5 @@ config SIFIVE_PLIC
496498
interrupt sources are subordinate to the PLIC.
497499

498500
If you don't know what to do here, say Y.
501+
502+
endmenu

drivers/irqchip/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ obj-$(CONFIG_MVEBU_ICU) += irq-mvebu-icu.o
8484
obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
8585
obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
8686
obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
87+
obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o
8788
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
8889
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
8990
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o

drivers/irqchip/irq-bcm7038-l1.c

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/types.h>
2828
#include <linux/irqchip.h>
2929
#include <linux/irqchip/chained_irq.h>
30+
#include <linux/syscore_ops.h>
3031

3132
#define IRQS_PER_WORD 32
3233
#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4)
@@ -39,6 +40,11 @@ struct bcm7038_l1_chip {
3940
unsigned int n_words;
4041
struct irq_domain *domain;
4142
struct bcm7038_l1_cpu *cpus[NR_CPUS];
43+
#ifdef CONFIG_PM_SLEEP
44+
struct list_head list;
45+
u32 wake_mask[MAX_WORDS];
46+
#endif
47+
u32 irq_fwd_mask[MAX_WORDS];
4248
u8 affinity[MAX_WORDS * IRQS_PER_WORD];
4349
};
4450

@@ -249,6 +255,7 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
249255
resource_size_t sz;
250256
struct bcm7038_l1_cpu *cpu;
251257
unsigned int i, n_words, parent_irq;
258+
int ret;
252259

253260
if (of_address_to_resource(dn, idx, &res))
254261
return -EINVAL;
@@ -262,6 +269,14 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
262269
else if (intc->n_words != n_words)
263270
return -EINVAL;
264271

272+
ret = of_property_read_u32_array(dn , "brcm,int-fwd-mask",
273+
intc->irq_fwd_mask, n_words);
274+
if (ret != 0 && ret != -EINVAL) {
275+
/* property exists but has the wrong number of words */
276+
pr_err("invalid brcm,int-fwd-mask property\n");
277+
return -EINVAL;
278+
}
279+
265280
cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32),
266281
GFP_KERNEL);
267282
if (!cpu)
@@ -272,21 +287,101 @@ static int __init bcm7038_l1_init_one(struct device_node *dn,
272287
return -ENOMEM;
273288

274289
for (i = 0; i < n_words; i++) {
275-
l1_writel(0xffffffff, cpu->map_base + reg_mask_set(intc, i));
276-
cpu->mask_cache[i] = 0xffffffff;
290+
l1_writel(~intc->irq_fwd_mask[i],
291+
cpu->map_base + reg_mask_set(intc, i));
292+
l1_writel(intc->irq_fwd_mask[i],
293+
cpu->map_base + reg_mask_clr(intc, i));
294+
cpu->mask_cache[i] = ~intc->irq_fwd_mask[i];
277295
}
278296

279297
parent_irq = irq_of_parse_and_map(dn, idx);
280298
if (!parent_irq) {
281299
pr_err("failed to map parent interrupt %d\n", parent_irq);
282300
return -EINVAL;
283301
}
302+
303+
if (of_property_read_bool(dn, "brcm,irq-can-wake"))
304+
enable_irq_wake(parent_irq);
305+
284306
irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle,
285307
intc);
286308

287309
return 0;
288310
}
289311

312+
#ifdef CONFIG_PM_SLEEP
313+
/*
314+
* We keep a list of bcm7038_l1_chip used for suspend/resume. This hack is
315+
* used because the struct chip_type suspend/resume hooks are not called
316+
* unless chip_type is hooked onto a generic_chip. Since this driver does
317+
* not use generic_chip, we need to manually hook our resume/suspend to
318+
* syscore_ops.
319+
*/
320+
static LIST_HEAD(bcm7038_l1_intcs_list);
321+
static DEFINE_RAW_SPINLOCK(bcm7038_l1_intcs_lock);
322+
323+
static int bcm7038_l1_suspend(void)
324+
{
325+
struct bcm7038_l1_chip *intc;
326+
int boot_cpu, word;
327+
u32 val;
328+
329+
/* Wakeup interrupt should only come from the boot cpu */
330+
boot_cpu = cpu_logical_map(0);
331+
332+
list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
333+
for (word = 0; word < intc->n_words; word++) {
334+
val = intc->wake_mask[word] | intc->irq_fwd_mask[word];
335+
l1_writel(~val,
336+
intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
337+
l1_writel(val,
338+
intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
339+
}
340+
}
341+
342+
return 0;
343+
}
344+
345+
static void bcm7038_l1_resume(void)
346+
{
347+
struct bcm7038_l1_chip *intc;
348+
int boot_cpu, word;
349+
350+
boot_cpu = cpu_logical_map(0);
351+
352+
list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
353+
for (word = 0; word < intc->n_words; word++) {
354+
l1_writel(intc->cpus[boot_cpu]->mask_cache[word],
355+
intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
356+
l1_writel(~intc->cpus[boot_cpu]->mask_cache[word],
357+
intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
358+
}
359+
}
360+
}
361+
362+
static struct syscore_ops bcm7038_l1_syscore_ops = {
363+
.suspend = bcm7038_l1_suspend,
364+
.resume = bcm7038_l1_resume,
365+
};
366+
367+
static int bcm7038_l1_set_wake(struct irq_data *d, unsigned int on)
368+
{
369+
struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
370+
unsigned long flags;
371+
u32 word = d->hwirq / IRQS_PER_WORD;
372+
u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
373+
374+
raw_spin_lock_irqsave(&intc->lock, flags);
375+
if (on)
376+
intc->wake_mask[word] |= mask;
377+
else
378+
intc->wake_mask[word] &= ~mask;
379+
raw_spin_unlock_irqrestore(&intc->lock, flags);
380+
381+
return 0;
382+
}
383+
#endif
384+
290385
static struct irq_chip bcm7038_l1_irq_chip = {
291386
.name = "bcm7038-l1",
292387
.irq_mask = bcm7038_l1_mask,
@@ -295,11 +390,21 @@ static struct irq_chip bcm7038_l1_irq_chip = {
295390
#ifdef CONFIG_SMP
296391
.irq_cpu_offline = bcm7038_l1_cpu_offline,
297392
#endif
393+
#ifdef CONFIG_PM_SLEEP
394+
.irq_set_wake = bcm7038_l1_set_wake,
395+
#endif
298396
};
299397

300398
static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq,
301399
irq_hw_number_t hw_irq)
302400
{
401+
struct bcm7038_l1_chip *intc = d->host_data;
402+
u32 mask = BIT(hw_irq % IRQS_PER_WORD);
403+
u32 word = hw_irq / IRQS_PER_WORD;
404+
405+
if (intc->irq_fwd_mask[word] & mask)
406+
return -EPERM;
407+
303408
irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq);
304409
irq_set_chip_data(virq, d->host_data);
305410
irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
@@ -340,6 +445,16 @@ int __init bcm7038_l1_of_init(struct device_node *dn,
340445
goto out_unmap;
341446
}
342447

448+
#ifdef CONFIG_PM_SLEEP
449+
/* Add bcm7038_l1_chip into a list */
450+
raw_spin_lock(&bcm7038_l1_intcs_lock);
451+
list_add_tail(&intc->list, &bcm7038_l1_intcs_list);
452+
raw_spin_unlock(&bcm7038_l1_intcs_lock);
453+
454+
if (list_is_singular(&bcm7038_l1_intcs_list))
455+
register_syscore_ops(&bcm7038_l1_syscore_ops);
456+
#endif
457+
343458
pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
344459
dn, IRQS_PER_WORD * intc->n_words);
345460

0 commit comments

Comments
 (0)