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

📄 apic.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
                    smp_found_config = 0;                    skip_ioapic_setup = 1;                    goto fake_ioapic_page;                }            } else {fake_ioapic_page:                ioapic_phys = __pa(alloc_xenheap_page());                clear_page(__va(ioapic_phys));            }            set_fixmap_nocache(idx, ioapic_phys);            apic_printk(APIC_VERBOSE, "mapped IOAPIC to %08lx (%08lx)\n",                        __fix_to_virt(idx), ioapic_phys);            idx++;        }    }#endif}/***************************************************************************** * APIC calibration *  * The APIC is programmed in bus cycles. * Timeout values should specified in real time units. * The "cheapest" time source is the cyclecounter. *  * Thus, we need a mappings from: bus cycles <- cycle counter <- system time *  * The calibration is currently a bit shoddy since it requires the external * timer chip to generate periodic timer interupts.  *****************************************************************************//* used for system time scaling */static unsigned long bus_freq;    /* KAF: pointer-size avoids compile warns. */static u32           bus_cycle;   /* length of one bus cycle in pico-seconds */static u32           bus_scale;   /* scaling factor convert ns to bus cycles *//* * The timer chip is already set up at HZ interrupts per second here, * but we do not accept timer interrupts yet. We only allow the BP * to calibrate. */static unsigned int __init get_8254_timer_count(void){    /*extern spinlock_t i8253_lock;*/    /*unsigned long flags;*/    unsigned int count;    /*spin_lock_irqsave(&i8253_lock, flags);*/    outb_p(0x00, PIT_MODE);    count = inb_p(PIT_CH0);    count |= inb_p(PIT_CH0) << 8;    /*spin_unlock_irqrestore(&i8253_lock, flags);*/    return count;}/* next tick in 8254 can be caught by catching timer wraparound */static void __init wait_8254_wraparound(void){    unsigned int curr_count, prev_count;        curr_count = get_8254_timer_count();    do {        prev_count = curr_count;        curr_count = get_8254_timer_count();        /* workaround for broken Mercury/Neptune */        if (prev_count >= curr_count + 0x100)            curr_count = get_8254_timer_count();            } while (prev_count >= curr_count);}/* * Default initialization for 8254 timers. If we use other timers like HPET, * we override this later */void (*wait_timer_tick)(void) __initdata = wait_8254_wraparound;/* * This function sets up the local APIC timer, with a timeout of * 'clocks' APIC bus clock. During calibration we actually call * this function twice on the boot CPU, once with a bogus timeout * value, second time for real. The other (noncalibrating) CPUs * call this function only once, with the real, calibrated value. * * We do reads before writes even if unnecessary, to get around the * P5 APIC double write bug. */#define APIC_DIVISOR 1void __setup_APIC_LVTT(unsigned int clocks){    unsigned int lvtt_value, tmp_value, ver;    ver = GET_APIC_VERSION(apic_read(APIC_LVR));    /* NB. Xen uses local APIC timer in one-shot mode. */    lvtt_value = /*APIC_LVT_TIMER_PERIODIC |*/ LOCAL_TIMER_VECTOR;    if (!APIC_INTEGRATED(ver))        lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);    apic_write_around(APIC_LVTT, lvtt_value);    tmp_value = apic_read(APIC_TDCR);    apic_write_around(APIC_TDCR, (tmp_value | APIC_TDR_DIV_1));    apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);}static void __devinit setup_APIC_timer(unsigned int clocks){    unsigned long flags;    local_irq_save(flags);    __setup_APIC_LVTT(clocks);    local_irq_restore(flags);}/* * In this function we calibrate APIC bus clocks to the external * timer. Unfortunately we cannot use jiffies and the timer irq * to calibrate, since some later bootup code depends on getting * the first irq? Ugh. * * We want to do the calibration only once since we * want to have local timer irqs syncron. CPUs connected * by the same APIC bus have the very same bus frequency. * And we want to have irqs off anyways, no accidental * APIC irq that way. */int __init calibrate_APIC_clock(void){    unsigned long long t1 = 0, t2 = 0;    long tt1, tt2;    long result;    int i;    const int LOOPS = HZ/10;    apic_printk(APIC_VERBOSE, "calibrating APIC timer ...\n");    /*     * Put whatever arbitrary (but long enough) timeout     * value into the APIC clock, we just want to get the     * counter running for calibration.     */    __setup_APIC_LVTT(1000000000);    /*     * The timer chip counts down to zero. Let's wait     * for a wraparound to start exact measurement:     * (the current tick might have been already half done)     */    wait_timer_tick();    /*     * We wrapped around just now. Let's start:     */    if (cpu_has_tsc)        rdtscll(t1);    tt1 = apic_read(APIC_TMCCT);    /*     * Let's wait LOOPS wraprounds:     */    for (i = 0; i < LOOPS; i++)        wait_timer_tick();    tt2 = apic_read(APIC_TMCCT);    if (cpu_has_tsc)        rdtscll(t2);    /*     * The APIC bus clock counter is 32 bits only, it     * might have overflown, but note that we use signed     * longs, thus no extra care needed.     *     * underflown to be exact, as the timer counts down ;)     */    result = (tt1-tt2)*APIC_DIVISOR/LOOPS;    if (cpu_has_tsc)        apic_printk(APIC_VERBOSE, "..... CPU clock speed is "                    "%ld.%04ld MHz.\n",                    ((long)(t2-t1)/LOOPS)/(1000000/HZ),                    ((long)(t2-t1)/LOOPS)%(1000000/HZ));    apic_printk(APIC_VERBOSE, "..... host bus clock speed is "                "%ld.%04ld MHz.\n",                result/(1000000/HZ),                result%(1000000/HZ));    /* set up multipliers for accurate timer code */    bus_freq   = result*HZ;    bus_cycle  = (u32) (1000000000000LL/bus_freq); /* in pico seconds */    bus_scale  = (1000*262144)/bus_cycle;    apic_printk(APIC_VERBOSE, "..... bus_scale = 0x%08X\n", bus_scale);    /* reset APIC to zero timeout value */    __setup_APIC_LVTT(0);    return result;}u32 get_apic_bus_cycle(void){    return bus_cycle;}static unsigned int calibration_result;void __init setup_boot_APIC_clock(void){    unsigned long flags;    apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n");    using_apic_timer = 1;    local_irq_save(flags);    calibration_result = calibrate_APIC_clock();    /*     * Now set up the timer for real.     */    setup_APIC_timer(calibration_result);        local_irq_restore(flags);}void __devinit setup_secondary_APIC_clock(void){    setup_APIC_timer(calibration_result);}void disable_APIC_timer(void){    if (using_apic_timer) {        unsigned long v;                v = apic_read(APIC_LVTT);        apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);    }}void enable_APIC_timer(void){    if (using_apic_timer) {        unsigned long v;                v = apic_read(APIC_LVTT);        apic_write_around(APIC_LVTT, v & ~APIC_LVT_MASKED);    }}#undef APIC_DIVISOR/* * reprogram the APIC timer. Timeoutvalue is in ns from start of boot * returns 1 on success * returns 0 if the timeout value is too small or in the past. */int reprogram_timer(s_time_t timeout){    s_time_t    now;    s_time_t    expire;    u64         apic_tmict;    /*     * If we don't have local APIC then we just poll the timer list off the     * PIT interrupt.     */    if ( !cpu_has_apic )        return 1;    /*     * We use this value because we don't trust zero (we think it may just     * cause an immediate interrupt). At least this is guaranteed to hold it     * off for ages (esp. since the clock ticks on bus clock, not cpu clock!).     */    if ( timeout == 0 )    {        apic_tmict = 0xffffffff;        goto reprogram;    }    now = NOW();    expire = timeout - now; /* value from now */    if ( expire <= 0 )    {        Dprintk("APICT[%02d] Timeout in the past 0x%08X%08X > 0x%08X%08X\n",                 smp_processor_id(), (u32)(now>>32),                 (u32)now, (u32)(timeout>>32),(u32)timeout);        return 0;    }    /* conversion to bus units */    apic_tmict = (((u64)bus_scale) * expire)>>18;    if ( apic_tmict >= 0xffffffff )    {        Dprintk("APICT[%02d] Timeout value too large\n", smp_processor_id());        apic_tmict = 0xffffffff;    }    if ( apic_tmict == 0 )    {        Dprintk("APICT[%02d] timeout value too small\n", smp_processor_id());        return 0;    } reprogram:    /* Program the timer. */    apic_write(APIC_TMICT, (unsigned long)apic_tmict);    return 1;}fastcall void smp_apic_timer_interrupt(struct cpu_user_regs * regs){    ack_APIC_irq();    perfc_incr(apic_timer);    raise_softirq(TIMER_SOFTIRQ);}/* * This interrupt should _never_ happen with our APIC/SMP architecture */fastcall void smp_spurious_interrupt(struct cpu_user_regs *regs){    unsigned long v;    irq_enter();    /*     * Check if this really is a spurious interrupt and ACK it     * if it is a vectored one.  Just in case...     * Spurious interrupts should not be ACKed.     */    v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));    if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))        ack_APIC_irq();    /* see sw-dev-man vol 3, chapter 7.4.13.5 */    printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n",           smp_processor_id());    irq_exit();}/* * This interrupt should never happen with our APIC/SMP architecture */fastcall void smp_error_interrupt(struct cpu_user_regs *regs){    unsigned long v, v1;    irq_enter();    /* First tickle the hardware, only then report what went on. -- REW */    v = apic_read(APIC_ESR);    apic_write(APIC_ESR, 0);    v1 = apic_read(APIC_ESR);    ack_APIC_irq();    atomic_inc(&irq_err_count);    /* Here is what the APIC error bits mean:       0: Send CS error       1: Receive CS error       2: Send accept error       3: Receive accept error       4: Reserved       5: Send illegal vector       6: Received illegal vector       7: Illegal register address    */    printk (KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n",            smp_processor_id(), v , v1);    irq_exit();}/* * This interrupt handles performance counters interrupt */fastcall void smp_pmu_apic_interrupt(struct cpu_user_regs *regs){    ack_APIC_irq();    hvm_do_pmu_interrupt(regs);}/* * This initializes the IO-APIC and APIC hardware if this is * a UP kernel. */int __init APIC_init_uniprocessor (void){    if (enable_local_apic < 0)        clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);    if (!smp_found_config && !cpu_has_apic)        return -1;    /*     * Complain if the BIOS pretends there is one.     */    if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {        printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",               boot_cpu_physical_apicid);        clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);        return -1;    }    verify_local_APIC();    connect_bsp_APIC();    /*     * Hack: In case of kdump, after a crash, kernel might be booting     * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid     * might be zero if read from MP tables. Get it from LAPIC.     */#ifdef CONFIG_CRASH_DUMP    boot_cpu_physical_apicid = get_apic_id();#endif    phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);    setup_local_APIC();    if (nmi_watchdog == NMI_LOCAL_APIC)        check_nmi_watchdog();#ifdef CONFIG_X86_IO_APIC    if (smp_found_config)        if (!skip_ioapic_setup && nr_ioapics)            setup_IO_APIC();#endif    setup_boot_APIC_clock();    return 0;}

⌨️ 快捷键说明

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