Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/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()
This commit is contained in:
Linus Torvalds 2015-02-16 15:20:40 -08:00
commit 3c6847eaa3
17 changed files with 296 additions and 72 deletions

View file

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

View file

@ -0,0 +1,120 @@
/*
* Conexant Digicolor SoCs IRQ chip driver
*
* Author: Baruch Siach <baruch@tkos.co.il>
*
* 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);

View file

@ -21,7 +21,7 @@
#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);
@ -29,16 +29,17 @@ void gic_configure_irq(unsigned int irq, unsigned int type,
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;
/*
@ -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,

View file

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

View file

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

View file

@ -188,12 +188,15 @@ 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);
@ -201,11 +204,11 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
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)

View file

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

View file

@ -235,9 +235,9 @@ int gic_get_c0_perfcount_int(void)
GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
}
static unsigned int gic_get_int(void)
static void gic_handle_shared_int(void)
{
unsigned int i;
unsigned int i, intr, virq;
unsigned long *pcpu_mask;
unsigned long pending_reg, intrmask_reg;
DECLARE_BITMAP(pending, GIC_MAX_INTRS);
@ -259,7 +259,16 @@ static unsigned int gic_get_int(void)
bitmap_and(pending, pending, intrmask, gic_shared_intrs);
bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
return find_first_bit(pending, gic_shared_intrs);
intr = find_first_bit(pending, gic_shared_intrs);
while (intr != gic_shared_intrs) {
virq = irq_linear_revmap(gic_irq_domain,
GIC_SHARED_TO_HWIRQ(intr));
do_IRQ(virq);
/* go to next pending bit */
bitmap_clear(pending, intr, 1);
intr = find_first_bit(pending, gic_shared_intrs);
}
}
static void gic_mask_irq(struct irq_data *d)
@ -386,16 +395,26 @@ static struct irq_chip gic_edge_irq_controller = {
#endif
};
static unsigned int gic_get_local_int(void)
static void gic_handle_local_int(void)
{
unsigned long pending, masked;
unsigned int intr, virq;
pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK));
bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
intr = find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
while (intr != GIC_NUM_LOCAL_INTRS) {
virq = irq_linear_revmap(gic_irq_domain,
GIC_LOCAL_TO_HWIRQ(intr));
do_IRQ(virq);
/* go to next pending bit */
bitmap_clear(&pending, intr, 1);
intr = find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
}
}
static void gic_mask_local_irq(struct irq_data *d)
@ -454,19 +473,8 @@ static struct irq_chip gic_all_vpes_local_irq_controller = {
static void __gic_irq_dispatch(void)
{
unsigned int intr, virq;
while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) {
virq = irq_linear_revmap(gic_irq_domain,
GIC_LOCAL_TO_HWIRQ(intr));
do_IRQ(virq);
}
while ((intr = gic_get_int()) != gic_shared_intrs) {
virq = irq_linear_revmap(gic_irq_domain,
GIC_SHARED_TO_HWIRQ(intr));
do_IRQ(virq);
}
gic_handle_local_int();
gic_handle_shared_int();
}
static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc)

View file

