linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / sparc64 / kernel / time.c
index e55b5c6..0af3b83 100644 (file)
@@ -30,8 +30,6 @@
 #include <linux/cpufreq.h>
 #include <linux/percpu.h>
 #include <linux/profile.h>
-#include <linux/miscdevice.h>
-#include <linux/rtc.h>
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
@@ -47,7 +45,6 @@
 #include <asm/smp.h>
 #include <asm/sections.h>
 #include <asm/cpudata.h>
-#include <asm/uaccess.h>
 
 DEFINE_SPINLOCK(mostek_lock);
 DEFINE_SPINLOCK(rtc_lock);
@@ -196,22 +193,16 @@ struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations;
 
 static void stick_init_tick(unsigned long offset)
 {
-       /* Writes to the %tick and %stick register are not
-        * allowed on sun4v.  The Hypervisor controls that
-        * bit, per-strand.
-        */
-       if (tlb_type != hypervisor) {
-               tick_disable_protection();
-
-               /* Let the user get at STICK too. */
-               __asm__ __volatile__(
-               "       rd      %%asr24, %%g2\n"
-               "       andn    %%g2, %0, %%g2\n"
-               "       wr      %%g2, 0, %%asr24"
-               : /* no outputs */
-               : "r" (TICK_PRIV_BIT)
-               : "g1", "g2");
-       }
+       tick_disable_protection();
+
+       /* Let the user get at STICK too. */
+       __asm__ __volatile__(
+       "       rd      %%asr24, %%g2\n"
+       "       andn    %%g2, %0, %%g2\n"
+       "       wr      %%g2, 0, %%asr24"
+       : /* no outputs */
+       : "r" (TICK_PRIV_BIT)
+       : "g1", "g2");
 
        __asm__ __volatile__(
        "       rd      %%asr24, %%g1\n"
@@ -641,8 +632,23 @@ static void __init set_system_time(void)
                mon = MSTK_REG_MONTH(mregs);
                year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
        } else {
+               int i;
+
                /* Dallas 12887 RTC chip. */
 
+               /* Stolen from arch/i386/kernel/time.c, see there for
+                * credits and descriptive comments.
+                */
+               for (i = 0; i < 1000000; i++) {
+                       if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+                               break;
+                       udelay(10);
+               }
+               for (i = 0; i < 1000000; i++) {
+                       if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+                               break;
+                       udelay(10);
+               }
                do {
                        sec  = CMOS_READ(RTC_SECONDS);
                        min  = CMOS_READ(RTC_MINUTES);
@@ -651,7 +657,6 @@ static void __init set_system_time(void)
                        mon  = CMOS_READ(RTC_MONTH);
                        year = CMOS_READ(RTC_YEAR);
                } while (sec != CMOS_READ(RTC_SECONDS));
-
                if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
                        BCD_TO_BIN(sec);
                        BCD_TO_BIN(min);
@@ -678,83 +683,6 @@ static void __init set_system_time(void)
        }
 }
 
