--- zzzz-none-000/linux-2.6.19.2/arch/powerpc/kernel/time.c 2007-01-10 19:10:37.000000000 +0000 +++ davinci-8020-5504/linux-2.6.19.2/arch/powerpc/kernel/time.c 2007-01-11 07:38:19.000000000 +0000 @@ -220,8 +220,11 @@ */ struct cpu_purr_data { int initialized; /* thread is running */ + u64 tb0; /* timebase at origin time */ + u64 purr0; /* PURR at origin time */ u64 tb; /* last TB value read */ u64 purr; /* last PURR value read */ + u64 stolen; /* stolen time so far */ spinlock_t lock; }; @@ -231,8 +234,10 @@ { struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data); - p->tb = mftb(); - p->purr = mfspr(SPRN_PURR); + p->tb0 = mftb(); + p->purr0 = mfspr(SPRN_PURR); + p->tb = p->tb0; + p->purr = 0; wmb(); p->initialized = 1; } @@ -253,24 +258,37 @@ void calculate_steal_time(void) { - u64 tb, purr; + u64 tb, purr, t0; s64 stolen; - struct cpu_purr_data *pme; + struct cpu_purr_data *p0, *pme, *phim; + int cpu; if (!cpu_has_feature(CPU_FTR_PURR)) return; - pme = &per_cpu(cpu_purr_data, smp_processor_id()); + cpu = smp_processor_id(); + pme = &per_cpu(cpu_purr_data, cpu); if (!pme->initialized) return; /* this can happen in early boot */ - spin_lock(&pme->lock); + p0 = &per_cpu(cpu_purr_data, cpu & ~1); + phim = &per_cpu(cpu_purr_data, cpu ^ 1); + spin_lock(&p0->lock); tb = mftb(); - purr = mfspr(SPRN_PURR); - stolen = (tb - pme->tb) - (purr - pme->purr); - if (stolen > 0) + purr = mfspr(SPRN_PURR) - pme->purr0; + if (!phim->initialized || !cpu_online(cpu ^ 1)) { + stolen = (tb - pme->tb) - (purr - pme->purr); + } else { + t0 = pme->tb0; + if (phim->tb0 < t0) + t0 = phim->tb0; + stolen = phim->tb - t0 - phim->purr - purr - p0->stolen; + } + if (stolen > 0) { account_steal_time(current, stolen); + p0->stolen += stolen; + } pme->tb = tb; pme->purr = purr; - spin_unlock(&pme->lock); + spin_unlock(&p0->lock); } /* @@ -279,17 +297,30 @@ */ static void snapshot_purr(void) { - struct cpu_purr_data *pme; + int cpu; + u64 purr; + struct cpu_purr_data *p0, *pme, *phim; unsigned long flags; if (!cpu_has_feature(CPU_FTR_PURR)) return; - pme = &per_cpu(cpu_purr_data, smp_processor_id()); - spin_lock_irqsave(&pme->lock, flags); - pme->tb = mftb(); - pme->purr = mfspr(SPRN_PURR); + cpu = smp_processor_id(); + pme = &per_cpu(cpu_purr_data, cpu); + p0 = &per_cpu(cpu_purr_data, cpu & ~1); + phim = &per_cpu(cpu_purr_data, cpu ^ 1); + spin_lock_irqsave(&p0->lock, flags); + pme->tb = pme->tb0 = mftb(); + purr = mfspr(SPRN_PURR); + if (!phim->initialized) { + pme->purr = 0; + pme->purr0 = purr; + } else { + /* set p->purr and p->purr0 for no change in p0->stolen */ + pme->purr = phim->tb - phim->tb0 - phim->purr - p0->stolen; + pme->purr0 = purr - pme->purr; + } pme->initialized = 1; - spin_unlock_irqrestore(&pme->lock, flags); + spin_unlock_irqrestore(&p0->lock, flags); } #endif /* CONFIG_PPC_SPLPAR */ @@ -1014,6 +1045,48 @@ set_dec(tb_ticks_per_jiffy); } +#ifdef CONFIG_RTC_CLASS +static int set_rtc_class_time(struct rtc_time *tm) +{ + int err; + struct class_device *class_dev = + rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + + if (class_dev == NULL) + return -ENODEV; + + err = rtc_set_time(class_dev, tm); + + rtc_class_close(class_dev); + + return 0; +} + +static void get_rtc_class_time(struct rtc_time *tm) +{ + int err; + struct class_device *class_dev = + rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + + if (class_dev == NULL) + return; + + err = rtc_read_time(class_dev, tm); + + rtc_class_close(class_dev); + + return; +} + +int __init rtc_class_hookup(void) +{ + ppc_md.get_rtc_time = get_rtc_class_time; + ppc_md.set_rtc_time = set_rtc_class_time; + + return 0; +} +#endif /* CONFIG_RTC_CLASS */ + #define FEBRUARY 2 #define STARTOFTIME 1970