12be6bb0cSPaul Mundt /* 22be6bb0cSPaul Mundt * Shared interrupt handling code for IPR and INTC2 types of IRQs. 32be6bb0cSPaul Mundt * 42be6bb0cSPaul Mundt * Copyright (C) 2007, 2008 Magnus Damm 5b59f9f97SPaul Mundt * Copyright (C) 2009 - 2012 Paul Mundt 62be6bb0cSPaul Mundt * 72be6bb0cSPaul Mundt * Based on intc2.c and ipr.c 82be6bb0cSPaul Mundt * 92be6bb0cSPaul Mundt * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi 102be6bb0cSPaul Mundt * Copyright (C) 2000 Kazumoto Kojima 112be6bb0cSPaul Mundt * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) 122be6bb0cSPaul Mundt * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> 132be6bb0cSPaul Mundt * Copyright (C) 2005, 2006 Paul Mundt 142be6bb0cSPaul Mundt * 152be6bb0cSPaul Mundt * This file is subject to the terms and conditions of the GNU General Public 162be6bb0cSPaul Mundt * License. See the file "COPYING" in the main directory of this archive 172be6bb0cSPaul Mundt * for more details. 182be6bb0cSPaul Mundt */ 192be6bb0cSPaul Mundt #define pr_fmt(fmt) "intc: " fmt 202be6bb0cSPaul Mundt 212be6bb0cSPaul Mundt #include <linux/init.h> 222be6bb0cSPaul Mundt #include <linux/irq.h> 232be6bb0cSPaul Mundt #include <linux/io.h> 242be6bb0cSPaul Mundt #include <linux/slab.h> 250c43871bSPaul Gortmaker #include <linux/stat.h> 262be6bb0cSPaul Mundt #include <linux/interrupt.h> 272be6bb0cSPaul Mundt #include <linux/sh_intc.h> 281d6a21b0SPaul Mundt #include <linux/irqdomain.h> 29f4e73bfcSKay Sievers #include <linux/device.h> 30a696b89cSRafael J. Wysocki #include <linux/syscore_ops.h> 312be6bb0cSPaul Mundt #include <linux/list.h> 322be6bb0cSPaul Mundt #include <linux/spinlock.h> 332be6bb0cSPaul Mundt #include <linux/radix-tree.h> 34f7be3455SPaul Gortmaker #include <linux/export.h> 35b59f9f97SPaul Mundt #include <linux/sort.h> 362be6bb0cSPaul Mundt #include "internals.h" 372be6bb0cSPaul Mundt 382be6bb0cSPaul Mundt LIST_HEAD(intc_list); 392be6bb0cSPaul Mundt DEFINE_RAW_SPINLOCK(intc_big_lock); 405fbebcbdSPaul Mundt static unsigned int nr_intc_controllers; 412be6bb0cSPaul Mundt 422be6bb0cSPaul Mundt /* 432be6bb0cSPaul Mundt * Default priority level 442be6bb0cSPaul Mundt * - this needs to be at least 2 for 5-bit priorities on 7780 452be6bb0cSPaul Mundt */ 462be6bb0cSPaul Mundt static unsigned int default_prio_level = 2; /* 2 - 16 */ 470f552393SRob Herring static unsigned int intc_prio_level[INTC_NR_IRQS]; /* for now */ 482be6bb0cSPaul Mundt 492be6bb0cSPaul Mundt unsigned int intc_get_dfl_prio_level(void) 502be6bb0cSPaul Mundt { 512be6bb0cSPaul Mundt return default_prio_level; 522be6bb0cSPaul Mundt } 532be6bb0cSPaul Mundt 542be6bb0cSPaul Mundt unsigned int intc_get_prio_level(unsigned int irq) 552be6bb0cSPaul Mundt { 562be6bb0cSPaul Mundt return intc_prio_level[irq]; 572be6bb0cSPaul Mundt } 582be6bb0cSPaul Mundt 592be6bb0cSPaul Mundt void intc_set_prio_level(unsigned int irq, unsigned int level) 602be6bb0cSPaul Mundt { 612be6bb0cSPaul Mundt unsigned long flags; 622be6bb0cSPaul Mundt 632be6bb0cSPaul Mundt raw_spin_lock_irqsave(&intc_big_lock, flags); 642be6bb0cSPaul Mundt intc_prio_level[irq] = level; 652be6bb0cSPaul Mundt raw_spin_unlock_irqrestore(&intc_big_lock, flags); 662be6bb0cSPaul Mundt } 672be6bb0cSPaul Mundt 68bd0b9ac4SThomas Gleixner static void intc_redirect_irq(struct irq_desc *desc) 692be6bb0cSPaul Mundt { 708228a048SJiang Liu generic_handle_irq((unsigned int)irq_desc_get_handler_data(desc)); 712be6bb0cSPaul Mundt } 722be6bb0cSPaul Mundt 732be6bb0cSPaul Mundt static void __init intc_register_irq(struct intc_desc *desc, 742be6bb0cSPaul Mundt struct intc_desc_int *d, 752be6bb0cSPaul Mundt intc_enum enum_id, 762be6bb0cSPaul Mundt unsigned int irq) 772be6bb0cSPaul Mundt { 782be6bb0cSPaul Mundt struct intc_handle_int *hp; 7926599a94SPaul Mundt struct irq_data *irq_data; 802be6bb0cSPaul Mundt unsigned int data[2], primary; 812be6bb0cSPaul Mundt unsigned long flags; 822be6bb0cSPaul Mundt 832be6bb0cSPaul Mundt raw_spin_lock_irqsave(&intc_big_lock, flags); 842be6bb0cSPaul Mundt radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); 852be6bb0cSPaul Mundt raw_spin_unlock_irqrestore(&intc_big_lock, flags); 862be6bb0cSPaul Mundt 872be6bb0cSPaul Mundt /* 882be6bb0cSPaul Mundt * Prefer single interrupt source bitmap over other combinations: 892be6bb0cSPaul Mundt * 902be6bb0cSPaul Mundt * 1. bitmap, single interrupt source 912be6bb0cSPaul Mundt * 2. priority, single interrupt source 922be6bb0cSPaul Mundt * 3. bitmap, multiple interrupt sources (groups) 932be6bb0cSPaul Mundt * 4. priority, multiple interrupt sources (groups) 942be6bb0cSPaul Mundt */ 952be6bb0cSPaul Mundt data[0] = intc_get_mask_handle(desc, d, enum_id, 0); 962be6bb0cSPaul Mundt data[1] = intc_get_prio_handle(desc, d, enum_id, 0); 972be6bb0cSPaul Mundt 982be6bb0cSPaul Mundt primary = 0; 992be6bb0cSPaul Mundt if (!data[0] && data[1]) 1002be6bb0cSPaul Mundt primary = 1; 1012be6bb0cSPaul Mundt 1022be6bb0cSPaul Mundt if (!data[0] && !data[1]) 1032be6bb0cSPaul Mundt pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n", 1042be6bb0cSPaul Mundt irq, irq2evt(irq)); 1052be6bb0cSPaul Mundt 1062be6bb0cSPaul Mundt data[0] = data[0] ? data[0] : intc_get_mask_handle(desc, d, enum_id, 1); 1072be6bb0cSPaul Mundt data[1] = data[1] ? data[1] : intc_get_prio_handle(desc, d, enum_id, 1); 1082be6bb0cSPaul Mundt 1092be6bb0cSPaul Mundt if (!data[primary]) 1102be6bb0cSPaul Mundt primary ^= 1; 1112be6bb0cSPaul Mundt 1122be6bb0cSPaul Mundt BUG_ON(!data[primary]); /* must have primary masking method */ 1132be6bb0cSPaul Mundt 11426599a94SPaul Mundt irq_data = irq_get_irq_data(irq); 11526599a94SPaul Mundt 1162be6bb0cSPaul Mundt disable_irq_nosync(irq); 117fcb8918fSThomas Gleixner irq_set_chip_and_handler_name(irq, &d->chip, handle_level_irq, 118fcb8918fSThomas Gleixner "level"); 119fcb8918fSThomas Gleixner irq_set_chip_data(irq, (void *)data[primary]); 1202be6bb0cSPaul Mundt 1212be6bb0cSPaul Mundt /* 1222be6bb0cSPaul Mundt * set priority level 1232be6bb0cSPaul Mundt */ 1242be6bb0cSPaul Mundt intc_set_prio_level(irq, intc_get_dfl_prio_level()); 1252be6bb0cSPaul Mundt 1262be6bb0cSPaul Mundt /* enable secondary masking method if present */ 1272be6bb0cSPaul Mundt if (data[!primary]) 12826599a94SPaul Mundt _intc_enable(irq_data, data[!primary]); 1292be6bb0cSPaul Mundt 1302be6bb0cSPaul Mundt /* add irq to d->prio list if priority is available */ 1312be6bb0cSPaul Mundt if (data[1]) { 1322be6bb0cSPaul Mundt hp = d->prio + d->nr_prio; 1332be6bb0cSPaul Mundt hp->irq = irq; 1342be6bb0cSPaul Mundt hp->handle = data[1]; 1352be6bb0cSPaul Mundt 1362be6bb0cSPaul Mundt if (primary) { 1372be6bb0cSPaul Mundt /* 1382be6bb0cSPaul Mundt * only secondary priority should access registers, so 1392be6bb0cSPaul Mundt * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() 1402be6bb0cSPaul Mundt */ 1412be6bb0cSPaul Mundt hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); 1422be6bb0cSPaul Mundt hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); 1432be6bb0cSPaul Mundt } 1442be6bb0cSPaul Mundt d->nr_prio++; 1452be6bb0cSPaul Mundt } 1462be6bb0cSPaul Mundt 1472be6bb0cSPaul Mundt /* add irq to d->sense list if sense is available */ 1482be6bb0cSPaul Mundt data[0] = intc_get_sense_handle(desc, d, enum_id); 1492be6bb0cSPaul Mundt if (data[0]) { 1502be6bb0cSPaul Mundt (d->sense + d->nr_sense)->irq = irq; 1512be6bb0cSPaul Mundt (d->sense + d->nr_sense)->handle = data[0]; 1522be6bb0cSPaul Mundt d->nr_sense++; 1532be6bb0cSPaul Mundt } 1542be6bb0cSPaul Mundt 1552be6bb0cSPaul Mundt /* irq should be disabled by default */ 15626599a94SPaul Mundt d->chip.irq_mask(irq_data); 1572be6bb0cSPaul Mundt 1582be6bb0cSPaul Mundt intc_set_ack_handle(irq, desc, d, enum_id); 1592be6bb0cSPaul Mundt intc_set_dist_handle(irq, desc, d, enum_id); 1602be6bb0cSPaul Mundt 1612be6bb0cSPaul Mundt activate_irq(irq); 1622be6bb0cSPaul Mundt } 1632be6bb0cSPaul Mundt 1642be6bb0cSPaul Mundt static unsigned int __init save_reg(struct intc_desc_int *d, 1652be6bb0cSPaul Mundt unsigned int cnt, 1662be6bb0cSPaul Mundt unsigned long value, 1672be6bb0cSPaul Mundt unsigned int smp) 1682be6bb0cSPaul Mundt { 1692be6bb0cSPaul Mundt if (value) { 1702be6bb0cSPaul Mundt value = intc_phys_to_virt(d, value); 1712be6bb0cSPaul Mundt 1722be6bb0cSPaul Mundt d->reg[cnt] = value; 1732be6bb0cSPaul Mundt #ifdef CONFIG_SMP 1742be6bb0cSPaul Mundt d->smp[cnt] = smp; 1752be6bb0cSPaul Mundt #endif 1762be6bb0cSPaul Mundt return 1; 1772be6bb0cSPaul Mundt } 1782be6bb0cSPaul Mundt 1792be6bb0cSPaul Mundt return 0; 1802be6bb0cSPaul Mundt } 1812be6bb0cSPaul Mundt 1822be6bb0cSPaul Mundt int __init register_intc_controller(struct intc_desc *desc) 1832be6bb0cSPaul Mundt { 1842be6bb0cSPaul Mundt unsigned int i, k, smp; 1852be6bb0cSPaul Mundt struct intc_hw_desc *hw = &desc->hw; 1862be6bb0cSPaul Mundt struct intc_desc_int *d; 1872be6bb0cSPaul Mundt struct resource *res; 1882be6bb0cSPaul Mundt 1892be6bb0cSPaul Mundt pr_info("Registered controller '%s' with %u IRQs\n", 1902be6bb0cSPaul Mundt desc->name, hw->nr_vectors); 1912be6bb0cSPaul Mundt 1922be6bb0cSPaul Mundt d = kzalloc(sizeof(*d), GFP_NOWAIT); 1932be6bb0cSPaul Mundt if (!d) 1942be6bb0cSPaul Mundt goto err0; 1952be6bb0cSPaul Mundt 1962be6bb0cSPaul Mundt INIT_LIST_HEAD(&d->list); 1972be6bb0cSPaul Mundt list_add_tail(&d->list, &intc_list); 1982be6bb0cSPaul Mundt 1992be6bb0cSPaul Mundt raw_spin_lock_init(&d->lock); 20030f2ba38SPaul Mundt INIT_RADIX_TREE(&d->tree, GFP_ATOMIC); 2012be6bb0cSPaul Mundt 2022be6bb0cSPaul Mundt d->index = nr_intc_controllers; 2032be6bb0cSPaul Mundt 2042be6bb0cSPaul Mundt if (desc->num_resources) { 2052be6bb0cSPaul Mundt d->nr_windows = desc->num_resources; 2062be6bb0cSPaul Mundt d->window = kzalloc(d->nr_windows * sizeof(*d->window), 2072be6bb0cSPaul Mundt GFP_NOWAIT); 2082be6bb0cSPaul Mundt if (!d->window) 2092be6bb0cSPaul Mundt goto err1; 2102be6bb0cSPaul Mundt 2112be6bb0cSPaul Mundt for (k = 0; k < d->nr_windows; k++) { 2122be6bb0cSPaul Mundt res = desc->resource + k; 2132be6bb0cSPaul Mundt WARN_ON(resource_type(res) != IORESOURCE_MEM); 2142be6bb0cSPaul Mundt d->window[k].phys = res->start; 2152be6bb0cSPaul Mundt d->window[k].size = resource_size(res); 2162be6bb0cSPaul Mundt d->window[k].virt = ioremap_nocache(res->start, 2172be6bb0cSPaul Mundt resource_size(res)); 2182be6bb0cSPaul Mundt if (!d->window[k].virt) 2192be6bb0cSPaul Mundt goto err2; 2202be6bb0cSPaul Mundt } 2212be6bb0cSPaul Mundt } 2222be6bb0cSPaul Mundt 2232be6bb0cSPaul Mundt d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; 2242be6bb0cSPaul Mundt #ifdef CONFIG_INTC_BALANCING 2252be6bb0cSPaul Mundt if (d->nr_reg) 2262be6bb0cSPaul Mundt d->nr_reg += hw->nr_mask_regs; 2272be6bb0cSPaul Mundt #endif 2282be6bb0cSPaul Mundt d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; 2292be6bb0cSPaul Mundt d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; 2302be6bb0cSPaul Mundt d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; 2312be6bb0cSPaul Mundt d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0; 2322be6bb0cSPaul Mundt 2332be6bb0cSPaul Mundt d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); 2342be6bb0cSPaul Mundt if (!d->reg) 2352be6bb0cSPaul Mundt goto err2; 2362be6bb0cSPaul Mundt 2372be6bb0cSPaul Mundt #ifdef CONFIG_SMP 2382be6bb0cSPaul Mundt d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); 2392be6bb0cSPaul Mundt if (!d->smp) 2402be6bb0cSPaul Mundt goto err3; 2412be6bb0cSPaul Mundt #endif 2422be6bb0cSPaul Mundt k = 0; 2432be6bb0cSPaul Mundt 2442be6bb0cSPaul Mundt if (hw->mask_regs) { 2452be6bb0cSPaul Mundt for (i = 0; i < hw->nr_mask_regs; i++) { 2462be6bb0cSPaul Mundt smp = IS_SMP(hw->mask_regs[i]); 2472be6bb0cSPaul Mundt k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); 2482be6bb0cSPaul Mundt k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); 2492be6bb0cSPaul Mundt #ifdef CONFIG_INTC_BALANCING 2502be6bb0cSPaul Mundt k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0); 2512be6bb0cSPaul Mundt #endif 2522be6bb0cSPaul Mundt } 2532be6bb0cSPaul Mundt } 2542be6bb0cSPaul Mundt 2552be6bb0cSPaul Mundt if (hw->prio_regs) { 2562be6bb0cSPaul Mundt d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), 2572be6bb0cSPaul Mundt GFP_NOWAIT); 2582be6bb0cSPaul Mundt if (!d->prio) 2592be6bb0cSPaul Mundt goto err4; 2602be6bb0cSPaul Mundt 2612be6bb0cSPaul Mundt for (i = 0; i < hw->nr_prio_regs; i++) { 2622be6bb0cSPaul Mundt smp = IS_SMP(hw->prio_regs[i]); 2632be6bb0cSPaul Mundt k += save_reg(d, k, hw->prio_regs[i].set_reg, smp); 2642be6bb0cSPaul Mundt k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp); 2652be6bb0cSPaul Mundt } 266b59f9f97SPaul Mundt 267b59f9f97SPaul Mundt sort(d->prio, hw->nr_prio_regs, sizeof(*d->prio), 268b59f9f97SPaul Mundt intc_handle_int_cmp, NULL); 2692be6bb0cSPaul Mundt } 2702be6bb0cSPaul Mundt 2712be6bb0cSPaul Mundt if (hw->sense_regs) { 2722be6bb0cSPaul Mundt d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), 2732be6bb0cSPaul Mundt GFP_NOWAIT); 2742be6bb0cSPaul Mundt if (!d->sense) 2752be6bb0cSPaul Mundt goto err5; 2762be6bb0cSPaul Mundt 2772be6bb0cSPaul Mundt for (i = 0; i < hw->nr_sense_regs; i++) 2782be6bb0cSPaul Mundt k += save_reg(d, k, hw->sense_regs[i].reg, 0); 279b59f9f97SPaul Mundt 280b59f9f97SPaul Mundt sort(d->sense, hw->nr_sense_regs, sizeof(*d->sense), 281b59f9f97SPaul Mundt intc_handle_int_cmp, NULL); 2822be6bb0cSPaul Mundt } 2832be6bb0cSPaul Mundt 2842be6bb0cSPaul Mundt if (hw->subgroups) 2852be6bb0cSPaul Mundt for (i = 0; i < hw->nr_subgroups; i++) 2862be6bb0cSPaul Mundt if (hw->subgroups[i].reg) 2872be6bb0cSPaul Mundt k+= save_reg(d, k, hw->subgroups[i].reg, 0); 2882be6bb0cSPaul Mundt 2892be6bb0cSPaul Mundt memcpy(&d->chip, &intc_irq_chip, sizeof(struct irq_chip)); 2902be6bb0cSPaul Mundt d->chip.name = desc->name; 2912be6bb0cSPaul Mundt 2922be6bb0cSPaul Mundt if (hw->ack_regs) 2932be6bb0cSPaul Mundt for (i = 0; i < hw->nr_ack_regs; i++) 2942be6bb0cSPaul Mundt k += save_reg(d, k, hw->ack_regs[i].set_reg, 0); 2952be6bb0cSPaul Mundt else 29626599a94SPaul Mundt d->chip.irq_mask_ack = d->chip.irq_disable; 2972be6bb0cSPaul Mundt 2982be6bb0cSPaul Mundt /* disable bits matching force_disable before registering irqs */ 2992be6bb0cSPaul Mundt if (desc->force_disable) 3002be6bb0cSPaul Mundt intc_enable_disable_enum(desc, d, desc->force_disable, 0); 3012be6bb0cSPaul Mundt 3022be6bb0cSPaul Mundt /* disable bits matching force_enable before registering irqs */ 3032be6bb0cSPaul Mundt if (desc->force_enable) 3042be6bb0cSPaul Mundt intc_enable_disable_enum(desc, d, desc->force_enable, 0); 3052be6bb0cSPaul Mundt 3062be6bb0cSPaul Mundt BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ 3072be6bb0cSPaul Mundt 3081d6a21b0SPaul Mundt intc_irq_domain_init(d, hw); 3091d6a21b0SPaul Mundt 3102be6bb0cSPaul Mundt /* register the vectors one by one */ 3112be6bb0cSPaul Mundt for (i = 0; i < hw->nr_vectors; i++) { 3122be6bb0cSPaul Mundt struct intc_vect *vect = hw->vectors + i; 3132be6bb0cSPaul Mundt unsigned int irq = evt2irq(vect->vect); 314c4318bafSThomas Gleixner int res; 3152be6bb0cSPaul Mundt 3162be6bb0cSPaul Mundt if (!vect->enum_id) 3172be6bb0cSPaul Mundt continue; 3182be6bb0cSPaul Mundt 3191d6a21b0SPaul Mundt res = irq_create_identity_mapping(d->domain, irq); 3201d6a21b0SPaul Mundt if (unlikely(res)) { 32110260237SPaul Mundt if (res == -EEXIST) { 32210260237SPaul Mundt res = irq_domain_associate(d->domain, irq, irq); 32310260237SPaul Mundt if (unlikely(res)) { 32410260237SPaul Mundt pr_err("domain association failure\n"); 3252be6bb0cSPaul Mundt continue; 3262be6bb0cSPaul Mundt } 32710260237SPaul Mundt } else { 32810260237SPaul Mundt pr_err("can't identity map IRQ %d\n", irq); 32910260237SPaul Mundt continue; 33010260237SPaul Mundt } 33110260237SPaul Mundt } 3322be6bb0cSPaul Mundt 3332be6bb0cSPaul Mundt intc_irq_xlate_set(irq, vect->enum_id, d); 3342be6bb0cSPaul Mundt intc_register_irq(desc, d, vect->enum_id, irq); 3352be6bb0cSPaul Mundt 3362be6bb0cSPaul Mundt for (k = i + 1; k < hw->nr_vectors; k++) { 3372be6bb0cSPaul Mundt struct intc_vect *vect2 = hw->vectors + k; 3382be6bb0cSPaul Mundt unsigned int irq2 = evt2irq(vect2->vect); 3392be6bb0cSPaul Mundt 3402be6bb0cSPaul Mundt if (vect->enum_id != vect2->enum_id) 3412be6bb0cSPaul Mundt continue; 3422be6bb0cSPaul Mundt 3432be6bb0cSPaul Mundt /* 3442be6bb0cSPaul Mundt * In the case of multi-evt handling and sparse 3452be6bb0cSPaul Mundt * IRQ support, each vector still needs to have 3462be6bb0cSPaul Mundt * its own backing irq_desc. 3472be6bb0cSPaul Mundt */ 3481d6a21b0SPaul Mundt res = irq_create_identity_mapping(d->domain, irq2); 3491d6a21b0SPaul Mundt if (unlikely(res)) { 35010260237SPaul Mundt if (res == -EEXIST) { 35110260237SPaul Mundt res = irq_domain_associate(d->domain, 352d4b7c5dbSPaul Mundt irq2, irq2); 35310260237SPaul Mundt if (unlikely(res)) { 35410260237SPaul Mundt pr_err("domain association " 35510260237SPaul Mundt "failure\n"); 3562be6bb0cSPaul Mundt continue; 3572be6bb0cSPaul Mundt } 35810260237SPaul Mundt } else { 35910260237SPaul Mundt pr_err("can't identity map IRQ %d\n", 36010260237SPaul Mundt irq); 36110260237SPaul Mundt continue; 36210260237SPaul Mundt } 36310260237SPaul Mundt } 3642be6bb0cSPaul Mundt 3652be6bb0cSPaul Mundt vect2->enum_id = 0; 3662be6bb0cSPaul Mundt 3672be6bb0cSPaul Mundt /* redirect this interrupts to the first one */ 368fcb8918fSThomas Gleixner irq_set_chip(irq2, &dummy_irq_chip); 36951b971b1SThomas Gleixner irq_set_chained_handler_and_data(irq2, 37051b971b1SThomas Gleixner intc_redirect_irq, 37151b971b1SThomas Gleixner (void *)irq); 3722be6bb0cSPaul Mundt } 3732be6bb0cSPaul Mundt } 3742be6bb0cSPaul Mundt 3752be6bb0cSPaul Mundt intc_subgroup_init(desc, d); 3762be6bb0cSPaul Mundt 3772be6bb0cSPaul Mundt /* enable bits matching force_enable after registering irqs */ 3782be6bb0cSPaul Mundt if (desc->force_enable) 3792be6bb0cSPaul Mundt intc_enable_disable_enum(desc, d, desc->force_enable, 1); 3802be6bb0cSPaul Mundt 3810f966d74SRafael J. Wysocki d->skip_suspend = desc->skip_syscore_suspend; 3820f966d74SRafael J. Wysocki 3832be6bb0cSPaul Mundt nr_intc_controllers++; 3842be6bb0cSPaul Mundt 3852be6bb0cSPaul Mundt return 0; 3862be6bb0cSPaul Mundt err5: 3872be6bb0cSPaul Mundt kfree(d->prio); 3882be6bb0cSPaul Mundt err4: 3892be6bb0cSPaul Mundt #ifdef CONFIG_SMP 3902be6bb0cSPaul Mundt kfree(d->smp); 3912be6bb0cSPaul Mundt err3: 3922be6bb0cSPaul Mundt #endif 3932be6bb0cSPaul Mundt kfree(d->reg); 3942be6bb0cSPaul Mundt err2: 3952be6bb0cSPaul Mundt for (k = 0; k < d->nr_windows; k++) 3962be6bb0cSPaul Mundt if (d->window[k].virt) 3972be6bb0cSPaul Mundt iounmap(d->window[k].virt); 3982be6bb0cSPaul Mundt 3992be6bb0cSPaul Mundt kfree(d->window); 4002be6bb0cSPaul Mundt err1: 4012be6bb0cSPaul Mundt kfree(d); 4022be6bb0cSPaul Mundt err0: 4032be6bb0cSPaul Mundt pr_err("unable to allocate INTC memory\n"); 4042be6bb0cSPaul Mundt 4052be6bb0cSPaul Mundt return -ENOMEM; 4062be6bb0cSPaul Mundt } 4072be6bb0cSPaul Mundt 408a696b89cSRafael J. Wysocki static int intc_suspend(void) 409a696b89cSRafael J. Wysocki { 410a696b89cSRafael J. Wysocki struct intc_desc_int *d; 411a696b89cSRafael J. Wysocki 412a696b89cSRafael J. Wysocki list_for_each_entry(d, &intc_list, list) { 413a696b89cSRafael J. Wysocki int irq; 414a696b89cSRafael J. Wysocki 4150f966d74SRafael J. Wysocki if (d->skip_suspend) 4160f966d74SRafael J. Wysocki continue; 4170f966d74SRafael J. Wysocki 418a696b89cSRafael J. Wysocki /* enable wakeup irqs belonging to this intc controller */ 419a696b89cSRafael J. Wysocki for_each_active_irq(irq) { 420a696b89cSRafael J. Wysocki struct irq_data *data; 421a696b89cSRafael J. Wysocki struct irq_chip *chip; 422a696b89cSRafael J. Wysocki 423a696b89cSRafael J. Wysocki data = irq_get_irq_data(irq); 424a696b89cSRafael J. Wysocki chip = irq_data_get_irq_chip(data); 425a696b89cSRafael J. Wysocki if (chip != &d->chip) 426a696b89cSRafael J. Wysocki continue; 427a821b279SThomas Gleixner if (irqd_is_wakeup_set(data)) 428a696b89cSRafael J. Wysocki chip->irq_enable(data); 429a696b89cSRafael J. Wysocki } 430a696b89cSRafael J. Wysocki } 431a696b89cSRafael J. Wysocki return 0; 432a696b89cSRafael J. Wysocki } 433a696b89cSRafael J. Wysocki 434a696b89cSRafael J. Wysocki static void intc_resume(void) 435a696b89cSRafael J. Wysocki { 436a696b89cSRafael J. Wysocki struct intc_desc_int *d; 437a696b89cSRafael J. Wysocki 438a696b89cSRafael J. Wysocki list_for_each_entry(d, &intc_list, list) { 439a696b89cSRafael J. Wysocki int irq; 440a696b89cSRafael J. Wysocki 4410f966d74SRafael J. Wysocki if (d->skip_suspend) 4420f966d74SRafael J. Wysocki continue; 4430f966d74SRafael J. Wysocki 444a696b89cSRafael J. Wysocki for_each_active_irq(irq) { 445a696b89cSRafael J. Wysocki struct irq_data *data; 446a696b89cSRafael J. Wysocki struct irq_chip *chip; 447a696b89cSRafael J. Wysocki 448a696b89cSRafael J. Wysocki data = irq_get_irq_data(irq); 449a696b89cSRafael J. Wysocki chip = irq_data_get_irq_chip(data); 450a696b89cSRafael J. Wysocki /* 451a696b89cSRafael J. Wysocki * This will catch the redirect and VIRQ cases 452a696b89cSRafael J. Wysocki * due to the dummy_irq_chip being inserted. 453a696b89cSRafael J. Wysocki */ 454a696b89cSRafael J. Wysocki if (chip != &d->chip) 455a696b89cSRafael J. Wysocki continue; 456a821b279SThomas Gleixner if (irqd_irq_disabled(data)) 457a696b89cSRafael J. Wysocki chip->irq_disable(data); 458a696b89cSRafael J. Wysocki else 459a696b89cSRafael J. Wysocki chip->irq_enable(data); 460a696b89cSRafael J. Wysocki } 461a696b89cSRafael J. Wysocki } 462a696b89cSRafael J. Wysocki } 463a696b89cSRafael J. Wysocki 464a696b89cSRafael J. Wysocki struct syscore_ops intc_syscore_ops = { 465a696b89cSRafael J. Wysocki .suspend = intc_suspend, 466a696b89cSRafael J. Wysocki .resume = intc_resume, 467a696b89cSRafael J. Wysocki }; 468a696b89cSRafael J. Wysocki 469f4e73bfcSKay Sievers struct bus_type intc_subsys = { 470a696b89cSRafael J. Wysocki .name = "intc", 471f4e73bfcSKay Sievers .dev_name = "intc", 472a696b89cSRafael J. Wysocki }; 473a696b89cSRafael J. Wysocki 4742be6bb0cSPaul Mundt static ssize_t 475f4e73bfcSKay Sievers show_intc_name(struct device *dev, struct device_attribute *attr, char *buf) 4762be6bb0cSPaul Mundt { 4772be6bb0cSPaul Mundt struct intc_desc_int *d; 4782be6bb0cSPaul Mundt 479f4e73bfcSKay Sievers d = container_of(dev, struct intc_desc_int, dev); 4802be6bb0cSPaul Mundt 4812be6bb0cSPaul Mundt return sprintf(buf, "%s\n", d->chip.name); 4822be6bb0cSPaul Mundt } 4832be6bb0cSPaul Mundt 484f4e73bfcSKay Sievers static DEVICE_ATTR(name, S_IRUGO, show_intc_name, NULL); 4852be6bb0cSPaul Mundt 486f4e73bfcSKay Sievers static int __init register_intc_devs(void) 4872be6bb0cSPaul Mundt { 4882be6bb0cSPaul Mundt struct intc_desc_int *d; 4892be6bb0cSPaul Mundt int error; 4902be6bb0cSPaul Mundt 491a696b89cSRafael J. Wysocki register_syscore_ops(&intc_syscore_ops); 492a696b89cSRafael J. Wysocki 493f4e73bfcSKay Sievers error = subsys_system_register(&intc_subsys, NULL); 4942be6bb0cSPaul Mundt if (!error) { 4952be6bb0cSPaul Mundt list_for_each_entry(d, &intc_list, list) { 496f4e73bfcSKay Sievers d->dev.id = d->index; 497f4e73bfcSKay Sievers d->dev.bus = &intc_subsys; 498f4e73bfcSKay Sievers error = device_register(&d->dev); 4992be6bb0cSPaul Mundt if (error == 0) 500f4e73bfcSKay Sievers error = device_create_file(&d->dev, 501f4e73bfcSKay Sievers &dev_attr_name); 5022be6bb0cSPaul Mundt if (error) 5032be6bb0cSPaul Mundt break; 5042be6bb0cSPaul Mundt } 5052be6bb0cSPaul Mundt } 5062be6bb0cSPaul Mundt 5072be6bb0cSPaul Mundt if (error) 508f4e73bfcSKay Sievers pr_err("device registration error\n"); 5092be6bb0cSPaul Mundt 5102be6bb0cSPaul Mundt return error; 5112be6bb0cSPaul Mundt } 512f4e73bfcSKay Sievers device_initcall(register_intc_devs); 513