diff options
author | Tejun Heo <tj@kernel.org> | 2010-02-02 00:38:15 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2010-02-02 00:38:15 -0500 |
commit | ab386128f20c44c458a90039ab1bdc265ac474c9 (patch) | |
tree | 2ad188744922b1bb951fd10ff50dc04c83acce22 /arch/sparc/kernel/pcic.c | |
parent | dbfc196a3cc1a2514ad0737a82f764de23bd65e6 (diff) | |
parent | ab658321f32770b903a4426e2a6fae0392757755 (diff) |
Merge branch 'master' into percpu
Diffstat (limited to 'arch/sparc/kernel/pcic.c')
-rw-r--r-- | arch/sparc/kernel/pcic.c | 103 |
1 files changed, 16 insertions, 87 deletions
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 85e7037429b9..4e2724ec2bb6 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/oplib.h> | 30 | #include <asm/oplib.h> |
31 | #include <asm/prom.h> | 31 | #include <asm/prom.h> |
32 | #include <asm/pcic.h> | 32 | #include <asm/pcic.h> |
33 | #include <asm/timex.h> | ||
33 | #include <asm/timer.h> | 34 | #include <asm/timer.h> |
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
35 | #include <asm/irq_regs.h> | 36 | #include <asm/irq_regs.h> |
@@ -163,8 +164,6 @@ void __iomem *pcic_regs; | |||
163 | volatile int pcic_speculative; | 164 | volatile int pcic_speculative; |
164 | volatile int pcic_trapped; | 165 | volatile int pcic_trapped; |
165 | 166 | ||
166 | static void pci_do_gettimeofday(struct timeval *tv); | ||
167 | static int pci_do_settimeofday(struct timespec *tv); | ||
168 | 167 | ||
169 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) | 168 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) |
170 | 169 | ||
@@ -716,19 +715,27 @@ static irqreturn_t pcic_timer_handler (int irq, void *h) | |||
716 | #define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */ | 715 | #define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */ |
717 | #define TICK_TIMER_LIMIT ((100*1000000/4)/100) | 716 | #define TICK_TIMER_LIMIT ((100*1000000/4)/100) |
718 | 717 | ||
718 | u32 pci_gettimeoffset(void) | ||
719 | { | ||
720 | /* | ||
721 | * We divide all by 100 | ||
722 | * to have microsecond resolution and to avoid overflow | ||
723 | */ | ||
724 | unsigned long count = | ||
725 | readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; | ||
726 | count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); | ||
727 | return count * 1000; | ||
728 | } | ||
729 | |||
730 | |||
719 | void __init pci_time_init(void) | 731 | void __init pci_time_init(void) |
720 | { | 732 | { |
721 | struct linux_pcic *pcic = &pcic0; | 733 | struct linux_pcic *pcic = &pcic0; |
722 | unsigned long v; | 734 | unsigned long v; |
723 | int timer_irq, irq; | 735 | int timer_irq, irq; |
724 | 736 | ||
725 | /* A hack until do_gettimeofday prototype is moved to arch specific headers | 737 | do_arch_gettimeoffset = pci_gettimeoffset; |
726 | and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */ | 738 | |
727 | ((unsigned int *)do_gettimeofday)[0] = | ||
728 | 0x10800000 | ((((unsigned long)pci_do_gettimeofday - | ||
729 | (unsigned long)do_gettimeofday) >> 2) & 0x003fffff); | ||
730 | ((unsigned int *)do_gettimeofday)[1] = 0x01000000; | ||
731 | BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM); | ||
732 | btfixup(); | 739 | btfixup(); |
733 | 740 | ||
734 | writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT); | 741 | writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT); |
@@ -746,84 +753,6 @@ void __init pci_time_init(void) | |||
746 | local_irq_enable(); | 753 | local_irq_enable(); |
747 | } | 754 | } |
748 | 755 | ||
749 | static inline unsigned long do_gettimeoffset(void) | ||
750 | { | ||
751 | /* | ||
752 | * We divide all by 100 | ||
753 | * to have microsecond resolution and to avoid overflow | ||
754 | */ | ||
755 | unsigned long count = | ||
756 | readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; | ||
757 | count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); | ||
758 | return count; | ||
759 | } | ||
760 | |||
761 | static void pci_do_gettimeofday(struct timeval *tv) | ||
762 | { | ||
763 | unsigned long flags; | ||
764 | unsigned long seq; | ||
765 | unsigned long usec, sec; | ||
766 | unsigned long max_ntp_tick = tick_usec - tickadj; | ||
767 | |||
768 | do { | ||
769 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | ||
770 | usec = do_gettimeoffset(); | ||
771 | |||
772 | /* | ||
773 | * If time_adjust is negative then NTP is slowing the clock | ||
774 | * so make sure not to go into next possible interval. | ||
775 | * Better to lose some accuracy than have time go backwards.. | ||
776 | */ | ||
777 | if (unlikely(time_adjust < 0)) | ||
778 | usec = min(usec, max_ntp_tick); | ||
779 | |||
780 | sec = xtime.tv_sec; | ||
781 | usec += (xtime.tv_nsec / 1000); | ||
782 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | ||
783 | |||
784 | while (usec >= 1000000) { | ||
785 | usec -= 1000000; | ||
786 | sec++; | ||
787 | } | ||
788 | |||
789 | tv->tv_sec = sec; | ||
790 | tv->tv_usec = usec; | ||
791 | } | ||
792 | |||
793 | static int pci_do_settimeofday(struct timespec *tv) | ||
794 | { | ||
795 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
796 | return -EINVAL; | ||
797 | |||
798 | /* | ||
799 | * This is revolting. We need to set "xtime" correctly. However, the | ||
800 | * value in this location is the value at the most recent update of | ||
801 | * wall time. Discover what correction gettimeofday() would have | ||
802 | * made, and then undo it! | ||
803 | */ | ||
804 | tv->tv_nsec -= 1000 * do_gettimeoffset(); | ||
805 | while (tv->tv_nsec < 0) { | ||
806 | tv->tv_nsec += NSEC_PER_SEC; | ||
807 | tv->tv_sec--; | ||
808 | } | ||
809 | |||
810 | wall_to_monotonic.tv_sec += xtime.tv_sec - tv->tv_sec; | ||
811 | wall_to_monotonic.tv_nsec += xtime.tv_nsec - tv->tv_nsec; | ||
812 | |||
813 | if (wall_to_monotonic.tv_nsec > NSEC_PER_SEC) { | ||
814 | wall_to_monotonic.tv_nsec -= NSEC_PER_SEC; | ||
815 | wall_to_monotonic.tv_sec++; | ||
816 | } | ||
817 | if (wall_to_monotonic.tv_nsec < 0) { | ||
818 | wall_to_monotonic.tv_nsec += NSEC_PER_SEC; | ||
819 | wall_to_monotonic.tv_sec--; | ||
820 | } | ||
821 | |||
822 | xtime.tv_sec = tv->tv_sec; | ||
823 | xtime.tv_nsec = tv->tv_nsec; | ||
824 | ntp_clear(); | ||
825 | return 0; | ||
826 | } | ||
827 | 756 | ||
828 | #if 0 | 757 | #if 0 |
829 | static void watchdog_reset() { | 758 | static void watchdog_reset() { |