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
 313#ifdef CONFIG_SMP
 314static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 315
 316static int armada_xp_set_affinity(struct irq_data *d,
 317                                  const struct cpumask *mask_val, bool force)
 318{
 319        irq_hw_number_t hwirq = irqd_to_hwirq(d);
 320        unsigned long reg, mask;
 321        int cpu;
 322
 323        /* Select a single core from the affinity mask which is online */
 324        cpu = cpumask_any_and(mask_val, cpu_online_mask);
 325        mask = 1UL << cpu_logical_map(cpu);
 326
 327        raw_spin_lock(&irq_controller_lock);
 328        reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
 329        reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask;
 330        writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
 331        raw_spin_unlock(&irq_controller_lock);
 332
 333        irq_data_update_effective_affinity(d, cpumask_of(cpu));
 334
 335        return IRQ_SET_MASK_OK;
 336}
 337#endif
 338
 339static struct irq_chip armada_370_xp_irq_chip = {
 340        .name           = "MPIC",
 341        .irq_mask       = armada_370_xp_irq_mask,
 342        .irq_mask_ack   = armada_370_xp_irq_mask,
 343        .irq_unmask     = armada_370_xp_irq_unmask,
 344#ifdef CONFIG_SMP
 345        .irq_set_affinity = armada_xp_set_affinity,
 346#endif
 347        .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
 348};
 349
 350static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
 351                                      unsigned int virq, irq_hw_number_t hw)
 352{
 353        armada_370_xp_irq_mask(irq_get_irq_data(virq));
 354        if (!is_percpu_irq(hw))
 355                writel(hw, per_cpu_int_base +
 356                        ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 357        else
 358                writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
 359        irq_set_status_flags(virq, IRQ_LEVEL);
 360
 361        if (is_percpu_irq(hw)) {
 362                irq_set_percpu_devid(virq);
 363                irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
 364                                        handle_percpu_devid_irq);
 365        } else {
 366                irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
 367                                        handle_level_irq);
 368                irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));
 369        }
 370        irq_set_probe(virq);
 371
 372        return 0;
 373}
 374
 375static void armada_xp_mpic_smp_cpu_init(void)
 376{
 377        u32 control;
 378        int nr_irqs, i;
 379
 380        control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
 381        nr_irqs = (control >> 2) & 0x3ff;
 382
 383        for (i = 0; i < nr_irqs; i++)
 384                writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
 385
 386        /* Clear pending IPIs */
 387        writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
 388
 389        /* Enable first 8 IPIs */
 390        writel(IPI_DOORBELL_MASK, per_cpu_int_base +
 391                ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 392
 393        /* Unmask IPI interrupt */
 394        writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 395}
 396
 397static void armada_xp_mpic_perf_init(void)
 398{
 399        unsigned long cpuid = cpu_logical_map(smp_processor_id());
 400
 401        /* Enable Performance Counter Overflow interrupts */
 402        writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
 403               per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS);
 404}
 405
 406#ifdef CONFIG_SMP
 407static void armada_mpic_send_doorbell(const struct cpumask *mask,
 408                                      unsigned int irq)
 409{
 410        int cpu;
 411        unsigned long map = 0;
 412
 413        /* Convert our logical CPU mask into a physical one. */
 414        for_each_cpu(cpu, mask)
 415                map |= 1 << cpu_logical_map(cpu);
 416
 417        /*
 418         * Ensure that stores to Normal memory are visible to the
 419         * other CPUs before issuing the IPI.
 420         */
 421        dsb();
 422
 423        /* submit softirq */
 424        writel((map << 8) | irq, main_int_base +
 425                ARMADA_370_XP_SW_TRIG_INT_OFFS);
 426}
 427
 428static void armada_xp_mpic_reenable_percpu(void)
 429{
 430        unsigned int irq;
 431
 432        /* Re-enable per-CPU interrupts that were enabled before suspend */
 433        for (irq = 0; irq < ARMADA_370_XP_MAX_PER_CPU_IRQS; irq++) {
 434                struct irq_data *data;
 435                int virq;
 436
 437                virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
 438                if (virq == 0)
 439                        continue;
 440
 441                data = irq_get_irq_data(virq);
 442
 443                if (!irq_percpu_is_enabled(virq))
 444                        continue;
 445
 446                armada_370_xp_irq_unmask(data);
 447        }
 448}
 449
 450static int armada_xp_mpic_starting_cpu(unsigned int cpu)
 451{
 452        armada_xp_mpic_perf_init();
 453        armada_xp_mpic_smp_cpu_init();
 454        armada_xp_mpic_reenable_percpu();
 455        return 0;
 456}
 457
 458static int mpic_cascaded_starting_cpu(unsigned int cpu)
 459{
 460        armada_xp_mpic_perf_init();
 461        armada_xp_mpic_reenable_percpu();
 462        enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
 463        return 0;
 464}
 465#endif
 466
 467static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
 468        .map = armada_370_xp_mpic_irq_map,
 469        .xlate = irq_domain_xlate_onecell,
 470};
 471
 472#ifdef CONFIG_PCI_MSI
 473static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
 474{
 475        u32 msimask, msinr;
 476
 477        msimask = readl_relaxed(per_cpu_int_base +
 478                                ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
 479                & PCI_MSI_DOORBELL_MASK;
 480
 481        writel(~msimask, per_cpu_int_base +
 482               ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
 483
 484        for (msinr = PCI_MSI_DOORBELL_START;
 485             msinr < PCI_MSI_DOORBELL_END; msinr++) {
 486                int irq;
 487
 488                if (!(msimask & BIT(msinr)))
 489                        continue;
 490
 491                if (is_chained) {
 492                        irq = irq_find_mapping(armada_370_xp_msi_inner_domain,
 493                                               msinr - PCI_MSI_DOORBELL_START);
 494                        generic_handle_irq(irq);
 495                } else {
 496                        irq = msinr - PCI_MSI_DOORBELL_START;
 497                        handle_domain_irq(armada_370_xp_msi_inner_domain,
 498                                          irq, regs);
 499                }
 500        }
 501}
 502#else
 503static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
 504#endif
 505
 506static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc)
 507{
 508        struct irq_chip *chip = irq_desc_get_chip(desc);
 509        unsigned long irqmap, irqn, irqsrc, cpuid;
 510        unsigned int cascade_irq;
 511
 512        chained_irq_enter(chip, desc);
 513
 514        irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
 515        cpuid = cpu_logical_map(smp_processor_id());
 516
 517        for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
 518                irqsrc = readl_relaxed(main_int_base +
 519                                       ARMADA_370_XP_INT_SOURCE_CTL(irqn));
 520
 521                /* Check if the interrupt is not masked on current CPU.
 522                 * Test IRQ (0-1) and FIQ (8-9) mask bits.
 523                 */
 524                if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid)))
 525                        continue;
 526
 527                if (irqn == 1) {
 528                        armada_370_xp_handle_msi_irq(NULL, true);
 529                        continue;
 530                }
 531
 532                cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
 533                generic_handle_irq(cascade_irq);
 534        }
 535
 536        chained_irq_exit(chip, desc);
 537}
 538
 539static void __exception_irq_entry
 540armada_370_xp_handle_irq(struct pt_regs *regs)
 541{
 542        u32 irqstat, irqnr;
 543
 544        do {
 545                irqstat = readl_relaxed(per_cpu_int_base +
 546                                        ARMADA_370_XP_CPU_INTACK_OFFS);
 547                irqnr = irqstat & 0x3FF;
 548
 549                if (irqnr > 1022)
 550                        break;
 551
 552                if (irqnr > 1) {
 553                        handle_domain_irq(armada_370_xp_mpic_domain,
 554                                          irqnr, regs);
 555                        continue;
 556                }
 557
 558                /* MSI handling */
 559                if (irqnr == 1)
 560                        armada_370_xp_handle_msi_irq(regs, false);
 561
 562#ifdef CONFIG_SMP
 563                /* IPI Handling */
 564                if (irqnr == 0) {
 565                        u32 ipimask, ipinr;
 566
 567                        ipimask = readl_relaxed(per_cpu_int_base +
 568                                                ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
 569                                & IPI_DOORBELL_MASK;
 570
 571                        writel(~ipimask, per_cpu_int_base +
 572                                ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
 573
 574                        /* Handle all pending doorbells */
 575                        for (ipinr = IPI_DOORBELL_START;
 576                             ipinr < IPI_DOORBELL_END; ipinr++) {
 577                                if (ipimask & (0x1 << ipinr))
 578                                        handle_IPI(ipinr, regs);
 579                        }
 580                        continue;
 581                }
 582#endif
 583
 584        } while (1);
 585}
 586
 587static int armada_370_xp_mpic_suspend(void)
 588{
 589        doorbell_mask_reg = readl(per_cpu_int_base +
 590                                  ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 591        return 0;
 592}
 593
 594static void armada_370_xp_mpic_resume(void)
 595{
 596        int nirqs;
 597        irq_hw_number_t irq;
 598
 599        /* Re-enable interrupts */
 600        nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
 601        for (irq = 0; irq < nirqs; irq++) {
 602                struct irq_data *data;
 603                int virq;
 604
 605                virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
 606                if (virq == 0)
 607                        continue;
 608
 609                data = irq_get_irq_data(virq);
 610
 611                if (!is_percpu_irq(irq)) {
 612                        /* Non per-CPU interrupts */
 613                        writel(irq, per_cpu_int_base +
 614                               ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 615                        if (!irqd_irq_disabled(data))
 616                                armada_370_xp_irq_unmask(data);
 617                } else {
 618                        /* Per-CPU interrupts */
 619                        writel(irq, main_int_base +
 620                               ARMADA_370_XP_INT_SET_ENABLE_OFFS);
 621
 622                        /*
 623                         * Re-enable on the current CPU,
 624                         * armada_xp_mpic_reenable_percpu() will take
 625                         * care of secondary CPUs when they come up.
 626                         */
 627                        if (irq_percpu_is_enabled(virq))
 628                                armada_370_xp_irq_unmask(data);
 629                }
 630        }
 631
 632        /* Reconfigure doorbells for IPIs and MSIs */
 633        writel(doorbell_mask_reg,
 634               per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
 635        if (doorbell_mask_reg & IPI_DOORBELL_MASK)
 636                writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 637        if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
 638                writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
 639}
 640
 641static struct syscore_ops armada_370_xp_mpic_syscore_ops = {
 642        .suspend        = armada_370_xp_mpic_suspend,
 643        .resume         = armada_370_xp_mpic_resume,
 644};
 645
 646static int __init armada_370_xp_mpic_of_init(struct device_node *node,
 647                                             struct device_node *parent)
 648{
 649        struct resource main_int_res, per_cpu_int_res;
 650        int nr_irqs, i;
 651        u32 control;
 652
 653        BUG_ON(of_address_to_resource(node, 0, &main_int_res));
 654        BUG_ON(of_address_to_resource(node, 1, &per_cpu_int_res));
 655
 656        BUG_ON(!request_mem_region(main_int_res.start,
 657                                   resource_size(&main_int_res),
 658                                   node->full_name));
 659        BUG_ON(!request_mem_region(per_cpu_int_res.start,
 660                                   resource_size(&per_cpu_int_res),
 661                                   node->full_name));
 662
 663        main_int_base = ioremap(main_int_res.start,
 664                                resource_size(&main_int_res));
 665        BUG_ON(!main_int_base);
 666
 667        per_cpu_int_base = ioremap(per_cpu_int_res.start,
 668                                   resource_size(&per_cpu_int_res));
 669        BUG_ON(!per_cpu_int_base);
 670
 671        control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
 672        nr_irqs = (control >> 2) & 0x3ff;
 673
 674        for (i = 0; i < nr_irqs; i++)
 675                writel(i, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
 676
 677        armada_370_xp_mpic_domain =
 678                irq_domain_add_linear(node, nr_irqs,
 679                                &armada_370_xp_mpic_irq_ops, NULL);
 680        BUG_ON(!armada_370_xp_mpic_domain);
 681        irq_domain_update_bus_token(armada_370_xp_mpic_domain, DOMAIN_BUS_WIRED);
 682
 683        /* Setup for the boot CPU */
 684        armada_xp_mpic_perf_init();
 685        armada_xp_mpic_smp_cpu_init();
 686
 687        armada_370_xp_msi_init(node, main_int_res.start);
 688
 689        parent_irq = irq_of_parse_and_map(node, 0);
 690        if (parent_irq <= 0) {
 691                irq_set_default_host(armada_370_xp_mpic_domain);
 692                set_handle_irq(armada_370_xp_handle_irq);
 693#ifdef CONFIG_SMP
 694                set_smp_cross_call(armada_mpic_send_doorbell);
 695                cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
 696                                          "irqchip/armada/ipi:starting",
 697                                          armada_xp_mpic_starting_cpu, NULL);
 698#endif
 699        } else {
 700#ifdef CONFIG_SMP
 701                cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
 702                                          "irqchip/armada/cascade:starting",
 703                                          mpic_cascaded_starting_cpu, NULL);
 704#endif
 705                irq_set_chained_handler(parent_irq,
 706                                        armada_370_xp_mpic_handle_cascade_irq);
 707        }
 708
 709        register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
 710
 711        return 0;
 712}
 713
 714IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init);
 715