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 52be6bb0cSPaul Mundt * Copyright (C) 2009, 2010 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> 282be6bb0cSPaul Mundt #include <linux/sysdev.h> 29a696b89cSRafael J. Wysocki #include <linux/syscore_ops.h> 302be6bb0cSPaul Mundt #include <linux/list.h> 312be6bb0cSPaul Mundt #include <linux/spinlock.h> 322be6bb0cSPaul Mundt #include <linux/radix-tree.h> 33f7be3455SPaul Gortmaker #include <linux/export.h> 342be6bb0cSPaul Mundt #include "internals.h" 352be6bb0cSPaul Mundt 362be6bb0cSPaul Mundt LIST_HEAD(intc_list); 372be6bb0cSPaul Mundt DEFINE_RAW_SPINLOCK(intc_big_lock); 382be6bb0cSPaul Mundt unsigned int nr_intc_controllers; 392be6bb0cSPaul Mundt 402be6bb0cSPaul Mundt /* 412be6bb0cSPaul Mundt * Default priority level 422be6bb0cSPaul Mundt * - this needs to be at least 2 for 5-bit priorities on 7780 432be6bb0cSPaul Mundt */ 442be6bb0cSPaul Mundt static unsigned int default_prio_level = 2; /* 2 - 16 */ 452be6bb0cSPaul Mundt static unsigned int intc_prio_level[NR_IRQS]; /* for now */ 462be6bb0cSPaul Mundt 472be6bb0cSPaul Mundt unsigned int intc_get_dfl_prio_level(void) 482be6bb0cSPaul Mundt { 492be6bb0cSPaul Mundt return default_prio_level; 502be6bb0cSPaul Mundt } 512be6bb0cSPaul Mundt 522be6bb0cSPaul Mundt unsigned int intc_get_prio_level(unsigned int irq) 532be6bb0cSPaul Mundt { 542be6bb0cSPaul Mundt return intc_prio_level[irq]; 552be6bb0cSPaul Mundt } 562be6bb0cSPaul Mundt 572be6bb0cSPaul Mundt void intc_set_prio_level(unsigned int irq, unsigned int level) 582be6bb0cSPaul Mundt { 592be6bb0cSPaul Mundt unsigned long flags; 602be6bb0cSPaul Mundt 612be6bb0cSPaul Mundt raw_spin_lock_irqsave(&intc_big_lock, flags); 622be6bb0cSPaul Mundt intc_prio_level[irq] = level; 632be6bb0cSPaul Mundt raw_spin_unlock_irqrestore(&intc_big_lock, flags); 642be6bb0cSPaul Mundt } 652be6bb0cSPaul Mundt 662be6bb0cSPaul Mundt static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) 672be6bb0cSPaul Mundt { 68fcb8918fSThomas Gleixner generic_handle_irq((unsigned int)irq_get_handler_data(irq)); 692be6bb0cSPaul Mundt } 702be6bb0cSPaul Mundt 712be6bb0cSPaul Mundt static void __init intc_register_irq(struct intc_desc *desc, 722be6bb0cSPaul Mundt struct intc_desc_int *d, 732be6bb0cSPaul Mundt intc_enum enum_id, 742be6bb0cSPaul Mundt unsigned int irq) 752be6bb0cSPaul Mundt { 762be6bb0cSPaul Mundt struct intc_handle_int *hp; 7726599a94SPaul Mundt struct irq_data *irq_data; 782be6bb0cSPaul Mundt unsigned int data[2], primary; 792be6bb0cSPaul Mundt unsigned long flags; 802be6bb0cSPaul Mundt 812be6bb0cSPaul Mundt /* 822be6bb0cSPaul Mundt * Register the IRQ position with the global IRQ map, then insert 832be6bb0cSPaul Mundt * it in to the radix tree. 842be6bb0cSPaul Mundt */ 8520f95e0bSPaul Mundt irq_reserve_irq(irq); 862be6bb0cSPaul Mundt 872be6bb0cSPaul Mundt raw_spin_lock_irqsave(&intc_big_lock, flags); 882be6bb0cSPaul Mundt radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq)); 892be6bb0cSPaul Mundt raw_spin_unlock_irqrestore(&intc_big_lock, flags); 902be6bb0cSPaul Mundt 912be6bb0cSPaul Mundt /* 922be6bb0cSPaul Mundt * Prefer single interrupt source bitmap over other combinations: 932be6bb0cSPaul Mundt * 942be6bb0cSPaul Mundt * 1. bitmap, single interrupt source 952be6bb0cSPaul Mundt * 2. priority, single interrupt source 962be6bb0cSPaul Mundt * 3. bitmap, multiple interrupt sources (groups) 972be6bb0cSPaul Mundt * 4. priority, multiple interrupt sources (groups) 982be6bb0cSPaul Mundt */ 992be6bb0cSPaul Mundt data[0] = intc_get_mask_handle(desc, d, enum_id, 0); 1002be6bb0cSPaul Mundt data[1] = intc_get_prio_handle(desc, d, enum_id, 0); 1012be6bb0cSPaul Mundt 1022be6bb0cSPaul Mundt primary = 0; 1032be6bb0cSPaul Mundt if (!data[0] && data[1]) 1042be6bb0cSPaul Mundt primary = 1; 1052be6bb0cSPaul Mundt 1062be6bb0cSPaul Mundt if (!data[0] && !data[1]) 1072be6bb0cSPaul Mundt pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n", 1082be6bb0cSPaul Mundt irq, irq2evt(irq)); 1092be6bb0cSPaul Mundt 1102be6bb0cSPaul Mundt data[0] = data[0] ? data[0] : intc_get_mask_handle(desc, d, enum_id, 1); 1112be6bb0cSPaul Mundt data[1] = data[1] ? data[1] : intc_get_prio_handle(desc, d, enum_id, 1); 1122be6bb0cSPaul Mundt 1132be6bb0cSPaul Mundt if (!data[primary]) 1142be6bb0cSPaul Mundt primary ^= 1; 1152be6bb0cSPaul Mundt 1162be6bb0cSPaul Mundt BUG_ON(!data[primary]); /* must have primary masking method */ 1172be6bb0cSPaul Mundt 11826599a94SPaul Mundt irq_data = irq_get_irq_data(irq); 11926599a94SPaul Mundt 1202be6bb0cSPaul Mundt disable_irq_nosync(irq); 121fcb8918fSThomas Gleixner irq_set_chip_and_handler_name(irq, &d->chip, handle_level_irq, 122fcb8918fSThomas Gleixner "level"); 123fcb8918fSThomas Gleixner irq_set_chip_data(irq, (void *)data[primary]); 1242be6bb0cSPaul Mundt 1252be6bb0cSPaul Mundt /* 1262be6bb0cSPaul Mundt * set priority level 1272be6bb0cSPaul Mundt */ 1282be6bb0cSPaul Mundt intc_set_prio_level(irq, intc_get_dfl_prio_level()); 1292be6bb0cSPaul Mundt 1302be6bb0cSPaul Mundt /* enable secondary masking method if present */ 1312be6bb0cSPaul Mundt if (data[!primary]) 13226599a94SPaul Mundt _intc_enable(irq_data, data[!primary]); 1332be6bb0cSPaul Mundt 1342be6bb0cSPaul Mundt /* add irq to d->prio list if priority is available */ 1352be6bb0cSPaul Mundt if (data[1]) { 1362be6bb0cSPaul Mundt hp = d->prio + d->nr_prio; 1372be6bb0cSPaul Mundt hp->irq = irq; 1382be6bb0cSPaul Mundt hp->handle = data[1]; 1392be6bb0cSPaul Mundt 1402be6bb0cSPaul Mundt if (primary) { 1412be6bb0cSPaul Mundt /* 1422be6bb0cSPaul Mundt * only secondary priority should access registers, so 1432be6bb0cSPaul Mundt * set _INTC_FN(h) = REG_FN_ERR for intc_set_priority() 1442be6bb0cSPaul Mundt */ 1452be6bb0cSPaul Mundt hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0); 1462be6bb0cSPaul Mundt hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0); 1472be6bb0cSPaul Mundt } 1482be6bb0cSPaul Mundt d->nr_prio++; 1492be6bb0cSPaul Mundt } 1502be6bb0cSPaul Mundt 1512be6bb0cSPaul Mundt /* add irq to d->sense list if sense is available */ 1522be6bb0cSPaul Mundt data[0] = intc_get_sense_handle(desc, d, enum_id); 1532be6bb0cSPaul Mundt if (data[0]) { 1542be6bb0cSPaul Mundt (d->sense + d->nr_sense)->irq = irq; 1552be6bb0cSPaul Mundt (d->sense + d->nr_sense)->handle = data[0]; 1562be6bb0cSPaul Mundt d->nr_sense++; 1572be6bb0cSPaul Mundt } 1582be6bb0cSPaul Mundt 1592be6bb0cSPaul Mundt /* irq should be disabled by default */ 16026599a94SPaul Mundt d->chip.irq_mask(irq_data); 1612be6bb0cSPaul Mundt 1622be6bb0cSPaul Mundt intc_set_ack_handle(irq, desc, d, enum_id); 1632be6bb0cSPaul Mundt intc_set_dist_handle(irq, desc, d, enum_id); 1642be6bb0cSPaul Mundt 1652be6bb0cSPaul Mundt activate_irq(irq); 1662be6bb0cSPaul Mundt } 1672be6bb0cSPaul Mundt 1682be6bb0cSPaul Mundt static unsigned int __init save_reg(struct intc_desc_int *d, 1692be6bb0cSPaul Mundt unsigned int cnt, 1702be6bb0cSPaul Mundt unsigned long value, 1712be6bb0cSPaul Mundt unsigned int smp) 1722be6bb0cSPaul Mundt { 1732be6bb0cSPaul Mundt if (value) { 1742be6bb0cSPaul Mundt value = intc_phys_to_virt(d, value); 1752be6bb0cSPaul Mundt 1762be6bb0cSPaul Mundt d->reg[cnt] = value; 1772be6bb0cSPaul Mundt #ifdef CONFIG_SMP 1782be6bb0cSPaul Mundt d->smp[cnt] = smp; 1792be6bb0cSPaul Mundt #endif 1802be6bb0cSPaul Mundt return 1; 1812be6bb0cSPaul Mundt } 1822be6bb0cSPaul Mundt 1832be6bb0cSPaul Mundt return 0; 1842be6bb0cSPaul Mundt } 1852be6bb0cSPaul Mundt 1862be6bb0cSPaul Mundt int __init register_intc_controller(struct intc_desc *desc) 1872be6bb0cSPaul Mundt { 1882be6bb0cSPaul Mundt unsigned int i, k, smp; 1892be6bb0cSPaul Mundt struct intc_hw_desc *hw = &desc->hw; 1902be6bb0cSPaul Mundt struct intc_desc_int *d; 1912be6bb0cSPaul Mundt struct resource *res; 1922be6bb0cSPaul Mundt 1932be6bb0cSPaul Mundt pr_info("Registered controller '%s' with %u IRQs\n", 1942be6bb0cSPaul Mundt desc->name, hw->nr_vectors); 1952be6bb0cSPaul Mundt 1962be6bb0cSPaul Mundt d = kzalloc(sizeof(*d), GFP_NOWAIT); 1972be6bb0cSPaul Mundt if (!d) 1982be6bb0cSPaul Mundt goto err0; 1992be6bb0cSPaul Mundt 2002be6bb0cSPaul Mundt INIT_LIST_HEAD(&d->list); 2012be6bb0cSPaul Mundt list_add_tail(&d->list, &intc_list); 2022be6bb0cSPaul Mundt 2032be6bb0cSPaul Mundt raw_spin_lock_init(&d->lock); 20430f2ba38SPaul Mundt INIT_RADIX_TREE(&d->tree, GFP_ATOMIC); 2052be6bb0cSPaul Mundt 2062be6bb0cSPaul Mundt d->index = nr_intc_controllers; 2072be6bb0cSPaul Mundt 2082be6bb0cSPaul Mundt if (desc->num_resources) { 2092be6bb0cSPaul Mundt d->nr_windows = desc->num_resources; 2102be6bb0cSPaul Mundt d->window = kzalloc(d->nr_windows * sizeof(*d->window), 2112be6bb0cSPaul Mundt GFP_NOWAIT); 2122be6bb0cSPaul Mundt if (!d->window) 2132be6bb0cSPaul Mundt goto err1; 2142be6bb0cSPaul Mundt 2152be6bb0cSPaul Mundt for (k = 0; k < d->nr_windows; k++) { 2162be6bb0cSPaul Mundt res = desc->resource + k; 2172be6bb0cSPaul Mundt WARN_ON(resource_type(res) != IORESOURCE_MEM); 2182be6bb0cSPaul Mundt d->window[k].phys = res->start; 2192be6bb0cSPaul Mundt d->window[k].size = resource_size(res); 2202be6bb0cSPaul Mundt d->window[k].virt = ioremap_nocache(res->start, 2212be6bb0cSPaul Mundt resource_size(res)); 2222be6bb0cSPaul Mundt if (!d->window[k].virt) 2232be6bb0cSPaul Mundt goto err2; 2242be6bb0cSPaul Mundt } 2252be6bb0cSPaul Mundt } 2262be6bb0cSPaul Mundt 2272be6bb0cSPaul Mundt d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; 2282be6bb0cSPaul Mundt #ifdef CONFIG_INTC_BALANCING 2292be6bb0cSPaul Mundt if (d->nr_reg) 2302be6bb0cSPaul Mundt d->nr_reg += hw->nr_mask_regs; 2312be6bb0cSPaul Mundt #endif 2322be6bb0cSPaul Mundt d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; 2332be6bb0cSPaul Mundt d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; 2342be6bb0cSPaul Mundt d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; 2352be6bb0cSPaul Mundt d->nr_reg += hw->subgroups ? hw->nr_subgroups : 0; 2362be6bb0cSPaul Mundt 2372be6bb0cSPaul Mundt d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); 2382be6bb0cSPaul Mundt if (!d->reg) 2392be6bb0cSPaul Mundt goto err2; 2402be6bb0cSPaul Mundt 2412be6bb0cSPaul Mundt #ifdef CONFIG_SMP 2422be6bb0cSPaul Mundt d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); 2432be6bb0cSPaul Mundt if (!d->smp) 2442be6bb0cSPaul Mundt goto err3; 2452be6bb0cSPaul Mundt #endif 2462be6bb0cSPaul Mundt k = 0; 2472be6bb0cSPaul Mundt 2482be6bb0cSPaul Mundt if (hw->mask_regs) { 2492be6bb0cSPaul Mundt for (i = 0; i < hw->nr_mask_regs; i++) { 2502be6bb0cSPaul Mundt smp = IS_SMP(hw->mask_regs[i]); 2512be6bb0cSPaul Mundt k += save_reg(d, k, hw->mask_regs[i].set_reg, smp); 2522be6bb0cSPaul Mundt k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp); 2532be6bb0cSPaul Mundt #ifdef CONFIG_INTC_BALANCING 2542be6bb0cSPaul Mundt k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0); 2552be6bb0cSPaul Mundt #endif 2562be6bb0cSPaul Mundt } 2572be6bb0cSPaul Mundt } 2582be6bb0cSPaul Mundt 2592be6bb0cSPaul Mundt if (hw->prio_regs) { 2602be6bb0cSPaul Mundt d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), 2612be6bb0cSPaul Mundt GFP_NOWAIT); 2622be6bb0cSPaul Mundt if (!d->prio) 2632be6bb0cSPaul Mundt goto err4; 2642be6bb0cSPaul Mundt 2652be6bb0cSPaul Mundt for (i = 0; i < hw->nr_prio_regs; i++) { 2662be6bb0cSPaul Mundt smp = IS_SMP(hw->prio_regs[i]); 2672be6bb0cSPaul Mundt k += save_reg(d, k, hw->prio_regs[i].set_reg, smp); 2682be6bb0cSPaul Mundt k += save_reg(d, k, hw->prio_regs[i].clr_reg, smp); 2692be6bb0cSPaul Mundt } 2702be6bb0cSPaul Mundt } 2712be6bb0cSPaul Mundt 2722be6bb0cSPaul Mundt if (hw->sense_regs) { 2732be6bb0cSPaul Mundt d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), 2742be6bb0cSPaul Mundt GFP_NOWAIT); 2752be6bb0cSPaul Mundt if (!d->sense) 2762be6bb0cSPaul Mundt goto err5; 2772be6bb0cSPaul Mundt 2782be6bb0cSPaul Mundt for (i = 0; i < hw->nr_sense_regs; i++) 2792be6bb0cSPaul Mundt k += save_reg(d, k, hw->sense_regs[i].reg, 0); 2802be6bb0cSPaul Mundt } 2812be6bb0cSPaul Mundt 2822be6bb0cSPaul Mundt if (hw->subgroups) 2832be6bb0cSPaul Mundt for (i = 0; i < hw->nr_subgroups; i++) 2842be6bb0cSPaul Mundt if (hw->subgroups[i].reg) 2852be6bb0cSPaul Mundt k+= save_reg(d, k, hw->subgroups[i].reg, 0); 2862be6bb0cSPaul Mundt 2872be6bb0cSPaul Mundt memcpy(&d->chip, &intc_irq_chip, sizeof(struct irq_chip)); 2882be6bb0cSPaul Mundt d->chip.name = desc->name; 2892be6bb0cSPaul Mundt 2902be6bb0cSPaul Mundt if (hw->ack_regs) 2912be6bb0cSPaul Mundt for (i = 0; i < hw->nr_ack_regs; i++) 2922be6bb0cSPaul Mundt k += save_reg(d, k, hw->ack_regs[i].set_reg, 0); 2932be6bb0cSPaul Mundt else 29426599a94SPaul Mundt d->chip.irq_mask_ack = d->chip.irq_disable; 2952be6bb0cSPaul Mundt 2962be6bb0cSPaul Mundt /* disable bits matching force_disable before registering irqs */ 2972be6bb0cSPaul Mundt if (desc->force_disable) 2982be6bb0cSPaul Mundt intc_enable_disable_enum(desc, d, desc->force_disable, 0); 2992be6bb0cSPaul Mundt 3002be6bb0cSPaul Mundt /* disable bits matching force_enable before registering irqs */ 3012be6bb0cSPaul Mundt if (desc->force_enable) 3022be6bb0cSPaul Mundt intc_enable_disable_enum(desc, d, desc->force_enable, 0); 3032be6bb0cSPaul Mundt 3042be6bb0cSPaul Mundt BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ 3052be6bb0cSPaul Mundt 3062be6bb0cSPaul Mundt /* register the vectors one by one */ 3072be6bb0cSPaul Mundt for (i = 0; i < hw->nr_vectors; i++) { 3082be6bb0cSPaul Mundt struct intc_vect *vect = hw->vectors + i; 3092be6bb0cSPaul Mundt unsigned int irq = evt2irq(vect->vect); 310c4318bafSThomas Gleixner int res; 3112be6bb0cSPaul Mundt 3122be6bb0cSPaul Mundt if (!vect->enum_id) 3132be6bb0cSPaul Mundt continue; 3142be6bb0cSPaul Mundt 315c4318bafSThomas Gleixner res = irq_alloc_desc_at(irq, numa_node_id()); 316c4318bafSThomas Gleixner if (res != irq && res != -EEXIST) { 3172be6bb0cSPaul Mundt pr_err("can't get irq_desc for %d\n", irq); 3182be6bb0cSPaul Mundt continue; 3192be6bb0cSPaul Mundt } 3202be6bb0cSPaul Mundt 3212be6bb0cSPaul Mundt intc_irq_xlate_set(irq, vect->enum_id, d); 3222be6bb0cSPaul Mundt intc_register_irq(desc, d, vect->enum_id, irq); 3232be6bb0cSPaul Mundt 3242be6bb0cSPaul Mundt for (k = i + 1; k < hw->nr_vectors; k++) { 3252be6bb0cSPaul Mundt struct intc_vect *vect2 = hw->vectors + k; 3262be6bb0cSPaul Mundt unsigned int irq2 = evt2irq(vect2->vect); 3272be6bb0cSPaul Mundt 3282be6bb0cSPaul Mundt if (vect->enum_id != vect2->enum_id) 3292be6bb0cSPaul Mundt continue; 3302be6bb0cSPaul Mundt 3312be6bb0cSPaul Mundt /* 3322be6bb0cSPaul Mundt * In the case of multi-evt handling and sparse 3332be6bb0cSPaul Mundt * IRQ support, each vector still needs to have 3342be6bb0cSPaul Mundt * its own backing irq_desc. 3352be6bb0cSPaul Mundt */ 336c4318bafSThomas Gleixner res = irq_alloc_desc_at(irq2, numa_node_id()); 337c4318bafSThomas Gleixner if (res != irq2 && res != -EEXIST) { 3382be6bb0cSPaul Mundt pr_err("can't get irq_desc for %d\n", irq2); 3392be6bb0cSPaul Mundt continue; 3402be6bb0cSPaul Mundt } 3412be6bb0cSPaul Mundt 3422be6bb0cSPaul Mundt vect2->enum_id = 0; 3432be6bb0cSPaul Mundt 3442be6bb0cSPaul Mundt /* redirect this interrupts to the first one */ 345fcb8918fSThomas Gleixner irq_set_chip(irq2, &dummy_irq_chip); 346fcb8918fSThomas Gleixner irq_set_chained_handler(irq2, intc_redirect_irq); 347fcb8918fSThomas Gleixner irq_set_handler_data(irq2, (void *)irq); 3482be6bb0cSPaul Mundt } 3492be6bb0cSPaul Mundt } 3502be6bb0cSPaul Mundt 3512be6bb0cSPaul Mundt intc_subgroup_init(desc, d); 3522be6bb0cSPaul Mundt 3532be6bb0cSPaul Mundt /* enable bits matching force_enable after registering irqs */ 3542be6bb0cSPaul Mundt if (desc->force_enable) 3552be6bb0cSPaul Mundt intc_enable_disable_enum(desc, d, desc->force_enable, 1); 3562be6bb0cSPaul Mundt 3572be6bb0cSPaul Mundt nr_intc_controllers++; 3582be6bb0cSPaul Mundt 3592be6bb0cSPaul Mundt return 0; 3602be6bb0cSPaul Mundt err5: 3612be6bb0cSPaul Mundt kfree(d->prio); 3622be6bb0cSPaul Mundt err4: 3632be6bb0cSPaul Mundt #ifdef CONFIG_SMP 3642be6bb0cSPaul Mundt kfree(d->smp); 3652be6bb0cSPaul Mundt err3: 3662be6bb0cSPaul Mundt #endif 3672be6bb0cSPaul Mundt kfree(d->reg); 3682be6bb0cSPaul Mundt err2: 3692be6bb0cSPaul Mundt for (k = 0; k < d->nr_windows; k++) 3702be6bb0cSPaul Mundt if (d->window[k].virt) 3712be6bb0cSPaul Mundt iounmap(d->window[k].virt); 3722be6bb0cSPaul Mundt 3732be6bb0cSPaul Mundt kfree(d->window); 3742be6bb0cSPaul Mundt err1: 3752be6bb0cSPaul Mundt kfree(d); 3762be6bb0cSPaul Mundt err0: 3772be6bb0cSPaul Mundt pr_err("unable to allocate INTC memory\n"); 3782be6bb0cSPaul Mundt 3792be6bb0cSPaul Mundt return -ENOMEM; 3802be6bb0cSPaul Mundt } 3812be6bb0cSPaul Mundt 382a696b89cSRafael J. Wysocki static int intc_suspend(void) 383a696b89cSRafael J. Wysocki { 384a696b89cSRafael J. Wysocki struct intc_desc_int *d; 385a696b89cSRafael J. Wysocki 386a696b89cSRafael J. Wysocki list_for_each_entry(d, &intc_list, list) { 387a696b89cSRafael J. Wysocki int irq; 388a696b89cSRafael J. Wysocki 389a696b89cSRafael J. Wysocki /* enable wakeup irqs belonging to this intc controller */ 390a696b89cSRafael J. Wysocki for_each_active_irq(irq) { 391a696b89cSRafael J. Wysocki struct irq_data *data; 392a696b89cSRafael J. Wysocki struct irq_chip *chip; 393a696b89cSRafael J. Wysocki 394a696b89cSRafael J. Wysocki data = irq_get_irq_data(irq); 395a696b89cSRafael J. Wysocki chip = irq_data_get_irq_chip(data); 396a696b89cSRafael J. Wysocki if (chip != &d->chip) 397a696b89cSRafael J. Wysocki continue; 398a821b279SThomas Gleixner if (irqd_is_wakeup_set(data)) 399a696b89cSRafael J. Wysocki chip->irq_enable(data); 400a696b89cSRafael J. Wysocki } 401a696b89cSRafael J. Wysocki } 402a696b89cSRafael J. Wysocki return 0; 403a696b89cSRafael J. Wysocki } 404a696b89cSRafael J. Wysocki 405a696b89cSRafael J. Wysocki static void intc_resume(void) 406a696b89cSRafael J. Wysocki { 407a696b89cSRafael J. Wysocki struct intc_desc_int *d; 408a696b89cSRafael J. Wysocki 409a696b89cSRafael J. Wysocki list_for_each_entry(d, &intc_list, list) { 410a696b89cSRafael J. Wysocki int irq; 411a696b89cSRafael J. Wysocki 412a696b89cSRafael J. Wysocki for_each_active_irq(irq) { 413a696b89cSRafael J. Wysocki struct irq_data *data; 414a696b89cSRafael J. Wysocki struct irq_chip *chip; 415a696b89cSRafael J. Wysocki 416a696b89cSRafael J. Wysocki data = irq_get_irq_data(irq); 417a696b89cSRafael J. Wysocki chip = irq_data_get_irq_chip(data); 418a696b89cSRafael J. Wysocki /* 419a696b89cSRafael J. Wysocki * This will catch the redirect and VIRQ cases 420a696b89cSRafael J. Wysocki * due to the dummy_irq_chip being inserted. 421a696b89cSRafael J. Wysocki */ 422a696b89cSRafael J. Wysocki if (chip != &d->chip) 423a696b89cSRafael J. Wysocki continue; 424a821b279SThomas Gleixner if (irqd_irq_disabled(data)) 425a696b89cSRafael J. Wysocki chip->irq_disable(data); 426a696b89cSRafael J. Wysocki else 427a696b89cSRafael J. Wysocki chip->irq_enable(data); 428a696b89cSRafael J. Wysocki } 429a696b89cSRafael J. Wysocki } 430a696b89cSRafael J. Wysocki } 431a696b89cSRafael J. Wysocki 432a696b89cSRafael J. Wysocki struct syscore_ops intc_syscore_ops = { 433a696b89cSRafael J. Wysocki .suspend = intc_suspend, 434a696b89cSRafael J. Wysocki .resume = intc_resume, 435a696b89cSRafael J. Wysocki }; 436a696b89cSRafael J. Wysocki 437a696b89cSRafael J. Wysocki struct sysdev_class intc_sysdev_class = { 438a696b89cSRafael J. Wysocki .name = "intc", 439a696b89cSRafael J. Wysocki }; 440a696b89cSRafael J. Wysocki 4412be6bb0cSPaul Mundt static ssize_t 4422be6bb0cSPaul Mundt show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) 4432be6bb0cSPaul Mundt { 4442be6bb0cSPaul Mundt struct intc_desc_int *d; 4452be6bb0cSPaul Mundt 4462be6bb0cSPaul Mundt d = container_of(dev, struct intc_desc_int, sysdev); 4472be6bb0cSPaul Mundt 4482be6bb0cSPaul Mundt return sprintf(buf, "%s\n", d->chip.name); 4492be6bb0cSPaul Mundt } 4502be6bb0cSPaul Mundt 4512be6bb0cSPaul Mundt static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL); 4522be6bb0cSPaul Mundt 4532be6bb0cSPaul Mundt static int __init register_intc_sysdevs(void) 4542be6bb0cSPaul Mundt { 4552be6bb0cSPaul Mundt struct intc_desc_int *d; 4562be6bb0cSPaul Mundt int error; 4572be6bb0cSPaul Mundt 458a696b89cSRafael J. Wysocki register_syscore_ops(&intc_syscore_ops); 459a696b89cSRafael J. Wysocki 4602be6bb0cSPaul Mundt error = sysdev_class_register(&intc_sysdev_class); 4612be6bb0cSPaul Mundt if (!error) { 4622be6bb0cSPaul Mundt list_for_each_entry(d, &intc_list, list) { 4632be6bb0cSPaul Mundt d->sysdev.id = d->index; 4642be6bb0cSPaul Mundt d->sysdev.cls = &intc_sysdev_class; 4652be6bb0cSPaul Mundt error = sysdev_register(&d->sysdev); 4662be6bb0cSPaul Mundt if (error == 0) 4672be6bb0cSPaul Mundt error = sysdev_create_file(&d->sysdev, 4682be6bb0cSPaul Mundt &attr_name); 4692be6bb0cSPaul Mundt if (error) 4702be6bb0cSPaul Mundt break; 4712be6bb0cSPaul Mundt } 4722be6bb0cSPaul Mundt } 4732be6bb0cSPaul Mundt 4742be6bb0cSPaul Mundt if (error) 4752be6bb0cSPaul Mundt pr_err("sysdev registration error\n"); 4762be6bb0cSPaul Mundt 4772be6bb0cSPaul Mundt return error; 4782be6bb0cSPaul Mundt } 4792be6bb0cSPaul Mundt device_initcall(register_intc_sysdevs); 480