root/drivers/irqchip/irq-armada-370-xp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_percpu_irq
  2. armada_370_xp_irq_mask
  3. armada_370_xp_irq_unmask
  4. armada_370_xp_compose_msi_msg
  5. armada_370_xp_msi_set_affinity
  6. armada_370_xp_msi_alloc
  7. armada_370_xp_msi_free
  8. armada_370_xp_msi_init
  9. armada_370_xp_msi_init
  10. armada_xp_set_affinity
  11. armada_370_xp_mpic_irq_map
  12. armada_xp_mpic_smp_cpu_init
  13. armada_xp_mpic_perf_init
  14. armada_mpic_send_doorbell
  15. armada_xp_mpic_reenable_percpu
  16. armada_xp_mpic_starting_cpu
  17. mpic_cascaded_starting_cpu
  18. armada_370_xp_handle_msi_irq
  19. armada_370_xp_handle_msi_irq
  20. armada_370_xp_mpic_handle_cascade_irq
  21. armada_370_xp_handle_irq
  22. armada_370_xp_mpic_suspend
  23. armada_370_xp_mpic_resume
  24. armada_370_xp_mpic_of_init

   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 
 146 static void __iomem *per_cpu_int_base;
 147 static void __iomem *main_int_base;
 148 static struct irq_domain *armada_370_xp_mpic_domain;
 149 static u32 doorbell_mask_reg;
 150 static int parent_irq;
 151 #ifdef CONFIG_PCI_MSI
 152 static struct irq_domain *armada_370_xp_msi_domain;
 153 static struct irq_domain *armada_370_xp_msi_inner_domain;
 154 static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
 155 static DEFINE_MUTEX(msi_used_lock);
 156 static phys_addr_t msi_doorbell_addr;
 157 #endif
 158 
 159 static 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  */
 172 static 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 
 184 static 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 
 198 static 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 
 204 static 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 
 210 static 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 
 217 static 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 
 223 static 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 
 229 static 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 
 256 static 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 
 266 static 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 
 271 static 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
 306 static 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
 314 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 315 
 316 static 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 
 339 static 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 
 350 static 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 
 375 static 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 
 397 static 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
 407 static 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 
 428 static 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 
 450 static 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 
 458 static 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 
 467 static 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
 473 static 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
 503 static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
 504 #endif
 505 
 506 static 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 
 539 static void __exception_irq_entry
 540 armada_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 
 587 static 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 
 594 static 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 
 641 static 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 
 646 static 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 
 714 IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init);

/* [<][>][^][v][top][bottom][index][help] */