Commit 7bcd3425 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq updates from Thomas Gleixner:
 "A rather small set of irq updates this time:

   - removal of the old and now obsolete irq domain debugging code

   - the new Goldfish PIC driver

   - the usual pile of small fixes and updates"

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  irqdomain: Kill CONFIG_IRQ_DOMAIN_DEBUG
  irq/work: Improve the flag definitions
  irqchip/gic-v3: Fix the driver probe() fail due to disabled GICC entry
  irqchip/irq-goldfish-pic: Add Goldfish PIC driver
  dt-bindings/goldfish-pic: Add device tree binding for Goldfish PIC driver
  irqchip/ompic: fix return value check in ompic_of_init()
  dt-bindings/bcm283x: Define polarity of per-cpu interrupts
  irqchip/irq-bcm2836: Add support for DT interrupt polarity
  dt-bindings/bcm2836-l1-intc: Add interrupt polarity support
parents d0bd31dc c5baa1be
...@@ -265,37 +265,5 @@ support other architectures, such as ARM, ARM64 etc. ...@@ -265,37 +265,5 @@ support other architectures, such as ARM, ARM64 etc.
=== Debugging === === Debugging ===
If you switch on CONFIG_IRQ_DOMAIN_DEBUG (which depends on Most of the internals of the IRQ subsystem are exposed in debugfs by
CONFIG_IRQ_DOMAIN and CONFIG_DEBUG_FS), you will find a new file in turning CONFIG_GENERIC_IRQ_DEBUGFS on.
your debugfs mount point, called irq_domain_mapping. This file
contains a live snapshot of all the IRQ domains in the system:
name mapped linear-max direct-max devtree-node
pl061 8 8 0 /smb/gpio@e0080000
pl061 8 8 0 /smb/gpio@e1050000
pMSI 0 0 0 /interrupt-controller@e1101000/v2m@e0080000
MSI 37 0 0 /interrupt-controller@e1101000/v2m@e0080000
GICv2m 37 0 0 /interrupt-controller@e1101000/v2m@e0080000
GICv2 448 448 0 /interrupt-controller@e1101000
it also iterates over the interrupts to display their mapping in the
domains, and makes the domain stacking visible:
irq hwirq chip name chip data active type domain
1 0x00019 GICv2 0xffff00000916bfd8 * LINEAR GICv2
2 0x0001d GICv2 0xffff00000916bfd8 LINEAR GICv2
3 0x0001e GICv2 0xffff00000916bfd8 * LINEAR GICv2
4 0x0001b GICv2 0xffff00000916bfd8 * LINEAR GICv2
5 0x0001a GICv2 0xffff00000916bfd8 LINEAR GICv2
[...]
96 0x81808 MSI 0x (null) RADIX MSI
96+ 0x00063 GICv2m 0xffff8003ee116980 RADIX GICv2m
96+ 0x00063 GICv2 0xffff00000916bfd8 LINEAR GICv2
97 0x08800 MSI 0x (null) * RADIX MSI
97+ 0x00064 GICv2m 0xffff8003ee116980 * RADIX GICv2m
97+ 0x00064 GICv2 0xffff00000916bfd8 * LINEAR GICv2
Here, interrupts 1-5 are only using a single domain, while 96 and 97
are build out of a stack of three domain, each level performing a
particular function.
...@@ -12,7 +12,7 @@ Required properties: ...@@ -12,7 +12,7 @@ Required properties:
registers registers
- interrupt-controller: Identifies the node as an interrupt controller - interrupt-controller: Identifies the node as an interrupt controller
- #interrupt-cells: Specifies the number of cells needed to encode an - #interrupt-cells: Specifies the number of cells needed to encode an
interrupt source. The value shall be 1 interrupt source. The value shall be 2
Please refer to interrupts.txt in this directory for details of the common Please refer to interrupts.txt in this directory for details of the common
Interrupt Controllers bindings used by client devices. Interrupt Controllers bindings used by client devices.
...@@ -32,6 +32,6 @@ local_intc: local_intc { ...@@ -32,6 +32,6 @@ local_intc: local_intc {
compatible = "brcm,bcm2836-l1-intc"; compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>; reg = <0x40000000 0x100>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <2>;
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
}; };
Android Goldfish PIC
Android Goldfish programmable interrupt device used by Android
emulator.
Required properties:
- compatible : should contain "google,goldfish-pic"
- reg : <registers mapping>
- interrupts : <interrupt mapping>
Example for mips when used in cascade mode:
cpuintc {
#interrupt-cells = <0x1>;
#address-cells = <0>;
interrupt-controller;
compatible = "mti,cpu-interrupt-controller";
};
interrupt-controller@1f000000 {
compatible = "google,goldfish-pic";
reg = <0x1f000000 0x1000>;
interrupt-controller;
#interrupt-cells = <0x1>;
interrupt-parent = <&cpuintc>;
interrupts = <0x2>;
};
...@@ -875,6 +875,12 @@ S: Supported ...@@ -875,6 +875,12 @@ S: Supported
F: drivers/android/ F: drivers/android/
F: drivers/staging/android/ F: drivers/staging/android/
ANDROID GOLDFISH PIC DRIVER
M: Miodrag Dinic <miodrag.dinic@mips.com>
S: Supported
F: Documentation/devicetree/bindings/interrupt-controller/google,goldfish-pic.txt
F: drivers/irqchip/irq-goldfish-pic.c
ANDROID GOLDFISH RTC DRIVER ANDROID GOLDFISH RTC DRIVER
M: Miodrag Dinic <miodrag.dinic@mips.com> M: Miodrag Dinic <miodrag.dinic@mips.com>
S: Supported S: Supported
......
...@@ -13,24 +13,24 @@ local_intc: local_intc { ...@@ -13,24 +13,24 @@ local_intc: local_intc {
compatible = "brcm,bcm2836-l1-intc"; compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>; reg = <0x40000000 0x100>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <2>;
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
}; };
arm-pmu { arm-pmu {
compatible = "arm,cortex-a7-pmu"; compatible = "arm,cortex-a7-pmu";
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
interrupts = <9>; interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
}; };
}; };
timer { timer {
compatible = "arm,armv7-timer"; compatible = "arm,armv7-timer";
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
interrupts = <0>, // PHYS_SECURE_PPI interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI
<1>, // PHYS_NONSECURE_PPI <1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI
<3>, // VIRT_PPI <3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI
<2>; // HYP_PPI <2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI
always-on; always-on;
}; };
...@@ -76,7 +76,7 @@ &intc { ...@@ -76,7 +76,7 @@ &intc {
compatible = "brcm,bcm2836-armctrl-ic"; compatible = "brcm,bcm2836-armctrl-ic";
reg = <0x7e00b200 0x200>; reg = <0x7e00b200 0x200>;
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
interrupts = <8>; interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
}; };
&cpu_thermal { &cpu_thermal {
......
...@@ -12,7 +12,7 @@ local_intc: local_intc { ...@@ -12,7 +12,7 @@ local_intc: local_intc {
compatible = "brcm,bcm2836-l1-intc"; compatible = "brcm,bcm2836-l1-intc";
reg = <0x40000000 0x100>; reg = <0x40000000 0x100>;
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <2>;
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
}; };
}; };
...@@ -20,10 +20,10 @@ local_intc: local_intc { ...@@ -20,10 +20,10 @@ local_intc: local_intc {
timer { timer {
compatible = "arm,armv7-timer"; compatible = "arm,armv7-timer";
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
interrupts = <0>, // PHYS_SECURE_PPI interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI
<1>, // PHYS_NONSECURE_PPI <1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI
<3>, // VIRT_PPI <3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI
<2>; // HYP_PPI <2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI
always-on; always-on;
}; };
...@@ -73,7 +73,7 @@ &intc { ...@@ -73,7 +73,7 @@ &intc {
compatible = "brcm,bcm2836-armctrl-ic"; compatible = "brcm,bcm2836-armctrl-ic";
reg = <0x7e00b200 0x200>; reg = <0x7e00b200 0x200>;
interrupt-parent = <&local_intc>; interrupt-parent = <&local_intc>;
interrupts = <8>; interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
}; };
&cpu_thermal { &cpu_thermal {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <dt-bindings/clock/bcm2835.h> #include <dt-bindings/clock/bcm2835.h>
#include <dt-bindings/clock/bcm2835-aux.h> #include <dt-bindings/clock/bcm2835-aux.h>
#include <dt-bindings/gpio/gpio.h> #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
/* firmware-provided startup stubs live here, where the secondary CPUs are /* firmware-provided startup stubs live here, where the secondary CPUs are
* spinning. * spinning.
......
CONFIG_KERNEL_XZ=y CONFIG_KERNEL_XZ=y
# CONFIG_SWAP is not set # CONFIG_SWAP is not set
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14 CONFIG_LOG_BUF_SHIFT=14
......
CONFIG_KERNEL_XZ=y CONFIG_KERNEL_XZ=y
# CONFIG_SWAP is not set # CONFIG_SWAP is not set
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14 CONFIG_LOG_BUF_SHIFT=14
......
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_INITRD=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_CGROUPS=y CONFIG_CGROUPS=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14 CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_INITRD=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT=y
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
# CONFIG_SWAP is not set # CONFIG_SWAP is not set
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14 CONFIG_LOG_BUF_SHIFT=14
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y CONFIG_IKCONFIG=y
......
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_INITRD=y
......
...@@ -71,7 +71,6 @@ CONFIG_IP_ROUTE_MULTIPATH=y ...@@ -71,7 +71,6 @@ CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_SCTP=m CONFIG_IP_SCTP=m
CONFIG_IPV6=y CONFIG_IPV6=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_ISO9660_FS=m CONFIG_ISO9660_FS=m
CONFIG_JFFS2_FS_DEBUG=1 CONFIG_JFFS2_FS_DEBUG=1
CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS=y
......
...@@ -4,7 +4,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y ...@@ -4,7 +4,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y CONFIG_AUDIT=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_TASKSTATS=y CONFIG_TASKSTATS=y
......
CONFIG_PPC64=y CONFIG_PPC64=y
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_TASKSTATS=y CONFIG_TASKSTATS=y
......
...@@ -3,7 +3,6 @@ CONFIG_NR_CPUS=2048 ...@@ -3,7 +3,6 @@ CONFIG_NR_CPUS=2048
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y CONFIG_AUDIT=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_TASKSTATS=y CONFIG_TASKSTATS=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_TIME_ACCOUNTING=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_USELIB=y CONFIG_USELIB=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_TIME_ACCOUNTING=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_TIME_ACCOUNTING=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_TIME_ACCOUNTING=y
......
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_FHANDLE=y CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ_IDLE=y CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_IRQ_TIME_ACCOUNTING=y
......
...@@ -343,4 +343,12 @@ config MESON_IRQ_GPIO ...@@ -343,4 +343,12 @@ config MESON_IRQ_GPIO
help help
Support Meson SoC Family GPIO Interrupt Multiplexer Support Meson SoC Family GPIO Interrupt Multiplexer
config GOLDFISH_PIC
bool "Goldfish programmable interrupt controller"
depends on MIPS && (GOLDFISH || COMPILE_TEST)
select IRQ_DOMAIN
help
Say yes here to enable Goldfish interrupt controller driver used
for Goldfish based virtual platforms.
endmenu endmenu
...@@ -84,3 +84,4 @@ obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o ...@@ -84,3 +84,4 @@ obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o
obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o
obj-$(CONFIG_GOLDFISH_PIC) += irq-goldfish-pic.o
...@@ -98,13 +98,35 @@ static struct irq_chip bcm2836_arm_irqchip_gpu = { ...@@ -98,13 +98,35 @@ static struct irq_chip bcm2836_arm_irqchip_gpu = {
.irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq,
}; };
static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip) static int bcm2836_map(struct irq_domain *d, unsigned int irq,
{ irq_hw_number_t hw)
int irq = irq_create_mapping(intc.domain, hwirq); {
struct irq_chip *chip;
switch (hw) {
case LOCAL_IRQ_CNTPSIRQ:
case LOCAL_IRQ_CNTPNSIRQ:
case LOCAL_IRQ_CNTHPIRQ:
case LOCAL_IRQ_CNTVIRQ:
chip = &bcm2836_arm_irqchip_timer;
break;
case LOCAL_IRQ_GPU_FAST:
chip = &bcm2836_arm_irqchip_gpu;
break;
case LOCAL_IRQ_PMU_FAST:
chip = &bcm2836_arm_irqchip_pmu;
break;
default:
pr_warn_once("Unexpected hw irq: %lu\n", hw);
return -EINVAL;
}
irq_set_percpu_devid(irq); irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); irq_domain_set_info(d, irq, hw, chip, d->host_data,
handle_percpu_devid_irq, NULL, NULL);
irq_set_status_flags(irq, IRQ_NOAUTOEN); irq_set_status_flags(irq, IRQ_NOAUTOEN);
return 0;
} }
static void static void
...@@ -165,7 +187,8 @@ static int bcm2836_cpu_dying(unsigned int cpu) ...@@ -165,7 +187,8 @@ static int bcm2836_cpu_dying(unsigned int cpu)
#endif #endif
static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
.xlate = irq_domain_xlate_onecell .xlate = irq_domain_xlate_onetwocell,
.map = bcm2836_map,
}; };
static void static void
...@@ -218,19 +241,6 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, ...@@ -218,19 +241,6 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
if (!intc.domain) if (!intc.domain)
panic("%pOF: unable to create IRQ domain\n", node); panic("%pOF: unable to create IRQ domain\n", node);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPSIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPNSIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTHPIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTVIRQ,
&bcm2836_arm_irqchip_timer);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_GPU_FAST,
&bcm2836_arm_irqchip_gpu);
bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_PMU_FAST,
&bcm2836_arm_irqchip_pmu);
bcm2836_arm_irqchip_smp_init(); bcm2836_arm_irqchip_smp_init();
set_handle_irq(bcm2836_arm_irqchip_handle_irq); set_handle_irq(bcm2836_arm_irqchip_handle_irq);
......
...@@ -1331,6 +1331,10 @@ gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, ...@@ -1331,6 +1331,10 @@ gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header,
u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
void __iomem *redist_base; void __iomem *redist_base;
/* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */
if (!(gicc->flags & ACPI_MADT_ENABLED))
return 0;
redist_base = ioremap(gicc->gicr_base_address, size); redist_base = ioremap(gicc->gicr_base_address, size);
if (!redist_base) if (!redist_base)
return -ENOMEM; return -ENOMEM;
...@@ -1380,6 +1384,13 @@ static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header, ...@@ -1380,6 +1384,13 @@ static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header,
if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
return 0; return 0;
/*
* It's perfectly valid firmware can pass disabled GICC entry, driver
* should not treat as errors, skip the entry instead of probe fail.
*/
if (!(gicc->flags & ACPI_MADT_ENABLED))
return 0;
return -ENODEV; return -ENODEV;
} }
......
/*
* Driver for MIPS Goldfish Programmable Interrupt Controller.
*
* Author: Miodrag Dinic <miodrag.dinic@mips.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#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 GFPIC_NR_IRQS 32
/* 8..39 Cascaded Goldfish PIC interrupts */
#define GFPIC_IRQ_BASE 8
#define GFPIC_REG_IRQ_PENDING 0x04
#define GFPIC_REG_IRQ_DISABLE_ALL 0x08
#define GFPIC_REG_IRQ_DISABLE 0x0c
#define GFPIC_REG_IRQ_ENABLE 0x10
struct goldfish_pic_data {
void __iomem *base;
struct irq_domain *irq_domain;
};
static void goldfish_pic_cascade(struct irq_desc *desc)
{
struct goldfish_pic_data *gfpic = 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 = readl(gfpic->base + GFPIC_REG_IRQ_PENDING);
while (pending) {
hwirq = __fls(pending);
virq = irq_linear_revmap(gfpic->irq_domain, hwirq);
generic_handle_irq(virq);
pending &= ~(1 << hwirq);
}
chained_irq_exit(host_chip, desc);
}
static const struct irq_domain_ops goldfish_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
static int __init goldfish_pic_of_init(struct device_node *of_node,
struct device_node *parent)
{
struct goldfish_pic_data *gfpic;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
unsigned int parent_irq;
int ret = 0;
gfpic = kzalloc(sizeof(*gfpic), GFP_KERNEL);
if (!gfpic) {
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;
}
gfpic->base = of_iomap(of_node, 0);
if (!gfpic->base) {
pr_err("Failed to map base address!\n");
ret = -ENOMEM;
goto out_unmap_irq;
}
/* Mask interrupts. */
writel(1, gfpic->base + GFPIC_REG_IRQ_DISABLE_ALL);
gc = irq_alloc_generic_chip("GFPIC", 1, GFPIC_IRQ_BASE, gfpic->base,
handle_level_irq);
if (!gc) {
pr_err("Failed to allocate chip structures!\n");
ret = -ENOMEM;
goto out_iounmap;
}
ct = gc->chip_types;
ct->regs.enable = GFPIC_REG_IRQ_ENABLE;
ct->regs.disable = GFPIC_REG_IRQ_DISABLE;
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
ct->chip.irq_mask = irq_gc_mask_disable_reg;
irq_setup_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS), 0,
IRQ_NOPROBE | IRQ_LEVEL, 0);
gfpic->irq_domain = irq_domain_add_legacy(of_node, GFPIC_NR_IRQS,
GFPIC_IRQ_BASE, 0,
&goldfish_irq_domain_ops,
NULL);
if (!gfpic->irq_domain) {
pr_err("Failed to add irqdomain!\n");
ret = -ENOMEM;
goto out_destroy_generic_chip;
}
irq_set_chained_handler_and_data(parent_irq,
goldfish_pic_cascade, gfpic);
pr_info("Successfully registered.\n");
return 0;
out_destroy_generic_chip:
irq_destroy_generic_chip(gc, IRQ_MSK(GFPIC_NR_IRQS),
IRQ_NOPROBE | IRQ_LEVEL, 0);
out_iounmap:
iounmap(gfpic->base);
out_unmap_irq:
irq_dispose_mapping(parent_irq);
out_free:
kfree(gfpic);
out_err:
pr_err("Failed to initialize! (errno = %d)\n", ret);
return ret;
}
IRQCHIP_DECLARE(google_gf_pic, "google,goldfish-pic", goldfish_pic_of_init);
...@@ -171,9 +171,9 @@ static int __init ompic_of_init(struct device_node *node, ...@@ -171,9 +171,9 @@ static int __init ompic_of_init(struct device_node *node,
/* Setup the device */ /* Setup the device */
ompic_base = ioremap(res.start, resource_size(&res)); ompic_base = ioremap(res.start, resource_size(&res));
if (IS_ERR(ompic_base)) { if (!ompic_base) {
pr_err("ompic: unable to map registers"); pr_err("ompic: unable to map registers");
return PTR_ERR(ompic_base); return -ENOMEM;
} }
irq = irq_of_parse_and_map(node, 0); irq = irq_of_parse_and_map(node, 0);
......
...@@ -13,10 +13,13 @@ ...@@ -13,10 +13,13 @@
* busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed * busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed
*/ */
#define IRQ_WORK_PENDING 1UL #define IRQ_WORK_PENDING BIT(0)
#define IRQ_WORK_BUSY 2UL #define IRQ_WORK_BUSY BIT(1)
#define IRQ_WORK_FLAGS 3UL
#define IRQ_WORK_LAZY 4UL /* Doesn't want IPI, wait for tick */ /* Doesn't want IPI, wait for tick: */
#define IRQ_WORK_LAZY BIT(2)
#define IRQ_WORK_CLAIMED (IRQ_WORK_PENDING | IRQ_WORK_BUSY)
struct irq_work { struct irq_work {
unsigned long flags; unsigned long flags;
......
...@@ -103,16 +103,6 @@ config GENERIC_IRQ_MATRIX_ALLOCATOR ...@@ -103,16 +103,6 @@ config GENERIC_IRQ_MATRIX_ALLOCATOR
config GENERIC_IRQ_RESERVATION_MODE config GENERIC_IRQ_RESERVATION_MODE
bool bool
config IRQ_DOMAIN_DEBUG
bool "Expose hardware/virtual IRQ mapping via debugfs"
depends on IRQ_DOMAIN && DEBUG_FS
help
This option will show the mapping relationship between hardware irq
numbers and Linux irq numbers. The mapping is exposed via debugfs
in the file "irq_domain_mapping".
If you don't know what this means you don't need it.
# Support forced irq threading # Support forced irq threading
config IRQ_FORCED_THREADING config IRQ_FORCED_THREADING
bool bool
......
...@@ -897,124 +897,6 @@ unsigned int irq_find_mapping(struct irq_domain *domain, ...@@ -897,124 +897,6 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
} }
EXPORT_SYMBOL_GPL(irq_find_mapping); EXPORT_SYMBOL_GPL(irq_find_mapping);
#ifdef CONFIG_IRQ_DOMAIN_DEBUG
static void virq_debug_show_one(struct seq_file *m, struct irq_desc *desc)
{
struct irq_domain *domain;
struct irq_data *data;
domain = desc->irq_data.domain;
data = &desc->irq_data;
while (domain) {
unsigned int irq = data->irq;
unsigned long hwirq = data->hwirq;
struct irq_chip *chip;
bool direct;
if (data == &desc->irq_data)
seq_printf(m, "%5d ", irq);
else
seq_printf(m, "%5d+ ", irq);
seq_printf(m, "0x%05lx ", hwirq);
chip = irq_data_get_irq_chip(data);
seq_printf(m, "%-15s ", (chip && chip->name) ? chip->name : "none");
seq_printf(m, "0x%p ", irq_data_get_irq_chip_data(data));
seq_printf(m, " %c ", (desc->action && desc->action->handler) ? '*' : ' ');
direct = (irq == hwirq) && (irq < domain->revmap_direct_max_irq);
seq_printf(m, "%6s%-8s ",
(hwirq < domain->revmap_size) ? "LINEAR" : "RADIX",
direct ? "(DIRECT)" : "");
seq_printf(m, "%s\n", domain->name);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
domain = domain->parent;
data = data->parent_data;
#else
domain = NULL;
#endif
}
}
static int virq_debug_show(struct seq_file *m, void *private)
{
unsigned long flags;
struct irq_desc *desc;
struct irq_domain *domain;
struct radix_tree_iter iter;
void __rcu **slot;
int i;
seq_printf(m, " %-16s %-6s %-10s %-10s %s\n",
"name", "mapped", "linear-max", "direct-max", "devtree-node");
mutex_lock(&irq_domain_mutex);
list_for_each_entry(domain, &irq_domain_list, link) {
struct device_node *of_node;
const char *name;
int count = 0;
of_node = irq_domain_get_of_node(domain);
if (of_node)
name = of_node_full_name(of_node);
else if (is_fwnode_irqchip(domain->fwnode))
name = container_of(domain->fwnode, struct irqchip_fwid,
fwnode)->name;
else
name = "";
radix_tree_for_each_slot(slot, &domain->revmap_tree, &iter, 0)
count++;
seq_printf(m, "%c%-16s %6u %10u %10u %s\n",
domain == irq_default_domain ? '*' : ' ', domain->name,
domain->revmap_size + count, domain->revmap_size,
domain->revmap_direct_max_irq,
name);
}
mutex_unlock(&irq_domain_mutex);
seq_printf(m, "%-5s %-7s %-15s %-*s %6s %-14s %s\n", "irq", "hwirq",
"chip name", (int)(2 * sizeof(void *) + 2), "chip data",
"active", "type", "domain");
for (i = 1; i < nr_irqs; i++) {
desc = irq_to_desc(i);
if (!desc)
continue;
raw_spin_lock_irqsave(&desc->lock, flags);
virq_debug_show_one(m, desc);
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
return 0;
}
static int virq_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, virq_debug_show, inode->i_private);
}
static const struct file_operations virq_debug_fops = {
.open = virq_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init irq_debugfs_init(void)
{
if (debugfs_create_file("irq_domain_mapping", S_IRUGO, NULL,
NULL, &virq_debug_fops) == NULL)
return -ENOMEM;
return 0;
}
__initcall(irq_debugfs_init);
#endif /* CONFIG_IRQ_DOMAIN_DEBUG */
/** /**
* irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings
* *
......
...@@ -36,7 +36,7 @@ static bool irq_work_claim(struct irq_work *work) ...@@ -36,7 +36,7 @@ static bool irq_work_claim(struct irq_work *work)
*/ */
flags = work->flags & ~IRQ_WORK_PENDING; flags = work->flags & ~IRQ_WORK_PENDING;
for (;;) { for (;;) {
nflags = flags | IRQ_WORK_FLAGS; nflags = flags | IRQ_WORK_CLAIMED;
oflags = cmpxchg(&work->flags, flags, nflags); oflags = cmpxchg(&work->flags, flags, nflags);
if (oflags == flags) if (oflags == flags)
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment