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

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

View File

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

View File

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

View File

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

View File

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

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_ARCH_SYNQUACER) += irq-sni-exiu.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,
};
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);

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

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 */
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);