Skip to content

Commit

Permalink
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/tip/tip

Pull irqchip updates from Ingo Molnar:
 "Various irqchip driver updates, plus a genirq core update that allows
  the initial spreading of irqs amonst CPUs without having to do it from
  user-space"

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  genirq: Fix null pointer reference in irq_set_affinity_hint()
  irqchip: gic: Allow interrupt level to be set for PPIs
  irqchip: mips-gic: Handle pending interrupts once in __gic_irq_dispatch()
  irqchip: Conexant CX92755 interrupts controller driver
  irqchip: Devicetree: document Conexant Digicolor irq binding
  irqchip: omap-intc: Remove unused legacy interface for omap2
  irqchip: omap-intc: Fix support for dm814 and dm816
  irqchip: mtk-sysirq: Get irq number from register resource size
  irqchip: renesas-intc-irqpin: r8a7779 IRLM setup support
  genirq: Set initial affinity in irq_set_affinity_hint()
  • Loading branch information
torvalds committed Feb 16, 2015
2 parents 3750771 + 4fe7ffb commit 3c6847e
Show file tree
Hide file tree
Showing 17 changed files with 296 additions and 72 deletions.
8 changes: 6 additions & 2 deletions Documentation/devicetree/bindings/arm/gic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ Main node required properties:
The 3rd cell is the flags, encoded as follows:
bits[3:0] trigger type and level flags.
1 = low-to-high edge triggered
2 = high-to-low edge triggered
2 = high-to-low edge triggered (invalid for SPIs)
4 = active high level-sensitive
8 = active low level-sensitive
8 = active low level-sensitive (invalid for SPIs).
bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of
the 8 possible cpus attached to the GIC. A bit set to '1' indicated
the interrupt is wired to that CPU. Only valid for PPI interrupts.
Also note that the configurability of PPI interrupts is IMPLEMENTATION
DEFINED and as such not guaranteed to be present (most SoC available
in 2014 seem to ignore the setting of this flag and use the hardware
default value).

- reg : Specifies base physical address(s) and size of the GIC registers. The
first region is the GIC distributor register base and size. The 2nd region is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Conexant Digicolor Interrupt Controller

Required properties:

- compatible : should be "cnxt,cx92755-ic"
- reg : Specifies base physical address and size of the interrupt controller
registers (IC) area
- 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.
- syscon: A phandle to the syscon node describing UC registers

Example:

