11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * I/O SAPIC support. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1999 Intel Corp. 51da177e4SLinus Torvalds * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> 61da177e4SLinus Torvalds * Copyright (C) 2000-2002 J.I. Lee <jung-ik.lee@intel.com> 71da177e4SLinus Torvalds * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co. 81da177e4SLinus Torvalds * David Mosberger-Tang <davidm@hpl.hp.com> 91da177e4SLinus Torvalds * Copyright (C) 1999 VA Linux Systems 101da177e4SLinus Torvalds * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. 131da177e4SLinus Torvalds * In particular, we now have separate handlers for edge 141da177e4SLinus Torvalds * and level triggered interrupts. 151da177e4SLinus Torvalds * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation 161da177e4SLinus Torvalds * PCI to vector mapping, shared PCI interrupts. 171da177e4SLinus Torvalds * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. 181da177e4SLinus Torvalds * Clean up much of the old IOSAPIC cruft. 191da177e4SLinus Torvalds * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts and fixes for 201da177e4SLinus Torvalds * ACPI S5(SoftOff) support. 211da177e4SLinus Torvalds * 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT 221da177e4SLinus Torvalds * 02/01/07 E. Focht <efocht@ess.nec.de> Redirectable interrupt vectors in 231da177e4SLinus Torvalds * iosapic_set_affinity(), initializations for 241da177e4SLinus Torvalds * /proc/irq/#/smp_affinity 251da177e4SLinus Torvalds * 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing. 261da177e4SLinus Torvalds * 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq 271da177e4SLinus Torvalds * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping 281da177e4SLinus Torvalds * error 291da177e4SLinus Torvalds * 02/07/29 T. Kochi Allocate interrupt vectors dynamically 301da177e4SLinus Torvalds * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector, etc.) 311da177e4SLinus Torvalds * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's pci_irq code. 321da177e4SLinus Torvalds * 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC. 331da177e4SLinus Torvalds * Remove iosapic_address & gsi_base from external interfaces. 341da177e4SLinus Torvalds * Rationalize __init/__devinit attributes. 351da177e4SLinus Torvalds * 04/12/04 Ashok Raj <ashok.raj@intel.com> Intel Corporation 2004 361da177e4SLinus Torvalds * Updated to work with irq migration necessary for CPU Hotplug 371da177e4SLinus Torvalds */ 381da177e4SLinus Torvalds /* 391da177e4SLinus Torvalds * Here is what the interrupt logic between a PCI device and the kernel looks like: 401da177e4SLinus Torvalds * 411da177e4SLinus Torvalds * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The 421da177e4SLinus Torvalds * device is uniquely identified by its bus--, and slot-number (the function 431da177e4SLinus Torvalds * number does not matter here because all functions share the same interrupt 441da177e4SLinus Torvalds * lines). 451da177e4SLinus Torvalds * 461da177e4SLinus Torvalds * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. 471da177e4SLinus Torvalds * Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level 481da177e4SLinus Torvalds * triggered and use the same polarity). Each interrupt line has a unique Global 491da177e4SLinus Torvalds * System Interrupt (GSI) number which can be calculated as the sum of the controller's 501da177e4SLinus Torvalds * base GSI number and the IOSAPIC pin number to which the line connects. 511da177e4SLinus Torvalds * 521da177e4SLinus Torvalds * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin 531da177e4SLinus Torvalds * into the IA-64 interrupt vector. This interrupt vector is then sent to the CPU. 541da177e4SLinus Torvalds * 551da177e4SLinus Torvalds * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is used as 561da177e4SLinus Torvalds * architecture-independent interrupt handling mechanism in Linux. As an 571da177e4SLinus Torvalds * IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number 581da177e4SLinus Torvalds * mapping. On smaller systems, we use one-to-one mapping between IA-64 vector and 591da177e4SLinus Torvalds * IRQ. A platform can implement platform_irq_to_vector(irq) and 601da177e4SLinus Torvalds * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. 611da177e4SLinus Torvalds * Please see also include/asm-ia64/hw_irq.h for those APIs. 621da177e4SLinus Torvalds * 631da177e4SLinus Torvalds * To sum up, there are three levels of mappings involved: 641da177e4SLinus Torvalds * 651da177e4SLinus Torvalds * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts. 681da177e4SLinus Torvalds * Now we use "IRQ" only for Linux IRQ's. ISA IRQ (isa_irq) is the only exception in this 691da177e4SLinus Torvalds * source code. 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds #include <linux/config.h> 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds #include <linux/acpi.h> 741da177e4SLinus Torvalds #include <linux/init.h> 751da177e4SLinus Torvalds #include <linux/irq.h> 761da177e4SLinus Torvalds #include <linux/kernel.h> 771da177e4SLinus Torvalds #include <linux/list.h> 781da177e4SLinus Torvalds #include <linux/pci.h> 791da177e4SLinus Torvalds #include <linux/smp.h> 801da177e4SLinus Torvalds #include <linux/smp_lock.h> 811da177e4SLinus Torvalds #include <linux/string.h> 8224eeb568SKenji Kaneshige #include <linux/bootmem.h> 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds #include <asm/delay.h> 851da177e4SLinus Torvalds #include <asm/hw_irq.h> 861da177e4SLinus Torvalds #include <asm/io.h> 871da177e4SLinus Torvalds #include <asm/iosapic.h> 881da177e4SLinus Torvalds #include <asm/machvec.h> 891da177e4SLinus Torvalds #include <asm/processor.h> 901da177e4SLinus Torvalds #include <asm/ptrace.h> 911da177e4SLinus Torvalds #include <asm/system.h> 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds #undef DEBUG_INTERRUPT_ROUTING 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds #ifdef DEBUG_INTERRUPT_ROUTING 971da177e4SLinus Torvalds #define DBG(fmt...) printk(fmt) 981da177e4SLinus Torvalds #else 991da177e4SLinus Torvalds #define DBG(fmt...) 1001da177e4SLinus Torvalds #endif 1011da177e4SLinus Torvalds 10224eeb568SKenji Kaneshige #define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info)) 10324eeb568SKenji Kaneshige #define RTE_PREALLOCATED (1) 10424eeb568SKenji Kaneshige 1051da177e4SLinus Torvalds static DEFINE_SPINLOCK(iosapic_lock); 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ 1081da177e4SLinus Torvalds 10924eeb568SKenji Kaneshige struct iosapic_rte_info { 11024eeb568SKenji Kaneshige struct list_head rte_list; /* node in list of RTEs sharing the same vector */ 1111da177e4SLinus Torvalds char __iomem *addr; /* base address of IOSAPIC */ 1121da177e4SLinus Torvalds unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ 11324eeb568SKenji Kaneshige char rte_index; /* IOSAPIC RTE index */ 11424eeb568SKenji Kaneshige int refcnt; /* reference counter */ 11524eeb568SKenji Kaneshige unsigned int flags; /* flags */ 11624eeb568SKenji Kaneshige } ____cacheline_aligned; 11724eeb568SKenji Kaneshige 11824eeb568SKenji Kaneshige static struct iosapic_intr_info { 11924eeb568SKenji Kaneshige struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */ 12024eeb568SKenji Kaneshige int count; /* # of RTEs that shares this vector */ 12124eeb568SKenji Kaneshige u32 low32; /* current value of low word of Redirection table entry */ 12224eeb568SKenji Kaneshige unsigned int dest; /* destination CPU physical ID */ 1231da177e4SLinus Torvalds unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ 1241da177e4SLinus Torvalds unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ 1251da177e4SLinus Torvalds unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ 1261da177e4SLinus Torvalds } iosapic_intr_info[IA64_NUM_VECTORS]; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds static struct iosapic { 1291da177e4SLinus Torvalds char __iomem *addr; /* base address of IOSAPIC */ 1301da177e4SLinus Torvalds unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ 1311da177e4SLinus Torvalds unsigned short num_rte; /* number of RTE in this IOSAPIC */ 1320e888adcSKenji Kaneshige int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ 1331da177e4SLinus Torvalds #ifdef CONFIG_NUMA 1341da177e4SLinus Torvalds unsigned short node; /* numa node association via pxm */ 1351da177e4SLinus Torvalds #endif 1361da177e4SLinus Torvalds } iosapic_lists[NR_IOSAPICS]; 1371da177e4SLinus Torvalds 1380e888adcSKenji Kaneshige static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ 1391da177e4SLinus Torvalds 14024eeb568SKenji Kaneshige static int iosapic_kmalloc_ok; 14124eeb568SKenji Kaneshige static LIST_HEAD(free_rte_list); 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds /* 1441da177e4SLinus Torvalds * Find an IOSAPIC associated with a GSI 1451da177e4SLinus Torvalds */ 1461da177e4SLinus Torvalds static inline int 1471da177e4SLinus Torvalds find_iosapic (unsigned int gsi) 1481da177e4SLinus Torvalds { 1491da177e4SLinus Torvalds int i; 1501da177e4SLinus Torvalds 1510e888adcSKenji Kaneshige for (i = 0; i < NR_IOSAPICS; i++) { 1521da177e4SLinus Torvalds if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) 1531da177e4SLinus Torvalds return i; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds return -1; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds static inline int 1601da177e4SLinus Torvalds _gsi_to_vector (unsigned int gsi) 1611da177e4SLinus Torvalds { 1621da177e4SLinus Torvalds struct iosapic_intr_info *info; 16324eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) 16624eeb568SKenji Kaneshige list_for_each_entry(rte, &info->rtes, rte_list) 16724eeb568SKenji Kaneshige if (rte->gsi_base + rte->rte_index == gsi) 1681da177e4SLinus Torvalds return info - iosapic_intr_info; 1691da177e4SLinus Torvalds return -1; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds /* 1731da177e4SLinus Torvalds * Translate GSI number to the corresponding IA-64 interrupt vector. If no 1741da177e4SLinus Torvalds * entry exists, return -1. 1751da177e4SLinus Torvalds */ 1761da177e4SLinus Torvalds inline int 1771da177e4SLinus Torvalds gsi_to_vector (unsigned int gsi) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds return _gsi_to_vector(gsi); 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds int 1831da177e4SLinus Torvalds gsi_to_irq (unsigned int gsi) 1841da177e4SLinus Torvalds { 18524eeb568SKenji Kaneshige unsigned long flags; 18624eeb568SKenji Kaneshige int irq; 1871da177e4SLinus Torvalds /* 1881da177e4SLinus Torvalds * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq 1891da177e4SLinus Torvalds * numbers... 1901da177e4SLinus Torvalds */ 19124eeb568SKenji Kaneshige spin_lock_irqsave(&iosapic_lock, flags); 19224eeb568SKenji Kaneshige { 19324eeb568SKenji Kaneshige irq = _gsi_to_vector(gsi); 19424eeb568SKenji Kaneshige } 19524eeb568SKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 19624eeb568SKenji Kaneshige 19724eeb568SKenji Kaneshige return irq; 19824eeb568SKenji Kaneshige } 19924eeb568SKenji Kaneshige 20024eeb568SKenji Kaneshige static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec) 20124eeb568SKenji Kaneshige { 20224eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 20324eeb568SKenji Kaneshige 20424eeb568SKenji Kaneshige list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) 20524eeb568SKenji Kaneshige if (rte->gsi_base + rte->rte_index == gsi) 20624eeb568SKenji Kaneshige return rte; 20724eeb568SKenji Kaneshige return NULL; 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds static void 21124eeb568SKenji Kaneshige set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) 2121da177e4SLinus Torvalds { 2131da177e4SLinus Torvalds unsigned long pol, trigger, dmode; 2141da177e4SLinus Torvalds u32 low32, high32; 2151da177e4SLinus Torvalds char __iomem *addr; 2161da177e4SLinus Torvalds int rte_index; 2171da177e4SLinus Torvalds char redir; 21824eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest); 2211da177e4SLinus Torvalds 22224eeb568SKenji Kaneshige rte = gsi_vector_to_rte(gsi, vector); 22324eeb568SKenji Kaneshige if (!rte) 2241da177e4SLinus Torvalds return; /* not an IOSAPIC interrupt */ 2251da177e4SLinus Torvalds 22624eeb568SKenji Kaneshige rte_index = rte->rte_index; 22724eeb568SKenji Kaneshige addr = rte->addr; 2281da177e4SLinus Torvalds pol = iosapic_intr_info[vector].polarity; 2291da177e4SLinus Torvalds trigger = iosapic_intr_info[vector].trigger; 2301da177e4SLinus Torvalds dmode = iosapic_intr_info[vector].dmode; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds #ifdef CONFIG_SMP 2351da177e4SLinus Torvalds { 2361da177e4SLinus Torvalds unsigned int irq; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds for (irq = 0; irq < NR_IRQS; ++irq) 2391da177e4SLinus Torvalds if (irq_to_vector(irq) == vector) { 2401da177e4SLinus Torvalds set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); 2411da177e4SLinus Torvalds break; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds #endif 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | 2471da177e4SLinus Torvalds (trigger << IOSAPIC_TRIGGER_SHIFT) | 2481da177e4SLinus Torvalds (dmode << IOSAPIC_DELIVERY_SHIFT) | 2491da177e4SLinus Torvalds ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) | 2501da177e4SLinus Torvalds vector); 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds /* dest contains both id and eid */ 2531da177e4SLinus Torvalds high32 = (dest << IOSAPIC_DEST_SHIFT); 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); 2561da177e4SLinus Torvalds iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 2571da177e4SLinus Torvalds iosapic_intr_info[vector].low32 = low32; 25824eeb568SKenji Kaneshige iosapic_intr_info[vector].dest = dest; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds static void 2621da177e4SLinus Torvalds nop (unsigned int vector) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds /* do nothing... */ 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds static void 2681da177e4SLinus Torvalds mask_irq (unsigned int irq) 2691da177e4SLinus Torvalds { 2701da177e4SLinus Torvalds unsigned long flags; 2711da177e4SLinus Torvalds char __iomem *addr; 2721da177e4SLinus Torvalds u32 low32; 2731da177e4SLinus Torvalds int rte_index; 2741da177e4SLinus Torvalds ia64_vector vec = irq_to_vector(irq); 27524eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 2761da177e4SLinus Torvalds 27724eeb568SKenji Kaneshige if (list_empty(&iosapic_intr_info[vec].rtes)) 2781da177e4SLinus Torvalds return; /* not an IOSAPIC interrupt! */ 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds spin_lock_irqsave(&iosapic_lock, flags); 2811da177e4SLinus Torvalds { 2821da177e4SLinus Torvalds /* set only the mask bit */ 2831da177e4SLinus Torvalds low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; 28424eeb568SKenji Kaneshige list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { 28524eeb568SKenji Kaneshige addr = rte->addr; 28624eeb568SKenji Kaneshige rte_index = rte->rte_index; 2871da177e4SLinus Torvalds iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 2881da177e4SLinus Torvalds } 28924eeb568SKenji Kaneshige } 2901da177e4SLinus Torvalds spin_unlock_irqrestore(&iosapic_lock, flags); 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds static void 2941da177e4SLinus Torvalds unmask_irq (unsigned int irq) 2951da177e4SLinus Torvalds { 2961da177e4SLinus Torvalds unsigned long flags; 2971da177e4SLinus Torvalds char __iomem *addr; 2981da177e4SLinus Torvalds u32 low32; 2991da177e4SLinus Torvalds int rte_index; 3001da177e4SLinus Torvalds ia64_vector vec = irq_to_vector(irq); 30124eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 3021da177e4SLinus Torvalds 30324eeb568SKenji Kaneshige if (list_empty(&iosapic_intr_info[vec].rtes)) 3041da177e4SLinus Torvalds return; /* not an IOSAPIC interrupt! */ 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds spin_lock_irqsave(&iosapic_lock, flags); 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; 30924eeb568SKenji Kaneshige list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { 31024eeb568SKenji Kaneshige addr = rte->addr; 31124eeb568SKenji Kaneshige rte_index = rte->rte_index; 3121da177e4SLinus Torvalds iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 3131da177e4SLinus Torvalds } 31424eeb568SKenji Kaneshige } 3151da177e4SLinus Torvalds spin_unlock_irqrestore(&iosapic_lock, flags); 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds static void 3201da177e4SLinus Torvalds iosapic_set_affinity (unsigned int irq, cpumask_t mask) 3211da177e4SLinus Torvalds { 3221da177e4SLinus Torvalds #ifdef CONFIG_SMP 3231da177e4SLinus Torvalds unsigned long flags; 3241da177e4SLinus Torvalds u32 high32, low32; 3251da177e4SLinus Torvalds int dest, rte_index; 3261da177e4SLinus Torvalds char __iomem *addr; 3271da177e4SLinus Torvalds int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; 3281da177e4SLinus Torvalds ia64_vector vec; 32924eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds irq &= (~IA64_IRQ_REDIRECTED); 3321da177e4SLinus Torvalds vec = irq_to_vector(irq); 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds if (cpus_empty(mask)) 3351da177e4SLinus Torvalds return; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds dest = cpu_physical_id(first_cpu(mask)); 3381da177e4SLinus Torvalds 33924eeb568SKenji Kaneshige if (list_empty(&iosapic_intr_info[vec].rtes)) 3401da177e4SLinus Torvalds return; /* not an IOSAPIC interrupt */ 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds set_irq_affinity_info(irq, dest, redir); 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* dest contains both id and eid */ 3451da177e4SLinus Torvalds high32 = dest << IOSAPIC_DEST_SHIFT; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds spin_lock_irqsave(&iosapic_lock, flags); 3481da177e4SLinus Torvalds { 3491da177e4SLinus Torvalds low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds if (redir) 3521da177e4SLinus Torvalds /* change delivery mode to lowest priority */ 3531da177e4SLinus Torvalds low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); 3541da177e4SLinus Torvalds else 3551da177e4SLinus Torvalds /* change delivery mode to fixed */ 3561da177e4SLinus Torvalds low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds iosapic_intr_info[vec].low32 = low32; 35924eeb568SKenji Kaneshige iosapic_intr_info[vec].dest = dest; 36024eeb568SKenji Kaneshige list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { 36124eeb568SKenji Kaneshige addr = rte->addr; 36224eeb568SKenji Kaneshige rte_index = rte->rte_index; 3631da177e4SLinus Torvalds iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); 3641da177e4SLinus Torvalds iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); 3651da177e4SLinus Torvalds } 36624eeb568SKenji Kaneshige } 3671da177e4SLinus Torvalds spin_unlock_irqrestore(&iosapic_lock, flags); 3681da177e4SLinus Torvalds #endif 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds /* 3721da177e4SLinus Torvalds * Handlers for level-triggered interrupts. 3731da177e4SLinus Torvalds */ 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds static unsigned int 3761da177e4SLinus Torvalds iosapic_startup_level_irq (unsigned int irq) 3771da177e4SLinus Torvalds { 3781da177e4SLinus Torvalds unmask_irq(irq); 3791da177e4SLinus Torvalds return 0; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds static void 3831da177e4SLinus Torvalds iosapic_end_level_irq (unsigned int irq) 3841da177e4SLinus Torvalds { 3851da177e4SLinus Torvalds ia64_vector vec = irq_to_vector(irq); 38624eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds move_irq(irq); 38924eeb568SKenji Kaneshige list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) 39024eeb568SKenji Kaneshige iosapic_eoi(rte->addr, vec); 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds #define iosapic_shutdown_level_irq mask_irq 3941da177e4SLinus Torvalds #define iosapic_enable_level_irq unmask_irq 3951da177e4SLinus Torvalds #define iosapic_disable_level_irq mask_irq 3961da177e4SLinus Torvalds #define iosapic_ack_level_irq nop 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds struct hw_interrupt_type irq_type_iosapic_level = { 3991da177e4SLinus Torvalds .typename = "IO-SAPIC-level", 4001da177e4SLinus Torvalds .startup = iosapic_startup_level_irq, 4011da177e4SLinus Torvalds .shutdown = iosapic_shutdown_level_irq, 4021da177e4SLinus Torvalds .enable = iosapic_enable_level_irq, 4031da177e4SLinus Torvalds .disable = iosapic_disable_level_irq, 4041da177e4SLinus Torvalds .ack = iosapic_ack_level_irq, 4051da177e4SLinus Torvalds .end = iosapic_end_level_irq, 4061da177e4SLinus Torvalds .set_affinity = iosapic_set_affinity 4071da177e4SLinus Torvalds }; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* 4101da177e4SLinus Torvalds * Handlers for edge-triggered interrupts. 4111da177e4SLinus Torvalds */ 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds static unsigned int 4141da177e4SLinus Torvalds iosapic_startup_edge_irq (unsigned int irq) 4151da177e4SLinus Torvalds { 4161da177e4SLinus Torvalds unmask_irq(irq); 4171da177e4SLinus Torvalds /* 4181da177e4SLinus Torvalds * IOSAPIC simply drops interrupts pended while the 4191da177e4SLinus Torvalds * corresponding pin was masked, so we can't know if an 4201da177e4SLinus Torvalds * interrupt is pending already. Let's hope not... 4211da177e4SLinus Torvalds */ 4221da177e4SLinus Torvalds return 0; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds static void 4261da177e4SLinus Torvalds iosapic_ack_edge_irq (unsigned int irq) 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds irq_desc_t *idesc = irq_descp(irq); 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds move_irq(irq); 4311da177e4SLinus Torvalds /* 4321da177e4SLinus Torvalds * Once we have recorded IRQ_PENDING already, we can mask the 4331da177e4SLinus Torvalds * interrupt for real. This prevents IRQ storms from unhandled 4341da177e4SLinus Torvalds * devices. 4351da177e4SLinus Torvalds */ 4361da177e4SLinus Torvalds if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) 4371da177e4SLinus Torvalds mask_irq(irq); 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds #define iosapic_enable_edge_irq unmask_irq 4411da177e4SLinus Torvalds #define iosapic_disable_edge_irq nop 4421da177e4SLinus Torvalds #define iosapic_end_edge_irq nop 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds struct hw_interrupt_type irq_type_iosapic_edge = { 4451da177e4SLinus Torvalds .typename = "IO-SAPIC-edge", 4461da177e4SLinus Torvalds .startup = iosapic_startup_edge_irq, 4471da177e4SLinus Torvalds .shutdown = iosapic_disable_edge_irq, 4481da177e4SLinus Torvalds .enable = iosapic_enable_edge_irq, 4491da177e4SLinus Torvalds .disable = iosapic_disable_edge_irq, 4501da177e4SLinus Torvalds .ack = iosapic_ack_edge_irq, 4511da177e4SLinus Torvalds .end = iosapic_end_edge_irq, 4521da177e4SLinus Torvalds .set_affinity = iosapic_set_affinity 4531da177e4SLinus Torvalds }; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds unsigned int 4561da177e4SLinus Torvalds iosapic_version (char __iomem *addr) 4571da177e4SLinus Torvalds { 4581da177e4SLinus Torvalds /* 4591da177e4SLinus Torvalds * IOSAPIC Version Register return 32 bit structure like: 4601da177e4SLinus Torvalds * { 4611da177e4SLinus Torvalds * unsigned int version : 8; 4621da177e4SLinus Torvalds * unsigned int reserved1 : 8; 4631da177e4SLinus Torvalds * unsigned int max_redir : 8; 4641da177e4SLinus Torvalds * unsigned int reserved2 : 8; 4651da177e4SLinus Torvalds * } 4661da177e4SLinus Torvalds */ 4671da177e4SLinus Torvalds return iosapic_read(addr, IOSAPIC_VERSION); 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 47024eeb568SKenji Kaneshige static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol) 47124eeb568SKenji Kaneshige { 47224eeb568SKenji Kaneshige int i, vector = -1, min_count = -1; 47324eeb568SKenji Kaneshige struct iosapic_intr_info *info; 47424eeb568SKenji Kaneshige 47524eeb568SKenji Kaneshige /* 47624eeb568SKenji Kaneshige * shared vectors for edge-triggered interrupts are not 47724eeb568SKenji Kaneshige * supported yet 47824eeb568SKenji Kaneshige */ 47924eeb568SKenji Kaneshige if (trigger == IOSAPIC_EDGE) 48024eeb568SKenji Kaneshige return -1; 48124eeb568SKenji Kaneshige 48224eeb568SKenji Kaneshige for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) { 48324eeb568SKenji Kaneshige info = &iosapic_intr_info[i]; 48424eeb568SKenji Kaneshige if (info->trigger == trigger && info->polarity == pol && 48524eeb568SKenji Kaneshige (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) { 48624eeb568SKenji Kaneshige if (min_count == -1 || info->count < min_count) { 48724eeb568SKenji Kaneshige vector = i; 48824eeb568SKenji Kaneshige min_count = info->count; 48924eeb568SKenji Kaneshige } 49024eeb568SKenji Kaneshige } 49124eeb568SKenji Kaneshige } 49224eeb568SKenji Kaneshige 49324eeb568SKenji Kaneshige return vector; 49424eeb568SKenji Kaneshige } 49524eeb568SKenji Kaneshige 4961da177e4SLinus Torvalds /* 4971da177e4SLinus Torvalds * if the given vector is already owned by other, 4981da177e4SLinus Torvalds * assign a new vector for the other and make the vector available 4991da177e4SLinus Torvalds */ 5001da177e4SLinus Torvalds static void __init 5011da177e4SLinus Torvalds iosapic_reassign_vector (int vector) 5021da177e4SLinus Torvalds { 5031da177e4SLinus Torvalds int new_vector; 5041da177e4SLinus Torvalds 50524eeb568SKenji Kaneshige if (!list_empty(&iosapic_intr_info[vector].rtes)) { 5061da177e4SLinus Torvalds new_vector = assign_irq_vector(AUTO_ASSIGN); 5073b5cc090SKenji Kaneshige if (new_vector < 0) 5083b5cc090SKenji Kaneshige panic("%s: out of interrupt vectors!\n", __FUNCTION__); 5091da177e4SLinus Torvalds printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); 5101da177e4SLinus Torvalds memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], 5111da177e4SLinus Torvalds sizeof(struct iosapic_intr_info)); 51224eeb568SKenji Kaneshige INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes); 51324eeb568SKenji Kaneshige list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes); 5141da177e4SLinus Torvalds memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); 51524eeb568SKenji Kaneshige iosapic_intr_info[vector].low32 = IOSAPIC_MASK; 51624eeb568SKenji Kaneshige INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); 5171da177e4SLinus Torvalds } 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds 52024eeb568SKenji Kaneshige static struct iosapic_rte_info *iosapic_alloc_rte (void) 52124eeb568SKenji Kaneshige { 52224eeb568SKenji Kaneshige int i; 52324eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 52424eeb568SKenji Kaneshige int preallocated = 0; 52524eeb568SKenji Kaneshige 52624eeb568SKenji Kaneshige if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { 52724eeb568SKenji Kaneshige rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES); 52824eeb568SKenji Kaneshige if (!rte) 52924eeb568SKenji Kaneshige return NULL; 53024eeb568SKenji Kaneshige for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) 53124eeb568SKenji Kaneshige list_add(&rte->rte_list, &free_rte_list); 53224eeb568SKenji Kaneshige } 53324eeb568SKenji Kaneshige 53424eeb568SKenji Kaneshige if (!list_empty(&free_rte_list)) { 53524eeb568SKenji Kaneshige rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list); 53624eeb568SKenji Kaneshige list_del(&rte->rte_list); 53724eeb568SKenji Kaneshige preallocated++; 53824eeb568SKenji Kaneshige } else { 53924eeb568SKenji Kaneshige rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC); 54024eeb568SKenji Kaneshige if (!rte) 54124eeb568SKenji Kaneshige return NULL; 54224eeb568SKenji Kaneshige } 54324eeb568SKenji Kaneshige 54424eeb568SKenji Kaneshige memset(rte, 0, sizeof(struct iosapic_rte_info)); 54524eeb568SKenji Kaneshige if (preallocated) 54624eeb568SKenji Kaneshige rte->flags |= RTE_PREALLOCATED; 54724eeb568SKenji Kaneshige 54824eeb568SKenji Kaneshige return rte; 54924eeb568SKenji Kaneshige } 55024eeb568SKenji Kaneshige 55124eeb568SKenji Kaneshige static void iosapic_free_rte (struct iosapic_rte_info *rte) 55224eeb568SKenji Kaneshige { 55324eeb568SKenji Kaneshige if (rte->flags & RTE_PREALLOCATED) 55424eeb568SKenji Kaneshige list_add_tail(&rte->rte_list, &free_rte_list); 55524eeb568SKenji Kaneshige else 55624eeb568SKenji Kaneshige kfree(rte); 55724eeb568SKenji Kaneshige } 55824eeb568SKenji Kaneshige 55924eeb568SKenji Kaneshige static inline int vector_is_shared (int vector) 56024eeb568SKenji Kaneshige { 56124eeb568SKenji Kaneshige return (iosapic_intr_info[vector].count > 1); 56224eeb568SKenji Kaneshige } 56324eeb568SKenji Kaneshige 5641da177e4SLinus Torvalds static void 5651da177e4SLinus Torvalds register_intr (unsigned int gsi, int vector, unsigned char delivery, 5661da177e4SLinus Torvalds unsigned long polarity, unsigned long trigger) 5671da177e4SLinus Torvalds { 5681da177e4SLinus Torvalds irq_desc_t *idesc; 5691da177e4SLinus Torvalds struct hw_interrupt_type *irq_type; 5701da177e4SLinus Torvalds int rte_index; 5711da177e4SLinus Torvalds int index; 5721da177e4SLinus Torvalds unsigned long gsi_base; 5731da177e4SLinus Torvalds void __iomem *iosapic_address; 57424eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds index = find_iosapic(gsi); 5771da177e4SLinus Torvalds if (index < 0) { 5781da177e4SLinus Torvalds printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi); 5791da177e4SLinus Torvalds return; 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds iosapic_address = iosapic_lists[index].addr; 5831da177e4SLinus Torvalds gsi_base = iosapic_lists[index].gsi_base; 5841da177e4SLinus Torvalds 58524eeb568SKenji Kaneshige rte = gsi_vector_to_rte(gsi, vector); 58624eeb568SKenji Kaneshige if (!rte) { 58724eeb568SKenji Kaneshige rte = iosapic_alloc_rte(); 58824eeb568SKenji Kaneshige if (!rte) { 58924eeb568SKenji Kaneshige printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__); 59024eeb568SKenji Kaneshige return; 59124eeb568SKenji Kaneshige } 59224eeb568SKenji Kaneshige 5931da177e4SLinus Torvalds rte_index = gsi - gsi_base; 59424eeb568SKenji Kaneshige rte->rte_index = rte_index; 59524eeb568SKenji Kaneshige rte->addr = iosapic_address; 59624eeb568SKenji Kaneshige rte->gsi_base = gsi_base; 59724eeb568SKenji Kaneshige rte->refcnt++; 59824eeb568SKenji Kaneshige list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); 59924eeb568SKenji Kaneshige iosapic_intr_info[vector].count++; 6000e888adcSKenji Kaneshige iosapic_lists[index].rtes_inuse++; 60124eeb568SKenji Kaneshige } 60224eeb568SKenji Kaneshige else if (vector_is_shared(vector)) { 60324eeb568SKenji Kaneshige struct iosapic_intr_info *info = &iosapic_intr_info[vector]; 60424eeb568SKenji Kaneshige if (info->trigger != trigger || info->polarity != polarity) { 60524eeb568SKenji Kaneshige printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__); 60624eeb568SKenji Kaneshige return; 60724eeb568SKenji Kaneshige } 60824eeb568SKenji Kaneshige } 60924eeb568SKenji Kaneshige 6101da177e4SLinus Torvalds iosapic_intr_info[vector].polarity = polarity; 6111da177e4SLinus Torvalds iosapic_intr_info[vector].dmode = delivery; 6121da177e4SLinus Torvalds iosapic_intr_info[vector].trigger = trigger; 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds if (trigger == IOSAPIC_EDGE) 6151da177e4SLinus Torvalds irq_type = &irq_type_iosapic_edge; 6161da177e4SLinus Torvalds else 6171da177e4SLinus Torvalds irq_type = &irq_type_iosapic_level; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds idesc = irq_descp(vector); 6201da177e4SLinus Torvalds if (idesc->handler != irq_type) { 6211da177e4SLinus Torvalds if (idesc->handler != &no_irq_type) 6221da177e4SLinus Torvalds printk(KERN_WARNING "%s: changing vector %d from %s to %s\n", 6231da177e4SLinus Torvalds __FUNCTION__, vector, idesc->handler->typename, irq_type->typename); 6241da177e4SLinus Torvalds idesc->handler = irq_type; 6251da177e4SLinus Torvalds } 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds static unsigned int 6291da177e4SLinus Torvalds get_target_cpu (unsigned int gsi, int vector) 6301da177e4SLinus Torvalds { 6311da177e4SLinus Torvalds #ifdef CONFIG_SMP 6321da177e4SLinus Torvalds static int cpu = -1; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds /* 63524eeb568SKenji Kaneshige * In case of vector shared by multiple RTEs, all RTEs that 63624eeb568SKenji Kaneshige * share the vector need to use the same destination CPU. 63724eeb568SKenji Kaneshige */ 63824eeb568SKenji Kaneshige if (!list_empty(&iosapic_intr_info[vector].rtes)) 63924eeb568SKenji Kaneshige return iosapic_intr_info[vector].dest; 64024eeb568SKenji Kaneshige 64124eeb568SKenji Kaneshige /* 6421da177e4SLinus Torvalds * If the platform supports redirection via XTP, let it 6431da177e4SLinus Torvalds * distribute interrupts. 6441da177e4SLinus Torvalds */ 6451da177e4SLinus Torvalds if (smp_int_redirect & SMP_IRQ_REDIRECTION) 6461da177e4SLinus Torvalds return cpu_physical_id(smp_processor_id()); 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds /* 6491da177e4SLinus Torvalds * Some interrupts (ACPI SCI, for instance) are registered 6501da177e4SLinus Torvalds * before the BSP is marked as online. 6511da177e4SLinus Torvalds */ 6521da177e4SLinus Torvalds if (!cpu_online(smp_processor_id())) 6531da177e4SLinus Torvalds return cpu_physical_id(smp_processor_id()); 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds #ifdef CONFIG_NUMA 6561da177e4SLinus Torvalds { 6571da177e4SLinus Torvalds int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; 6581da177e4SLinus Torvalds cpumask_t cpu_mask; 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds iosapic_index = find_iosapic(gsi); 6611da177e4SLinus Torvalds if (iosapic_index < 0 || 6621da177e4SLinus Torvalds iosapic_lists[iosapic_index].node == MAX_NUMNODES) 6631da177e4SLinus Torvalds goto skip_numa_setup; 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node); 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds for_each_cpu_mask(numa_cpu, cpu_mask) { 6681da177e4SLinus Torvalds if (!cpu_online(numa_cpu)) 6691da177e4SLinus Torvalds cpu_clear(numa_cpu, cpu_mask); 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds 6721da177e4SLinus Torvalds num_cpus = cpus_weight(cpu_mask); 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds if (!num_cpus) 6751da177e4SLinus Torvalds goto skip_numa_setup; 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds /* Use vector assigment to distribute across cpus in node */ 6781da177e4SLinus Torvalds cpu_index = vector % num_cpus; 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) 6811da177e4SLinus Torvalds numa_cpu = next_cpu(numa_cpu, cpu_mask); 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds if (numa_cpu != NR_CPUS) 6841da177e4SLinus Torvalds return cpu_physical_id(numa_cpu); 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds skip_numa_setup: 6871da177e4SLinus Torvalds #endif 6881da177e4SLinus Torvalds /* 6891da177e4SLinus Torvalds * Otherwise, round-robin interrupt vectors across all the 6901da177e4SLinus Torvalds * processors. (It'd be nice if we could be smarter in the 6911da177e4SLinus Torvalds * case of NUMA.) 6921da177e4SLinus Torvalds */ 6931da177e4SLinus Torvalds do { 6941da177e4SLinus Torvalds if (++cpu >= NR_CPUS) 6951da177e4SLinus Torvalds cpu = 0; 6961da177e4SLinus Torvalds } while (!cpu_online(cpu)); 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds return cpu_physical_id(cpu); 6991da177e4SLinus Torvalds #else 7001da177e4SLinus Torvalds return cpu_physical_id(smp_processor_id()); 7011da177e4SLinus Torvalds #endif 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds /* 7051da177e4SLinus Torvalds * ACPI can describe IOSAPIC interrupts via static tables and namespace 7061da177e4SLinus Torvalds * methods. This provides an interface to register those interrupts and 7071da177e4SLinus Torvalds * program the IOSAPIC RTE. 7081da177e4SLinus Torvalds */ 7091da177e4SLinus Torvalds int 7101da177e4SLinus Torvalds iosapic_register_intr (unsigned int gsi, 7111da177e4SLinus Torvalds unsigned long polarity, unsigned long trigger) 7121da177e4SLinus Torvalds { 71324eeb568SKenji Kaneshige int vector, mask = 1; 7141da177e4SLinus Torvalds unsigned int dest; 7151da177e4SLinus Torvalds unsigned long flags; 71624eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 71724eeb568SKenji Kaneshige u32 low32; 71824eeb568SKenji Kaneshige again: 7191da177e4SLinus Torvalds /* 7201da177e4SLinus Torvalds * If this GSI has already been registered (i.e., it's a 7211da177e4SLinus Torvalds * shared interrupt, or we lost a race to register it), 7221da177e4SLinus Torvalds * don't touch the RTE. 7231da177e4SLinus Torvalds */ 7241da177e4SLinus Torvalds spin_lock_irqsave(&iosapic_lock, flags); 7251da177e4SLinus Torvalds { 7261da177e4SLinus Torvalds vector = gsi_to_vector(gsi); 7271da177e4SLinus Torvalds if (vector > 0) { 72824eeb568SKenji Kaneshige rte = gsi_vector_to_rte(gsi, vector); 72924eeb568SKenji Kaneshige rte->refcnt++; 7301da177e4SLinus Torvalds spin_unlock_irqrestore(&iosapic_lock, flags); 7311da177e4SLinus Torvalds return vector; 7321da177e4SLinus Torvalds } 73324eeb568SKenji Kaneshige } 73424eeb568SKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 7351da177e4SLinus Torvalds 73624eeb568SKenji Kaneshige /* If vector is running out, we try to find a sharable vector */ 7373b5cc090SKenji Kaneshige vector = assign_irq_vector(AUTO_ASSIGN); 7383b5cc090SKenji Kaneshige if (vector < 0) { 73924eeb568SKenji Kaneshige vector = iosapic_find_sharable_vector(trigger, polarity); 7403b5cc090SKenji Kaneshige if (vector < 0) 7413b5cc090SKenji Kaneshige panic("%s: out of interrupt vectors!\n", __FUNCTION__); 7423b5cc090SKenji Kaneshige } 74324eeb568SKenji Kaneshige 74424eeb568SKenji Kaneshige spin_lock_irqsave(&irq_descp(vector)->lock, flags); 74524eeb568SKenji Kaneshige spin_lock(&iosapic_lock); 74624eeb568SKenji Kaneshige { 74724eeb568SKenji Kaneshige if (gsi_to_vector(gsi) > 0) { 74824eeb568SKenji Kaneshige if (list_empty(&iosapic_intr_info[vector].rtes)) 74924eeb568SKenji Kaneshige free_irq_vector(vector); 75024eeb568SKenji Kaneshige spin_unlock(&iosapic_lock); 75124eeb568SKenji Kaneshige spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); 75224eeb568SKenji Kaneshige goto again; 75324eeb568SKenji Kaneshige } 75424eeb568SKenji Kaneshige 7551da177e4SLinus Torvalds dest = get_target_cpu(gsi, vector); 7561da177e4SLinus Torvalds register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, 7571da177e4SLinus Torvalds polarity, trigger); 7581da177e4SLinus Torvalds 75924eeb568SKenji Kaneshige /* 76024eeb568SKenji Kaneshige * If the vector is shared and already unmasked for 76124eeb568SKenji Kaneshige * other interrupt sources, don't mask it. 76224eeb568SKenji Kaneshige */ 76324eeb568SKenji Kaneshige low32 = iosapic_intr_info[vector].low32; 76424eeb568SKenji Kaneshige if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK)) 76524eeb568SKenji Kaneshige mask = 0; 76624eeb568SKenji Kaneshige set_rte(gsi, vector, dest, mask); 7671da177e4SLinus Torvalds } 768b9e41d7fSKenji Kaneshige spin_unlock(&iosapic_lock); 76924eeb568SKenji Kaneshige spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", 7721da177e4SLinus Torvalds gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), 7731da177e4SLinus Torvalds (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 7741da177e4SLinus Torvalds cpu_logical_id(dest), dest, vector); 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds return vector; 7771da177e4SLinus Torvalds } 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds #ifdef CONFIG_ACPI_DEALLOCATE_IRQ 7801da177e4SLinus Torvalds void 7811da177e4SLinus Torvalds iosapic_unregister_intr (unsigned int gsi) 7821da177e4SLinus Torvalds { 7831da177e4SLinus Torvalds unsigned long flags; 7840e888adcSKenji Kaneshige int irq, vector, index; 7851da177e4SLinus Torvalds irq_desc_t *idesc; 78624eeb568SKenji Kaneshige u32 low32; 7871da177e4SLinus Torvalds unsigned long trigger, polarity; 78824eeb568SKenji Kaneshige unsigned int dest; 78924eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds /* 7921da177e4SLinus Torvalds * If the irq associated with the gsi is not found, 7931da177e4SLinus Torvalds * iosapic_unregister_intr() is unbalanced. We need to check 7941da177e4SLinus Torvalds * this again after getting locks. 7951da177e4SLinus Torvalds */ 7961da177e4SLinus Torvalds irq = gsi_to_irq(gsi); 7971da177e4SLinus Torvalds if (irq < 0) { 7981da177e4SLinus Torvalds printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); 7991da177e4SLinus Torvalds WARN_ON(1); 8001da177e4SLinus Torvalds return; 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds vector = irq_to_vector(irq); 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds idesc = irq_descp(irq); 8051da177e4SLinus Torvalds spin_lock_irqsave(&idesc->lock, flags); 8061da177e4SLinus Torvalds spin_lock(&iosapic_lock); 8071da177e4SLinus Torvalds { 80824eeb568SKenji Kaneshige if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) { 8091da177e4SLinus Torvalds printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); 8101da177e4SLinus Torvalds WARN_ON(1); 81124eeb568SKenji Kaneshige goto out; 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds 81424eeb568SKenji Kaneshige if (--rte->refcnt > 0) 81524eeb568SKenji Kaneshige goto out; 8161da177e4SLinus Torvalds 81724eeb568SKenji Kaneshige /* Mask the interrupt */ 81824eeb568SKenji Kaneshige low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; 81924eeb568SKenji Kaneshige iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32); 8201da177e4SLinus Torvalds 82124eeb568SKenji Kaneshige /* Remove the rte entry from the list */ 82224eeb568SKenji Kaneshige list_del(&rte->rte_list); 82324eeb568SKenji Kaneshige iosapic_intr_info[vector].count--; 82424eeb568SKenji Kaneshige iosapic_free_rte(rte); 8250e888adcSKenji Kaneshige index = find_iosapic(gsi); 8260e888adcSKenji Kaneshige iosapic_lists[index].rtes_inuse--; 8270e888adcSKenji Kaneshige WARN_ON(iosapic_lists[index].rtes_inuse < 0); 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds trigger = iosapic_intr_info[vector].trigger; 8301da177e4SLinus Torvalds polarity = iosapic_intr_info[vector].polarity; 83124eeb568SKenji Kaneshige dest = iosapic_intr_info[vector].dest; 83224eeb568SKenji Kaneshige printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", 83324eeb568SKenji Kaneshige gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), 83424eeb568SKenji Kaneshige (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 83524eeb568SKenji Kaneshige cpu_logical_id(dest), dest, vector); 8361da177e4SLinus Torvalds 83724eeb568SKenji Kaneshige if (list_empty(&iosapic_intr_info[vector].rtes)) { 83824eeb568SKenji Kaneshige /* Sanity check */ 83924eeb568SKenji Kaneshige BUG_ON(iosapic_intr_info[vector].count); 84024eeb568SKenji Kaneshige 84124eeb568SKenji Kaneshige /* Clear the interrupt controller descriptor */ 84224eeb568SKenji Kaneshige idesc->handler = &no_irq_type; 84324eeb568SKenji Kaneshige 84424eeb568SKenji Kaneshige /* Clear the interrupt information */ 8451da177e4SLinus Torvalds memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); 84624eeb568SKenji Kaneshige iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; 84724eeb568SKenji Kaneshige INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); 84824eeb568SKenji Kaneshige 84924eeb568SKenji Kaneshige if (idesc->action) { 85024eeb568SKenji Kaneshige printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq); 85124eeb568SKenji Kaneshige WARN_ON(1); 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds /* Free the interrupt vector */ 8551da177e4SLinus Torvalds free_irq_vector(vector); 85624eeb568SKenji Kaneshige } 85724eeb568SKenji Kaneshige } 85824eeb568SKenji Kaneshige out: 85924eeb568SKenji Kaneshige spin_unlock(&iosapic_lock); 86024eeb568SKenji Kaneshige spin_unlock_irqrestore(&idesc->lock, flags); 8611da177e4SLinus Torvalds } 8621da177e4SLinus Torvalds #endif /* CONFIG_ACPI_DEALLOCATE_IRQ */ 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds /* 8651da177e4SLinus Torvalds * ACPI calls this when it finds an entry for a platform interrupt. 8661da177e4SLinus Torvalds * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). 8671da177e4SLinus Torvalds */ 8681da177e4SLinus Torvalds int __init 8691da177e4SLinus Torvalds iosapic_register_platform_intr (u32 int_type, unsigned int gsi, 8701da177e4SLinus Torvalds int iosapic_vector, u16 eid, u16 id, 8711da177e4SLinus Torvalds unsigned long polarity, unsigned long trigger) 8721da177e4SLinus Torvalds { 8731da177e4SLinus Torvalds static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"}; 8741da177e4SLinus Torvalds unsigned char delivery; 8751da177e4SLinus Torvalds int vector, mask = 0; 8761da177e4SLinus Torvalds unsigned int dest = ((id << 8) | eid) & 0xffff; 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds switch (int_type) { 8791da177e4SLinus Torvalds case ACPI_INTERRUPT_PMI: 8801da177e4SLinus Torvalds vector = iosapic_vector; 8811da177e4SLinus Torvalds /* 8821da177e4SLinus Torvalds * since PMI vector is alloc'd by FW(ACPI) not by kernel, 8831da177e4SLinus Torvalds * we need to make sure the vector is available 8841da177e4SLinus Torvalds */ 8851da177e4SLinus Torvalds iosapic_reassign_vector(vector); 8861da177e4SLinus Torvalds delivery = IOSAPIC_PMI; 8871da177e4SLinus Torvalds break; 8881da177e4SLinus Torvalds case ACPI_INTERRUPT_INIT: 8891da177e4SLinus Torvalds vector = assign_irq_vector(AUTO_ASSIGN); 8903b5cc090SKenji Kaneshige if (vector < 0) 8913b5cc090SKenji Kaneshige panic("%s: out of interrupt vectors!\n", __FUNCTION__); 8921da177e4SLinus Torvalds delivery = IOSAPIC_INIT; 8931da177e4SLinus Torvalds break; 8941da177e4SLinus Torvalds case ACPI_INTERRUPT_CPEI: 8951da177e4SLinus Torvalds vector = IA64_CPE_VECTOR; 8961da177e4SLinus Torvalds delivery = IOSAPIC_LOWEST_PRIORITY; 8971da177e4SLinus Torvalds mask = 1; 8981da177e4SLinus Torvalds break; 8991da177e4SLinus Torvalds default: 9001da177e4SLinus Torvalds printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type); 9011da177e4SLinus Torvalds return -1; 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds register_intr(gsi, vector, delivery, polarity, trigger); 9051da177e4SLinus Torvalds 9061da177e4SLinus Torvalds printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", 9071da177e4SLinus Torvalds int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown", 9081da177e4SLinus Torvalds int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), 9091da177e4SLinus Torvalds (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 9101da177e4SLinus Torvalds cpu_logical_id(dest), dest, vector); 9111da177e4SLinus Torvalds 91224eeb568SKenji Kaneshige set_rte(gsi, vector, dest, mask); 9131da177e4SLinus Torvalds return vector; 9141da177e4SLinus Torvalds } 9151da177e4SLinus Torvalds 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds /* 9181da177e4SLinus Torvalds * ACPI calls this when it finds an entry for a legacy ISA IRQ override. 9191da177e4SLinus Torvalds * Note that the gsi_base and IOSAPIC address must be set in iosapic_init(). 9201da177e4SLinus Torvalds */ 9211da177e4SLinus Torvalds void __init 9221da177e4SLinus Torvalds iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, 9231da177e4SLinus Torvalds unsigned long polarity, 9241da177e4SLinus Torvalds unsigned long trigger) 9251da177e4SLinus Torvalds { 9261da177e4SLinus Torvalds int vector; 9271da177e4SLinus Torvalds unsigned int dest = cpu_physical_id(smp_processor_id()); 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds vector = isa_irq_to_vector(isa_irq); 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger); 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n", 9341da177e4SLinus Torvalds isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level", 9351da177e4SLinus Torvalds polarity == IOSAPIC_POL_HIGH ? "high" : "low", 9361da177e4SLinus Torvalds cpu_logical_id(dest), dest, vector); 9371da177e4SLinus Torvalds 93824eeb568SKenji Kaneshige set_rte(gsi, vector, dest, 1); 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds void __init 9421da177e4SLinus Torvalds iosapic_system_init (int system_pcat_compat) 9431da177e4SLinus Torvalds { 9441da177e4SLinus Torvalds int vector; 9451da177e4SLinus Torvalds 94624eeb568SKenji Kaneshige for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) { 94724eeb568SKenji Kaneshige iosapic_intr_info[vector].low32 = IOSAPIC_MASK; 94824eeb568SKenji Kaneshige INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */ 94924eeb568SKenji Kaneshige } 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds pcat_compat = system_pcat_compat; 9521da177e4SLinus Torvalds if (pcat_compat) { 9531da177e4SLinus Torvalds /* 9541da177e4SLinus Torvalds * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support 9551da177e4SLinus Torvalds * enabled. 9561da177e4SLinus Torvalds */ 9571da177e4SLinus Torvalds printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__); 9581da177e4SLinus Torvalds outb(0xff, 0xA1); 9591da177e4SLinus Torvalds outb(0xff, 0x21); 9601da177e4SLinus Torvalds } 9611da177e4SLinus Torvalds } 9621da177e4SLinus Torvalds 9630e888adcSKenji Kaneshige static inline int 9640e888adcSKenji Kaneshige iosapic_alloc (void) 9650e888adcSKenji Kaneshige { 9660e888adcSKenji Kaneshige int index; 9670e888adcSKenji Kaneshige 9680e888adcSKenji Kaneshige for (index = 0; index < NR_IOSAPICS; index++) 9690e888adcSKenji Kaneshige if (!iosapic_lists[index].addr) 9700e888adcSKenji Kaneshige return index; 9710e888adcSKenji Kaneshige 9720e888adcSKenji Kaneshige printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__); 9730e888adcSKenji Kaneshige return -1; 9740e888adcSKenji Kaneshige } 9750e888adcSKenji Kaneshige 9760e888adcSKenji Kaneshige static inline void 9770e888adcSKenji Kaneshige iosapic_free (int index) 9780e888adcSKenji Kaneshige { 9790e888adcSKenji Kaneshige memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); 9800e888adcSKenji Kaneshige } 9810e888adcSKenji Kaneshige 9820e888adcSKenji Kaneshige static inline int 9830e888adcSKenji Kaneshige iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) 9840e888adcSKenji Kaneshige { 9850e888adcSKenji Kaneshige int index; 9860e888adcSKenji Kaneshige unsigned int gsi_end, base, end; 9870e888adcSKenji Kaneshige 9880e888adcSKenji Kaneshige /* check gsi range */ 9890e888adcSKenji Kaneshige gsi_end = gsi_base + ((ver >> 16) & 0xff); 9900e888adcSKenji Kaneshige for (index = 0; index < NR_IOSAPICS; index++) { 9910e888adcSKenji Kaneshige if (!iosapic_lists[index].addr) 9920e888adcSKenji Kaneshige continue; 9930e888adcSKenji Kaneshige 9940e888adcSKenji Kaneshige base = iosapic_lists[index].gsi_base; 9950e888adcSKenji Kaneshige end = base + iosapic_lists[index].num_rte - 1; 9960e888adcSKenji Kaneshige 9970e888adcSKenji Kaneshige if (gsi_base < base && gsi_end < base) 9980e888adcSKenji Kaneshige continue;/* OK */ 9990e888adcSKenji Kaneshige 10000e888adcSKenji Kaneshige if (gsi_base > end && gsi_end > end) 10010e888adcSKenji Kaneshige continue; /* OK */ 10020e888adcSKenji Kaneshige 10030e888adcSKenji Kaneshige return -EBUSY; 10040e888adcSKenji Kaneshige } 10050e888adcSKenji Kaneshige return 0; 10060e888adcSKenji Kaneshige } 10070e888adcSKenji Kaneshige 10080e888adcSKenji Kaneshige int __devinit 10091da177e4SLinus Torvalds iosapic_init (unsigned long phys_addr, unsigned int gsi_base) 10101da177e4SLinus Torvalds { 10110e888adcSKenji Kaneshige int num_rte, err, index; 10121da177e4SLinus Torvalds unsigned int isa_irq, ver; 10131da177e4SLinus Torvalds char __iomem *addr; 10140e888adcSKenji Kaneshige unsigned long flags; 10151da177e4SLinus Torvalds 10160e888adcSKenji Kaneshige spin_lock_irqsave(&iosapic_lock, flags); 10170e888adcSKenji Kaneshige { 10181da177e4SLinus Torvalds addr = ioremap(phys_addr, 0); 10191da177e4SLinus Torvalds ver = iosapic_version(addr); 10201da177e4SLinus Torvalds 10210e888adcSKenji Kaneshige if ((err = iosapic_check_gsi_range(gsi_base, ver))) { 10220e888adcSKenji Kaneshige iounmap(addr); 10230e888adcSKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 10240e888adcSKenji Kaneshige return err; 10250e888adcSKenji Kaneshige } 10260e888adcSKenji Kaneshige 10271da177e4SLinus Torvalds /* 10281da177e4SLinus Torvalds * The MAX_REDIR register holds the highest input pin 10291da177e4SLinus Torvalds * number (starting from 0). 10301da177e4SLinus Torvalds * We add 1 so that we can use it for number of pins (= RTEs) 10311da177e4SLinus Torvalds */ 10321da177e4SLinus Torvalds num_rte = ((ver >> 16) & 0xff) + 1; 10331da177e4SLinus Torvalds 10340e888adcSKenji Kaneshige index = iosapic_alloc(); 10350e888adcSKenji Kaneshige iosapic_lists[index].addr = addr; 10360e888adcSKenji Kaneshige iosapic_lists[index].gsi_base = gsi_base; 10370e888adcSKenji Kaneshige iosapic_lists[index].num_rte = num_rte; 10381da177e4SLinus Torvalds #ifdef CONFIG_NUMA 10390e888adcSKenji Kaneshige iosapic_lists[index].node = MAX_NUMNODES; 10401da177e4SLinus Torvalds #endif 10410e888adcSKenji Kaneshige } 10420e888adcSKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds if ((gsi_base == 0) && pcat_compat) { 10451da177e4SLinus Torvalds /* 10461da177e4SLinus Torvalds * Map the legacy ISA devices into the IOSAPIC data. Some of these may 10471da177e4SLinus Torvalds * get reprogrammed later on with data from the ACPI Interrupt Source 10481da177e4SLinus Torvalds * Override table. 10491da177e4SLinus Torvalds */ 10501da177e4SLinus Torvalds for (isa_irq = 0; isa_irq < 16; ++isa_irq) 10511da177e4SLinus Torvalds iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); 10521da177e4SLinus Torvalds } 10530e888adcSKenji Kaneshige return 0; 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 10560e888adcSKenji Kaneshige #ifdef CONFIG_HOTPLUG 10570e888adcSKenji Kaneshige int 10580e888adcSKenji Kaneshige iosapic_remove (unsigned int gsi_base) 10590e888adcSKenji Kaneshige { 10600e888adcSKenji Kaneshige int index, err = 0; 10610e888adcSKenji Kaneshige unsigned long flags; 10620e888adcSKenji Kaneshige 10630e888adcSKenji Kaneshige spin_lock_irqsave(&iosapic_lock, flags); 10640e888adcSKenji Kaneshige { 10650e888adcSKenji Kaneshige index = find_iosapic(gsi_base); 10660e888adcSKenji Kaneshige if (index < 0) { 10670e888adcSKenji Kaneshige printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", 10680e888adcSKenji Kaneshige __FUNCTION__, gsi_base); 10690e888adcSKenji Kaneshige goto out; 10700e888adcSKenji Kaneshige } 10710e888adcSKenji Kaneshige 10720e888adcSKenji Kaneshige if (iosapic_lists[index].rtes_inuse) { 10730e888adcSKenji Kaneshige err = -EBUSY; 10740e888adcSKenji Kaneshige printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", 10750e888adcSKenji Kaneshige __FUNCTION__, gsi_base); 10760e888adcSKenji Kaneshige goto out; 10770e888adcSKenji Kaneshige } 10780e888adcSKenji Kaneshige 10790e888adcSKenji Kaneshige iounmap(iosapic_lists[index].addr); 10800e888adcSKenji Kaneshige iosapic_free(index); 10810e888adcSKenji Kaneshige } 10820e888adcSKenji Kaneshige out: 10830e888adcSKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 10840e888adcSKenji Kaneshige return err; 10850e888adcSKenji Kaneshige } 10860e888adcSKenji Kaneshige #endif /* CONFIG_HOTPLUG */ 10870e888adcSKenji Kaneshige 10881da177e4SLinus Torvalds #ifdef CONFIG_NUMA 10890e888adcSKenji Kaneshige void __devinit 10901da177e4SLinus Torvalds map_iosapic_to_node(unsigned int gsi_base, int node) 10911da177e4SLinus Torvalds { 10921da177e4SLinus Torvalds int index; 10931da177e4SLinus Torvalds 10941da177e4SLinus Torvalds index = find_iosapic(gsi_base); 10951da177e4SLinus Torvalds if (index < 0) { 10961da177e4SLinus Torvalds printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", 10971da177e4SLinus Torvalds __FUNCTION__, gsi_base); 10981da177e4SLinus Torvalds return; 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds iosapic_lists[index].node = node; 11011da177e4SLinus Torvalds return; 11021da177e4SLinus Torvalds } 11031da177e4SLinus Torvalds #endif 110424eeb568SKenji Kaneshige 110524eeb568SKenji Kaneshige static int __init iosapic_enable_kmalloc (void) 110624eeb568SKenji Kaneshige { 110724eeb568SKenji Kaneshige iosapic_kmalloc_ok = 1; 110824eeb568SKenji Kaneshige return 0; 110924eeb568SKenji Kaneshige } 111024eeb568SKenji Kaneshige core_initcall (iosapic_enable_kmalloc); 1111