Skip to content

Commit

Permalink
Merge tag 'irqchip-for-4.7' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/maz/arm-platforms into irq/core

Pull irqchip updates for Linux 4.7 from Marc Zyngier

- Layerscape SCFG MSI controller support
- LPC32xx interrupt controller support
- RPi irqchip support on arm64
- GICv2 cleanup
- GICv2 and GICv3 bug fixes
  • Loading branch information
Thomas Gleixner committed May 11, 2016
2 parents 9d9b7ee + a1dcbd1 commit 0097852
Show file tree
Hide file tree
Showing 18 changed files with 826 additions and 136 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
* Freescale Layerscape SCFG PCIe MSI controller

Required properties:

- compatible: should be "fsl,<soc-name>-msi" to identify
Layerscape PCIe MSI controller block such as:
"fsl,1s1021a-msi"
"fsl,1s1043a-msi"
- msi-controller: indicates that this is a PCIe MSI controller node
- reg: physical base address of the controller and length of memory mapped.
- interrupts: an interrupt to the parent interrupt controller.

Optional properties:
- interrupt-parent: the phandle to the parent interrupt controller.

This interrupt controller hardware is a second level interrupt controller that
is hooked to a parent interrupt controller: e.g: ARM GIC for ARM-based
platforms. If interrupt-parent is not provided, the default parent interrupt
controller will be used.
Each PCIe node needs to have property msi-parent that points to
MSI controller node

Examples:

msi1: msi-controller@1571000 {
compatible = "fsl,1s1043a-msi";
reg = <0x0 0x1571000 0x0 0x8>,
msi-controller;
interrupts = <0 116 0x4>;
};
2 changes: 2 additions & 0 deletions arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ config ARCH_LPC32XX
select COMMON_CLK
select CPU_ARM926T
select GENERIC_CLOCKEVENTS
select MULTI_IRQ_HANDLER
select SPARSE_IRQ
select USE_OF
help
Support for the NXP LPC32XX family of processors
Expand Down
1 change: 0 additions & 1 deletion arch/arm/mach-lpc32xx/phy3250.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ static const char *const lpc32xx_dt_compat[] __initconst = {
DT_MACHINE_START(LPC32XX_DT, "LPC32XX SoC (Flattened Device Tree)")
.atag_offset = 0x100,
.map_io = lpc32xx_map_io,
.init_irq = lpc32xx_init_irq,
.init_machine = lpc3250_machine_init,
.dt_compat = lpc32xx_dt_compat,
MACHINE_END
5 changes: 5 additions & 0 deletions drivers/irqchip/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -246,5 +246,10 @@ config MVEBU_ODMI
bool
select GENERIC_MSI_IRQ_DOMAIN

config LS_SCFG_MSI
def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE
depends on PCI && PCI_MSI
select PCI_MSI_IRQ_DOMAIN

config PARTITION_PERCPU
bool
2 changes: 2 additions & 0 deletions drivers/irqchip/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o
obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o
obj-$(CONFIG_ARCH_LPC32XX) += irq-lpc32xx.o
obj-$(CONFIG_ARCH_MMP) += irq-mmp.o
obj-$(CONFIG_IRQ_MXS) += irq-mxs.o
obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o
Expand Down Expand Up @@ -66,3 +67,4 @@ obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o
obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o
obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o
obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
10 changes: 7 additions & 3 deletions drivers/irqchip/irq-bcm2836.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask,
* Ensure that stores to normal memory are visible to the
* other CPUs before issuing the IPI.
*/
dsb();
smp_wmb();

for_each_cpu(cpu, mask) {
writel(1 << ipi, mailbox0_base + 16 * cpu);
Expand Down Expand Up @@ -223,6 +223,7 @@ static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = {
.priority = 100,
};

#ifdef CONFIG_ARM
int __init bcm2836_smp_boot_secondary(unsigned int cpu,
struct task_struct *idle)
{
Expand All @@ -238,7 +239,7 @@ int __init bcm2836_smp_boot_secondary(unsigned int cpu,
static const struct smp_operations bcm2836_smp_ops __initconst = {
.smp_boot_secondary = bcm2836_smp_boot_secondary,
};

#endif
#endif

static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
Expand All @@ -252,12 +253,15 @@ bcm2836_arm_irqchip_smp_init(void)
/* Unmask IPIs to the boot CPU. */
bcm2836_arm_irqchip_cpu_notify(&bcm2836_arm_irqchip_cpu_notifier,
CPU_STARTING,
(void *)smp_processor_id());
(void *)(uintptr_t)smp_processor_id());
register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier);

set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);

#ifdef CONFIG_ARM
smp_set_ops(&bcm2836_smp_ops);
#endif
#endif
}

/*
Expand Down
2 changes: 1 addition & 1 deletion drivers/irqchip/irq-crossbar.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ static int crossbar_domain_translate(struct irq_domain *d,
return -EINVAL;

*hwirq = fwspec->param[1];
*type = fwspec->param[2];
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
return 0;
}

Expand Down
20 changes: 16 additions & 4 deletions drivers/irqchip/irq-gic-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,26 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
else if (type & IRQ_TYPE_EDGE_BOTH)
val |= confmask;

/* If the current configuration is the same, then we are done */
if (val == oldval)
return 0;

/*
* Write back the new configuration, and possibly re-enable
* the interrupt. If we tried to write a new configuration and failed,
* return an error.
* the interrupt. If we fail to write a new configuration for
* an SPI then WARN and return an error. If we fail to write the
* configuration for a PPI this is most likely because the GIC
* does not allow us to set the configuration or we are in a
* non-secure mode, and hence it may not be catastrophic.
*/
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
ret = -EINVAL;
if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val) {
if (WARN_ON(irq >= 32))
ret = -EINVAL;
else
pr_warn("GIC: PPI%d is secure or misconfigured\n",
irq - 16);
}

if (sync_access)
sync_access();
Expand Down
19 changes: 17 additions & 2 deletions drivers/irqchip/irq-gic-v2m.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
/* APM X-Gene with GICv2m MSI_IIDR register value */
#define XGENE_GICV2M_MSI_IIDR 0x06000170

/* Broadcom NS2 GICv2m MSI_IIDR register value */
#define BCM_NS2_GICV2M_MSI_IIDR 0x0000013f

/* List of flags for specific v2m implementation */
#define GICV2M_NEEDS_SPI_OFFSET 0x00000001

Expand All @@ -62,6 +65,7 @@ struct v2m_data {
void __iomem *base; /* GICv2m virt address */
u32 spi_start; /* The SPI number that MSIs start */
u32 nr_spis; /* The number of SPIs for MSIs */
u32 spi_offset; /* offset to be subtracted from SPI number */
unsigned long *bm; /* MSI vector bitmap */
u32 flags; /* v2m flags for specific implementation */
};
Expand Down Expand Up @@ -102,7 +106,7 @@ static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
msg->data = data->hwirq;

if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET)
msg->data -= v2m->spi_start;
msg->data -= v2m->spi_offset;
}

static struct irq_chip gicv2m_irq_chip = {
Expand Down Expand Up @@ -340,9 +344,20 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
* different from the standard GICv2m implementation where
* the MSI data is the absolute value within the range from
* spi_start to (spi_start + num_spis).
*
* Broadom NS2 GICv2m implementation has an erratum where the MSI data
* is 'spi_number - 32'
*/
if (readl_relaxed(v2m->base + V2M_MSI_IIDR) == XGENE_GICV2M_MSI_IIDR)
switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) {
case XGENE_GICV2M_MSI_IIDR:
v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
v2m->spi_offset = v2m->spi_start;
break;
case BCM_NS2_GICV2M_MSI_IIDR:
v2m->flags |= GICV2M_NEEDS_SPI_OFFSET;
v2m->spi_offset = 32;
break;
}

v2m->bm = kzalloc(sizeof(long) * BITS_TO_LONGS(v2m->nr_spis),
GFP_KERNEL);
Expand Down
42 changes: 38 additions & 4 deletions drivers/irqchip/irq-gic-v3-its.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ struct its_collection {
u16 col_id;
};

