mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'irq-core-2024-11-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull interrupt subsystem updates from Thomas Gleixner:
"Tree wide:
- Make nr_irqs static to the core code and provide accessor functions
to remove existing and prevent future aliasing problems with local
variables or function arguments of the same name.
Core code:
- Prevent freeing an interrupt in the devres code which is not
managed by devres in the first place.
- Use seq_put_decimal_ull_width() for decimal values output in
/proc/interrupts which increases performance significantly as it
avoids parsing the format strings over and over.
- Optimize raising the timer and hrtimer soft interrupts by using the
'set bit only' variants instead of the combined version which
checks whether ksoftirqd should be woken up. The latter is a
pointless exercise as both soft interrupts are raised in the
context of the timer interrupt and therefore never wake up
ksoftirqd.
- Delegate timer/hrtimer soft interrupt processing to a dedicated
thread on RT.
Timer and hrtimer soft interrupts are always processed in ksoftirqd
on RT enabled kernels. This can lead to high latencies when other
soft interrupts are delegated to ksoftirqd as well.
The separate thread allows to run them seperately under a RT
scheduling policy to reduce the latency overhead.
Drivers:
- New drivers or extensions of existing drivers to support Renesas
RZ/V2H(P), Aspeed AST27XX, T-HEAD C900 and ATMEL sam9x7 interrupt
chips
- Support for multi-cluster GICs on MIPS.
MIPS CPUs can come with multiple CPU clusters, where each CPU
cluster has its own GIC (Generic Interrupt Controller). This
requires to access the GIC of a remote cluster through a redirect
register block.
This is encapsulated into a set of helper functions to keep the
complexity out of the actual code paths which handle the GIC
details.
- Support for encrypted guests in the ARM GICV3 ITS driver
The ITS page needs to be shared with the hypervisor and therefore
must be decrypted.
- Small cleanups and fixes all over the place"
* tag 'irq-core-2024-11-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (50 commits)
irqchip/riscv-aplic: Prevent crash when MSI domain is missing
genirq/proc: Use seq_put_decimal_ull_width() for decimal values
softirq: Use a dedicated thread for timer wakeups on PREEMPT_RT.
timers: Use __raise_softirq_irqoff() to raise the softirq.
hrtimer: Use __raise_softirq_irqoff() to raise the softirq
riscv: defconfig: Enable T-HEAD C900 ACLINT SSWI drivers
irqchip: Add T-HEAD C900 ACLINT SSWI driver
dt-bindings: interrupt-controller: Add T-HEAD C900 ACLINT SSWI device
irqchip/stm32mp-exti: Use of_property_present() for non-boolean properties
irqchip/mips-gic: Fix selection of GENERIC_IRQ_EFFECTIVE_AFF_MASK
irqchip/mips-gic: Prevent indirect access to clusters without CPU cores
irqchip/mips-gic: Multi-cluster support
irqchip/mips-gic: Setup defaults in each cluster
irqchip/mips-gic: Support multi-cluster in for_each_online_cpu_gic()
irqchip/mips-gic: Replace open coded online CPU iterations
genirq/irqdesc: Use str_enabled_disabled() helper in wakeup_show()
genirq/devres: Don't free interrupt which is not managed by devres
irqchip/gic-v3-its: Fix over allocation in itt_alloc_pool()
irqchip/aspeed-intc: Add AST27XX INTC support
dt-bindings: interrupt-controller: Add support for ASPEED AST27XX INTC
...
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/aspeed,ast2700-intc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Aspeed AST2700 Interrupt Controller
|
||||
|
||||
description:
|
||||
This interrupt controller hardware is second level interrupt controller that
|
||||
is hooked to a parent interrupt controller. It's useful to combine multiple
|
||||
interrupt sources into 1 interrupt to parent interrupt controller.
|
||||
|
||||
maintainers:
|
||||
- Kevin Chen <kevin_chen@aspeedtech.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- aspeed,ast2700-intc-ic
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
'#interrupt-cells':
|
||||
const: 2
|
||||
description:
|
||||
The first cell is the IRQ number, the second cell is the trigger
|
||||
type as defined in interrupt.txt in this directory.
|
||||
|
||||
interrupts:
|
||||
maxItems: 6
|
||||
description: |
|
||||
Depend to which INTC0 or INTC1 used.
|
||||
INTC0 and INTC1 are two kinds of interrupt controller with enable and raw
|
||||
status registers for use.
|
||||
INTC0 is used to assert GIC if interrupt in INTC1 asserted.
|
||||
INTC1 is used to assert INTC0 if interrupt of modules asserted.
|
||||
+-----+ +-------+ +---------+---module0
|
||||
| GIC |---| INTC0 |--+--| INTC1_0 |---module2
|
||||
| | | | | | |---...
|
||||
+-----+ +-------+ | +---------+---module31
|
||||
|
|
||||
| +---------+---module0
|
||||
+---| INTC1_1 |---module2
|
||||
| | |---...
|
||||
| +---------+---module31
|
||||
...
|
||||
| +---------+---module0
|
||||
+---| INTC1_5 |---module2
|
||||
| |---...
|
||||
+---------+---module31
|
||||
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupt-controller
|
||||
- '#interrupt-cells'
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
bus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
interrupt-controller@12101b00 {
|
||||
compatible = "aspeed,ast2700-intc-ic";
|
||||
reg = <0 0x12101b00 0 0x10>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
@@ -23,6 +23,7 @@ properties:
|
||||
- atmel,sama5d3-aic
|
||||
- atmel,sama5d4-aic
|
||||
- microchip,sam9x60-aic
|
||||
- microchip,sam9x7-aic
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/renesas,rzv2h-icu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas RZ/V2H(P) Interrupt Control Unit
|
||||
|
||||
maintainers:
|
||||
- Fabrizio Castro <fabrizio.castro.jz@renesas.com>
|
||||
- Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/interrupt-controller.yaml#
|
||||
|
||||
description:
|
||||
The Interrupt Control Unit (ICU) handles external interrupts (NMI, IRQ, and
|
||||
TINT), error interrupts, DMAC requests, GPT interrupts, and internal
|
||||
interrupts.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: renesas,r9a09g057-icu # RZ/V2H(P)
|
||||
|
||||
'#interrupt-cells':
|
||||
description: The first cell is the SPI number of the NMI or the
|
||||
PORT_IRQ[0-15] interrupt, as per user manual. The second cell is used to
|
||||
specify the flag.
|
||||
const: 2
|
||||
|
||||
'#address-cells':
|
||||
const: 0
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 58
|
||||
items:
|
||||
- description: NMI interrupt
|
||||
- description: PORT_IRQ0 interrupt
|
||||
- description: PORT_IRQ1 interrupt
|
||||
- description: PORT_IRQ2 interrupt
|
||||
- description: PORT_IRQ3 interrupt
|
||||
- description: PORT_IRQ4 interrupt
|
||||
- description: PORT_IRQ5 interrupt
|
||||
- description: PORT_IRQ6 interrupt
|
||||
- description: PORT_IRQ7 interrupt
|
||||
- description: PORT_IRQ8 interrupt
|
||||
- description: PORT_IRQ9 interrupt
|
||||
- description: PORT_IRQ10 interrupt
|
||||
- description: PORT_IRQ11 interrupt
|
||||
- description: PORT_IRQ12 interrupt
|
||||
- description: PORT_IRQ13 interrupt
|
||||
- description: PORT_IRQ14 interrupt
|
||||
- description: PORT_IRQ15 interrupt
|
||||
- description: GPIO interrupt, TINT0
|
||||
- description: GPIO interrupt, TINT1
|
||||
- description: GPIO interrupt, TINT2
|
||||
- description: GPIO interrupt, TINT3
|
||||
- description: GPIO interrupt, TINT4
|
||||
- description: GPIO interrupt, TINT5
|
||||
- description: GPIO interrupt, TINT6
|
||||
- description: GPIO interrupt, TINT7
|
||||
- description: GPIO interrupt, TINT8
|
||||
- description: GPIO interrupt, TINT9
|
||||
- description: GPIO interrupt, TINT10
|
||||
- description: GPIO interrupt, TINT11
|
||||
- description: GPIO interrupt, TINT12
|
||||
- description: GPIO interrupt, TINT13
|
||||
- description: GPIO interrupt, TINT14
|
||||
- description: GPIO interrupt, TINT15
|
||||
- description: GPIO interrupt, TINT16
|
||||
- description: GPIO interrupt, TINT17
|
||||
- description: GPIO interrupt, TINT18
|
||||
- description: GPIO interrupt, TINT19
|
||||
- description: GPIO interrupt, TINT20
|
||||
- description: GPIO interrupt, TINT21
|
||||
- description: GPIO interrupt, TINT22
|
||||
- description: GPIO interrupt, TINT23
|
||||
- description: GPIO interrupt, TINT24
|
||||
- description: GPIO interrupt, TINT25
|
||||
- description: GPIO interrupt, TINT26
|
||||
- description: GPIO interrupt, TINT27
|
||||
- description: GPIO interrupt, TINT28
|
||||
- description: GPIO interrupt, TINT29
|
||||
- description: GPIO interrupt, TINT30
|
||||
- description: GPIO interrupt, TINT31
|
||||
- description: Software interrupt, INTA55_0
|
||||
- description: Software interrupt, INTA55_1
|
||||
- description: Software interrupt, INTA55_2
|
||||
- description: Software interrupt, INTA55_3
|
||||
- description: Error interrupt to CA55
|
||||
- description: GTCCRA compare match/input capture (U0)
|
||||
- description: GTCCRB compare match/input capture (U0)
|
||||
- description: GTCCRA compare match/input capture (U1)
|
||||
- description: GTCCRB compare match/input capture (U1)
|
||||
|
||||
interrupt-names:
|
||||
minItems: 58
|
||||
items:
|
||||
- const: nmi
|
||||
- const: port_irq0
|
||||
- const: port_irq1
|
||||
- const: port_irq2
|
||||
- const: port_irq3
|
||||
- const: port_irq4
|
||||
- const: port_irq5
|
||||
- const: port_irq6
|
||||
- const: port_irq7
|
||||
- const: port_irq8
|
||||
- const: port_irq9
|
||||
- const: port_irq10
|
||||
- const: port_irq11
|
||||
- const: port_irq12
|
||||
- const: port_irq13
|
||||
- const: port_irq14
|
||||
- const: port_irq15
|
||||
- const: tint0
|
||||
- const: tint1
|
||||
- const: tint2
|
||||
- const: tint3
|
||||
- const: tint4
|
||||
- const: tint5
|
||||
- const: tint6
|
||||
- const: tint7
|
||||
- const: tint8
|
||||
- const: tint9
|
||||
- const: tint10
|
||||
- const: tint11
|
||||
- const: tint12
|
||||
- const: tint13
|
||||
- const: tint14
|
||||
- const: tint15
|
||||
- const: tint16
|
||||
- const: tint17
|
||||
- const: tint18
|
||||
- const: tint19
|
||||
- const: tint20
|
||||
- const: tint21
|
||||
- const: tint22
|
||||
- const: tint23
|
||||
- const: tint24
|
||||
- const: tint25
|
||||
- const: tint26
|
||||
- const: tint27
|
||||
- const: tint28
|
||||
- const: tint29
|
||||
- const: tint30
|
||||
- const: tint31
|
||||
- const: int-ca55-0
|
||||
- const: int-ca55-1
|
||||
- const: int-ca55-2
|
||||
- const: int-ca55-3
|
||||
- const: icu-error-ca55
|
||||
- const: gpt-u0-gtciada
|
||||
- const: gpt-u0-gtciadb
|
||||
- const: gpt-u1-gtciada
|
||||
- const: gpt-u1-gtciadb
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#interrupt-cells'
|
||||
- '#address-cells'
|
||||
- interrupt-controller
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- power-domains
|
||||
- resets
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/renesas-cpg-mssr.h>
|
||||
|
||||
icu: interrupt-controller@10400000 {
|
||||
compatible = "renesas,r9a09g057-icu";
|
||||
reg = <0x10400000 0x10000>;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 433 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 436 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 437 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 439 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 440 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 441 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 442 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 443 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 262 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 263 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 265 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 452 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 453 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 454 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "nmi",
|
||||
"port_irq0", "port_irq1", "port_irq2",
|
||||
"port_irq3", "port_irq4", "port_irq5",
|
||||
"port_irq6", "port_irq7", "port_irq8",
|
||||
"port_irq9", "port_irq10", "port_irq11",
|
||||
"port_irq12", "port_irq13", "port_irq14",
|
||||
"port_irq15",
|
||||
"tint0", "tint1", "tint2", "tint3",
|
||||
"tint4", "tint5", "tint6", "tint7",
|
||||
"tint8", "tint9", "tint10", "tint11",
|
||||
"tint12", "tint13", "tint14", "tint15",
|
||||
"tint16", "tint17", "tint18", "tint19",
|
||||
"tint20", "tint21", "tint22", "tint23",
|
||||
"tint24", "tint25", "tint26", "tint27",
|
||||
"tint28", "tint29", "tint30", "tint31",
|
||||
"int-ca55-0", "int-ca55-1",
|
||||
"int-ca55-2", "int-ca55-3",
|
||||
"icu-error-ca55",
|
||||
"gpt-u0-gtciada", "gpt-u0-gtciadb",
|
||||
"gpt-u1-gtciada", "gpt-u1-gtciadb";
|
||||
clocks = <&cpg CPG_MOD 0x5>;
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg 0x36>;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-sswi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: T-HEAD C900 ACLINT Supervisor-level Software Interrupt Device
|
||||
|
||||
maintainers:
|
||||
- Inochi Amaoto <inochiama@outlook.com>
|
||||
|
||||
description:
|
||||
The SSWI device is a part of the THEAD ACLINT device. It provides
|
||||
supervisor-level IPI functionality for a set of HARTs on a THEAD
|
||||
platform. It provides a register to set an IPI (SETSSIP) for each
|
||||
HART connected to the SSWI device.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- sophgo,sg2044-aclint-sswi
|
||||
- const: thead,c900-aclint-sswi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 0
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
interrupts-extended:
|
||||
minItems: 1
|
||||
maxItems: 4095
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#interrupt-cells"
|
||||
- interrupt-controller
|
||||
- interrupts-extended
|
||||
|
||||
examples:
|
||||
- |
|
||||
interrupt-controller@94000000 {
|
||||
compatible = "sophgo,sg2044-aclint-sswi", "thead,c900-aclint-sswi";
|
||||
reg = <0x94000000 0x00004000>;
|
||||
#interrupt-cells = <0>;
|
||||
interrupt-controller;
|
||||
interrupts-extended = <&cpu1intc 1>,
|
||||
<&cpu2intc 1>,
|
||||
<&cpu3intc 1>,
|
||||
<&cpu4intc 1>;
|
||||
};
|
||||
...
|
||||
@@ -111,7 +111,7 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
* Some hardware gives randomly wrong interrupts. Rather
|
||||
* than crashing, do something sensible.
|
||||
*/
|
||||
if (unlikely(!irq || irq >= nr_irqs))
|
||||
if (unlikely(!irq || irq >= irq_get_nr_irqs()))
|
||||
desc = NULL;
|
||||
else
|
||||
desc = irq_to_desc(irq);
|
||||
@@ -151,7 +151,6 @@ void __init init_IRQ(void)
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
int __init arch_probe_nr_irqs(void)
|
||||
{
|
||||
nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS;
|
||||
return nr_irqs;
|
||||
return irq_set_nr_irqs(machine_desc->nr_irqs ? : NR_IRQS);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -90,6 +90,95 @@
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
icu: interrupt-controller@10400000 {
|
||||
compatible = "renesas,r9a09g057-icu";
|
||||
reg = <0 0x10400000 0 0x10000>;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 420 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 421 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 423 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 426 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 427 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 428 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 433 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 436 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 437 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 439 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 440 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 441 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 442 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 443 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 445 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 262 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 263 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 264 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 265 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 452 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 453 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 454 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "nmi",
|
||||
"port_irq0", "port_irq1", "port_irq2",
|
||||
"port_irq3", "port_irq4", "port_irq5",
|
||||
"port_irq6", "port_irq7", "port_irq8",
|
||||
"port_irq9", "port_irq10", "port_irq11",
|
||||
"port_irq12", "port_irq13", "port_irq14",
|
||||
"port_irq15",
|
||||
"tint0", "tint1", "tint2", "tint3",
|
||||
"tint4", "tint5", "tint6", "tint7",
|
||||
"tint8", "tint9", "tint10", "tint11",
|
||||
"tint12", "tint13", "tint14", "tint15",
|
||||
"tint16", "tint17", "tint18", "tint19",
|
||||
"tint20", "tint21", "tint22", "tint23",
|
||||
"tint24", "tint25", "tint26", "tint27",
|
||||
"tint28", "tint29", "tint30", "tint31",
|
||||
"int-ca55-0", "int-ca55-1",
|
||||
"int-ca55-2", "int-ca55-3",
|
||||
"icu-error-ca55",
|
||||
"gpt-u0-gtciada", "gpt-u0-gtciadb",
|
||||
"gpt-u1-gtciada", "gpt-u1-gtciadb";
|
||||
clocks = <&cpg CPG_MOD 0x5>;
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg 0x36>;
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@10410000 {
|
||||
compatible = "renesas,r9a09g057-pinctrl";
|
||||
reg = <0 0x10410000 0 0x10000>;
|
||||
@@ -99,6 +188,7 @@
|
||||
gpio-ranges = <&pinctrl 0 0 96>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
interrupt-parent = <&icu>;
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg 0xa5>, <&cpg 0xa6>;
|
||||
};
|
||||
|
||||
@@ -92,9 +92,9 @@ int __init arch_probe_nr_irqs(void)
|
||||
int nr_io_pics = bitmap_weight(loongson_sysconf.cores_io_master, NR_CPUS);
|
||||
|
||||
if (!cpu_has_avecint)
|
||||
nr_irqs = (64 + NR_VECTORS * nr_io_pics);
|
||||
irq_set_nr_irqs(64 + NR_VECTORS * nr_io_pics);
|
||||
else
|
||||
nr_irqs = (64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics));
|
||||
irq_set_nr_irqs(64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics));
|
||||
|
||||
return NR_IRQS_LEGACY;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ static void axon_msi_cascade(struct irq_desc *desc)
|
||||
pr_devel("axon_msi: woff %x roff %x msi %x\n",
|
||||
write_offset, msic->read_offset, msi);
|
||||
|
||||
if (msi < nr_irqs && irq_get_chip_data(msi) == msic) {
|
||||
if (msi < irq_get_nr_irqs() && irq_get_chip_data(msi) == msic) {
|
||||
generic_handle_irq(msi);
|
||||
msic->fifo_virt[idx] = cpu_to_le32(0xffffffff);
|
||||
} else {
|
||||
|
||||
@@ -256,6 +256,7 @@ CONFIG_RPMSG_CTRL=y
|
||||
CONFIG_RPMSG_VIRTIO=y
|
||||
CONFIG_PM_DEVFREQ=y
|
||||
CONFIG_IIO=y
|
||||
CONFIG_THEAD_C900_ACLINT_SSWI=y
|
||||
CONFIG_PHY_SUN4I_USB=m
|
||||
CONFIG_PHY_STARFIVE_JH7110_DPHY_RX=m
|
||||
CONFIG_PHY_STARFIVE_JH7110_PCIE=m
|
||||
|
||||
@@ -258,7 +258,7 @@ int show_interrupts(struct seq_file *p, void *v)
|
||||
seq_putc(p, '\n');
|
||||
goto out;
|
||||
}
|
||||
if (index < nr_irqs) {
|
||||
if (index < irq_get_nr_irqs()) {
|
||||
show_msi_interrupt(p, index);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1171,7 +1171,8 @@ static int __init acpi_parse_madt_ioapic_entries(void)
|
||||
}
|
||||
|
||||
count = acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE,
|
||||
acpi_parse_int_src_ovr, nr_irqs);
|
||||
acpi_parse_int_src_ovr,
|
||||
irq_get_nr_irqs());
|
||||
if (count < 0) {
|
||||
pr_err("Error parsing interrupt source overrides entry\n");
|
||||
/* TBD: Cleanup to allow fallback to MPS */
|
||||
@@ -1191,7 +1192,8 @@ static int __init acpi_parse_madt_ioapic_entries(void)
|
||||
mp_config_acpi_legacy_irqs();
|
||||
|
||||
count = acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE,
|
||||
acpi_parse_nmi_src, nr_irqs);
|
||||
acpi_parse_nmi_src,
|
||||
irq_get_nr_irqs());
|
||||
if (count < 0) {
|
||||
pr_err("Error parsing NMI SRC entry\n");
|
||||
/* TBD: Cleanup to allow fallback to MPS */
|
||||
|
||||
@@ -712,8 +712,8 @@ int __init arch_probe_nr_irqs(void)
|
||||
{
|
||||
int nr;
|
||||
|
||||
if (nr_irqs > (NR_VECTORS * nr_cpu_ids))
|
||||
nr_irqs = NR_VECTORS * nr_cpu_ids;
|
||||
if (irq_get_nr_irqs() > NR_VECTORS * nr_cpu_ids)
|
||||
irq_set_nr_irqs(NR_VECTORS * nr_cpu_ids);
|
||||
|
||||
nr = (gsi_top + nr_legacy_irqs()) + 8 * nr_cpu_ids;
|
||||
#if defined(CONFIG_PCI_MSI)
|
||||
@@ -725,8 +725,8 @@ int __init arch_probe_nr_irqs(void)
|
||||
else
|
||||
nr += gsi_top * 16;
|
||||
#endif
|
||||
if (nr < nr_irqs)
|
||||
nr_irqs = nr;
|
||||
if (nr < irq_get_nr_irqs())
|
||||
irq_set_nr_irqs(nr);
|
||||
|
||||
/*
|
||||
* We don't know if PIC is present at this point so we need to do
|
||||
|
||||
@@ -162,6 +162,7 @@ static irqreturn_t hpet_interrupt(int irq, void *data)
|
||||
|
||||
static void hpet_timer_set_irq(struct hpet_dev *devp)
|
||||
{
|
||||
const unsigned int nr_irqs = irq_get_nr_irqs();
|
||||
unsigned long v;
|
||||
int irq, gsi;
|
||||
struct hpet_timer __iomem *timer;
|
||||
|
||||
@@ -258,6 +258,13 @@ config RENESAS_RZG2L_IRQC
|
||||
Enable support for the Renesas RZ/G2L (and alike SoC) Interrupt Controller
|
||||
for external devices.
|
||||
|
||||
config RENESAS_RZV2H_ICU
|
||||
bool "Renesas RZ/V2H(P) ICU support" if COMPILE_TEST
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
Enable support for the Renesas RZ/V2H(P) Interrupt Control Unit (ICU)
|
||||
|
||||
config SL28CPLD_INTC
|
||||
bool "Kontron sl28cpld IRQ controller"
|
||||
depends on MFD_SL28CPLD=y || COMPILE_TEST
|
||||
@@ -338,6 +345,7 @@ config KEYSTONE_IRQ
|
||||
|
||||
config MIPS_GIC
|
||||
bool
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
|
||||
select GENERIC_IRQ_IPI if SMP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select MIPS_CM
|
||||
@@ -604,6 +612,18 @@ config STARFIVE_JH8100_INTC
|
||||
|
||||
If you don't know what to do here, say Y.
|
||||
|
||||
config THEAD_C900_ACLINT_SSWI
|
||||
bool "THEAD C9XX ACLINT S-mode IPI Interrupt Controller"
|
||||
depends on RISCV
|
||||
depends on SMP
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select GENERIC_IRQ_IPI_MUX
|
||||
help
|
||||
This enables support for T-HEAD specific ACLINT SSWI device
|
||||
support.
|
||||
|
||||
If you don't know what to do here, say Y.
|
||||
|
||||
config EXYNOS_IRQ_COMBINER
|
||||
bool "Samsung Exynos IRQ combiner support" if COMPILE_TEST
|
||||
depends on (ARCH_EXYNOS && ARM) || COMPILE_TEST
|
||||
|
||||
@@ -51,6 +51,7 @@ obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o
|
||||
obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o
|
||||
obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o
|
||||
obj-$(CONFIG_RENESAS_RZG2L_IRQC) += irq-renesas-rzg2l.o
|
||||
obj-$(CONFIG_RENESAS_RZV2H_ICU) += irq-renesas-rzv2h.o
|
||||
obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
|
||||
obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
|
||||
obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
|
||||
@@ -84,6 +85,7 @@ obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
|
||||
obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o
|
||||
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
|
||||
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o
|
||||
obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-intc.o
|
||||
obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o
|
||||
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
|
||||
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
|
||||
@@ -101,6 +103,7 @@ obj-$(CONFIG_RISCV_APLIC_MSI) += irq-riscv-aplic-msi.o
|
||||
obj-$(CONFIG_RISCV_IMSIC) += irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o
|
||||
obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
|
||||
obj-$(CONFIG_STARFIVE_JH8100_INTC) += irq-starfive-jh8100-intc.o
|
||||
obj-$(CONFIG_THEAD_C900_ACLINT_SSWI) += irq-thead-c900-aclint-sswi.o
|
||||
obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
|
||||
obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o
|
||||
obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o
|
||||
|
||||
139
drivers/irqchip/irq-aspeed-intc.c
Normal file
139
drivers/irqchip/irq-aspeed-intc.c
Normal file
@@ -0,0 +1,139 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Aspeed Interrupt Controller.
|
||||
*
|
||||
* Copyright (C) 2023 ASPEED Technology Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define INTC_INT_ENABLE_REG 0x00
|
||||
#define INTC_INT_STATUS_REG 0x04
|
||||
#define INTC_IRQS_PER_WORD 32
|
||||
|
||||
struct aspeed_intc_ic {
|
||||
void __iomem *base;
|
||||
raw_spinlock_t gic_lock;
|
||||
raw_spinlock_t intc_lock;
|
||||
struct irq_domain *irq_domain;
|
||||
};
|
||||
|
||||
static void aspeed_intc_ic_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct aspeed_intc_ic *intc_ic = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
scoped_guard(raw_spinlock, &intc_ic->gic_lock) {
|
||||
unsigned long bit, status;
|
||||
|
||||
status = readl(intc_ic->base + INTC_INT_STATUS_REG);
|
||||
for_each_set_bit(bit, &status, INTC_IRQS_PER_WORD) {
|
||||
generic_handle_domain_irq(intc_ic->irq_domain, bit);
|
||||
writel(BIT(bit), intc_ic->base + INTC_INT_STATUS_REG);
|
||||
}
|
||||
}
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static void aspeed_intc_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data);
|
||||
unsigned int mask = readl(intc_ic->base + INTC_INT_ENABLE_REG) & ~BIT(data->hwirq);
|
||||
|
||||
guard(raw_spinlock)(&intc_ic->intc_lock);
|
||||
writel(mask, intc_ic->base + INTC_INT_ENABLE_REG);
|
||||
}
|
||||
|
||||
static void aspeed_intc_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data);
|
||||
unsigned int unmask = readl(intc_ic->base + INTC_INT_ENABLE_REG) | BIT(data->hwirq);
|
||||
|
||||
guard(raw_spinlock)(&intc_ic->intc_lock);
|
||||
writel(unmask, intc_ic->base + INTC_INT_ENABLE_REG);
|
||||
}
|
||||
|
||||
static struct irq_chip aspeed_intc_chip = {
|
||||
.name = "ASPEED INTC",
|
||||
.irq_mask = aspeed_intc_irq_mask,
|
||||
.irq_unmask = aspeed_intc_irq_unmask,
|
||||
};
|
||||
|
||||
static int aspeed_intc_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &aspeed_intc_chip, handle_level_irq);
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops aspeed_intc_ic_irq_domain_ops = {
|
||||
.map = aspeed_intc_ic_map_irq_domain,
|
||||
};
|
||||
|
||||
static int __init aspeed_intc_ic_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct aspeed_intc_ic *intc_ic;
|
||||
int irq, i, ret = 0;
|
||||
|
||||
intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL);
|
||||
if (!intc_ic)
|
||||
return -ENOMEM;
|
||||
|
||||
intc_ic->base = of_iomap(node, 0);
|
||||
if (!intc_ic->base) {
|
||||
pr_err("Failed to iomap intc_ic base\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_ic;
|
||||
}
|
||||
writel(0xffffffff, intc_ic->base + INTC_INT_STATUS_REG);
|
||||
writel(0x0, intc_ic->base + INTC_INT_ENABLE_REG);
|
||||
|
||||
intc_ic->irq_domain = irq_domain_add_linear(node, INTC_IRQS_PER_WORD,
|
||||
&aspeed_intc_ic_irq_domain_ops, intc_ic);
|
||||
if (!intc_ic->irq_domain) {
|
||||
ret = -ENOMEM;
|
||||
goto err_iounmap;
|
||||
}
|
||||
|
||||
raw_spin_lock_init(&intc_ic->gic_lock);
|
||||
raw_spin_lock_init(&intc_ic->intc_lock);
|
||||
|
||||
/* Check all the irq numbers valid. If not, unmaps all the base and frees the data. */
|
||||
for (i = 0; i < of_irq_count(node); i++) {
|
||||
irq = irq_of_parse_and_map(node, i);
|
||||
if (!irq) {
|
||||
pr_err("Failed to get irq number\n");
|
||||
ret = -EINVAL;
|
||||
goto err_iounmap;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < of_irq_count(node); i++) {
|
||||
irq = irq_of_parse_and_map(node, i);
|
||||
irq_set_chained_handler_and_data(irq, aspeed_intc_ic_irq_handler, intc_ic);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_iounmap:
|
||||
iounmap(intc_ic->base);
|
||||
err_free_ic:
|
||||
kfree(intc_ic);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(ast2700_intc_ic, "aspeed,ast2700-intc-ic", aspeed_intc_ic_of_init);
|
||||
@@ -319,6 +319,7 @@ static const struct of_device_id aic5_irq_fixups[] __initconst = {
|
||||
{ .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup },
|
||||
{ .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup },
|
||||
{ .compatible = "microchip,sam9x60", .data = sam9x60_aic_irq_fixup },
|
||||
{ .compatible = "microchip,sam9x7", .data = sam9x60_aic_irq_fixup },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
@@ -405,3 +406,11 @@ static int __init sam9x60_aic5_of_init(struct device_node *node,
|
||||
return aic5_of_init(node, parent, NR_SAM9X60_IRQS);
|
||||
}
|
||||
IRQCHIP_DECLARE(sam9x60_aic5, "microchip,sam9x60-aic", sam9x60_aic5_of_init);
|
||||
|
||||
#define NR_SAM9X7_IRQS 70
|
||||
|
||||
static int __init sam9x7_aic5_of_init(struct device_node *node, struct device_node *parent)
|
||||
{
|
||||
return aic5_of_init(node, parent, NR_SAM9X7_IRQS);
|
||||
}
|
||||
IRQCHIP_DECLARE(sam9x7_aic5, "microchip,sam9x7-aic", sam9x7_aic5_of_init);
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/mem_encrypt.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/msi.h>
|
||||
@@ -27,6 +29,7 @@
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
@@ -164,6 +167,7 @@ struct its_device {
|
||||
struct its_node *its;
|
||||
struct event_lpi_map event_map;
|
||||
void *itt;
|
||||
u32 itt_sz;
|
||||
u32 nr_ites;
|
||||
u32 device_id;
|
||||
bool shared;
|
||||
@@ -199,6 +203,87 @@ static DEFINE_IDA(its_vpeid_ida);
|
||||
#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base)
|
||||
#define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K)
|
||||
|
||||
static struct page *its_alloc_pages_node(int node, gfp_t gfp,
|
||||
unsigned int order)
|
||||
{
|
||||
struct page *page;
|
||||
int ret = 0;
|
||||
|
||||
page = alloc_pages_node(node, gfp, order);
|
||||
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
ret = set_memory_decrypted((unsigned long)page_address(page),
|
||||
1 << order);
|
||||
/*
|
||||
* If set_memory_decrypted() fails then we don't know what state the
|
||||
* page is in, so we can't free it. Instead we leak it.
|
||||
* set_memory_decrypted() will already have WARNed.
|
||||
*/
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static struct page *its_alloc_pages(gfp_t gfp, unsigned int order)
|
||||
{
|
||||
return its_alloc_pages_node(NUMA_NO_NODE, gfp, order);
|
||||
}
|
||||
|
||||
static void its_free_pages(void *addr, unsigned int order)
|
||||
{
|
||||
/*
|
||||
* If the memory cannot be encrypted again then we must leak the pages.
|
||||
* set_memory_encrypted() will already have WARNed.
|
||||
*/
|
||||
if (set_memory_encrypted((unsigned long)addr, 1 << order))
|
||||
return;
|
||||
free_pages((unsigned long)addr, order);
|
||||
}
|
||||
|
||||
static struct gen_pool *itt_pool;
|
||||
|
||||
static void *itt_alloc_pool(int node, int size)
|
||||
{
|
||||
unsigned long addr;
|
||||
struct page *page;
|
||||
|
||||
if (size >= PAGE_SIZE) {
|
||||
page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, get_order(size));
|
||||
|
||||
return page ? page_address(page) : NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
addr = gen_pool_alloc(itt_pool, size);
|
||||
if (addr)
|
||||
break;
|
||||
|
||||
page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
|
||||
if (!page)
|
||||
break;
|
||||
|
||||
gen_pool_add(itt_pool, (unsigned long)page_address(page), PAGE_SIZE, node);
|
||||
} while (!addr);
|
||||
|
||||
return (void *)addr;
|
||||
}
|
||||
|
||||
static void itt_free_pool(void *addr, int size)
|
||||
{
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
if (size >= PAGE_SIZE) {
|
||||
its_free_pages(addr, get_order(size));
|
||||
return;
|
||||
}
|
||||
|
||||
gen_pool_free(itt_pool, (unsigned long)addr, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we
|
||||
* always have vSGIs mapped.
|
||||
@@ -621,7 +706,6 @@ static struct its_collection *its_build_mapd_cmd(struct its_node *its,
|
||||
u8 size = ilog2(desc->its_mapd_cmd.dev->nr_ites);
|
||||
|
||||
itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
|
||||
itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
|
||||
|
||||
its_encode_cmd(cmd, GITS_CMD_MAPD);
|
||||
its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id);
|
||||
@@ -2181,7 +2265,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
|
||||
{
|
||||
struct page *prop_page;
|
||||
|
||||
prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ));
|
||||
prop_page = its_alloc_pages(gfp_flags,
|
||||
get_order(LPI_PROPBASE_SZ));
|
||||
if (!prop_page)
|
||||
return NULL;
|
||||
|
||||
@@ -2192,8 +2277,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags)
|
||||
|
||||
static void its_free_prop_table(struct page *prop_page)
|
||||
{
|
||||
free_pages((unsigned long)page_address(prop_page),
|
||||
get_order(LPI_PROPBASE_SZ));
|
||||
its_free_pages(page_address(prop_page), get_order(LPI_PROPBASE_SZ));
|
||||
}
|
||||
|
||||
static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size)
|
||||
@@ -2315,7 +2399,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
|
||||
order = get_order(GITS_BASER_PAGES_MAX * psz);
|
||||
}
|
||||
|
||||
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
|
||||
page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2328,7 +2412,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
|
||||
/* 52bit PA is supported only when PageSize=64K */
|
||||
if (psz != SZ_64K) {
|
||||
pr_err("ITS: no 52bit PA support when psz=%d\n", psz);
|
||||
free_pages((unsigned long)base, order);
|
||||
its_free_pages(base, order);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
@@ -2384,7 +2468,7 @@ retry_baser:
|
||||
pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n",
|
||||
&its->phys_base, its_base_type_string[type],
|
||||
val, tmp);
|
||||
free_pages((unsigned long)base, order);
|
||||
its_free_pages(base, order);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
@@ -2523,8 +2607,7 @@ static void its_free_tables(struct its_node *its)
|
||||
|
||||
for (i = 0; i < GITS_BASER_NR_REGS; i++) {
|
||||
if (its->tables[i].base) {
|
||||
free_pages((unsigned long)its->tables[i].base,
|
||||
its->tables[i].order);
|
||||
its_free_pages(its->tables[i].base, its->tables[i].order);
|
||||
its->tables[i].base = NULL;
|
||||
}
|
||||
}
|
||||
@@ -2790,7 +2873,7 @@ static bool allocate_vpe_l2_table(int cpu, u32 id)
|
||||
|
||||
/* Allocate memory for 2nd level table */
|
||||
if (!table[idx]) {
|
||||
page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
|
||||
page = its_alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz));
|
||||
if (!page)
|
||||
return false;
|
||||
|
||||
@@ -2909,7 +2992,7 @@ static int allocate_vpe_l1_table(void)
|
||||
|
||||
pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n",
|
||||
np, npg, psz, epp, esz);
|
||||
page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
|
||||
page = its_alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE));
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2955,8 +3038,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
|
||||
{
|
||||
struct page *pend_page;
|
||||
|
||||
pend_page = alloc_pages(gfp_flags | __GFP_ZERO,
|
||||
get_order(LPI_PENDBASE_SZ));
|
||||
pend_page = its_alloc_pages(gfp_flags | __GFP_ZERO, get_order(LPI_PENDBASE_SZ));
|
||||
if (!pend_page)
|
||||
return NULL;
|
||||
|
||||
@@ -2968,7 +3050,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags)
|
||||
|
||||
static void its_free_pending_table(struct page *pt)
|
||||
{
|
||||
free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ));
|
||||
its_free_pages(page_address(pt), get_order(LPI_PENDBASE_SZ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3303,8 +3385,8 @@ static bool its_alloc_table_entry(struct its_node *its,
|
||||
|
||||
/* Allocate memory for 2nd level table */
|
||||
if (!table[idx]) {
|
||||
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
|
||||
get_order(baser->psz));
|
||||
page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
|
||||
get_order(baser->psz));
|
||||
if (!page)
|
||||
return false;
|
||||
|
||||
@@ -3399,15 +3481,18 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
|
||||
if (WARN_ON(!is_power_of_2(nvecs)))
|
||||
nvecs = roundup_pow_of_two(nvecs);
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
/*
|
||||
* Even if the device wants a single LPI, the ITT must be
|
||||
* sized as a power of two (and you need at least one bit...).
|
||||
*/
|
||||
nr_ites = max(2, nvecs);
|
||||
sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
|
||||
sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
|
||||
itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node);
|
||||
sz = max(sz, ITS_ITT_ALIGN);
|
||||
|
||||
itt = itt_alloc_pool(its->numa_node, sz);
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
|
||||
if (alloc_lpis) {
|
||||
lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis);
|
||||
if (lpi_map)
|
||||
@@ -3419,9 +3504,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
|
||||
lpi_base = 0;
|
||||
}
|
||||
|
||||
if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) {
|
||||
if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) {
|
||||
kfree(dev);
|
||||
kfree(itt);
|
||||
itt_free_pool(itt, sz);
|
||||
bitmap_free(lpi_map);
|
||||
kfree(col_map);
|
||||
return NULL;
|
||||
@@ -3431,6 +3516,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
|
||||
|
||||
dev->its = its;
|
||||
dev->itt = itt;
|
||||
dev->itt_sz = sz;
|
||||
dev->nr_ites = nr_ites;
|
||||
dev->event_map.lpi_map = lpi_map;
|
||||
dev->event_map.col_map = col_map;
|
||||
@@ -3458,7 +3544,7 @@ static void its_free_device(struct its_device *its_dev)
|
||||
list_del(&its_dev->entry);
|
||||
raw_spin_unlock_irqrestore(&its_dev->its->lock, flags);
|
||||
kfree(its_dev->event_map.col_map);
|
||||
kfree(its_dev->itt);
|
||||
itt_free_pool(its_dev->itt, its_dev->itt_sz);
|
||||
kfree(its_dev);
|
||||
}
|
||||
|
||||
@@ -5132,8 +5218,9 @@ static int __init its_probe_one(struct its_node *its)
|
||||
}
|
||||
}
|
||||
|
||||
page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO,
|
||||
get_order(ITS_CMD_QUEUE_SZ));
|
||||
page = its_alloc_pages_node(its->numa_node,
|
||||
GFP_KERNEL | __GFP_ZERO,
|
||||
get_order(ITS_CMD_QUEUE_SZ));
|
||||
if (!page) {
|
||||
err = -ENOMEM;
|
||||
goto out_unmap_sgir;
|
||||
@@ -5197,7 +5284,7 @@ static int __init its_probe_one(struct its_node *its)
|
||||
out_free_tables:
|
||||
its_free_tables(its);
|
||||
out_free_cmd:
|
||||
free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
|
||||
its_free_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
|
||||
out_unmap_sgir:
|
||||
if (its->sgir_base)
|
||||
iounmap(its->sgir_base);
|
||||
@@ -5683,6 +5770,10 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
|
||||
bool has_v4_1 = false;
|
||||
int err;
|
||||
|
||||
itt_pool = gen_pool_create(get_order(ITS_ITT_ALIGN), -1);
|
||||
if (!itt_pool)
|
||||
return -ENOMEM;
|
||||
|
||||
gic_rdists = rdists;
|
||||
|
||||
lpi_prop_prio = irq_prio;
|
||||
|
||||
@@ -66,6 +66,87 @@ static struct gic_all_vpes_chip_data {
|
||||
bool mask;
|
||||
} gic_all_vpes_chip_data[GIC_NUM_LOCAL_INTRS];
|
||||
|
||||
static int __gic_with_next_online_cpu(int prev)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* Discover the next online CPU */
|
||||
cpu = cpumask_next(prev, cpu_online_mask);
|
||||
|
||||
/* If there isn't one, we're done */
|
||||
if (cpu >= nr_cpu_ids)
|
||||
return cpu;
|
||||
|
||||
/*
|
||||
* Move the access lock to the next CPU's GIC local register block.
|
||||
*
|
||||
* Set GIC_VL_OTHER. Since the caller holds gic_lock nothing can
|
||||
* clobber the written value.
|
||||
*/
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
static inline void gic_unlock_cluster(void)
|
||||
{
|
||||
if (mips_cps_multicluster_cpus())
|
||||
mips_cm_unlock_other();
|
||||
}
|
||||
|
||||
/**
|
||||
* for_each_online_cpu_gic() - Iterate over online CPUs, access local registers
|
||||
* @cpu: An integer variable to hold the current CPU number
|
||||
* @gic_lock: A pointer to raw spin lock used as a guard
|
||||
*
|
||||
* Iterate over online CPUs & configure the other/redirect register region to
|
||||
* access each CPUs GIC local register block, which can be accessed from the
|
||||
* loop body using read_gic_vo_*() or write_gic_vo_*() accessor functions or
|
||||
* their derivatives.
|
||||
*/
|
||||
#define for_each_online_cpu_gic(cpu, gic_lock) \
|
||||
guard(raw_spinlock_irqsave)(gic_lock); \
|
||||
for ((cpu) = __gic_with_next_online_cpu(-1); \
|
||||
(cpu) < nr_cpu_ids; \
|
||||
gic_unlock_cluster(), \
|
||||
(cpu) = __gic_with_next_online_cpu(cpu))
|
||||
|
||||
/**
|
||||
* gic_irq_lock_cluster() - Lock redirect block access to IRQ's cluster
|
||||
* @d: struct irq_data corresponding to the interrupt we're interested in
|
||||
*
|
||||
* Locks redirect register block access to the global register block of the GIC
|
||||
* within the remote cluster that the IRQ corresponding to @d is affine to,
|
||||
* returning true when this redirect block setup & locking has been performed.
|
||||
*
|
||||
* If @d is affine to the local cluster then no locking is performed and this
|
||||
* function will return false, indicating to the caller that it should access
|
||||
* the local clusters registers without the overhead of indirection through the
|
||||
* redirect block.
|
||||
*
|
||||
* In summary, if this function returns true then the caller should access GIC
|
||||
* registers using redirect register block accessors & then call
|
||||
* mips_cm_unlock_other() when done. If this function returns false then the
|
||||
* caller should trivially access GIC registers in the local cluster.
|
||||
*
|
||||
* Returns true if locking performed, else false.
|
||||
*/
|
||||
static bool gic_irq_lock_cluster(struct irq_data *d)
|
||||
{
|
||||
unsigned int cpu, cl;
|
||||
|
||||
cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
|
||||
BUG_ON(cpu >= NR_CPUS);
|
||||
|
||||
cl = cpu_cluster(&cpu_data[cpu]);
|
||||
if (cl == cpu_cluster(¤t_cpu_data))
|
||||
return false;
|
||||
if (mips_cps_numcores(cl) == 0)
|
||||
return false;
|
||||
mips_cm_lock_other(cl, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gic_clear_pcpu_masks(unsigned int intr)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -112,7 +193,12 @@ static void gic_send_ipi(struct irq_data *d, unsigned int cpu)
|
||||
{
|
||||
irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d));
|
||||
|
||||
write_gic_wedge(GIC_WEDGE_RW | hwirq);
|
||||
if (gic_irq_lock_cluster(d)) {
|
||||
write_gic_redir_wedge(GIC_WEDGE_RW | hwirq);
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
write_gic_wedge(GIC_WEDGE_RW | hwirq);
|
||||
}
|
||||
}
|
||||
|
||||
int gic_get_c0_compare_int(void)
|
||||
@@ -180,7 +266,13 @@ static void gic_mask_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
|
||||
|
||||
write_gic_rmask(intr);
|
||||
if (gic_irq_lock_cluster(d)) {
|
||||
write_gic_redir_rmask(intr);
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
write_gic_rmask(intr);
|
||||
}
|
||||
|
||||
gic_clear_pcpu_masks(intr);
|
||||
}
|
||||
|
||||
@@ -189,7 +281,12 @@ static void gic_unmask_irq(struct irq_data *d)
|
||||
unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq);
|
||||
unsigned int cpu;
|
||||
|
||||
write_gic_smask(intr);
|
||||
if (gic_irq_lock_cluster(d)) {
|
||||
write_gic_redir_smask(intr);
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
write_gic_smask(intr);
|
||||
}
|
||||
|
||||
gic_clear_pcpu_masks(intr);
|
||||
cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
|
||||
@@ -200,7 +297,12 @@ static void gic_ack_irq(struct irq_data *d)
|
||||
{
|
||||
unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
|
||||
|
||||
write_gic_wedge(irq);
|
||||
if (gic_irq_lock_cluster(d)) {
|
||||
write_gic_redir_wedge(irq);
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
write_gic_wedge(irq);
|
||||
}
|
||||
}
|
||||
|
||||
static int gic_set_type(struct irq_data *d, unsigned int type)
|
||||
@@ -240,9 +342,16 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
|
||||
break;
|
||||
}
|
||||
|
||||
change_gic_pol(irq, pol);
|
||||
change_gic_trig(irq, trig);
|
||||
change_gic_dual(irq, dual);
|
||||
if (gic_irq_lock_cluster(d)) {
|
||||
change_gic_redir_pol(irq, pol);
|
||||
change_gic_redir_trig(irq, trig);
|
||||
change_gic_redir_dual(irq, dual);
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
change_gic_pol(irq, pol);
|
||||
change_gic_trig(irq, trig);
|
||||
change_gic_dual(irq, dual);
|
||||
}
|
||||
|
||||
if (trig == GIC_TRIG_EDGE)
|
||||
irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller,
|
||||
@@ -260,25 +369,72 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
|
||||
bool force)
|
||||
{
|
||||
unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
|
||||
unsigned int cpu, cl, old_cpu, old_cl;
|
||||
unsigned long flags;
|
||||
unsigned int cpu;
|
||||
|
||||
/*
|
||||
* The GIC specifies that we can only route an interrupt to one VP(E),
|
||||
* ie. CPU in Linux parlance, at a time. Therefore we always route to
|
||||
* the first online CPU in the mask.
|
||||
*/
|
||||
cpu = cpumask_first_and(cpumask, cpu_online_mask);
|
||||
if (cpu >= NR_CPUS)
|
||||
return -EINVAL;
|
||||
|
||||
/* Assumption : cpumask refers to a single CPU */
|
||||
old_cpu = cpumask_first(irq_data_get_effective_affinity_mask(d));
|
||||
old_cl = cpu_cluster(&cpu_data[old_cpu]);
|
||||
cl = cpu_cluster(&cpu_data[cpu]);
|
||||
|
||||
raw_spin_lock_irqsave(&gic_lock, flags);
|
||||
|
||||
/* Re-route this IRQ */
|
||||
write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu)));
|
||||
|
||||
/* Update the pcpu_masks */
|
||||
gic_clear_pcpu_masks(irq);
|
||||
if (read_gic_mask(irq))
|
||||
set_bit(irq, per_cpu_ptr(pcpu_masks, cpu));
|
||||
/*
|
||||
* If we're moving affinity between clusters, stop routing the
|
||||
* interrupt to any VP(E) in the old cluster.
|
||||
*/
|
||||
if (cl != old_cl) {
|
||||
if (gic_irq_lock_cluster(d)) {
|
||||
write_gic_redir_map_vp(irq, 0);
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
write_gic_map_vp(irq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update effective affinity - after this gic_irq_lock_cluster() will
|
||||
* begin operating on the new cluster.
|
||||
*/
|
||||
irq_data_update_effective_affinity(d, cpumask_of(cpu));
|
||||
|
||||
/*
|
||||
* If we're moving affinity between clusters, configure the interrupt
|
||||
* trigger type in the new cluster.
|
||||
*/
|
||||
if (cl != old_cl)
|
||||
gic_set_type(d, irqd_get_trigger_type(d));
|
||||
|
||||
/* Route the interrupt to its new VP(E) */
|
||||
if (gic_irq_lock_cluster(d)) {
|
||||
write_gic_redir_map_pin(irq,
|
||||
GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
|
||||
write_gic_redir_map_vp(irq, BIT(mips_cm_vp_id(cpu)));
|
||||
|
||||
/* Update the pcpu_masks */
|
||||
gic_clear_pcpu_masks(irq);
|
||||
if (read_gic_redir_mask(irq))
|
||||
set_bit(irq, per_cpu_ptr(pcpu_masks, cpu));
|
||||
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
write_gic_map_pin(irq, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
|
||||
write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu)));
|
||||
|
||||
/* Update the pcpu_masks */
|
||||
gic_clear_pcpu_masks(irq);
|
||||
if (read_gic_mask(irq))
|
||||
set_bit(irq, per_cpu_ptr(pcpu_masks, cpu));
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
||||
return IRQ_SET_MASK_OK;
|
||||
@@ -350,37 +506,33 @@ static struct irq_chip gic_local_irq_controller = {
|
||||
static void gic_mask_local_irq_all_vpes(struct irq_data *d)
|
||||
{
|
||||
struct gic_all_vpes_chip_data *cd;
|
||||
unsigned long flags;
|
||||
int intr, cpu;
|
||||
|
||||
if (!mips_cps_multicluster_cpus())
|
||||
return;
|
||||
|
||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
cd = irq_data_get_irq_chip_data(d);
|
||||
cd->mask = false;
|
||||
|
||||
raw_spin_lock_irqsave(&gic_lock, flags);
|
||||
for_each_online_cpu(cpu) {
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
for_each_online_cpu_gic(cpu, &gic_lock)
|
||||
write_gic_vo_rmask(BIT(intr));
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&gic_lock, flags);
|
||||
}
|
||||
|
||||
static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
|
||||
{
|
||||
struct gic_all_vpes_chip_data *cd;
|
||||
unsigned long flags;
|
||||
int intr, cpu;
|
||||
|
||||
if (!mips_cps_multicluster_cpus())
|
||||
return;
|
||||
|
||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||
cd = irq_data_get_irq_chip_data(d);
|
||||
cd->mask = true;
|
||||
|
||||
raw_spin_lock_irqsave(&gic_lock, flags);
|
||||
for_each_online_cpu(cpu) {
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
for_each_online_cpu_gic(cpu, &gic_lock)
|
||||
write_gic_vo_smask(BIT(intr));
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&gic_lock, flags);
|
||||
}
|
||||
|
||||
static void gic_all_vpes_irq_cpu_online(void)
|
||||
@@ -436,11 +588,21 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
unsigned long flags;
|
||||
|
||||
data = irq_get_irq_data(virq);
|
||||
irq_data_update_effective_affinity(data, cpumask_of(cpu));
|
||||
|
||||
raw_spin_lock_irqsave(&gic_lock, flags);
|
||||
write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
|
||||
write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
|
||||
irq_data_update_effective_affinity(data, cpumask_of(cpu));
|
||||
|
||||
/* Route the interrupt to its VP(E) */
|
||||
if (gic_irq_lock_cluster(data)) {
|
||||
write_gic_redir_map_pin(intr,
|
||||
GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
|
||||
write_gic_redir_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
|
||||
mips_cm_unlock_other();
|
||||
} else {
|
||||
write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
|
||||
write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
||||
return 0;
|
||||
@@ -469,7 +631,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct gic_all_vpes_chip_data *cd;
|
||||
unsigned long flags;
|
||||
unsigned int intr;
|
||||
int err, cpu;
|
||||
u32 map;
|
||||
@@ -533,12 +694,10 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||
if (!gic_local_irq_is_routable(intr))
|
||||
return -EPERM;
|
||||
|
||||
raw_spin_lock_irqsave(&gic_lock, flags);
|
||||
for_each_online_cpu(cpu) {
|
||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||
write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
|
||||
if (mips_cps_multicluster_cpus()) {
|
||||
for_each_online_cpu_gic(cpu, &gic_lock)
|
||||
write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&gic_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -621,6 +780,9 @@ static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq,
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* Set affinity to cpu. */
|
||||
irq_data_update_effective_affinity(irq_get_irq_data(virq + i),
|
||||
cpumask_of(cpu));
|
||||
ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING);
|
||||
if (ret)
|
||||
goto error;
|
||||
@@ -734,7 +896,7 @@ static int gic_cpu_startup(unsigned int cpu)
|
||||
static int __init gic_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
unsigned int cpu_vec, i, gicconfig;
|
||||
unsigned int cpu_vec, i, gicconfig, cl, nclusters;
|
||||
unsigned long reserved;
|
||||
phys_addr_t gic_base;
|
||||
struct resource res;
|
||||
@@ -815,11 +977,32 @@ static int __init gic_of_init(struct device_node *node,
|
||||
|
||||
board_bind_eic_interrupt = &gic_bind_eic_interrupt;
|
||||
|
||||
/* Setup defaults */
|
||||
for (i = 0; i < gic_shared_intrs; i++) {
|
||||
change_gic_pol(i, GIC_POL_ACTIVE_HIGH);
|
||||
change_gic_trig(i, GIC_TRIG_LEVEL);
|
||||
write_gic_rmask(i);
|
||||
/*
|
||||
* Initialise each cluster's GIC shared registers to sane default
|
||||
* values.
|
||||
* Otherwise, the IPI set up will be erased if we move code
|
||||
* to gic_cpu_startup for each cpu.
|
||||
*/
|
||||
nclusters = mips_cps_numclusters();
|
||||
for (cl = 0; cl < nclusters; cl++) {
|
||||
if (cl == cpu_cluster(¤t_cpu_data)) {
|
||||
for (i = 0; i < gic_shared_intrs; i++) {
|
||||
change_gic_pol(i, GIC_POL_ACTIVE_HIGH);
|
||||
change_gic_trig(i, GIC_TRIG_LEVEL);
|
||||
write_gic_rmask(i);
|
||||
}
|
||||
} else if (mips_cps_numcores(cl) != 0) {
|
||||
mips_cm_lock_other(cl, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
|
||||
for (i = 0; i < gic_shared_intrs; i++) {
|
||||
change_gic_redir_pol(i, GIC_POL_ACTIVE_HIGH);
|
||||
change_gic_redir_trig(i, GIC_TRIG_LEVEL);
|
||||
write_gic_redir_rmask(i);
|
||||
}
|
||||
mips_cm_unlock_other();
|
||||
|
||||
} else {
|
||||
pr_warn("No CPU cores on the cluster %d skip it\n", cl);
|
||||
}
|
||||
}
|
||||
|
||||
return cpuhp_setup_state(CPUHP_AP_IRQ_MIPS_GIC_STARTING,
|
||||
|
||||
513
drivers/irqchip/irq-renesas-rzv2h.c
Normal file
513
drivers/irqchip/irq-renesas-rzv2h.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user