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 <maz@kernel.org>

+171 -46
+59
Documentation/devicetree/bindings/interrupt-controller/loongson,eiointc.yaml
··· 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 <zhoubinbin@loongson.cn> 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 + ...
+99 -36
drivers/irqchip/irq-loongson-eiointc.c
··· 36 36 37 37 struct eiointc_priv { 38 38 u32 node; 39 + u32 vec_count; 39 40 nodemask_t node_map; 40 41 cpumask_t cpuspan_map; 41 42 struct fwnode_handle *domain_handle; ··· 154 153 if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) { 155 154 eiointc_enable(); 156 155 157 - for (i = 0; i < VEC_COUNT / 32; i++) { 156 + for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) { 158 157 data = (((1 << (i * 2 + 1)) << 16) | (1 << (i * 2))); 159 158 iocsr_write32(data, EIOINTC_REG_NODEMAP + i * 4); 160 159 } 161 160 162 - for (i = 0; i < VEC_COUNT / 32 / 4; i++) { 161 + for (i = 0; i < eiointc_priv[0]->vec_count / 32 / 4; i++) { 163 162 bit = BIT(1 + index); /* Route to IP[1 + index] */ 164 163 data = bit | (bit << 8) | (bit << 16) | (bit << 24); 165 164 iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4); 166 165 } 167 166 168 - for (i = 0; i < VEC_COUNT / 4; i++) { 167 + for (i = 0; i < eiointc_priv[0]->vec_count / 4; i++) { 169 168 /* Route to Node-0 Core-0 */ 170 169 if (index == 0) 171 170 bit = BIT(cpu_logical_map(0)); ··· 176 175 iocsr_write32(data, EIOINTC_REG_ROUTE + i * 4); 177 176 } 178 177 179 - for (i = 0; i < VEC_COUNT / 32; i++) { 178 + for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) { 180 179 data = 0xffffffff; 181 180 iocsr_write32(data, EIOINTC_REG_ENABLE + i * 4); 182 181 iocsr_write32(data, EIOINTC_REG_BOUNCE + i * 4); ··· 196 195 197 196 chained_irq_enter(chip, desc); 198 197 199 - for (i = 0; i < VEC_REG_COUNT; i++) { 198 + for (i = 0; i < eiointc_priv[0]->vec_count / VEC_COUNT_PER_REG; i++) { 200 199 pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3)); 201 200 iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3)); 202 201 while (pending) { ··· 311 310 eiointc_router_init(0); 312 311 313 312 for (i = 0; i < nr_pics; i++) { 314 - for (j = 0; j < VEC_COUNT; j++) { 313 + for (j = 0; j < eiointc_priv[0]->vec_count; j++) { 315 314 desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j); 316 315 if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) { 317 316 raw_spin_lock(&desc->lock); 318 - irq_data = &desc->irq_data; 317 + irq_data = irq_domain_get_irq_data(eiointc_priv[i]->eiointc_domain, irq_desc_get_irq(desc)); 319 318 eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0); 320 319 raw_spin_unlock(&desc->lock); 321 320 } ··· 376 375 return 0; 377 376 } 378 377 378 + static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq, 379 + u64 node_map) 380 + { 381 + int i; 382 + 383 + node_map = node_map ? node_map : -1ULL; 384 + for_each_possible_cpu(i) { 385 + if (node_map & (1ULL << (cpu_to_eio_node(i)))) { 386 + node_set(cpu_to_eio_node(i), priv->node_map); 387 + cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map, 388 + cpumask_of(i)); 389 + } 390 + } 391 + 392 + priv->eiointc_domain = irq_domain_create_linear(priv->domain_handle, 393 + priv->vec_count, 394 + &eiointc_domain_ops, 395 + priv); 396 + if (!priv->eiointc_domain) { 397 + pr_err("loongson-extioi: cannot add IRQ domain\n"); 398 + return -ENOMEM; 399 + } 400 + 401 + eiointc_priv[nr_pics++] = priv; 402 + eiointc_router_init(0); 403 + irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); 404 + 405 + if (nr_pics == 1) { 406 + register_syscore_ops(&eiointc_syscore_ops); 407 + cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, 408 + "irqchip/loongarch/intc:starting", 409 + eiointc_router_init, NULL); 410 + } 411 + 412 + return 0; 413 + } 414 + 379 415 int __init eiointc_acpi_init(struct irq_domain *parent, 380 416 struct acpi_madt_eio_pic *acpi_eiointc) 381 417 { 382 - int i, ret, parent_irq; 383 - unsigned long node_map; 418 + int parent_irq, ret; 384 419 struct eiointc_priv *priv; 385 420 int node; 386 421 ··· 431 394 goto out_free_priv; 432 395 } 433 396 397 + priv->vec_count = VEC_COUNT; 434 398 priv->node = acpi_eiointc->node; 435 - node_map = acpi_eiointc->node_map ? : -1ULL; 436 - 437 - for_each_possible_cpu(i) { 438 - if (node_map & (1ULL << cpu_to_eio_node(i))) { 439 - node_set(cpu_to_eio_node(i), priv->node_map); 440 - cpumask_or(&priv->cpuspan_map, &priv->cpuspan_map, cpumask_of(i)); 441 - } 442 - } 443 - 444 - /* Setup IRQ domain */ 445 - priv->eiointc_domain = irq_domain_create_linear(priv->domain_handle, VEC_COUNT, 446 - &eiointc_domain_ops, priv); 447 - if (!priv->eiointc_domain) { 448 - pr_err("loongson-eiointc: cannot add IRQ domain\n"); 449 - goto out_free_handle; 450 - } 451 - 452 - eiointc_priv[nr_pics++] = priv; 453 - 454 - eiointc_router_init(0); 455 399 456 400 parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade); 457 - irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); 458 401 459 - if (nr_pics == 1) { 460 - register_syscore_ops(&eiointc_syscore_ops); 461 - cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, 462 - "irqchip/loongarch/intc:starting", 463 - eiointc_router_init, NULL); 464 - } 402 + ret = eiointc_init(priv, parent_irq, acpi_eiointc->node_map); 403 + if (ret < 0) 404 + goto out_free_handle; 465 405 466 406 if (cpu_has_flatmode) 467 407 node = cpu_to_node(acpi_eiointc->node * CORES_PER_EIO_NODE); ··· 446 432 node = acpi_eiointc->node; 447 433 acpi_set_vec_parent(node, priv->eiointc_domain, pch_group); 448 434 acpi_set_vec_parent(node, priv->eiointc_domain, msi_group); 435 + 449 436 ret = acpi_cascade_irqdomain_init(); 437 + if (ret < 0) 438 + goto out_free_handle; 450 439 451 440 return ret; 452 441 ··· 461 444 462 445 return -ENOMEM; 463 446 } 447 + 448 + static int __init eiointc_of_init(struct device_node *of_node, 449 + struct device_node *parent) 450 + { 451 + int parent_irq, ret; 452 + struct eiointc_priv *priv; 453 + 454 + priv = kzalloc(sizeof(*priv), GFP_KERNEL); 455 + if (!priv) 456 + return -ENOMEM; 457 + 458 + parent_irq = irq_of_parse_and_map(of_node, 0); 459 + if (parent_irq <= 0) { 460 + ret = -ENODEV; 461 + goto out_free_priv; 462 + } 463 + 464 + ret = irq_set_handler_data(parent_irq, priv); 465 + if (ret < 0) 466 + goto out_free_priv; 467 + 468 + /* 469 + * In particular, the number of devices supported by the LS2K0500 470 + * extended I/O interrupt vector is 128. 471 + */ 472 + if (of_device_is_compatible(of_node, "loongson,ls2k0500-eiointc")) 473 + priv->vec_count = 128; 474 + else 475 + priv->vec_count = VEC_COUNT; 476 + 477 + priv->node = 0; 478 + priv->domain_handle = of_node_to_fwnode(of_node); 479 + 480 + ret = eiointc_init(priv, parent_irq, 0); 481 + if (ret < 0) 482 + goto out_free_priv; 483 + 484 + return 0; 485 + 486 + out_free_priv: 487 + kfree(priv); 488 + return ret; 489 + } 490 + 491 + IRQCHIP_DECLARE(loongson_ls2k0500_eiointc, "loongson,ls2k0500-eiointc", eiointc_of_init); 492 + IRQCHIP_DECLARE(loongson_ls2k2000_eiointc, "loongson,ls2k2000-eiointc", eiointc_of_init);
+9 -4
drivers/irqchip/irq-loongson-liointc.c
··· 32 32 #define LIOINTC_REG_INTC_EN_STATUS (LIOINTC_INTC_CHIP_START + 0x04) 33 33 #define LIOINTC_REG_INTC_ENABLE (LIOINTC_INTC_CHIP_START + 0x08) 34 34 #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 + */ 35 39 #define LIOINTC_REG_INTC_POL (LIOINTC_INTC_CHIP_START + 0x10) 36 40 #define LIOINTC_REG_INTC_EDGE (LIOINTC_INTC_CHIP_START + 0x14) 37 41 ··· 120 116 switch (type) { 121 117 case IRQ_TYPE_LEVEL_HIGH: 122 118 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false); 123 - liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true); 119 + liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false); 124 120 break; 125 121 case IRQ_TYPE_LEVEL_LOW: 126 122 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false); 127 - liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false); 123 + liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true); 128 124 break; 129 125 case IRQ_TYPE_EDGE_RISING: 130 126 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true); 131 - liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true); 127 + liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false); 132 128 break; 133 129 case IRQ_TYPE_EDGE_FALLING: 134 130 liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true); 135 - liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false); 131 + liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true); 136 132 break; 137 133 default: 138 134 irq_gc_unlock_irqrestore(gc, flags); ··· 295 291 ct->chip.irq_mask = irq_gc_mask_disable_reg; 296 292 ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; 297 293 ct->chip.irq_set_type = liointc_set_type; 294 + ct->chip.flags = IRQCHIP_SKIP_SET_WAKE; 298 295 299 296 gc->mask_cache = 0; 300 297 priv->gc = gc;
+4 -6
drivers/irqchip/irq-loongson-pch-pic.c
··· 164 164 if (fwspec->param_count < 2) 165 165 return -EINVAL; 166 166 167 - *hwirq = fwspec->param[0] + priv->ht_vec_base; 167 + *hwirq = fwspec->param[0]; 168 168 *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; 169 169 } else { 170 170 if (fwspec->param_count < 1) ··· 196 196 197 197 parent_fwspec.fwnode = domain->parent->fwnode; 198 198 parent_fwspec.param_count = 1; 199 - parent_fwspec.param[0] = hwirq; 199 + parent_fwspec.param[0] = hwirq + priv->ht_vec_base; 200 200 201 201 err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec); 202 202 if (err) ··· 401 401 int __init pch_pic_acpi_init(struct irq_domain *parent, 402 402 struct acpi_madt_bio_pic *acpi_pchpic) 403 403 { 404 - int ret, vec_base; 404 + int ret; 405 405 struct fwnode_handle *domain_handle; 406 406 407 407 if (find_pch_pic(acpi_pchpic->gsi_base) >= 0) 408 408 return 0; 409 - 410 - vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ; 411 409 412 410 domain_handle = irq_domain_alloc_fwnode(&acpi_pchpic->address); 413 411 if (!domain_handle) { ··· 414 416 } 415 417 416 418 ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size, 417 - vec_base, parent, domain_handle, acpi_pchpic->gsi_base); 419 + 0, parent, domain_handle, acpi_pchpic->gsi_base); 418 420 419 421 if (ret < 0) { 420 422 irq_domain_free_fwnode(domain_handle);