⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io_apic.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	Intel IO-APIC support for multi-Pentium hosts. * *	Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar, Hajnalka Szabo * *	Many thanks to Stig Venaas for trying out countless experimental *	patches and reporting/debugging problems patiently! * *	(c) 1999, Multiple IO-APIC support, developed by *	Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and *      Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>, *	further tested and cleaned up by Zach Brown <zab@redhat.com> *	and Ingo Molnar <mingo@redhat.com> * *	Fixes *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs; *					thanks to Eric Gilmore *					and Rolf G. Tews *					for testing these extensively *	Paul Diefenbaugh	:	Added full ACPI support */#include <xen/config.h>#include <xen/lib.h>#include <xen/init.h>#include <xen/irq.h>#include <xen/delay.h>#include <xen/sched.h>#include <xen/acpi.h>#include <xen/keyhandler.h>#include <asm/io.h>#include <asm/mc146818rtc.h>#include <asm/smp.h>#include <asm/desc.h>#include <mach_apic.h>#include <io_ports.h>/* Different to Linux: our implementation can be simpler. */#define make_8259A_irq(irq) (io_apic_irqs &= ~(1<<(irq)))int (*ioapic_renumber_irq)(int ioapic, int irq);atomic_t irq_mis_count;/* Where if anywhere is the i8259 connect in external int mode */static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };static DEFINE_SPINLOCK(ioapic_lock);static DEFINE_SPINLOCK(vector_lock);int skip_ioapic_setup;#ifndef sis_apic_bug/* * Is the SiS APIC rmw bug present? * -1 = don't know, 0 = no, 1 = yes */int sis_apic_bug = -1;#endif/* * # of IRQ routing registers */int nr_ioapic_registers[MAX_IO_APICS];int disable_timer_pin_1 __initdata;/* * Rough estimation of how many shared IRQs there are, can * be changed anytime. */#define MAX_PLUS_SHARED_IRQS NR_IRQS#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)/* * This is performance-critical, we want to do it O(1) * * the indexing order of this array favors 1:1 mappings * between pins and IRQs. */static struct irq_pin_list {    int apic, pin, next;} irq_2_pin[PIN_MAP_SIZE];static int irq_2_pin_free_entry = NR_IRQS;int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};/* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */static void add_pin_to_irq(unsigned int irq, int apic, int pin){    struct irq_pin_list *entry = irq_2_pin + irq;    while (entry->next) {        BUG_ON((entry->apic == apic) && (entry->pin == pin));        entry = irq_2_pin + entry->next;    }    BUG_ON((entry->apic == apic) && (entry->pin == pin));    if (entry->pin != -1) {        if (irq_2_pin_free_entry >= PIN_MAP_SIZE)            panic("io_apic.c: whoops");        entry->next = irq_2_pin_free_entry;        entry = irq_2_pin + entry->next;        irq_2_pin_free_entry = entry->next;        entry->next = 0;    }    entry->apic = apic;    entry->pin = pin;}static void remove_pin_at_irq(unsigned int irq, int apic, int pin){    struct irq_pin_list *entry, *prev;    for (entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next]) {        if ((entry->apic == apic) && (entry->pin == pin))            break;        if (!entry->next)            BUG();    }    entry->pin = entry->apic = -1;        if (entry != &irq_2_pin[irq]) {        /* Removed entry is not at head of list. */        prev = &irq_2_pin[irq];        while (&irq_2_pin[prev->next] != entry)            prev = &irq_2_pin[prev->next];        prev->next = entry->next;        entry->next = irq_2_pin_free_entry;        irq_2_pin_free_entry = entry - irq_2_pin;    } else if (entry->next != 0) {        /* Removed entry is at head of multi-item list. */        prev  = entry;        entry = &irq_2_pin[entry->next];        *prev = *entry;        entry->pin = entry->apic = -1;        entry->next = irq_2_pin_free_entry;        irq_2_pin_free_entry = entry - irq_2_pin;    }}/* * Reroute an IRQ to a different pin. */static void __init replace_pin_at_irq(unsigned int irq,				      int oldapic, int oldpin,				      int newapic, int newpin){    struct irq_pin_list *entry = irq_2_pin + irq;    while (1) {        if (entry->apic == oldapic && entry->pin == oldpin) {            entry->apic = newapic;            entry->pin = newpin;        }        if (!entry->next)            break;        entry = irq_2_pin + entry->next;    }}static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable){    struct irq_pin_list *entry = irq_2_pin + irq;    unsigned int pin, reg;    for (;;) {        pin = entry->pin;        if (pin == -1)            break;        reg = io_apic_read(entry->apic, 0x10 + pin*2);        reg &= ~disable;        reg |= enable;        io_apic_modify(entry->apic, 0x10 + pin*2, reg);        if (!entry->next)            break;        entry = irq_2_pin + entry->next;    }}/* mask = 1 */static void __mask_IO_APIC_irq (unsigned int irq){    __modify_IO_APIC_irq(irq, 0x00010000, 0);}/* mask = 0 */static void __unmask_IO_APIC_irq (unsigned int irq){    __modify_IO_APIC_irq(irq, 0, 0x00010000);}/* trigger = 0 */static void __edge_IO_APIC_irq (unsigned int irq){    __modify_IO_APIC_irq(irq, 0, 0x00008000);}/* trigger = 1 */static void __level_IO_APIC_irq (unsigned int irq){    __modify_IO_APIC_irq(irq, 0x00008000, 0);}static void mask_IO_APIC_irq (unsigned int irq){    unsigned long flags;    spin_lock_irqsave(&ioapic_lock, flags);    __mask_IO_APIC_irq(irq);    spin_unlock_irqrestore(&ioapic_lock, flags);}static void unmask_IO_APIC_irq (unsigned int irq){    unsigned long flags;    spin_lock_irqsave(&ioapic_lock, flags);    __unmask_IO_APIC_irq(irq);    spin_unlock_irqrestore(&ioapic_lock, flags);}static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin){    struct IO_APIC_route_entry entry;    unsigned long flags;	    /* Check delivery_mode to be sure we're not clearing an SMI pin */    spin_lock_irqsave(&ioapic_lock, flags);    *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);    *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);    spin_unlock_irqrestore(&ioapic_lock, flags);    if (entry.delivery_mode == dest_SMI)        return;    /*     * Disable it in the IO-APIC irq-routing table:     */    memset(&entry, 0, sizeof(entry));    entry.mask = 1;    spin_lock_irqsave(&ioapic_lock, flags);    io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));    io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));    spin_unlock_irqrestore(&ioapic_lock, flags);}static void clear_IO_APIC (void){    int apic, pin;    for (apic = 0; apic < nr_ioapics; apic++)        for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)            clear_IO_APIC_pin(apic, pin);}#ifdef CONFIG_SMPstatic void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask){    unsigned long flags;    int pin;    struct irq_pin_list *entry = irq_2_pin + irq;    unsigned int apicid_value;    cpus_and(cpumask, cpumask, cpu_online_map);    if (cpus_empty(cpumask))        cpumask = TARGET_CPUS;    apicid_value = cpu_mask_to_apicid(cpumask);    /* Prepare to do the io_apic_write */    apicid_value = apicid_value << 24;    spin_lock_irqsave(&ioapic_lock, flags);    for (;;) {        pin = entry->pin;        if (pin == -1)            break;        io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value);        if (!entry->next)            break;        entry = irq_2_pin + entry->next;    }    set_irq_info(irq, cpumask);    spin_unlock_irqrestore(&ioapic_lock, flags);}#endif /* CONFIG_SMP *//* * Find the IRQ entry number of a certain pin. */static int find_irq_entry(int apic, int pin, int type){    int i;    for (i = 0; i < mp_irq_entries; i++)        if (mp_irqs[i].mpc_irqtype == type &&            (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||             mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&            mp_irqs[i].mpc_dstirq == pin)            return i;    return -1;}/* * Find the pin to which IRQ[irq] (ISA) is connected */static int __init find_isa_irq_pin(int irq, int type){    int i;    for (i = 0; i < mp_irq_entries; i++) {        int lbus = mp_irqs[i].mpc_srcbus;        if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||             mp_bus_id_to_type[lbus] == MP_BUS_EISA ||             mp_bus_id_to_type[lbus] == MP_BUS_MCA ||             mp_bus_id_to_type[lbus] == MP_BUS_NEC98            ) &&            (mp_irqs[i].mpc_irqtype == type) &&            (mp_irqs[i].mpc_srcbusirq == irq))            return mp_irqs[i].mpc_dstirq;    }    return -1;}static int __init find_isa_irq_apic(int irq, int type){    int i;    for (i = 0; i < mp_irq_entries; i++) {        int lbus = mp_irqs[i].mpc_srcbus;        if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||             mp_bus_id_to_type[lbus] == MP_BUS_EISA ||             mp_bus_id_to_type[lbus] == MP_BUS_MCA ||             mp_bus_id_to_type[lbus] == MP_BUS_NEC98            ) &&            (mp_irqs[i].mpc_irqtype == type) &&            (mp_irqs[i].mpc_srcbusirq == irq))            break;    }    if (i < mp_irq_entries) {        int apic;        for(apic = 0; apic < nr_ioapics; apic++) {            if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)                return apic;        }    }    return -1;}/* * Find a specific PCI IRQ entry. * Not an __init, possibly needed by modules */static int pin_2_irq(int idx, int apic, int pin);/* * This function currently is only a helper for the i386 smp boot process where  * we need to reprogram the ioredtbls to cater for the cpus which have come online * so mask in all cases should simply be TARGET_CPUS */#ifdef CONFIG_SMPvoid /*__init*/ setup_ioapic_dest(void){    int pin, ioapic, irq, irq_entry;    if (skip_ioapic_setup == 1)        return;    for (ioapic = 0; ioapic < nr_ioapics; ioapic++) {        for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {            irq_entry = find_irq_entry(ioapic, pin, mp_INT);            if (irq_entry == -1)                continue;            irq = pin_2_irq(irq_entry, ioapic, pin);            set_ioapic_affinity_irq(irq, TARGET_CPUS);        }    }}#endif/* * EISA Edge/Level control register, ELCR */static int EISA_ELCR(unsigned int irq){    if (irq < 16) {        unsigned int port = 0x4d0 + (irq >> 3);        return (inb(port) >> (irq & 7)) & 1;    }    apic_printk(APIC_VERBOSE, KERN_INFO                "Broken MPtable reports ISA irq %d\n", irq);    return 0;}/* EISA interrupts are always polarity zero and can be edge or level * trigger depending on the ELCR value.  If an interrupt is listed as * EISA conforming in the MP table, that means its trigger type must * be read in from the ELCR */#define default_EISA_trigger(idx)	(EISA_ELCR(mp_irqs[idx].mpc_srcbusirq))#define default_EISA_polarity(idx)	(0)/* ISA interrupts are always polarity zero edge triggered, * when listed as conforming in the MP table. */#define default_ISA_trigger(idx)	(0)#define default_ISA_polarity(idx)	(0)/* PCI interrupts are always polarity one level triggered, * when listed as conforming in the MP table. */#define default_PCI_trigger(idx)	(1)#define default_PCI_polarity(idx)	(1)/* MCA interrupts are always polarity zero level triggered, * when listed as conforming in the MP table. */#define default_MCA_trigger(idx)	(1)#define default_MCA_polarity(idx)	(0)/* NEC98 interrupts are always polarity zero edge triggered, * when listed as conforming in the MP table. */#define default_NEC98_trigger(idx)     (0)#define default_NEC98_polarity(idx)    (0)static int __init MPBIOS_polarity(int idx){    int bus = mp_irqs[idx].mpc_srcbus;    int polarity;    /*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -