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

📄 hpet.c

📁 xen虚拟机源代码安装包
💻 C
字号:
/****************************************************************************** * arch/x86/hpet.c *  * HPET management. */#include <xen/config.h>#include <xen/errno.h>#include <xen/time.h>#include <xen/timer.h>#include <xen/smp.h>#include <xen/softirq.h>#include <asm/fixmap.h>#include <asm/div64.h>#include <asm/hpet.h>#define STIME_MAX ((s_time_t)((uint64_t)~0ull>>1))#define MAX_DELTA_NS MILLISECS(10*1000)#define MIN_DELTA_NS MICROSECS(20)struct hpet_event_channel{    unsigned long mult;    int           shift;    s_time_t      next_event;    cpumask_t     cpumask;    spinlock_t    lock;    void          (*event_handler)(struct hpet_event_channel *);};static struct hpet_event_channel hpet_event;unsigned long hpet_address;/* * Calculate a multiplication factor for scaled math, which is used to convert * nanoseconds based values to clock ticks: * * clock_ticks = (nanoseconds * factor) >> shift. * * div_sc is the rearranged equation to calculate a factor from a given clock * ticks / nanoseconds ratio: * * factor = (clock_ticks << shift) / nanoseconds */static inline unsigned long div_sc(unsigned long ticks, unsigned long nsec,                                   int shift){    uint64_t tmp = ((uint64_t)ticks) << shift;    do_div(tmp, nsec);    return (unsigned long) tmp;}/* * Convert nanoseconds based values to clock ticks: * * clock_ticks = (nanoseconds * factor) >> shift. */static inline unsigned long ns2ticks(unsigned long nsec, int shift,                                     unsigned long factor){    uint64_t tmp = ((uint64_t)nsec * factor) >> shift;    return (unsigned long) tmp;}static int hpet_legacy_next_event(unsigned long delta){    uint32_t cnt, cmp;    unsigned long flags;    local_irq_save(flags);    cnt = hpet_read32(HPET_COUNTER);    cmp = cnt + delta;    hpet_write32(cmp, HPET_T0_CMP);    cmp = hpet_read32(HPET_COUNTER);    local_irq_restore(flags);    /* Are we within two ticks of the deadline passing? Then we may miss. */    return ((cmp + 2 - cnt) > delta) ? -ETIME : 0;}static int reprogram_hpet_evt_channel(    struct hpet_event_channel *ch,    s_time_t expire, s_time_t now, int force){    int64_t delta;    int ret;    if ( unlikely(expire < 0) )    {        printk(KERN_DEBUG "reprogram: expire < 0\n");        return -ETIME;    }    delta = expire - now;    if ( (delta <= 0) && !force )        return -ETIME;    ch->next_event = expire;    delta = min_t(int64_t, delta, MAX_DELTA_NS);    delta = max_t(int64_t, delta, MIN_DELTA_NS);    delta = ns2ticks(delta, ch->shift, ch->mult);    ret = hpet_legacy_next_event(delta);    while ( ret && force )    {        delta += delta;        ret = hpet_legacy_next_event(delta);    }    return ret;}static int evt_do_broadcast(cpumask_t mask){    int ret = 0, cpu = smp_processor_id();    if ( cpu_isset(cpu, mask) )    {        cpu_clear(cpu, mask);        raise_softirq(TIMER_SOFTIRQ);        ret = 1;    }    if ( !cpus_empty(mask) )    {       cpumask_raise_softirq(mask, TIMER_SOFTIRQ);       ret = 1;    }    return ret;}static void handle_hpet_broadcast(struct hpet_event_channel *ch){    cpumask_t mask;    s_time_t now, next_event;    int cpu;    spin_lock(&ch->lock);again:    ch->next_event = STIME_MAX;    next_event = STIME_MAX;    mask = (cpumask_t)CPU_MASK_NONE;    now = NOW();    /* find all expired events */    for_each_cpu_mask(cpu, ch->cpumask)    {        if ( per_cpu(timer_deadline, cpu) <= now )            cpu_set(cpu, mask);        else if ( per_cpu(timer_deadline, cpu) < next_event )            next_event = per_cpu(timer_deadline, cpu);    }    /* wakeup the cpus which have an expired event. */    evt_do_broadcast(mask);    if ( next_event != STIME_MAX )    {        if ( reprogram_hpet_evt_channel(ch, next_event, now, 0) )            goto again;    }    spin_unlock(&ch->lock);}void hpet_broadcast_init(void){    u64 hpet_rate;    u32 hpet_id, cfg;    hpet_rate = hpet_setup();    if ( hpet_rate == 0 )        return;    hpet_id = hpet_read32(HPET_ID);    if ( !(hpet_id & HPET_ID_LEGSUP) )        return;    /* Start HPET legacy interrupts */    cfg = hpet_read32(HPET_CFG);    cfg |= HPET_CFG_LEGACY;    hpet_write32(cfg, HPET_CFG);    /* set HPET T0 as oneshot */    cfg = hpet_read32(HPET_T0_CFG);    cfg &= ~HPET_TN_PERIODIC;    cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;    hpet_write32(cfg, HPET_T0_CFG);    /*     * The period is a femto seconds value. We need to calculate the scaled     * math multiplication factor for nanosecond to hpet tick conversion.     */    hpet_event.mult = div_sc((unsigned long)hpet_rate, 1000000000ul, 32);    hpet_event.shift = 32;    hpet_event.next_event = STIME_MAX;    hpet_event.event_handler = handle_hpet_broadcast;    spin_lock_init(&hpet_event.lock);}void hpet_broadcast_enter(void){    struct hpet_event_channel *ch = &hpet_event;    cpu_set(smp_processor_id(), ch->cpumask);    spin_lock(&ch->lock);    /* reprogram if current cpu expire time is nearer */    if ( this_cpu(timer_deadline) < ch->next_event )        reprogram_hpet_evt_channel(ch, this_cpu(timer_deadline), NOW(), 1);    spin_unlock(&ch->lock);}void hpet_broadcast_exit(void){    struct hpet_event_channel *ch = &hpet_event;    int cpu = smp_processor_id();    if ( cpu_test_and_clear(cpu, ch->cpumask) )        reprogram_timer(per_cpu(timer_deadline, cpu));}int hpet_broadcast_is_available(void){    return (hpet_event.event_handler == handle_hpet_broadcast);}int hpet_legacy_irq_tick(void){    if ( !hpet_event.event_handler )        return 0;    hpet_event.event_handler(&hpet_event);    return 1;}u64 hpet_setup(void){    static u64 hpet_rate;    static int initialised;    u32 hpet_id, hpet_period, cfg;    int i;    if ( initialised )        return hpet_rate;    initialised = 1;    if ( hpet_address == 0 )        return 0;    set_fixmap_nocache(FIX_HPET_BASE, hpet_address);    hpet_id = hpet_read32(HPET_ID);    if ( hpet_id == 0 )    {        printk("BAD HPET vendor id.\n");        return 0;    }    /* Check for sane period (100ps <= period <= 100ns). */    hpet_period = hpet_read32(HPET_PERIOD);    if ( (hpet_period > 100000000) || (hpet_period < 100000) )    {        printk("BAD HPET period %u.\n", hpet_period);        return 0;    }    cfg = hpet_read32(HPET_CFG);    cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);    hpet_write32(cfg, HPET_CFG);    for ( i = 0; i <= ((hpet_id >> 8) & 31); i++ )    {        cfg = hpet_read32(HPET_T0_CFG + i*0x20);        cfg &= ~HPET_TN_ENABLE;        hpet_write32(cfg & ~HPET_TN_ENABLE, HPET_T0_CFG);    }    cfg = hpet_read32(HPET_CFG);    cfg |= HPET_CFG_ENABLE;    hpet_write32(cfg, HPET_CFG);    hpet_rate = 1000000000000000ULL; /* 10^15 */    (void)do_div(hpet_rate, hpet_period);    return hpet_rate;}

⌨️ 快捷键说明

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