-/* davem suggests we keep this within the 4M locked kernel image */
-static u32 starfire_get_time(void)
-{
-       static char obp_gettod[32];
-       static u32 unix_tod;
-
-       sprintf(obp_gettod, "h# %08x unix-gettod",
-               (unsigned int) (long) &unix_tod);
-       prom_feval(obp_gettod);
-
-       return unix_tod;
-}
-
-static int starfire_set_time(u32 val)
-{
-       /* Do nothing, time is set using the service processor
-        * console on this platform.
-        */
-       return 0;
-}
-
-static u32 hypervisor_get_time(void)
-{
-       register unsigned long func asm("%o5");
-       register unsigned long arg0 asm("%o0");
-       register unsigned long arg1 asm("%o1");
-       int retries = 10000;
-
-retry:
-       func = HV_FAST_TOD_GET;
-       arg0 = 0;
-       arg1 = 0;
-       __asm__ __volatile__("ta        %6"
-                            : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
-                            : "0" (func), "1" (arg0), "2" (arg1),
-                              "i" (HV_FAST_TRAP));
-       if (arg0 == HV_EOK)
-               return arg1;
-       if (arg0 == HV_EWOULDBLOCK) {
-               if (--retries > 0) {
-                       udelay(100);
-                       goto retry;
-               }
-               printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
-               return 0;
-       }
-       printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
-       return 0;
-}
-
-static int hypervisor_set_time(u32 secs)
-{
-       register unsigned long func asm("%o5");
-       register unsigned long arg0 asm("%o0");
-       int retries = 10000;
-
-retry:
-       func = HV_FAST_TOD_SET;
-       arg0 = secs;
-       __asm__ __volatile__("ta        %4"
-                            : "=&r" (func), "=&r" (arg0)
-                            : "0" (func), "1" (arg0),
-                              "i" (HV_FAST_TRAP));
-       if (arg0 == HV_EOK)
-               return 0;
-       if (arg0 == HV_EWOULDBLOCK) {
-               if (--retries > 0) {
-                       udelay(100);
-                       goto retry;
-               }
-               printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
-               return -EAGAIN;
-       }
-       printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
-       return -EOPNOTSUPP;
-}
-
 void __init clock_probe(void)
 {
        struct linux_prom_registers clk_reg[2];
@@ -774,14 +702,14 @@ void __init clock_probe(void)
 
 
        if (this_is_starfire) {
-               xtime.tv_sec = starfire_get_time();
-               xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-               set_normalized_timespec(&wall_to_monotonic,
-                                       -xtime.tv_sec, -xtime.tv_nsec);
-               return;
-       }
-       if (tlb_type == hypervisor) {
-               xtime.tv_sec = hypervisor_get_time();
+               /* davem suggests we keep this within the 4M locked kernel image */
+               static char obp_gettod[256];
+               static u32 unix_tod;
+
+               sprintf(obp_gettod, "h# %08x unix-gettod",
+                       (unsigned int) (long) &unix_tod);
+               prom_feval(obp_gettod);
+               xtime.tv_sec = unix_tod;
                xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
                set_normalized_timespec(&wall_to_monotonic,
                                        -xtime.tv_sec, -xtime.tv_nsec);
@@ -1053,10 +981,11 @@ static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_reg
 }
 
 struct freq_table {
+       unsigned long udelay_val_ref;
        unsigned long clock_tick_ref;
        unsigned int ref_freq;
 };
-static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0 };
+static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 };
 
 unsigned long sparc64_get_clock_tick(unsigned int cpu)
 {
@@ -1078,11 +1007,16 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
 
        if (!ft->ref_freq) {
                ft->ref_freq = freq->old;
+               ft->udelay_val_ref = cpu_data(cpu).udelay_val;
                ft->clock_tick_ref = cpu_data(cpu).clock_tick;
        }
        if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
            (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
            (val == CPUFREQ_RESUMECHANGE)) {
+               cpu_data(cpu).udelay_val =
+                       cpufreq_scale(ft->udelay_val_ref,
+                                     ft->ref_freq,
+                                     freq->new);
                cpu_data(cpu).clock_tick =
                        cpufreq_scale(ft->clock_tick_ref,
                                      ft->ref_freq,
@@ -1105,7 +1039,7 @@ static struct time_interpolator sparc64_cpu_interpolator = {
 };
 
 /* The quotient formula is taken from the IA64 port. */
-#define SPARC64_NSEC_PER_CYC_SHIFT     30UL
+#define SPARC64_NSEC_PER_CYC_SHIFT     10UL
 void __init time_init(void)
 {
        unsigned long clock = sparc64_init_timers();
@@ -1245,246 +1179,3 @@ static int set_rtc_mmss(unsigned long nowtime)
                return retval;
        }
 }
-
-#define RTC_IS_OPEN            0x01    /* means /dev/rtc is in use     */
-static unsigned char mini_rtc_status;  /* bitmapped status byte.       */
-
-/* months start at 0 now */
-static unsigned char days_in_mo[] =
-{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-#define FEBRUARY       2
-#define        STARTOFTIME     1970
-#define SECDAY         86400L
-#define SECYR          (SECDAY * 365)
-#define        leapyear(year)          ((year) % 4 == 0 && \
-                                ((year) % 100 != 0 || (year) % 400 == 0))
-#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
-#define        days_in_month(a)        (month_days[(a) - 1])
-
-static int month_days[12] = {
-       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-/*
- * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
- */
-static void GregorianDay(struct rtc_time * tm)
-{
-       int leapsToDate;
-       int lastYear;
-       int day;
-       int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-
-       lastYear = tm->tm_year - 1;
-
-       /*
-        * Number of leap corrections to apply up to end of last year
-        */
-       leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
-
-       /*
-        * This year is a leap year if it is divisible by 4 except when it is
-        * divisible by 100 unless it is divisible by 400
-        *
-        * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
-        */
-       day = tm->tm_mon > 2 && leapyear(tm->tm_year);
-
-       day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
-                  tm->tm_mday;
-
-       tm->tm_wday = day % 7;
-}
-
-static void to_tm(int tim, struct rtc_time *tm)
-{
-       register int    i;
-       register long   hms, day;
-
-       day = tim / SECDAY;
-       hms = tim % SECDAY;
-
-       /* Hours, minutes, seconds are easy */
-       tm->tm_hour = hms / 3600;
-       tm->tm_min = (hms % 3600) / 60;
-       tm->tm_sec = (hms % 3600) % 60;
-
-       /* Number of years in days */
-       for (i = STARTOFTIME; day >= days_in_year(i); i++)
-               day -= days_in_year(i);
-       tm->tm_year = i;
-
-       /* Number of months in days left */
-       if (leapyear(tm->tm_year))
-               days_in_month(FEBRUARY) = 29;
-       for (i = 1; day >= days_in_month(i); i++)
-               day -= days_in_month(i);
-       days_in_month(FEBRUARY) = 28;
-       tm->tm_mon = i;
-
-       /* Days are what is left over (+1) from all that. */
-       tm->tm_mday = day + 1;
-
-       /*
-        * Determine the day of week
-        */
-       GregorianDay(tm);
-}
-
-/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
- * aka Unix time.  So we have to convert to/from rtc_time.
- */
-static inline void mini_get_rtc_time(struct rtc_time *time)
-{
-       unsigned long flags;
-       u32 seconds;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       seconds = 0;
-       if (this_is_starfire)
-               seconds = starfire_get_time();
-       else if (tlb_type == hypervisor)
-               seconds = hypervisor_get_time();
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       to_tm(seconds, time);
-       time->tm_year -= 1900;
-       time->tm_mon -= 1;
-}
-
-static inline int mini_set_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
-                            time->tm_mday, time->tm_hour,
-                            time->tm_min, time->tm_sec);
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       err = -ENODEV;
-       if (this_is_starfire)
-               err = starfire_set_time(seconds);
-       else  if (tlb_type == hypervisor)
-               err = hypervisor_set_time(seconds);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return err;
-}
-
-static int mini_rtc_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct rtc_time wtime;
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-
-       case RTC_PLL_GET:
-               return -EINVAL;
-
-       case RTC_PLL_SET:
-               return -EINVAL;
-
-       case RTC_UIE_OFF:       /* disable ints from RTC updates.       */
-               return 0;
-
-       case RTC_UIE_ON:        /* enable ints for RTC updates. */
-               return -EINVAL;
-
-       case RTC_RD_TIME:       /* Read the time/date from RTC  */
-               /* this doesn't get week-day, who cares */
-               memset(&wtime, 0, sizeof(wtime));
-               mini_get_rtc_time(&wtime);
-
-               return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
-
-       case RTC_SET_TIME:      /* Set the RTC */
-           {
-               int year;
-               unsigned char leap_yr;
-
-               if (!capable(CAP_SYS_TIME))
-                       return -EACCES;
-
-               if (copy_from_user(&wtime, argp, sizeof(wtime)))
-                       return -EFAULT;
-
-               year = wtime.tm_year + 1900;
-               leap_yr = ((!(year % 4) && (year % 100)) ||
-                          !(year % 400));
-
-               if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
-                       return -EINVAL;
-
-               if (wtime.tm_mday < 0 || wtime.tm_mday >
-                   (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
-                       return -EINVAL;
-
-               if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
-                   wtime.tm_min < 0 || wtime.tm_min >= 60 ||
-                   wtime.tm_sec < 0 || wtime.tm_sec >= 60)
-                       return -EINVAL;
-
-               return mini_set_rtc_time(&wtime);
-           }
-       }
-
-       return -EINVAL;
-}
-
-static int mini_rtc_open(struct inode *inode, struct file *file)
-{
-       if (mini_rtc_status & RTC_IS_OPEN)
-               return -EBUSY;
-
-       mini_rtc_status |= RTC_IS_OPEN;
-
-       return 0;
-}
-
-static int mini_rtc_release(struct inode *inode, struct file *file)
-{
-       mini_rtc_status &= ~RTC_IS_OPEN;
-       return 0;
-}
-
-
-static struct file_operations mini_rtc_fops = {
-       .owner          = THIS_MODULE,
-       .ioctl          = mini_rtc_ioctl,
-       .open           = mini_rtc_open,
-       .release        = mini_rtc_release,
-};
-
-static struct miscdevice rtc_mini_dev =
-{
-       .minor          = RTC_MINOR,
-       .name           = "rtc",
-       .fops           = &mini_rtc_fops,
-};
-
-static int __init rtc_mini_init(void)
-{
-       int retval;
-
-       if (tlb_type != hypervisor && !this_is_starfire)
-               return -ENODEV;
-
-       printk(KERN_INFO "Mini RTC Driver\n");
-
-       retval = misc_register(&rtc_mini_dev);
-       if (retval < 0)
-               return retval;
-
-       return 0;
-}
-
-static void __exit rtc_mini_exit(void)
-{
-       misc_deregister(&rtc_mini_dev);
-}
-
-
-module_init(rtc_mini_init);
-module_exit(rtc_mini_exit);