debuggers.hg
changeset 9862: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>
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 */