irqchip updates for 4.16

- Fix a GICv3 issue when parsing ACPI entries for disabled CPUs
 - Driver for the MIPS Goldfish virtual platform
 - Small fixlet for the ompic driver
 - Interrupt polatiry support for the Raspberry Pi irqchip
 -----BEGIN PGP SIGNATURE-----
 
 iQJJBAABCAAzFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAlpWYKkVHG1hcmMuenlu
 Z2llckBhcm0uY29tAAoJECPQ0LrRPXpDJ+MQAKIoE5YA5AydC64kAyQyuKcPb5S4
 N/9R/9DoPDbYLc9SY+1I5ygHGzorq7zx/PWJmamNMjknwk0xhfuBaS5smE/m6H+1
 dCmgTM3fknEMd5HfLIwpAp/L1Pmq9KYqMtxounSabduWnVMnIqc+7OGAj5fZE7B1
 IPTh8xQQ4HPGR3MBYa/754OIBe8Uprb2KGrZugU2Pz8WPAd9NDdKxM84jCwQ9r58
 4TFesdC4iC1J83Qr1JmxiBdGOnfhi3cq7wfmRLnTmBeRlhXqYHuzRxPQmjbKtcWk
 yzFj3OhSLB2KoV7x4nXaaIcKrwETJCj+GThlK8/ZRZ7lu0irBnmBNomFm4RwwRV4
 MkqItMqvNAwd+enq0LMAxBScUt/3EEYUJxV6xA6RBfluKPlZMlcyfGi+pS72fNho
 0SiKSzokaiTt/XLBfT1s0NI1ASkdPD5Xqo7yAzxDN4O8SzLY71bkFLrQB3ErL/gr
 50FYOsRv24e9a6NrSmtw/7z1Os6mY6QEB6lcSi7A0/+MmudU6Kk0mTk5fRf92+rl
 vqcB7bkkZrMSSsFPJkrBqoPZ+O9R6yqZudt29+n2G9BNWMea/oOCWnz6oYZh0HvX
 DdE3YQUQBJj2ZGc0CG8XlWY94sJLsS8n99rLxXDkAJ7aQU0uT4g8hbxJG0nDXJfu
 d7J2FO7LTtaW4JKo
 =QFqN
 -----END PGP SIGNATURE-----

Merge tag 'irqchip-4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core

Pull irqchip updates for 4.16 from Marc Zyngier

- Fix a GICv3 issue when parsing ACPI entries for disabled CPUs
- Driver for the MIPS Goldfish virtual platform
- Small fixlet for the ompic driver
- Interrupt polarity support for the Raspberry Pi irqchip
This commit is contained in:
Thomas Gleixner 2018-01-10 21:04:21 +01:00
commit 80023aea83
12 changed files with 240 additions and 34 deletions

View File

@ -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 {
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>;
}; };

View File

@ -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>;
};

View File

@ -867,6 +867,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

View File

@ -13,24 +13,24 @@
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 @@
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 {

View File

@ -12,7 +12,7 @@
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 @@
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 @@
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 {

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)
#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,
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);

View File

@ -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,
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;
} }

View File

@ -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);

View File

@ -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);