📄 io_apic.c
字号:
int apic, idx, pin; for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { idx = find_irq_entry(apic,pin,mp_INT); if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin))) return irq_trigger(idx); } } /* * nonexistent IRQs are edge default */ return 0;}int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 };static int __init assign_irq_vector(int irq){ static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; if (IO_APIC_VECTOR(irq) > 0) return IO_APIC_VECTOR(irq);next: current_vector += 8; if (current_vector == SYSCALL_VECTOR) goto next; if (current_vector > FIRST_SYSTEM_VECTOR) { offset++; current_vector = FIRST_DEVICE_VECTOR + offset; } if (current_vector == FIRST_SYSTEM_VECTOR) panic("ran out of interrupt sources!"); IO_APIC_VECTOR(irq) = current_vector; return current_vector;}extern void (*interrupt[NR_IRQS])(void);static struct hw_interrupt_type ioapic_level_irq_type;static struct hw_interrupt_type ioapic_edge_irq_type;void __init setup_IO_APIC_irqs(void){ struct IO_APIC_route_entry entry; int apic, pin, idx, irq, first_notcon = 1, vector; unsigned long flags; printk(KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { /* * add it to the IO-APIC irq-routing table: */ memset(&entry,0,sizeof(entry)); entry.delivery_mode = dest_LowestPrio; entry.dest_mode = INT_DELIVERY_MODE; entry.mask = 0; /* enable IRQ */ entry.dest.logical.logical_dest = TARGET_CPUS; idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { if (first_notcon) { printk(KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin); first_notcon = 0; } else printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin); continue; } entry.trigger = irq_trigger(idx); entry.polarity = irq_polarity(idx); if (irq_trigger(idx)) { entry.trigger = 1; entry.mask = 1; entry.dest.logical.logical_dest = TARGET_CPUS; } irq = pin_2_irq(idx, apic, pin); add_pin_to_irq(irq, apic, pin); if (!apic && !IO_APIC_IRQ(irq)) continue; if (IO_APIC_IRQ(irq)) { vector = assign_irq_vector(irq); entry.vector = vector; if (IO_APIC_irq_trigger(irq)) irq_desc[irq].handler = &ioapic_level_irq_type; else irq_desc[irq].handler = &ioapic_edge_irq_type; set_intr_gate(vector, interrupt[irq]); if (!apic && (irq < 16)) disable_8259A_irq(irq); } spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0)); spin_unlock_irqrestore(&ioapic_lock, flags); } } if (!first_notcon) printk(" not connected.\n");}/* * Set up the 8259A-master output pin as broadcast to all * CPUs. */void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector){ struct IO_APIC_route_entry entry; unsigned long flags; memset(&entry,0,sizeof(entry)); disable_8259A_irq(0); /* mask LVT0 */ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); /* * We use logical delivery to get the timer IRQ * to the first CPU. */ entry.dest_mode = INT_DELIVERY_MODE; entry.mask = 0; /* unmask IRQ now */ entry.dest.logical.logical_dest = TARGET_CPUS; entry.delivery_mode = dest_LowestPrio; entry.polarity = 0; entry.trigger = 0; entry.vector = vector; /* * The timer IRQ doesnt have to know that behind the * scene we have a 8259A-master in AEOI mode ... */ irq_desc[0].handler = &ioapic_edge_irq_type; /* * Add it to the IO-APIC irq-routing table: */ spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1)); io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0)); spin_unlock_irqrestore(&ioapic_lock, flags); enable_8259A_irq(0);}void __init UNEXPECTED_IO_APIC(void){ printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n"); printk(KERN_WARNING " to linux-smp@vger.kernel.org\n");}void __init print_IO_APIC(void){ int apic, i; struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_02 reg_02; unsigned long flags; printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]); /* * We are a bit conservative about what we expect. We have to * know about every hardware change ASAP. */ printk(KERN_INFO "testing the IO APIC.......................\n"); for (apic = 0; apic < nr_ioapics; apic++) { spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_00 = io_apic_read(apic, 0); *(int *)®_01 = io_apic_read(apic, 1); if (reg_01.version >= 0x10) *(int *)®_02 = io_apic_read(apic, 2); spin_unlock_irqrestore(&ioapic_lock, flags); printk("\n"); printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)®_00); printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.ID); if (reg_00.__reserved_1 || reg_00.__reserved_2) UNEXPECTED_IO_APIC(); printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.entries); if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */ (reg_01.entries != 0x17) && /* typical ISA+PCI boards */ (reg_01.entries != 0x1b) && /* Compaq Proliant boards */ (reg_01.entries != 0x1f) && /* dual Xeon boards */ (reg_01.entries != 0x22) && /* bigger Xeon boards */ (reg_01.entries != 0x2E) && (reg_01.entries != 0x3F) ) UNEXPECTED_IO_APIC(); printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.PRQ); printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.version); if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */ (reg_01.version != 0x10) && /* oldest IO-APICs */ (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */ (reg_01.version != 0x13) && /* Xeon IO-APICs */ (reg_01.version != 0x20) /* Intel P64H (82806 AA) */ ) UNEXPECTED_IO_APIC(); if (reg_01.__reserved_1 || reg_01.__reserved_2) UNEXPECTED_IO_APIC(); if (reg_01.version >= 0x10) { printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)®_02); printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration); if (reg_02.__reserved_1 || reg_02.__reserved_2) 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.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_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 ", 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;}static void print_APIC_bitfield (int base){ unsigned int v; int i, j; printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); for (i = 0; i < 8; i++) { v = apic_read(base + i*0x10); for (j = 0; j < 32; j++) { if (v & (1<<j)) printk("1"); else printk("0"); } printk("\n"); }}void /*__init*/ print_local_APIC(void * dummy){ unsigned int v, ver, maxlvt; printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n", smp_processor_id(), hard_smp_processor_id()); v = apic_read(APIC_ID); printk(KERN_INFO "... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v)); v = apic_read(APIC_LVR); printk(KERN_INFO "... APIC VERSION: %08x\n", v); ver = GET_APIC_VERSION(v); maxlvt = get_maxlvt(); v = apic_read(APIC_TASKPRI); printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK); if (APIC_INTEGRATED(ver)) { /* !82489DX */ v = apic_read(APIC_ARBPRI); printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v, v & APIC_ARBPRI_MASK); v = apic_read(APIC_PROCPRI); printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v); } v = apic_read(APIC_EOI); printk(KERN_DEBUG "... APIC EOI: %08x\n", v); v = apic_read(APIC_RRR); printk(KERN_DEBUG "... APIC RRR: %08x\n", v); v = apic_read(APIC_LDR); printk(KERN_DEBUG "... APIC LDR: %08x\n", v); v = apic_read(APIC_DFR); printk(KERN_DEBUG "... APIC DFR: %08x\n", v); v = apic_read(APIC_SPIV); printk(KERN_DEBUG "... APIC SPIV: %08x\n", v); printk(KERN_DEBUG "... APIC ISR field:\n"); print_APIC_bitfield(APIC_ISR); printk(KERN_DEBUG "... APIC TMR field:\n"); print_APIC_bitfield(APIC_TMR); printk(KERN_DEBUG "... APIC IRR field:\n"); print_APIC_bitfield(APIC_IRR); if (APIC_INTEGRATED(ver)) { /* !82489DX */ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); v = apic_read(APIC_ESR); printk(KERN_DEBUG "... APIC ESR: %08x\n", v); } v = apic_read(APIC_ICR); printk(KERN_DEBUG "... APIC ICR: %08x\n", v); v = apic_read(APIC_ICR2); printk(KERN_DEBUG "... APIC ICR2: %08x\n", v); v = apic_read(APIC_LVTT); printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); if (maxlvt > 3) { /* PC is LVT#4. */ v = apic_read(APIC_LVTPC); printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v); } v = apic_read(APIC_LVT0); printk(KERN_DEBUG "... APIC LVT0: %08x\n", v); v = apic_read(APIC_LVT1); printk(KERN_DEBUG "... APIC LVT1: %08x\n", v); if (maxlvt > 2) { /* ERR is LVT#3. */ v = apic_read(APIC_LVTERR); printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v); } v = apic_read(APIC_TMICT); printk(KERN_DEBUG "... APIC TMICT: %08x\n", v); v = apic_read(APIC_TMCCT); printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v); v = apic_read(APIC_TDCR); printk(KERN_DEBUG "... APIC TDCR: %08x\n", v); printk("\n");}void print_all_local_APICs (void){ smp_call_function(print_local_APIC, NULL, 1, 1); print_local_APIC(NULL);}void /*__init*/ print_PIC(void){ extern spinlock_t i8259A_lock; unsigned int v, flags; printk(KERN_DEBUG "\nprinting PIC contents\n"); spin_lock_irqsave(&i8259A_lock, flags); v = inb(0xa1) << 8 | inb(0x21); printk(KERN_DEBUG "... PIC IMR: %04x\n", v); v = inb(0xa0) << 8 | inb(0x20); printk(KERN_DEBUG "... PIC IRR: %04x\n", v); outb(0x0b,0xa0); outb(0x0b,0x20); v = inb(0xa0) << 8 | inb(0x20); outb(0x0a,0xa0); outb(0x0a,0x20); spin_unlock_irqrestore(&i8259A_lock, flags); printk(KERN_DEBUG "... PIC ISR: %04x\n", v); v = inb(0x4d1) << 8 | inb(0x4d0); printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);}static void __init enable_IO_APIC(void){ struct IO_APIC_reg_01 reg_01; int i; unsigned long flags; for (i = 0; i < PIN_MAP_SIZE; i++) { irq_2_pin[i].pin = -1; irq_2_pin[i].next = 0; } if (!pirqs_enabled) for (i = 0; i < MAX_PIRQS; i++) pirq_entries[i] = -1; /* * The number of IO-APIC IRQ registers (== #pins): */ for (i = 0; i < nr_ioapics; i++) { spin_lock_irqsave(&ioapic_lock, flags); *(int *)®_01 = io_apic_read(i, 1); spin_unlock_irqrestore(&ioapic_lock, flags); nr_ioapic_registers[i] = reg_01.entries+1; } /* * 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(); disconnect_bsp_APIC();}/* * 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 */static void __init setup_ioapic_ids_from_mpc (void){ struct IO_APIC_reg_00 reg_00; unsigned long phys_id_present_map = phys_cpu_present_map; int apic; int i; unsigned char old_id; unsigned long flags; if (clustered_apic_mode) /* We don't have a good way to do this yet - hack */ phys_id_present_map = (u_long) 0xf; /* * 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); *(int *)®_00 = io_apic_read(apic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); old_id = mp_ioapics[apic].mpc_apicid; if (mp_ioapics[apic].mpc_apicid >= 0xf) { 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.ID); mp_ioapics[apic].mpc_apicid = reg_00.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 (phys_id_present_map & (1 << 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 < 0xf; i++) if (!(phys_id_present_map & (1 << i))) break; if (i >= 0xf) panic("Max APIC ID exceeded!\n"); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", i); phys_id_present_map |= 1 << i; mp_ioapics[apic].mpc_apicid = i; } else { printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid); phys_id_present_map |= 1 << mp_ioapics[apic].mpc_apicid; } /* * 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. */ printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", mp_ioapics[apic].mpc_apicid); reg_00.ID = mp_ioapics[apic].mpc_apicid; spin_lock_irqsave(&ioapic_lock, flags); io_apic_write(apic, 0, *(int *)®_00);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -