123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- /*
- * Copyright 2012 Tilera Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
- #define VDSO_BUILD /* avoid some shift warnings for -m32 in <asm/page.h> */
- #include <linux/time.h>
- #include <asm/timex.h>
- #include <asm/vdso.h>
- #if CHIP_HAS_SPLIT_CYCLE()
- static inline cycles_t get_cycles_inline(void)
- {
- unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH);
- unsigned int low = __insn_mfspr(SPR_CYCLE_LOW);
- unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH);
- while (unlikely(high != high2)) {
- low = __insn_mfspr(SPR_CYCLE_LOW);
- high = high2;
- high2 = __insn_mfspr(SPR_CYCLE_HIGH);
- }
- return (((cycles_t)high) << 32) | low;
- }
- #define get_cycles get_cycles_inline
- #endif
- /*
- * Find out the vDSO data page address in the process address space.
- */
- inline unsigned long get_datapage(void)
- {
- unsigned long ret;
- /* vdso data page located in the 2nd vDSO page. */
- asm volatile ("lnk %0" : "=r"(ret));
- ret &= ~(PAGE_SIZE - 1);
- ret += PAGE_SIZE;
- return ret;
- }
- int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
- {
- cycles_t cycles;
- unsigned long count, sec, ns;
- volatile struct vdso_data *vdso_data;
- vdso_data = (struct vdso_data *)get_datapage();
- /* The use of the timezone is obsolete, normally tz is NULL. */
- if (unlikely(tz != NULL)) {
- while (1) {
- /* Spin until the update finish. */
- count = vdso_data->tz_update_count;
- if (count & 1)
- continue;
- tz->tz_minuteswest = vdso_data->tz_minuteswest;
- tz->tz_dsttime = vdso_data->tz_dsttime;
- /* Check whether updated, read again if so. */
- if (count == vdso_data->tz_update_count)
- break;
- }
- }
- if (unlikely(tv == NULL))
- return 0;
- while (1) {
- /* Spin until the update finish. */
- count = vdso_data->tb_update_count;
- if (count & 1)
- continue;
- cycles = (get_cycles() - vdso_data->xtime_tod_stamp);
- ns = (cycles * vdso_data->mult) >> vdso_data->shift;
- sec = vdso_data->xtime_clock_sec;
- ns += vdso_data->xtime_clock_nsec;
- if (ns >= NSEC_PER_SEC) {
- ns -= NSEC_PER_SEC;
- sec += 1;
- }
- /* Check whether updated, read again if so. */
- if (count == vdso_data->tb_update_count)
- break;
- }
- tv->tv_sec = sec;
- tv->tv_usec = ns / 1000;
- return 0;
- }
- int gettimeofday(struct timeval *tv, struct timezone *tz)
- __attribute__((weak, alias("__vdso_gettimeofday")));
|