Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit a3f1132

Browse files
AaronDotMarc Zyngier
authored andcommitted
irqchip/loongson-eiointc: Add DT init support
Add EIOINTC irqchip DT support, which is needed for Loongson chips based on DT and supporting EIOINTC, such as the Loongson-2K0500 SOC. Signed-off-by: Binbin Zhou <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubinbin@loongson.cn
1 parent 2c23c07 commit a3f1132

File tree

1 file changed

+98
-35
lines changed

1 file changed

+98
-35
lines changed

drivers/irqchip/irq-loongson-eiointc.c

Lines changed: 98 additions & 35 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,7 +311,7 @@ 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);
@@ -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);

0 commit comments

Comments
 (0)