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