linux/drivers/irqchip/irq-armada-370-xp.c
<<
>>
Prefs
   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        msg->address_lo = lower_32_bits(msi_doorbell_addr);
 213        msg->address_hi = upper_32_bits(msi_doorbell_addr);
 214        msg->data = 0xf00 | (data->hwirq + PCI_MSI_DOORBELL_START);
 215}
 216
 217static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data,
 218                                          const struct cpumask *mask, bool force)
 219{
 220         return -EINVAL;
 221}
 222
 223static struct irq_chip armada_370_xp_msi_bottom_irq_chip = {
 224        .name                   = "MPIC MSI",
 225        .irq_compose_msi_msg    = armada_370_xp_compose_msi_msg,
 226        .irq_set_affinity       = armada_370_xp_msi_set_affinity,
 227};
 228
 229static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq,
 230                                   unsigned int nr_irqs, void *args)
 231{
 232        int hwirq, i;
 233
 234        mutex_lock(&msi_used_lock);
 235
 236        hwirq = bitmap_find_next_zero_area(msi_used, PCI_MSI_DOORBELL_NR,
 237                                           0, nr_irqs, 0);
 238        if (hwirq >= PCI_MSI_DOORBELL_NR) {
 239                mutex_unlock(&msi_used_lock);
 240                return -ENOSPC;
 241        }
 242
 243        bitmap_set(msi_used, hwirq, nr_irqs);
 244        mutex_unlock(&msi_used_lock);
 245
 246        for (i = 0; i < nr_irqs; i++) {
 247                irq_domain_set_info(domain, virq + i, hwirq + i,
 248                                    &armada_370_xp_msi_bottom_irq_chip,
 249                                    domain->host_data, handle_simple_irq,
 250                                    NULL, NULL);
 251        }
 252
 253        return hwirq;
 254}
 255
 256static void armada_370_xp_msi_free(struct irq_domain *domain,
 257                                   unsigned int virq, unsigned int nr_irqs)
 258{
 259        struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 260
 261        mutex_lock(&msi_used_lock);
 262        bitmap_clear(msi_used, d->hwirq, nr_irqs);
 263        mutex_unlock(&msi_used_lock);
 264}
 265
 266static const struct irq_domain_ops armada_370_xp_msi_domain_ops = {
 267        .alloc  = armada_370_xp_msi_alloc,
 268        .free   = armada_370_xp_msi_free,
 269};
 270
 271static int armada_370_xp_msi_init(struct device_node *node,
 272                                  phys_addr_t main_int_phys_base)
 273{
 274        u32 reg;
 275
 276        msi_doorbell_addr = main_int_phys_base +
 277                ARMADA_370_XP_SW_TRIG_INT_OFFS;
 278
 279        armada_370_xp_msi_inner_domain =
 280                irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
 281                                      &armada_370_xp_msi_domain_ops, NULL);
 282        if (!armada_370_xp_msi_inner_domain)
 283                return -ENOMEM;
 284
 285        armada_370_xp_msi_domain =
 286                pci_msi_create_irq_domain(of_node_to_fwnode(node),
 287                                          &armada_370_xp_msi_domain_info,
 288                                          armada_370_xp_msi_inner_domain);
 289        if (!armada_370_xp_msi_domain) {
 290                irq_domain_remove(armada_370_xp_msi_inner_domain);
 291                return -ENOMEM;
 292        }
 293
 294        reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
 295                | PCI_MSI_DOORBELL_MASK;
 296
 297        writel(reg, per_cpu_int_base +
 298               ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 299
 300        /* Unmask IPI interrupt */
 301        writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 302
 303        return 0;
 304}
 305#else
 306static inline int armada_370_xp_msi_init(struct device_node *node,
 307                                         phys_addr_t main_int_phys_base)
 308{
 309        return 0;
 310}
 311#endif
 312
 313static void armada_xp_mpic_perf_init(void)
 314{
 315        unsigned long cpuid = cpu_logical_map(smp_processor_id());
 316
 317        /* Enable Performance Counter Overflow interrupts */
 318        writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
 319               per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS);
 320}
 321
 322#ifdef CONFIG_SMP
 323static struct irq_domain *ipi_domain;
 324
 325static void armada_370_xp_ipi_mask(struct irq_data *d)
 326{
 327        u32 reg;
 328        reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 329        reg &= ~BIT(d->hwirq);
 330        writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 331}
 332
 333static void armada_370_xp_ipi_unmask(struct irq_data *d)
 334{
 335        u32 reg;
 336        reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 337        reg |= BIT(d->hwirq);
 338        writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 339}
 340
 341static void armada_370_xp_ipi_send_mask(struct irq_data *d,
 342                                        const struct cpumask *mask)
 343{
 344        unsigned long map = 0;
 345        int cpu;
 346
 347        /* Convert our logical CPU mask into a physical one. */
 348        for_each_cpu(cpu, mask)
 349                map |= 1 << cpu_logical_map(cpu);
 350
 351        /*
 352         * Ensure that stores to Normal memory are visible to the
 353         * other CPUs before issuing the IPI.
 354         */
 355        dsb();
 356
 357        /* submit softirq */
 358        writel((map << 8) | d->hwirq, main_int_base +
 359                ARMADA_370_XP_SW_TRIG_INT_OFFS);
 360}
 361
 362static void armada_370_xp_ipi_eoi(struct irq_data *d)
 363{
 364        writel(~BIT(d->hwirq), per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
 365}
 366
 367static struct irq_chip ipi_irqchip = {
 368        .name           = "IPI",
 369        .irq_mask       = armada_370_xp_ipi_mask,
 370        .irq_unmask     = armada_370_xp_ipi_unmask,
 371        .irq_eoi        = armada_370_xp_ipi_eoi,
 372        .ipi_send_mask  = armada_370_xp_ipi_send_mask,
 373};
 374
 375static int armada_370_xp_ipi_alloc(struct irq_domain *d,
 376                                         unsigned int virq,
 377                                         unsigned int nr_irqs, void *args)
 378{
 379        int i;
 380
 381        for (i = 0; i < nr_irqs; i++) {
 382                irq_set_percpu_devid(virq + i);
 383                irq_domain_set_info(d, virq + i, i, &ipi_irqchip,
 384                                    d->host_data,
 385                                    handle_percpu_devid_irq,
 386                                    NULL, NULL);
 387        }
 388
 389        return 0;
 390}
 391
 392static void armada_370_xp_ipi_free(struct irq_domain *d,
 393                                         unsigned int virq,
 394                                         unsigned int nr_irqs)
 395{
 396        /* Not freeing IPIs */
 397}
 398
 399static const struct irq_domain_ops ipi_domain_ops = {
 400        .alloc  = armada_370_xp_ipi_alloc,
 401        .free   = armada_370_xp_ipi_free,
 402};
 403
 404static void ipi_resume(void)
 405{
 406        int i;
 407
 408        for (i = 0; i < IPI_DOORBELL_END; i++) {
 409                int irq;
 410
 411                irq = irq_find_mapping(ipi_domain, i);
 412                if (irq <= 0)
 413                        continue;
 414                if (irq_percpu_is_enabled(irq)) {
 415                        struct irq_data *d;
 416                        d = irq_domain_get_irq_data(ipi_domain, irq);
 417                        armada_370_xp_ipi_unmask(d);
 418                }
 419        }
 420}
 421
 422static __init void armada_xp_ipi_init(struct device_node *node)
 423{
 424        int base_ipi;
 425
 426        ipi_domain = irq_domain_create_linear(of_node_to_fwnode(node),
 427                                              IPI_DOORBELL_END,
 428                                              &ipi_domain_ops, NULL);
 429        if (WARN_ON(!ipi_domain))
 430                return;
 431
 432        irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI);
 433        base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, IPI_DOORBELL_END,
 434                                           NUMA_NO_NODE, NULL, false, NULL);
 435        if (WARN_ON(!base_ipi))
 436                return;
 437
 438        set_smp_ipi_range(base_ipi, IPI_DOORBELL_END);
 439}
 440
 441static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 442
 443static int armada_xp_set_affinity(struct irq_data *d,
 444                                  const struct cpumask *mask_val, bool force)
 445{
 446        irq_hw_number_t hwirq = irqd_to_hwirq(d);
 447        unsigned long reg, mask;
 448        int cpu;
 449
 450        /* Select a single core from the affinity mask which is online */
 451        cpu = cpumask_any_and(mask_val, cpu_online_mask);
 452        mask = 1UL << cpu_logical_map(cpu);
 453
 454        raw_spin_lock(&irq_controller_lock);
 455        reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
 456        reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask;
 457        writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
 458        raw_spin_unlock(&irq_controller_lock);
 459
 460        irq_data_update_effective_affinity(d, cpumask_of(cpu));
 461
 462        return IRQ_SET_MASK_OK;
 463}
 464
 465static void armada_xp_mpic_smp_cpu_init(void)
 466{
 467        u32 control;
 468        int nr_irqs, i;
 469
 470        control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
 471        nr_irqs = (control >> 2) & 0x3ff;
 472
 473        for (i = 0; i < nr_irqs; i++)
 474                writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
 475
 476        /* Disable all IPIs */
 477        writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 478
 479        /* Clear pending IPIs */
 480        writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
 481
 482        /* Unmask IPI interrupt */
 483        writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 484}
 485
 486static void armada_xp_mpic_reenable_percpu(void)
 487{
 488        unsigned int irq;
 489
 490        /* Re-enable per-CPU interrupts that were enabled before suspend */
 491        for (irq = 0; irq < ARMADA_370_XP_MAX_PER_CPU_IRQS; irq++) {
 492                struct irq_data *data;
 493                int virq;
 494
 495                virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
 496                if (virq == 0)
 497                        continue;
 498
 499                data = irq_get_irq_data(virq);
 500
 501                if (!irq_percpu_is_enabled(virq))
 502                        continue;
 503
 504                armada_370_xp_irq_unmask(data);
 505        }
 506
 507        ipi_resume();
 508}
 509
 510static int armada_xp_mpic_starting_cpu(unsigned int cpu)
 511{
 512        armada_xp_mpic_perf_init();
 513        armada_xp_mpic_smp_cpu_init();
 514        armada_xp_mpic_reenable_percpu();
 515        return 0;
 516}
 517
 518static int mpic_cascaded_starting_cpu(unsigned int cpu)
 519{
 520        armada_xp_mpic_perf_init();
 521        armada_xp_mpic_reenable_percpu();
 522        enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
 523        return 0;
 524}
 525#else
 526static void armada_xp_mpic_smp_cpu_init(void) {}
 527static void ipi_resume(void) {}
 528#endif
 529
 530static struct irq_chip armada_370_xp_irq_chip = {
 531        .name           = "MPIC",
 532        .irq_mask       = armada_370_xp_irq_mask,
 533        .irq_mask_ack   = armada_370_xp_irq_mask,
 534        .irq_unmask     = armada_370_xp_irq_unmask,
 535#ifdef CONFIG_SMP
 536        .irq_set_affinity = armada_xp_set_affinity,
 537#endif
 538        .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
 539};
 540
 541static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
 542                                      unsigned int virq, irq_hw_number_t hw)
 543{
 544        armada_370_xp_irq_mask(irq_get_irq_data(virq));
 545        if (!is_percpu_irq(hw))
 546                writel(hw, per_cpu_int_base +
 547                        ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 548        else
 549                writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
 550        irq_set_status_flags(virq, IRQ_LEVEL);
 551
 552        if (is_percpu_irq(hw)) {
 553                irq_set_percpu_devid(virq);
 554                irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
 555                                        handle_percpu_devid_irq);
 556        } else {
 557                irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
 558                                        handle_level_irq);
 559                irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
 560        }
 561        irq_set_probe(virq);
 562
 563        return 0;
 564}
 565
 566static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
 567        .map = armada_370_xp_mpic_irq_map,
 568        .xlate = irq_domain_xlate_onecell,
 569};
 570
 571#ifdef CONFIG_PCI_MSI
 572static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
 573{
 574        u32 msimask, msinr;
 575
 576        msimask = readl_relaxed(per_cpu_int_base +
 577                                ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
 578                & PCI_MSI_DOORBELL_MASK;
 579
 580        writel(~msimask, per_cpu_int_base +
 581               ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
 582
 583        for (msinr = PCI_MSI_DOORBELL_START;
 584             msinr < PCI_MSI_DOORBELL_END; msinr++) {
 585                unsigned int irq;
 586
 587                if (!(msimask & BIT(msinr)))
 588                        continue;
 589
 590                irq = msinr - PCI_MSI_DOORBELL_START;
 591
 592                if (is_chained)
 593                        generic_handle_domain_irq(armada_370_xp_msi_inner_domain,
 594                                                  irq);
 595                else
 596                        handle_domain_irq(armada_370_xp_msi_inner_domain,
 597                                          irq, regs);
 598        }
 599}
 600#else
 601static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
 602#endif
 603
 604static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
 605{
 606        struct irq_chip *chip = irq_desc_get_chip(desc);
 607        unsigned long irqmap, irqn, irqsrc, cpuid;
 608
 609        chained_irq_enter(chip, desc);
 610
 611        irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
 612        cpuid = cpu_logical_map(smp_processor_id());
 613
 614        for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
 615                irqsrc = readl_relaxed(main_int_base +
 616                                       ARMADA_370_XP_INT_SOURCE_CTL(irqn));
 617
 618                /* Check if the interrupt is not masked on current CPU.
 619                 * Test IRQ (0-1) and FIQ (8-9) mask bits.
 620                 */
 621                if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid)))
 622                        continue;
 623
 624                if (irqn == 1) {
 625                        armada_370_xp_handle_msi_irq(NULL, true);
 626                        continue;
 627                }
 628
 629                generic_handle_domain_irq(armada_370_xp_mpic_domain, irqn);
 630        }
 631
 632        chained_irq_exit(chip, desc);
 633}
 634
 635static void __exception_irq_entry
 636armada_370_xp_handle_irq(struct pt_regs *regs)
 637{
 638        u32 irqstat, irqnr;
 639
 640        do {
 641                irqstat = readl_relaxed(per_cpu_int_base +
 642                                        ARMADA_370_XP_CPU_INTACK_OFFS);
 643                irqnr = irqstat & 0x3FF;
 644
 645                if (irqnr > 1022)
 646                        break;
 647
 648                if (irqnr > 1) {
 649                        handle_domain_irq(armada_370_xp_mpic_domain,
 650                                          irqnr, regs);
 651                        continue;
 652                }
 653
 654                /* MSI handling */
 655                if (irqnr == 1)
 656                        armada_370_xp_handle_msi_irq(regs, false);
 657
 658#ifdef CONFIG_SMP
 659                /* IPI Handling */
 660                if (irqnr == 0) {
 661                        unsigned long ipimask;
 662                        int ipi;
 663
 664                        ipimask = readl_relaxed(per_cpu_int_base +
 665                                                ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
 666                                & IPI_DOORBELL_MASK;
 667
 668                        for_each_set_bit(ipi, &ipimask, IPI_DOORBELL_END)
 669                                handle_domain_irq(ipi_domain, ipi, regs);
 670                }
 671#endif
 672
 673        } while (1);
 674}
 675
 676static int armada_370_xp_mpic_suspend(void)
 677{
 678        doorbell_mask_reg = readl(per_cpu_int_base +
 679                                  ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 680        return 0;
 681}
 682
 683static void armada_370_xp_mpic_resume(void)
 684{
 685        int nirqs;
 686        irq_hw_number_t irq;
 687
 688        /* Re-enable interrupts */
 689        nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
 690        for (irq = 0; irq < nirqs; irq++) {
 691                struct irq_data *data;
 692                int virq;
 693
 694                virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
 695                if (virq == 0)
 696                        continue;
 697
 698                data = irq_get_irq_data(virq);
 699
 700                if (!is_percpu_irq(irq)) {
 701                        /* Non per-CPU interrupts */
 702                        writel(irq, per_cpu_int_base +
 703                               ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 704                        if (!irqd_irq_disabled(data))
 705                                armada_370_xp_irq_unmask(data);
 706                } else {
 707                        /* Per-CPU interrupts */
 708                        writel(irq, main_int_base +
 709                               ARMADA_370_XP_INT_SET_ENABLE_OFFS);
 710
 711                        /*
 712                         * Re-enable on the current CPU,
 713                         * armada_xp_mpic_reenable_percpu() will take
 714                         * care of secondary CPUs when they come up.
 715                         */
 716                        if (irq_percpu_is_enabled(virq))
 717                                armada_370_xp_irq_unmask(data);
 718                }
 719        }
 720
 721        /* Reconfigure doorbells for IPIs and MSIs */
 722        writel(doorbell_mask_reg,
 723               per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 724        if (doorbell_mask_reg & IPI_DOORBELL_MASK)
 725                writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 726        if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
 727                writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 728
 729        ipi_resume();
 730}
 731
 732static struct syscore_ops armada_370_xp_mpic_syscore_ops = {
 733        .suspend        = armada_370_xp_mpic_suspend,
 734        .resume         = armada_370_xp_mpic_resume,
 735};
 736
 737static int __init armada_370_xp_mpic_of_init(struct device_node *node,
 738                                             struct device_node *parent)
 739{
 740        struct resource main_int_res, per_cpu_int_res;
 741        int nr_irqs, i;
 742        u32 control;
 743
 744        BUG_ON(of_address_to_resource(node, 0, &main_int_res));
 745        BUG_ON(of_address_to_resource(node, 1, &per_cpu_int_res));
 746
 747        BUG_ON(!request_mem_region(main_int_res.start,
 748                                   resource_size(&main_int_res),
 749                                   node->full_name));
 750        BUG_ON(!request_mem_region(per_cpu_int_res.start,
 751                                   resource_size(&per_cpu_int_res),
 752                                   node->full_name));
 753
 754        main_int_base = ioremap(main_int_res.start,
 755                                resource_size(&main_int_res));
 756        BUG_ON(!main_int_base);
 757
 758        per_cpu_int_base = ioremap(per_cpu_int_res.start,
 759                                   resource_size(&per_cpu_int_res));
 760        BUG_ON(!per_cpu_int_base);
 761
 762        control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
 763        nr_irqs = (control >> 2) & 0x3ff;
 764
 765        for (i = 0; i < nr_irqs; i++)
 766                writel(i, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
 767
 768        armada_370_xp_mpic_domain =
 769                irq_domain_add_linear(node, nr_irqs,
 770                                &armada_370_xp_mpic_irq_ops, NULL);
 771        BUG_ON(!armada_370_xp_mpic_domain);
 772        irq_domain_update_bus_token(armada_370_xp_mpic_domain, DOMAIN_BUS_WIRED);
 773
 774        /* Setup for the boot CPU */
 775        armada_xp_mpic_perf_init();
 776        armada_xp_mpic_smp_cpu_init();
 777
 778        armada_370_xp_msi_init(node, main_int_res.start);
 779
 780        parent_irq = irq_of_parse_and_map(node, 0);
 781        if (parent_irq <= 0) {
 782                irq_set_default_host(armada_370_xp_mpic_domain);
 783                set_handle_irq(armada_370_xp_handle_irq);
 784#ifdef CONFIG_SMP
 785                armada_xp_ipi_init(node);
 786                cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
 787                                          "irqchip/armada/ipi:starting",
 788                                          armada_xp_mpic_starting_cpu, NULL);
 789#endif
 790        } else {
 791#ifdef CONFIG_SMP
 792                cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
 793                                          "irqchip/armada/cascade:starting",
 794                                          mpic_cascaded_starting_cpu, NULL);
 795#endif
 796                irq_set_chained_handler(parent_irq,
 797                                        armada_370_xp_mpic_handle_cascade_irq);
 798        }
 799
 800        register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
 801
 802        return 0;
 803}
 804
 805IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init);
 806