Skip to content

Commit e0b78e9

Browse files
author
Marc Zyngier
committed
Merge branch irq/loongarch-fixes-6.5 into irq/irqchip-next
* irq/loongarch-fixes-6.5: : . : Yet another series of random fixes for the Loongson/Loongarch : string of interrupt controller, covering : : - affinity setting, : - trigger polarity, : - wake-up, : - DT support : . irqchip/loongson-eiointc: Add DT init support dt-bindings: interrupt-controller: Add Loongson EIOINTC irqchip/loongson-eiointc: Fix irq affinity setting during resume irqchip/loongson-liointc: Add IRQCHIP_SKIP_SET_WAKE flag irqchip/loongson-liointc: Fix IRQ trigger polarity irqchip/loongson-pch-pic: Fix potential incorrect hwirq assignment irqchip/loongson-pch-pic: Fix initialization of HT vector register Signed-off-by: Marc Zyngier <[email protected]>
2 parents d59b553 + a3f1132 commit e0b78e9

File tree

4 files changed

+171
-46
lines changed

4 files changed

+171
-46
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/interrupt-controller/loongson,eiointc.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Loongson Extended I/O Interrupt Controller
8+
9+
maintainers:
10+
- Binbin Zhou <[email protected]>
11+
12+
description: |
13+
This interrupt controller is found on the Loongson-3 family chips and
14+
Loongson-2K series chips and is used to distribute interrupts directly to
15+
individual cores without forwarding them through the HT's interrupt line.
16+
17+
allOf:
18+
- $ref: /schemas/interrupt-controller.yaml#
19+
20+
properties:
21+
compatible:
22+
enum:
23+
- loongson,ls2k0500-eiointc
24+
- loongson,ls2k2000-eiointc
25+
26+
reg:
27+
maxItems: 1
28+
29+
interrupts:
30+
maxItems: 1
31+
32+
interrupt-controller: true
33+
34+
'#interrupt-cells':
35+
const: 1
36+
37+
required:
38+
- compatible
39+
- reg
40+
- interrupts
41+
- interrupt-controller
42+
- '#interrupt-cells'
43+
44+
unevaluatedProperties: false
45+
46+
examples:
47+
- |
48+
eiointc: interrupt-controller@1fe11600 {
49+
compatible = "loongson,ls2k0500-eiointc";
50+
reg = <0x1fe10000 0x10000>;
51+
52+
interrupt-controller;
53+
#interrupt-cells = <1>;
54+
55+
interrupt-parent = <&cpuintc>;
56+
interrupts = <3>;
57+
};
58+
59+
...

drivers/irqchip/irq-loongson-eiointc.c

Lines changed: 99 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ static int nr_pics;
3636

