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

📄 io_apic.c

📁 xen 3.2.2 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (reg_00.bits.ID >= get_physical_broadcast())            UNEXPECTED_IO_APIC();	if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)            UNEXPECTED_IO_APIC();	printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw);	printk(KERN_DEBUG ".......     : max redirection entries: %04X\n", reg_01.bits.entries);	if (	(reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */		(reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */		(reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */		(reg_01.bits.entries != 0x1f) && /* dual Xeon boards */		(reg_01.bits.entries != 0x22) && /* bigger Xeon boards */		(reg_01.bits.entries != 0x2E) &&		(reg_01.bits.entries != 0x3F)            )            UNEXPECTED_IO_APIC();	printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.bits.PRQ);	printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.bits.version);	if (	(reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */		(reg_01.bits.version != 0x10) && /* oldest IO-APICs */		(reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */		(reg_01.bits.version != 0x13) && /* Xeon IO-APICs */		(reg_01.bits.version != 0x20)    /* Intel P64H (82806 AA) */            )            UNEXPECTED_IO_APIC();	if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)            UNEXPECTED_IO_APIC();	/*	 * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,	 * but the value of reg_02 is read as the previous read register	 * value, so ignore it if reg_02 == reg_01.	 */	if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {            printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);            printk(KERN_DEBUG ".......     : arbitration: %02X\n", reg_02.bits.arbitration);            if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)                UNEXPECTED_IO_APIC();	}	/*	 * Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02	 * or reg_03, but the value of reg_0[23] is read as the previous read	 * register value, so ignore it if reg_03 == reg_0[12].	 */	if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw &&	    reg_03.raw != reg_01.raw) {            printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw);            printk(KERN_DEBUG ".......     : Boot DT    : %X\n", reg_03.bits.boot_DT);            if (reg_03.bits.__reserved_1)                UNEXPECTED_IO_APIC();	}	printk(KERN_DEBUG ".... IRQ redirection table:\n");	printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"               " Stat Dest Deli Vect:   \n");	for (i = 0; i <= reg_01.bits.entries; i++) {            struct IO_APIC_route_entry entry;            spin_lock_irqsave(&ioapic_lock, flags);            *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);            *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);            spin_unlock_irqrestore(&ioapic_lock, flags);            printk(KERN_DEBUG " %02x %03X %02X  ",                   i,                   entry.dest.logical.logical_dest,                   entry.dest.physical.physical_dest		);            printk("%1d    %1d    %1d   %1d   %1d    %1d    %1d    %02X\n",                   entry.mask,                   entry.trigger,                   entry.irr,                   entry.polarity,                   entry.delivery_status,                   entry.dest_mode,                   entry.delivery_mode,                   entry.vector		);	}    }    printk(KERN_INFO "Using vector-based indexing\n");    printk(KERN_DEBUG "IRQ to pin mappings:\n");    for (i = 0; i < NR_IRQS; i++) {        struct irq_pin_list *entry = irq_2_pin + i;        if (entry->pin < 0)            continue;        printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));        for (;;) {            printk("-> %d:%d", entry->apic, entry->pin);            if (!entry->next)                break;            entry = irq_2_pin + entry->next;        }        printk("\n");    }    printk(KERN_INFO ".................................... done.\n");    return;}void print_IO_APIC(void){    if (apic_verbosity != APIC_QUIET)        __print_IO_APIC();}void print_IO_APIC_keyhandler(unsigned char key){    __print_IO_APIC();}static void __init enable_IO_APIC(void){    union IO_APIC_reg_01 reg_01;    int i8259_apic, i8259_pin;    int i, apic;    unsigned long flags;    for (i = 0; i < PIN_MAP_SIZE; i++) {        irq_2_pin[i].pin = -1;        irq_2_pin[i].next = 0;    }    /* Initialise dynamic irq_2_pin free list. */    for (i = NR_IRQS; i < PIN_MAP_SIZE; i++)        irq_2_pin[i].next = i + 1;    /*     * The number of IO-APIC IRQ registers (== #pins):     */    for (apic = 0; apic < nr_ioapics; apic++) {        spin_lock_irqsave(&ioapic_lock, flags);        reg_01.raw = io_apic_read(apic, 1);        spin_unlock_irqrestore(&ioapic_lock, flags);        nr_ioapic_registers[apic] = reg_01.bits.entries+1;    }    for(apic = 0; apic < nr_ioapics; apic++) {        int pin;        /* See if any of the pins is in ExtINT mode */        for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {            struct IO_APIC_route_entry entry;            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 the interrupt line is enabled and in ExtInt mode             * I have found the pin where the i8259 is connected.             */            if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {                ioapic_i8259.apic = apic;                ioapic_i8259.pin  = pin;                goto found_i8259;            }        }    } found_i8259:    /* Look to see what if the MP table has reported the ExtINT */    /* If we could not find the appropriate pin by looking at the ioapic     * the i8259 probably is not connected the ioapic but give the     * mptable a chance anyway.     */    i8259_pin  = find_isa_irq_pin(0, mp_ExtINT);    i8259_apic = find_isa_irq_apic(0, mp_ExtINT);    /* Trust the MP table if nothing is setup in the hardware */    if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {        printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n");        ioapic_i8259.pin  = i8259_pin;        ioapic_i8259.apic = i8259_apic;    }    /* Complain if the MP table and the hardware disagree */    if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&        (i8259_pin >= 0) && (ioapic_i8259.pin >= 0))    {        printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");    }    /*     * Do not trust the IO-APIC being empty at bootup     */    clear_IO_APIC();}/* * Not an __init, needed by the reboot code */void disable_IO_APIC(void){    /*     * Clear the IO-APIC before rebooting:     */    clear_IO_APIC();    /*     * If the i8259 is routed through an IOAPIC     * Put that IOAPIC in virtual wire mode     * so legacy interrupts can be delivered.     */    if (ioapic_i8259.pin != -1) {        struct IO_APIC_route_entry entry;        unsigned long flags;        memset(&entry, 0, sizeof(entry));        entry.mask            = 0; /* Enabled */        entry.trigger         = 0; /* Edge */        entry.irr             = 0;        entry.polarity        = 0; /* High */        entry.delivery_status = 0;        entry.dest_mode       = 0; /* Physical */        entry.delivery_mode   = dest_ExtINT; /* ExtInt */        entry.vector          = 0;        entry.dest.physical.physical_dest =            GET_APIC_ID(apic_read(APIC_ID));        /*         * Add it to the IO-APIC irq-routing table:         */        spin_lock_irqsave(&ioapic_lock, flags);        io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin,                      *(((int *)&entry)+1));        io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin,                      *(((int *)&entry)+0));        spin_unlock_irqrestore(&ioapic_lock, flags);    }    disconnect_bsp_APIC(ioapic_i8259.pin != -1);}/* * function to set the IO-APIC physical IDs based on the * values stored in the MPC table. * * by Matt Domsch <Matt_Domsch@dell.com>  Tue Dec 21 12:25:05 CST 1999 */#ifndef CONFIG_X86_NUMAQstatic void __init setup_ioapic_ids_from_mpc(void){    union IO_APIC_reg_00 reg_00;    physid_mask_t phys_id_present_map;    int apic;    int i;    unsigned char old_id;    unsigned long flags;    /*     * Don't check I/O APIC IDs for xAPIC systems. They have     * no meaning without the serial APIC bus.     */    if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)        || APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))        return;    /*     * This is broken; anything with a real cpu count has to     * circumvent this idiocy regardless.     */    phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map);    /*     * Set the IOAPIC ID to the value stored in the MPC table.     */    for (apic = 0; apic < nr_ioapics; apic++) {        /* Read the register 0 value */        spin_lock_irqsave(&ioapic_lock, flags);        reg_00.raw = io_apic_read(apic, 0);        spin_unlock_irqrestore(&ioapic_lock, flags);		        old_id = mp_ioapics[apic].mpc_apicid;        if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {            printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",                   apic, mp_ioapics[apic].mpc_apicid);            printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",                   reg_00.bits.ID);            mp_ioapics[apic].mpc_apicid = reg_00.bits.ID;        }        /*         * Sanity check, is the ID really free? Every APIC in a         * system must have a unique ID or we get lots of nice         * 'stuck on smp_invalidate_needed IPI wait' messages.         */        if (check_apicid_used(phys_id_present_map,                              mp_ioapics[apic].mpc_apicid)) {            printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",                   apic, mp_ioapics[apic].mpc_apicid);            for (i = 0; i < get_physical_broadcast(); i++)                if (!physid_isset(i, phys_id_present_map))                    break;            if (i >= get_physical_broadcast())                panic("Max APIC ID exceeded!\n");            printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",                   i);            physid_set(i, phys_id_present_map);            mp_ioapics[apic].mpc_apicid = i;        } else {            physid_mask_t tmp;            tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid);            apic_printk(APIC_VERBOSE, "Setting %d in the "                        "phys_id_present_map\n",                        mp_ioapics[apic].mpc_apicid);            physids_or(phys_id_present_map, phys_id_present_map, tmp);        }        /*         * We need to adjust the IRQ routing table         * if the ID changed.         */        if (old_id != mp_ioapics[apic].mpc_apicid)            for (i = 0; i < mp_irq_entries; i++)                if (mp_irqs[i].mpc_dstapic == old_id)                    mp_irqs[i].mpc_dstapic                        = mp_ioapics[apic].mpc_apicid;        /*         * Read the right value from the MPC table and         * write it into the ID register.         */        apic_printk(APIC_VERBOSE, KERN_INFO                    "...changing IO-APIC physical APIC ID to %d ...",                    mp_ioapics[apic].mpc_apicid);        reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;        spin_lock_irqsave(&ioapic_lock, flags);        io_apic_write(apic, 0, reg_00.raw);        spin_unlock_irqrestore(&ioapic_lock, flags);        /*         * Sanity check         */        spin_lock_irqsave(&ioapic_lock, flags);        reg_00.raw = io_apic_read(apic, 0);        spin_unlock_irqrestore(&ioapic_lock, flags);        if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)            printk("could not set ID!\n");        else            apic_printk(APIC_VERBOSE, " ok.\n");    }}#elsestatic void __init setup_ioapic_ids_from_mpc(void) { }#endif/* * There is a nasty bug in some older SMP boards, their mptable lies * about the timer IRQ. We do the following to work around the situation: * *	- timer IRQ defaults to IO-APIC IRQ *	- if this function detects that timer IRQs are defunct, then we fall *	  back to ISA timer IRQs */static int __init timer_irq_works(void){    unsigned long t1 = jiffies;    local_irq_enable();    /* Let ten ticks pass... */    mdelay((10 * 1000) / HZ);    /*     * Expect a few ticks at least, to be sure some possible     * glue logic does not lock up after one or two first     * ticks in a non-ExtINT mode.  Also the local APIC     * might have cached one ExtINT interrupt.  Finally, at     * least one tick may be lost due to delays.     */    if (jiffies - t1 > 4)        return 1;    return 0;}/* * In the SMP+IOAPIC case it might happen that there are an unspecified * number of pending IRQ events unhandled. These cases are very rare, * so we 'resend' these IRQs via IPIs, to the same CPU. It's much * better to do it this way as thus we do not have to be aware of * 'pending' interrupts in the IRQ path, except at this point. *//* * Edge triggered needs to resend any interrupt * that was delayed but this is now handled in the device * independent code. *//* * Starting up a edge-triggered IO-APIC interrupt is * nasty - we need to make sure that we get the edge. * If it is already asserted for some reason, we need * return 1 to indicate that is was pending. * * This is not complete - we should be able to fake * an edge even if it isn't on the 8259A... */static unsigned int startup_edge_ioapic_irq(unsigned int irq){    int was_pending = 0;    unsigned long flags;    spin_lock_irqsave(&ioapic_lock, flags);    if (irq < 16) {        disable_8259A_irq(irq);        if (i8259A_irq_pending(irq))            was_pending = 1;    }    __unmask_IO_APIC_irq(irq);    spin_unlock_irqrestore(&ioapic_lock, flags);    return was_pending;}/* * Once we have recorded IRQ_PENDING already, we can mask the * interrupt for real. This prevents IRQ storms from unhandled * devices. */static void ack_edge_ioapic_irq(unsigned int irq){    if ((irq_desc[IO_APIC_VECTOR(irq)].status & (IRQ_PENDING | IRQ_DISABLED))        == (IRQ_PENDING | IRQ_DISABLED))        mask_IO_APIC_irq(irq);    ack_APIC_irq();}/* * Level triggered interrupts can just be masked, * and shutting down and starting up the interrupt * is the same as enabling and disabling them -- except * with a startup need to return a "was pending" value. * * Level triggered interrupts are special because we * do not touch any IO-APIC register while handling * them. We ack the APIC in the end-IRQ handler, not

⌨️ 快捷键说明

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