X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=kitten%2Farch%2Fx86_64%2Fkernel%2Flapic.c;fp=kitten%2Farch%2Fx86_64%2Fkernel%2Flapic.c;h=0000000000000000000000000000000000000000;hb=80d6ccd14cca51eec611cc96cf1e39c7a9c98421;hp=f10c372ae9d2a624bef5406e7ad66147857128d1;hpb=e5d7715c14a23e72d742d402d4e4cdf97ffab697;p=palacios.releases.git diff --git a/kitten/arch/x86_64/kernel/lapic.c b/kitten/arch/x86_64/kernel/lapic.c deleted file mode 100644 index f10c372..0000000 --- a/kitten/arch/x86_64/kernel/lapic.c +++ /dev/null @@ -1,472 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Physical address of the local APIC memory mapping. - * If the system BIOS provided an MP configuration table, this is set in - * arch/x86_64/kernel/mpparse.c to the value parsed from the table. - * Otherwise, the default address is used. - */ -unsigned long lapic_phys_addr = APIC_DEFAULT_PHYS_BASE; - -/** - * Resource entry for the local APIC memory mapping. - */ -static struct resource lapic_resource = { - .name = "Local APIC", - .flags = IORESOURCE_MEM | IORESOURCE_BUSY, - /* .start and .end filled in later based on detected address */ -}; - -/** - * Creates a kernel mapping for the local APIC. - * - * The hardware/platform/BIOS maps each CPU's local APIC at the same location - * in physical memory. This function uses the 'fixmap' to map the local APIC - * into the kernel's virtual memory space at a fixed virtual address that is - * known at compile time. Since the local APIC's virtual address is known - * at compile time, local APIC registers can be accessed directly, without - * any pointer dereferencing. - */ -void __init -lapic_map(void) -{ - if (!cpu_has_apic) - panic("No local APIC."); - - /* Reserve physical memory used by the local APIC */ - lapic_resource.start = lapic_phys_addr; - lapic_resource.end = lapic_phys_addr + 4096 - 1; - request_resource(&iomem_resource, &lapic_resource); - - /* Map local APIC into the kernel */ - set_fixmap_nocache(FIX_APIC_BASE, lapic_phys_addr); - - printk(KERN_DEBUG "Local APIC mapped to virtual address 0x%016lx\n", - fix_to_virt(FIX_APIC_BASE)); -} - -/** - * Initializes the calling CPU's local APIC. - */ -void __init -lapic_init(void) -{ - uint32_t val; - - /* - * Initialize Destination Format Register. - * When using logical destination mode, we want to use the flat model. - */ - apic_write(APIC_DFR, APIC_DFR_FLAT); - - /* - * Initialize the Logical Destination Register. - * The LWK never uses logical destination mode, so just set it to the - * APIC's physical ID to avoid possible confusion. - */ - val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; - val |= SET_APIC_LOGICAL_ID( GET_APIC_ID(apic_read(APIC_ID)) ); - apic_write(APIC_LDR, val); - - /* - * Initialize the Task Priority Register. - * We set this to accept all (0) and never touch it again. - */ - val = apic_read(APIC_TASKPRI) & ~APIC_TPRI_MASK; - apic_write(APIC_TASKPRI, val); - - /* - * Intialize the Spurious-Interrupt Vector Register. - * This also enables the local APIC. - */ - val = apic_read(APIC_SPIV) & ~APIC_VECTOR_MASK; - val |= (APIC_SPIV_APIC_ENABLED | APIC_SPURIOUS_VECTOR); - apic_write(APIC_SPIV, val); - - /* Setup LVT[0] = APIC Timer Interrupt */ - apic_write(APIC_LVTT, 0 - | APIC_DM_FIXED /* route to fixed IDT vector */ - | APIC_TIMER_VECTOR /* IDT vector to route to */ - | APIC_LVT_MASKED /* initially disable */ - ); - - /* Setup LVT[1] = Thermal Sensor Interrupt */ - apic_write(APIC_LVTTHMR, 0 - | APIC_DM_FIXED /* route to fixed IDT vector */ - | APIC_THERMAL_VECTOR /* IDT vector to route to */ - ); - - /* Setup LVT[2] = Performance Counter Interrupt */ - apic_write(APIC_LVTPC, 0 - | APIC_DM_NMI /* treat as non-maskable interrupt */ - /* NMIs are routed to IDT vector 2 */ - | APIC_LVT_MASKED /* initially disable */ - ); - - /* Setup LVT[3] = Local Interrupt Pin 0 */ - apic_write(APIC_LVT0, 0 - | APIC_DM_EXTINT /* hooked up to old 8259A PIC */ - /* IDT vector provided by 8259A */ - | APIC_LVT_MASKED /* disable */ - ); - - /* Setup LVT[4] = Local Interrupt Pin 1 */ - apic_write(APIC_LVT1, 0 - | APIC_DM_NMI /* treat as non-maskable interrupt */ - /* NMIs are routed to IDT vector 2 */ - | ((this_cpu != 0) - ? APIC_LVT_MASKED /* mask on all but bootstrap CPU */ - : 0) /* bootstrap CPU (0) receives NMIs */ - ); - - /* Setup LVT[5] = Internal APIC Error Detector Interrupt */ - apic_write(APIC_LVTERR, 0 - | APIC_DM_FIXED /* route to fixed IDT vector */ - | APIC_ERROR_VECTOR /* IDT vector to route to */ - ); - apic_write(APIC_ESR, 0); /* spec says to clear after enabling LVTERR */ -} - -void -lapic_set_timer(uint32_t count) -{ - uint32_t lvt; - - /* Setup Divide Count Register to use the bus frequency directly. */ - apic_write(APIC_TDCR, APIC_TDR_DIV_1); - - /* Program the initial count register */ - apic_write(APIC_TMICT, count); - - /* Enable the local APIC timer */ - lvt = apic_read(APIC_LVTT); - lvt &= ~APIC_LVT_MASKED; - lvt |= APIC_LVT_TIMER_PERIODIC; - apic_write(APIC_LVTT, lvt); -} - -void -lapic_stop_timer(void) -{ - uint32_t lvt; - - /* Set the initial count to 0 */ - apic_write(APIC_TMICT, 0); - - /* Enable the local APIC timer */ - lvt = apic_read(APIC_LVTT); - lvt |= APIC_LVT_MASKED; - apic_write(APIC_LVTT, lvt); -} - -/** - * Detects the local APIC reference bus clock. The only sure-fire way to do - * this is to depend on some other absolute timing source. This function uses - * the CPU's cycle counter and the previously detected CPU clock frequency. - * - * NOTE: This assumes that the CPU's clock frequency has already been detected. - * (i.e., cpu_info[cpu_id()].arch.tsc_khz has been initialized. - */ -unsigned int __init -lapic_calibrate_timer(void) -{ - const unsigned int tick_count = 100000000; - cycles_t tsc_start, tsc_now; - uint32_t apic_start, apic_now; - unsigned int apic_Hz; - - /* Start the APIC counter running for calibration */ - lapic_set_timer(4000000000); - - apic_start = apic_read(APIC_TMCCT); - tsc_start = get_cycles_sync(); - - /* Spin until enough ticks for a meaningful result have elapsed */ - do { - apic_now = apic_read(APIC_TMCCT); - tsc_now = get_cycles_sync(); - } while ( ((tsc_now - tsc_start) < tick_count) && - ((apic_start - apic_now) < tick_count) ); - - apic_Hz = (apic_start - apic_now) * 1000L * - cpu_info[this_cpu].arch.tsc_khz / (tsc_now - tsc_start); - - lapic_stop_timer(); - - return (apic_Hz / 1000); -} - -static uint32_t -lapic_wait4_icr_idle(void) -{ - uint32_t send_status; - int timeout; - - /* Wait up to 100 milliseconds */ - timeout = 0; - do { - send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY; - if (!send_status) - break; - udelay(100); - } while (timeout++ < 1000); - - return send_status; -} - -/** - * Returns the number of entries in the Local Vector Table minus one. - * - * This should return 5 or higher on all x86_64 CPUs. - * 6 is returned if the APIC Thermal Interrupt is supported, 5 otherwise. - */ -static uint32_t -lapic_get_maxlvt(void) -{ - return GET_APIC_MAXLVT(apic_read(APIC_LVR)); -} - -/** - * Sends an INIT inter-processor interrupt. - * This is used during bootstrap to wakeup the AP CPUs. - */ -void __init -lapic_send_init_ipi(unsigned int cpu) -{ - uint32_t status; - unsigned int apic_id = cpu_info[cpu].arch.apic_id; - - /* Turn on INIT at target CPU */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT - | APIC_DM_INIT); - status = lapic_wait4_icr_idle(); - if (status) - panic("INIT IPI ERROR: failed to assert INIT. (%x)", status); - mdelay(10); - - /* Turn off INIT at target CPU */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id)); - apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); - status = lapic_wait4_icr_idle(); - if (status) - panic("INIT IPI ERROR: failed to deassert INIT. (%x)", status); -} - -/** - * Send a STARTUP inter-processor interrupt. - * This is used during bootstrap to wakeup the AP CPUs. - */ -void __init -lapic_send_startup_ipi( - unsigned int cpu, /* Logical CPU ID */ - unsigned long start_rip /* Physical addr */ -) -{ - uint32_t status; - unsigned int maxlvt = lapic_get_maxlvt(); - unsigned int apic_id = cpu_info[cpu].arch.apic_id; - - /* Clear errors */ - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); - - /* Set target CPU */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id)); - - /* Send Startup IPI to target CPU */ - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id)); - apic_write(APIC_ICR, APIC_DM_STARTUP | (start_rip >> 12)); - udelay(300); /* Give AP CPU some time to accept the IPI */ - status = lapic_wait4_icr_idle(); - if (status) - panic("STARTUP IPI ERROR: failed to send. (%x)", status); - udelay(300); /* Give AP CPU some time to accept the IPI */ - - /* Fixup for Pentium erratum 3AP, clear errors */ - if (maxlvt > 3) - apic_write(APIC_ESR, 0); - - /* Verify that IPI was accepted */ - status = (apic_read(APIC_ESR) & 0xEF); - if (status) - panic("STARTUP IPI ERROR: failed to accept. (%x)", status); -} - -/** - * Sends an inter-processor interrupt (IPI) to the specified CPU. - * Note that the IPI has not necessarily been delivered when this function - * returns. - */ -void -lapic_send_ipi( - unsigned int cpu, /* Logical CPU ID */ - unsigned int vector /* Interrupt vector to send */ -) -{ - uint32_t status; - unsigned int apic_id; - - /* Wait for idle */ - status = lapic_wait4_icr_idle(); - if (status) - panic("lapic_wait4_icr_idle() timed out. (%x)", status); - - /* Set target CPU */ - apic_id = cpu_info[cpu].arch.apic_id; - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id)); - - /* Send the IPI */ - if (unlikely(vector == NMI_VECTOR)) - apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_NMI); - else - apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_FIXED|vector); -} - -/** - * Converts an entry in a local APIC's Local Vector Table to a - * human-readable string. - */ -static char * -lvt_stringify(uint32_t entry, char *buf) -{ - uint32_t delivery_mode = GET_APIC_DELIVERY_MODE(entry); - - if (delivery_mode == APIC_MODE_FIXED) { - sprintf(buf, "FIXED -> IDT_VECTOR %d", - entry & APIC_VECTOR_MASK - ); - } else if (delivery_mode == APIC_MODE_NMI) { - sprintf(buf, "NMI -> IDT VECTOR 2"); - } else if (delivery_mode == APIC_MODE_EXTINT) { - sprintf(buf, "ExtINT, hooked to old 8259A PIC"); - } else { - sprintf(buf, "UNKNOWN"); - } - - if (entry & APIC_LVT_MASKED) - strcat(buf, ", MASKED"); - - return buf; -} - -/** - * Prints various local APIC registers of interest to the console. - */ -void -lapic_dump(void) -{ - char buf[128]; - - printk(KERN_DEBUG "LOCAL APIC DUMP (LOGICAL CPU #%d):\n", this_cpu); - - /* - * Lead off with the important stuff... - */ - printk(KERN_DEBUG - " ID: 0x%08x (id=%d)\n", - apic_read(APIC_ID), - GET_APIC_ID(apic_read(APIC_ID)) - ); - printk(KERN_DEBUG - " VER: 0x%08x (version=0x%x, max_lvt=%d)\n", - apic_read(APIC_LVR), - GET_APIC_VERSION(apic_read(APIC_LVR)), - GET_APIC_MAXLVT(apic_read(APIC_LVR)) - ); - printk(KERN_DEBUG - " ESR: 0x%08x (Error Status Reg, non-zero is bad)\n", - apic_read(APIC_ESR) - ); - printk(KERN_DEBUG - " SVR: 0x%08x (Spurious vector=%d, %s)\n", - apic_read(APIC_SPIV), - apic_read(APIC_SPIV) & APIC_VECTOR_MASK, - (apic_read(APIC_SPIV) & APIC_SPIV_APIC_ENABLED) - ? "APIC IS ENABLED" - : "APIC IS DISABLED" - ); - - /* - * Local Vector Table - */ - printk(KERN_DEBUG " Local Vector Table Entries:\n"); - printk(KERN_DEBUG " LVT[0] Timer: 0x%08x (%s)\n", - apic_read(APIC_LVTT), - lvt_stringify(apic_read(APIC_LVTT), buf) - ); - printk(KERN_DEBUG " LVT[1] Thermal: 0x%08x (%s)\n", - apic_read(APIC_LVTTHMR), - lvt_stringify(apic_read(APIC_LVTTHMR), buf) - ); - printk(KERN_DEBUG " LVT[2] Perf Cnt: 0x%08x (%s)\n", - apic_read(APIC_LVTPC), - lvt_stringify(apic_read(APIC_LVTPC), buf) - ); - printk(KERN_DEBUG " LVT[3] LINT0 Pin: 0x%08x (%s)\n", - apic_read(APIC_LVT0), - lvt_stringify(apic_read(APIC_LVT0), buf) - ); - printk(KERN_DEBUG " LVT[4] LINT1 Pin: 0x%08x (%s)\n", - apic_read(APIC_LVT1), - lvt_stringify(apic_read(APIC_LVT1), buf) - ); - printk(KERN_DEBUG " LVT[5] Error: 0x%08x (%s)\n", - apic_read(APIC_LVTERR), - lvt_stringify(apic_read(APIC_LVTERR), buf) - ); - - /* - * APIC timer configuration registers - */ - printk(KERN_DEBUG " Local APIC Timer:\n"); - printk(KERN_DEBUG " DCR (Divide Config Reg): 0x%08x\n", - apic_read(APIC_TDCR) - ); - printk(KERN_DEBUG " ICT (Initial Count Reg): 0x%08x\n", - apic_read(APIC_TMICT) - ); - printk(KERN_DEBUG " CCT (Current Count Reg): 0x%08x\n", - apic_read(APIC_TMCCT) - ); - - /* - * Logical APIC addressing mode registers - */ - printk(KERN_DEBUG " Logical Addressing Mode Information:\n"); - printk(KERN_DEBUG " LDR (Logical Dest Reg): 0x%08x (id=%d)\n", - apic_read(APIC_LDR), - GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)) - ); - printk(KERN_DEBUG " DFR (Dest Format Reg): 0x%08x (%s)\n", - apic_read(APIC_DFR), - (apic_read(APIC_DFR) == APIC_DFR_FLAT) ? "FLAT" : "CLUSTER" - ); - - /* - * Task/processor/arbitration priority registers - */ - printk(KERN_DEBUG " Task/Processor/Arbitration Priorities:\n"); - printk(KERN_DEBUG " TPR (Task Priority Reg): 0x%08x\n", - apic_read(APIC_TASKPRI) - ); - printk(KERN_DEBUG " PPR (Processor Priority Reg): 0x%08x\n", - apic_read(APIC_PROCPRI) - ); - printk(KERN_DEBUG " APR (Arbitration Priority Reg): 0x%08x\n", - apic_read(APIC_ARBPRI) - ); -} -