/*
* The ITS_BASER structure - contains memory information and cached
* value of BASER register configuration.
*/
struct its_baser {
void *base;
u64 val;
u32 order;
};

/*
* The ITS structure - contains most of the infrastructure, with the
* top-level MSI domain, the command queue, the collections, and the
Expand All @@ -66,14 +76,12 @@ struct its_node {
unsigned long phys_base;
struct its_cmd_block *cmd_base;
struct its_cmd_block *cmd_write;
struct {
void *base;
u32 order;
} tables[GITS_BASER_NR_REGS];
struct its_baser tables[GITS_BASER_NR_REGS];
struct its_collection *collections;
struct list_head its_device_list;
u64 flags;
u32 ite_size;
u32 device_ids;
};

#define ITS_ITT_ALIGN SZ_256
Expand Down Expand Up @@ -838,6 +846,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
ids = GITS_TYPER_DEVBITS(typer);
}

its->device_ids = ids;

for (i = 0; i < GITS_BASER_NR_REGS; i++) {
u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
u64 type = GITS_BASER_TYPE(val);
Expand Down Expand Up @@ -913,6 +923,7 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
}

val |= alloc_pages - 1;
its->tables[i].val = val;

writeq_relaxed(val, its->base + GITS_BASER + i * 8);
tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
Expand Down Expand Up @@ -1138,9 +1149,22 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
return its_dev;
}

static struct its_baser *its_get_baser(struct its_node *its, u32 type)
{
int i;

for (i = 0; i < GITS_BASER_NR_REGS; i++) {
if (GITS_BASER_TYPE(its->tables[i].val) == type)
return &its->tables[i];
}

return NULL;
}

static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
int nvecs)
{
struct its_baser *baser;
struct its_device *dev;
unsigned long *lpi_map;
unsigned long flags;
Expand All @@ -1151,6 +1175,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
int nr_ites;
int sz;

baser = its_get_baser(its, GITS_BASER_TYPE_DEVICE);

/* Don't allow 'dev_id' that exceeds single, flat table limit */
if (baser) {
if (dev_id >= (PAGE_ORDER_TO_SIZE(baser->order) /
GITS_BASER_ENTRY_SIZE(baser->val)))
return NULL;
} else if (ilog2(dev_id) >= its->device_ids)
return NULL;

dev = kzalloc(sizeof(*dev), GFP_KERNEL);
/*
* At least one bit of EventID is being used, hence a minimum
Expand Down
19 changes: 19 additions & 0 deletions drivers/irqchip/irq-gic-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,13 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
if (static_key_true(&supports_deactivate))
gic_write_dir(irqnr);
#ifdef CONFIG_SMP
/*
* Unlike GICv2, we don't need an smp_rmb() here.
* The control dependency from gic_read_iar to
* the ISB in gic_write_eoir is enough to ensure
* that any shared data read by handle_IPI will
* be read after the ACK.
*/
handle_IPI(irqnr, regs);
#else
WARN_ONCE(true, "Unexpected SGI received!\n");
Expand All @@ -386,6 +393,15 @@ static void __init gic_dist_init(void)
writel_relaxed(0, base + GICD_CTLR);
gic_dist_wait_for_rwp();

/*
* Configure SPIs as non-secure Group-1. This will only matter
* if the GIC only has a single security state. This will not
* do the right thing if the kernel is running in secure mode,
* but that's not the intended use case anyway.
*/
for (i = 32; i < gic_data.irq_nr; i += 32)
writel_relaxed(~0, base + GICD_IGROUPR + i / 8);

gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);

/* Enable distributor with ARE, Group1 */
Expand Down Expand Up @@ -503,6 +519,9 @@ static void gic_cpu_init(void)

rbase = gic_data_rdist_sgi_base();

/* Configure SGIs/PPIs as non-secure Group-1 */
writel_relaxed(~0, rbase + GICR_IGROUPR0);

gic_cpu_config(rbase, gic_redist_wait_for_rwp);

/* Give LPIs a spin */
Expand Down
Loading

0 comments on commit 0097852

Please sign in to comment.