@ -23,8 +23,6 @@
#include "irqchip.h"
#define MT6577_SYS_INTPOL_NUM (224)
struct mtk_sysirq_chip_data {
spinlock_t lock;
void __iomem *intpol_base;
@ -124,7 +122,8 @@ static int __init mtk_sysirq_of_init(struct device_node *node,
{
struct irq_domain *domain, *domain_parent;
struct mtk_sysirq_chip_data *chip_data;
int ret = 0;
int ret, size, intpol_num;
struct resource res;
domain_parent = irq_find_host(parent);
if (!domain_parent) {
@ -132,19 +131,24 @@ static int __init mtk_sysirq_of_init(struct device_node *node,
return -EINVAL;
}
ret = of_address_to_resource(node, 0, &res);
if (ret)
return ret;
chip_data = kzalloc(sizeof(*chip_data), GFP_KERNEL);
if (!chip_data)
return -ENOMEM;
chip_data->intpol_base = of_io_request_and_map(node, 0, "intpol");
if (IS_ERR(chip_data->intpol_base)) {
size = resource_size(&res);
intpol_num = size * 8;
chip_data->intpol_base = ioremap(res.start, size);
if (!chip_data->intpol_base) {
pr_err("mtk_sysirq: unable to map sysirq register\n");
ret = PTR_ERR(chip_data->intpol_base);
goto out_free;
}
domain = irq_domain_add_hierarchy(domain_parent, 0,
MT6577_SYS_INTPOL_NUM, node,
domain = irq_domain_add_hierarchy(domain_parent, 0, intpol_num, node,
&sysirq_domain_ops, chip_data);
if (!domain) {
ret = -ENOMEM;

View file

@ -364,14 +364,6 @@ out:
omap_ack_irq(NULL);
}
void __init omap2_init_irq(void)
{
omap_nr_irqs = 96;
omap_nr_pending = 3;
omap_init_irq(OMAP24XX_IC_BASE, NULL);
set_handle_irq(omap_intc_handle_irq);
}
void __init omap3_init_irq(void)
{
omap_nr_irqs = 96;
@ -380,14 +372,6 @@ void __init omap3_init_irq(void)
set_handle_irq(omap_intc_handle_irq);
}
void __init ti81xx_init_irq(void)
{
omap_nr_irqs = 96;
omap_nr_pending = 4;
omap_init_irq(OMAP34XX_IC_BASE, NULL);
set_handle_irq(omap_intc_handle_irq);
}
static int __init intc_of_init(struct device_node *node,
struct device_node *parent)
{
@ -399,7 +383,9 @@ static int __init intc_of_init(struct device_node *node,
if (WARN_ON(!node))
return -ENODEV;
if (of_device_is_compatible(node, "ti,am33xx-intc")) {
if (of_device_is_compatible(node, "ti,dm814-intc") ||
of_device_is_compatible(node, "ti,dm816-intc") ||
of_device_is_compatible(node, "ti,am33xx-intc")) {
omap_nr_irqs = 128;
omap_nr_pending = 4;
}
@ -415,4 +401,6 @@ static int __init intc_of_init(struct device_node *node,
IRQCHIP_DECLARE(omap2_intc, "ti,omap2-intc", intc_of_init);
IRQCHIP_DECLARE(omap3_intc, "ti,omap3-intc", intc_of_init);
IRQCHIP_DECLARE(dm814x_intc, "ti,dm814-intc", intc_of_init);
IRQCHIP_DECLARE(dm816x_intc, "ti,dm816-intc", intc_of_init);
IRQCHIP_DECLARE(am33xx_intc, "ti,am33xx-intc", intc_of_init);

View file

@ -30,6 +30,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_data/irq-renesas-intc-irqpin.h>
#include <linux/pm_runtime.h>
@ -40,7 +41,9 @@
#define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */
#define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */
#define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */
#define INTC_IRQPIN_REG_NR 5
#define INTC_IRQPIN_REG_NR_MANDATORY 5
#define INTC_IRQPIN_REG_IRLM 5 /* ICR0 with IRLM bit (optional) */
#define INTC_IRQPIN_REG_NR 6
/* INTC external IRQ PIN hardware register access:
*
@ -82,6 +85,10 @@ struct intc_irqpin_priv {
u8 shared_irq_mask;
};
struct intc_irqpin_irlm_config {
unsigned int irlm_bit;
};
static unsigned long intc_irqpin_read32(void __iomem *iomem)
{
return ioread32(iomem);
@ -345,10 +352,23 @@ static struct irq_domain_ops intc_irqpin_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
static const struct intc_irqpin_irlm_config intc_irqpin_irlm_r8a7779 = {
.irlm_bit = 23, /* ICR0.IRLM0 */
};
static const struct of_device_id intc_irqpin_dt_ids[] = {
{ .compatible = "renesas,intc-irqpin", },
{ .compatible = "renesas,intc-irqpin-r8a7779",
.data = &intc_irqpin_irlm_r8a7779 },
{},
};
MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
static int intc_irqpin_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct renesas_intc_irqpin_config *pdata = dev->platform_data;
const struct of_device_id *of_id;
struct intc_irqpin_priv *p;
struct intc_irqpin_iomem *i;
struct resource *io[INTC_IRQPIN_REG_NR];
@ -391,10 +411,11 @@ static int intc_irqpin_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
/* get hold of manadatory IOMEM */
/* get hold of register banks */
memset(io, 0, sizeof(io));
for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
if (!io[k]) {
if (!io[k] && k < INTC_IRQPIN_REG_NR_MANDATORY) {
dev_err(dev, "not enough IOMEM resources\n");
ret = -EINVAL;
goto err0;
@ -422,6 +443,10 @@ static int intc_irqpin_probe(struct platform_device *pdev)
for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
i = &p->iomem[k];
/* handle optional registers */
if (!io[k])
continue;
switch (resource_size(io[k])) {
case 1:
i->width = 8;
@ -448,6 +473,19 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
}
/* configure "individual IRQ mode" where needed */
of_id = of_match_device(intc_irqpin_dt_ids, dev);
if (of_id && of_id->data) {
const struct intc_irqpin_irlm_config *irlm_config = of_id->data;
if (io[INTC_IRQPIN_REG_IRLM])
intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM,
irlm_config->irlm_bit,
1, 1);
else
dev_warn(dev, "unable to select IRLM mode\n");
}
/* mask all interrupts using priority */
for (k = 0; k < p->number_of_irqs; k++)
intc_irqpin_mask_unmask_prio(p, k, 1);
@ -550,12 +588,6 @@ static int intc_irqpin_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id intc_irqpin_dt_ids[] = {
{ .compatible = "renesas,intc-irqpin", },
{},
};
MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
static struct platform_driver intc_irqpin_device_driver = {
.probe = intc_irqpin_probe,
.remove = intc_irqpin_remove,