intc: interrupt-controller@f0000040 {
compatible = "cnxt,cx92755-ic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0xf0000040 0x40>;
syscon = <&uc_regs>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ Required properties:
- "renesas,intc-irqpin-r8a7778" (R-Car M1A)
- "renesas,intc-irqpin-r8a7779" (R-Car H1)
- "renesas,intc-irqpin-sh73a0" (SH-Mobile AG5)

- reg: Base address and length of each register bank used by the external
IRQ pins driven by the interrupt controller hardware module. The base
addresses, length and number of required register banks varies with soctype.

- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
interrupts.txt in this directory

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Omap2/3 intc controller

On TI omap2 and 3 the intc interrupt controller can provide
96 or 128 IRQ signals to the ARM host depending on the SoC.

Required Properties:
- compatible: should be one of
"ti,omap2-intc"
"ti,omap3-intc"
"ti,dm814-intc"
"ti,dm816-intc"
"ti,am33xx-intc"

- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode interrupt
source, should be 1 for intc
- interrupts: interrupt reference to primary interrupt controller

Please refer to interrupts.txt in this directory for details of the common
Interrupt Controllers bindings used by client devices.

Example:
intc: interrupt-controller@48200000 {
compatible = "ti,omap3-intc";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x48200000 0x1000>;
};
1 change: 1 addition & 0 deletions drivers/irqchip/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o
obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o
obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o
120 changes: 120 additions & 0 deletions drivers/irqchip/irq-digicolor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Conexant Digicolor SoCs IRQ chip driver
*
* Author: Baruch Siach <[email protected]>
*
* Copyright (C) 2014 Paradox Innovation Ltd.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/

#include <linux/io.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>

#include <asm/exception.h>

#include "irqchip.h"

#define UC_IRQ_CONTROL 0x04

#define IC_FLAG_CLEAR_LO 0x00
#define IC_FLAG_CLEAR_XLO 0x04
#define IC_INT0ENABLE_LO 0x10
#define IC_INT0ENABLE_XLO 0x14
#define IC_INT0STATUS_LO 0x18
#define IC_INT0STATUS_XLO 0x1c

static struct irq_domain *digicolor_irq_domain;

static void __exception_irq_entry digicolor_handle_irq(struct pt_regs *regs)
{
struct irq_domain_chip_generic *dgc = digicolor_irq_domain->gc;
struct irq_chip_generic *gc = dgc->gc[0];
u32 status, hwirq;

do {
status = irq_reg_readl(gc, IC_INT0STATUS_LO);
if (status) {
hwirq = ffs(status) - 1;
} else {
status = irq_reg_readl(gc, IC_INT0STATUS_XLO);
if (status)
hwirq = ffs(status) - 1 + 32;
else
return;
}

handle_domain_irq(digicolor_irq_domain, hwirq, regs);
} while (1);
}

static void digicolor_set_gc(void __iomem *reg_base, unsigned irq_base,
unsigned en_reg, unsigned ack_reg)
{
struct irq_chip_generic *gc;

gc = irq_get_domain_generic_chip(digicolor_irq_domain, irq_base);
gc->reg_base = reg_base;
gc->chip_types[0].regs.ack = ack_reg;
gc->chip_types[0].regs.mask = en_reg;
gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
}

static int __init digicolor_of_init(struct device_node *node,
struct device_node *parent)
{
static void __iomem *reg_base;
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
struct regmap *ucregs;
int ret;

reg_base = of_iomap(node, 0);
if (!reg_base) {
pr_err("%s: unable to map IC registers\n", node->full_name);
return -ENXIO;
}

/* disable all interrupts */
writel(0, reg_base + IC_INT0ENABLE_LO);
writel(0, reg_base + IC_INT0ENABLE_XLO);

ucregs = syscon_regmap_lookup_by_phandle(node, "syscon");
if (IS_ERR(ucregs)) {
pr_err("%s: unable to map UC registers\n", node->full_name);
return PTR_ERR(ucregs);
}
/* channel 1, regular IRQs */
regmap_write(ucregs, UC_IRQ_CONTROL, 1);

digicolor_irq_domain =
irq_domain_add_linear(node, 64, &irq_generic_chip_ops, NULL);
if (!digicolor_irq_domain) {
pr_err("%s: unable to create IRQ domain\n", node->full_name);
return -ENOMEM;
}

ret = irq_alloc_domain_generic_chips(digicolor_irq_domain, 32, 1,
"digicolor_irq", handle_level_irq,
clr, 0, 0);
if (ret) {
pr_err("%s: unable to allocate IRQ gc\n", node->full_name);
return ret;
}

digicolor_set_gc(reg_base, 0, IC_INT0ENABLE_LO, IC_FLAG_CLEAR_LO);
digicolor_set_gc(reg_base, 32, IC_INT0ENABLE_XLO, IC_FLAG_CLEAR_XLO);

set_handle_irq(digicolor_handle_irq);

return 0;
}
IRQCHIP_DECLARE(conexant_digicolor_ic, "cnxt,cx92755-ic", digicolor_of_init);
18 changes: 12 additions & 6 deletions drivers/irqchip/irq-gic-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,25 @@

#include "irq-gic-common.h"

void gic_configure_irq(unsigned int irq, unsigned int type,
int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void))
{
u32 enablemask = 1 << (irq % 32);
u32 enableoff = (irq / 32) * 4;
u32 confmask = 0x2 << ((irq % 16) * 2);
u32 confoff = (irq / 16) * 4;
bool enabled = false;
u32 val;
u32 val, oldval;
int ret = 0;

/*
* Read current configuration register, and insert the config
* for "irq", depending on "type".
*/
val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
if (type == IRQ_TYPE_LEVEL_HIGH)
val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
if (type & IRQ_TYPE_LEVEL_MASK)
val &= ~confmask;
else if (type == IRQ_TYPE_EDGE_RISING)
else if (type & IRQ_TYPE_EDGE_BOTH)
val |= confmask;

/*
Expand All @@ -54,15 +55,20 @@ void gic_configure_irq(unsigned int irq, unsigned int type,

/*
* Write back the new configuration, and possibly re-enable
* the interrupt.
* the interrupt. If we tried to write a new configuration and failed,
* return an error.
*/
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
ret = -EINVAL;

if (enabled)
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);

if (sync_access)
sync_access();

return ret;
}

void __init gic_dist_config(void __iomem *base, int gic_irqs,
Expand Down
2 changes: 1 addition & 1 deletion drivers/irqchip/irq-gic-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include <linux/of.h>
#include <linux/irqdomain.h>

void gic_configure_irq(unsigned int irq, unsigned int type,
int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void));
void gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void));
Expand Down
8 changes: 4 additions & 4 deletions drivers/irqchip/irq-gic-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if (irq < 16)
return -EINVAL;

if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
/* SPIs have restrictions on the supported types */
if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;

if (gic_irq_in_rdist(d)) {
Expand All @@ -249,9 +251,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
rwp_wait = gic_dist_wait_for_rwp;
}

gic_configure_irq(irq, type, base, rwp_wait);

return 0;
return gic_configure_irq(irq, type, base, rwp_wait);
}

static u64 gic_mpidr_to_affinity(u64 mpidr)
Expand Down
9 changes: 6 additions & 3 deletions drivers/irqchip/irq-gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,24 +188,27 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d);
int ret;

/* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16)
return -EINVAL;

if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
/* SPIs have restrictions on the supported types */
if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;

raw_spin_lock(&irq_controller_lock);

if (gic_arch_extn.irq_set_type)
gic_arch_extn.irq_set_type(d, type);

gic_configure_irq(gicirq, type, base, NULL);
ret = gic_configure_irq(gicirq, type, base, NULL);

raw_spin_unlock(&irq_controller_lock);

return 0;
return ret;
}

static int gic_retrigger(struct irq_data *d)
Expand Down
9 changes: 6 additions & 3 deletions drivers/irqchip/irq-hip04.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,24 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = hip04_dist_base(d);
unsigned int irq = hip04_irq(d);
int ret;

/* Interrupt configuration for SGIs can't be changed */
if (irq < 16)
return -EINVAL;

if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
/* SPIs have restrictions on the supported types */
if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;

raw_spin_lock(&irq_controller_lock);

gic_configure_irq(irq, type, base, NULL);
ret = gic_configure_irq(irq, type, base, NULL);

raw_spin_unlock(&irq_controller_lock);

return 0;
return ret;
}

#ifdef CONFIG_SMP
Expand Down
Loading

0 comments on commit 3c6847e

Please sign in to comment.