cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

irq-armada-370-xp.c (22814B)


      1/*
      2 * Marvell Armada 370 and Armada XP SoC IRQ handling
      3 *
      4 * Copyright (C) 2012 Marvell
      5 *
      6 * Lior Amsalem <alior@marvell.com>
      7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
      8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
      9 * Ben Dooks <ben.dooks@codethink.co.uk>
     10 *
     11 * This file is licensed under the terms of the GNU General Public
     12 * License version 2.  This program is licensed "as is" without any
     13 * warranty of any kind, whether express or implied.
     14 */
     15
     16#include <linux/kernel.h>
     17#include <linux/module.h>
     18#include <linux/init.h>
     19#include <linux/irq.h>
     20#include <linux/interrupt.h>
     21#include <linux/irqchip.h>
     22#include <linux/irqchip/chained_irq.h>
     23#include <linux/cpu.h>
     24#include <linux/io.h>
     25#include <linux/of_address.h>
     26#include <linux/of_irq.h>
     27#include <linux/of_pci.h>
     28#include <linux/irqdomain.h>
     29#include <linux/slab.h>
     30#include <linux/syscore_ops.h>
     31#include <linux/msi.h>
     32#include <asm/mach/arch.h>
     33#include <asm/exception.h>
     34#include <asm/smp_plat.h>
     35#include <asm/mach/irq.h>
     36
     37/*
     38 * Overall diagram of the Armada XP interrupt controller:
     39 *
     40 *    To CPU 0                 To CPU 1
     41 *
     42 *       /\                       /\
     43 *       ||                       ||
     44 * +---------------+     +---------------+
     45 * |               |	 |               |
     46 * |    per-CPU    |	 |    per-CPU    |
     47 * |  mask/unmask  |	 |  mask/unmask  |
     48 * |     CPU0      |	 |     CPU1      |
     49 * |               |	 |               |
     50 * +---------------+	 +---------------+
     51 *        /\                       /\
     52 *        ||                       ||
     53 *        \\_______________________//
     54 *                     ||
     55 *            +-------------------+
     56 *            |                   |
     57 *            | Global interrupt  |
     58 *            |    mask/unmask    |
     59 *            |                   |
     60 *            +-------------------+
     61 *                     /\
     62 *                     ||
     63 *               interrupt from
     64 *                   device
     65 *
     66 * The "global interrupt mask/unmask" is modified using the
     67 * ARMADA_370_XP_INT_SET_ENABLE_OFFS and
     68 * ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS registers, which are relative
     69 * to "main_int_base".
     70 *
     71 * The "per-CPU mask/unmask" is modified using the
     72 * ARMADA_370_XP_INT_SET_MASK_OFFS and
     73 * ARMADA_370_XP_INT_CLEAR_MASK_OFFS registers, which are relative to
     74 * "per_cpu_int_base". This base address points to a special address,
     75 * which automatically accesses the registers of the current CPU.
     76 *
     77 * The per-CPU mask/unmask can also be adjusted using the global
     78 * per-interrupt ARMADA_370_XP_INT_SOURCE_CTL register, which we use
     79 * to configure interrupt affinity.
     80 *
     81 * Due to this model, all interrupts need to be mask/unmasked at two
     82 * different levels: at the global level and at the per-CPU level.
     83 *
     84 * This driver takes the following approach to deal with this:
     85 *
     86 *  - For global interrupts:
     87 *
     88 *    At ->map() time, a global interrupt is unmasked at the per-CPU
     89 *    mask/unmask level. It is therefore unmasked at this level for
     90 *    the current CPU, running the ->map() code. This allows to have
     91 *    the interrupt unmasked at this level in non-SMP
     92 *    configurations. In SMP configurations, the ->set_affinity()
     93 *    callback is called, which using the
     94 *    ARMADA_370_XP_INT_SOURCE_CTL() readjusts the per-CPU mask/unmask
     95 *    for the interrupt.
     96 *
     97 *    The ->mask() and ->unmask() operations only mask/unmask the
     98 *    interrupt at the "global" level.
     99 *
    100 *    So, a global interrupt is enabled at the per-CPU level as soon
    101 *    as it is mapped. At run time, the masking/unmasking takes place
    102 *    at the global level.
    103 *
    104 *  - For per-CPU interrupts
    105 *
    106 *    At ->map() time, a per-CPU interrupt is unmasked at the global
    107 *    mask/unmask level.
    108 *
    109 *    The ->mask() and ->unmask() operations mask/unmask the interrupt
    110 *    at the per-CPU level.
    111 *
    112 *    So, a per-CPU interrupt is enabled at the global level as soon
    113 *    as it is mapped. At run time, the masking/unmasking takes place
    114 *    at the per-CPU level.
    115 */
    116
    117/* Registers relative to main_int_base */
    118#define ARMADA_370_XP_INT_CONTROL		(0x00)
    119#define ARMADA_370_XP_SW_TRIG_INT_OFFS		(0x04)
    120#define ARMADA_370_XP_INT_SET_ENABLE_OFFS	(0x30)
    121#define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS	(0x34)
    122#define ARMADA_370_XP_INT_SOURCE_CTL(irq)	(0x100 + irq*4)
    123#define ARMADA_370_XP_INT_SOURCE_CPU_MASK	0xF
    124#define ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid)	((BIT(0) | BIT(8)) << cpuid)
    125
    126/* Registers relative to per_cpu_int_base */
    127#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS	(0x08)
    128#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS		(0x0c)
    129#define ARMADA_375_PPI_CAUSE			(0x10)
    130#define ARMADA_370_XP_CPU_INTACK_OFFS		(0x44)
    131#define ARMADA_370_XP_INT_SET_MASK_OFFS		(0x48)
    132#define ARMADA_370_XP_INT_CLEAR_MASK_OFFS	(0x4C)
    133#define ARMADA_370_XP_INT_FABRIC_MASK_OFFS	(0x54)
    134#define ARMADA_370_XP_INT_CAUSE_PERF(cpu)	(1 << cpu)
    135
    136#define ARMADA_370_XP_MAX_PER_CPU_IRQS		(28)
    137
    138#define IPI_DOORBELL_START                      (0)
    139#define IPI_DOORBELL_END                        (8)
    140#define IPI_DOORBELL_MASK                       0xFF
    141#define PCI_MSI_DOORBELL_START                  (16)
    142#define PCI_MSI_DOORBELL_NR                     (16)
    143#define PCI_MSI_DOORBELL_END                    (32)
    144#define PCI_MSI_DOORBELL_MASK                   0xFFFF0000
    145
    146static void __iomem *per_cpu_int_base;
    147static void __iomem *main_int_base;
    148static struct irq_domain *armada_370_xp_mpic_domain;
    149static u32 doorbell_mask_reg;
    150static int parent_irq;
    151#ifdef CONFIG_PCI_MSI
    152static struct irq_domain *armada_370_xp_msi_domain;
    153static struct irq_domain *armada_370_xp_msi_inner_domain;
    154static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
    155static DEFINE_MUTEX(msi_used_lock);
    156static phys_addr_t msi_doorbell_addr;
    157#endif
    158
    159static inline bool is_percpu_irq(irq_hw_number_t irq)
    160{
    161	if (irq <= ARMADA_370_XP_MAX_PER_CPU_IRQS)
    162		return true;
    163
    164	return false;
    165}
    166
    167/*
    168 * In SMP mode:
    169 * For shared global interrupts, mask/unmask global enable bit
    170 * For CPU interrupts, mask/unmask the calling CPU's bit
    171 */
    172static void armada_370_xp_irq_mask(struct irq_data *d)
    173{
    174	irq_hw_number_t hwirq = irqd_to_hwirq(d);
    175
    176	if (!is_percpu_irq(hwirq))
    177		writel(hwirq, main_int_base +
    178				ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
    179	else
    180		writel(hwirq, per_cpu_int_base +
    181				ARMADA_370_XP_INT_SET_MASK_OFFS);
    182}
    183
    184static void armada_370_xp_irq_unmask(struct irq_data *d)
    185{
    186	irq_hw_number_t hwirq = irqd_to_hwirq(d);
    187
    188	if (!is_percpu_irq(hwirq))
    189		writel(hwirq, main_int_base +
    190				ARMADA_370_XP_INT_SET_ENABLE_OFFS);
    191	else
    192		writel(hwirq, per_cpu_int_base +
    193				ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
    194}
    195
    196#ifdef CONFIG_PCI_MSI
    197
    198static struct irq_chip armada_370_xp_msi_irq_chip = {
    199	.name = "MPIC MSI",
    200	.irq_mask = pci_msi_mask_irq,
    201	.irq_unmask = pci_msi_unmask_irq,
    202};
    203
    204static struct msi_domain_info armada_370_xp_msi_domain_info = {
    205	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
    206		   MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
    207	.chip	= &armada_370_xp_msi_irq_chip,
    208};
    209
    210static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
    211{
    212	unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(data));
    213
    214	msg->address_lo = lower_32_bits(msi_doorbell_addr);
    215	msg->address_hi = upper_32_bits(msi_doorbell_addr);
    216	msg->data = BIT(cpu + 8) | (data->hwirq + PCI_MSI_DOORBELL_START);
    217}
    218
    219static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data,
    220					  const struct cpumask *mask, bool force)
    221{
    222	unsigned int cpu;
    223
    224	if (!force)
    225		cpu = cpumask_any_and(mask, cpu_online_mask);
    226	else
    227		cpu = cpumask_first(mask);
    228
    229	if (cpu >= nr_cpu_ids)
    230		return -EINVAL;
    231
    232	irq_data_update_effective_affinity(irq_data, cpumask_of(cpu));
    233
    234	return IRQ_SET_MASK_OK;
    235}
    236
    237static struct irq_chip armada_370_xp_msi_bottom_irq_chip = {
    238	.name			= "MPIC MSI",
    239	.irq_compose_msi_msg	= armada_370_xp_compose_msi_msg,
    240	.irq_set_affinity	= armada_370_xp_msi_set_affinity,
    241};
    242
    243static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
    244				   unsigned int nr_irqs, void *args)
    245{
    246	int hwirq, i;
    247
    248	mutex_lock(&msi_used_lock);
    249	hwirq = bitmap_find_free_region(msi_used, PCI_MSI_DOORBELL_NR,
    250					order_base_2(nr_irqs));
    251	mutex_unlock(&msi_used_lock);
    252
    253	if (hwirq < 0)
    254		return -ENOSPC;
    255
    256	for (i = 0; i < nr_irqs; i++) {
    257		irq_domain_set_info(domain, virq + i, hwirq + i,
    258				    &armada_370_xp_msi_bottom_irq_chip,
    259				    domain->host_data, handle_simple_irq,
    260				    NULL, NULL);
    261	}
    262
    263	return 0;
    264}
    265
    266static void armada_370_xp_msi_free(struct irq_domain *domain,
    267				   unsigned int virq, unsigned int nr_irqs)
    268{
    269	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
    270
    271	mutex_lock(&msi_used_lock);
    272	bitmap_release_region(msi_used, d->hwirq, order_base_2(nr_irqs));
    273	mutex_unlock(&msi_used_lock);
    274}
    275
    276static const struct irq_domain_ops armada_370_xp_msi_domain_ops = {
    277	.alloc	= armada_370_xp_msi_alloc,
    278	.free	= armada_370_xp_msi_free,
    279};
    280
    281static void armada_370_xp_msi_reenable_percpu(void)
    282{
    283	u32 reg;
    284
    285	/* Enable MSI doorbell mask and combined cpu local interrupt */
    286	reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
    287		| PCI_MSI_DOORBELL_MASK;
    288	writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    289	/* Unmask local doorbell interrupt */
    290	writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
    291}
    292
    293static int armada_370_xp_msi_init(struct device_node *node,
    294				  phys_addr_t main_int_phys_base)
    295{
    296	msi_doorbell_addr = main_int_phys_base +
    297		ARMADA_370_XP_SW_TRIG_INT_OFFS;
    298
    299	armada_370_xp_msi_inner_domain =
    300		irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
    301				      &armada_370_xp_msi_domain_ops, NULL);
    302	if (!armada_370_xp_msi_inner_domain)
    303		return -ENOMEM;
    304
    305	armada_370_xp_msi_domain =
    306		pci_msi_create_irq_domain(of_node_to_fwnode(node),
    307					  &armada_370_xp_msi_domain_info,
    308					  armada_370_xp_msi_inner_domain);
    309	if (!armada_370_xp_msi_domain) {
    310		irq_domain_remove(armada_370_xp_msi_inner_domain);
    311		return -ENOMEM;
    312	}
    313
    314	armada_370_xp_msi_reenable_percpu();
    315
    316	return 0;
    317}
    318#else
    319static void armada_370_xp_msi_reenable_percpu(void) {}
    320
    321static inline int armada_370_xp_msi_init(struct device_node *node,
    322					 phys_addr_t main_int_phys_base)
    323{
    324	return 0;
    325}
    326#endif
    327
    328static void armada_xp_mpic_perf_init(void)
    329{
    330	unsigned long cpuid;
    331
    332	/*
    333	 * This Performance Counter Overflow interrupt is specific for
    334	 * Armada 370 and XP. It is not available on Armada 375, 38x and 39x.
    335	 */
    336	if (!of_machine_is_compatible("marvell,armada-370-xp"))
    337		return;
    338
    339	cpuid = cpu_logical_map(smp_processor_id());
    340
    341	/* Enable Performance Counter Overflow interrupts */
    342	writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
    343	       per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS);
    344}
    345
    346#ifdef CONFIG_SMP
    347static struct irq_domain *ipi_domain;
    348
    349static void armada_370_xp_ipi_mask(struct irq_data *d)
    350{
    351	u32 reg;
    352	reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    353	reg &= ~BIT(d->hwirq);
    354	writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    355}
    356
    357static void armada_370_xp_ipi_unmask(struct irq_data *d)
    358{
    359	u32 reg;
    360	reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    361	reg |= BIT(d->hwirq);
    362	writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    363}
    364
    365static void armada_370_xp_ipi_send_mask(struct irq_data *d,
    366					const struct cpumask *mask)
    367{
    368	unsigned long map = 0;
    369	int cpu;
    370
    371	/* Convert our logical CPU mask into a physical one. */
    372	for_each_cpu(cpu, mask)
    373		map |= 1 << cpu_logical_map(cpu);
    374
    375	/*
    376	 * Ensure that stores to Normal memory are visible to the
    377	 * other CPUs before issuing the IPI.
    378	 */
    379	dsb();
    380
    381	/* submit softirq */
    382	writel((map << 8) | d->hwirq, main_int_base +
    383		ARMADA_370_XP_SW_TRIG_INT_OFFS);
    384}
    385
    386static void armada_370_xp_ipi_ack(struct irq_data *d)
    387{
    388	writel(~BIT(d->hwirq), per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
    389}
    390
    391static struct irq_chip ipi_irqchip = {
    392	.name		= "IPI",
    393	.irq_ack	= armada_370_xp_ipi_ack,
    394	.irq_mask	= armada_370_xp_ipi_mask,
    395	.irq_unmask	= armada_370_xp_ipi_unmask,
    396	.ipi_send_mask	= armada_370_xp_ipi_send_mask,
    397};
    398
    399static int armada_370_xp_ipi_alloc(struct irq_domain *d,
    400					 unsigned int virq,
    401					 unsigned int nr_irqs, void *args)
    402{
    403	int i;
    404
    405	for (i = 0; i < nr_irqs; i++) {
    406		irq_set_percpu_devid(virq + i);
    407		irq_domain_set_info(d, virq + i, i, &ipi_irqchip,
    408				    d->host_data,
    409				    handle_percpu_devid_irq,
    410				    NULL, NULL);
    411	}
    412
    413	return 0;
    414}
    415
    416static void armada_370_xp_ipi_free(struct irq_domain *d,
    417					 unsigned int virq,
    418					 unsigned int nr_irqs)
    419{
    420	/* Not freeing IPIs */
    421}
    422
    423static const struct irq_domain_ops ipi_domain_ops = {
    424	.alloc	= armada_370_xp_ipi_alloc,
    425	.free	= armada_370_xp_ipi_free,
    426};
    427
    428static void ipi_resume(void)
    429{
    430	int i;
    431
    432	for (i = 0; i < IPI_DOORBELL_END; i++) {
    433		int irq;
    434
    435		irq = irq_find_mapping(ipi_domain, i);
    436		if (irq <= 0)
    437			continue;
    438		if (irq_percpu_is_enabled(irq)) {
    439			struct irq_data *d;
    440			d = irq_domain_get_irq_data(ipi_domain, irq);
    441			armada_370_xp_ipi_unmask(d);
    442		}
    443	}
    444}
    445
    446static __init void armada_xp_ipi_init(struct device_node *node)
    447{
    448	int base_ipi;
    449
    450	ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node),
    451					      IPI_DOORBELL_END,
    452					      &ipi_domain_ops, NULL);
    453	if (WARN_ON(!ipi_domain))
    454		return;
    455
    456	irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI);
    457	base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, IPI_DOORBELL_END,
    458					   NUMA_NO_NODE, NULL, false, NULL);
    459	if (WARN_ON(!base_ipi))
    460		return;
    461
    462	set_smp_ipi_range(base_ipi, IPI_DOORBELL_END);
    463}
    464
    465static DEFINE_RAW_SPINLOCK(irq_controller_lock);
    466
    467static int armada_xp_set_affinity(struct irq_data *d,
    468				  const struct cpumask *mask_val, bool force)
    469{
    470	irq_hw_number_t hwirq = irqd_to_hwirq(d);
    471	unsigned long reg, mask;
    472	int cpu;
    473
    474	/* Select a single core from the affinity mask which is online */
    475	cpu = cpumask_any_and(mask_val, cpu_online_mask);
    476	mask = 1UL << cpu_logical_map(cpu);
    477
    478	raw_spin_lock(&irq_controller_lock);
    479	reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
    480	reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask;
    481	writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
    482	raw_spin_unlock(&irq_controller_lock);
    483
    484	irq_data_update_effective_affinity(d, cpumask_of(cpu));
    485
    486	return IRQ_SET_MASK_OK;
    487}
    488
    489static void armada_xp_mpic_smp_cpu_init(void)
    490{
    491	u32 control;
    492	int nr_irqs, i;
    493
    494	control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
    495	nr_irqs = (control >> 2) & 0x3ff;
    496
    497	for (i = 0; i < nr_irqs; i++)
    498		writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
    499
    500	/* Disable all IPIs */
    501	writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    502
    503	/* Clear pending IPIs */
    504	writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
    505
    506	/* Unmask IPI interrupt */
    507	writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
    508}
    509
    510static void armada_xp_mpic_reenable_percpu(void)
    511{
    512	unsigned int irq;
    513
    514	/* Re-enable per-CPU interrupts that were enabled before suspend */
    515	for (irq = 0; irq < ARMADA_370_XP_MAX_PER_CPU_IRQS; irq++) {
    516		struct irq_data *data;
    517		int virq;
    518
    519		virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
    520		if (virq == 0)
    521			continue;
    522
    523		data = irq_get_irq_data(virq);
    524
    525		if (!irq_percpu_is_enabled(virq))
    526			continue;
    527
    528		armada_370_xp_irq_unmask(data);
    529	}
    530
    531	ipi_resume();
    532
    533	armada_370_xp_msi_reenable_percpu();
    534}
    535
    536static int armada_xp_mpic_starting_cpu(unsigned int cpu)
    537{
    538	armada_xp_mpic_perf_init();
    539	armada_xp_mpic_smp_cpu_init();
    540	armada_xp_mpic_reenable_percpu();
    541	return 0;
    542}
    543
    544static int mpic_cascaded_starting_cpu(unsigned int cpu)
    545{
    546	armada_xp_mpic_perf_init();
    547	armada_xp_mpic_reenable_percpu();
    548	enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
    549	return 0;
    550}
    551#else
    552static void armada_xp_mpic_smp_cpu_init(void) {}
    553static void ipi_resume(void) {}
    554#endif
    555
    556static struct irq_chip armada_370_xp_irq_chip = {
    557	.name		= "MPIC",
    558	.irq_mask       = armada_370_xp_irq_mask,
    559	.irq_mask_ack   = armada_370_xp_irq_mask,
    560	.irq_unmask     = armada_370_xp_irq_unmask,
    561#ifdef CONFIG_SMP
    562	.irq_set_affinity = armada_xp_set_affinity,
    563#endif
    564	.flags		= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
    565};
    566
    567static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
    568				      unsigned int virq, irq_hw_number_t hw)
    569{
    570	armada_370_xp_irq_mask(irq_get_irq_data(virq));
    571	if (!is_percpu_irq(hw))
    572		writel(hw, per_cpu_int_base +
    573			ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
    574	else
    575		writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
    576	irq_set_status_flags(virq, IRQ_LEVEL);
    577
    578	if (is_percpu_irq(hw)) {
    579		irq_set_percpu_devid(virq);
    580		irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
    581					handle_percpu_devid_irq);
    582	} else {
    583		irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
    584					handle_level_irq);
    585		irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
    586	}
    587	irq_set_probe(virq);
    588
    589	return 0;
    590}
    591
    592static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
    593	.map = armada_370_xp_mpic_irq_map,
    594	.xlate = irq_domain_xlate_onecell,
    595};
    596
    597#ifdef CONFIG_PCI_MSI
    598static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
    599{
    600	u32 msimask, msinr;
    601
    602	msimask = readl_relaxed(per_cpu_int_base +
    603				ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
    604		& PCI_MSI_DOORBELL_MASK;
    605
    606	writel(~msimask, per_cpu_int_base +
    607	       ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
    608
    609	for (msinr = PCI_MSI_DOORBELL_START;
    610	     msinr < PCI_MSI_DOORBELL_END; msinr++) {
    611		unsigned int irq;
    612
    613		if (!(msimask & BIT(msinr)))
    614			continue;
    615
    616		irq = msinr - PCI_MSI_DOORBELL_START;
    617
    618		generic_handle_domain_irq(armada_370_xp_msi_inner_domain, irq);
    619	}
    620}
    621#else
    622static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
    623#endif
    624
    625static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
    626{
    627	struct irq_chip *chip = irq_desc_get_chip(desc);
    628	unsigned long irqmap, irqn, irqsrc, cpuid;
    629
    630	chained_irq_enter(chip, desc);
    631
    632	irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
    633	cpuid = cpu_logical_map(smp_processor_id());
    634
    635	for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
    636		irqsrc = readl_relaxed(main_int_base +
    637				       ARMADA_370_XP_INT_SOURCE_CTL(irqn));
    638
    639		/* Check if the interrupt is not masked on current CPU.
    640		 * Test IRQ (0-1) and FIQ (8-9) mask bits.
    641		 */
    642		if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid)))
    643			continue;
    644
    645		if (irqn == 1) {
    646			armada_370_xp_handle_msi_irq(NULL, true);
    647			continue;
    648		}
    649
    650		generic_handle_domain_irq(armada_370_xp_mpic_domain, irqn);
    651	}
    652
    653	chained_irq_exit(chip, desc);
    654}
    655
    656static void __exception_irq_entry
    657armada_370_xp_handle_irq(struct pt_regs *regs)
    658{
    659	u32 irqstat, irqnr;
    660
    661	do {
    662		irqstat = readl_relaxed(per_cpu_int_base +
    663					ARMADA_370_XP_CPU_INTACK_OFFS);
    664		irqnr = irqstat & 0x3FF;
    665
    666		if (irqnr > 1022)
    667			break;
    668
    669		if (irqnr > 1) {
    670			generic_handle_domain_irq(armada_370_xp_mpic_domain,
    671						  irqnr);
    672			continue;
    673		}
    674
    675		/* MSI handling */
    676		if (irqnr == 1)
    677			armada_370_xp_handle_msi_irq(regs, false);
    678
    679#ifdef CONFIG_SMP
    680		/* IPI Handling */
    681		if (irqnr == 0) {
    682			unsigned long ipimask;
    683			int ipi;
    684
    685			ipimask = readl_relaxed(per_cpu_int_base +
    686						ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
    687				& IPI_DOORBELL_MASK;
    688
    689			for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END)
    690				generic_handle_domain_irq(ipi_domain, ipi);
    691		}
    692#endif
    693
    694	} while (1);
    695}
    696
    697static int armada_370_xp_mpic_suspend(void)
    698{
    699	doorbell_mask_reg = readl(per_cpu_int_base +
    700				  ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    701	return 0;
    702}
    703
    704static void armada_370_xp_mpic_resume(void)
    705{
    706	int nirqs;
    707	irq_hw_number_t irq;
    708
    709	/* Re-enable interrupts */
    710	nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
    711	for (irq = 0; irq < nirqs; irq++) {
    712		struct irq_data *data;
    713		int virq;
    714
    715		virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
    716		if (virq == 0)
    717			continue;
    718
    719		data = irq_get_irq_data(virq);
    720
    721		if (!is_percpu_irq(irq)) {
    722			/* Non per-CPU interrupts */
    723			writel(irq, per_cpu_int_base +
    724			       ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
    725			if (!irqd_irq_disabled(data))
    726				armada_370_xp_irq_unmask(data);
    727		} else {
    728			/* Per-CPU interrupts */
    729			writel(irq, main_int_base +
    730			       ARMADA_370_XP_INT_SET_ENABLE_OFFS);
    731
    732			/*
    733			 * Re-enable on the current CPU,
    734			 * armada_xp_mpic_reenable_percpu() will take
    735			 * care of secondary CPUs when they come up.
    736			 */
    737			if (irq_percpu_is_enabled(virq))
    738				armada_370_xp_irq_unmask(data);
    739		}
    740	}
    741
    742	/* Reconfigure doorbells for IPIs and MSIs */
    743	writel(doorbell_mask_reg,
    744	       per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
    745	if (doorbell_mask_reg & IPI_DOORBELL_MASK)
    746		writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
    747	if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
    748		writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
    749
    750	ipi_resume();
    751}
    752
    753static struct syscore_ops armada_370_xp_mpic_syscore_ops = {
    754	.suspend	= armada_370_xp_mpic_suspend,
    755	.resume		= armada_370_xp_mpic_resume,
    756};
    757
    758static int __init armada_370_xp_mpic_of_init(struct device_node *node,
    759					     struct device_node *parent)
    760{
    761	struct resource main_int_res, per_cpu_int_res;
    762	int nr_irqs, i;
    763	u32 control;
    764
    765	BUG_ON(of_address_to_resource(node, 0, &main_int_res));
    766	BUG_ON(of_address_to_resource(node, 1, &per_cpu_int_res));
    767
    768	BUG_ON(!request_mem_region(main_int_res.start,
    769				   resource_size(&main_int_res),
    770				   node->full_name));
    771	BUG_ON(!request_mem_region(per_cpu_int_res.start,
    772				   resource_size(&per_cpu_int_res),
    773				   node->full_name));
    774
    775	main_int_base = ioremap(main_int_res.start,
    776				resource_size(&main_int_res));
    777	BUG_ON(!main_int_base);
    778
    779	per_cpu_int_base = ioremap(per_cpu_int_res.start,
    780				   resource_size(&per_cpu_int_res));
    781	BUG_ON(!per_cpu_int_base);
    782
    783	control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
    784	nr_irqs = (control >> 2) & 0x3ff;
    785
    786	for (i = 0; i < nr_irqs; i++)
    787		writel(i, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
    788
    789	armada_370_xp_mpic_domain =
    790		irq_domain_add_linear(node, nr_irqs,
    791				&armada_370_xp_mpic_irq_ops, NULL);
    792	BUG_ON(!armada_370_xp_mpic_domain);
    793	irq_domain_update_bus_token(armada_370_xp_mpic_domain, DOMAIN_BUS_WIRED);
    794
    795	/* Setup for the boot CPU */
    796	armada_xp_mpic_perf_init();
    797	armada_xp_mpic_smp_cpu_init();
    798
    799	armada_370_xp_msi_init(node, main_int_res.start);
    800
    801	parent_irq = irq_of_parse_and_map(node, 0);
    802	if (parent_irq <= 0) {
    803		irq_set_default_host(armada_370_xp_mpic_domain);
    804		set_handle_irq(armada_370_xp_handle_irq);
    805#ifdef CONFIG_SMP
    806		armada_xp_ipi_init(node);
    807		cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
    808					  "irqchip/armada/ipi:starting",
    809					  armada_xp_mpic_starting_cpu, NULL);
    810#endif
    811	} else {
    812#ifdef CONFIG_SMP
    813		cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
    814					  "irqchip/armada/cascade:starting",
    815					  mpic_cascaded_starting_cpu, NULL);
    816#endif
    817		irq_set_chained_handler(parent_irq,
    818					armada_370_xp_mpic_handle_cascade_irq);
    819	}
    820
    821	register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
    822
    823	return 0;
    824}
    825
    826IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init);