iosapic.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 695 行 · 第 1/2 页
C
695 行
/* * I/O SAPIC support. * * Copyright (C) 1999 Intel Corp. * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 2000-2002 J.I. Lee <jung-ik.lee@intel.com> * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co. * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> * * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. * In particular, we now have separate handlers for edge * and level triggered interrupts. * 00/10/27 Asit Mallick, Goutham Rao <goutham.rao@intel.com> IRQ vector allocation * PCI to vector mapping, shared PCI interrupts. * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. * Clean up much of the old IOSAPIC cruft. * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts and fixes for * ACPI S5(SoftOff) support. * 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT * 02/01/07 E. Focht <efocht@ess.nec.de> Redirectable interrupt vectors in * iosapic_set_affinity(), initializations for * /proc/irq/#/smp_affinity * 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing. * 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping * error * 02/07/29 T. Kochi Allocate interrupt vectors dynamically * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector, etc.) * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's pci_irq code. * 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC. * Remove iosapic_address & gsi_base from external interfaces. * Rationalize __init/__devinit attributes. * 04/12/04 Ashok Raj <ashok.raj@intel.com> Intel Corporation 2004 * Updated to work with irq migration necessary for CPU Hotplug *//* * Here is what the interrupt logic between a PCI device and the kernel looks like: * * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The * device is uniquely identified by its bus--, and slot-number (the function * number does not matter here because all functions share the same interrupt * lines). * * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. * Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level * triggered and use the same polarity). Each interrupt line has a unique Global * System Interrupt (GSI) number which can be calculated as the sum of the controller's * base GSI number and the IOSAPIC pin number to which the line connects. * * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin * into the IA-64 interrupt vector. This interrupt vector is then sent to the CPU. * * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is used as * architecture-independent interrupt handling mechanism in Linux. As an * IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number * mapping. On smaller systems, we use one-to-one mapping between IA-64 vector and * IRQ. A platform can implement platform_irq_to_vector(irq) and * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. * Please see also include/asm-ia64/hw_irq.h for those APIs. * * To sum up, there are three levels of mappings involved: * * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ * * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts. * Now we use "IRQ" only for Linux IRQ's. ISA IRQ (isa_irq) is the only exception in this * source code. */#include <linux/config.h>#include <linux/acpi.h>#include <linux/init.h>#include <linux/irq.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/pci.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/string.h>#include <asm/delay.h>#include <asm/hw_irq.h>#include <asm/io.h>#include <asm/iosapic.h>#include <asm/machvec.h>#include <asm/processor.h>#include <asm/ptrace.h>#include <asm/system.h>#undef DEBUG_INTERRUPT_ROUTING#undef OVERRIDE_DEBUG#ifdef DEBUG_INTERRUPT_ROUTING#define DBG(fmt...) printk(fmt)#else#define DBG(fmt...)#endifstatic spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED;/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */static struct iosapic_intr_info { char *addr; /* base address of IOSAPIC */ u32 low32; /* current value of low word of Redirection table entry */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ char rte_index; /* IOSAPIC RTE index (-1 => not an IOSAPIC interrupt) */ unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ unsigned char trigger : 1; /* trigger mode (see iosapic.h) */} iosapic_intr_info[IA64_NUM_VECTORS];static struct iosapic { char *addr; /* base address of IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */} iosapic_lists[NR_IOSAPICS];static int num_iosapic;static unsigned char pcat_compat __initdata; /* 8259 compatibility flag *//* * Find an IOSAPIC associated with a GSI */static inline intfind_iosapic (unsigned int gsi){ int i; for (i = 0; i < num_iosapic; i++) { if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) return i; } return -1;}static inline int_gsi_to_vector (unsigned int gsi){ struct iosapic_intr_info *info; for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) if (info->gsi_base + info->rte_index == gsi) return info - iosapic_intr_info; return -1;}/* * Translate GSI number to the corresponding IA-64 interrupt vector. If no * entry exists, return -1. */inline intgsi_to_vector (unsigned int gsi){ return _gsi_to_vector(gsi);}intgsi_to_irq (unsigned int gsi){ /* * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq * numbers... */ return _gsi_to_vector(gsi);}static voidset_rte (unsigned int vector, unsigned int dest, int mask){ unsigned long pol, trigger, dmode, flags; u32 low32, high32; char *addr; int rte_index; char redir; DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest); rte_index = iosapic_intr_info[vector].rte_index; if (rte_index < 0) return; /* not an IOSAPIC interrupt */ addr = iosapic_intr_info[vector].addr; pol = iosapic_intr_info[vector].polarity; trigger = iosapic_intr_info[vector].trigger; dmode = iosapic_intr_info[vector].dmode; vector &= (~IA64_IRQ_REDIRECTED); redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;#ifdef CONFIG_SMP { unsigned int irq; for (irq = 0; irq < NR_IRQS; ++irq) if (irq_to_vector(irq) == vector) { set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); break; } }#endif low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | (trigger << IOSAPIC_TRIGGER_SHIFT) | (dmode << IOSAPIC_DELIVERY_SHIFT) | ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) | vector); /* dest contains both id and eid */ high32 = (dest << IOSAPIC_DEST_SHIFT); spin_lock_irqsave(&iosapic_lock, flags); { iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_intr_info[vector].low32 = low32; } spin_unlock_irqrestore(&iosapic_lock, flags);}static voidnop (unsigned int vector){ /* do nothing... */}static voidmask_irq (unsigned int irq){ unsigned long flags; char *addr; u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); addr = iosapic_intr_info[vec].addr; rte_index = iosapic_intr_info[vec].rte_index; if (rte_index < 0) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { /* set only the mask bit */ low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); } spin_unlock_irqrestore(&iosapic_lock, flags);}static voidunmask_irq (unsigned int irq){ unsigned long flags; char *addr; u32 low32; int rte_index; ia64_vector vec = irq_to_vector(irq); addr = iosapic_intr_info[vec].addr; rte_index = iosapic_intr_info[vec].rte_index; if (rte_index < 0) return; /* not an IOSAPIC interrupt! */ spin_lock_irqsave(&iosapic_lock, flags); { low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); } spin_unlock_irqrestore(&iosapic_lock, flags);}static voidiosapic_set_affinity (unsigned int irq, cpumask_t mask){#ifdef CONFIG_SMP unsigned long flags; u32 high32, low32; int dest, rte_index; char *addr; int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0; ia64_vector vec; irq &= (~IA64_IRQ_REDIRECTED); vec = irq_to_vector(irq); if (cpus_empty(mask)) return; dest = cpu_physical_id(first_cpu(mask)); rte_index = iosapic_intr_info[vec].rte_index; addr = iosapic_intr_info[vec].addr; if (rte_index < 0) return; /* not an IOSAPIC interrupt */ set_irq_affinity_info(irq, dest, redir); /* dest contains both id and eid */ high32 = dest << IOSAPIC_DEST_SHIFT; spin_lock_irqsave(&iosapic_lock, flags); { low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); if (redir) /* change delivery mode to lowest priority */ low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); else /* change delivery mode to fixed */ low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); iosapic_intr_info[vec].low32 = low32; iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); } spin_unlock_irqrestore(&iosapic_lock, flags);#endif}/* * Handlers for level-triggered interrupts. */static unsigned intiosapic_startup_level_irq (unsigned int irq){ unmask_irq(irq); return 0;}static voidiosapic_end_level_irq (unsigned int irq){ ia64_vector vec = irq_to_vector(irq); move_irq(irq); iosapic_eoi(iosapic_intr_info[vec].addr, vec);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?