mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 20:48:49 +08:00
irqchip updates for Linux 5.13
New HW support: - New driver for the Nuvoton WPCM450 interrupt controller - New driver for the IDT 79rc3243x interrupt controller - Add support for interrupt trigger configuration to the MStar irqchip - Add more external interrupt support to the STM32 irqchip - Add new compatible strings for QCOM SC7280 to the qcom-pdc binding Fixes and cleanups: - Drop irq_create_strict_mappings() and irq_create_identity_mapping() from the irqdomain API, with cleanups in a couple of drivers - Fix nested NMI issue with spurious interrupts on GICv3 - Don't allow GICv4.1 vSGIs when the CPU doesn't support them - Various cleanups and minor fixes -----BEGIN PGP SIGNATURE----- iQJDBAABCgAtFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAmCD5kwPHG1hekBrZXJu ZWwub3JnAAoJECPQ0LrRPXpDCWsQAL5yHXtApf4l3F0W99SJIooumrQh3UR6nENG 2WVR66g+MiuZ/JQcHAojdLQ6W6K9W8eTcY3hRNFCqlI1lrKffz6ovstuYg3Wphog JX1gQYcpqt67WYtb/TVw3JM5D3NLU4XKPKZPhRzSHv5G9utI2QeAv13EBcPoHxZd UBRAEdUrv90KIFDe2CxWo8B5ra07xfgOpDvlYYKlee+jQLtf6i4Kj7Tm0XoK3hoW w0Mo//5r2SggdXfFLW1sm0BGs0bpJMSNixKCZWRfXbnZLAYIaBynSoLT9XoYT/uC FDegtFZ9IG/5NXJ1d3Yl0RjsPp+iPUOOTq/5gAoXI0hRCLZ1f8G1IuDEoIf8ElOg kxA1JpYE1fewxNt7oh48BAs3Qa3fdjJ1+k6gFlau4ctJBjxTHMz7v7lr7PmjhPz7 HgcmzFCu9Wb8pj1IDHMINkOMmAiQhgr3N0WK372wQyNE8Z8iB0ZeCYX9jAV5YTK6 eQdsDgNW18rv1ks/f7vzJw4EHRUM2tzSYimgf3oW+EJq6xKacMHfDMp9ERtHcnfJ +4CCEEafrSOj/KsNpNnA7Bq3Qjh+RdRXDtCPsoGQ3LS1L5/JOaUoSmrCkWNNfXuZ kUKTrNzopmMPvvwx6Q1YUypMbKCloNvlO3IgKalKNVP5drWA184abOIU2MGp+yI1 LAA8SFYU =RqVj -----END PGP SIGNATURE----- Merge tag 'irqchip-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core Pull irqchip and irqdomain updates from Marc Zyngier: New HW support: - New driver for the Nuvoton WPCM450 interrupt controller - New driver for the IDT 79rc3243x interrupt controller - Add support for interrupt trigger configuration to the MStar irqchip - Add more external interrupt support to the STM32 irqchip - Add new compatible strings for QCOM SC7280 to the qcom-pdc binding Fixes and cleanups: - Drop irq_create_strict_mappings() and irq_create_identity_mapping() from the irqdomain API, with cleanups in a couple of drivers - Fix nested NMI issue with spurious interrupts on GICv3 - Don't allow GICv4.1 vSGIs when the CPU doesn't support them - Various cleanups and minor fixes Link: https://lore.kernel.org/r/20210424094640.1731920-1-maz@kernel.org
This commit is contained in:
commit
765822e156
@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/idt,32434-pic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: IDT 79RC32434 Interrupt Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/interrupt-controller.yaml#
|
||||
|
||||
properties:
|
||||
"#interrupt-cells":
|
||||
const: 1
|
||||
|
||||
compatible:
|
||||
const: idt,32434-pic
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
required:
|
||||
- "#interrupt-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- interrupt-controller
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
idtpic3: interrupt-controller@3800c {
|
||||
compatible = "idt,32434-pic";
|
||||
reg = <0x3800c 0x0c>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
|
||||
interrupt-parent = <&cpuintc>;
|
||||
interrupts = <3>;
|
||||
};
|
||||
|
||||
...
|
@ -23,6 +23,7 @@ properties:
|
||||
- enum:
|
||||
- ingenic,jz4775-intc
|
||||
- ingenic,jz4770-intc
|
||||
- ingenic,jz4760b-intc
|
||||
- const: ingenic,jz4760-intc
|
||||
- items:
|
||||
- const: ingenic,x1000-intc
|
||||
|
@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interrupt-controller/nuvoton,wpcm450-aic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Nuvoton WPCM450 Advanced Interrupt Controller bindings
|
||||
|
||||
maintainers:
|
||||
- Jonathan Neuschäfer <j.neuschaefer@gmx.net>
|
||||
|
||||
properties:
|
||||
'#interrupt-cells':
|
||||
const: 2
|
||||
|
||||
compatible:
|
||||
const: nuvoton,wpcm450-aic
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- '#interrupt-cells'
|
||||
- compatible
|
||||
- reg
|
||||
- interrupt-controller
|
||||
|
||||
examples:
|
||||
- |
|
||||
aic: interrupt-controller@b8002000 {
|
||||
compatible = "nuvoton,wpcm450-aic";
|
||||
reg = <0xb8002000 0x1000>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
@ -19,6 +19,7 @@ Properties:
|
||||
Value type: <string>
|
||||
Definition: Should contain "qcom,<soc>-pdc" and "qcom,pdc"
|
||||
- "qcom,sc7180-pdc": For SC7180
|
||||
- "qcom,sc7280-pdc": For SC7280
|
||||
- "qcom,sdm845-pdc": For SDM845
|
||||
- "qcom,sdm8250-pdc": For SM8250
|
||||
- "qcom,sdm8350-pdc": For SM8350
|
||||
|
@ -348,6 +348,7 @@ config ARCH_EP93XX
|
||||
select ARM_AMBA
|
||||
imply ARM_PATCH_PHYS_VIRT
|
||||
select ARM_VIC
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select AUTO_ZRELADDR
|
||||
select CLKDEV_LOOKUP
|
||||
select CLKSRC_MMIO
|
||||
|
@ -147,22 +147,20 @@ static int cplds_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
irq_set_irq_wake(fpga->irq, 1);
|
||||
fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
|
||||
CPLDS_NB_IRQ,
|
||||
&cplds_irq_domain_ops, fpga);
|
||||
if (base_irq)
|
||||
fpga->irqdomain = irq_domain_add_legacy(pdev->dev.of_node,
|
||||
CPLDS_NB_IRQ,
|
||||
base_irq, 0,
|
||||
&cplds_irq_domain_ops,
|
||||
fpga);
|
||||
else
|
||||
fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
|
||||
CPLDS_NB_IRQ,
|
||||
&cplds_irq_domain_ops,
|
||||
fpga);
|
||||
if (!fpga->irqdomain)
|
||||
return -ENODEV;
|
||||
|
||||
if (base_irq) {
|
||||
ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0,
|
||||
CPLDS_NB_IRQ);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n",
|
||||
base_irq, base_irq + CPLDS_NB_IRQ);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
break;
|
||||
case GICD_TYPER2:
|
||||
if (kvm_vgic_global_state.has_gicv4_1)
|
||||
if (kvm_vgic_global_state.has_gicv4_1 && gic_cpuif_has_vsgi())
|
||||
value = GICD_TYPER2_nASSGIcap;
|
||||
break;
|
||||
case GICD_IIDR:
|
||||
@ -119,7 +119,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
|
||||
dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
|
||||
|
||||
/* Not a GICv4.1? No HW SGIs */
|
||||
if (!kvm_vgic_global_state.has_gicv4_1)
|
||||
if (!kvm_vgic_global_state.has_gicv4_1 || !gic_cpuif_has_vsgi())
|
||||
val &= ~GICD_CTLR_nASSGIreq;
|
||||
|
||||
/* Dist stays enabled? nASSGIreq is RO */
|
||||
|
@ -276,10 +276,6 @@ asmlinkage void plat_irq_dispatch(void)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_XLP
|
||||
static const struct irq_domain_ops xlp_pic_irq_domain_ops = {
|
||||
.xlate = irq_domain_xlate_onetwocell,
|
||||
};
|
||||
|
||||
static int __init xlp_of_pic_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
@ -324,7 +320,7 @@ static int __init xlp_of_pic_init(struct device_node *node,
|
||||
|
||||
xlp_pic_domain = irq_domain_add_legacy(node, n_picirqs,
|
||||
nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE,
|
||||
&xlp_pic_irq_domain_ops, NULL);
|
||||
&irq_domain_simple_ops, NULL);
|
||||
if (xlp_pic_domain == NULL) {
|
||||
pr_err("PIC %pOFn: Creating legacy domain failed!\n", node);
|
||||
return -EINVAL;
|
||||
|
@ -8,7 +8,6 @@ config IRQCHIP
|
||||
config ARM_GIC
|
||||
bool
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
|
||||
config ARM_GIC_PM
|
||||
@ -33,7 +32,6 @@ config GIC_NON_BANKED
|
||||
|
||||
config ARM_GIC_V3
|
||||
bool
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select PARTITION_PERCPU
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
@ -64,7 +62,6 @@ config ARM_NVIC
|
||||
config ARM_VIC
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
|
||||
config ARM_VIC_NR
|
||||
int
|
||||
@ -99,14 +96,12 @@ config ATMEL_AIC_IRQ
|
||||
bool
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select SPARSE_IRQ
|
||||
|
||||
config ATMEL_AIC5_IRQ
|
||||
bool
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select SPARSE_IRQ
|
||||
|
||||
config I8259
|
||||
@ -153,7 +148,6 @@ config DW_APB_ICTL
|
||||
config FARADAY_FTINTC010
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select SPARSE_IRQ
|
||||
|
||||
config HISILICON_IRQ_MBIGEN
|
||||
@ -169,7 +163,6 @@ config IMGPDC_IRQ
|
||||
config IXP4XX_IRQ
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select SPARSE_IRQ
|
||||
|
||||
config MADERA_IRQ
|
||||
@ -186,7 +179,6 @@ config CLPS711X_IRQCHIP
|
||||
bool
|
||||
depends on ARCH_CLPS711X
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
select SPARSE_IRQ
|
||||
default y
|
||||
|
||||
@ -205,7 +197,6 @@ config OMAP_IRQCHIP
|
||||
config ORION_IRQCHIP
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
select GENERIC_IRQ_MULTI_HANDLER
|
||||
|
||||
config PIC32_EVIC
|
||||
bool
|
||||
@ -288,8 +279,13 @@ config XTENSA_MX
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK
|
||||
|
||||
config XILINX_INTC
|
||||
bool
|
||||
bool "Xilinx Interrupt Controller IP"
|
||||
depends on MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
Support for the Xilinx Interrupt Controller IP core.
|
||||
This is used as a primary controller with MicroBlaze and can also
|
||||
be used as a secondary chained controller on other platforms.
|
||||
|
||||
config IRQ_CROSSBAR
|
||||
bool
|
||||
@ -586,4 +582,15 @@ config MST_IRQ
|
||||
help
|
||||
Support MStar Interrupt Controller.
|
||||
|
||||
config WPCM450_AIC
|
||||
bool "Nuvoton WPCM450 Advanced Interrupt Controller"
|
||||
depends on ARCH_WPCM450
|
||||
help
|
||||
Support for the interrupt controller in the Nuvoton WPCM450 BMC SoC.
|
||||
|
||||
config IRQ_IDT3243X
|
||||
bool
|
||||
select GENERIC_IRQ_CHIP
|
||||
select IRQ_DOMAIN
|
||||
|
||||
endmenu
|
||||
|
@ -113,3 +113,5 @@ obj-$(CONFIG_LOONGSON_PCH_MSI) += irq-loongson-pch-msi.o
|
||||
obj-$(CONFIG_MST_IRQ) += irq-mst-intc.o
|
||||
obj-$(CONFIG_SL28CPLD_INTC) += irq-sl28cpld.o
|
||||
obj-$(CONFIG_MACH_REALTEK_RTL) += irq-realtek-rtl.o
|
||||
obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o
|
||||
obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o
|
||||
|
@ -303,7 +303,7 @@ int __init mbi_init(struct fwnode_handle *fwnode, struct irq_domain *parent)
|
||||
reg = of_get_property(np, "mbi-alias", NULL);
|
||||
if (reg) {
|
||||
mbi_phys_base = of_translate_address(np, reg);
|
||||
if (mbi_phys_base == OF_BAD_ADDR) {
|
||||
if (mbi_phys_base == (phys_addr_t)OF_BAD_ADDR) {
|
||||
ret = -ENXIO;
|
||||
goto err_free_mbi;
|
||||
}
|
||||
|
@ -648,6 +648,10 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
|
||||
|
||||
irqnr = gic_read_iar();
|
||||
|
||||
/* Check for special IDs first */
|
||||
if ((irqnr >= 1020 && irqnr <= 1023))
|
||||
return;
|
||||
|
||||
if (gic_supports_nmi() &&
|
||||
unlikely(gic_read_rpr() == GICD_INT_NMI_PRI)) {
|
||||
gic_handle_nmi(irqnr, regs);
|
||||
@ -659,10 +663,6 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
|
||||
gic_arch_enable_irqs();
|
||||
}
|
||||
|
||||
/* Check for special IDs first */
|
||||
if ((irqnr >= 1020 && irqnr <= 1023))
|
||||
return;
|
||||
|
||||
if (static_branch_likely(&supports_deactivate_key))
|
||||
gic_write_eoir(irqnr);
|
||||
else
|
||||
|
@ -87,17 +87,40 @@ static struct irq_domain *gic_domain;
|
||||
static const struct irq_domain_ops *vpe_domain_ops;
|
||||
static const struct irq_domain_ops *sgi_domain_ops;
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
bool gic_cpuif_has_vsgi(void)
|
||||
{
|
||||
unsigned long fld, reg = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
|
||||
|
||||
fld = cpuid_feature_extract_unsigned_field(reg, ID_AA64PFR0_GIC_SHIFT);
|
||||
|
||||
return fld >= 0x3;
|
||||
}
|
||||
#else
|
||||
bool gic_cpuif_has_vsgi(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool has_v4_1(void)
|
||||
{
|
||||
return !!sgi_domain_ops;
|
||||
}
|
||||
|
||||
static bool has_v4_1_sgi(void)
|
||||
{
|
||||
return has_v4_1() && gic_cpuif_has_vsgi();
|
||||
}
|
||||
|
||||
static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
|
||||
{
|
||||
char *name;
|
||||
int sgi_base;
|
||||
|
||||
if (!has_v4_1())
|
||||
if (!has_v4_1_sgi())
|
||||
return 0;
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current));
|
||||
@ -182,7 +205,7 @@ static void its_free_sgi_irqs(struct its_vm *vm)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!has_v4_1())
|
||||
if (!has_v4_1_sgi())
|
||||
return;
|
||||
|
||||
for (i = 0; i < vm->nr_vpes; i++) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Hisilicon HiP04 INTC
|
||||
* HiSilicon HiP04 INTC
|
||||
*
|
||||
* Copyright (C) 2002-2014 ARM Limited.
|
||||
* Copyright (c) 2013-2014 Hisilicon Ltd.
|
||||
* Copyright (c) 2013-2014 HiSilicon Ltd.
|
||||
* Copyright (c) 2013-2014 Linaro Ltd.
|
||||
*
|
||||
* Interrupt architecture for the HIP04 INTC:
|
||||
|
124
drivers/irqchip/irq-idt3243x.c
Normal file
124
drivers/irqchip/irq-idt3243x.c
Normal file
@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for IDT/Renesas 79RC3243x Interrupt Controller.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/interrupt.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>
|
||||
|
||||
#define IDT_PIC_NR_IRQS 32
|
||||
|
||||
#define IDT_PIC_IRQ_PEND 0x00
|
||||
#define IDT_PIC_IRQ_MASK 0x08
|
||||
|
||||
struct idt_pic_data {
|
||||
void __iomem *base;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_chip_generic *gc;
|
||||
};
|
||||
|
||||
static void idt_irq_dispatch(struct irq_desc *desc)
|
||||
{
|
||||
struct idt_pic_data *idtpic = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *host_chip = irq_desc_get_chip(desc);
|
||||
u32 pending, hwirq, virq;
|
||||
|
||||
chained_irq_enter(host_chip, desc);
|
||||
|
||||
pending = irq_reg_readl(idtpic->gc, IDT_PIC_IRQ_PEND);
|
||||
pending &= ~idtpic->gc->mask_cache;
|
||||
while (pending) {
|
||||
hwirq = __fls(pending);
|
||||
virq = irq_linear_revmap(idtpic->irq_domain, hwirq);
|
||||
if (virq)
|
||||
generic_handle_irq(virq);
|
||||
pending &= ~(1 << hwirq);
|
||||
}
|
||||
|
||||
chained_irq_exit(host_chip, desc);
|
||||
}
|
||||
|
||||
static int idt_pic_init(struct device_node *of_node, struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
struct idt_pic_data *idtpic;
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
unsigned int parent_irq;
|
||||
int ret = 0;
|
||||
|
||||
idtpic = kzalloc(sizeof(*idtpic), GFP_KERNEL);
|
||||
if (!idtpic) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
parent_irq = irq_of_parse_and_map(of_node, 0);
|
||||
if (!parent_irq) {
|
||||
pr_err("Failed to map parent IRQ!\n");
|
||||
ret = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
idtpic->base = of_iomap(of_node, 0);
|
||||
if (!idtpic->base) {
|
||||
pr_err("Failed to map base address!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_unmap_irq;
|
||||
}
|
||||
|
||||
domain = irq_domain_add_linear(of_node, IDT_PIC_NR_IRQS,
|
||||
&irq_generic_chip_ops, NULL);
|
||||
if (!domain) {
|
||||
pr_err("Failed to add irqdomain!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_iounmap;
|
||||
}
|
||||
idtpic->irq_domain = domain;
|
||||
|
||||
ret = irq_alloc_domain_generic_chips(domain, 32, 1, "IDTPIC",
|
||||
handle_level_irq, 0,
|
||||
IRQ_NOPROBE | IRQ_LEVEL, 0);
|
||||
if (ret)
|
||||
goto out_domain_remove;
|
||||
|
||||
gc = irq_get_domain_generic_chip(domain, 0);
|
||||
gc->reg_base = idtpic->base;
|
||||
gc->private = idtpic;
|
||||
|
||||
ct = gc->chip_types;
|
||||
ct->regs.mask = IDT_PIC_IRQ_MASK;
|
||||
ct->chip.irq_mask = irq_gc_mask_set_bit;
|
||||
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
|
||||
idtpic->gc = gc;
|
||||
|
||||
/* Mask interrupts. */
|
||||
writel(0xffffffff, idtpic->base + IDT_PIC_IRQ_MASK);
|
||||
gc->mask_cache = 0xffffffff;
|
||||
|
||||
irq_set_chained_handler_and_data(parent_irq,
|
||||
idt_irq_dispatch, idtpic);
|
||||
|
||||
return 0;
|
||||
|
||||
out_domain_remove:
|
||||
irq_domain_remove(domain);
|
||||
out_iounmap:
|
||||
iounmap(idtpic->base);
|
||||
out_unmap_irq:
|
||||
irq_dispose_mapping(parent_irq);
|
||||
out_free:
|
||||
kfree(idtpic);
|
||||
out_err:
|
||||
pr_err("Failed to initialize! (errno = %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(idt_pic, "idt,32434-pic", idt_pic_init);
|
@ -179,5 +179,6 @@ err_free_tcu:
|
||||
}
|
||||
IRQCHIP_DECLARE(jz4740_tcu_irq, "ingenic,jz4740-tcu", ingenic_tcu_irq_init);
|
||||
IRQCHIP_DECLARE(jz4725b_tcu_irq, "ingenic,jz4725b-tcu", ingenic_tcu_irq_init);
|
||||
IRQCHIP_DECLARE(jz4760_tcu_irq, "ingenic,jz4760-tcu", ingenic_tcu_irq_init);
|
||||
IRQCHIP_DECLARE(jz4770_tcu_irq, "ingenic,jz4770-tcu", ingenic_tcu_irq_init);
|
||||
IRQCHIP_DECLARE(x1000_tcu_irq, "ingenic,x1000-tcu", ingenic_tcu_irq_init);
|
||||
|
@ -155,6 +155,7 @@ static int __init intc_2chip_of_init(struct device_node *node,
|
||||
{
|
||||
return ingenic_intc_of_init(node, 2);
|
||||
}
|
||||
IRQCHIP_DECLARE(jz4760_intc, "ingenic,jz4760-intc", intc_2chip_of_init);
|
||||
IRQCHIP_DECLARE(jz4770_intc, "ingenic,jz4770-intc", intc_2chip_of_init);
|
||||
IRQCHIP_DECLARE(jz4775_intc, "ingenic,jz4775-intc", intc_2chip_of_init);
|
||||
IRQCHIP_DECLARE(jz4780_intc, "ingenic,jz4780-intc", intc_2chip_of_init);
|
||||
|
@ -100,11 +100,11 @@ static int __init aic_irq_of_init(struct device_node *node,
|
||||
jcore_aic.irq_unmask = noop;
|
||||
jcore_aic.name = "AIC";
|
||||
|
||||
domain = irq_domain_add_linear(node, dom_sz, &jcore_aic_irqdomain_ops,
|
||||
domain = irq_domain_add_legacy(node, dom_sz - min_irq, min_irq, min_irq,
|
||||
&jcore_aic_irqdomain_ops,
|
||||
&jcore_aic);
|
||||
if (!domain)
|
||||
return -ENOMEM;
|
||||
irq_create_strict_mappings(domain, min_irq, min_irq, dom_sz - min_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
|
||||
* Copyright (C) 2015 HiSilicon Limited, All Rights Reserved.
|
||||
* Author: Jun Ma <majun258@huawei.com>
|
||||
* Author: Yun Wu <wuyun.wu@huawei.com>
|
||||
*/
|
||||
@ -390,4 +390,4 @@ module_platform_driver(mbigen_platform_driver);
|
||||
MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
|
||||
MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Hisilicon MBI Generator driver");
|
||||
MODULE_DESCRIPTION("HiSilicon MBI Generator driver");
|
||||
|
@ -13,15 +13,27 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#define INTC_MASK 0x0
|
||||
#define INTC_EOI 0x20
|
||||
#define MST_INTC_MAX_IRQS 64
|
||||
|
||||
#define INTC_MASK 0x0
|
||||
#define INTC_REV_POLARITY 0x10
|
||||
#define INTC_EOI 0x20
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static LIST_HEAD(mst_intc_list);
|
||||
#endif
|
||||
|
||||
struct mst_intc_chip_data {
|
||||
raw_spinlock_t lock;
|
||||
unsigned int irq_start, nr_irqs;
|
||||
void __iomem *base;
|
||||
bool no_eoi;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct list_head entry;
|
||||
u16 saved_polarity_conf[DIV_ROUND_UP(MST_INTC_MAX_IRQS, 16)];
|
||||
#endif
|
||||
};
|
||||
|
||||
static void mst_set_irq(struct irq_data *d, u32 offset)
|
||||
@ -78,6 +90,24 @@ static void mst_intc_eoi_irq(struct irq_data *d)
|
||||
irq_chip_eoi_parent(d);
|
||||
}
|
||||
|
||||
static int mst_irq_chip_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
switch (type) {
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
mst_set_irq(data, INTC_REV_POLARITY);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
mst_clear_irq(data, INTC_REV_POLARITY);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return irq_chip_set_type_parent(data, IRQ_TYPE_LEVEL_HIGH);
|
||||
}
|
||||
|
||||
static struct irq_chip mst_intc_chip = {
|
||||
.name = "mst-intc",
|
||||
.irq_mask = mst_intc_mask_irq,
|
||||
@ -87,13 +117,62 @@ static struct irq_chip mst_intc_chip = {
|
||||
.irq_set_irqchip_state = irq_chip_set_parent_state,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_set_vcpu_affinity = irq_chip_set_vcpu_affinity_parent,
|
||||
.irq_set_type = irq_chip_set_type_parent,
|
||||
.irq_set_type = mst_irq_chip_set_type,
|
||||
.irq_retrigger = irq_chip_retrigger_hierarchy,
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED |
|
||||
IRQCHIP_SKIP_SET_WAKE |
|
||||
IRQCHIP_MASK_ON_SUSPEND,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static void mst_intc_polarity_save(struct mst_intc_chip_data *cd)
|
||||
{
|
||||
int i;
|
||||
void __iomem *addr = cd->base + INTC_REV_POLARITY;
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(cd->nr_irqs, 16); i++)
|
||||
cd->saved_polarity_conf[i] = readw_relaxed(addr + i * 4);
|
||||
}
|
||||
|
||||
static void mst_intc_polarity_restore(struct mst_intc_chip_data *cd)
|
||||
{
|
||||
int i;
|
||||
void __iomem *addr = cd->base + INTC_REV_POLARITY;
|
||||
|
||||
for (i = 0; i < DIV_ROUND_UP(cd->nr_irqs, 16); i++)
|
||||
writew_relaxed(cd->saved_polarity_conf[i], addr + i * 4);
|
||||
}
|
||||
|
||||
static void mst_irq_resume(void)
|
||||
{
|
||||
struct mst_intc_chip_data *cd;
|
||||
|
||||
list_for_each_entry(cd, &mst_intc_list, entry)
|
||||
mst_intc_polarity_restore(cd);
|
||||
}
|
||||
|
||||
static int mst_irq_suspend(void)
|
||||
{
|
||||
struct mst_intc_chip_data *cd;
|
||||
|
||||
list_for_each_entry(cd, &mst_intc_list, entry)
|
||||
mst_intc_polarity_save(cd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct syscore_ops mst_irq_syscore_ops = {
|
||||
.suspend = mst_irq_suspend,
|
||||
.resume = mst_irq_resume,
|
||||
};
|
||||
|
||||
static int __init mst_irq_pm_init(void)
|
||||
{
|
||||
register_syscore_ops(&mst_irq_syscore_ops);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(mst_irq_pm_init);
|
||||
#endif
|
||||
|
||||
static int mst_intc_domain_translate(struct irq_domain *d,
|
||||
struct irq_fwspec *fwspec,
|
||||
unsigned long *hwirq,
|
||||
@ -145,6 +224,15 @@ static int mst_intc_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
parent_fwspec = *fwspec;
|
||||
parent_fwspec.fwnode = domain->parent->fwnode;
|
||||
parent_fwspec.param[1] = cd->irq_start + hwirq;
|
||||
|
||||
/*
|
||||
* mst-intc latch the interrupt request if it's edge triggered,
|
||||
* so the output signal to parent GIC is always level sensitive.
|
||||
* And if the irq signal is active low, configure it to active high
|
||||
* to meet GIC SPI spec in mst_irq_chip_set_type via REV_POLARITY bit.
|
||||
*/
|
||||
parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
|
||||
|
||||
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec);
|
||||
}
|
||||
|
||||
@ -193,6 +281,10 @@ static int __init mst_intc_of_init(struct device_node *dn,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
INIT_LIST_HEAD(&cd->entry);
|
||||
list_add_tail(&cd->entry, &mst_intc_list);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -77,8 +77,8 @@ struct plic_handler {
|
||||
void __iomem *enable_base;
|
||||
struct plic_priv *priv;
|
||||
};
|
||||
static int plic_parent_irq;
|
||||
static bool plic_cpuhp_setup_done;
|
||||
static int plic_parent_irq __ro_after_init;
|
||||
static bool plic_cpuhp_setup_done __ro_after_init;
|
||||
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
|
||||
|
||||
static inline void plic_toggle(struct plic_handler *handler,
|
||||
|
@ -193,7 +193,14 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = {
|
||||
{ .exti = 23, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 24, .irq_parent = 95, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 26, .irq_parent = 37, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 27, .irq_parent = 38, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 28, .irq_parent = 39, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 29, .irq_parent = 71, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 30, .irq_parent = 52, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 31, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 32, .irq_parent = 82, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct },
|
||||
{ .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct },
|
||||
|
@ -60,6 +60,7 @@ static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
break;
|
||||
case IRQ_TYPE_NONE:
|
||||
flow_type = IRQ_TYPE_LEVEL_LOW;
|
||||
fallthrough;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
mod ^= im;
|
||||
pol ^= im;
|
||||
|
161
drivers/irqchip/irq-wpcm450-aic.c
Normal file
161
drivers/irqchip/irq-wpcm450-aic.c
Normal file
@ -0,0 +1,161 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright 2021 Jonathan Neuschäfer
|
||||
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
|
||||
#define AIC_SCR(x) ((x)*4) /* Source control registers */
|
||||
#define AIC_GEN 0x84 /* Interrupt group enable control register */
|
||||
#define AIC_GRSR 0x88 /* Interrupt group raw status register */
|
||||
#define AIC_IRSR 0x100 /* Interrupt raw status register */
|
||||
#define AIC_IASR 0x104 /* Interrupt active status register */
|
||||
#define AIC_ISR 0x108 /* Interrupt status register */
|
||||
#define AIC_IPER 0x10c /* Interrupt priority encoding register */
|
||||
#define AIC_ISNR 0x110 /* Interrupt source number register */
|
||||
#define AIC_IMR 0x114 /* Interrupt mask register */
|
||||
#define AIC_OISR 0x118 /* Output interrupt status register */
|
||||
#define AIC_MECR 0x120 /* Mask enable command register */
|
||||
#define AIC_MDCR 0x124 /* Mask disable command register */
|
||||
#define AIC_SSCR 0x128 /* Source set command register */
|
||||
#define AIC_SCCR 0x12c /* Source clear command register */
|
||||
#define AIC_EOSCR 0x130 /* End of service command register */
|
||||
|
||||
#define AIC_SCR_SRCTYPE_LOW_LEVEL (0 << 6)
|
||||
#define AIC_SCR_SRCTYPE_HIGH_LEVEL (1 << 6)
|
||||
#define AIC_SCR_SRCTYPE_NEG_EDGE (2 << 6)
|
||||
#define AIC_SCR_SRCTYPE_POS_EDGE (3 << 6)
|
||||
#define AIC_SCR_PRIORITY(x) (x)
|
||||
#define AIC_SCR_PRIORITY_MASK 0x7
|
||||
|
||||
#define AIC_NUM_IRQS 32
|
||||
|
||||
struct wpcm450_aic {
|
||||
void __iomem *regs;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
static struct wpcm450_aic *aic;
|
||||
|
||||
static void wpcm450_aic_init_hw(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Disable (mask) all interrupts */
|
||||
writel(0xffffffff, aic->regs + AIC_MDCR);
|
||||
|
||||
/*
|
||||
* Make sure the interrupt controller is ready to serve new interrupts.
|
||||
* Reading from IPER indicates that the nIRQ signal may be deasserted,
|
||||
* and writing to EOSCR indicates that interrupt handling has finished.
|
||||
*/
|
||||
readl(aic->regs + AIC_IPER);
|
||||
writel(0, aic->regs + AIC_EOSCR);
|
||||
|
||||
/* Initialize trigger mode and priority of each interrupt source */
|
||||
for (i = 0; i < AIC_NUM_IRQS; i++)
|
||||
writel(AIC_SCR_SRCTYPE_HIGH_LEVEL | AIC_SCR_PRIORITY(7),
|
||||
aic->regs + AIC_SCR(i));
|
||||
}
|
||||
|
||||
static void __exception_irq_entry wpcm450_aic_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
int hwirq;
|
||||
|
||||
/* Determine the interrupt source */
|
||||
/* Read IPER to signal that nIRQ can be de-asserted */
|
||||
hwirq = readl(aic->regs + AIC_IPER) / 4;
|
||||
|
||||
handle_domain_irq(aic->domain, hwirq, regs);
|
||||
}
|
||||
|
||||
static void wpcm450_aic_eoi(struct irq_data *d)
|
||||
{
|
||||
/* Signal end-of-service */
|
||||
writel(0, aic->regs + AIC_EOSCR);
|
||||
}
|
||||
|
||||
static void wpcm450_aic_mask(struct irq_data *d)
|
||||
{
|
||||
unsigned int mask = BIT(d->hwirq);
|
||||
|
||||
/* Disable (mask) the interrupt */
|
||||
writel(mask, aic->regs + AIC_MDCR);
|
||||
}
|
||||
|
||||
static void wpcm450_aic_unmask(struct irq_data *d)
|
||||
{
|
||||
unsigned int mask = BIT(d->hwirq);
|
||||
|
||||
/* Enable (unmask) the interrupt */
|
||||
writel(mask, aic->regs + AIC_MECR);
|
||||
}
|
||||
|
||||
static int wpcm450_aic_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
{
|
||||
/*
|
||||
* The hardware supports high/low level, as well as rising/falling edge
|
||||
* modes, and the DT binding accommodates for that, but as long as
|
||||
* other modes than high level mode are not used and can't be tested,
|
||||
* they are rejected in this driver.
|
||||
*/
|
||||
if ((flow_type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_HIGH)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip wpcm450_aic_chip = {
|
||||
.name = "wpcm450-aic",
|
||||
.irq_eoi = wpcm450_aic_eoi,
|
||||
.irq_mask = wpcm450_aic_mask,
|
||||
.irq_unmask = wpcm450_aic_unmask,
|
||||
.irq_set_type = wpcm450_aic_set_type,
|
||||
};
|
||||
|
||||
static int wpcm450_aic_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
if (hwirq >= AIC_NUM_IRQS)
|
||||
return -EPERM;
|
||||
|
||||
irq_set_chip_and_handler(irq, &wpcm450_aic_chip, handle_fasteoi_irq);
|
||||
irq_set_chip_data(irq, aic);
|
||||
irq_set_probe(irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops wpcm450_aic_ops = {
|
||||
.map = wpcm450_aic_map,
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
};
|
||||
|
||||
static int __init wpcm450_aic_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
if (parent)
|
||||
return -EINVAL;
|
||||
|
||||
aic = kzalloc(sizeof(*aic), GFP_KERNEL);
|
||||
if (!aic)
|
||||
return -ENOMEM;
|
||||
|
||||
aic->regs = of_iomap(node, 0);
|
||||
if (!aic->regs) {
|
||||
pr_err("Failed to map WPCM450 AIC registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wpcm450_aic_init_hw();
|
||||
|
||||
set_handle_irq(wpcm450_aic_handle_irq);
|
||||
|
||||
aic->domain = irq_domain_add_linear(node, AIC_NUM_IRQS, &wpcm450_aic_ops, aic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(wpcm450_aic, "nuvoton,wpcm450-aic", wpcm450_aic_of_init);
|
@ -179,6 +179,21 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool __init intc_map(struct irq_domain *domain, int irq)
|
||||
{
|
||||
if (!irq_to_desc(irq) && irq_alloc_desc_at(irq, NUMA_NO_NODE) != irq) {
|
||||
pr_err("uname to allocate IRQ %d\n", irq);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (irq_domain_associate(domain, irq, irq)) {
|
||||
pr_err("domain association failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int __init register_intc_controller(struct intc_desc *desc)
|
||||
{
|
||||
unsigned int i, k, smp;
|
||||
@ -311,24 +326,12 @@ int __init register_intc_controller(struct intc_desc *desc)
|
||||
for (i = 0; i < hw->nr_vectors; i++) {
|
||||
struct intc_vect *vect = hw->vectors + i;
|
||||
unsigned int irq = evt2irq(vect->vect);
|
||||
int res;
|
||||
|
||||
if (!vect->enum_id)
|
||||
continue;
|
||||
|
||||
res = irq_create_identity_mapping(d->domain, irq);
|
||||
if (unlikely(res)) {
|
||||
if (res == -EEXIST) {
|
||||
res = irq_domain_associate(d->domain, irq, irq);
|
||||
if (unlikely(res)) {
|
||||
pr_err("domain association failure\n");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
pr_err("can't identity map IRQ %d\n", irq);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!intc_map(d->domain, irq))
|
||||
continue;
|
||||
|
||||
intc_irq_xlate_set(irq, vect->enum_id, d);
|
||||
intc_register_irq(desc, d, vect->enum_id, irq);
|
||||
@ -345,22 +348,8 @@ int __init register_intc_controller(struct intc_desc *desc)
|
||||
* IRQ support, each vector still needs to have
|
||||
* its own backing irq_desc.
|
||||
*/
|
||||
res = irq_create_identity_mapping(d->domain, irq2);
|
||||
if (unlikely(res)) {
|
||||
if (res == -EEXIST) {
|
||||
res = irq_domain_associate(d->domain,
|
||||
irq2, irq2);
|
||||
if (unlikely(res)) {
|
||||
pr_err("domain association "
|
||||
"failure\n");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
pr_err("can't identity map IRQ %d\n",
|
||||
irq);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!intc_map(d->domain, irq2))
|
||||
continue;
|
||||
|
||||
vect2->enum_id = 0;
|
||||
|
||||
|
@ -145,4 +145,6 @@ int its_init_v4(struct irq_domain *domain,
|
||||
const struct irq_domain_ops *vpe_ops,
|
||||
const struct irq_domain_ops *sgi_ops);
|
||||
|
||||
bool gic_cpuif_has_vsgi(void);
|
||||
|
||||
#endif
|
||||
|
@ -150,7 +150,6 @@ struct irq_domain_chip_generic;
|
||||
* setting up one or more generic chips for interrupt controllers
|
||||
* drivers using the generic chip library which uses this pointer.
|
||||
* @parent: Pointer to parent irq_domain to support hierarchy irq_domains
|
||||
* @debugfs_file: dentry for the domain debugfs file
|
||||
*
|
||||
* Revmap data, used internally by irq_domain
|
||||
* @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
|
||||
@ -174,9 +173,6 @@ struct irq_domain {
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
struct irq_domain *parent;
|
||||
#endif
|
||||
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
|
||||
struct dentry *debugfs_file;
|
||||
#endif
|
||||
|
||||
/* reverse map data. The linear map gets appended to the irq_domain */
|
||||
irq_hw_number_t hwirq_max;
|
||||
@ -419,15 +415,6 @@ static inline unsigned int irq_linear_revmap(struct irq_domain *domain,
|
||||
extern unsigned int irq_find_mapping(struct irq_domain *host,
|
||||
irq_hw_number_t hwirq);
|
||||
extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
|
||||
extern int irq_create_strict_mappings(struct irq_domain *domain,
|
||||
unsigned int irq_base,
|
||||
irq_hw_number_t hwirq_base, int count);
|
||||
|
||||
static inline int irq_create_identity_mapping(struct irq_domain *host,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
return irq_create_strict_mappings(host, hwirq, hwirq, 1);
|
||||
}
|
||||
|
||||
extern const struct irq_domain_ops irq_domain_simple_ops;
|
||||
|
||||
|
@ -703,41 +703,6 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_create_mapping_affinity);
|
||||
|
||||
/**
|
||||
* irq_create_strict_mappings() - Map a range of hw irqs to fixed linux irqs
|
||||
* @domain: domain owning the interrupt range
|
||||
* @irq_base: beginning of linux IRQ range
|
||||
* @hwirq_base: beginning of hardware IRQ range
|
||||
* @count: Number of interrupts to map
|
||||
*
|
||||
* This routine is used for allocating and mapping a range of hardware
|
||||
* irqs to linux irqs where the linux irq numbers are at pre-defined
|
||||
* locations. For use by controllers that already have static mappings
|
||||
* to insert in to the domain.
|
||||
*
|
||||
* Non-linear users can use irq_create_identity_mapping() for IRQ-at-a-time
|
||||
* domain insertion.
|
||||
*
|
||||
* 0 is returned upon success, while any failure to establish a static
|
||||
* mapping is treated as an error.
|
||||
*/
|
||||
int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
|
||||
irq_hw_number_t hwirq_base, int count)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
int ret;
|
||||
|
||||
of_node = irq_domain_get_of_node(domain);
|
||||
ret = irq_alloc_descs(irq_base, irq_base, count,
|
||||
of_node_to_nid(of_node));
|
||||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
irq_domain_associate_many(domain, irq_base, hwirq_base, count);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
|
||||
|
||||
static int irq_domain_translate(struct irq_domain *d,
|
||||
struct irq_fwspec *fwspec,
|
||||
irq_hw_number_t *hwirq, unsigned int *type)
|
||||
@ -1694,12 +1659,10 @@ void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs)
|
||||
|
||||
/**
|
||||
* irq_domain_alloc_irqs_parent - Allocate interrupts from parent domain
|
||||
* @domain: Domain below which interrupts must be allocated
|
||||
* @irq_base: Base IRQ number
|
||||
* @nr_irqs: Number of IRQs to allocate
|
||||
* @arg: Allocation data (arch/domain specific)
|
||||
*
|
||||
* Check whether the domain has been setup recursive. If not allocate
|
||||
* through the parent domain.
|
||||
*/
|
||||
int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
|
||||
unsigned int irq_base, unsigned int nr_irqs,
|
||||
@ -1715,11 +1678,9 @@ EXPORT_SYMBOL_GPL(irq_domain_alloc_irqs_parent);
|
||||
|
||||
/**
|
||||
* irq_domain_free_irqs_parent - Free interrupts from parent domain
|
||||
* @domain: Domain below which interrupts must be freed
|
||||
* @irq_base: Base IRQ number
|
||||
* @nr_irqs: Number of IRQs to free
|
||||
*
|
||||
* Check whether the domain has been setup recursive. If not free
|
||||
* through the parent domain.
|
||||
*/
|
||||
void irq_domain_free_irqs_parent(struct irq_domain *domain,
|
||||
unsigned int irq_base, unsigned int nr_irqs)
|
||||
@ -1898,16 +1859,15 @@ DEFINE_SHOW_ATTRIBUTE(irq_domain_debug);
|
||||
|
||||
static void debugfs_add_domain_dir(struct irq_domain *d)
|
||||
{
|
||||
if (!d->name || !domain_dir || d->debugfs_file)
|
||||
if (!d->name || !domain_dir)
|
||||
return;
|
||||
d->debugfs_file = debugfs_create_file(d->name, 0444, domain_dir, d,
|
||||
&irq_domain_debug_fops);
|
||||
debugfs_create_file(d->name, 0444, domain_dir, d,
|
||||
&irq_domain_debug_fops);
|
||||
}
|
||||
|
||||
static void debugfs_remove_domain_dir(struct irq_domain *d)
|
||||
{
|
||||
debugfs_remove(d->debugfs_file);
|
||||
d->debugfs_file = NULL;
|
||||
debugfs_remove(debugfs_lookup(d->name, domain_dir));
|
||||
}
|
||||
|
||||
void __init irq_domain_debugfs_init(struct dentry *root)
|
||||
|
Loading…
Reference in New Issue
Block a user