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
This commit is contained in:
Коммит
7bcd342594
|
@ -265,37 +265,5 @@ support other architectures, such as ARM, ARM64 etc.
|
|||
|
||||
=== Debugging ===
|
||||
|
||||
If you switch on CONFIG_IRQ_DOMAIN_DEBUG (which depends on
|
||||
CONFIG_IRQ_DOMAIN and CONFIG_DEBUG_FS), you will find a new file in
|
||||
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.
|
||||
Most of the internals of the IRQ subsystem are exposed in debugfs by
|
||||
turning CONFIG_GENERIC_IRQ_DEBUGFS on.
|
||||
|
|
|
@ -12,7 +12,7 @@ Required properties:
|
|||
registers
|
||||
- interrupt-controller: Identifies the node as an interrupt controller
|
||||
- #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
|
||||
Interrupt Controllers bindings used by client devices.
|
||||
|
@ -32,6 +32,6 @@ local_intc: local_intc {
|
|||
compatible = "brcm,bcm2836-l1-intc";
|
||||
reg = <0x40000000 0x100>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
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
|
|||
F: drivers/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
|
||||
M: Miodrag Dinic <miodrag.dinic@mips.com>
|
||||
S: Supported
|
||||
|
|
|
@ -13,24 +13,24 @@
|
|||
compatible = "brcm,bcm2836-l1-intc";
|
||||
reg = <0x40000000 0x100>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
};
|
||||
|
||||
arm-pmu {
|
||||
compatible = "arm,cortex-a7-pmu";
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <9>;
|
||||
interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
timer {
|
||||
compatible = "arm,armv7-timer";
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <0>, // PHYS_SECURE_PPI
|
||||
<1>, // PHYS_NONSECURE_PPI
|
||||
<3>, // VIRT_PPI
|
||||
<2>; // HYP_PPI
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI
|
||||
<1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI
|
||||
<3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI
|
||||
<2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI
|
||||
always-on;
|
||||
};
|
||||
|
||||
|
@ -76,7 +76,7 @@
|
|||
compatible = "brcm,bcm2836-armctrl-ic";
|
||||
reg = <0x7e00b200 0x200>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <8>;
|
||||
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
&cpu_thermal {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
compatible = "brcm,bcm2836-l1-intc";
|
||||
reg = <0x40000000 0x100>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
};
|
||||
};
|
||||
|
@ -20,10 +20,10 @@
|
|||
timer {
|
||||
compatible = "arm,armv7-timer";
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <0>, // PHYS_SECURE_PPI
|
||||
<1>, // PHYS_NONSECURE_PPI
|
||||
<3>, // VIRT_PPI
|
||||
<2>; // HYP_PPI
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, // PHYS_SECURE_PPI
|
||||
<1 IRQ_TYPE_LEVEL_HIGH>, // PHYS_NONSECURE_PPI
|
||||
<3 IRQ_TYPE_LEVEL_HIGH>, // VIRT_PPI
|
||||
<2 IRQ_TYPE_LEVEL_HIGH>; // HYP_PPI
|
||||
always-on;
|
||||
};
|
||||
|
||||
|
@ -73,7 +73,7 @@
|
|||
compatible = "brcm,bcm2836-armctrl-ic";
|
||||
reg = <0x7e00b200 0x200>;
|
||||
interrupt-parent = <&local_intc>;
|
||||
interrupts = <8>;
|
||||
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
&cpu_thermal {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <dt-bindings/clock/bcm2835.h>
|
||||
#include <dt-bindings/clock/bcm2835-aux.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
|
||||
* spinning.
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_KERNEL_XZ=y
|
||||
# CONFIG_SWAP is not set
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_KERNEL_XZ=y
|
||||
# CONFIG_SWAP is not set
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_CGROUPS=y
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# CONFIG_SWAP is not set
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_IKCONFIG=y
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
|
|
|
@ -71,7 +71,6 @@ CONFIG_IP_ROUTE_MULTIPATH=y
|
|||
CONFIG_IP_ROUTE_VERBOSE=y
|
||||
CONFIG_IP_SCTP=m
|
||||
CONFIG_IPV6=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_ISO9660_FS=m
|
||||
CONFIG_JFFS2_FS_DEBUG=1
|
||||
CONFIG_JFFS2_FS=y
|
||||
|
|
|
@ -4,7 +4,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_TASKSTATS=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_PPC64=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_TASKSTATS=y
|
||||
|
|
|
@ -3,7 +3,6 @@ CONFIG_NR_CPUS=2048
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_TASKSTATS=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_USELIB=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_SYSVIPC=y
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_FHANDLE=y
|
||||
CONFIG_IRQ_DOMAIN_DEBUG=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_IRQ_TIME_ACCOUNTING=y
|
||||
|
|
|
@ -343,4 +343,12 @@ config MESON_IRQ_GPIO
|
|||
help
|
||||
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
|
||||
|
|
|
@ -84,3 +84,4 @@ obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
|
|||
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
|
||||
obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.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 = {
|
|||
.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_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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -165,7 +187,8 @@ static int bcm2836_cpu_dying(unsigned int cpu)
|
|||
#endif
|
||||
|
||||
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
|
||||
|
@ -218,19 +241,6 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
|
|||
if (!intc.domain)
|
||||
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();
|
||||
|
||||
set_handle_irq(bcm2836_arm_irqchip_handle_irq);
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
if (!redist_base)
|
||||
return -ENOMEM;
|
||||
|
@ -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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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,
|
|||
|
||||
/* Setup the device */
|
||||
ompic_base = ioremap(res.start, resource_size(&res));
|
||||
if (IS_ERR(ompic_base)) {
|
||||
if (!ompic_base) {
|
||||
pr_err("ompic: unable to map registers");
|
||||
return PTR_ERR(ompic_base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
irq = irq_of_parse_and_map(node, 0);
|
||||
|
|
|
@ -13,10 +13,13 @@
|
|||
* busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed
|
||||
*/
|
||||
|
||||
#define IRQ_WORK_PENDING 1UL
|
||||
#define IRQ_WORK_BUSY 2UL
|
||||
#define IRQ_WORK_FLAGS 3UL
|
||||
#define IRQ_WORK_LAZY 4UL /* Doesn't want IPI, wait for tick */
|
||||
#define IRQ_WORK_PENDING BIT(0)
|
||||
#define IRQ_WORK_BUSY BIT(1)
|
||||
|
||||
/* 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 {
|
||||
unsigned long flags;
|
||||
|
|
|
@ -103,16 +103,6 @@ config GENERIC_IRQ_MATRIX_ALLOCATOR
|
|||
config GENERIC_IRQ_RESERVATION_MODE
|
||||
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
|
||||
config IRQ_FORCED_THREADING
|
||||
bool
|
||||
|
|
|
@ -897,124 +897,6 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
|
|||
}
|
||||
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
|
||||
*
|
||||
|
|
|
@ -36,7 +36,7 @@ static bool irq_work_claim(struct irq_work *work)
|
|||
*/
|
||||
flags = work->flags & ~IRQ_WORK_PENDING;
|
||||
for (;;) {
|
||||
nflags = flags | IRQ_WORK_FLAGS;
|
||||
nflags = flags | IRQ_WORK_CLAIMED;
|
||||
oflags = cmpxchg(&work->flags, flags, nflags);
|
||||
if (oflags == flags)
|
||||
break;
|
||||
|
|
Загрузка…
Ссылка в новой задаче