ia64/xen-unstable

changeset 9745:19148831ab05

[IA64] add base iosapic files

Add base iosapic files from Linux-2.6.16 in preparation for
Kevin's iosapic changes.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
author awilliam@xenbuild.aw
date Fri Apr 21 08:56:24 2006 -0600 (2006-04-21)
parents 7ed6c203efe9
children eab6fd4949f0
files linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c linux-2.6-xen-sparse/include/asm-ia64/iosapic.h xen/arch/ia64/linux-xen/README.origin xen/arch/ia64/linux-xen/iosapic.c xen/include/asm-ia64/linux-xen/asm/README.origin xen/include/asm-ia64/linux-xen/asm/iosapic.h
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c	Fri Apr 21 08:56:24 2006 -0600
     1.3 @@ -0,0 +1,1114 @@
     1.4 +/*
     1.5 + * I/O SAPIC support.
     1.6 + *
     1.7 + * Copyright (C) 1999 Intel Corp.
     1.8 + * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
     1.9 + * Copyright (C) 2000-2002 J.I. Lee <jung-ik.lee@intel.com>
    1.10 + * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co.
    1.11 + *	David Mosberger-Tang <davidm@hpl.hp.com>
    1.12 + * Copyright (C) 1999 VA Linux Systems
    1.13 + * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
    1.14 + *
    1.15 + * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O APIC code.
    1.16 + *				In particular, we now have separate handlers for edge
    1.17 + *				and level triggered interrupts.
    1.18 + * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation
    1.19 + *				PCI to vector mapping, shared PCI interrupts.
    1.20 + * 00/10/27	D. Mosberger	Document things a bit more to make them more understandable.
    1.21 + *				Clean up much of the old IOSAPIC cruft.
    1.22 + * 01/07/27	J.I. Lee	PCI irq routing, Platform/Legacy interrupts and fixes for
    1.23 + *				ACPI S5(SoftOff) support.
    1.24 + * 02/01/23	J.I. Lee	iosapic pgm fixes for PCI irq routing from _PRT
    1.25 + * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt vectors in
    1.26 + *                              iosapic_set_affinity(), initializations for
    1.27 + *                              /proc/irq/#/smp_affinity
    1.28 + * 02/04/02	P. Diefenbaugh	Cleaned up ACPI PCI IRQ routing.
    1.29 + * 02/04/18	J.I. Lee	bug fix in iosapic_init_pci_irq
    1.30 + * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
    1.31 + *				error
    1.32 + * 02/07/29	T. Kochi	Allocate interrupt vectors dynamically
    1.33 + * 02/08/04	T. Kochi	Cleaned up terminology (irq, global system interrupt, vector, etc.)
    1.34 + * 02/09/20	D. Mosberger	Simplified by taking advantage of ACPI's pci_irq code.
    1.35 + * 03/02/19	B. Helgaas	Make pcat_compat system-wide, not per-IOSAPIC.
    1.36 + *				Remove iosapic_address & gsi_base from external interfaces.
    1.37 + *				Rationalize __init/__devinit attributes.
    1.38 + * 04/12/04 Ashok Raj	<ashok.raj@intel.com> Intel Corporation 2004
    1.39 + *				Updated to work with irq migration necessary for CPU Hotplug
    1.40 + */
    1.41 +/*
    1.42 + * Here is what the interrupt logic between a PCI device and the kernel looks like:
    1.43 + *
    1.44 + * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
    1.45 + *     device is uniquely identified by its bus--, and slot-number (the function
    1.46 + *     number does not matter here because all functions share the same interrupt
    1.47 + *     lines).
    1.48 + *
    1.49 + * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller.
    1.50 + *     Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level
    1.51 + *     triggered and use the same polarity).  Each interrupt line has a unique Global
    1.52 + *     System Interrupt (GSI) number which can be calculated as the sum of the controller's
    1.53 + *     base GSI number and the IOSAPIC pin number to which the line connects.
    1.54 + *
    1.55 + * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin
    1.56 + *     into the IA-64 interrupt vector.  This interrupt vector is then sent to the CPU.
    1.57 + *
    1.58 + * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface is used as
    1.59 + *     architecture-independent interrupt handling mechanism in Linux.  As an
    1.60 + *     IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number
    1.61 + *     mapping.  On smaller systems, we use one-to-one mapping between IA-64 vector and
    1.62 + *     IRQ.  A platform can implement platform_irq_to_vector(irq) and
    1.63 + *     platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
    1.64 + *     Please see also include/asm-ia64/hw_irq.h for those APIs.
    1.65 + *
    1.66 + * To sum up, there are three levels of mappings involved:
    1.67 + *
    1.68 + *	PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
    1.69 + *
    1.70 + * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts.
    1.71 + * Now we use "IRQ" only for Linux IRQ's.  ISA IRQ (isa_irq) is the only exception in this
    1.72 + * source code.
    1.73 + */
    1.74 +#include <linux/config.h>
    1.75 +
    1.76 +#include <linux/acpi.h>
    1.77 +#include <linux/init.h>
    1.78 +#include <linux/irq.h>
    1.79 +#include <linux/kernel.h>
    1.80 +#include <linux/list.h>
    1.81 +#include <linux/pci.h>
    1.82 +#include <linux/smp.h>
    1.83 +#include <linux/smp_lock.h>
    1.84 +#include <linux/string.h>
    1.85 +#include <linux/bootmem.h>
    1.86 +
    1.87 +#include <asm/delay.h>
    1.88 +#include <asm/hw_irq.h>
    1.89 +#include <asm/io.h>
    1.90 +#include <asm/iosapic.h>
    1.91 +#include <asm/machvec.h>
    1.92 +#include <asm/processor.h>
    1.93 +#include <asm/ptrace.h>
    1.94 +#include <asm/system.h>
    1.95 +
    1.96 +
    1.97 +#undef DEBUG_INTERRUPT_ROUTING
    1.98 +
    1.99 +#ifdef DEBUG_INTERRUPT_ROUTING
   1.100 +#define DBG(fmt...)	printk(fmt)
   1.101 +#else
   1.102 +#define DBG(fmt...)
   1.103 +#endif
   1.104 +
   1.105 +#define NR_PREALLOCATE_RTE_ENTRIES	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
   1.106 +#define RTE_PREALLOCATED	(1)
   1.107 +
   1.108 +static DEFINE_SPINLOCK(iosapic_lock);
   1.109 +
   1.110 +/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
   1.111 +
   1.112 +struct iosapic_rte_info {
   1.113 +	struct list_head rte_list;	/* node in list of RTEs sharing the same vector */
   1.114 +	char __iomem	*addr;		/* base address of IOSAPIC */
   1.115 +	unsigned int	gsi_base;	/* first GSI assigned to this IOSAPIC */
   1.116 +	char		rte_index;	/* IOSAPIC RTE index */
   1.117 +	int		refcnt;		/* reference counter */
   1.118 +	unsigned int	flags;		/* flags */
   1.119 +} ____cacheline_aligned;
   1.120 +
   1.121 +static struct iosapic_intr_info {
   1.122 +	struct list_head rtes;		/* RTEs using this vector (empty => not an IOSAPIC interrupt) */
   1.123 +	int		count;		/* # of RTEs that shares this vector */
   1.124 +	u32		low32;		/* current value of low word of Redirection table entry */
   1.125 +	unsigned int	dest;		/* destination CPU physical ID */
   1.126 +	unsigned char	dmode	: 3;	/* delivery mode (see iosapic.h) */
   1.127 +	unsigned char 	polarity: 1;	/* interrupt polarity (see iosapic.h) */
   1.128 +	unsigned char	trigger	: 1;	/* trigger mode (see iosapic.h) */
   1.129 +} iosapic_intr_info[IA64_NUM_VECTORS];
   1.130 +
   1.131 +static struct iosapic {
   1.132 +	char __iomem	*addr;		/* base address of IOSAPIC */
   1.133 +	unsigned int 	gsi_base;	/* first GSI assigned to this IOSAPIC */
   1.134 +	unsigned short 	num_rte;	/* number of RTE in this IOSAPIC */
   1.135 +	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */
   1.136 +#ifdef CONFIG_NUMA
   1.137 +	unsigned short	node;		/* numa node association via pxm */
   1.138 +#endif
   1.139 +} iosapic_lists[NR_IOSAPICS];
   1.140 +
   1.141 +static unsigned char pcat_compat __devinitdata;	/* 8259 compatibility flag */
   1.142 +
   1.143 +static int iosapic_kmalloc_ok;
   1.144 +static LIST_HEAD(free_rte_list);
   1.145 +
   1.146 +/*
   1.147 + * Find an IOSAPIC associated with a GSI
   1.148 + */
   1.149 +static inline int
   1.150 +find_iosapic (unsigned int gsi)
   1.151 +{
   1.152 +	int i;
   1.153 +
   1.154 +	for (i = 0; i < NR_IOSAPICS; i++) {
   1.155 +		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
   1.156 +			return i;
   1.157 +	}
   1.158 +
   1.159 +	return -1;
   1.160 +}
   1.161 +
   1.162 +static inline int
   1.163 +_gsi_to_vector (unsigned int gsi)
   1.164 +{
   1.165 +	struct iosapic_intr_info *info;
   1.166 +	struct iosapic_rte_info *rte;
   1.167 +
   1.168 +	for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
   1.169 +		list_for_each_entry(rte, &info->rtes, rte_list)
   1.170 +			if (rte->gsi_base + rte->rte_index == gsi)
   1.171 +				return info - iosapic_intr_info;
   1.172 +	return -1;
   1.173 +}
   1.174 +
   1.175 +/*
   1.176 + * Translate GSI number to the corresponding IA-64 interrupt vector.  If no
   1.177 + * entry exists, return -1.
   1.178 + */
   1.179 +inline int
   1.180 +gsi_to_vector (unsigned int gsi)
   1.181 +{
   1.182 +	return _gsi_to_vector(gsi);
   1.183 +}
   1.184 +
   1.185 +int
   1.186 +gsi_to_irq (unsigned int gsi)
   1.187 +{
   1.188 +	unsigned long flags;
   1.189 +	int irq;
   1.190 +	/*
   1.191 +	 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
   1.192 +	 * numbers...
   1.193 +	 */
   1.194 +	spin_lock_irqsave(&iosapic_lock, flags);
   1.195 +	{
   1.196 +		irq = _gsi_to_vector(gsi);
   1.197 +	}
   1.198 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   1.199 +
   1.200 +	return irq;
   1.201 +}
   1.202 +
   1.203 +static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
   1.204 +{
   1.205 +	struct iosapic_rte_info *rte;
   1.206 +
   1.207 +	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
   1.208 +		if (rte->gsi_base + rte->rte_index == gsi)
   1.209 +			return rte;
   1.210 +	return NULL;
   1.211 +}
   1.212 +
   1.213 +static void
   1.214 +set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
   1.215 +{
   1.216 +	unsigned long pol, trigger, dmode;
   1.217 +	u32 low32, high32;
   1.218 +	char __iomem *addr;
   1.219 +	int rte_index;
   1.220 +	char redir;
   1.221 +	struct iosapic_rte_info *rte;
   1.222 +
   1.223 +	DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
   1.224 +
   1.225 +	rte = gsi_vector_to_rte(gsi, vector);
   1.226 +	if (!rte)
   1.227 +		return;		/* not an IOSAPIC interrupt */
   1.228 +
   1.229 +	rte_index = rte->rte_index;
   1.230 +	addr	= rte->addr;
   1.231 +	pol     = iosapic_intr_info[vector].polarity;
   1.232 +	trigger = iosapic_intr_info[vector].trigger;
   1.233 +	dmode   = iosapic_intr_info[vector].dmode;
   1.234 +
   1.235 +	redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
   1.236 +
   1.237 +#ifdef CONFIG_SMP
   1.238 +	{
   1.239 +		unsigned int irq;
   1.240 +
   1.241 +		for (irq = 0; irq < NR_IRQS; ++irq)
   1.242 +			if (irq_to_vector(irq) == vector) {
   1.243 +				set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
   1.244 +				break;
   1.245 +			}
   1.246 +	}
   1.247 +#endif
   1.248 +
   1.249 +	low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
   1.250 +		 (trigger << IOSAPIC_TRIGGER_SHIFT) |
   1.251 +		 (dmode << IOSAPIC_DELIVERY_SHIFT) |
   1.252 +		 ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
   1.253 +		 vector);
   1.254 +
   1.255 +	/* dest contains both id and eid */
   1.256 +	high32 = (dest << IOSAPIC_DEST_SHIFT);
   1.257 +
   1.258 +	iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
   1.259 +	iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   1.260 +	iosapic_intr_info[vector].low32 = low32;
   1.261 +	iosapic_intr_info[vector].dest = dest;
   1.262 +}
   1.263 +
   1.264 +static void
   1.265 +nop (unsigned int vector)
   1.266 +{
   1.267 +	/* do nothing... */
   1.268 +}
   1.269 +
   1.270 +static void
   1.271 +mask_irq (unsigned int irq)
   1.272 +{
   1.273 +	unsigned long flags;
   1.274 +	char __iomem *addr;
   1.275 +	u32 low32;
   1.276 +	int rte_index;
   1.277 +	ia64_vector vec = irq_to_vector(irq);
   1.278 +	struct iosapic_rte_info *rte;
   1.279 +
   1.280 +	if (list_empty(&iosapic_intr_info[vec].rtes))
   1.281 +		return;			/* not an IOSAPIC interrupt! */
   1.282 +
   1.283 +	spin_lock_irqsave(&iosapic_lock, flags);
   1.284 +	{
   1.285 +		/* set only the mask bit */
   1.286 +		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
   1.287 +		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
   1.288 +			addr = rte->addr;
   1.289 +			rte_index = rte->rte_index;
   1.290 +			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   1.291 +		}
   1.292 +	}
   1.293 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   1.294 +}
   1.295 +
   1.296 +static void
   1.297 +unmask_irq (unsigned int irq)
   1.298 +{
   1.299 +	unsigned long flags;
   1.300 +	char __iomem *addr;
   1.301 +	u32 low32;
   1.302 +	int rte_index;
   1.303 +	ia64_vector vec = irq_to_vector(irq);
   1.304 +	struct iosapic_rte_info *rte;
   1.305 +
   1.306 +	if (list_empty(&iosapic_intr_info[vec].rtes))
   1.307 +		return;			/* not an IOSAPIC interrupt! */
   1.308 +
   1.309 +	spin_lock_irqsave(&iosapic_lock, flags);
   1.310 +	{
   1.311 +		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
   1.312 +		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
   1.313 +			addr = rte->addr;
   1.314 +			rte_index = rte->rte_index;
   1.315 +			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   1.316 +		}
   1.317 +	}
   1.318 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   1.319 +}
   1.320 +
   1.321 +
   1.322 +static void
   1.323 +iosapic_set_affinity (unsigned int irq, cpumask_t mask)
   1.324 +{
   1.325 +#ifdef CONFIG_SMP
   1.326 +	unsigned long flags;
   1.327 +	u32 high32, low32;
   1.328 +	int dest, rte_index;
   1.329 +	char __iomem *addr;
   1.330 +	int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
   1.331 +	ia64_vector vec;
   1.332 +	struct iosapic_rte_info *rte;
   1.333 +
   1.334 +	irq &= (~IA64_IRQ_REDIRECTED);
   1.335 +	vec = irq_to_vector(irq);
   1.336 +
   1.337 +	if (cpus_empty(mask))
   1.338 +		return;
   1.339 +
   1.340 +	dest = cpu_physical_id(first_cpu(mask));
   1.341 +
   1.342 +	if (list_empty(&iosapic_intr_info[vec].rtes))
   1.343 +		return;			/* not an IOSAPIC interrupt */
   1.344 +
   1.345 +	set_irq_affinity_info(irq, dest, redir);
   1.346 +
   1.347 +	/* dest contains both id and eid */
   1.348 +	high32 = dest << IOSAPIC_DEST_SHIFT;
   1.349 +
   1.350 +	spin_lock_irqsave(&iosapic_lock, flags);
   1.351 +	{
   1.352 +		low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
   1.353 +
   1.354 +		if (redir)
   1.355 +		        /* change delivery mode to lowest priority */
   1.356 +			low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
   1.357 +		else
   1.358 +		        /* change delivery mode to fixed */
   1.359 +			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
   1.360 +
   1.361 +		iosapic_intr_info[vec].low32 = low32;
   1.362 +		iosapic_intr_info[vec].dest = dest;
   1.363 +		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
   1.364 +			addr = rte->addr;
   1.365 +			rte_index = rte->rte_index;
   1.366 +			iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
   1.367 +			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   1.368 +		}
   1.369 +	}
   1.370 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   1.371 +#endif
   1.372 +}
   1.373 +
   1.374 +/*
   1.375 + * Handlers for level-triggered interrupts.
   1.376 + */
   1.377 +
   1.378 +static unsigned int
   1.379 +iosapic_startup_level_irq (unsigned int irq)
   1.380 +{
   1.381 +	unmask_irq(irq);
   1.382 +	return 0;
   1.383 +}
   1.384 +
   1.385 +static void
   1.386 +iosapic_end_level_irq (unsigned int irq)
   1.387 +{
   1.388 +	ia64_vector vec = irq_to_vector(irq);
   1.389 +	struct iosapic_rte_info *rte;
   1.390 +
   1.391 +	move_irq(irq);
   1.392 +	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
   1.393 +		iosapic_eoi(rte->addr, vec);
   1.394 +}
   1.395 +
   1.396 +#define iosapic_shutdown_level_irq	mask_irq
   1.397 +#define iosapic_enable_level_irq	unmask_irq
   1.398 +#define iosapic_disable_level_irq	mask_irq
   1.399 +#define iosapic_ack_level_irq		nop
   1.400 +
   1.401 +struct hw_interrupt_type irq_type_iosapic_level = {
   1.402 +	.typename =	"IO-SAPIC-level",
   1.403 +	.startup =	iosapic_startup_level_irq,
   1.404 +	.shutdown =	iosapic_shutdown_level_irq,
   1.405 +	.enable =	iosapic_enable_level_irq,
   1.406 +	.disable =	iosapic_disable_level_irq,
   1.407 +	.ack =		iosapic_ack_level_irq,
   1.408 +	.end =		iosapic_end_level_irq,
   1.409 +	.set_affinity =	iosapic_set_affinity
   1.410 +};
   1.411 +
   1.412 +/*
   1.413 + * Handlers for edge-triggered interrupts.
   1.414 + */
   1.415 +
   1.416 +static unsigned int
   1.417 +iosapic_startup_edge_irq (unsigned int irq)
   1.418 +{
   1.419 +	unmask_irq(irq);
   1.420 +	/*
   1.421 +	 * IOSAPIC simply drops interrupts pended while the
   1.422 +	 * corresponding pin was masked, so we can't know if an
   1.423 +	 * interrupt is pending already.  Let's hope not...
   1.424 +	 */
   1.425 +	return 0;
   1.426 +}
   1.427 +
   1.428 +static void
   1.429 +iosapic_ack_edge_irq (unsigned int irq)
   1.430 +{
   1.431 +	irq_desc_t *idesc = irq_descp(irq);
   1.432 +
   1.433 +	move_irq(irq);
   1.434 +	/*
   1.435 +	 * Once we have recorded IRQ_PENDING already, we can mask the
   1.436 +	 * interrupt for real. This prevents IRQ storms from unhandled
   1.437 +	 * devices.
   1.438 +	 */
   1.439 +	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
   1.440 +		mask_irq(irq);
   1.441 +}
   1.442 +
   1.443 +#define iosapic_enable_edge_irq		unmask_irq
   1.444 +#define iosapic_disable_edge_irq	nop
   1.445 +#define iosapic_end_edge_irq		nop
   1.446 +
   1.447 +struct hw_interrupt_type irq_type_iosapic_edge = {
   1.448 +	.typename =	"IO-SAPIC-edge",
   1.449 +	.startup =	iosapic_startup_edge_irq,
   1.450 +	.shutdown =	iosapic_disable_edge_irq,
   1.451 +	.enable =	iosapic_enable_edge_irq,
   1.452 +	.disable =	iosapic_disable_edge_irq,
   1.453 +	.ack =		iosapic_ack_edge_irq,
   1.454 +	.end =		iosapic_end_edge_irq,
   1.455 +	.set_affinity =	iosapic_set_affinity
   1.456 +};
   1.457 +
   1.458 +unsigned int
   1.459 +iosapic_version (char __iomem *addr)
   1.460 +{
   1.461 +	/*
   1.462 +	 * IOSAPIC Version Register return 32 bit structure like:
   1.463 +	 * {
   1.464 +	 *	unsigned int version   : 8;
   1.465 +	 *	unsigned int reserved1 : 8;
   1.466 +	 *	unsigned int max_redir : 8;
   1.467 +	 *	unsigned int reserved2 : 8;
   1.468 +	 * }
   1.469 +	 */
   1.470 +	return iosapic_read(addr, IOSAPIC_VERSION);
   1.471 +}
   1.472 +
   1.473 +static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
   1.474 +{
   1.475 +	int i, vector = -1, min_count = -1;
   1.476 +	struct iosapic_intr_info *info;
   1.477 +
   1.478 +	/*
   1.479 +	 * shared vectors for edge-triggered interrupts are not
   1.480 +	 * supported yet
   1.481 +	 */
   1.482 +	if (trigger == IOSAPIC_EDGE)
   1.483 +		return -1;
   1.484 +
   1.485 +	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
   1.486 +		info = &iosapic_intr_info[i];
   1.487 +		if (info->trigger == trigger && info->polarity == pol &&
   1.488 +		    (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {
   1.489 +			if (min_count == -1 || info->count < min_count) {
   1.490 +				vector = i;
   1.491 +				min_count = info->count;
   1.492 +			}
   1.493 +		}
   1.494 +	}
   1.495 +
   1.496 +	return vector;
   1.497 +}
   1.498 +
   1.499 +/*
   1.500 + * if the given vector is already owned by other,
   1.501 + *  assign a new vector for the other and make the vector available
   1.502 + */
   1.503 +static void __init
   1.504 +iosapic_reassign_vector (int vector)
   1.505 +{
   1.506 +	int new_vector;
   1.507 +
   1.508 +	if (!list_empty(&iosapic_intr_info[vector].rtes)) {
   1.509 +		new_vector = assign_irq_vector(AUTO_ASSIGN);
   1.510 +		if (new_vector < 0)
   1.511 +			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
   1.512 +		printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
   1.513 +		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
   1.514 +		       sizeof(struct iosapic_intr_info));
   1.515 +		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
   1.516 +		list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);
   1.517 +		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
   1.518 +		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
   1.519 +		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
   1.520 +	}
   1.521 +}
   1.522 +
   1.523 +static struct iosapic_rte_info *iosapic_alloc_rte (void)
   1.524 +{
   1.525 +	int i;
   1.526 +	struct iosapic_rte_info *rte;
   1.527 +	int preallocated = 0;
   1.528 +
   1.529 +	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
   1.530 +		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
   1.531 +		if (!rte)
   1.532 +			return NULL;
   1.533 +		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
   1.534 +			list_add(&rte->rte_list, &free_rte_list);
   1.535 +	}
   1.536 +
   1.537 +	if (!list_empty(&free_rte_list)) {
   1.538 +		rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
   1.539 +		list_del(&rte->rte_list);
   1.540 +		preallocated++;
   1.541 +	} else {
   1.542 +		rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
   1.543 +		if (!rte)
   1.544 +			return NULL;
   1.545 +	}
   1.546 +
   1.547 +	memset(rte, 0, sizeof(struct iosapic_rte_info));
   1.548 +	if (preallocated)
   1.549 +		rte->flags |= RTE_PREALLOCATED;
   1.550 +
   1.551 +	return rte;
   1.552 +}
   1.553 +
   1.554 +static void iosapic_free_rte (struct iosapic_rte_info *rte)
   1.555 +{
   1.556 +	if (rte->flags & RTE_PREALLOCATED)
   1.557 +		list_add_tail(&rte->rte_list, &free_rte_list);
   1.558 +	else
   1.559 +		kfree(rte);
   1.560 +}
   1.561 +
   1.562 +static inline int vector_is_shared (int vector)
   1.563 +{
   1.564 +	return (iosapic_intr_info[vector].count > 1);
   1.565 +}
   1.566 +
   1.567 +static int
   1.568 +register_intr (unsigned int gsi, int vector, unsigned char delivery,
   1.569 +	       unsigned long polarity, unsigned long trigger)
   1.570 +{
   1.571 +	irq_desc_t *idesc;
   1.572 +	struct hw_interrupt_type *irq_type;
   1.573 +	int rte_index;
   1.574 +	int index;
   1.575 +	unsigned long gsi_base;
   1.576 +	void __iomem *iosapic_address;
   1.577 +	struct iosapic_rte_info *rte;
   1.578 +
   1.579 +	index = find_iosapic(gsi);
   1.580 +	if (index < 0) {
   1.581 +		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
   1.582 +		return -ENODEV;
   1.583 +	}
   1.584 +
   1.585 +	iosapic_address = iosapic_lists[index].addr;
   1.586 +	gsi_base = iosapic_lists[index].gsi_base;
   1.587 +
   1.588 +	rte = gsi_vector_to_rte(gsi, vector);
   1.589 +	if (!rte) {
   1.590 +		rte = iosapic_alloc_rte();
   1.591 +		if (!rte) {
   1.592 +			printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
   1.593 +			return -ENOMEM;
   1.594 +		}
   1.595 +
   1.596 +		rte_index = gsi - gsi_base;
   1.597 +		rte->rte_index	= rte_index;
   1.598 +		rte->addr	= iosapic_address;
   1.599 +		rte->gsi_base	= gsi_base;
   1.600 +		rte->refcnt++;
   1.601 +		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
   1.602 +		iosapic_intr_info[vector].count++;
   1.603 +		iosapic_lists[index].rtes_inuse++;
   1.604 +	}
   1.605 +	else if (vector_is_shared(vector)) {
   1.606 +		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
   1.607 +		if (info->trigger != trigger || info->polarity != polarity) {
   1.608 +			printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
   1.609 +			return -EINVAL;
   1.610 +		}
   1.611 +	}
   1.612 +
   1.613 +	iosapic_intr_info[vector].polarity = polarity;
   1.614 +	iosapic_intr_info[vector].dmode    = delivery;
   1.615 +	iosapic_intr_info[vector].trigger  = trigger;
   1.616 +
   1.617 +	if (trigger == IOSAPIC_EDGE)
   1.618 +		irq_type = &irq_type_iosapic_edge;
   1.619 +	else
   1.620 +		irq_type = &irq_type_iosapic_level;
   1.621 +
   1.622 +	idesc = irq_descp(vector);
   1.623 +	if (idesc->handler != irq_type) {
   1.624 +		if (idesc->handler != &no_irq_type)
   1.625 +			printk(KERN_WARNING "%s: changing vector %d from %s to %s\n",
   1.626 +			       __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);
   1.627 +		idesc->handler = irq_type;
   1.628 +	}
   1.629 +	return 0;
   1.630 +}
   1.631 +
   1.632 +static unsigned int
   1.633 +get_target_cpu (unsigned int gsi, int vector)
   1.634 +{
   1.635 +#ifdef CONFIG_SMP
   1.636 +	static int cpu = -1;
   1.637 +
   1.638 +	/*
   1.639 +	 * In case of vector shared by multiple RTEs, all RTEs that
   1.640 +	 * share the vector need to use the same destination CPU.
   1.641 +	 */
   1.642 +	if (!list_empty(&iosapic_intr_info[vector].rtes))
   1.643 +		return iosapic_intr_info[vector].dest;
   1.644 +
   1.645 +	/*
   1.646 +	 * If the platform supports redirection via XTP, let it
   1.647 +	 * distribute interrupts.
   1.648 +	 */
   1.649 +	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
   1.650 +		return cpu_physical_id(smp_processor_id());
   1.651 +
   1.652 +	/*
   1.653 +	 * Some interrupts (ACPI SCI, for instance) are registered
   1.654 +	 * before the BSP is marked as online.
   1.655 +	 */
   1.656 +	if (!cpu_online(smp_processor_id()))
   1.657 +		return cpu_physical_id(smp_processor_id());
   1.658 +
   1.659 +#ifdef CONFIG_NUMA
   1.660 +	{
   1.661 +		int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0;
   1.662 +		cpumask_t cpu_mask;
   1.663 +
   1.664 +		iosapic_index = find_iosapic(gsi);
   1.665 +		if (iosapic_index < 0 ||
   1.666 +		    iosapic_lists[iosapic_index].node == MAX_NUMNODES)
   1.667 +			goto skip_numa_setup;
   1.668 +
   1.669 +		cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);
   1.670 +
   1.671 +		for_each_cpu_mask(numa_cpu, cpu_mask) {
   1.672 +			if (!cpu_online(numa_cpu))
   1.673 +				cpu_clear(numa_cpu, cpu_mask);
   1.674 +		}
   1.675 +
   1.676 +		num_cpus = cpus_weight(cpu_mask);
   1.677 +
   1.678 +		if (!num_cpus)
   1.679 +			goto skip_numa_setup;
   1.680 +
   1.681 +		/* Use vector assigment to distribute across cpus in node */
   1.682 +		cpu_index = vector % num_cpus;
   1.683 +
   1.684 +		for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
   1.685 +			numa_cpu = next_cpu(numa_cpu, cpu_mask);
   1.686 +
   1.687 +		if (numa_cpu != NR_CPUS)
   1.688 +			return cpu_physical_id(numa_cpu);
   1.689 +	}
   1.690 +skip_numa_setup:
   1.691 +#endif
   1.692 +	/*
   1.693 +	 * Otherwise, round-robin interrupt vectors across all the
   1.694 +	 * processors.  (It'd be nice if we could be smarter in the
   1.695 +	 * case of NUMA.)
   1.696 +	 */
   1.697 +	do {
   1.698 +		if (++cpu >= NR_CPUS)
   1.699 +			cpu = 0;
   1.700 +	} while (!cpu_online(cpu));
   1.701 +
   1.702 +	return cpu_physical_id(cpu);
   1.703 +#else
   1.704 +	return cpu_physical_id(smp_processor_id());
   1.705 +#endif
   1.706 +}
   1.707 +
   1.708 +/*
   1.709 + * ACPI can describe IOSAPIC interrupts via static tables and namespace
   1.710 + * methods.  This provides an interface to register those interrupts and
   1.711 + * program the IOSAPIC RTE.
   1.712 + */
   1.713 +int
   1.714 +iosapic_register_intr (unsigned int gsi,
   1.715 +		       unsigned long polarity, unsigned long trigger)
   1.716 +{
   1.717 +	int vector, mask = 1, err;
   1.718 +	unsigned int dest;
   1.719 +	unsigned long flags;
   1.720 +	struct iosapic_rte_info *rte;
   1.721 +	u32 low32;
   1.722 +again:
   1.723 +	/*
   1.724 +	 * If this GSI has already been registered (i.e., it's a
   1.725 +	 * shared interrupt, or we lost a race to register it),
   1.726 +	 * don't touch the RTE.
   1.727 +	 */
   1.728 +	spin_lock_irqsave(&iosapic_lock, flags);
   1.729 +	{
   1.730 +		vector = gsi_to_vector(gsi);
   1.731 +		if (vector > 0) {
   1.732 +			rte = gsi_vector_to_rte(gsi, vector);
   1.733 +			rte->refcnt++;
   1.734 +			spin_unlock_irqrestore(&iosapic_lock, flags);
   1.735 +			return vector;
   1.736 +		}
   1.737 +	}
   1.738 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   1.739 +
   1.740 +	/* If vector is running out, we try to find a sharable vector */
   1.741 +	vector = assign_irq_vector(AUTO_ASSIGN);
   1.742 +	if (vector < 0) {
   1.743 +		vector = iosapic_find_sharable_vector(trigger, polarity);
   1.744 +  		if (vector < 0)
   1.745 +			return -ENOSPC;
   1.746 +	}
   1.747 +
   1.748 +	spin_lock_irqsave(&irq_descp(vector)->lock, flags);
   1.749 +	spin_lock(&iosapic_lock);
   1.750 +	{
   1.751 +		if (gsi_to_vector(gsi) > 0) {
   1.752 +			if (list_empty(&iosapic_intr_info[vector].rtes))
   1.753 +				free_irq_vector(vector);
   1.754 +			spin_unlock(&iosapic_lock);
   1.755 +			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
   1.756 +			goto again;
   1.757 +		}
   1.758 +
   1.759 +		dest = get_target_cpu(gsi, vector);
   1.760 +		err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
   1.761 +			      polarity, trigger);
   1.762 +		if (err < 0) {
   1.763 +			spin_unlock(&iosapic_lock);
   1.764 +			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
   1.765 +			return err;
   1.766 +		}
   1.767 +
   1.768 +		/*
   1.769 +		 * If the vector is shared and already unmasked for
   1.770 +		 * other interrupt sources, don't mask it.
   1.771 +		 */
   1.772 +		low32 = iosapic_intr_info[vector].low32;
   1.773 +		if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
   1.774 +			mask = 0;
   1.775 +		set_rte(gsi, vector, dest, mask);
   1.776 +	}
   1.777 +	spin_unlock(&iosapic_lock);
   1.778 +	spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
   1.779 +
   1.780 +	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
   1.781 +	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
   1.782 +	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
   1.783 +	       cpu_logical_id(dest), dest, vector);
   1.784 +
   1.785 +	return vector;
   1.786 +}
   1.787 +
   1.788 +void
   1.789 +iosapic_unregister_intr (unsigned int gsi)
   1.790 +{
   1.791 +	unsigned long flags;
   1.792 +	int irq, vector, index;
   1.793 +	irq_desc_t *idesc;
   1.794 +	u32 low32;
   1.795 +	unsigned long trigger, polarity;
   1.796 +	unsigned int dest;
   1.797 +	struct iosapic_rte_info *rte;
   1.798 +
   1.799 +	/*
   1.800 +	 * If the irq associated with the gsi is not found,
   1.801 +	 * iosapic_unregister_intr() is unbalanced. We need to check
   1.802 +	 * this again after getting locks.
   1.803 +	 */
   1.804 +	irq = gsi_to_irq(gsi);
   1.805 +	if (irq < 0) {
   1.806 +		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
   1.807 +		WARN_ON(1);
   1.808 +		return;
   1.809 +	}
   1.810 +	vector = irq_to_vector(irq);
   1.811 +
   1.812 +	idesc = irq_descp(irq);
   1.813 +	spin_lock_irqsave(&idesc->lock, flags);
   1.814 +	spin_lock(&iosapic_lock);
   1.815 +	{
   1.816 +		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
   1.817 +			printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
   1.818 +			WARN_ON(1);
   1.819 +			goto out;
   1.820 +		}
   1.821 +
   1.822 +		if (--rte->refcnt > 0)
   1.823 +			goto out;
   1.824 +
   1.825 +		/* Mask the interrupt */
   1.826 +		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
   1.827 +		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
   1.828 +
   1.829 +		/* Remove the rte entry from the list */
   1.830 +		list_del(&rte->rte_list);
   1.831 +		iosapic_intr_info[vector].count--;
   1.832 +		iosapic_free_rte(rte);
   1.833 +		index = find_iosapic(gsi);
   1.834 +		iosapic_lists[index].rtes_inuse--;
   1.835 +		WARN_ON(iosapic_lists[index].rtes_inuse < 0);
   1.836 +
   1.837 +		trigger	 = iosapic_intr_info[vector].trigger;
   1.838 +		polarity = iosapic_intr_info[vector].polarity;
   1.839 +		dest     = iosapic_intr_info[vector].dest;
   1.840 +		printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
   1.841 +		       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
   1.842 +		       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
   1.843 +		       cpu_logical_id(dest), dest, vector);
   1.844 +
   1.845 +		if (list_empty(&iosapic_intr_info[vector].rtes)) {
   1.846 +			/* Sanity check */
   1.847 +			BUG_ON(iosapic_intr_info[vector].count);
   1.848 +
   1.849 +			/* Clear the interrupt controller descriptor */
   1.850 +			idesc->handler = &no_irq_type;
   1.851 +
   1.852 +			/* Clear the interrupt information */
   1.853 +			memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
   1.854 +			iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
   1.855 +			INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
   1.856 +
   1.857 +			if (idesc->action) {
   1.858 +				printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq);
   1.859 +				WARN_ON(1);
   1.860 +			}
   1.861 +
   1.862 +			/* Free the interrupt vector */
   1.863 +			free_irq_vector(vector);
   1.864 +		}
   1.865 +	}
   1.866 + out:
   1.867 +	spin_unlock(&iosapic_lock);
   1.868 +	spin_unlock_irqrestore(&idesc->lock, flags);
   1.869 +}
   1.870 +
   1.871 +/*
   1.872 + * ACPI calls this when it finds an entry for a platform interrupt.
   1.873 + * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
   1.874 + */
   1.875 +int __init
   1.876 +iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
   1.877 +				int iosapic_vector, u16 eid, u16 id,
   1.878 +				unsigned long polarity, unsigned long trigger)
   1.879 +{
   1.880 +	static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
   1.881 +	unsigned char delivery;
   1.882 +	int vector, mask = 0;
   1.883 +	unsigned int dest = ((id << 8) | eid) & 0xffff;
   1.884 +
   1.885 +	switch (int_type) {
   1.886 +	      case ACPI_INTERRUPT_PMI:
   1.887 +		vector = iosapic_vector;
   1.888 +		/*
   1.889 +		 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
   1.890 +		 * we need to make sure the vector is available
   1.891 +		 */
   1.892 +		iosapic_reassign_vector(vector);
   1.893 +		delivery = IOSAPIC_PMI;
   1.894 +		break;
   1.895 +	      case ACPI_INTERRUPT_INIT:
   1.896 +		vector = assign_irq_vector(AUTO_ASSIGN);
   1.897 +		if (vector < 0)
   1.898 +			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
   1.899 +		delivery = IOSAPIC_INIT;
   1.900 +		break;
   1.901 +	      case ACPI_INTERRUPT_CPEI:
   1.902 +		vector = IA64_CPE_VECTOR;
   1.903 +		delivery = IOSAPIC_LOWEST_PRIORITY;
   1.904 +		mask = 1;
   1.905 +		break;
   1.906 +	      default:
   1.907 +		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
   1.908 +		return -1;
   1.909 +	}
   1.910 +
   1.911 +	register_intr(gsi, vector, delivery, polarity, trigger);
   1.912 +
   1.913 +	printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
   1.914 +	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
   1.915 +	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
   1.916 +	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
   1.917 +	       cpu_logical_id(dest), dest, vector);
   1.918 +
   1.919 +	set_rte(gsi, vector, dest, mask);
   1.920 +	return vector;
   1.921 +}
   1.922 +
   1.923 +
   1.924 +/*
   1.925 + * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
   1.926 + * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
   1.927 + */
   1.928 +void __init
   1.929 +iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
   1.930 +			  unsigned long polarity,
   1.931 +			  unsigned long trigger)
   1.932 +{
   1.933 +	int vector;
   1.934 +	unsigned int dest = cpu_physical_id(smp_processor_id());
   1.935 +
   1.936 +	vector = isa_irq_to_vector(isa_irq);
   1.937 +
   1.938 +	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
   1.939 +
   1.940 +	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
   1.941 +	    isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
   1.942 +	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",
   1.943 +	    cpu_logical_id(dest), dest, vector);
   1.944 +
   1.945 +	set_rte(gsi, vector, dest, 1);
   1.946 +}
   1.947 +
   1.948 +void __init
   1.949 +iosapic_system_init (int system_pcat_compat)
   1.950 +{
   1.951 +	int vector;
   1.952 +
   1.953 +	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
   1.954 +		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
   1.955 +		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);	/* mark as unused */
   1.956 +	}
   1.957 +
   1.958 +	pcat_compat = system_pcat_compat;
   1.959 +	if (pcat_compat) {
   1.960 +		/*
   1.961 +		 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
   1.962 +		 * enabled.
   1.963 +		 */
   1.964 +		printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
   1.965 +		outb(0xff, 0xA1);
   1.966 +		outb(0xff, 0x21);
   1.967 +	}
   1.968 +}
   1.969 +
   1.970 +static inline int
   1.971 +iosapic_alloc (void)
   1.972 +{
   1.973 +	int index;
   1.974 +
   1.975 +	for (index = 0; index < NR_IOSAPICS; index++)
   1.976 +		if (!iosapic_lists[index].addr)
   1.977 +			return index;
   1.978 +
   1.979 +	printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
   1.980 +	return -1;
   1.981 +}
   1.982 +
   1.983 +static inline void
   1.984 +iosapic_free (int index)
   1.985 +{
   1.986 +	memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
   1.987 +}
   1.988 +
   1.989 +static inline int
   1.990 +iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
   1.991 +{
   1.992 +	int index;
   1.993 +	unsigned int gsi_end, base, end;
   1.994 +
   1.995 +	/* check gsi range */
   1.996 +	gsi_end = gsi_base + ((ver >> 16) & 0xff);
   1.997 +	for (index = 0; index < NR_IOSAPICS; index++) {
   1.998 +		if (!iosapic_lists[index].addr)
   1.999 +			continue;
  1.1000 +
  1.1001 +		base = iosapic_lists[index].gsi_base;
  1.1002 +		end  = base + iosapic_lists[index].num_rte - 1;
  1.1003 +
  1.1004 +		if (gsi_base < base && gsi_end < base)
  1.1005 +			continue;/* OK */
  1.1006 +
  1.1007 +		if (gsi_base > end && gsi_end > end)
  1.1008 +			continue; /* OK */
  1.1009 +
  1.1010 +		return -EBUSY;
  1.1011 +	}
  1.1012 +	return 0;
  1.1013 +}
  1.1014 +
  1.1015 +int __devinit
  1.1016 +iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
  1.1017 +{
  1.1018 +	int num_rte, err, index;
  1.1019 +	unsigned int isa_irq, ver;
  1.1020 +	char __iomem *addr;
  1.1021 +	unsigned long flags;
  1.1022 +
  1.1023 +	spin_lock_irqsave(&iosapic_lock, flags);
  1.1024 +	{
  1.1025 +		addr = ioremap(phys_addr, 0);
  1.1026 +		ver = iosapic_version(addr);
  1.1027 +
  1.1028 +		if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
  1.1029 +			iounmap(addr);
  1.1030 +			spin_unlock_irqrestore(&iosapic_lock, flags);
  1.1031 +			return err;
  1.1032 +		}
  1.1033 +
  1.1034 +		/*
  1.1035 +		 * The MAX_REDIR register holds the highest input pin
  1.1036 +		 * number (starting from 0).
  1.1037 +		 * We add 1 so that we can use it for number of pins (= RTEs)
  1.1038 +		 */
  1.1039 +		num_rte = ((ver >> 16) & 0xff) + 1;
  1.1040 +
  1.1041 +		index = iosapic_alloc();
  1.1042 +		iosapic_lists[index].addr = addr;
  1.1043 +		iosapic_lists[index].gsi_base = gsi_base;
  1.1044 +		iosapic_lists[index].num_rte = num_rte;
  1.1045 +#ifdef CONFIG_NUMA
  1.1046 +		iosapic_lists[index].node = MAX_NUMNODES;
  1.1047 +#endif
  1.1048 +	}
  1.1049 +	spin_unlock_irqrestore(&iosapic_lock, flags);
  1.1050 +
  1.1051 +	if ((gsi_base == 0) && pcat_compat) {
  1.1052 +		/*
  1.1053 +		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
  1.1054 +		 * get reprogrammed later on with data from the ACPI Interrupt Source
  1.1055 +		 * Override table.
  1.1056 +		 */
  1.1057 +		for (isa_irq = 0; isa_irq < 16; ++isa_irq)
  1.1058 +			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
  1.1059 +	}
  1.1060 +	return 0;
  1.1061 +}
  1.1062 +
  1.1063 +#ifdef CONFIG_HOTPLUG
  1.1064 +int
  1.1065 +iosapic_remove (unsigned int gsi_base)
  1.1066 +{
  1.1067 +	int index, err = 0;
  1.1068 +	unsigned long flags;
  1.1069 +
  1.1070 +	spin_lock_irqsave(&iosapic_lock, flags);
  1.1071 +	{
  1.1072 +		index = find_iosapic(gsi_base);
  1.1073 +		if (index < 0) {
  1.1074 +			printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
  1.1075 +			       __FUNCTION__, gsi_base);
  1.1076 +			goto out;
  1.1077 +		}
  1.1078 +
  1.1079 +		if (iosapic_lists[index].rtes_inuse) {
  1.1080 +			err = -EBUSY;
  1.1081 +			printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
  1.1082 +			       __FUNCTION__, gsi_base);
  1.1083 +			goto out;
  1.1084 +		}
  1.1085 +
  1.1086 +		iounmap(iosapic_lists[index].addr);
  1.1087 +		iosapic_free(index);
  1.1088 +	}
  1.1089 + out:
  1.1090 +	spin_unlock_irqrestore(&iosapic_lock, flags);
  1.1091 +	return err;
  1.1092 +}
  1.1093 +#endif /* CONFIG_HOTPLUG */
  1.1094 +
  1.1095 +#ifdef CONFIG_NUMA
  1.1096 +void __devinit
  1.1097 +map_iosapic_to_node(unsigned int gsi_base, int node)
  1.1098 +{
  1.1099 +	int index;
  1.1100 +
  1.1101 +	index = find_iosapic(gsi_base);
  1.1102 +	if (index < 0) {
  1.1103 +		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",
  1.1104 +		       __FUNCTION__, gsi_base);
  1.1105 +		return;
  1.1106 +	}
  1.1107 +	iosapic_lists[index].node = node;
  1.1108 +	return;
  1.1109 +}
  1.1110 +#endif
  1.1111 +
  1.1112 +static int __init iosapic_enable_kmalloc (void)
  1.1113 +{
  1.1114 +	iosapic_kmalloc_ok = 1;
  1.1115 +	return 0;
  1.1116 +}
  1.1117 +core_initcall (iosapic_enable_kmalloc);
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c	Fri Apr 21 08:56:24 2006 -0600
     2.3 @@ -0,0 +1,277 @@
     2.4 +/*
     2.5 + * linux/arch/ia64/kernel/irq.c
     2.6 + *
     2.7 + * Copyright (C) 1998-2001 Hewlett-Packard Co
     2.8 + *	Stephane Eranian <eranian@hpl.hp.com>
     2.9 + *	David Mosberger-Tang <davidm@hpl.hp.com>
    2.10 + *
    2.11 + *  6/10/99: Updated to bring in sync with x86 version to facilitate
    2.12 + *	     support for SMP and different interrupt controllers.
    2.13 + *
    2.14 + * 09/15/00 Goutham Rao <goutham.rao@intel.com> Implemented pci_irq_to_vector
    2.15 + *                      PCI to vector allocation routine.
    2.16 + * 04/14/2004 Ashok Raj <ashok.raj@intel.com>
    2.17 + *						Added CPU Hotplug handling for IPF.
    2.18 + */
    2.19 +
    2.20 +#include <linux/config.h>
    2.21 +#include <linux/module.h>
    2.22 +
    2.23 +#include <linux/jiffies.h>
    2.24 +#include <linux/errno.h>
    2.25 +#include <linux/init.h>
    2.26 +#include <linux/interrupt.h>
    2.27 +#include <linux/ioport.h>
    2.28 +#include <linux/kernel_stat.h>
    2.29 +#include <linux/slab.h>
    2.30 +#include <linux/ptrace.h>
    2.31 +#include <linux/random.h>	/* for rand_initialize_irq() */
    2.32 +#include <linux/signal.h>
    2.33 +#include <linux/smp.h>
    2.34 +#include <linux/smp_lock.h>
    2.35 +#include <linux/threads.h>
    2.36 +#include <linux/bitops.h>
    2.37 +
    2.38 +#include <asm/delay.h>
    2.39 +#include <asm/intrinsics.h>
    2.40 +#include <asm/io.h>
    2.41 +#include <asm/hw_irq.h>
    2.42 +#include <asm/machvec.h>
    2.43 +#include <asm/pgtable.h>
    2.44 +#include <asm/system.h>
    2.45 +
    2.46 +#ifdef CONFIG_PERFMON
    2.47 +# include <asm/perfmon.h>
    2.48 +#endif
    2.49 +
    2.50 +#define IRQ_DEBUG	0
    2.51 +
    2.52 +/* default base addr of IPI table */
    2.53 +void __iomem *ipi_base_addr = ((void __iomem *)
    2.54 +			       (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
    2.55 +
    2.56 +/*
    2.57 + * Legacy IRQ to IA-64 vector translation table.
    2.58 + */
    2.59 +__u8 isa_irq_to_vector_map[16] = {
    2.60 +	/* 8259 IRQ translation, first 16 entries */
    2.61 +	0x2f, 0x20, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
    2.62 +	0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21
    2.63 +};
    2.64 +EXPORT_SYMBOL(isa_irq_to_vector_map);
    2.65 +
    2.66 +static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
    2.67 +
    2.68 +int
    2.69 +assign_irq_vector (int irq)
    2.70 +{
    2.71 +	int pos, vector;
    2.72 + again:
    2.73 +	pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
    2.74 +	vector = IA64_FIRST_DEVICE_VECTOR + pos;
    2.75 +	if (vector > IA64_LAST_DEVICE_VECTOR)
    2.76 +		return -ENOSPC;
    2.77 +	if (test_and_set_bit(pos, ia64_vector_mask))
    2.78 +		goto again;
    2.79 +	return vector;
    2.80 +}
    2.81 +
    2.82 +void
    2.83 +free_irq_vector (int vector)
    2.84 +{
    2.85 +	int pos;
    2.86 +
    2.87 +	if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
    2.88 +		return;
    2.89 +
    2.90 +	pos = vector - IA64_FIRST_DEVICE_VECTOR;
    2.91 +	if (!test_and_clear_bit(pos, ia64_vector_mask))
    2.92 +		printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
    2.93 +}
    2.94 +
    2.95 +#ifdef CONFIG_SMP
    2.96 +#	define IS_RESCHEDULE(vec)	(vec == IA64_IPI_RESCHEDULE)
    2.97 +#else
    2.98 +#	define IS_RESCHEDULE(vec)	(0)
    2.99 +#endif
   2.100 +/*
   2.101 + * That's where the IVT branches when we get an external
   2.102 + * interrupt. This branches to the correct hardware IRQ handler via
   2.103 + * function ptr.
   2.104 + */
   2.105 +void
   2.106 +ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
   2.107 +{
   2.108 +	unsigned long saved_tpr;
   2.109 +
   2.110 +#if IRQ_DEBUG
   2.111 +	{
   2.112 +		unsigned long bsp, sp;
   2.113 +
   2.114 +		/*
   2.115 +		 * Note: if the interrupt happened while executing in
   2.116 +		 * the context switch routine (ia64_switch_to), we may
   2.117 +		 * get a spurious stack overflow here.  This is
   2.118 +		 * because the register and the memory stack are not
   2.119 +		 * switched atomically.
   2.120 +		 */
   2.121 +		bsp = ia64_getreg(_IA64_REG_AR_BSP);
   2.122 +		sp = ia64_getreg(_IA64_REG_SP);
   2.123 +
   2.124 +		if ((sp - bsp) < 1024) {
   2.125 +			static unsigned char count;
   2.126 +			static long last_time;
   2.127 +
   2.128 +			if (jiffies - last_time > 5*HZ)
   2.129 +				count = 0;
   2.130 +			if (++count < 5) {
   2.131 +				last_time = jiffies;
   2.132 +				printk("ia64_handle_irq: DANGER: less than "
   2.133 +				       "1KB of free stack space!!\n"
   2.134 +				       "(bsp=0x%lx, sp=%lx)\n", bsp, sp);
   2.135 +			}
   2.136 +		}
   2.137 +	}
   2.138 +#endif /* IRQ_DEBUG */
   2.139 +
   2.140 +	/*
   2.141 +	 * Always set TPR to limit maximum interrupt nesting depth to
   2.142 +	 * 16 (without this, it would be ~240, which could easily lead
   2.143 +	 * to kernel stack overflows).
   2.144 +	 */
   2.145 +	irq_enter();
   2.146 +	saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
   2.147 +	ia64_srlz_d();
   2.148 +	while (vector != IA64_SPURIOUS_INT_VECTOR) {
   2.149 +		if (!IS_RESCHEDULE(vector)) {
   2.150 +			ia64_setreg(_IA64_REG_CR_TPR, vector);
   2.151 +			ia64_srlz_d();
   2.152 +
   2.153 +			__do_IRQ(local_vector_to_irq(vector), regs);
   2.154 +
   2.155 +			/*
   2.156 +			 * Disable interrupts and send EOI:
   2.157 +			 */
   2.158 +			local_irq_disable();
   2.159 +			ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
   2.160 +		}
   2.161 +		ia64_eoi();
   2.162 +		vector = ia64_get_ivr();
   2.163 +	}
   2.164 +	/*
   2.165 +	 * This must be done *after* the ia64_eoi().  For example, the keyboard softirq
   2.166 +	 * handler needs to be able to wait for further keyboard interrupts, which can't
   2.167 +	 * come through until ia64_eoi() has been done.
   2.168 +	 */
   2.169 +	irq_exit();
   2.170 +}
   2.171 +
   2.172 +#ifdef CONFIG_HOTPLUG_CPU
   2.173 +/*
   2.174 + * This function emulates a interrupt processing when a cpu is about to be
   2.175 + * brought down.
   2.176 + */
   2.177 +void ia64_process_pending_intr(void)
   2.178 +{
   2.179 +	ia64_vector vector;
   2.180 +	unsigned long saved_tpr;
   2.181 +	extern unsigned int vectors_in_migration[NR_IRQS];
   2.182 +
   2.183 +	vector = ia64_get_ivr();
   2.184 +
   2.185 +	 irq_enter();
   2.186 +	 saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
   2.187 +	 ia64_srlz_d();
   2.188 +
   2.189 +	 /*
   2.190 +	  * Perform normal interrupt style processing
   2.191 +	  */
   2.192 +	while (vector != IA64_SPURIOUS_INT_VECTOR) {
   2.193 +		if (!IS_RESCHEDULE(vector)) {
   2.194 +			ia64_setreg(_IA64_REG_CR_TPR, vector);
   2.195 +			ia64_srlz_d();
   2.196 +
   2.197 +			/*
   2.198 +			 * Now try calling normal ia64_handle_irq as it would have got called
   2.199 +			 * from a real intr handler. Try passing null for pt_regs, hopefully
   2.200 +			 * it will work. I hope it works!.
   2.201 +			 * Probably could shared code.
   2.202 +			 */
   2.203 +			vectors_in_migration[local_vector_to_irq(vector)]=0;
   2.204 +			__do_IRQ(local_vector_to_irq(vector), NULL);
   2.205 +
   2.206 +			/*
   2.207 +			 * Disable interrupts and send EOI
   2.208 +			 */
   2.209 +			local_irq_disable();
   2.210 +			ia64_setreg(_IA64_REG_CR_TPR, saved_tpr);
   2.211 +		}
   2.212 +		ia64_eoi();
   2.213 +		vector = ia64_get_ivr();
   2.214 +	}
   2.215 +	irq_exit();
   2.216 +}
   2.217 +#endif
   2.218 +
   2.219 +
   2.220 +#ifdef CONFIG_SMP
   2.221 +extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
   2.222 +
   2.223 +static struct irqaction ipi_irqaction = {
   2.224 +	.handler =	handle_IPI,
   2.225 +	.flags =	SA_INTERRUPT,
   2.226 +	.name =		"IPI"
   2.227 +};
   2.228 +#endif
   2.229 +
   2.230 +void
   2.231 +register_percpu_irq (ia64_vector vec, struct irqaction *action)
   2.232 +{
   2.233 +	irq_desc_t *desc;
   2.234 +	unsigned int irq;
   2.235 +
   2.236 +	for (irq = 0; irq < NR_IRQS; ++irq)
   2.237 +		if (irq_to_vector(irq) == vec) {
   2.238 +			desc = irq_descp(irq);
   2.239 +			desc->status |= IRQ_PER_CPU;
   2.240 +			desc->handler = &irq_type_ia64_lsapic;
   2.241 +			if (action)
   2.242 +				setup_irq(irq, action);
   2.243 +		}
   2.244 +}
   2.245 +
   2.246 +void __init
   2.247 +init_IRQ (void)
   2.248 +{
   2.249 +	register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
   2.250 +#ifdef CONFIG_SMP
   2.251 +	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
   2.252 +#endif
   2.253 +#ifdef CONFIG_PERFMON
   2.254 +	pfm_init_percpu();
   2.255 +#endif
   2.256 +	platform_irq_init();
   2.257 +}
   2.258 +
   2.259 +void
   2.260 +ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect)
   2.261 +{
   2.262 +	void __iomem *ipi_addr;
   2.263 +	unsigned long ipi_data;
   2.264 +	unsigned long phys_cpu_id;
   2.265 +
   2.266 +#ifdef CONFIG_SMP
   2.267 +	phys_cpu_id = cpu_physical_id(cpu);
   2.268 +#else
   2.269 +	phys_cpu_id = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
   2.270 +#endif
   2.271 +
   2.272 +	/*
   2.273 +	 * cpu number is in 8bit ID and 8bit EID
   2.274 +	 */
   2.275 +
   2.276 +	ipi_data = (delivery_mode << 8) | (vector & 0xff);
   2.277 +	ipi_addr = ipi_base_addr + ((phys_cpu_id << 4) | ((redirect & 1) << 3));
   2.278 +
   2.279 +	writeq(ipi_data, ipi_addr);
   2.280 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/linux-2.6-xen-sparse/include/asm-ia64/iosapic.h	Fri Apr 21 08:56:24 2006 -0600
     3.3 @@ -0,0 +1,112 @@
     3.4 +#ifndef __ASM_IA64_IOSAPIC_H
     3.5 +#define __ASM_IA64_IOSAPIC_H
     3.6 +
     3.7 +#define	IOSAPIC_REG_SELECT	0x0
     3.8 +#define	IOSAPIC_WINDOW		0x10
     3.9 +#define	IOSAPIC_EOI		0x40
    3.10 +
    3.11 +#define	IOSAPIC_VERSION		0x1
    3.12 +
    3.13 +/*
    3.14 + * Redirection table entry
    3.15 + */
    3.16 +#define	IOSAPIC_RTE_LOW(i)	(0x10+i*2)
    3.17 +#define	IOSAPIC_RTE_HIGH(i)	(0x11+i*2)
    3.18 +
    3.19 +#define	IOSAPIC_DEST_SHIFT		16
    3.20 +
    3.21 +/*
    3.22 + * Delivery mode
    3.23 + */
    3.24 +#define	IOSAPIC_DELIVERY_SHIFT		8
    3.25 +#define	IOSAPIC_FIXED			0x0
    3.26 +#define	IOSAPIC_LOWEST_PRIORITY	0x1
    3.27 +#define	IOSAPIC_PMI			0x2
    3.28 +#define	IOSAPIC_NMI			0x4
    3.29 +#define	IOSAPIC_INIT			0x5
    3.30 +#define	IOSAPIC_EXTINT			0x7
    3.31 +
    3.32 +/*
    3.33 + * Interrupt polarity
    3.34 + */
    3.35 +#define	IOSAPIC_POLARITY_SHIFT		13
    3.36 +#define	IOSAPIC_POL_HIGH		0
    3.37 +#define	IOSAPIC_POL_LOW		1
    3.38 +
    3.39 +/*
    3.40 + * Trigger mode
    3.41 + */
    3.42 +#define	IOSAPIC_TRIGGER_SHIFT		15
    3.43 +#define	IOSAPIC_EDGE			0
    3.44 +#define	IOSAPIC_LEVEL			1
    3.45 +
    3.46 +/*
    3.47 + * Mask bit
    3.48 + */
    3.49 +
    3.50 +#define	IOSAPIC_MASK_SHIFT		16
    3.51 +#define	IOSAPIC_MASK			(1<<IOSAPIC_MASK_SHIFT)
    3.52 +
    3.53 +#ifndef __ASSEMBLY__
    3.54 +
    3.55 +#ifdef CONFIG_IOSAPIC
    3.56 +
    3.57 +#define NR_IOSAPICS			256
    3.58 +
    3.59 +static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
    3.60 +{
    3.61 +	writel(reg, iosapic + IOSAPIC_REG_SELECT);
    3.62 +	return readl(iosapic + IOSAPIC_WINDOW);
    3.63 +}
    3.64 +
    3.65 +static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
    3.66 +{
    3.67 +	writel(reg, iosapic + IOSAPIC_REG_SELECT);
    3.68 +	writel(val, iosapic + IOSAPIC_WINDOW);
    3.69 +}
    3.70 +
    3.71 +static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
    3.72 +{
    3.73 +	writel(vector, iosapic + IOSAPIC_EOI);
    3.74 +}
    3.75 +
    3.76 +extern void __init iosapic_system_init (int pcat_compat);
    3.77 +extern int __devinit iosapic_init (unsigned long address,
    3.78 +				    unsigned int gsi_base);
    3.79 +#ifdef CONFIG_HOTPLUG
    3.80 +extern int iosapic_remove (unsigned int gsi_base);
    3.81 +#else
    3.82 +#define iosapic_remove(gsi_base)				(-EINVAL)
    3.83 +#endif /* CONFIG_HOTPLUG */
    3.84 +extern int gsi_to_vector (unsigned int gsi);
    3.85 +extern int gsi_to_irq (unsigned int gsi);
    3.86 +extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
    3.87 +				  unsigned long trigger);
    3.88 +extern void iosapic_unregister_intr (unsigned int irq);
    3.89 +extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
    3.90 +				      unsigned long polarity,
    3.91 +				      unsigned long trigger);
    3.92 +extern int __init iosapic_register_platform_intr (u32 int_type,
    3.93 +					   unsigned int gsi,
    3.94 +					   int pmi_vector,
    3.95 +					   u16 eid, u16 id,
    3.96 +					   unsigned long polarity,
    3.97 +					   unsigned long trigger);
    3.98 +extern unsigned int iosapic_version (char __iomem *addr);
    3.99 +
   3.100 +#ifdef CONFIG_NUMA
   3.101 +extern void __devinit map_iosapic_to_node (unsigned int, int);
   3.102 +#endif
   3.103 +#else
   3.104 +#define iosapic_system_init(pcat_compat)			do { } while (0)
   3.105 +#define iosapic_init(address,gsi_base)				(-EINVAL)
   3.106 +#define iosapic_remove(gsi_base)				(-ENODEV)
   3.107 +#define iosapic_register_intr(gsi,polarity,trigger)		(gsi)
   3.108 +#define iosapic_unregister_intr(irq)				do { } while (0)
   3.109 +#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger)	do { } while (0)
   3.110 +#define iosapic_register_platform_intr(type,gsi,pmi,eid,id, \
   3.111 +	polarity,trigger)					(gsi)
   3.112 +#endif
   3.113 +
   3.114 +# endif /* !__ASSEMBLY__ */
   3.115 +#endif /* __ASM_IA64_IOSAPIC_H */
     4.1 --- a/xen/arch/ia64/linux-xen/README.origin	Wed Apr 19 10:39:15 2006 -0600
     4.2 +++ b/xen/arch/ia64/linux-xen/README.origin	Fri Apr 21 08:56:24 2006 -0600
     4.3 @@ -26,3 +26,6 @@ unaligned.c		-> linux/arch/ia64/kernel/u
     4.4  unwind.c		-> linux/arch/ia64/kernel/unwind.c
     4.5  unwind_decoder.c	-> linux/arch/ia64/kernel/unwind_decoder.c
     4.6  unwind_i.h		-> linux/arch/ia64/kernel/unwind_i.h
     4.7 +
     4.8 +# The files below are from Linux-2.6.16
     4.9 +iosapic.c		-> linux/arch/ia64/kernel/iosapic.c
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/xen/arch/ia64/linux-xen/iosapic.c	Fri Apr 21 08:56:24 2006 -0600
     5.3 @@ -0,0 +1,1114 @@
     5.4 +/*
     5.5 + * I/O SAPIC support.
     5.6 + *
     5.7 + * Copyright (C) 1999 Intel Corp.
     5.8 + * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
     5.9 + * Copyright (C) 2000-2002 J.I. Lee <jung-ik.lee@intel.com>
    5.10 + * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co.
    5.11 + *	David Mosberger-Tang <davidm@hpl.hp.com>
    5.12 + * Copyright (C) 1999 VA Linux Systems
    5.13 + * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com>
    5.14 + *
    5.15 + * 00/04/19	D. Mosberger	Rewritten to mirror more closely the x86 I/O APIC code.
    5.16 + *				In particular, we now have separate handlers for edge
    5.17 + *				and level triggered interrupts.
    5.18 + * 00/10/27	Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation
    5.19 + *				PCI to vector mapping, shared PCI interrupts.
    5.20 + * 00/10/27	D. Mosberger	Document things a bit more to make them more understandable.
    5.21 + *				Clean up much of the old IOSAPIC cruft.
    5.22 + * 01/07/27	J.I. Lee	PCI irq routing, Platform/Legacy interrupts and fixes for
    5.23 + *				ACPI S5(SoftOff) support.
    5.24 + * 02/01/23	J.I. Lee	iosapic pgm fixes for PCI irq routing from _PRT
    5.25 + * 02/01/07     E. Focht        <efocht@ess.nec.de> Redirectable interrupt vectors in
    5.26 + *                              iosapic_set_affinity(), initializations for
    5.27 + *                              /proc/irq/#/smp_affinity
    5.28 + * 02/04/02	P. Diefenbaugh	Cleaned up ACPI PCI IRQ routing.
    5.29 + * 02/04/18	J.I. Lee	bug fix in iosapic_init_pci_irq
    5.30 + * 02/04/30	J.I. Lee	bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping
    5.31 + *				error
    5.32 + * 02/07/29	T. Kochi	Allocate interrupt vectors dynamically
    5.33 + * 02/08/04	T. Kochi	Cleaned up terminology (irq, global system interrupt, vector, etc.)
    5.34 + * 02/09/20	D. Mosberger	Simplified by taking advantage of ACPI's pci_irq code.
    5.35 + * 03/02/19	B. Helgaas	Make pcat_compat system-wide, not per-IOSAPIC.
    5.36 + *				Remove iosapic_address & gsi_base from external interfaces.
    5.37 + *				Rationalize __init/__devinit attributes.
    5.38 + * 04/12/04 Ashok Raj	<ashok.raj@intel.com> Intel Corporation 2004
    5.39 + *				Updated to work with irq migration necessary for CPU Hotplug
    5.40 + */
    5.41 +/*
    5.42 + * Here is what the interrupt logic between a PCI device and the kernel looks like:
    5.43 + *
    5.44 + * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
    5.45 + *     device is uniquely identified by its bus--, and slot-number (the function
    5.46 + *     number does not matter here because all functions share the same interrupt
    5.47 + *     lines).
    5.48 + *
    5.49 + * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller.
    5.50 + *     Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level
    5.51 + *     triggered and use the same polarity).  Each interrupt line has a unique Global
    5.52 + *     System Interrupt (GSI) number which can be calculated as the sum of the controller's
    5.53 + *     base GSI number and the IOSAPIC pin number to which the line connects.
    5.54 + *
    5.55 + * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin
    5.56 + *     into the IA-64 interrupt vector.  This interrupt vector is then sent to the CPU.
    5.57 + *
    5.58 + * (4) The kernel recognizes an interrupt as an IRQ.  The IRQ interface is used as
    5.59 + *     architecture-independent interrupt handling mechanism in Linux.  As an
    5.60 + *     IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number
    5.61 + *     mapping.  On smaller systems, we use one-to-one mapping between IA-64 vector and
    5.62 + *     IRQ.  A platform can implement platform_irq_to_vector(irq) and
    5.63 + *     platform_local_vector_to_irq(vector) APIs to differentiate the mapping.
    5.64 + *     Please see also include/asm-ia64/hw_irq.h for those APIs.
    5.65 + *
    5.66 + * To sum up, there are three levels of mappings involved:
    5.67 + *
    5.68 + *	PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
    5.69 + *
    5.70 + * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts.
    5.71 + * Now we use "IRQ" only for Linux IRQ's.  ISA IRQ (isa_irq) is the only exception in this
    5.72 + * source code.
    5.73 + */
    5.74 +#include <linux/config.h>
    5.75 +
    5.76 +#include <linux/acpi.h>
    5.77 +#include <linux/init.h>
    5.78 +#include <linux/irq.h>
    5.79 +#include <linux/kernel.h>
    5.80 +#include <linux/list.h>
    5.81 +#include <linux/pci.h>
    5.82 +#include <linux/smp.h>
    5.83 +#include <linux/smp_lock.h>
    5.84 +#include <linux/string.h>
    5.85 +#include <linux/bootmem.h>
    5.86 +
    5.87 +#include <asm/delay.h>
    5.88 +#include <asm/hw_irq.h>
    5.89 +#include <asm/io.h>
    5.90 +#include <asm/iosapic.h>
    5.91 +#include <asm/machvec.h>
    5.92 +#include <asm/processor.h>
    5.93 +#include <asm/ptrace.h>
    5.94 +#include <asm/system.h>
    5.95 +
    5.96 +
    5.97 +#undef DEBUG_INTERRUPT_ROUTING
    5.98 +
    5.99 +#ifdef DEBUG_INTERRUPT_ROUTING
   5.100 +#define DBG(fmt...)	printk(fmt)
   5.101 +#else
   5.102 +#define DBG(fmt...)
   5.103 +#endif
   5.104 +
   5.105 +#define NR_PREALLOCATE_RTE_ENTRIES	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
   5.106 +#define RTE_PREALLOCATED	(1)
   5.107 +
   5.108 +static DEFINE_SPINLOCK(iosapic_lock);
   5.109 +
   5.110 +/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */
   5.111 +
   5.112 +struct iosapic_rte_info {
   5.113 +	struct list_head rte_list;	/* node in list of RTEs sharing the same vector */
   5.114 +	char __iomem	*addr;		/* base address of IOSAPIC */
   5.115 +	unsigned int	gsi_base;	/* first GSI assigned to this IOSAPIC */
   5.116 +	char		rte_index;	/* IOSAPIC RTE index */
   5.117 +	int		refcnt;		/* reference counter */
   5.118 +	unsigned int	flags;		/* flags */
   5.119 +} ____cacheline_aligned;
   5.120 +
   5.121 +static struct iosapic_intr_info {
   5.122 +	struct list_head rtes;		/* RTEs using this vector (empty => not an IOSAPIC interrupt) */
   5.123 +	int		count;		/* # of RTEs that shares this vector */
   5.124 +	u32		low32;		/* current value of low word of Redirection table entry */
   5.125 +	unsigned int	dest;		/* destination CPU physical ID */
   5.126 +	unsigned char	dmode	: 3;	/* delivery mode (see iosapic.h) */
   5.127 +	unsigned char 	polarity: 1;	/* interrupt polarity (see iosapic.h) */
   5.128 +	unsigned char	trigger	: 1;	/* trigger mode (see iosapic.h) */
   5.129 +} iosapic_intr_info[IA64_NUM_VECTORS];
   5.130 +
   5.131 +static struct iosapic {
   5.132 +	char __iomem	*addr;		/* base address of IOSAPIC */
   5.133 +	unsigned int 	gsi_base;	/* first GSI assigned to this IOSAPIC */
   5.134 +	unsigned short 	num_rte;	/* number of RTE in this IOSAPIC */
   5.135 +	int		rtes_inuse;	/* # of RTEs in use on this IOSAPIC */
   5.136 +#ifdef CONFIG_NUMA
   5.137 +	unsigned short	node;		/* numa node association via pxm */
   5.138 +#endif
   5.139 +} iosapic_lists[NR_IOSAPICS];
   5.140 +
   5.141 +static unsigned char pcat_compat __devinitdata;	/* 8259 compatibility flag */
   5.142 +
   5.143 +static int iosapic_kmalloc_ok;
   5.144 +static LIST_HEAD(free_rte_list);
   5.145 +
   5.146 +/*
   5.147 + * Find an IOSAPIC associated with a GSI
   5.148 + */
   5.149 +static inline int
   5.150 +find_iosapic (unsigned int gsi)
   5.151 +{
   5.152 +	int i;
   5.153 +
   5.154 +	for (i = 0; i < NR_IOSAPICS; i++) {
   5.155 +		if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
   5.156 +			return i;
   5.157 +	}
   5.158 +
   5.159 +	return -1;
   5.160 +}
   5.161 +
   5.162 +static inline int
   5.163 +_gsi_to_vector (unsigned int gsi)
   5.164 +{
   5.165 +	struct iosapic_intr_info *info;
   5.166 +	struct iosapic_rte_info *rte;
   5.167 +
   5.168 +	for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info)
   5.169 +		list_for_each_entry(rte, &info->rtes, rte_list)
   5.170 +			if (rte->gsi_base + rte->rte_index == gsi)
   5.171 +				return info - iosapic_intr_info;
   5.172 +	return -1;
   5.173 +}
   5.174 +
   5.175 +/*
   5.176 + * Translate GSI number to the corresponding IA-64 interrupt vector.  If no
   5.177 + * entry exists, return -1.
   5.178 + */
   5.179 +inline int
   5.180 +gsi_to_vector (unsigned int gsi)
   5.181 +{
   5.182 +	return _gsi_to_vector(gsi);
   5.183 +}
   5.184 +
   5.185 +int
   5.186 +gsi_to_irq (unsigned int gsi)
   5.187 +{
   5.188 +	unsigned long flags;
   5.189 +	int irq;
   5.190 +	/*
   5.191 +	 * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq
   5.192 +	 * numbers...
   5.193 +	 */
   5.194 +	spin_lock_irqsave(&iosapic_lock, flags);
   5.195 +	{
   5.196 +		irq = _gsi_to_vector(gsi);
   5.197 +	}
   5.198 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   5.199 +
   5.200 +	return irq;
   5.201 +}
   5.202 +
   5.203 +static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec)
   5.204 +{
   5.205 +	struct iosapic_rte_info *rte;
   5.206 +
   5.207 +	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
   5.208 +		if (rte->gsi_base + rte->rte_index == gsi)
   5.209 +			return rte;
   5.210 +	return NULL;
   5.211 +}
   5.212 +
   5.213 +static void
   5.214 +set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
   5.215 +{
   5.216 +	unsigned long pol, trigger, dmode;
   5.217 +	u32 low32, high32;
   5.218 +	char __iomem *addr;
   5.219 +	int rte_index;
   5.220 +	char redir;
   5.221 +	struct iosapic_rte_info *rte;
   5.222 +
   5.223 +	DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
   5.224 +
   5.225 +	rte = gsi_vector_to_rte(gsi, vector);
   5.226 +	if (!rte)
   5.227 +		return;		/* not an IOSAPIC interrupt */
   5.228 +
   5.229 +	rte_index = rte->rte_index;
   5.230 +	addr	= rte->addr;
   5.231 +	pol     = iosapic_intr_info[vector].polarity;
   5.232 +	trigger = iosapic_intr_info[vector].trigger;
   5.233 +	dmode   = iosapic_intr_info[vector].dmode;
   5.234 +
   5.235 +	redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
   5.236 +
   5.237 +#ifdef CONFIG_SMP
   5.238 +	{
   5.239 +		unsigned int irq;
   5.240 +
   5.241 +		for (irq = 0; irq < NR_IRQS; ++irq)
   5.242 +			if (irq_to_vector(irq) == vector) {
   5.243 +				set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
   5.244 +				break;
   5.245 +			}
   5.246 +	}
   5.247 +#endif
   5.248 +
   5.249 +	low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
   5.250 +		 (trigger << IOSAPIC_TRIGGER_SHIFT) |
   5.251 +		 (dmode << IOSAPIC_DELIVERY_SHIFT) |
   5.252 +		 ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
   5.253 +		 vector);
   5.254 +
   5.255 +	/* dest contains both id and eid */
   5.256 +	high32 = (dest << IOSAPIC_DEST_SHIFT);
   5.257 +
   5.258 +	iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
   5.259 +	iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   5.260 +	iosapic_intr_info[vector].low32 = low32;
   5.261 +	iosapic_intr_info[vector].dest = dest;
   5.262 +}
   5.263 +
   5.264 +static void
   5.265 +nop (unsigned int vector)
   5.266 +{
   5.267 +	/* do nothing... */
   5.268 +}
   5.269 +
   5.270 +static void
   5.271 +mask_irq (unsigned int irq)
   5.272 +{
   5.273 +	unsigned long flags;
   5.274 +	char __iomem *addr;
   5.275 +	u32 low32;
   5.276 +	int rte_index;
   5.277 +	ia64_vector vec = irq_to_vector(irq);
   5.278 +	struct iosapic_rte_info *rte;
   5.279 +
   5.280 +	if (list_empty(&iosapic_intr_info[vec].rtes))
   5.281 +		return;			/* not an IOSAPIC interrupt! */
   5.282 +
   5.283 +	spin_lock_irqsave(&iosapic_lock, flags);
   5.284 +	{
   5.285 +		/* set only the mask bit */
   5.286 +		low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
   5.287 +		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
   5.288 +			addr = rte->addr;
   5.289 +			rte_index = rte->rte_index;
   5.290 +			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   5.291 +		}
   5.292 +	}
   5.293 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   5.294 +}
   5.295 +
   5.296 +static void
   5.297 +unmask_irq (unsigned int irq)
   5.298 +{
   5.299 +	unsigned long flags;
   5.300 +	char __iomem *addr;
   5.301 +	u32 low32;
   5.302 +	int rte_index;
   5.303 +	ia64_vector vec = irq_to_vector(irq);
   5.304 +	struct iosapic_rte_info *rte;
   5.305 +
   5.306 +	if (list_empty(&iosapic_intr_info[vec].rtes))
   5.307 +		return;			/* not an IOSAPIC interrupt! */
   5.308 +
   5.309 +	spin_lock_irqsave(&iosapic_lock, flags);
   5.310 +	{
   5.311 +		low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
   5.312 +		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
   5.313 +			addr = rte->addr;
   5.314 +			rte_index = rte->rte_index;
   5.315 +			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   5.316 +		}
   5.317 +	}
   5.318 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   5.319 +}
   5.320 +
   5.321 +
   5.322 +static void
   5.323 +iosapic_set_affinity (unsigned int irq, cpumask_t mask)
   5.324 +{
   5.325 +#ifdef CONFIG_SMP
   5.326 +	unsigned long flags;
   5.327 +	u32 high32, low32;
   5.328 +	int dest, rte_index;
   5.329 +	char __iomem *addr;
   5.330 +	int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
   5.331 +	ia64_vector vec;
   5.332 +	struct iosapic_rte_info *rte;
   5.333 +
   5.334 +	irq &= (~IA64_IRQ_REDIRECTED);
   5.335 +	vec = irq_to_vector(irq);
   5.336 +
   5.337 +	if (cpus_empty(mask))
   5.338 +		return;
   5.339 +
   5.340 +	dest = cpu_physical_id(first_cpu(mask));
   5.341 +
   5.342 +	if (list_empty(&iosapic_intr_info[vec].rtes))
   5.343 +		return;			/* not an IOSAPIC interrupt */
   5.344 +
   5.345 +	set_irq_affinity_info(irq, dest, redir);
   5.346 +
   5.347 +	/* dest contains both id and eid */
   5.348 +	high32 = dest << IOSAPIC_DEST_SHIFT;
   5.349 +
   5.350 +	spin_lock_irqsave(&iosapic_lock, flags);
   5.351 +	{
   5.352 +		low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
   5.353 +
   5.354 +		if (redir)
   5.355 +		        /* change delivery mode to lowest priority */
   5.356 +			low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
   5.357 +		else
   5.358 +		        /* change delivery mode to fixed */
   5.359 +			low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
   5.360 +
   5.361 +		iosapic_intr_info[vec].low32 = low32;
   5.362 +		iosapic_intr_info[vec].dest = dest;
   5.363 +		list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) {
   5.364 +			addr = rte->addr;
   5.365 +			rte_index = rte->rte_index;
   5.366 +			iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
   5.367 +			iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
   5.368 +		}
   5.369 +	}
   5.370 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   5.371 +#endif
   5.372 +}
   5.373 +
   5.374 +/*
   5.375 + * Handlers for level-triggered interrupts.
   5.376 + */
   5.377 +
   5.378 +static unsigned int
   5.379 +iosapic_startup_level_irq (unsigned int irq)
   5.380 +{
   5.381 +	unmask_irq(irq);
   5.382 +	return 0;
   5.383 +}
   5.384 +
   5.385 +static void
   5.386 +iosapic_end_level_irq (unsigned int irq)
   5.387 +{
   5.388 +	ia64_vector vec = irq_to_vector(irq);
   5.389 +	struct iosapic_rte_info *rte;
   5.390 +
   5.391 +	move_irq(irq);
   5.392 +	list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
   5.393 +		iosapic_eoi(rte->addr, vec);
   5.394 +}
   5.395 +
   5.396 +#define iosapic_shutdown_level_irq	mask_irq
   5.397 +#define iosapic_enable_level_irq	unmask_irq
   5.398 +#define iosapic_disable_level_irq	mask_irq
   5.399 +#define iosapic_ack_level_irq		nop
   5.400 +
   5.401 +struct hw_interrupt_type irq_type_iosapic_level = {
   5.402 +	.typename =	"IO-SAPIC-level",
   5.403 +	.startup =	iosapic_startup_level_irq,
   5.404 +	.shutdown =	iosapic_shutdown_level_irq,
   5.405 +	.enable =	iosapic_enable_level_irq,
   5.406 +	.disable =	iosapic_disable_level_irq,
   5.407 +	.ack =		iosapic_ack_level_irq,
   5.408 +	.end =		iosapic_end_level_irq,
   5.409 +	.set_affinity =	iosapic_set_affinity
   5.410 +};
   5.411 +
   5.412 +/*
   5.413 + * Handlers for edge-triggered interrupts.
   5.414 + */
   5.415 +
   5.416 +static unsigned int
   5.417 +iosapic_startup_edge_irq (unsigned int irq)
   5.418 +{
   5.419 +	unmask_irq(irq);
   5.420 +	/*
   5.421 +	 * IOSAPIC simply drops interrupts pended while the
   5.422 +	 * corresponding pin was masked, so we can't know if an
   5.423 +	 * interrupt is pending already.  Let's hope not...
   5.424 +	 */
   5.425 +	return 0;
   5.426 +}
   5.427 +
   5.428 +static void
   5.429 +iosapic_ack_edge_irq (unsigned int irq)
   5.430 +{
   5.431 +	irq_desc_t *idesc = irq_descp(irq);
   5.432 +
   5.433 +	move_irq(irq);
   5.434 +	/*
   5.435 +	 * Once we have recorded IRQ_PENDING already, we can mask the
   5.436 +	 * interrupt for real. This prevents IRQ storms from unhandled
   5.437 +	 * devices.
   5.438 +	 */
   5.439 +	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))
   5.440 +		mask_irq(irq);
   5.441 +}
   5.442 +
   5.443 +#define iosapic_enable_edge_irq		unmask_irq
   5.444 +#define iosapic_disable_edge_irq	nop
   5.445 +#define iosapic_end_edge_irq		nop
   5.446 +
   5.447 +struct hw_interrupt_type irq_type_iosapic_edge = {
   5.448 +	.typename =	"IO-SAPIC-edge",
   5.449 +	.startup =	iosapic_startup_edge_irq,
   5.450 +	.shutdown =	iosapic_disable_edge_irq,
   5.451 +	.enable =	iosapic_enable_edge_irq,
   5.452 +	.disable =	iosapic_disable_edge_irq,
   5.453 +	.ack =		iosapic_ack_edge_irq,
   5.454 +	.end =		iosapic_end_edge_irq,
   5.455 +	.set_affinity =	iosapic_set_affinity
   5.456 +};
   5.457 +
   5.458 +unsigned int
   5.459 +iosapic_version (char __iomem *addr)
   5.460 +{
   5.461 +	/*
   5.462 +	 * IOSAPIC Version Register return 32 bit structure like:
   5.463 +	 * {
   5.464 +	 *	unsigned int version   : 8;
   5.465 +	 *	unsigned int reserved1 : 8;
   5.466 +	 *	unsigned int max_redir : 8;
   5.467 +	 *	unsigned int reserved2 : 8;
   5.468 +	 * }
   5.469 +	 */
   5.470 +	return iosapic_read(addr, IOSAPIC_VERSION);
   5.471 +}
   5.472 +
   5.473 +static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol)
   5.474 +{
   5.475 +	int i, vector = -1, min_count = -1;
   5.476 +	struct iosapic_intr_info *info;
   5.477 +
   5.478 +	/*
   5.479 +	 * shared vectors for edge-triggered interrupts are not
   5.480 +	 * supported yet
   5.481 +	 */
   5.482 +	if (trigger == IOSAPIC_EDGE)
   5.483 +		return -1;
   5.484 +
   5.485 +	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
   5.486 +		info = &iosapic_intr_info[i];
   5.487 +		if (info->trigger == trigger && info->polarity == pol &&
   5.488 +		    (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {
   5.489 +			if (min_count == -1 || info->count < min_count) {
   5.490 +				vector = i;
   5.491 +				min_count = info->count;
   5.492 +			}
   5.493 +		}
   5.494 +	}
   5.495 +
   5.496 +	return vector;
   5.497 +}
   5.498 +
   5.499 +/*
   5.500 + * if the given vector is already owned by other,
   5.501 + *  assign a new vector for the other and make the vector available
   5.502 + */
   5.503 +static void __init
   5.504 +iosapic_reassign_vector (int vector)
   5.505 +{
   5.506 +	int new_vector;
   5.507 +
   5.508 +	if (!list_empty(&iosapic_intr_info[vector].rtes)) {
   5.509 +		new_vector = assign_irq_vector(AUTO_ASSIGN);
   5.510 +		if (new_vector < 0)
   5.511 +			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
   5.512 +		printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
   5.513 +		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
   5.514 +		       sizeof(struct iosapic_intr_info));
   5.515 +		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
   5.516 +		list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);
   5.517 +		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
   5.518 +		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
   5.519 +		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
   5.520 +	}
   5.521 +}
   5.522 +
   5.523 +static struct iosapic_rte_info *iosapic_alloc_rte (void)
   5.524 +{
   5.525 +	int i;
   5.526 +	struct iosapic_rte_info *rte;
   5.527 +	int preallocated = 0;
   5.528 +
   5.529 +	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
   5.530 +		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);
   5.531 +		if (!rte)
   5.532 +			return NULL;
   5.533 +		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
   5.534 +			list_add(&rte->rte_list, &free_rte_list);
   5.535 +	}
   5.536 +
   5.537 +	if (!list_empty(&free_rte_list)) {
   5.538 +		rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);
   5.539 +		list_del(&rte->rte_list);
   5.540 +		preallocated++;
   5.541 +	} else {
   5.542 +		rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
   5.543 +		if (!rte)
   5.544 +			return NULL;
   5.545 +	}
   5.546 +
   5.547 +	memset(rte, 0, sizeof(struct iosapic_rte_info));
   5.548 +	if (preallocated)
   5.549 +		rte->flags |= RTE_PREALLOCATED;
   5.550 +
   5.551 +	return rte;
   5.552 +}
   5.553 +
   5.554 +static void iosapic_free_rte (struct iosapic_rte_info *rte)
   5.555 +{
   5.556 +	if (rte->flags & RTE_PREALLOCATED)
   5.557 +		list_add_tail(&rte->rte_list, &free_rte_list);
   5.558 +	else
   5.559 +		kfree(rte);
   5.560 +}
   5.561 +
   5.562 +static inline int vector_is_shared (int vector)
   5.563 +{
   5.564 +	return (iosapic_intr_info[vector].count > 1);
   5.565 +}
   5.566 +
   5.567 +static int
   5.568 +register_intr (unsigned int gsi, int vector, unsigned char delivery,
   5.569 +	       unsigned long polarity, unsigned long trigger)
   5.570 +{
   5.571 +	irq_desc_t *idesc;
   5.572 +	struct hw_interrupt_type *irq_type;
   5.573 +	int rte_index;
   5.574 +	int index;
   5.575 +	unsigned long gsi_base;
   5.576 +	void __iomem *iosapic_address;
   5.577 +	struct iosapic_rte_info *rte;
   5.578 +
   5.579 +	index = find_iosapic(gsi);
   5.580 +	if (index < 0) {
   5.581 +		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
   5.582 +		return -ENODEV;
   5.583 +	}
   5.584 +
   5.585 +	iosapic_address = iosapic_lists[index].addr;
   5.586 +	gsi_base = iosapic_lists[index].gsi_base;
   5.587 +
   5.588 +	rte = gsi_vector_to_rte(gsi, vector);
   5.589 +	if (!rte) {
   5.590 +		rte = iosapic_alloc_rte();
   5.591 +		if (!rte) {
   5.592 +			printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
   5.593 +			return -ENOMEM;
   5.594 +		}
   5.595 +
   5.596 +		rte_index = gsi - gsi_base;
   5.597 +		rte->rte_index	= rte_index;
   5.598 +		rte->addr	= iosapic_address;
   5.599 +		rte->gsi_base	= gsi_base;
   5.600 +		rte->refcnt++;
   5.601 +		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
   5.602 +		iosapic_intr_info[vector].count++;
   5.603 +		iosapic_lists[index].rtes_inuse++;
   5.604 +	}
   5.605 +	else if (vector_is_shared(vector)) {
   5.606 +		struct iosapic_intr_info *info = &iosapic_intr_info[vector];
   5.607 +		if (info->trigger != trigger || info->polarity != polarity) {
   5.608 +			printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
   5.609 +			return -EINVAL;
   5.610 +		}
   5.611 +	}
   5.612 +
   5.613 +	iosapic_intr_info[vector].polarity = polarity;
   5.614 +	iosapic_intr_info[vector].dmode    = delivery;
   5.615 +	iosapic_intr_info[vector].trigger  = trigger;
   5.616 +
   5.617 +	if (trigger == IOSAPIC_EDGE)
   5.618 +		irq_type = &irq_type_iosapic_edge;
   5.619 +	else
   5.620 +		irq_type = &irq_type_iosapic_level;
   5.621 +
   5.622 +	idesc = irq_descp(vector);
   5.623 +	if (idesc->handler != irq_type) {
   5.624 +		if (idesc->handler != &no_irq_type)
   5.625 +			printk(KERN_WARNING "%s: changing vector %d from %s to %s\n",
   5.626 +			       __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);
   5.627 +		idesc->handler = irq_type;
   5.628 +	}
   5.629 +	return 0;
   5.630 +}
   5.631 +
   5.632 +static unsigned int
   5.633 +get_target_cpu (unsigned int gsi, int vector)
   5.634 +{
   5.635 +#ifdef CONFIG_SMP
   5.636 +	static int cpu = -1;
   5.637 +
   5.638 +	/*
   5.639 +	 * In case of vector shared by multiple RTEs, all RTEs that
   5.640 +	 * share the vector need to use the same destination CPU.
   5.641 +	 */
   5.642 +	if (!list_empty(&iosapic_intr_info[vector].rtes))
   5.643 +		return iosapic_intr_info[vector].dest;
   5.644 +
   5.645 +	/*
   5.646 +	 * If the platform supports redirection via XTP, let it
   5.647 +	 * distribute interrupts.
   5.648 +	 */
   5.649 +	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
   5.650 +		return cpu_physical_id(smp_processor_id());
   5.651 +
   5.652 +	/*
   5.653 +	 * Some interrupts (ACPI SCI, for instance) are registered
   5.654 +	 * before the BSP is marked as online.
   5.655 +	 */
   5.656 +	if (!cpu_online(smp_processor_id()))
   5.657 +		return cpu_physical_id(smp_processor_id());
   5.658 +
   5.659 +#ifdef CONFIG_NUMA
   5.660 +	{
   5.661 +		int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0;
   5.662 +		cpumask_t cpu_mask;
   5.663 +
   5.664 +		iosapic_index = find_iosapic(gsi);
   5.665 +		if (iosapic_index < 0 ||
   5.666 +		    iosapic_lists[iosapic_index].node == MAX_NUMNODES)
   5.667 +			goto skip_numa_setup;
   5.668 +
   5.669 +		cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);
   5.670 +
   5.671 +		for_each_cpu_mask(numa_cpu, cpu_mask) {
   5.672 +			if (!cpu_online(numa_cpu))
   5.673 +				cpu_clear(numa_cpu, cpu_mask);
   5.674 +		}
   5.675 +
   5.676 +		num_cpus = cpus_weight(cpu_mask);
   5.677 +
   5.678 +		if (!num_cpus)
   5.679 +			goto skip_numa_setup;
   5.680 +
   5.681 +		/* Use vector assigment to distribute across cpus in node */
   5.682 +		cpu_index = vector % num_cpus;
   5.683 +
   5.684 +		for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
   5.685 +			numa_cpu = next_cpu(numa_cpu, cpu_mask);
   5.686 +
   5.687 +		if (numa_cpu != NR_CPUS)
   5.688 +			return cpu_physical_id(numa_cpu);
   5.689 +	}
   5.690 +skip_numa_setup:
   5.691 +#endif
   5.692 +	/*
   5.693 +	 * Otherwise, round-robin interrupt vectors across all the
   5.694 +	 * processors.  (It'd be nice if we could be smarter in the
   5.695 +	 * case of NUMA.)
   5.696 +	 */
   5.697 +	do {
   5.698 +		if (++cpu >= NR_CPUS)
   5.699 +			cpu = 0;
   5.700 +	} while (!cpu_online(cpu));
   5.701 +
   5.702 +	return cpu_physical_id(cpu);
   5.703 +#else
   5.704 +	return cpu_physical_id(smp_processor_id());
   5.705 +#endif
   5.706 +}
   5.707 +
   5.708 +/*
   5.709 + * ACPI can describe IOSAPIC interrupts via static tables and namespace
   5.710 + * methods.  This provides an interface to register those interrupts and
   5.711 + * program the IOSAPIC RTE.
   5.712 + */
   5.713 +int
   5.714 +iosapic_register_intr (unsigned int gsi,
   5.715 +		       unsigned long polarity, unsigned long trigger)
   5.716 +{
   5.717 +	int vector, mask = 1, err;
   5.718 +	unsigned int dest;
   5.719 +	unsigned long flags;
   5.720 +	struct iosapic_rte_info *rte;
   5.721 +	u32 low32;
   5.722 +again:
   5.723 +	/*
   5.724 +	 * If this GSI has already been registered (i.e., it's a
   5.725 +	 * shared interrupt, or we lost a race to register it),
   5.726 +	 * don't touch the RTE.
   5.727 +	 */
   5.728 +	spin_lock_irqsave(&iosapic_lock, flags);
   5.729 +	{
   5.730 +		vector = gsi_to_vector(gsi);
   5.731 +		if (vector > 0) {
   5.732 +			rte = gsi_vector_to_rte(gsi, vector);
   5.733 +			rte->refcnt++;
   5.734 +			spin_unlock_irqrestore(&iosapic_lock, flags);
   5.735 +			return vector;
   5.736 +		}
   5.737 +	}
   5.738 +	spin_unlock_irqrestore(&iosapic_lock, flags);
   5.739 +
   5.740 +	/* If vector is running out, we try to find a sharable vector */
   5.741 +	vector = assign_irq_vector(AUTO_ASSIGN);
   5.742 +	if (vector < 0) {
   5.743 +		vector = iosapic_find_sharable_vector(trigger, polarity);
   5.744 +  		if (vector < 0)
   5.745 +			return -ENOSPC;
   5.746 +	}
   5.747 +
   5.748 +	spin_lock_irqsave(&irq_descp(vector)->lock, flags);
   5.749 +	spin_lock(&iosapic_lock);
   5.750 +	{
   5.751 +		if (gsi_to_vector(gsi) > 0) {
   5.752 +			if (list_empty(&iosapic_intr_info[vector].rtes))
   5.753 +				free_irq_vector(vector);
   5.754 +			spin_unlock(&iosapic_lock);
   5.755 +			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
   5.756 +			goto again;
   5.757 +		}
   5.758 +
   5.759 +		dest = get_target_cpu(gsi, vector);
   5.760 +		err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
   5.761 +			      polarity, trigger);
   5.762 +		if (err < 0) {
   5.763 +			spin_unlock(&iosapic_lock);
   5.764 +			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
   5.765 +			return err;
   5.766 +		}
   5.767 +
   5.768 +		/*
   5.769 +		 * If the vector is shared and already unmasked for
   5.770 +		 * other interrupt sources, don't mask it.
   5.771 +		 */
   5.772 +		low32 = iosapic_intr_info[vector].low32;
   5.773 +		if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
   5.774 +			mask = 0;
   5.775 +		set_rte(gsi, vector, dest, mask);
   5.776 +	}
   5.777 +	spin_unlock(&iosapic_lock);
   5.778 +	spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
   5.779 +
   5.780 +	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
   5.781 +	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
   5.782 +	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
   5.783 +	       cpu_logical_id(dest), dest, vector);
   5.784 +
   5.785 +	return vector;
   5.786 +}
   5.787 +
   5.788 +void
   5.789 +iosapic_unregister_intr (unsigned int gsi)
   5.790 +{
   5.791 +	unsigned long flags;
   5.792 +	int irq, vector, index;
   5.793 +	irq_desc_t *idesc;
   5.794 +	u32 low32;
   5.795 +	unsigned long trigger, polarity;
   5.796 +	unsigned int dest;
   5.797 +	struct iosapic_rte_info *rte;
   5.798 +
   5.799 +	/*
   5.800 +	 * If the irq associated with the gsi is not found,
   5.801 +	 * iosapic_unregister_intr() is unbalanced. We need to check
   5.802 +	 * this again after getting locks.
   5.803 +	 */
   5.804 +	irq = gsi_to_irq(gsi);
   5.805 +	if (irq < 0) {
   5.806 +		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
   5.807 +		WARN_ON(1);
   5.808 +		return;
   5.809 +	}
   5.810 +	vector = irq_to_vector(irq);
   5.811 +
   5.812 +	idesc = irq_descp(irq);
   5.813 +	spin_lock_irqsave(&idesc->lock, flags);
   5.814 +	spin_lock(&iosapic_lock);
   5.815 +	{
   5.816 +		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
   5.817 +			printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
   5.818 +			WARN_ON(1);
   5.819 +			goto out;
   5.820 +		}
   5.821 +
   5.822 +		if (--rte->refcnt > 0)
   5.823 +			goto out;
   5.824 +
   5.825 +		/* Mask the interrupt */
   5.826 +		low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
   5.827 +		iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32);
   5.828 +
   5.829 +		/* Remove the rte entry from the list */
   5.830 +		list_del(&rte->rte_list);
   5.831 +		iosapic_intr_info[vector].count--;
   5.832 +		iosapic_free_rte(rte);
   5.833 +		index = find_iosapic(gsi);
   5.834 +		iosapic_lists[index].rtes_inuse--;
   5.835 +		WARN_ON(iosapic_lists[index].rtes_inuse < 0);
   5.836 +
   5.837 +		trigger	 = iosapic_intr_info[vector].trigger;
   5.838 +		polarity = iosapic_intr_info[vector].polarity;
   5.839 +		dest     = iosapic_intr_info[vector].dest;
   5.840 +		printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
   5.841 +		       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
   5.842 +		       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
   5.843 +		       cpu_logical_id(dest), dest, vector);
   5.844 +
   5.845 +		if (list_empty(&iosapic_intr_info[vector].rtes)) {
   5.846 +			/* Sanity check */
   5.847 +			BUG_ON(iosapic_intr_info[vector].count);
   5.848 +
   5.849 +			/* Clear the interrupt controller descriptor */
   5.850 +			idesc->handler = &no_irq_type;
   5.851 +
   5.852 +			/* Clear the interrupt information */
   5.853 +			memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
   5.854 +			iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
   5.855 +			INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
   5.856 +
   5.857 +			if (idesc->action) {
   5.858 +				printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq);
   5.859 +				WARN_ON(1);
   5.860 +			}
   5.861 +
   5.862 +			/* Free the interrupt vector */
   5.863 +			free_irq_vector(vector);
   5.864 +		}
   5.865 +	}
   5.866 + out:
   5.867 +	spin_unlock(&iosapic_lock);
   5.868 +	spin_unlock_irqrestore(&idesc->lock, flags);
   5.869 +}
   5.870 +
   5.871 +/*
   5.872 + * ACPI calls this when it finds an entry for a platform interrupt.
   5.873 + * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
   5.874 + */
   5.875 +int __init
   5.876 +iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
   5.877 +				int iosapic_vector, u16 eid, u16 id,
   5.878 +				unsigned long polarity, unsigned long trigger)
   5.879 +{
   5.880 +	static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
   5.881 +	unsigned char delivery;
   5.882 +	int vector, mask = 0;
   5.883 +	unsigned int dest = ((id << 8) | eid) & 0xffff;
   5.884 +
   5.885 +	switch (int_type) {
   5.886 +	      case ACPI_INTERRUPT_PMI:
   5.887 +		vector = iosapic_vector;
   5.888 +		/*
   5.889 +		 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
   5.890 +		 * we need to make sure the vector is available
   5.891 +		 */
   5.892 +		iosapic_reassign_vector(vector);
   5.893 +		delivery = IOSAPIC_PMI;
   5.894 +		break;
   5.895 +	      case ACPI_INTERRUPT_INIT:
   5.896 +		vector = assign_irq_vector(AUTO_ASSIGN);
   5.897 +		if (vector < 0)
   5.898 +			panic("%s: out of interrupt vectors!\n", __FUNCTION__);
   5.899 +		delivery = IOSAPIC_INIT;
   5.900 +		break;
   5.901 +	      case ACPI_INTERRUPT_CPEI:
   5.902 +		vector = IA64_CPE_VECTOR;
   5.903 +		delivery = IOSAPIC_LOWEST_PRIORITY;
   5.904 +		mask = 1;
   5.905 +		break;
   5.906 +	      default:
   5.907 +		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
   5.908 +		return -1;
   5.909 +	}
   5.910 +
   5.911 +	register_intr(gsi, vector, delivery, polarity, trigger);
   5.912 +
   5.913 +	printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
   5.914 +	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
   5.915 +	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
   5.916 +	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
   5.917 +	       cpu_logical_id(dest), dest, vector);
   5.918 +
   5.919 +	set_rte(gsi, vector, dest, mask);
   5.920 +	return vector;
   5.921 +}
   5.922 +
   5.923 +
   5.924 +/*
   5.925 + * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
   5.926 + * Note that the gsi_base and IOSAPIC address must be set in iosapic_init().
   5.927 + */
   5.928 +void __init
   5.929 +iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
   5.930 +			  unsigned long polarity,
   5.931 +			  unsigned long trigger)
   5.932 +{
   5.933 +	int vector;
   5.934 +	unsigned int dest = cpu_physical_id(smp_processor_id());
   5.935 +
   5.936 +	vector = isa_irq_to_vector(isa_irq);
   5.937 +
   5.938 +	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
   5.939 +
   5.940 +	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
   5.941 +	    isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
   5.942 +	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",
   5.943 +	    cpu_logical_id(dest), dest, vector);
   5.944 +
   5.945 +	set_rte(gsi, vector, dest, 1);
   5.946 +}
   5.947 +
   5.948 +void __init
   5.949 +iosapic_system_init (int system_pcat_compat)
   5.950 +{
   5.951 +	int vector;
   5.952 +
   5.953 +	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
   5.954 +		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
   5.955 +		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);	/* mark as unused */
   5.956 +	}
   5.957 +
   5.958 +	pcat_compat = system_pcat_compat;
   5.959 +	if (pcat_compat) {
   5.960 +		/*
   5.961 +		 * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
   5.962 +		 * enabled.
   5.963 +		 */
   5.964 +		printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
   5.965 +		outb(0xff, 0xA1);
   5.966 +		outb(0xff, 0x21);
   5.967 +	}
   5.968 +}
   5.969 +
   5.970 +static inline int
   5.971 +iosapic_alloc (void)
   5.972 +{
   5.973 +	int index;
   5.974 +
   5.975 +	for (index = 0; index < NR_IOSAPICS; index++)
   5.976 +		if (!iosapic_lists[index].addr)
   5.977 +			return index;
   5.978 +
   5.979 +	printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
   5.980 +	return -1;
   5.981 +}
   5.982 +
   5.983 +static inline void
   5.984 +iosapic_free (int index)
   5.985 +{
   5.986 +	memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
   5.987 +}
   5.988 +
   5.989 +static inline int
   5.990 +iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
   5.991 +{
   5.992 +	int index;
   5.993 +	unsigned int gsi_end, base, end;
   5.994 +
   5.995 +	/* check gsi range */
   5.996 +	gsi_end = gsi_base + ((ver >> 16) & 0xff);
   5.997 +	for (index = 0; index < NR_IOSAPICS; index++) {
   5.998 +		if (!iosapic_lists[index].addr)
   5.999 +			continue;
  5.1000 +
  5.1001 +		base = iosapic_lists[index].gsi_base;
  5.1002 +		end  = base + iosapic_lists[index].num_rte - 1;
  5.1003 +
  5.1004 +		if (gsi_base < base && gsi_end < base)
  5.1005 +			continue;/* OK */
  5.1006 +
  5.1007 +		if (gsi_base > end && gsi_end > end)
  5.1008 +			continue; /* OK */
  5.1009 +
  5.1010 +		return -EBUSY;
  5.1011 +	}
  5.1012 +	return 0;
  5.1013 +}
  5.1014 +
  5.1015 +int __devinit
  5.1016 +iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
  5.1017 +{
  5.1018 +	int num_rte, err, index;
  5.1019 +	unsigned int isa_irq, ver;
  5.1020 +	char __iomem *addr;
  5.1021 +	unsigned long flags;
  5.1022 +
  5.1023 +	spin_lock_irqsave(&iosapic_lock, flags);
  5.1024 +	{
  5.1025 +		addr = ioremap(phys_addr, 0);
  5.1026 +		ver = iosapic_version(addr);
  5.1027 +
  5.1028 +		if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
  5.1029 +			iounmap(addr);
  5.1030 +			spin_unlock_irqrestore(&iosapic_lock, flags);
  5.1031 +			return err;
  5.1032 +		}
  5.1033 +
  5.1034 +		/*
  5.1035 +		 * The MAX_REDIR register holds the highest input pin
  5.1036 +		 * number (starting from 0).
  5.1037 +		 * We add 1 so that we can use it for number of pins (= RTEs)
  5.1038 +		 */
  5.1039 +		num_rte = ((ver >> 16) & 0xff) + 1;
  5.1040 +
  5.1041 +		index = iosapic_alloc();
  5.1042 +		iosapic_lists[index].addr = addr;
  5.1043 +		iosapic_lists[index].gsi_base = gsi_base;
  5.1044 +		iosapic_lists[index].num_rte = num_rte;
  5.1045 +#ifdef CONFIG_NUMA
  5.1046 +		iosapic_lists[index].node = MAX_NUMNODES;
  5.1047 +#endif
  5.1048 +	}
  5.1049 +	spin_unlock_irqrestore(&iosapic_lock, flags);
  5.1050 +
  5.1051 +	if ((gsi_base == 0) && pcat_compat) {
  5.1052 +		/*
  5.1053 +		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
  5.1054 +		 * get reprogrammed later on with data from the ACPI Interrupt Source
  5.1055 +		 * Override table.
  5.1056 +		 */
  5.1057 +		for (isa_irq = 0; isa_irq < 16; ++isa_irq)
  5.1058 +			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
  5.1059 +	}
  5.1060 +	return 0;
  5.1061 +}
  5.1062 +
  5.1063 +#ifdef CONFIG_HOTPLUG
  5.1064 +int
  5.1065 +iosapic_remove (unsigned int gsi_base)
  5.1066 +{
  5.1067 +	int index, err = 0;
  5.1068 +	unsigned long flags;
  5.1069 +
  5.1070 +	spin_lock_irqsave(&iosapic_lock, flags);
  5.1071 +	{
  5.1072 +		index = find_iosapic(gsi_base);
  5.1073 +		if (index < 0) {
  5.1074 +			printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
  5.1075 +			       __FUNCTION__, gsi_base);
  5.1076 +			goto out;
  5.1077 +		}
  5.1078 +
  5.1079 +		if (iosapic_lists[index].rtes_inuse) {
  5.1080 +			err = -EBUSY;
  5.1081 +			printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
  5.1082 +			       __FUNCTION__, gsi_base);
  5.1083 +			goto out;
  5.1084 +		}
  5.1085 +
  5.1086 +		iounmap(iosapic_lists[index].addr);
  5.1087 +		iosapic_free(index);
  5.1088 +	}
  5.1089 + out:
  5.1090 +	spin_unlock_irqrestore(&iosapic_lock, flags);
  5.1091 +	return err;
  5.1092 +}
  5.1093 +#endif /* CONFIG_HOTPLUG */
  5.1094 +
  5.1095 +#ifdef CONFIG_NUMA
  5.1096 +void __devinit
  5.1097 +map_iosapic_to_node(unsigned int gsi_base, int node)
  5.1098 +{
  5.1099 +	int index;
  5.1100 +
  5.1101 +	index = find_iosapic(gsi_base);
  5.1102 +	if (index < 0) {
  5.1103 +		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",
  5.1104 +		       __FUNCTION__, gsi_base);
  5.1105 +		return;
  5.1106 +	}
  5.1107 +	iosapic_lists[index].node = node;
  5.1108 +	return;
  5.1109 +}
  5.1110 +#endif
  5.1111 +
  5.1112 +static int __init iosapic_enable_kmalloc (void)
  5.1113 +{
  5.1114 +	iosapic_kmalloc_ok = 1;
  5.1115 +	return 0;
  5.1116 +}
  5.1117 +core_initcall (iosapic_enable_kmalloc);
     6.1 --- a/xen/include/asm-ia64/linux-xen/asm/README.origin	Wed Apr 19 10:39:15 2006 -0600
     6.2 +++ b/xen/include/asm-ia64/linux-xen/asm/README.origin	Fri Apr 21 08:56:24 2006 -0600
     6.3 @@ -5,7 +5,7 @@
     6.4  # (e.g. with #ifdef XEN or XEN in a comment) so that they can be
     6.5  # easily updated to future versions of the corresponding Linux files.
     6.6  
     6.7 -cache.h		-> linux/include/asm-ia64/cache.h
     6.8 +cache.h			-> linux/include/asm-ia64/cache.h
     6.9  gcc_intrin.h		-> linux/include/asm-ia64/gcc_intrin.h
    6.10  ia64regs.h		-> linux/include/asm-ia64/ia64regs.h
    6.11  io.h			-> linux/include/asm-ia64/io.h
    6.12 @@ -22,3 +22,6 @@ spinlock.h		-> linux/include/asm-ia64/sp
    6.13  system.h		-> linux/include/asm-ia64/system.h
    6.14  tlbflush.h		-> linux/include/asm-ia64/tlbflush.h
    6.15  types.h			-> linux/include/asm-ia64/types.h
    6.16 +
    6.17 +# The files below are from Linux-2.6.16
    6.18 +iosapic.h		-> linux/include/asm-ia64/iosapic.h
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/xen/include/asm-ia64/linux-xen/asm/iosapic.h	Fri Apr 21 08:56:24 2006 -0600
     7.3 @@ -0,0 +1,112 @@
     7.4 +#ifndef __ASM_IA64_IOSAPIC_H
     7.5 +#define __ASM_IA64_IOSAPIC_H
     7.6 +
     7.7 +#define	IOSAPIC_REG_SELECT	0x0
     7.8 +#define	IOSAPIC_WINDOW		0x10
     7.9 +#define	IOSAPIC_EOI		0x40
    7.10 +
    7.11 +#define	IOSAPIC_VERSION		0x1
    7.12 +
    7.13 +/*
    7.14 + * Redirection table entry
    7.15 + */
    7.16 +#define	IOSAPIC_RTE_LOW(i)	(0x10+i*2)
    7.17 +#define	IOSAPIC_RTE_HIGH(i)	(0x11+i*2)
    7.18 +
    7.19 +#define	IOSAPIC_DEST_SHIFT		16
    7.20 +
    7.21 +/*
    7.22 + * Delivery mode
    7.23 + */
    7.24 +#define	IOSAPIC_DELIVERY_SHIFT		8
    7.25 +#define	IOSAPIC_FIXED			0x0
    7.26 +#define	IOSAPIC_LOWEST_PRIORITY	0x1
    7.27 +#define	IOSAPIC_PMI			0x2
    7.28 +#define	IOSAPIC_NMI			0x4
    7.29 +#define	IOSAPIC_INIT			0x5
    7.30 +#define	IOSAPIC_EXTINT			0x7
    7.31 +
    7.32 +/*
    7.33 + * Interrupt polarity
    7.34 + */
    7.35 +#define	IOSAPIC_POLARITY_SHIFT		13
    7.36 +#define	IOSAPIC_POL_HIGH		0
    7.37 +#define	IOSAPIC_POL_LOW		1
    7.38 +
    7.39 +/*
    7.40 + * Trigger mode
    7.41 + */
    7.42 +#define	IOSAPIC_TRIGGER_SHIFT		15
    7.43 +#define	IOSAPIC_EDGE			0
    7.44 +#define	IOSAPIC_LEVEL			1
    7.45 +
    7.46 +/*
    7.47 + * Mask bit
    7.48 + */
    7.49 +
    7.50 +#define	IOSAPIC_MASK_SHIFT		16
    7.51 +#define	IOSAPIC_MASK			(1<<IOSAPIC_MASK_SHIFT)
    7.52 +
    7.53 +#ifndef __ASSEMBLY__
    7.54 +
    7.55 +#ifdef CONFIG_IOSAPIC
    7.56 +
    7.57 +#define NR_IOSAPICS			256
    7.58 +
    7.59 +static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
    7.60 +{
    7.61 +	writel(reg, iosapic + IOSAPIC_REG_SELECT);
    7.62 +	return readl(iosapic + IOSAPIC_WINDOW);
    7.63 +}
    7.64 +
    7.65 +static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
    7.66 +{
    7.67 +	writel(reg, iosapic + IOSAPIC_REG_SELECT);
    7.68 +	writel(val, iosapic + IOSAPIC_WINDOW);
    7.69 +}
    7.70 +
    7.71 +static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
    7.72 +{
    7.73 +	writel(vector, iosapic + IOSAPIC_EOI);
    7.74 +}
    7.75 +
    7.76 +extern void __init iosapic_system_init (int pcat_compat);
    7.77 +extern int __devinit iosapic_init (unsigned long address,
    7.78 +				    unsigned int gsi_base);
    7.79 +#ifdef CONFIG_HOTPLUG
    7.80 +extern int iosapic_remove (unsigned int gsi_base);
    7.81 +#else
    7.82 +#define iosapic_remove(gsi_base)				(-EINVAL)
    7.83 +#endif /* CONFIG_HOTPLUG */
    7.84 +extern int gsi_to_vector (unsigned int gsi);
    7.85 +extern int gsi_to_irq (unsigned int gsi);
    7.86 +extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
    7.87 +				  unsigned long trigger);
    7.88 +extern void iosapic_unregister_intr (unsigned int irq);
    7.89 +extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
    7.90 +				      unsigned long polarity,
    7.91 +				      unsigned long trigger);
    7.92 +extern int __init iosapic_register_platform_intr (u32 int_type,
    7.93 +					   unsigned int gsi,
    7.94 +					   int pmi_vector,
    7.95 +					   u16 eid, u16 id,
    7.96 +					   unsigned long polarity,
    7.97 +					   unsigned long trigger);
    7.98 +extern unsigned int iosapic_version (char __iomem *addr);
    7.99 +
   7.100 +#ifdef CONFIG_NUMA
   7.101 +extern void __devinit map_iosapic_to_node (unsigned int, int);
   7.102 +#endif
   7.103 +#else
   7.104 +#define iosapic_system_init(pcat_compat)			do { } while (0)
   7.105 +#define iosapic_init(address,gsi_base)				(-EINVAL)
   7.106 +#define iosapic_remove(gsi_base)				(-ENODEV)
   7.107 +#define iosapic_register_intr(gsi,polarity,trigger)		(gsi)
   7.108 +#define iosapic_unregister_intr(irq)				do { } while (0)
   7.109 +#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger)	do { } while (0)
   7.110 +#define iosapic_register_platform_intr(type,gsi,pmi,eid,id, \
   7.111 +	polarity,trigger)					(gsi)
   7.112 +#endif
   7.113 +
   7.114 +# endif /* !__ASSEMBLY__ */
   7.115 +#endif /* __ASM_IA64_IOSAPIC_H */