xref: /openbmc/linux/arch/ia64/kernel/iosapic.c (revision b9e41d7f)
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 */
1321da177e4SLinus Torvalds #ifdef CONFIG_NUMA
1331da177e4SLinus Torvalds 	unsigned short	node;		/* numa node association via pxm */
1341da177e4SLinus Torvalds #endif
1351da177e4SLinus Torvalds } iosapic_lists[NR_IOSAPICS];
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds static int num_iosapic;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds static unsigned char pcat_compat __initdata;	/* 8259 compatibility flag */
1401da177e4SLinus Torvalds 
14124eeb568SKenji Kaneshige static int iosapic_kmalloc_ok;
14224eeb568SKenji Kaneshige static LIST_HEAD(free_rte_list);
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds /*
1451da177e4SLinus Torvalds  * Find an IOSAPIC associated with a GSI
1461da177e4SLinus Torvalds  */
1471da177e4SLinus Torvalds static inline int
1481da177e4SLinus Torvalds find_iosapic (unsigned int gsi)
1491da177e4SLinus Torvalds {
1501da177e4SLinus Torvalds 	int i;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	for (i = 0; i < num_iosapic; i++) {
1531da177e4SLinus Torvalds 		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
1541da177e4SLinus Torvalds 			return i;
1551da177e4SLinus Torvalds 	}
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	return -1;
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds static inline int
1611da177e4SLinus Torvalds _gsi_to_vector (unsigned int gsi)
1621da177e4SLinus Torvalds {
1631da177e4SLinus Torvalds 	struct iosapic_intr_info *info;
16424eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
16724eeb568SKenji Kaneshige 		list_for_each_entry(rte, &info->rtes, rte_list)
16824eeb568SKenji Kaneshige 			if (rte->gsi_base + rte->rte_index == gsi)
1691da177e4SLinus Torvalds 				return info - iosapic_intr_info;
1701da177e4SLinus Torvalds 	return -1;
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds /*
1741da177e4SLinus Torvalds  * Translate GSI number to the corresponding IA-64 interrupt vector.  If no
1751da177e4SLinus Torvalds  * entry exists, return -1.
1761da177e4SLinus Torvalds  */
1771da177e4SLinus Torvalds inline int
1781da177e4SLinus Torvalds gsi_to_vector (unsigned int gsi)
1791da177e4SLinus Torvalds {
1801da177e4SLinus Torvalds 	return _gsi_to_vector(gsi);
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds int
1841da177e4SLinus Torvalds gsi_to_irq (unsigned int gsi)
1851da177e4SLinus Torvalds {
18624eeb568SKenji Kaneshige 	unsigned long flags;
18724eeb568SKenji Kaneshige 	int irq;
1881da177e4SLinus Torvalds 	/*
1891da177e4SLinus Torvalds 	 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
1901da177e4SLinus Torvalds 	 * numbers...
1911da177e4SLinus Torvalds 	 */
19224eeb568SKenji Kaneshige 	spin_lock_irqsave(&iosapic_lock, flags);
19324eeb568SKenji Kaneshige 	{
19424eeb568SKenji Kaneshige 		irq = _gsi_to_vector(gsi);
19524eeb568SKenji Kaneshige 	}
19624eeb568SKenji Kaneshige 	spin_unlock_irqrestore(&iosapic_lock, flags);
19724eeb568SKenji Kaneshige 
19824eeb568SKenji Kaneshige 	return irq;
19924eeb568SKenji Kaneshige }
20024eeb568SKenji Kaneshige 
20124eeb568SKenji Kaneshige static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
20224eeb568SKenji Kaneshige {
20324eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
20424eeb568SKenji Kaneshige 
20524eeb568SKenji Kaneshige 	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
20624eeb568SKenji Kaneshige 		if (rte->gsi_base + rte->rte_index == gsi)
20724eeb568SKenji Kaneshige 			return rte;
20824eeb568SKenji Kaneshige 	return NULL;
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds static void
21224eeb568SKenji Kaneshige set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	unsigned long pol, trigger, dmode;
2151da177e4SLinus Torvalds 	u32 low32, high32;
2161da177e4SLinus Torvalds 	char __iomem *addr;
2171da177e4SLinus Torvalds 	int rte_index;
2181da177e4SLinus Torvalds 	char redir;
21924eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
2221da177e4SLinus Torvalds 
22324eeb568SKenji Kaneshige 	rte = gsi_vector_to_rte(gsi, vector);
22424eeb568SKenji Kaneshige 	if (!rte)
2251da177e4SLinus Torvalds 		return;		/* not an IOSAPIC interrupt */
2261da177e4SLinus Torvalds 
22724eeb568SKenji Kaneshige 	rte_index = rte->rte_index;
22824eeb568SKenji Kaneshige 	addr	= rte->addr;
2291da177e4SLinus Torvalds 	pol     = iosapic_intr_info[vector].polarity;
2301da177e4SLinus Torvalds 	trigger = iosapic_intr_info[vector].trigger;
2311da177e4SLinus Torvalds 	dmode   = iosapic_intr_info[vector].dmode;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds #ifdef CONFIG_SMP
2361da177e4SLinus Torvalds 	{
2371da177e4SLinus Torvalds 		unsigned int irq;
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 		for (irq = 0; irq < NR_IRQS; ++irq)
2401da177e4SLinus Torvalds 			if (irq_to_vector(irq) == vector) {
2411da177e4SLinus Torvalds 				set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
2421da177e4SLinus Torvalds 				break;
2431da177e4SLinus Torvalds 			}
2441da177e4SLinus Torvalds 	}
2451da177e4SLinus Torvalds #endif
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 	low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
2481da177e4SLinus Torvalds 		 (trigger << IOSAPIC_TRIGGER_SHIFT) |
2491da177e4SLinus Torvalds 		 (dmode << IOSAPIC_DELIVERY_SHIFT) |
2501da177e4SLinus Torvalds 		 ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
2511da177e4SLinus Torvalds 		 vector);
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	/* dest contains both id and eid */
2541da177e4SLinus Torvalds 	high32 = (dest << IOSAPIC_DEST_SHIFT);
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
2571da177e4SLinus Torvalds 	iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
2581da177e4SLinus Torvalds 	iosapic_intr_info[vector].low32 = low32;
25924eeb568SKenji Kaneshige 	iosapic_intr_info[vector].dest = dest;
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds static void
2631da177e4SLinus Torvalds nop (unsigned int vector)
2641da177e4SLinus Torvalds {
2651da177e4SLinus Torvalds 	/* do nothing... */
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds static void
2691da177e4SLinus Torvalds mask_irq (unsigned int irq)
2701da177e4SLinus Torvalds {
2711da177e4SLinus Torvalds 	unsigned long flags;
2721da177e4SLinus Torvalds 	char __iomem *addr;
2731da177e4SLinus Torvalds 	u32 low32;
2741da177e4SLinus Torvalds 	int rte_index;
2751da177e4SLinus Torvalds 	ia64_vector vec = irq_to_vector(irq);
27624eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
2771da177e4SLinus Torvalds 
27824eeb568SKenji Kaneshige 	if (list_empty(&iosapic_intr_info[vec].rtes))
2791da177e4SLinus Torvalds 		return;			/* not an IOSAPIC interrupt! */
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	spin_lock_irqsave(&iosapic_lock, flags);
2821da177e4SLinus Torvalds 	{
2831da177e4SLinus Torvalds 		/* set only the mask bit */
2841da177e4SLinus Torvalds 		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
28524eeb568SKenji Kaneshige 		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
28624eeb568SKenji Kaneshige 			addr = rte->addr;
28724eeb568SKenji Kaneshige 			rte_index = rte->rte_index;
2881da177e4SLinus Torvalds 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
2891da177e4SLinus Torvalds 		}
29024eeb568SKenji Kaneshige 	}
2911da177e4SLinus Torvalds 	spin_unlock_irqrestore(&iosapic_lock, flags);
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds static void
2951da177e4SLinus Torvalds unmask_irq (unsigned int irq)
2961da177e4SLinus Torvalds {
2971da177e4SLinus Torvalds 	unsigned long flags;
2981da177e4SLinus Torvalds 	char __iomem *addr;
2991da177e4SLinus Torvalds 	u32 low32;
3001da177e4SLinus Torvalds 	int rte_index;
3011da177e4SLinus Torvalds 	ia64_vector vec = irq_to_vector(irq);
30224eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
3031da177e4SLinus Torvalds 
30424eeb568SKenji Kaneshige 	if (list_empty(&iosapic_intr_info[vec].rtes))
3051da177e4SLinus Torvalds 		return;			/* not an IOSAPIC interrupt! */
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 	spin_lock_irqsave(&iosapic_lock, flags);
3081da177e4SLinus Torvalds 	{
3091da177e4SLinus Torvalds 		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
31024eeb568SKenji Kaneshige 		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
31124eeb568SKenji Kaneshige 			addr = rte->addr;
31224eeb568SKenji Kaneshige 			rte_index = rte->rte_index;
3131da177e4SLinus Torvalds 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
3141da177e4SLinus Torvalds 		}
31524eeb568SKenji Kaneshige 	}
3161da177e4SLinus Torvalds 	spin_unlock_irqrestore(&iosapic_lock, flags);
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds static void
3211da177e4SLinus Torvalds iosapic_set_affinity (unsigned int irq, cpumask_t mask)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds #ifdef CONFIG_SMP
3241da177e4SLinus Torvalds 	unsigned long flags;
3251da177e4SLinus Torvalds 	u32 high32, low32;
3261da177e4SLinus Torvalds 	int dest, rte_index;
3271da177e4SLinus Torvalds 	char __iomem *addr;
3281da177e4SLinus Torvalds 	int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
3291da177e4SLinus Torvalds 	ia64_vector vec;
33024eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds 	irq &= (~IA64_IRQ_REDIRECTED);
3331da177e4SLinus Torvalds 	vec = irq_to_vector(irq);
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	if (cpus_empty(mask))
3361da177e4SLinus Torvalds 		return;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	dest = cpu_physical_id(first_cpu(mask));
3391da177e4SLinus Torvalds 
34024eeb568SKenji Kaneshige 	if (list_empty(&iosapic_intr_info[vec].rtes))
3411da177e4SLinus Torvalds 		return;			/* not an IOSAPIC interrupt */
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	set_irq_affinity_info(irq, dest, redir);
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 	/* dest contains both id and eid */
3461da177e4SLinus Torvalds 	high32 = dest << IOSAPIC_DEST_SHIFT;
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 	spin_lock_irqsave(&iosapic_lock, flags);
3491da177e4SLinus Torvalds 	{
3501da177e4SLinus Torvalds 		low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 		if (redir)
3531da177e4SLinus Torvalds 		        /* change delivery mode to lowest priority */
3541da177e4SLinus Torvalds 			low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
3551da177e4SLinus Torvalds 		else
3561da177e4SLinus Torvalds 		        /* change delivery mode to fixed */
3571da177e4SLinus Torvalds 			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 		iosapic_intr_info[vec].low32 = low32;
36024eeb568SKenji Kaneshige 		iosapic_intr_info[vec].dest = dest;
36124eeb568SKenji Kaneshige 		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
36224eeb568SKenji Kaneshige 			addr = rte->addr;
36324eeb568SKenji Kaneshige 			rte_index = rte->rte_index;
3641da177e4SLinus Torvalds 			iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
3651da177e4SLinus Torvalds 			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
3661da177e4SLinus Torvalds 		}
36724eeb568SKenji Kaneshige 	}
3681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&iosapic_lock, flags);
3691da177e4SLinus Torvalds #endif
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds 
3721da177e4SLinus Torvalds /*
3731da177e4SLinus Torvalds  * Handlers for level-triggered interrupts.
3741da177e4SLinus Torvalds  */
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds static unsigned int
3771da177e4SLinus Torvalds iosapic_startup_level_irq (unsigned int irq)
3781da177e4SLinus Torvalds {
3791da177e4SLinus Torvalds 	unmask_irq(irq);
3801da177e4SLinus Torvalds 	return 0;
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds static void
3841da177e4SLinus Torvalds iosapic_end_level_irq (unsigned int irq)
3851da177e4SLinus Torvalds {
3861da177e4SLinus Torvalds 	ia64_vector vec = irq_to_vector(irq);
38724eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	move_irq(irq);
39024eeb568SKenji Kaneshige 	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
39124eeb568SKenji Kaneshige 		iosapic_eoi(rte->addr, vec);
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds #define iosapic_shutdown_level_irq	mask_irq
3951da177e4SLinus Torvalds #define iosapic_enable_level_irq	unmask_irq
3961da177e4SLinus Torvalds #define iosapic_disable_level_irq	mask_irq
3971da177e4SLinus Torvalds #define iosapic_ack_level_irq		nop
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds struct hw_interrupt_type irq_type_iosapic_level = {
4001da177e4SLinus Torvalds 	.typename =	"IO-SAPIC-level",
4011da177e4SLinus Torvalds 	.startup =	iosapic_startup_level_irq,
4021da177e4SLinus Torvalds 	.shutdown =	iosapic_shutdown_level_irq,
4031da177e4SLinus Torvalds 	.enable =	iosapic_enable_level_irq,
4041da177e4SLinus Torvalds 	.disable =	iosapic_disable_level_irq,
4051da177e4SLinus Torvalds 	.ack =		iosapic_ack_level_irq,
4061da177e4SLinus Torvalds 	.end =		iosapic_end_level_irq,
4071da177e4SLinus Torvalds 	.set_affinity =	iosapic_set_affinity
4081da177e4SLinus Torvalds };
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds /*
4111da177e4SLinus Torvalds  * Handlers for edge-triggered interrupts.
4121da177e4SLinus Torvalds  */
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds static unsigned int
4151da177e4SLinus Torvalds iosapic_startup_edge_irq (unsigned int irq)
4161da177e4SLinus Torvalds {
4171da177e4SLinus Torvalds 	unmask_irq(irq);
4181da177e4SLinus Torvalds 	/*
4191da177e4SLinus Torvalds 	 * IOSAPIC simply drops interrupts pended while the
4201da177e4SLinus Torvalds 	 * corresponding pin was masked, so we can't know if an
4211da177e4SLinus Torvalds 	 * interrupt is pending already.  Let's hope not...
4221da177e4SLinus Torvalds 	 */
4231da177e4SLinus Torvalds 	return 0;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds static void
4271da177e4SLinus Torvalds iosapic_ack_edge_irq (unsigned int irq)
4281da177e4SLinus Torvalds {
4291da177e4SLinus Torvalds 	irq_desc_t *idesc = irq_descp(irq);
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 	move_irq(irq);
4321da177e4SLinus Torvalds 	/*
4331da177e4SLinus Torvalds 	 * Once we have recorded IRQ_PENDING already, we can mask the
4341da177e4SLinus Torvalds 	 * interrupt for real. This prevents IRQ storms from unhandled
4351da177e4SLinus Torvalds 	 * devices.
4361da177e4SLinus Torvalds 	 */
4371da177e4SLinus Torvalds 	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
4381da177e4SLinus Torvalds 		mask_irq(irq);
4391da177e4SLinus Torvalds }
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds #define iosapic_enable_edge_irq		unmask_irq
4421da177e4SLinus Torvalds #define iosapic_disable_edge_irq	nop
4431da177e4SLinus Torvalds #define iosapic_end_edge_irq		nop
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds struct hw_interrupt_type irq_type_iosapic_edge = {
4461da177e4SLinus Torvalds 	.typename =	"IO-SAPIC-edge",
4471da177e4SLinus Torvalds 	.startup =	iosapic_startup_edge_irq,
4481da177e4SLinus Torvalds 	.shutdown =	iosapic_disable_edge_irq,
4491da177e4SLinus Torvalds 	.enable =	iosapic_enable_edge_irq,
4501da177e4SLinus Torvalds 	.disable =	iosapic_disable_edge_irq,
4511da177e4SLinus Torvalds 	.ack =		iosapic_ack_edge_irq,
4521da177e4SLinus Torvalds 	.end =		iosapic_end_edge_irq,
4531da177e4SLinus Torvalds 	.set_affinity =	iosapic_set_affinity
4541da177e4SLinus Torvalds };
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds unsigned int
4571da177e4SLinus Torvalds iosapic_version (char __iomem *addr)
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds 	/*
4601da177e4SLinus Torvalds 	 * IOSAPIC Version Register return 32 bit structure like:
4611da177e4SLinus Torvalds 	 * {
4621da177e4SLinus Torvalds 	 *	unsigned int version   : 8;
4631da177e4SLinus Torvalds 	 *	unsigned int reserved1 : 8;
4641da177e4SLinus Torvalds 	 *	unsigned int max_redir : 8;
4651da177e4SLinus Torvalds 	 *	unsigned int reserved2 : 8;
4661da177e4SLinus Torvalds 	 * }
4671da177e4SLinus Torvalds 	 */
4681da177e4SLinus Torvalds 	return iosapic_read(addr, IOSAPIC_VERSION);
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds 
47124eeb568SKenji Kaneshige static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
47224eeb568SKenji Kaneshige {
47324eeb568SKenji Kaneshige 	int i, vector = -1, min_count = -1;
47424eeb568SKenji Kaneshige 	struct iosapic_intr_info *info;
47524eeb568SKenji Kaneshige 
47624eeb568SKenji Kaneshige 	/*
47724eeb568SKenji Kaneshige 	 * shared vectors for edge-triggered interrupts are not
47824eeb568SKenji Kaneshige 	 * supported yet
47924eeb568SKenji Kaneshige 	 */
48024eeb568SKenji Kaneshige 	if (trigger == IOSAPIC_EDGE)
48124eeb568SKenji Kaneshige 		return -1;
48224eeb568SKenji Kaneshige 
48324eeb568SKenji Kaneshige 	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
48424eeb568SKenji Kaneshige 		info = &iosapic_intr_info[i];
48524eeb568SKenji Kaneshige 		if (info->trigger == trigger && info->polarity == pol &&
48624eeb568SKenji Kaneshige 		    (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {
48724eeb568SKenji Kaneshige 			if (min_count == -1 || info->count < min_count) {
48824eeb568SKenji Kaneshige 				vector = i;
48924eeb568SKenji Kaneshige 				min_count = info->count;
49024eeb568SKenji Kaneshige 			}
49124eeb568SKenji Kaneshige 		}
49224eeb568SKenji Kaneshige 	}
49324eeb568SKenji Kaneshige 	if (vector < 0)
49424eeb568SKenji Kaneshige 		panic("%s: out of interrupt vectors!\n", __FUNCTION__);
49524eeb568SKenji Kaneshige 
49624eeb568SKenji Kaneshige 	return vector;
49724eeb568SKenji Kaneshige }
49824eeb568SKenji Kaneshige 
4991da177e4SLinus Torvalds /*
5001da177e4SLinus Torvalds  * if the given vector is already owned by other,
5011da177e4SLinus Torvalds  *  assign a new vector for the other and make the vector available
5021da177e4SLinus Torvalds  */
5031da177e4SLinus Torvalds static void __init
5041da177e4SLinus Torvalds iosapic_reassign_vector (int vector)
5051da177e4SLinus Torvalds {
5061da177e4SLinus Torvalds 	int new_vector;
5071da177e4SLinus Torvalds 
50824eeb568SKenji Kaneshige 	if (!list_empty(&iosapic_intr_info[vector].rtes)) {
5091da177e4SLinus Torvalds 		new_vector = assign_irq_vector(AUTO_ASSIGN);
5101da177e4SLinus Torvalds 		printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
5111da177e4SLinus Torvalds 		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
5121da177e4SLinus Torvalds 		       sizeof(struct iosapic_intr_info));
51324eeb568SKenji Kaneshige 		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
51424eeb568SKenji Kaneshige 		list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);
5151da177e4SLinus Torvalds 		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
51624eeb568SKenji Kaneshige 		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
51724eeb568SKenji Kaneshige 		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
5181da177e4SLinus Torvalds 	}
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds 
52124eeb568SKenji Kaneshige static struct iosapic_rte_info *iosapic_alloc_rte (void)
52224eeb568SKenji Kaneshige {
52324eeb568SKenji Kaneshige 	int i;
52424eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
52524eeb568SKenji Kaneshige 	int preallocated = 0;
52624eeb568SKenji Kaneshige 
52724eeb568SKenji Kaneshige 	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
52824eeb568SKenji Kaneshige 		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
52924eeb568SKenji Kaneshige 		if (!rte)
53024eeb568SKenji Kaneshige 			return NULL;
53124eeb568SKenji Kaneshige 		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
53224eeb568SKenji Kaneshige 			list_add(&rte->rte_list, &free_rte_list);
53324eeb568SKenji Kaneshige 	}
53424eeb568SKenji Kaneshige 
53524eeb568SKenji Kaneshige 	if (!list_empty(&free_rte_list)) {
53624eeb568SKenji Kaneshige 		rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
53724eeb568SKenji Kaneshige 		list_del(&rte->rte_list);
53824eeb568SKenji Kaneshige 		preallocated++;
53924eeb568SKenji Kaneshige 	} else {
54024eeb568SKenji Kaneshige 		rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
54124eeb568SKenji Kaneshige 		if (!rte)
54224eeb568SKenji Kaneshige 			return NULL;
54324eeb568SKenji Kaneshige 	}
54424eeb568SKenji Kaneshige 
54524eeb568SKenji Kaneshige 	memset(rte, 0, sizeof(struct iosapic_rte_info));
54624eeb568SKenji Kaneshige 	if (preallocated)
54724eeb568SKenji Kaneshige 		rte->flags |= RTE_PREALLOCATED;
54824eeb568SKenji Kaneshige 
54924eeb568SKenji Kaneshige 	return rte;
55024eeb568SKenji Kaneshige }
55124eeb568SKenji Kaneshige 
55224eeb568SKenji Kaneshige static void iosapic_free_rte (struct iosapic_rte_info *rte)
55324eeb568SKenji Kaneshige {
55424eeb568SKenji Kaneshige 	if (rte->flags & RTE_PREALLOCATED)
55524eeb568SKenji Kaneshige 		list_add_tail(&rte->rte_list, &free_rte_list);
55624eeb568SKenji Kaneshige 	else
55724eeb568SKenji Kaneshige 		kfree(rte);
55824eeb568SKenji Kaneshige }
55924eeb568SKenji Kaneshige 
56024eeb568SKenji Kaneshige static inline int vector_is_shared (int vector)
56124eeb568SKenji Kaneshige {
56224eeb568SKenji Kaneshige 	return (iosapic_intr_info[vector].count > 1);
56324eeb568SKenji Kaneshige }
56424eeb568SKenji Kaneshige 
5651da177e4SLinus Torvalds static void
5661da177e4SLinus Torvalds register_intr (unsigned int gsi, int vector, unsigned char delivery,
5671da177e4SLinus Torvalds 	       unsigned long polarity, unsigned long trigger)
5681da177e4SLinus Torvalds {
5691da177e4SLinus Torvalds 	irq_desc_t *idesc;
5701da177e4SLinus Torvalds 	struct hw_interrupt_type *irq_type;
5711da177e4SLinus Torvalds 	int rte_index;
5721da177e4SLinus Torvalds 	int index;
5731da177e4SLinus Torvalds 	unsigned long gsi_base;
5741da177e4SLinus Torvalds 	void __iomem *iosapic_address;
57524eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds 	index = find_iosapic(gsi);
5781da177e4SLinus Torvalds 	if (index < 0) {
5791da177e4SLinus Torvalds 		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
5801da177e4SLinus Torvalds 		return;
5811da177e4SLinus Torvalds 	}
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds 	iosapic_address = iosapic_lists[index].addr;
5841da177e4SLinus Torvalds 	gsi_base = iosapic_lists[index].gsi_base;
5851da177e4SLinus Torvalds 
58624eeb568SKenji Kaneshige 	rte = gsi_vector_to_rte(gsi, vector);
58724eeb568SKenji Kaneshige 	if (!rte) {
58824eeb568SKenji Kaneshige 		rte = iosapic_alloc_rte();
58924eeb568SKenji Kaneshige 		if (!rte) {
59024eeb568SKenji Kaneshige 			printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
59124eeb568SKenji Kaneshige 			return;
59224eeb568SKenji Kaneshige 		}
59324eeb568SKenji Kaneshige 
5941da177e4SLinus Torvalds 		rte_index = gsi - gsi_base;
59524eeb568SKenji Kaneshige 		rte->rte_index	= rte_index;
59624eeb568SKenji Kaneshige 		rte->addr	= iosapic_address;
59724eeb568SKenji Kaneshige 		rte->gsi_base	= gsi_base;
59824eeb568SKenji Kaneshige 		rte->refcnt++;
59924eeb568SKenji Kaneshige 		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
60024eeb568SKenji Kaneshige 		iosapic_intr_info[vector].count++;
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 */
73724eeb568SKenji Kaneshige 	vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
73824eeb568SKenji Kaneshige 	if (vector < 0)
73924eeb568SKenji Kaneshige 		vector = iosapic_find_sharable_vector(trigger, polarity);
74024eeb568SKenji Kaneshige 
74124eeb568SKenji Kaneshige 	spin_lock_irqsave(&irq_descp(vector)->lock, flags);
74224eeb568SKenji Kaneshige 	spin_lock(&iosapic_lock);
74324eeb568SKenji Kaneshige 	{
74424eeb568SKenji Kaneshige 		if (gsi_to_vector(gsi) > 0) {
74524eeb568SKenji Kaneshige 			if (list_empty(&iosapic_intr_info[vector].rtes))
74624eeb568SKenji Kaneshige 				free_irq_vector(vector);
74724eeb568SKenji Kaneshige 			spin_unlock(&iosapic_lock);
74824eeb568SKenji Kaneshige 			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
74924eeb568SKenji Kaneshige 			goto again;
75024eeb568SKenji Kaneshige 		}
75124eeb568SKenji Kaneshige 
7521da177e4SLinus Torvalds 		dest = get_target_cpu(gsi, vector);
7531da177e4SLinus Torvalds 		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
7541da177e4SLinus Torvalds 			      polarity, trigger);
7551da177e4SLinus Torvalds 
75624eeb568SKenji Kaneshige 		/*
75724eeb568SKenji Kaneshige 		 * If the vector is shared and already unmasked for
75824eeb568SKenji Kaneshige 		 * other interrupt sources, don't mask it.
75924eeb568SKenji Kaneshige 		 */
76024eeb568SKenji Kaneshige 		low32 = iosapic_intr_info[vector].low32;
76124eeb568SKenji Kaneshige 		if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
76224eeb568SKenji Kaneshige 			mask = 0;
76324eeb568SKenji Kaneshige 		set_rte(gsi, vector, dest, mask);
7641da177e4SLinus Torvalds 	}
765b9e41d7fSKenji Kaneshige 	spin_unlock(&iosapic_lock);
76624eeb568SKenji Kaneshige 	spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
7691da177e4SLinus Torvalds 	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
7701da177e4SLinus Torvalds 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
7711da177e4SLinus Torvalds 	       cpu_logical_id(dest), dest, vector);
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds 	return vector;
7741da177e4SLinus Torvalds }
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds #ifdef CONFIG_ACPI_DEALLOCATE_IRQ
7771da177e4SLinus Torvalds void
7781da177e4SLinus Torvalds iosapic_unregister_intr (unsigned int gsi)
7791da177e4SLinus Torvalds {
7801da177e4SLinus Torvalds 	unsigned long flags;
7811da177e4SLinus Torvalds 	int irq, vector;
7821da177e4SLinus Torvalds 	irq_desc_t *idesc;
78324eeb568SKenji Kaneshige 	u32 low32;
7841da177e4SLinus Torvalds 	unsigned long trigger, polarity;
78524eeb568SKenji Kaneshige 	unsigned int dest;
78624eeb568SKenji Kaneshige 	struct iosapic_rte_info *rte;
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds 	/*
7891da177e4SLinus Torvalds 	 * If the irq associated with the gsi is not found,
7901da177e4SLinus Torvalds 	 * iosapic_unregister_intr() is unbalanced. We need to check
7911da177e4SLinus Torvalds 	 * this again after getting locks.
7921da177e4SLinus Torvalds 	 */
7931da177e4SLinus Torvalds 	irq = gsi_to_irq(gsi);
7941da177e4SLinus Torvalds 	if (irq < 0) {
7951da177e4SLinus Torvalds 		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
7961da177e4SLinus Torvalds 		WARN_ON(1);
7971da177e4SLinus Torvalds 		return;
7981da177e4SLinus Torvalds 	}
7991da177e4SLinus Torvalds 	vector = irq_to_vector(irq);
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 	idesc = irq_descp(irq);
8021da177e4SLinus Torvalds 	spin_lock_irqsave(&idesc->lock, flags);
8031da177e4SLinus Torvalds 	spin_lock(&iosapic_lock);
8041da177e4SLinus Torvalds 	{
80524eeb568SKenji Kaneshige 		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
8061da177e4SLinus Torvalds 			printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
8071da177e4SLinus Torvalds 			WARN_ON(1);
80824eeb568SKenji Kaneshige 			goto out;
8091da177e4SLinus Torvalds 		}
8101da177e4SLinus Torvalds 
81124eeb568SKenji Kaneshige 		if (--rte->refcnt > 0)
81224eeb568SKenji Kaneshige 			goto out;
8131da177e4SLinus Torvalds 
81424eeb568SKenji Kaneshige 		/* Mask the interrupt */
81524eeb568SKenji Kaneshige 		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
81624eeb568SKenji Kaneshige 		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
8171da177e4SLinus Torvalds 
81824eeb568SKenji Kaneshige 		/* Remove the rte entry from the list */
81924eeb568SKenji Kaneshige 		list_del(&rte->rte_list);
82024eeb568SKenji Kaneshige 		iosapic_intr_info[vector].count--;
82124eeb568SKenji Kaneshige 		iosapic_free_rte(rte);
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds 		trigger	 = iosapic_intr_info[vector].trigger;
8241da177e4SLinus Torvalds 		polarity = iosapic_intr_info[vector].polarity;
82524eeb568SKenji Kaneshige 		dest     = iosapic_intr_info[vector].dest;
82624eeb568SKenji Kaneshige 		printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
82724eeb568SKenji Kaneshige 		       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
82824eeb568SKenji Kaneshige 		       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
82924eeb568SKenji Kaneshige 		       cpu_logical_id(dest), dest, vector);
8301da177e4SLinus Torvalds 
83124eeb568SKenji Kaneshige 		if (list_empty(&iosapic_intr_info[vector].rtes)) {
83224eeb568SKenji Kaneshige 			/* Sanity check */
83324eeb568SKenji Kaneshige 			BUG_ON(iosapic_intr_info[vector].count);
83424eeb568SKenji Kaneshige 
83524eeb568SKenji Kaneshige 			/* Clear the interrupt controller descriptor */
83624eeb568SKenji Kaneshige 			idesc->handler = &no_irq_type;
83724eeb568SKenji Kaneshige 
83824eeb568SKenji Kaneshige 			/* Clear the interrupt information */
8391da177e4SLinus Torvalds 			memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
84024eeb568SKenji Kaneshige 			iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
84124eeb568SKenji Kaneshige 			INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
84224eeb568SKenji Kaneshige 
84324eeb568SKenji Kaneshige 			if (idesc->action) {
84424eeb568SKenji Kaneshige 				printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq);
84524eeb568SKenji Kaneshige 				WARN_ON(1);
8461da177e4SLinus Torvalds 			}
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 			/* Free the interrupt vector */
8491da177e4SLinus Torvalds 			free_irq_vector(vector);
85024eeb568SKenji Kaneshige 		}
85124eeb568SKenji Kaneshige 	}
85224eeb568SKenji Kaneshige  out:
85324eeb568SKenji Kaneshige 	spin_unlock(&iosapic_lock);
85424eeb568SKenji Kaneshige 	spin_unlock_irqrestore(&idesc->lock, flags);
8551da177e4SLinus Torvalds }
8561da177e4SLinus Torvalds #endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds /*
8591da177e4SLinus Torvalds  * ACPI calls this when it finds an entry for a platform interrupt.
8601da177e4SLinus Torvalds  * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
8611da177e4SLinus Torvalds  */
8621da177e4SLinus Torvalds int __init
8631da177e4SLinus Torvalds iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
8641da177e4SLinus Torvalds 				int iosapic_vector, u16 eid, u16 id,
8651da177e4SLinus Torvalds 				unsigned long polarity, unsigned long trigger)
8661da177e4SLinus Torvalds {
8671da177e4SLinus Torvalds 	static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
8681da177e4SLinus Torvalds 	unsigned char delivery;
8691da177e4SLinus Torvalds 	int vector, mask = 0;
8701da177e4SLinus Torvalds 	unsigned int dest = ((id << 8) | eid) & 0xffff;
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 	switch (int_type) {
8731da177e4SLinus Torvalds 	      case ACPI_INTERRUPT_PMI:
8741da177e4SLinus Torvalds 		vector = iosapic_vector;
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 		 */
8791da177e4SLinus Torvalds 		iosapic_reassign_vector(vector);
8801da177e4SLinus Torvalds 		delivery = IOSAPIC_PMI;
8811da177e4SLinus Torvalds 		break;
8821da177e4SLinus Torvalds 	      case ACPI_INTERRUPT_INIT:
8831da177e4SLinus Torvalds 		vector = assign_irq_vector(AUTO_ASSIGN);
8841da177e4SLinus Torvalds 		delivery = IOSAPIC_INIT;
8851da177e4SLinus Torvalds 		break;
8861da177e4SLinus Torvalds 	      case ACPI_INTERRUPT_CPEI:
8871da177e4SLinus Torvalds 		vector = IA64_CPE_VECTOR;
8881da177e4SLinus Torvalds 		delivery = IOSAPIC_LOWEST_PRIORITY;
8891da177e4SLinus Torvalds 		mask = 1;
8901da177e4SLinus Torvalds 		break;
8911da177e4SLinus Torvalds 	      default:
8921da177e4SLinus Torvalds 		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
8931da177e4SLinus Torvalds 		return -1;
8941da177e4SLinus Torvalds 	}
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	register_intr(gsi, vector, delivery, polarity, trigger);
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds 	printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
8991da177e4SLinus Torvalds 	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
9001da177e4SLinus Torvalds 	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
9011da177e4SLinus Torvalds 	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
9021da177e4SLinus Torvalds 	       cpu_logical_id(dest), dest, vector);
9031da177e4SLinus Torvalds 
90424eeb568SKenji Kaneshige 	set_rte(gsi, vector, dest, mask);
9051da177e4SLinus Torvalds 	return vector;
9061da177e4SLinus Torvalds }
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds 
9091da177e4SLinus Torvalds /*
9101da177e4SLinus Torvalds  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
9111da177e4SLinus Torvalds  * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
9121da177e4SLinus Torvalds  */
9131da177e4SLinus Torvalds void __init
9141da177e4SLinus Torvalds iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
9151da177e4SLinus Torvalds 			  unsigned long polarity,
9161da177e4SLinus Torvalds 			  unsigned long trigger)
9171da177e4SLinus Torvalds {
9181da177e4SLinus Torvalds 	int vector;
9191da177e4SLinus Torvalds 	unsigned int dest = cpu_physical_id(smp_processor_id());
9201da177e4SLinus Torvalds 
9211da177e4SLinus Torvalds 	vector = isa_irq_to_vector(isa_irq);
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds 	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
9261da177e4SLinus Torvalds 	    isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
9271da177e4SLinus Torvalds 	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",
9281da177e4SLinus Torvalds 	    cpu_logical_id(dest), dest, vector);
9291da177e4SLinus Torvalds 
93024eeb568SKenji Kaneshige 	set_rte(gsi, vector, dest, 1);
9311da177e4SLinus Torvalds }
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds void __init
9341da177e4SLinus Torvalds iosapic_system_init (int system_pcat_compat)
9351da177e4SLinus Torvalds {
9361da177e4SLinus Torvalds 	int vector;
9371da177e4SLinus Torvalds 
93824eeb568SKenji Kaneshige 	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
93924eeb568SKenji Kaneshige 		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
94024eeb568SKenji Kaneshige 		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);	/* mark as unused */
94124eeb568SKenji Kaneshige 	}
9421da177e4SLinus Torvalds 
9431da177e4SLinus Torvalds 	pcat_compat = system_pcat_compat;
9441da177e4SLinus Torvalds 	if (pcat_compat) {
9451da177e4SLinus Torvalds 		/*
9461da177e4SLinus Torvalds 		 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
9471da177e4SLinus Torvalds 		 * enabled.
9481da177e4SLinus Torvalds 		 */
9491da177e4SLinus Torvalds 		printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
9501da177e4SLinus Torvalds 		outb(0xff, 0xA1);
9511da177e4SLinus Torvalds 		outb(0xff, 0x21);
9521da177e4SLinus Torvalds 	}
9531da177e4SLinus Torvalds }
9541da177e4SLinus Torvalds 
9551da177e4SLinus Torvalds void __init
9561da177e4SLinus Torvalds iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
9571da177e4SLinus Torvalds {
9581da177e4SLinus Torvalds 	int num_rte;
9591da177e4SLinus Torvalds 	unsigned int isa_irq, ver;
9601da177e4SLinus Torvalds 	char __iomem *addr;
9611da177e4SLinus Torvalds 
9621da177e4SLinus Torvalds 	addr = ioremap(phys_addr, 0);
9631da177e4SLinus Torvalds 	ver = iosapic_version(addr);
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 	/*
9661da177e4SLinus Torvalds 	 * The MAX_REDIR register holds the highest input pin
9671da177e4SLinus Torvalds 	 * number (starting from 0).
9681da177e4SLinus Torvalds 	 * We add 1 so that we can use it for number of pins (= RTEs)
9691da177e4SLinus Torvalds 	 */
9701da177e4SLinus Torvalds 	num_rte = ((ver >> 16) & 0xff) + 1;
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds 	iosapic_lists[num_iosapic].addr = addr;
9731da177e4SLinus Torvalds 	iosapic_lists[num_iosapic].gsi_base = gsi_base;
9741da177e4SLinus Torvalds 	iosapic_lists[num_iosapic].num_rte = num_rte;
9751da177e4SLinus Torvalds #ifdef CONFIG_NUMA
9761da177e4SLinus Torvalds 	iosapic_lists[num_iosapic].node = MAX_NUMNODES;
9771da177e4SLinus Torvalds #endif
9781da177e4SLinus Torvalds 	num_iosapic++;
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds 	if ((gsi_base == 0) && pcat_compat) {
9811da177e4SLinus Torvalds 		/*
9821da177e4SLinus Torvalds 		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
9831da177e4SLinus Torvalds 		 * get reprogrammed later on with data from the ACPI Interrupt Source
9841da177e4SLinus Torvalds 		 * Override table.
9851da177e4SLinus Torvalds 		 */
9861da177e4SLinus Torvalds 		for (isa_irq = 0; isa_irq < 16; ++isa_irq)
9871da177e4SLinus Torvalds 			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
9881da177e4SLinus Torvalds 	}
9891da177e4SLinus Torvalds }
9901da177e4SLinus Torvalds 
9911da177e4SLinus Torvalds #ifdef CONFIG_NUMA
9921da177e4SLinus Torvalds void __init
9931da177e4SLinus Torvalds map_iosapic_to_node(unsigned int gsi_base, int node)
9941da177e4SLinus Torvalds {
9951da177e4SLinus Torvalds 	int index;
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 	index = find_iosapic(gsi_base);
9981da177e4SLinus Torvalds 	if (index < 0) {
9991da177e4SLinus Torvalds 		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",
10001da177e4SLinus Torvalds 		       __FUNCTION__, gsi_base);
10011da177e4SLinus Torvalds 		return;
10021da177e4SLinus Torvalds 	}
10031da177e4SLinus Torvalds 	iosapic_lists[index].node = node;
10041da177e4SLinus Torvalds 	return;
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds #endif
100724eeb568SKenji Kaneshige 
100824eeb568SKenji Kaneshige static int __init iosapic_enable_kmalloc (void)
100924eeb568SKenji Kaneshige {
101024eeb568SKenji Kaneshige 	iosapic_kmalloc_ok = 1;
101124eeb568SKenji Kaneshige 	return 0;
101224eeb568SKenji Kaneshige }
101324eeb568SKenji Kaneshige core_initcall (iosapic_enable_kmalloc);
1014