3737
struct eiointc_priv {
3838
u32 node;
39+
u32 vec_count;
3940
nodemask_t node_map;
4041
cpumask_t cpuspan_map;
4142
struct fwnode_handle *domain_handle;
@@ -153,18 +154,18 @@ static int eiointc_router_init(unsigned int cpu)
153154
if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) {
154155
eiointc_enable();
155156

156-
for (i = 0; i < VEC_COUNT / 32; i++) {
157+
for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) {
157158
data = (((1 << (i * 2 + 1)) << 16) | (1 << (i * 2)));
158159
iocsr_write32(data, EIOINTC_REG_NODEMAP + i * 4);
159160
}
160161

161-
for (i = 0; i < VEC_COUNT / 32 / 4; i++) {
162+
for (i = 0; i < eiointc_priv[0]->vec_count / 32 / 4; i++) {
162163
bit = BIT(1 + index); /* Route to IP[1 + index] */
163164
data = bit | (bit << 8) | (bit << 16) | (bit << 24);
164165
iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
165166
}
166167

167-
for (i = 0; i < VEC_COUNT / 4; i++) {
168+
for (i = 0; i < eiointc_priv[0]->vec_count / 4; i++) {
168169
/* Route to Node-0 Core-0 */
169170
if (index == 0)
170171
bit = BIT(cpu_logical_map(0));
@@ -175,7 +176,7 @@ static int eiointc_router_init(unsigned int cpu)
175176
iocsr_write32(data, EIOINTC_REG_ROUTE + i * 4);
176177
}
177178

178-
for (i = 0; i < VEC_COUNT / 32; i++) {
179+
for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) {
179180
data = 0xffffffff;
180181
iocsr_write32(data, EIOINTC_REG_ENABLE + i * 4);
181182
iocsr_write32(data, EIOINTC_REG_BOUNCE + i * 4);
@@ -195,7 +196,7 @@ static void eiointc_irq_dispatch(struct irq_desc *desc)
195196

196197
chained_irq_enter(chip, desc);
197198

198-
for (i = 0; i < VEC_REG_COUNT; i++) {
199+
for (i = 0; i < eiointc_priv[0]->vec_count / VEC_COUNT_PER_REG; i++) {
199200
pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3));
200201
iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3));
201202
while (pending) {
@@ -310,11 +311,11 @@ static void eiointc_resume(void)
310311
eiointc_router_init(0);
311312

312313
for (i = 0; i < nr_pics; i++) {
313-
for (j = 0; j < VEC_COUNT; j++) {
314+
for (j = 0; j < eiointc_priv[0]->vec_count; j++) {
314315
desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j);
315316
if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) {
316317
raw_spin_lock(&desc->lock);
317-
irq_data = &desc->irq_data;
318+
irq_data = irq_domain_get_irq_data(eiointc_priv[i]->eiointc_domain, irq_desc_get_irq(desc));
318319
eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0);
319320
raw_spin_unlock(&desc->lock);
320321
}
@@ -375,11 +376,47 @@ static int __init acpi_cascade_irqdomain_init(void)
375376
return 0;
376377
}
377378

379+
static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
380+
u64 node_map)
381+
{
382+
int i;
383+
384+
node_map = node_map ? node_map : -1ULL;
385+
for_each_possible_cpu(i) {
386+
if (node_map & (1ULL << (cpu_to_eio_node(i)))) {
387+
node_set(cpu_to_eio_node(i), priv->node_map);
388+
cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map,
389+
cpumask_of(i));
390+
}
391+
}
392+
393+
priv->eiointc_domain = irq_domain_create_linear(priv->domain_handle,
394+
priv->vec_count,
395+
&eiointc_domain_ops,
396+
priv);
397+
if (!priv->eiointc_domain) {
398+
pr_err("loongson-extioi: cannot add IRQ domain\n");
399+
return -ENOMEM;
400+
}
401+
402+
eiointc_priv[nr_pics++] = priv;
403+
eiointc_router_init(0);
404+
irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
405+
406+
if (nr_pics == 1) {
407+
register_syscore_ops(&eiointc_syscore_ops);
408+
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,
409+
"irqchip/loongarch/intc:starting",
410+
eiointc_router_init, NULL);
411+
}
412+
413+
return 0;
414+
}
415+
378416
int __init eiointc_acpi_init(struct irq_domain *parent,
379417
struct acpi_madt_eio_pic *acpi_eiointc)
380418
{
381-
int i, ret, parent_irq;
382-
unsigned long node_map;
419+
int parent_irq, ret;
383420
struct eiointc_priv *priv;
384421
int node;
385422

@@ -394,45 +431,25 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
394431
goto out_free_priv;
395432
}
396433

434+
priv->vec_count = VEC_COUNT;
397435
priv->node = acpi_eiointc->node;
398-
node_map = acpi_eiointc->node_map ? : -1ULL;
399-
400-
for_each_possible_cpu(i) {
401-
if (node_map & (1ULL << cpu_to_eio_node(i))) {
402-
node_set(cpu_to_eio_node(i), priv->node_map);
403-
cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map, cpumask_of(i));
404-
}
405-
}
406-
407-
/* Setup IRQ domain */
408-
priv->eiointc_domain = irq_domain_create_linear(priv->domain_handle, VEC_COUNT,
409-
&eiointc_domain_ops, priv);
410-
if (!priv->eiointc_domain) {
411-
pr_err("loongson-eiointc: cannot add IRQ domain\n");
412-
goto out_free_handle;
413-
}
414-
415-
eiointc_priv[nr_pics++] = priv;
416-
417-
eiointc_router_init(0);
418436

419437
parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
420-
irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
421438

422-
if (nr_pics == 1) {
423-
register_syscore_ops(&eiointc_syscore_ops);
424-
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING,
425-
"irqchip/loongarch/intc:starting",
426-
eiointc_router_init, NULL);
427-
}
439+
ret = eiointc_init(priv, parent_irq, acpi_eiointc->node_map);
440+
if (ret < 0)
441+
goto out_free_handle;
428442

429443
if (cpu_has_flatmode)
430444
node = cpu_to_node(acpi_eiointc->node * CORES_PER_EIO_NODE);
431445
else
432446
node = acpi_eiointc->node;
433447
acpi_set_vec_parent(node, priv->eiointc_domain, pch_group);
434448
acpi_set_vec_parent(node, priv->eiointc_domain, msi_group);
449+
435450
ret = acpi_cascade_irqdomain_init();
451+
if (ret < 0)
452+
goto out_free_handle;
436453

437454
return ret;
438455

@@ -444,3 +461,49 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
444461

