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 * 1246cba3dcSSatoru Takeuchi * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O 1346cba3dcSSatoru Takeuchi * APIC code. In particular, we now have separate 1446cba3dcSSatoru Takeuchi * handlers for edge and level triggered 1546cba3dcSSatoru Takeuchi * interrupts. 1646cba3dcSSatoru Takeuchi * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector 1746cba3dcSSatoru Takeuchi * allocation PCI to vector mapping, shared PCI 1846cba3dcSSatoru Takeuchi * interrupts. 1946cba3dcSSatoru Takeuchi * 00/10/27 D. Mosberger Document things a bit more to make them more 2046cba3dcSSatoru Takeuchi * understandable. Clean up much of the old 2146cba3dcSSatoru Takeuchi * IOSAPIC cruft. 2246cba3dcSSatoru Takeuchi * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts 2346cba3dcSSatoru Takeuchi * and fixes for ACPI S5(SoftOff) support. 241da177e4SLinus Torvalds * 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT 2546cba3dcSSatoru Takeuchi * 02/01/07 E. Focht <efocht@ess.nec.de> Redirectable interrupt 2646cba3dcSSatoru Takeuchi * vectors in iosapic_set_affinity(), 2746cba3dcSSatoru Takeuchi * initializations for /proc/irq/#/smp_affinity 281da177e4SLinus Torvalds * 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing. 291da177e4SLinus Torvalds * 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq 3046cba3dcSSatoru Takeuchi * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to 3146cba3dcSSatoru Takeuchi * IOSAPIC mapping error 321da177e4SLinus Torvalds * 02/07/29 T. Kochi Allocate interrupt vectors dynamically 3346cba3dcSSatoru Takeuchi * 02/08/04 T. Kochi Cleaned up terminology (irq, global system 3446cba3dcSSatoru Takeuchi * interrupt, vector, etc.) 3546cba3dcSSatoru Takeuchi * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's 3646cba3dcSSatoru Takeuchi * pci_irq code. 371da177e4SLinus Torvalds * 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC. 3846cba3dcSSatoru Takeuchi * Remove iosapic_address & gsi_base from 3946cba3dcSSatoru Takeuchi * external interfaces. Rationalize 4046cba3dcSSatoru Takeuchi * __init/__devinit attributes. 411da177e4SLinus Torvalds * 04/12/04 Ashok Raj <ashok.raj@intel.com> Intel Corporation 2004 4246cba3dcSSatoru Takeuchi * Updated to work with irq migration necessary 4346cba3dcSSatoru Takeuchi * for CPU Hotplug 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds /* 4646cba3dcSSatoru Takeuchi * Here is what the interrupt logic between a PCI device and the kernel looks 4746cba3dcSSatoru Takeuchi * like: 481da177e4SLinus Torvalds * 4946cba3dcSSatoru Takeuchi * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, 5046cba3dcSSatoru Takeuchi * INTD). The device is uniquely identified by its bus-, and slot-number 5146cba3dcSSatoru Takeuchi * (the function number does not matter here because all functions share 5246cba3dcSSatoru Takeuchi * the same interrupt lines). 531da177e4SLinus Torvalds * 5446cba3dcSSatoru Takeuchi * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC 5546cba3dcSSatoru Takeuchi * controller. Multiple interrupt lines may have to share the same 5646cba3dcSSatoru Takeuchi * IOSAPIC pin (if they're level triggered and use the same polarity). 5746cba3dcSSatoru Takeuchi * Each interrupt line has a unique Global System Interrupt (GSI) number 5846cba3dcSSatoru Takeuchi * which can be calculated as the sum of the controller's base GSI number 5946cba3dcSSatoru Takeuchi * and the IOSAPIC pin number to which the line connects. 601da177e4SLinus Torvalds * 6146cba3dcSSatoru Takeuchi * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the 6246cba3dcSSatoru Takeuchi * IOSAPIC pin into the IA-64 interrupt vector. This interrupt vector is then 6346cba3dcSSatoru Takeuchi * sent to the CPU. 641da177e4SLinus Torvalds * 6546cba3dcSSatoru Takeuchi * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is 6646cba3dcSSatoru Takeuchi * used as architecture-independent interrupt handling mechanism in Linux. 6746cba3dcSSatoru Takeuchi * As an IRQ is a number, we have to have 6846cba3dcSSatoru Takeuchi * IA-64 interrupt vector number <-> IRQ number mapping. On smaller 6946cba3dcSSatoru Takeuchi * systems, we use one-to-one mapping between IA-64 vector and IRQ. A 7046cba3dcSSatoru Takeuchi * platform can implement platform_irq_to_vector(irq) and 711da177e4SLinus Torvalds * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. 727f30491cSTony Luck * Please see also arch/ia64/include/asm/hw_irq.h for those APIs. 731da177e4SLinus Torvalds * 741da177e4SLinus Torvalds * To sum up, there are three levels of mappings involved: 751da177e4SLinus Torvalds * 761da177e4SLinus Torvalds * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ 771da177e4SLinus Torvalds * 7846cba3dcSSatoru Takeuchi * Note: The term "IRQ" is loosely used everywhere in Linux kernel to 7946cba3dcSSatoru Takeuchi * describeinterrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ 8046cba3dcSSatoru Takeuchi * (isa_irq) is the only exception in this source code. 811da177e4SLinus Torvalds */ 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds #include <linux/acpi.h> 841da177e4SLinus Torvalds #include <linux/init.h> 851da177e4SLinus Torvalds #include <linux/irq.h> 861da177e4SLinus Torvalds #include <linux/kernel.h> 871da177e4SLinus Torvalds #include <linux/list.h> 881da177e4SLinus Torvalds #include <linux/pci.h> 895a0e3ad6STejun Heo #include <linux/slab.h> 901da177e4SLinus Torvalds #include <linux/smp.h> 911da177e4SLinus Torvalds #include <linux/string.h> 9224eeb568SKenji Kaneshige #include <linux/bootmem.h> 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds #include <asm/delay.h> 951da177e4SLinus Torvalds #include <asm/hw_irq.h> 961da177e4SLinus Torvalds #include <asm/io.h> 971da177e4SLinus Torvalds #include <asm/iosapic.h> 981da177e4SLinus Torvalds #include <asm/machvec.h> 991da177e4SLinus Torvalds #include <asm/processor.h> 1001da177e4SLinus Torvalds #include <asm/ptrace.h> 1011da177e4SLinus Torvalds #include <asm/system.h> 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds #undef DEBUG_INTERRUPT_ROUTING 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds #ifdef DEBUG_INTERRUPT_ROUTING 1061da177e4SLinus Torvalds #define DBG(fmt...) printk(fmt) 1071da177e4SLinus Torvalds #else 1081da177e4SLinus Torvalds #define DBG(fmt...) 1091da177e4SLinus Torvalds #endif 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds static DEFINE_SPINLOCK(iosapic_lock); 1121da177e4SLinus Torvalds 11346cba3dcSSatoru Takeuchi /* 11446cba3dcSSatoru Takeuchi * These tables map IA-64 vectors to the IOSAPIC pin that generates this 11546cba3dcSSatoru Takeuchi * vector. 11646cba3dcSSatoru Takeuchi */ 117e1b30a39SYasuaki Ishimatsu 118e1b30a39SYasuaki Ishimatsu #define NO_REF_RTE 0 119e1b30a39SYasuaki Ishimatsu 120c5e3f9e5SYasuaki Ishimatsu static struct iosapic { 121c5e3f9e5SYasuaki Ishimatsu char __iomem *addr; /* base address of IOSAPIC */ 122c5e3f9e5SYasuaki Ishimatsu unsigned int gsi_base; /* GSI base */ 123c5e3f9e5SYasuaki Ishimatsu unsigned short num_rte; /* # of RTEs on this IOSAPIC */ 124c5e3f9e5SYasuaki Ishimatsu int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ 125c5e3f9e5SYasuaki Ishimatsu #ifdef CONFIG_NUMA 126c5e3f9e5SYasuaki Ishimatsu unsigned short node; /* numa node association via pxm */ 127c5e3f9e5SYasuaki Ishimatsu #endif 128c1726d6fSYasuaki Ishimatsu spinlock_t lock; /* lock for indirect reg access */ 129c5e3f9e5SYasuaki Ishimatsu } iosapic_lists[NR_IOSAPICS]; 1301da177e4SLinus Torvalds 13124eeb568SKenji Kaneshige struct iosapic_rte_info { 132c5e3f9e5SYasuaki Ishimatsu struct list_head rte_list; /* RTEs sharing the same vector */ 13324eeb568SKenji Kaneshige char rte_index; /* IOSAPIC RTE index */ 13424eeb568SKenji Kaneshige int refcnt; /* reference counter */ 135c5e3f9e5SYasuaki Ishimatsu struct iosapic *iosapic; 13624eeb568SKenji Kaneshige } ____cacheline_aligned; 13724eeb568SKenji Kaneshige 13824eeb568SKenji Kaneshige static struct iosapic_intr_info { 13946cba3dcSSatoru Takeuchi struct list_head rtes; /* RTEs using this vector (empty => 14046cba3dcSSatoru Takeuchi * not an IOSAPIC interrupt) */ 141c4c376f7SKenji Kaneshige int count; /* # of registered RTEs */ 14246cba3dcSSatoru Takeuchi u32 low32; /* current value of low word of 14346cba3dcSSatoru Takeuchi * Redirection table entry */ 14424eeb568SKenji Kaneshige unsigned int dest; /* destination CPU physical ID */ 1451da177e4SLinus Torvalds unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ 14646cba3dcSSatoru Takeuchi unsigned char polarity: 1; /* interrupt polarity 14746cba3dcSSatoru Takeuchi * (see iosapic.h) */ 1481da177e4SLinus Torvalds unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ 1494bbdec7aSYasuaki Ishimatsu } iosapic_intr_info[NR_IRQS]; 1501da177e4SLinus Torvalds 1510e888adcSKenji Kaneshige static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ 1521da177e4SLinus Torvalds 153c1726d6fSYasuaki Ishimatsu static inline void 154c1726d6fSYasuaki Ishimatsu iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val) 155c1726d6fSYasuaki Ishimatsu { 156c1726d6fSYasuaki Ishimatsu unsigned long flags; 157c1726d6fSYasuaki Ishimatsu 158c1726d6fSYasuaki Ishimatsu spin_lock_irqsave(&iosapic->lock, flags); 159c1726d6fSYasuaki Ishimatsu __iosapic_write(iosapic->addr, reg, val); 160c1726d6fSYasuaki Ishimatsu spin_unlock_irqrestore(&iosapic->lock, flags); 161c1726d6fSYasuaki Ishimatsu } 162c1726d6fSYasuaki Ishimatsu 1631da177e4SLinus Torvalds /* 1641da177e4SLinus Torvalds * Find an IOSAPIC associated with a GSI 1651da177e4SLinus Torvalds */ 1661da177e4SLinus Torvalds static inline int 1671da177e4SLinus Torvalds find_iosapic (unsigned int gsi) 1681da177e4SLinus Torvalds { 1691da177e4SLinus Torvalds int i; 1701da177e4SLinus Torvalds 1710e888adcSKenji Kaneshige for (i = 0; i < NR_IOSAPICS; i++) { 17246cba3dcSSatoru Takeuchi if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < 17346cba3dcSSatoru Takeuchi iosapic_lists[i].num_rte) 1741da177e4SLinus Torvalds return i; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds return -1; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1804bbdec7aSYasuaki Ishimatsu static inline int __gsi_to_irq(unsigned int gsi) 1811da177e4SLinus Torvalds { 1824bbdec7aSYasuaki Ishimatsu int irq; 1831da177e4SLinus Torvalds struct iosapic_intr_info *info; 18424eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 1851da177e4SLinus Torvalds 1864bbdec7aSYasuaki Ishimatsu for (irq = 0; irq < NR_IRQS; irq++) { 1874bbdec7aSYasuaki Ishimatsu info = &iosapic_intr_info[irq]; 18824eeb568SKenji Kaneshige list_for_each_entry(rte, &info->rtes, rte_list) 189c5e3f9e5SYasuaki Ishimatsu if (rte->iosapic->gsi_base + rte->rte_index == gsi) 1904bbdec7aSYasuaki Ishimatsu return irq; 1914bbdec7aSYasuaki Ishimatsu } 1921da177e4SLinus Torvalds return -1; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds int 1961da177e4SLinus Torvalds gsi_to_irq (unsigned int gsi) 1971da177e4SLinus Torvalds { 19824eeb568SKenji Kaneshige unsigned long flags; 19924eeb568SKenji Kaneshige int irq; 20024eeb568SKenji Kaneshige 2014bbdec7aSYasuaki Ishimatsu spin_lock_irqsave(&iosapic_lock, flags); 2024bbdec7aSYasuaki Ishimatsu irq = __gsi_to_irq(gsi); 2034bbdec7aSYasuaki Ishimatsu spin_unlock_irqrestore(&iosapic_lock, flags); 20424eeb568SKenji Kaneshige return irq; 20524eeb568SKenji Kaneshige } 20624eeb568SKenji Kaneshige 2074bbdec7aSYasuaki Ishimatsu static struct iosapic_rte_info *find_rte(unsigned int irq, unsigned int gsi) 20824eeb568SKenji Kaneshige { 20924eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 21024eeb568SKenji Kaneshige 2114bbdec7aSYasuaki Ishimatsu list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) 212c5e3f9e5SYasuaki Ishimatsu if (rte->iosapic->gsi_base + rte->rte_index == gsi) 21324eeb568SKenji Kaneshige return rte; 21424eeb568SKenji Kaneshige return NULL; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds static void 2184bbdec7aSYasuaki Ishimatsu set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds unsigned long pol, trigger, dmode; 2211da177e4SLinus Torvalds u32 low32, high32; 2221da177e4SLinus Torvalds int rte_index; 2231da177e4SLinus Torvalds char redir; 22424eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 2254bbdec7aSYasuaki Ishimatsu ia64_vector vector = irq_to_vector(irq); 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest); 2281da177e4SLinus Torvalds 2294bbdec7aSYasuaki Ishimatsu rte = find_rte(irq, gsi); 23024eeb568SKenji Kaneshige if (!rte) 2311da177e4SLinus Torvalds return; /* not an IOSAPIC interrupt */ 2321da177e4SLinus Torvalds 23324eeb568SKenji Kaneshige rte_index = rte->rte_index; 2344bbdec7aSYasuaki Ishimatsu pol = iosapic_intr_info[irq].polarity; 2354bbdec7aSYasuaki Ishimatsu trigger = iosapic_intr_info[irq].trigger; 2364bbdec7aSYasuaki Ishimatsu dmode = iosapic_intr_info[irq].dmode; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds #ifdef CONFIG_SMP 2414bbdec7aSYasuaki Ishimatsu set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); 2421da177e4SLinus Torvalds #endif 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | 2451da177e4SLinus Torvalds (trigger << IOSAPIC_TRIGGER_SHIFT) | 2461da177e4SLinus Torvalds (dmode << IOSAPIC_DELIVERY_SHIFT) | 2471da177e4SLinus Torvalds ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) | 2481da177e4SLinus Torvalds vector); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* dest contains both id and eid */ 2511da177e4SLinus Torvalds high32 = (dest << IOSAPIC_DEST_SHIFT); 2521da177e4SLinus Torvalds 253c1726d6fSYasuaki Ishimatsu iosapic_write(rte->iosapic, IOSAPIC_RTE_HIGH(rte_index), high32); 254c1726d6fSYasuaki Ishimatsu iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32); 2554bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].low32 = low32; 2564bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].dest = dest; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds static void 2608fac171fSThomas Gleixner nop (struct irq_data *data) 2611da177e4SLinus Torvalds { 2621da177e4SLinus Torvalds /* do nothing... */ 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 265a7956113SZou Nan hai 266a7956113SZou Nan hai #ifdef CONFIG_KEXEC 267a7956113SZou Nan hai void 268a7956113SZou Nan hai kexec_disable_iosapic(void) 269a7956113SZou Nan hai { 270a7956113SZou Nan hai struct iosapic_intr_info *info; 271a7956113SZou Nan hai struct iosapic_rte_info *rte; 2724bbdec7aSYasuaki Ishimatsu ia64_vector vec; 2734bbdec7aSYasuaki Ishimatsu int irq; 2744bbdec7aSYasuaki Ishimatsu 2754bbdec7aSYasuaki Ishimatsu for (irq = 0; irq < NR_IRQS; irq++) { 2764bbdec7aSYasuaki Ishimatsu info = &iosapic_intr_info[irq]; 2774bbdec7aSYasuaki Ishimatsu vec = irq_to_vector(irq); 278a7956113SZou Nan hai list_for_each_entry(rte, &info->rtes, 279a7956113SZou Nan hai rte_list) { 280c1726d6fSYasuaki Ishimatsu iosapic_write(rte->iosapic, 281a7956113SZou Nan hai IOSAPIC_RTE_LOW(rte->rte_index), 282a7956113SZou Nan hai IOSAPIC_MASK|vec); 283c5e3f9e5SYasuaki Ishimatsu iosapic_eoi(rte->iosapic->addr, vec); 284a7956113SZou Nan hai } 285a7956113SZou Nan hai } 286a7956113SZou Nan hai } 287a7956113SZou Nan hai #endif 288a7956113SZou Nan hai 2891da177e4SLinus Torvalds static void 2908fac171fSThomas Gleixner mask_irq (struct irq_data *data) 2911da177e4SLinus Torvalds { 2928fac171fSThomas Gleixner unsigned int irq = data->irq; 2931da177e4SLinus Torvalds u32 low32; 2941da177e4SLinus Torvalds int rte_index; 29524eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 2961da177e4SLinus Torvalds 297c4c376f7SKenji Kaneshige if (!iosapic_intr_info[irq].count) 2981da177e4SLinus Torvalds return; /* not an IOSAPIC interrupt! */ 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* set only the mask bit */ 3014bbdec7aSYasuaki Ishimatsu low32 = iosapic_intr_info[irq].low32 |= IOSAPIC_MASK; 3024bbdec7aSYasuaki Ishimatsu list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) { 30324eeb568SKenji Kaneshige rte_index = rte->rte_index; 304c1726d6fSYasuaki Ishimatsu iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32); 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds static void 3098fac171fSThomas Gleixner unmask_irq (struct irq_data *data) 3101da177e4SLinus Torvalds { 3118fac171fSThomas Gleixner unsigned int irq = data->irq; 3121da177e4SLinus Torvalds u32 low32; 3131da177e4SLinus Torvalds int rte_index; 31424eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 3151da177e4SLinus Torvalds 316c4c376f7SKenji Kaneshige if (!iosapic_intr_info[irq].count) 3171da177e4SLinus Torvalds return; /* not an IOSAPIC interrupt! */ 3181da177e4SLinus Torvalds 3194bbdec7aSYasuaki Ishimatsu low32 = iosapic_intr_info[irq].low32 &= ~IOSAPIC_MASK; 3204bbdec7aSYasuaki Ishimatsu list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) { 32124eeb568SKenji Kaneshige rte_index = rte->rte_index; 322c1726d6fSYasuaki Ishimatsu iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32); 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds 327d5dedd45SYinghai Lu static int 3288fac171fSThomas Gleixner iosapic_set_affinity(struct irq_data *data, const struct cpumask *mask, 3298fac171fSThomas Gleixner bool force) 3301da177e4SLinus Torvalds { 3311da177e4SLinus Torvalds #ifdef CONFIG_SMP 3328fac171fSThomas Gleixner unsigned int irq = data->irq; 3331da177e4SLinus Torvalds u32 high32, low32; 3340de26520SRusty Russell int cpu, dest, rte_index; 3351da177e4SLinus Torvalds int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; 33624eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 337c1726d6fSYasuaki Ishimatsu struct iosapic *iosapic; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds irq &= (~IA64_IRQ_REDIRECTED); 3401da177e4SLinus Torvalds 3410de26520SRusty Russell cpu = cpumask_first_and(cpu_online_mask, mask); 3420de26520SRusty Russell if (cpu >= nr_cpu_ids) 343d5dedd45SYinghai Lu return -1; 3441da177e4SLinus Torvalds 3450de26520SRusty Russell if (irq_prepare_move(irq, cpu)) 346d5dedd45SYinghai Lu return -1; 347cd378f18SYasuaki Ishimatsu 3480de26520SRusty Russell dest = cpu_physical_id(cpu); 3491da177e4SLinus Torvalds 350c4c376f7SKenji Kaneshige if (!iosapic_intr_info[irq].count) 351d5dedd45SYinghai Lu return -1; /* not an IOSAPIC interrupt */ 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds set_irq_affinity_info(irq, dest, redir); 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds /* dest contains both id and eid */ 3561da177e4SLinus Torvalds high32 = dest << IOSAPIC_DEST_SHIFT; 3571da177e4SLinus Torvalds 3584bbdec7aSYasuaki Ishimatsu low32 = iosapic_intr_info[irq].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); 3591da177e4SLinus Torvalds if (redir) 3601da177e4SLinus Torvalds /* change delivery mode to lowest priority */ 361e3a8f7b8SYasuaki Ishimatsu low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); 3621da177e4SLinus Torvalds else 3631da177e4SLinus Torvalds /* change delivery mode to fixed */ 3641da177e4SLinus Torvalds low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); 365cd378f18SYasuaki Ishimatsu low32 &= IOSAPIC_VECTOR_MASK; 366cd378f18SYasuaki Ishimatsu low32 |= irq_to_vector(irq); 3671da177e4SLinus Torvalds 3684bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].low32 = low32; 3694bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].dest = dest; 3704bbdec7aSYasuaki Ishimatsu list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) { 371c1726d6fSYasuaki Ishimatsu iosapic = rte->iosapic; 37224eeb568SKenji Kaneshige rte_index = rte->rte_index; 373c1726d6fSYasuaki Ishimatsu iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32); 374c1726d6fSYasuaki Ishimatsu iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32); 3751da177e4SLinus Torvalds } 376d5dedd45SYinghai Lu 3771da177e4SLinus Torvalds #endif 378d5dedd45SYinghai Lu return 0; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds /* 3821da177e4SLinus Torvalds * Handlers for level-triggered interrupts. 3831da177e4SLinus Torvalds */ 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds static unsigned int 3868fac171fSThomas Gleixner iosapic_startup_level_irq (struct irq_data *data) 3871da177e4SLinus Torvalds { 3888fac171fSThomas Gleixner unmask_irq(data); 3891da177e4SLinus Torvalds return 0; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds static void 3938fac171fSThomas Gleixner iosapic_unmask_level_irq (struct irq_data *data) 3941da177e4SLinus Torvalds { 3958fac171fSThomas Gleixner unsigned int irq = data->irq; 3961da177e4SLinus Torvalds ia64_vector vec = irq_to_vector(irq); 39724eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 398cd378f18SYasuaki Ishimatsu int do_unmask_irq = 0; 3991da177e4SLinus Torvalds 400a6cd6322SKenji Kaneshige irq_complete_move(irq); 40191ce72e0SThomas Gleixner if (unlikely(irqd_is_setaffinity_pending(data))) { 402cd378f18SYasuaki Ishimatsu do_unmask_irq = 1; 4038fac171fSThomas Gleixner mask_irq(data); 4045d4bff94STony Luck } else 4058fac171fSThomas Gleixner unmask_irq(data); 406cd378f18SYasuaki Ishimatsu 4074bbdec7aSYasuaki Ishimatsu list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) 408c5e3f9e5SYasuaki Ishimatsu iosapic_eoi(rte->iosapic->addr, vec); 409cd378f18SYasuaki Ishimatsu 410cd378f18SYasuaki Ishimatsu if (unlikely(do_unmask_irq)) { 41191ce72e0SThomas Gleixner irq_move_masked_irq(data); 4128fac171fSThomas Gleixner unmask_irq(data); 413cd378f18SYasuaki Ishimatsu } 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 4161da177e4SLinus Torvalds #define iosapic_shutdown_level_irq mask_irq 4171da177e4SLinus Torvalds #define iosapic_enable_level_irq unmask_irq 4181da177e4SLinus Torvalds #define iosapic_disable_level_irq mask_irq 4191da177e4SLinus Torvalds #define iosapic_ack_level_irq nop 4201da177e4SLinus Torvalds 4219e004ebdSSimon Horman static struct irq_chip irq_type_iosapic_level = { 42206344db3SIngo Molnar .name = "IO-SAPIC-level", 4238fac171fSThomas Gleixner .irq_startup = iosapic_startup_level_irq, 4248fac171fSThomas Gleixner .irq_shutdown = iosapic_shutdown_level_irq, 4258fac171fSThomas Gleixner .irq_enable = iosapic_enable_level_irq, 4268fac171fSThomas Gleixner .irq_disable = iosapic_disable_level_irq, 4278fac171fSThomas Gleixner .irq_ack = iosapic_ack_level_irq, 4288fac171fSThomas Gleixner .irq_mask = mask_irq, 4298fac171fSThomas Gleixner .irq_unmask = iosapic_unmask_level_irq, 4308fac171fSThomas Gleixner .irq_set_affinity = iosapic_set_affinity 4311da177e4SLinus Torvalds }; 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds /* 4341da177e4SLinus Torvalds * Handlers for edge-triggered interrupts. 4351da177e4SLinus Torvalds */ 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds static unsigned int 4388fac171fSThomas Gleixner iosapic_startup_edge_irq (struct irq_data *data) 4391da177e4SLinus Torvalds { 4408fac171fSThomas Gleixner unmask_irq(data); 4411da177e4SLinus Torvalds /* 4421da177e4SLinus Torvalds * IOSAPIC simply drops interrupts pended while the 4431da177e4SLinus Torvalds * corresponding pin was masked, so we can't know if an 4441da177e4SLinus Torvalds * interrupt is pending already. Let's hope not... 4451da177e4SLinus Torvalds */ 4461da177e4SLinus Torvalds return 0; 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds static void 4508fac171fSThomas Gleixner iosapic_ack_edge_irq (struct irq_data *data) 4511da177e4SLinus Torvalds { 45291ce72e0SThomas Gleixner irq_complete_move(data->irq); 45391ce72e0SThomas Gleixner irq_move_irq(data); 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds #define iosapic_enable_edge_irq unmask_irq 4571da177e4SLinus Torvalds #define iosapic_disable_edge_irq nop 4581da177e4SLinus Torvalds 4599e004ebdSSimon Horman static struct irq_chip irq_type_iosapic_edge = { 46006344db3SIngo Molnar .name = "IO-SAPIC-edge", 4618fac171fSThomas Gleixner .irq_startup = iosapic_startup_edge_irq, 4628fac171fSThomas Gleixner .irq_shutdown = iosapic_disable_edge_irq, 4638fac171fSThomas Gleixner .irq_enable = iosapic_enable_edge_irq, 4648fac171fSThomas Gleixner .irq_disable = iosapic_disable_edge_irq, 4658fac171fSThomas Gleixner .irq_ack = iosapic_ack_edge_irq, 4668fac171fSThomas Gleixner .irq_mask = mask_irq, 4678fac171fSThomas Gleixner .irq_unmask = unmask_irq, 4688fac171fSThomas Gleixner .irq_set_affinity = iosapic_set_affinity 4691da177e4SLinus Torvalds }; 4701da177e4SLinus Torvalds 4719e004ebdSSimon Horman static unsigned int 4721da177e4SLinus Torvalds iosapic_version (char __iomem *addr) 4731da177e4SLinus Torvalds { 4741da177e4SLinus Torvalds /* 4751da177e4SLinus Torvalds * IOSAPIC Version Register return 32 bit structure like: 4761da177e4SLinus Torvalds * { 4771da177e4SLinus Torvalds * unsigned int version : 8; 4781da177e4SLinus Torvalds * unsigned int reserved1 : 8; 4791da177e4SLinus Torvalds * unsigned int max_redir : 8; 4801da177e4SLinus Torvalds * unsigned int reserved2 : 8; 4811da177e4SLinus Torvalds * } 4821da177e4SLinus Torvalds */ 483c1726d6fSYasuaki Ishimatsu return __iosapic_read(addr, IOSAPIC_VERSION); 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds 4864bbdec7aSYasuaki Ishimatsu static int iosapic_find_sharable_irq(unsigned long trigger, unsigned long pol) 48724eeb568SKenji Kaneshige { 4884bbdec7aSYasuaki Ishimatsu int i, irq = -ENOSPC, min_count = -1; 48924eeb568SKenji Kaneshige struct iosapic_intr_info *info; 49024eeb568SKenji Kaneshige 49124eeb568SKenji Kaneshige /* 49224eeb568SKenji Kaneshige * shared vectors for edge-triggered interrupts are not 49324eeb568SKenji Kaneshige * supported yet 49424eeb568SKenji Kaneshige */ 49524eeb568SKenji Kaneshige if (trigger == IOSAPIC_EDGE) 49640598cbeSYasuaki Ishimatsu return -EINVAL; 49724eeb568SKenji Kaneshige 4985b592397SRoel Kluin for (i = 0; i < NR_IRQS; i++) { 49924eeb568SKenji Kaneshige info = &iosapic_intr_info[i]; 50024eeb568SKenji Kaneshige if (info->trigger == trigger && info->polarity == pol && 501f8c087f3SYasuaki Ishimatsu (info->dmode == IOSAPIC_FIXED || 502f8c087f3SYasuaki Ishimatsu info->dmode == IOSAPIC_LOWEST_PRIORITY) && 503f8c087f3SYasuaki Ishimatsu can_request_irq(i, IRQF_SHARED)) { 50424eeb568SKenji Kaneshige if (min_count == -1 || info->count < min_count) { 5054bbdec7aSYasuaki Ishimatsu irq = i; 50624eeb568SKenji Kaneshige min_count = info->count; 50724eeb568SKenji Kaneshige } 50824eeb568SKenji Kaneshige } 50924eeb568SKenji Kaneshige } 5104bbdec7aSYasuaki Ishimatsu return irq; 51124eeb568SKenji Kaneshige } 51224eeb568SKenji Kaneshige 5131da177e4SLinus Torvalds /* 5141da177e4SLinus Torvalds * if the given vector is already owned by other, 5151da177e4SLinus Torvalds * assign a new vector for the other and make the vector available 5161da177e4SLinus Torvalds */ 5171da177e4SLinus Torvalds static void __init 5184bbdec7aSYasuaki Ishimatsu iosapic_reassign_vector (int irq) 5191da177e4SLinus Torvalds { 5204bbdec7aSYasuaki Ishimatsu int new_irq; 5211da177e4SLinus Torvalds 522c4c376f7SKenji Kaneshige if (iosapic_intr_info[irq].count) { 5234bbdec7aSYasuaki Ishimatsu new_irq = create_irq(); 5244bbdec7aSYasuaki Ishimatsu if (new_irq < 0) 525d4ed8084SHarvey Harrison panic("%s: out of interrupt vectors!\n", __func__); 52646cba3dcSSatoru Takeuchi printk(KERN_INFO "Reassigning vector %d to %d\n", 5274bbdec7aSYasuaki Ishimatsu irq_to_vector(irq), irq_to_vector(new_irq)); 5284bbdec7aSYasuaki Ishimatsu memcpy(&iosapic_intr_info[new_irq], &iosapic_intr_info[irq], 5291da177e4SLinus Torvalds sizeof(struct iosapic_intr_info)); 5304bbdec7aSYasuaki Ishimatsu INIT_LIST_HEAD(&iosapic_intr_info[new_irq].rtes); 5314bbdec7aSYasuaki Ishimatsu list_move(iosapic_intr_info[irq].rtes.next, 5324bbdec7aSYasuaki Ishimatsu &iosapic_intr_info[new_irq].rtes); 5334bbdec7aSYasuaki Ishimatsu memset(&iosapic_intr_info[irq], 0, 53446cba3dcSSatoru Takeuchi sizeof(struct iosapic_intr_info)); 5354bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].low32 = IOSAPIC_MASK; 5364bbdec7aSYasuaki Ishimatsu INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes); 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds 5404bbdec7aSYasuaki Ishimatsu static inline int irq_is_shared (int irq) 54124eeb568SKenji Kaneshige { 5424bbdec7aSYasuaki Ishimatsu return (iosapic_intr_info[irq].count > 1); 54324eeb568SKenji Kaneshige } 54424eeb568SKenji Kaneshige 54533b39e84SIsaku Yamahata struct irq_chip* 54633b39e84SIsaku Yamahata ia64_native_iosapic_get_irq_chip(unsigned long trigger) 54733b39e84SIsaku Yamahata { 54833b39e84SIsaku Yamahata if (trigger == IOSAPIC_EDGE) 54933b39e84SIsaku Yamahata return &irq_type_iosapic_edge; 55033b39e84SIsaku Yamahata else 55133b39e84SIsaku Yamahata return &irq_type_iosapic_level; 55233b39e84SIsaku Yamahata } 55333b39e84SIsaku Yamahata 55414454a1bSKenji Kaneshige static int 5554bbdec7aSYasuaki Ishimatsu register_intr (unsigned int gsi, int irq, unsigned char delivery, 5561da177e4SLinus Torvalds unsigned long polarity, unsigned long trigger) 5571da177e4SLinus Torvalds { 558dea1078eSThomas Gleixner struct irq_chip *chip, *irq_type; 5591da177e4SLinus Torvalds int index; 56024eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds index = find_iosapic(gsi); 5631da177e4SLinus Torvalds if (index < 0) { 56446cba3dcSSatoru Takeuchi printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", 565d4ed8084SHarvey Harrison __func__, gsi); 56614454a1bSKenji Kaneshige return -ENODEV; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 5694bbdec7aSYasuaki Ishimatsu rte = find_rte(irq, gsi); 57024eeb568SKenji Kaneshige if (!rte) { 5714de0a759STony Luck rte = kzalloc(sizeof (*rte), GFP_ATOMIC); 57224eeb568SKenji Kaneshige if (!rte) { 57346cba3dcSSatoru Takeuchi printk(KERN_WARNING "%s: cannot allocate memory\n", 574d4ed8084SHarvey Harrison __func__); 57514454a1bSKenji Kaneshige return -ENOMEM; 57624eeb568SKenji Kaneshige } 57724eeb568SKenji Kaneshige 578c5e3f9e5SYasuaki Ishimatsu rte->iosapic = &iosapic_lists[index]; 579c5e3f9e5SYasuaki Ishimatsu rte->rte_index = gsi - rte->iosapic->gsi_base; 58024eeb568SKenji Kaneshige rte->refcnt++; 5814bbdec7aSYasuaki Ishimatsu list_add_tail(&rte->rte_list, &iosapic_intr_info[irq].rtes); 5824bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].count++; 5830e888adcSKenji Kaneshige iosapic_lists[index].rtes_inuse++; 58424eeb568SKenji Kaneshige } 585e1b30a39SYasuaki Ishimatsu else if (rte->refcnt == NO_REF_RTE) { 5864bbdec7aSYasuaki Ishimatsu struct iosapic_intr_info *info = &iosapic_intr_info[irq]; 587e1b30a39SYasuaki Ishimatsu if (info->count > 0 && 588e1b30a39SYasuaki Ishimatsu (info->trigger != trigger || info->polarity != polarity)){ 58946cba3dcSSatoru Takeuchi printk (KERN_WARNING 59046cba3dcSSatoru Takeuchi "%s: cannot override the interrupt\n", 591d4ed8084SHarvey Harrison __func__); 59214454a1bSKenji Kaneshige return -EINVAL; 59324eeb568SKenji Kaneshige } 594e1b30a39SYasuaki Ishimatsu rte->refcnt++; 595e1b30a39SYasuaki Ishimatsu iosapic_intr_info[irq].count++; 596e1b30a39SYasuaki Ishimatsu iosapic_lists[index].rtes_inuse++; 59724eeb568SKenji Kaneshige } 59824eeb568SKenji Kaneshige 5994bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].polarity = polarity; 6004bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].dmode = delivery; 6014bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].trigger = trigger; 6021da177e4SLinus Torvalds 60333b39e84SIsaku Yamahata irq_type = iosapic_get_irq_chip(trigger); 6041da177e4SLinus Torvalds 605dea1078eSThomas Gleixner chip = irq_get_chip(irq); 606dea1078eSThomas Gleixner if (irq_type != NULL && chip != irq_type) { 607dea1078eSThomas Gleixner if (chip != &no_irq_chip) 60846cba3dcSSatoru Takeuchi printk(KERN_WARNING 60946cba3dcSSatoru Takeuchi "%s: changing vector %d from %s to %s\n", 610d4ed8084SHarvey Harrison __func__, irq_to_vector(irq), 611dea1078eSThomas Gleixner chip->name, irq_type->name); 612dea1078eSThomas Gleixner chip = irq_type; 6131da177e4SLinus Torvalds } 614dea1078eSThomas Gleixner __irq_set_chip_handler_name_locked(irq, chip, trigger == IOSAPIC_EDGE ? 615dea1078eSThomas Gleixner handle_edge_irq : handle_level_irq, 616dea1078eSThomas Gleixner NULL); 61714454a1bSKenji Kaneshige return 0; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds static unsigned int 6214bbdec7aSYasuaki Ishimatsu get_target_cpu (unsigned int gsi, int irq) 6221da177e4SLinus Torvalds { 6231da177e4SLinus Torvalds #ifdef CONFIG_SMP 6241da177e4SLinus Torvalds static int cpu = -1; 625ff741906SAshok Raj extern int cpe_vector; 6264994be1bSYasuaki Ishimatsu cpumask_t domain = irq_to_domain(irq); 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds /* 62924eeb568SKenji Kaneshige * In case of vector shared by multiple RTEs, all RTEs that 63024eeb568SKenji Kaneshige * share the vector need to use the same destination CPU. 63124eeb568SKenji Kaneshige */ 632c4c376f7SKenji Kaneshige if (iosapic_intr_info[irq].count) 6334bbdec7aSYasuaki Ishimatsu return iosapic_intr_info[irq].dest; 63424eeb568SKenji Kaneshige 63524eeb568SKenji Kaneshige /* 6361da177e4SLinus Torvalds * If the platform supports redirection via XTP, let it 6371da177e4SLinus Torvalds * distribute interrupts. 6381da177e4SLinus Torvalds */ 6391da177e4SLinus Torvalds if (smp_int_redirect & SMP_IRQ_REDIRECTION) 6401da177e4SLinus Torvalds return cpu_physical_id(smp_processor_id()); 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds /* 6431da177e4SLinus Torvalds * Some interrupts (ACPI SCI, for instance) are registered 6441da177e4SLinus Torvalds * before the BSP is marked as online. 6451da177e4SLinus Torvalds */ 6461da177e4SLinus Torvalds if (!cpu_online(smp_processor_id())) 6471da177e4SLinus Torvalds return cpu_physical_id(smp_processor_id()); 6481da177e4SLinus Torvalds 649ff741906SAshok Raj #ifdef CONFIG_ACPI 6504bbdec7aSYasuaki Ishimatsu if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR) 651ff741906SAshok Raj return get_cpei_target_cpu(); 652ff741906SAshok Raj #endif 653ff741906SAshok Raj 6541da177e4SLinus Torvalds #ifdef CONFIG_NUMA 6551da177e4SLinus Torvalds { 6561da177e4SLinus Torvalds int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0; 657fbb776c3SRusty Russell const struct cpumask *cpu_mask; 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds iosapic_index = find_iosapic(gsi); 6601da177e4SLinus Torvalds if (iosapic_index < 0 || 6611da177e4SLinus Torvalds iosapic_lists[iosapic_index].node == MAX_NUMNODES) 6621da177e4SLinus Torvalds goto skip_numa_setup; 6631da177e4SLinus Torvalds 664fbb776c3SRusty Russell cpu_mask = cpumask_of_node(iosapic_lists[iosapic_index].node); 665fbb776c3SRusty Russell num_cpus = 0; 666fbb776c3SRusty Russell for_each_cpu_and(numa_cpu, cpu_mask, &domain) { 667fbb776c3SRusty Russell if (cpu_online(numa_cpu)) 668fbb776c3SRusty Russell num_cpus++; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds if (!num_cpus) 6721da177e4SLinus Torvalds goto skip_numa_setup; 6731da177e4SLinus Torvalds 6744bbdec7aSYasuaki Ishimatsu /* Use irq assignment to distribute across cpus in node */ 6754bbdec7aSYasuaki Ishimatsu cpu_index = irq % num_cpus; 6761da177e4SLinus Torvalds 677fbb776c3SRusty Russell for_each_cpu_and(numa_cpu, cpu_mask, &domain) 678fbb776c3SRusty Russell if (cpu_online(numa_cpu) && i++ >= cpu_index) 679fbb776c3SRusty Russell break; 6801da177e4SLinus Torvalds 681fbb776c3SRusty Russell if (numa_cpu < nr_cpu_ids) 6821da177e4SLinus Torvalds return cpu_physical_id(numa_cpu); 6831da177e4SLinus Torvalds } 6841da177e4SLinus Torvalds skip_numa_setup: 6851da177e4SLinus Torvalds #endif 6861da177e4SLinus Torvalds /* 6871da177e4SLinus Torvalds * Otherwise, round-robin interrupt vectors across all the 6881da177e4SLinus Torvalds * processors. (It'd be nice if we could be smarter in the 6891da177e4SLinus Torvalds * case of NUMA.) 6901da177e4SLinus Torvalds */ 6911da177e4SLinus Torvalds do { 692fbb776c3SRusty Russell if (++cpu >= nr_cpu_ids) 6931da177e4SLinus Torvalds cpu = 0; 6944994be1bSYasuaki Ishimatsu } while (!cpu_online(cpu) || !cpu_isset(cpu, domain)); 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds return cpu_physical_id(cpu); 69746cba3dcSSatoru Takeuchi #else /* CONFIG_SMP */ 6981da177e4SLinus Torvalds return cpu_physical_id(smp_processor_id()); 6991da177e4SLinus Torvalds #endif 7001da177e4SLinus Torvalds } 7011da177e4SLinus Torvalds 702c9d059deSKenji Kaneshige static inline unsigned char choose_dmode(void) 703c9d059deSKenji Kaneshige { 704c9d059deSKenji Kaneshige #ifdef CONFIG_SMP 705c9d059deSKenji Kaneshige if (smp_int_redirect & SMP_IRQ_REDIRECTION) 706c9d059deSKenji Kaneshige return IOSAPIC_LOWEST_PRIORITY; 707c9d059deSKenji Kaneshige #endif 708c9d059deSKenji Kaneshige return IOSAPIC_FIXED; 709c9d059deSKenji Kaneshige } 710c9d059deSKenji Kaneshige 7111da177e4SLinus Torvalds /* 7121da177e4SLinus Torvalds * ACPI can describe IOSAPIC interrupts via static tables and namespace 7131da177e4SLinus Torvalds * methods. This provides an interface to register those interrupts and 7141da177e4SLinus Torvalds * program the IOSAPIC RTE. 7151da177e4SLinus Torvalds */ 7161da177e4SLinus Torvalds int 7171da177e4SLinus Torvalds iosapic_register_intr (unsigned int gsi, 7181da177e4SLinus Torvalds unsigned long polarity, unsigned long trigger) 7191da177e4SLinus Torvalds { 7204bbdec7aSYasuaki Ishimatsu int irq, mask = 1, err; 7211da177e4SLinus Torvalds unsigned int dest; 7221da177e4SLinus Torvalds unsigned long flags; 72324eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 72424eeb568SKenji Kaneshige u32 low32; 725c9d059deSKenji Kaneshige unsigned char dmode; 726dea1078eSThomas Gleixner struct irq_desc *desc; 72740598cbeSYasuaki Ishimatsu 7281da177e4SLinus Torvalds /* 7291da177e4SLinus Torvalds * If this GSI has already been registered (i.e., it's a 7301da177e4SLinus Torvalds * shared interrupt, or we lost a race to register it), 7311da177e4SLinus Torvalds * don't touch the RTE. 7321da177e4SLinus Torvalds */ 7331da177e4SLinus Torvalds spin_lock_irqsave(&iosapic_lock, flags); 7344bbdec7aSYasuaki Ishimatsu irq = __gsi_to_irq(gsi); 7354bbdec7aSYasuaki Ishimatsu if (irq > 0) { 7364bbdec7aSYasuaki Ishimatsu rte = find_rte(irq, gsi); 737e1b30a39SYasuaki Ishimatsu if(iosapic_intr_info[irq].count == 0) { 738e1b30a39SYasuaki Ishimatsu assign_irq_vector(irq); 739e1b30a39SYasuaki Ishimatsu dynamic_irq_init(irq); 740e1b30a39SYasuaki Ishimatsu } else if (rte->refcnt != NO_REF_RTE) { 74124eeb568SKenji Kaneshige rte->refcnt++; 74240598cbeSYasuaki Ishimatsu goto unlock_iosapic_lock; 7431da177e4SLinus Torvalds } 744e1b30a39SYasuaki Ishimatsu } else 745e1b30a39SYasuaki Ishimatsu irq = create_irq(); 7461da177e4SLinus Torvalds 74724eeb568SKenji Kaneshige /* If vector is running out, we try to find a sharable vector */ 748eb21ab24SYasuaki Ishimatsu if (irq < 0) { 7494bbdec7aSYasuaki Ishimatsu irq = iosapic_find_sharable_irq(trigger, polarity); 7504bbdec7aSYasuaki Ishimatsu if (irq < 0) 75140598cbeSYasuaki Ishimatsu goto unlock_iosapic_lock; 7524bbdec7aSYasuaki Ishimatsu } 75324eeb568SKenji Kaneshige 754dea1078eSThomas Gleixner desc = irq_to_desc(irq); 755dea1078eSThomas Gleixner raw_spin_lock(&desc->lock); 7564bbdec7aSYasuaki Ishimatsu dest = get_target_cpu(gsi, irq); 757c9d059deSKenji Kaneshige dmode = choose_dmode(); 758c9d059deSKenji Kaneshige err = register_intr(gsi, irq, dmode, polarity, trigger); 75914454a1bSKenji Kaneshige if (err < 0) { 760dea1078eSThomas Gleixner raw_spin_unlock(&desc->lock); 7614bbdec7aSYasuaki Ishimatsu irq = err; 762224685c0SKenji Kaneshige goto unlock_iosapic_lock; 76314454a1bSKenji Kaneshige } 7641da177e4SLinus Torvalds 76524eeb568SKenji Kaneshige /* 766e3a8f7b8SYasuaki Ishimatsu * If the vector is shared and already unmasked for other 767e3a8f7b8SYasuaki Ishimatsu * interrupt sources, don't mask it. 76824eeb568SKenji Kaneshige */ 7694bbdec7aSYasuaki Ishimatsu low32 = iosapic_intr_info[irq].low32; 7704bbdec7aSYasuaki Ishimatsu if (irq_is_shared(irq) && !(low32 & IOSAPIC_MASK)) 77124eeb568SKenji Kaneshige mask = 0; 7724bbdec7aSYasuaki Ishimatsu set_rte(gsi, irq, dest, mask); 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", 7751da177e4SLinus Torvalds gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), 7761da177e4SLinus Torvalds (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 7774bbdec7aSYasuaki Ishimatsu cpu_logical_id(dest), dest, irq_to_vector(irq)); 778224685c0SKenji Kaneshige 779dea1078eSThomas Gleixner raw_spin_unlock(&desc->lock); 78040598cbeSYasuaki Ishimatsu unlock_iosapic_lock: 78140598cbeSYasuaki Ishimatsu spin_unlock_irqrestore(&iosapic_lock, flags); 7824bbdec7aSYasuaki Ishimatsu return irq; 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds void 7861da177e4SLinus Torvalds iosapic_unregister_intr (unsigned int gsi) 7871da177e4SLinus Torvalds { 7881da177e4SLinus Torvalds unsigned long flags; 7894bbdec7aSYasuaki Ishimatsu int irq, index; 79024eeb568SKenji Kaneshige u32 low32; 7911da177e4SLinus Torvalds unsigned long trigger, polarity; 79224eeb568SKenji Kaneshige unsigned int dest; 79324eeb568SKenji Kaneshige struct iosapic_rte_info *rte; 7941da177e4SLinus Torvalds 7951da177e4SLinus Torvalds /* 7961da177e4SLinus Torvalds * If the irq associated with the gsi is not found, 7971da177e4SLinus Torvalds * iosapic_unregister_intr() is unbalanced. We need to check 7981da177e4SLinus Torvalds * this again after getting locks. 7991da177e4SLinus Torvalds */ 8001da177e4SLinus Torvalds irq = gsi_to_irq(gsi); 8011da177e4SLinus Torvalds if (irq < 0) { 80246cba3dcSSatoru Takeuchi printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", 80346cba3dcSSatoru Takeuchi gsi); 8041da177e4SLinus Torvalds WARN_ON(1); 8051da177e4SLinus Torvalds return; 8061da177e4SLinus Torvalds } 8071da177e4SLinus Torvalds 80840598cbeSYasuaki Ishimatsu spin_lock_irqsave(&iosapic_lock, flags); 8094bbdec7aSYasuaki Ishimatsu if ((rte = find_rte(irq, gsi)) == NULL) { 810e3a8f7b8SYasuaki Ishimatsu printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", 81146cba3dcSSatoru Takeuchi gsi); 8121da177e4SLinus Torvalds WARN_ON(1); 81324eeb568SKenji Kaneshige goto out; 8141da177e4SLinus Torvalds } 8151da177e4SLinus Torvalds 81624eeb568SKenji Kaneshige if (--rte->refcnt > 0) 81724eeb568SKenji Kaneshige goto out; 8181da177e4SLinus Torvalds 819e1b30a39SYasuaki Ishimatsu rte->refcnt = NO_REF_RTE; 82040598cbeSYasuaki Ishimatsu 82124eeb568SKenji Kaneshige /* Mask the interrupt */ 8224bbdec7aSYasuaki Ishimatsu low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK; 823c1726d6fSYasuaki Ishimatsu iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32); 8241da177e4SLinus Torvalds 8254bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].count--; 8260e888adcSKenji Kaneshige index = find_iosapic(gsi); 8270e888adcSKenji Kaneshige iosapic_lists[index].rtes_inuse--; 8280e888adcSKenji Kaneshige WARN_ON(iosapic_lists[index].rtes_inuse < 0); 8291da177e4SLinus Torvalds 8304bbdec7aSYasuaki Ishimatsu trigger = iosapic_intr_info[irq].trigger; 8314bbdec7aSYasuaki Ishimatsu polarity = iosapic_intr_info[irq].polarity; 8324bbdec7aSYasuaki Ishimatsu dest = iosapic_intr_info[irq].dest; 83346cba3dcSSatoru Takeuchi printk(KERN_INFO 834e3a8f7b8SYasuaki Ishimatsu "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", 83524eeb568SKenji Kaneshige gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), 83624eeb568SKenji Kaneshige (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 8374bbdec7aSYasuaki Ishimatsu cpu_logical_id(dest), dest, irq_to_vector(irq)); 8381da177e4SLinus Torvalds 839e1b30a39SYasuaki Ishimatsu if (iosapic_intr_info[irq].count == 0) { 840451fe00cSAlex Williamson #ifdef CONFIG_SMP 841451fe00cSAlex Williamson /* Clear affinity */ 842dea1078eSThomas Gleixner cpumask_setall(irq_get_irq_data(irq)->affinity); 843451fe00cSAlex Williamson #endif 84424eeb568SKenji Kaneshige /* Clear the interrupt information */ 845e1b30a39SYasuaki Ishimatsu iosapic_intr_info[irq].dest = 0; 846e1b30a39SYasuaki Ishimatsu iosapic_intr_info[irq].dmode = 0; 847e1b30a39SYasuaki Ishimatsu iosapic_intr_info[irq].polarity = 0; 848e1b30a39SYasuaki Ishimatsu iosapic_intr_info[irq].trigger = 0; 8494bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].low32 |= IOSAPIC_MASK; 85024eeb568SKenji Kaneshige 851e1b30a39SYasuaki Ishimatsu /* Destroy and reserve IRQ */ 852e1b30a39SYasuaki Ishimatsu destroy_and_reserve_irq(irq); 85324eeb568SKenji Kaneshige } 85424eeb568SKenji Kaneshige out: 85540598cbeSYasuaki Ishimatsu spin_unlock_irqrestore(&iosapic_lock, flags); 8561da177e4SLinus Torvalds } 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds /* 8591da177e4SLinus Torvalds * ACPI calls this when it finds an entry for a platform interrupt. 8601da177e4SLinus Torvalds */ 8611da177e4SLinus Torvalds int __init 8621da177e4SLinus Torvalds iosapic_register_platform_intr (u32 int_type, unsigned int gsi, 8631da177e4SLinus Torvalds int iosapic_vector, u16 eid, u16 id, 8641da177e4SLinus Torvalds unsigned long polarity, unsigned long trigger) 8651da177e4SLinus Torvalds { 8661da177e4SLinus Torvalds static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"}; 8671da177e4SLinus Torvalds unsigned char delivery; 868eb21ab24SYasuaki Ishimatsu int irq, vector, mask = 0; 8691da177e4SLinus Torvalds unsigned int dest = ((id << 8) | eid) & 0xffff; 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds switch (int_type) { 8721da177e4SLinus Torvalds case ACPI_INTERRUPT_PMI: 873e1b30a39SYasuaki Ishimatsu irq = vector = iosapic_vector; 8744994be1bSYasuaki Ishimatsu bind_irq_vector(irq, vector, CPU_MASK_ALL); 8751da177e4SLinus Torvalds /* 8761da177e4SLinus Torvalds * since PMI vector is alloc'd by FW(ACPI) not by kernel, 8771da177e4SLinus Torvalds * we need to make sure the vector is available 8781da177e4SLinus Torvalds */ 8794bbdec7aSYasuaki Ishimatsu iosapic_reassign_vector(irq); 8801da177e4SLinus Torvalds delivery = IOSAPIC_PMI; 8811da177e4SLinus Torvalds break; 8821da177e4SLinus Torvalds case ACPI_INTERRUPT_INIT: 883eb21ab24SYasuaki Ishimatsu irq = create_irq(); 884eb21ab24SYasuaki Ishimatsu if (irq < 0) 885d4ed8084SHarvey Harrison panic("%s: out of interrupt vectors!\n", __func__); 886eb21ab24SYasuaki Ishimatsu vector = irq_to_vector(irq); 8871da177e4SLinus Torvalds delivery = IOSAPIC_INIT; 8881da177e4SLinus Torvalds break; 8891da177e4SLinus Torvalds case ACPI_INTERRUPT_CPEI: 890e1b30a39SYasuaki Ishimatsu irq = vector = IA64_CPE_VECTOR; 8914994be1bSYasuaki Ishimatsu BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL)); 892aa0ebec9SKenji Kaneshige delivery = IOSAPIC_FIXED; 8931da177e4SLinus Torvalds mask = 1; 8941da177e4SLinus Torvalds break; 8951da177e4SLinus Torvalds default: 896d4ed8084SHarvey Harrison printk(KERN_ERR "%s: invalid int type 0x%x\n", __func__, 89746cba3dcSSatoru Takeuchi int_type); 8981da177e4SLinus Torvalds return -1; 8991da177e4SLinus Torvalds } 9001da177e4SLinus Torvalds 9014bbdec7aSYasuaki Ishimatsu register_intr(gsi, irq, delivery, polarity, trigger); 9021da177e4SLinus Torvalds 90346cba3dcSSatoru Takeuchi printk(KERN_INFO 90446cba3dcSSatoru Takeuchi "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)" 90546cba3dcSSatoru Takeuchi " vector %d\n", 9061da177e4SLinus Torvalds int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown", 9071da177e4SLinus Torvalds int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), 9081da177e4SLinus Torvalds (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 9091da177e4SLinus Torvalds cpu_logical_id(dest), dest, vector); 9101da177e4SLinus Torvalds 9114bbdec7aSYasuaki Ishimatsu set_rte(gsi, irq, dest, mask); 9121da177e4SLinus Torvalds return vector; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds /* 9161da177e4SLinus Torvalds * ACPI calls this when it finds an entry for a legacy ISA IRQ override. 9171da177e4SLinus Torvalds */ 9180f7ac29eSTony Luck void __devinit 9191da177e4SLinus Torvalds iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, 9201da177e4SLinus Torvalds unsigned long polarity, 9211da177e4SLinus Torvalds unsigned long trigger) 9221da177e4SLinus Torvalds { 9234bbdec7aSYasuaki Ishimatsu int vector, irq; 9241da177e4SLinus Torvalds unsigned int dest = cpu_physical_id(smp_processor_id()); 925c9d059deSKenji Kaneshige unsigned char dmode; 9261da177e4SLinus Torvalds 927e1b30a39SYasuaki Ishimatsu irq = vector = isa_irq_to_vector(isa_irq); 9284994be1bSYasuaki Ishimatsu BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL)); 929c9d059deSKenji Kaneshige dmode = choose_dmode(); 930c9d059deSKenji Kaneshige register_intr(gsi, irq, dmode, polarity, trigger); 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n", 9331da177e4SLinus Torvalds isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level", 9341da177e4SLinus Torvalds polarity == IOSAPIC_POL_HIGH ? "high" : "low", 9351da177e4SLinus Torvalds cpu_logical_id(dest), dest, vector); 9361da177e4SLinus Torvalds 9374bbdec7aSYasuaki Ishimatsu set_rte(gsi, irq, dest, 1); 9381da177e4SLinus Torvalds } 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds void __init 94133b39e84SIsaku Yamahata ia64_native_iosapic_pcat_compat_init(void) 94233b39e84SIsaku Yamahata { 94333b39e84SIsaku Yamahata if (pcat_compat) { 94433b39e84SIsaku Yamahata /* 94533b39e84SIsaku Yamahata * Disable the compatibility mode interrupts (8259 style), 94633b39e84SIsaku Yamahata * needs IN/OUT support enabled. 94733b39e84SIsaku Yamahata */ 94833b39e84SIsaku Yamahata printk(KERN_INFO 94933b39e84SIsaku Yamahata "%s: Disabling PC-AT compatible 8259 interrupts\n", 95033b39e84SIsaku Yamahata __func__); 95133b39e84SIsaku Yamahata outb(0xff, 0xA1); 95233b39e84SIsaku Yamahata outb(0xff, 0x21); 95333b39e84SIsaku Yamahata } 95433b39e84SIsaku Yamahata } 95533b39e84SIsaku Yamahata 95633b39e84SIsaku Yamahata void __init 9571da177e4SLinus Torvalds iosapic_system_init (int system_pcat_compat) 9581da177e4SLinus Torvalds { 9594bbdec7aSYasuaki Ishimatsu int irq; 9601da177e4SLinus Torvalds 9614bbdec7aSYasuaki Ishimatsu for (irq = 0; irq < NR_IRQS; ++irq) { 9624bbdec7aSYasuaki Ishimatsu iosapic_intr_info[irq].low32 = IOSAPIC_MASK; 96346cba3dcSSatoru Takeuchi /* mark as unused */ 9644bbdec7aSYasuaki Ishimatsu INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes); 965e1b30a39SYasuaki Ishimatsu 966e1b30a39SYasuaki Ishimatsu iosapic_intr_info[irq].count = 0; 96724eeb568SKenji Kaneshige } 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds pcat_compat = system_pcat_compat; 97033b39e84SIsaku Yamahata if (pcat_compat) 97133b39e84SIsaku Yamahata iosapic_pcat_compat_init(); 9721da177e4SLinus Torvalds } 9731da177e4SLinus Torvalds 9740e888adcSKenji Kaneshige static inline int 9750e888adcSKenji Kaneshige iosapic_alloc (void) 9760e888adcSKenji Kaneshige { 9770e888adcSKenji Kaneshige int index; 9780e888adcSKenji Kaneshige 9790e888adcSKenji Kaneshige for (index = 0; index < NR_IOSAPICS; index++) 9800e888adcSKenji Kaneshige if (!iosapic_lists[index].addr) 9810e888adcSKenji Kaneshige return index; 9820e888adcSKenji Kaneshige 983d4ed8084SHarvey Harrison printk(KERN_WARNING "%s: failed to allocate iosapic\n", __func__); 9840e888adcSKenji Kaneshige return -1; 9850e888adcSKenji Kaneshige } 9860e888adcSKenji Kaneshige 9870e888adcSKenji Kaneshige static inline void 9880e888adcSKenji Kaneshige iosapic_free (int index) 9890e888adcSKenji Kaneshige { 9900e888adcSKenji Kaneshige memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); 9910e888adcSKenji Kaneshige } 9920e888adcSKenji Kaneshige 9930e888adcSKenji Kaneshige static inline int 9940e888adcSKenji Kaneshige iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) 9950e888adcSKenji Kaneshige { 9960e888adcSKenji Kaneshige int index; 9970e888adcSKenji Kaneshige unsigned int gsi_end, base, end; 9980e888adcSKenji Kaneshige 9990e888adcSKenji Kaneshige /* check gsi range */ 10000e888adcSKenji Kaneshige gsi_end = gsi_base + ((ver >> 16) & 0xff); 10010e888adcSKenji Kaneshige for (index = 0; index < NR_IOSAPICS; index++) { 10020e888adcSKenji Kaneshige if (!iosapic_lists[index].addr) 10030e888adcSKenji Kaneshige continue; 10040e888adcSKenji Kaneshige 10050e888adcSKenji Kaneshige base = iosapic_lists[index].gsi_base; 10060e888adcSKenji Kaneshige end = base + iosapic_lists[index].num_rte - 1; 10070e888adcSKenji Kaneshige 1008e6d1ba5cSSatoru Takeuchi if (gsi_end < base || end < gsi_base) 10090e888adcSKenji Kaneshige continue; /* OK */ 10100e888adcSKenji Kaneshige 10110e888adcSKenji Kaneshige return -EBUSY; 10120e888adcSKenji Kaneshige } 10130e888adcSKenji Kaneshige return 0; 10140e888adcSKenji Kaneshige } 10150e888adcSKenji Kaneshige 10160e888adcSKenji Kaneshige int __devinit 10171da177e4SLinus Torvalds iosapic_init (unsigned long phys_addr, unsigned int gsi_base) 10181da177e4SLinus Torvalds { 10190e888adcSKenji Kaneshige int num_rte, err, index; 10201da177e4SLinus Torvalds unsigned int isa_irq, ver; 10211da177e4SLinus Torvalds char __iomem *addr; 10220e888adcSKenji Kaneshige unsigned long flags; 10231da177e4SLinus Torvalds 10240e888adcSKenji Kaneshige spin_lock_irqsave(&iosapic_lock, flags); 1025c1726d6fSYasuaki Ishimatsu index = find_iosapic(gsi_base); 1026c1726d6fSYasuaki Ishimatsu if (index >= 0) { 1027c1726d6fSYasuaki Ishimatsu spin_unlock_irqrestore(&iosapic_lock, flags); 1028c1726d6fSYasuaki Ishimatsu return -EBUSY; 1029c1726d6fSYasuaki Ishimatsu } 1030c1726d6fSYasuaki Ishimatsu 10311da177e4SLinus Torvalds addr = ioremap(phys_addr, 0); 1032e7369e01SRoel Kluin if (addr == NULL) { 1033e7369e01SRoel Kluin spin_unlock_irqrestore(&iosapic_lock, flags); 1034e7369e01SRoel Kluin return -ENOMEM; 1035e7369e01SRoel Kluin } 10361da177e4SLinus Torvalds ver = iosapic_version(addr); 10370e888adcSKenji Kaneshige if ((err = iosapic_check_gsi_range(gsi_base, ver))) { 10380e888adcSKenji Kaneshige iounmap(addr); 10390e888adcSKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 10400e888adcSKenji Kaneshige return err; 10410e888adcSKenji Kaneshige } 10420e888adcSKenji Kaneshige 10431da177e4SLinus Torvalds /* 1044e3a8f7b8SYasuaki Ishimatsu * The MAX_REDIR register holds the highest input pin number 1045e3a8f7b8SYasuaki Ishimatsu * (starting from 0). We add 1 so that we can use it for 1046e3a8f7b8SYasuaki Ishimatsu * number of pins (= RTEs) 10471da177e4SLinus Torvalds */ 10481da177e4SLinus Torvalds num_rte = ((ver >> 16) & 0xff) + 1; 10491da177e4SLinus Torvalds 10500e888adcSKenji Kaneshige index = iosapic_alloc(); 10510e888adcSKenji Kaneshige iosapic_lists[index].addr = addr; 10520e888adcSKenji Kaneshige iosapic_lists[index].gsi_base = gsi_base; 10530e888adcSKenji Kaneshige iosapic_lists[index].num_rte = num_rte; 10541da177e4SLinus Torvalds #ifdef CONFIG_NUMA 10550e888adcSKenji Kaneshige iosapic_lists[index].node = MAX_NUMNODES; 10561da177e4SLinus Torvalds #endif 1057c1726d6fSYasuaki Ishimatsu spin_lock_init(&iosapic_lists[index].lock); 10580e888adcSKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds if ((gsi_base == 0) && pcat_compat) { 10611da177e4SLinus Torvalds /* 106246cba3dcSSatoru Takeuchi * Map the legacy ISA devices into the IOSAPIC data. Some of 106346cba3dcSSatoru Takeuchi * these may get reprogrammed later on with data from the ACPI 106446cba3dcSSatoru Takeuchi * Interrupt Source Override table. 10651da177e4SLinus Torvalds */ 10661da177e4SLinus Torvalds for (isa_irq = 0; isa_irq < 16; ++isa_irq) 106746cba3dcSSatoru Takeuchi iosapic_override_isa_irq(isa_irq, isa_irq, 106846cba3dcSSatoru Takeuchi IOSAPIC_POL_HIGH, 106946cba3dcSSatoru Takeuchi IOSAPIC_EDGE); 10701da177e4SLinus Torvalds } 10710e888adcSKenji Kaneshige return 0; 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds 10740e888adcSKenji Kaneshige #ifdef CONFIG_HOTPLUG 10750e888adcSKenji Kaneshige int 10760e888adcSKenji Kaneshige iosapic_remove (unsigned int gsi_base) 10770e888adcSKenji Kaneshige { 10780e888adcSKenji Kaneshige int index, err = 0; 10790e888adcSKenji Kaneshige unsigned long flags; 10800e888adcSKenji Kaneshige 10810e888adcSKenji Kaneshige spin_lock_irqsave(&iosapic_lock, flags); 10820e888adcSKenji Kaneshige index = find_iosapic(gsi_base); 10830e888adcSKenji Kaneshige if (index < 0) { 10840e888adcSKenji Kaneshige printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", 1085d4ed8084SHarvey Harrison __func__, gsi_base); 10860e888adcSKenji Kaneshige goto out; 10870e888adcSKenji Kaneshige } 10880e888adcSKenji Kaneshige 10890e888adcSKenji Kaneshige if (iosapic_lists[index].rtes_inuse) { 10900e888adcSKenji Kaneshige err = -EBUSY; 1091e3a8f7b8SYasuaki Ishimatsu printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", 1092d4ed8084SHarvey Harrison __func__, gsi_base); 10930e888adcSKenji Kaneshige goto out; 10940e888adcSKenji Kaneshige } 10950e888adcSKenji Kaneshige 10960e888adcSKenji Kaneshige iounmap(iosapic_lists[index].addr); 10970e888adcSKenji Kaneshige iosapic_free(index); 10980e888adcSKenji Kaneshige out: 10990e888adcSKenji Kaneshige spin_unlock_irqrestore(&iosapic_lock, flags); 11000e888adcSKenji Kaneshige return err; 11010e888adcSKenji Kaneshige } 11020e888adcSKenji Kaneshige #endif /* CONFIG_HOTPLUG */ 11030e888adcSKenji Kaneshige 11041da177e4SLinus Torvalds #ifdef CONFIG_NUMA 11050e888adcSKenji Kaneshige void __devinit 11061da177e4SLinus Torvalds map_iosapic_to_node(unsigned int gsi_base, int node) 11071da177e4SLinus Torvalds { 11081da177e4SLinus Torvalds int index; 11091da177e4SLinus Torvalds 11101da177e4SLinus Torvalds index = find_iosapic(gsi_base); 11111da177e4SLinus Torvalds if (index < 0) { 11121da177e4SLinus Torvalds printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", 1113d4ed8084SHarvey Harrison __func__, gsi_base); 11141da177e4SLinus Torvalds return; 11151da177e4SLinus Torvalds } 11161da177e4SLinus Torvalds iosapic_lists[index].node = node; 11171da177e4SLinus Torvalds return; 11181da177e4SLinus Torvalds } 11191da177e4SLinus Torvalds #endif 1120