445462
return -ENOMEM;
446463
}
464+
465+
static int __init eiointc_of_init(struct device_node *of_node,
466+
struct device_node *parent)
467+
{
468+
int parent_irq, ret;
469+
struct eiointc_priv *priv;
470+
471+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
472+
if (!priv)
473+
return -ENOMEM;
474+
475+
parent_irq = irq_of_parse_and_map(of_node, 0);
476+
if (parent_irq <= 0) {
477+
ret = -ENODEV;
478+
goto out_free_priv;
479+
}
480+
481+
ret = irq_set_handler_data(parent_irq, priv);
482+
if (ret < 0)
483+
goto out_free_priv;
484+
485+
/*
486+
* In particular, the number of devices supported by the LS2K0500
487+
* extended I/O interrupt vector is 128.
488+
*/
489+
if (of_device_is_compatible(of_node, "loongson,ls2k0500-eiointc"))
490+
priv->vec_count = 128;
491+
else
492+
priv->vec_count = VEC_COUNT;
493+
494+
priv->node = 0;
495+
priv->domain_handle = of_node_to_fwnode(of_node);
496+
497+
ret = eiointc_init(priv, parent_irq, 0);
498+
if (ret < 0)
499+
goto out_free_priv;
500+
501+
return 0;
502+
503+
out_free_priv:
504+
kfree(priv);
505+
return ret;
506+
}
507+
508+
IRQCHIP_DECLARE(loongson_ls2k0500_eiointc, "loongson,ls2k0500-eiointc", eiointc_of_init);
509+
IRQCHIP_DECLARE(loongson_ls2k2000_eiointc, "loongson,ls2k2000-eiointc", eiointc_of_init);

drivers/irqchip/irq-loongson-liointc.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
#define LIOINTC_REG_INTC_EN_STATUS (LIOINTC_INTC_CHIP_START + 0x04)
3333
#define LIOINTC_REG_INTC_ENABLE (LIOINTC_INTC_CHIP_START + 0x08)
3434
#define LIOINTC_REG_INTC_DISABLE (LIOINTC_INTC_CHIP_START + 0x0c)
35+
/*
36+
* LIOINTC_REG_INTC_POL register is only valid for Loongson-2K series, and
37+
* Loongson-3 series behave as noops.
38+
*/
3539
#define LIOINTC_REG_INTC_POL (LIOINTC_INTC_CHIP_START + 0x10)
3640
#define LIOINTC_REG_INTC_EDGE (LIOINTC_INTC_CHIP_START + 0x14)
3741

@@ -116,19 +120,19 @@ static int liointc_set_type(struct irq_data *data, unsigned int type)
116120
switch (type) {
117121
case IRQ_TYPE_LEVEL_HIGH:
118122
liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false);
119-
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
123+
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
120124
break;
121125
case IRQ_TYPE_LEVEL_LOW:
122126
liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false);
123-
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
127+
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
124128
break;
125129
case IRQ_TYPE_EDGE_RISING:
126130
liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true);
127-
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
131+
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
128132
break;
129133
case IRQ_TYPE_EDGE_FALLING:
130134
liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true);
131-
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
135+
liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
132136
break;
133137
default:
134138
irq_gc_unlock_irqrestore(gc, flags);
@@ -291,6 +295,7 @@ static int liointc_init(phys_addr_t addr, unsigned long size, int revision,
291295
ct->chip.irq_mask = irq_gc_mask_disable_reg;
292296
ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
293297
ct->chip.irq_set_type = liointc_set_type;
298+
ct->chip.flags = IRQCHIP_SKIP_SET_WAKE;
294299

295300
gc->mask_cache = 0;
296301
priv->gc = gc;

drivers/irqchip/irq-loongson-pch-pic.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ static int pch_pic_domain_translate(struct irq_domain *d,
164164
if (fwspec->param_count < 2)
165165
return -EINVAL;
166166

167-
*hwirq = fwspec->param[0] + priv->ht_vec_base;
167+
*hwirq = fwspec->param[0];
168168
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
169169
} else {
170170
if (fwspec->param_count < 1)
@@ -196,7 +196,7 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
196196

197197
parent_fwspec.fwnode = domain->parent->fwnode;
198198
parent_fwspec.param_count = 1;
199-
parent_fwspec.param[0] = hwirq;
199+
parent_fwspec.param[0] = hwirq + priv->ht_vec_base;
200200

201201
err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
202202
if (err)
@@ -401,22 +401,20 @@ static int __init acpi_cascade_irqdomain_init(void)
401401
int __init pch_pic_acpi_init(struct irq_domain *parent,
402402
struct acpi_madt_bio_pic *acpi_pchpic)
403403
{
404-
int ret, vec_base;
404+
int ret;
405405
struct fwnode_handle *domain_handle;
406406

407407
if (find_pch_pic(acpi_pchpic->gsi_base) >= 0)
408408
return 0;
409409

410-
vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ;
411-
412410
domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address);
413411
if (!domain_handle) {
414412
pr_err("Unable to allocate domain handle\n");
415413
return -ENOMEM;
416414
}
417415

418416
ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
419-
vec_base, parent, domain_handle, acpi_pchpic->gsi_base);
417+
0, parent, domain_handle, acpi_pchpic->gsi_base);
420418

421419
if (ret < 0) {
422420
irq_domain_free_fwnode(domain_handle);

0 commit comments

Comments
 (0)