Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0299b137 authored by John Stultz's avatar John Stultz Committed by David S. Miller
Browse files

sparc: convert to arch_gettimeoffset()



This patch converts sparc (specifically sparc32) to use GENERIC_TIME via
the arch_getoffset() infrastructure, reducing the amount of arch
specific code we need to maintain.

The sparc architecture is one of the last 3 arches that need to be
converted.

This patch applies on top of Linus' current -git tree

I've taken my best swing at converting this, but I'm not 100% confident
I got it right. My cross-compiler is now out of date (gcc4.2) so I
wasn't able to check if it compiled. Any assistance from arch
maintainers or testers to get this merged would be great.

Signed-off-by: default avatarJohn Stultz <johnstul@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 09317146
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -64,8 +64,11 @@ config BITS
	default 64 if SPARC64

config GENERIC_TIME
	def_bool y

config ARCH_USES_GETTIMEOFFSET
	bool
	default y if SPARC64
	default y if SPARC32

config GENERIC_CMOS_UPDATE
	bool
+1 −0
Original line number Diff line number Diff line
@@ -12,4 +12,5 @@
typedef unsigned long cycles_t;
#define get_cycles()	(0)

extern u32 (*do_arch_gettimeoffset)(void);
#endif
+16 −87
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/pcic.h>
#include <asm/timex.h>
#include <asm/timer.h>
#include <asm/uaccess.h>
#include <asm/irq_regs.h>
@@ -163,8 +164,6 @@ void __iomem *pcic_regs;
volatile int pcic_speculative;
volatile int pcic_trapped;

static void pci_do_gettimeofday(struct timeval *tv);
static int pci_do_settimeofday(struct timespec *tv);

#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))

@@ -716,19 +715,27 @@ static irqreturn_t pcic_timer_handler (int irq, void *h)
#define USECS_PER_JIFFY  10000  /* We have 100HZ "standard" timer for sparc */
#define TICK_TIMER_LIMIT ((100*1000000/4)/100)

u32 pci_gettimeoffset(void)
{
	/*
	 * We divide all by 100
	 * to have microsecond resolution and to avoid overflow
	 */
	unsigned long count =
	    readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
	count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
	return count * 1000;
}


void __init pci_time_init(void)
{
	struct linux_pcic *pcic = &pcic0;
	unsigned long v;
	int timer_irq, irq;

	/* A hack until do_gettimeofday prototype is moved to arch specific headers
	   and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
	((unsigned int *)do_gettimeofday)[0] = 
	    0x10800000 | ((((unsigned long)pci_do_gettimeofday -
	     (unsigned long)do_gettimeofday) >> 2) & 0x003fffff);
	((unsigned int *)do_gettimeofday)[1] = 0x01000000;
	BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);
	do_arch_gettimeoffset = pci_gettimeoffset;

	btfixup();

	writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT);
@@ -746,84 +753,6 @@ void __init pci_time_init(void)
	local_irq_enable();
}

static inline unsigned long do_gettimeoffset(void)
{
	/*
	 * We divide all by 100
	 * to have microsecond resolution and to avoid overflow
	 */
	unsigned long count =
	    readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
	count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
	return count;
}

static void pci_do_gettimeofday(struct timeval *tv)
{
	unsigned long flags;
	unsigned long seq;
	unsigned long usec, sec;
	unsigned long max_ntp_tick = tick_usec - tickadj;

	do {
		seq = read_seqbegin_irqsave(&xtime_lock, flags);
		usec = do_gettimeoffset();

		/*
		 * If time_adjust is negative then NTP is slowing the clock
		 * so make sure not to go into next possible interval.
		 * Better to lose some accuracy than have time go backwards..
		 */
		if (unlikely(time_adjust < 0))
			usec = min(usec, max_ntp_tick);

		sec = xtime.tv_sec;
		usec += (xtime.tv_nsec / 1000);
	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));

	while (usec >= 1000000) {
		usec -= 1000000;
		sec++;
	}

	tv->tv_sec = sec;
	tv->tv_usec = usec;
}

static int pci_do_settimeofday(struct timespec *tv)
{
	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
		return -EINVAL;

	/*
	 * This is revolting. We need to set "xtime" correctly. However, the
	 * value in this location is the value at the most recent update of
	 * wall time.  Discover what correction gettimeofday() would have
	 * made, and then undo it!
	 */
	tv->tv_nsec -= 1000 * do_gettimeoffset();
	while (tv->tv_nsec < 0) {
		tv->tv_nsec += NSEC_PER_SEC;
		tv->tv_sec--;
	}

	wall_to_monotonic.tv_sec += xtime.tv_sec - tv->tv_sec;
	wall_to_monotonic.tv_nsec += xtime.tv_nsec - tv->tv_nsec;

	if (wall_to_monotonic.tv_nsec > NSEC_PER_SEC) {
		wall_to_monotonic.tv_nsec -= NSEC_PER_SEC;
		wall_to_monotonic.tv_sec++;
	}
	if (wall_to_monotonic.tv_nsec < 0) {
		wall_to_monotonic.tv_nsec += NSEC_PER_SEC;
		wall_to_monotonic.tv_sec--;
	}

	xtime.tv_sec = tv->tv_sec;
	xtime.tv_nsec = tv->tv_nsec;
	ntp_clear();
	return 0;
}

#if 0
static void watchdog_reset() {
+25 −91
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/platform_device.h>

#include <asm/oplib.h>
#include <asm/timex.h>
#include <asm/timer.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -51,7 +52,6 @@ DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);

static int set_rtc_mmss(unsigned long);
static int sbus_do_settimeofday(struct timespec *tv);

unsigned long profile_pc(struct pt_regs *regs)
{
@@ -76,6 +76,8 @@ EXPORT_SYMBOL(profile_pc);

__volatile__ unsigned int *master_l10_counter;

u32 (*do_arch_gettimeoffset)(void);

/*
 * timer_interrupt() needs to keep up the real-time clock,
 * as well as call the "do_timer()" routine every clocktick
@@ -196,35 +198,14 @@ static int __init clock_init(void)
{
	return of_register_driver(&clock_driver, &of_platform_bus_type);
}

/* Must be after subsys_initcall() so that busses are probed.  Must
 * be before device_initcall() because things like the RTC driver
 * need to see the clock registers.
 */
fs_initcall(clock_init);

static void __init sbus_time_init(void)
{

	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
	btfixup();

	sparc_init_timers(timer_interrupt);
}

void __init time_init(void)
{
#ifdef CONFIG_PCI
	extern void pci_time_init(void);
	if (pcic_present()) {
		pci_time_init();
		return;
	}
#endif
	sbus_time_init();
}

static inline unsigned long do_gettimeoffset(void)
u32 sbus_do_gettimeoffset(void)
{
	unsigned long val = *master_l10_counter;
	unsigned long usec = (val >> 10) & 0x1fffff;
@@ -233,85 +214,38 @@ static inline unsigned long do_gettimeoffset(void)
	if (val & 0x80000000)
		usec += 1000000 / HZ;

	return usec;
}

/* Ok, my cute asm atomicity trick doesn't work anymore.
 * There are just too many variables that need to be protected
 * now (both members of xtime, et al.)
 */
void do_gettimeofday(struct timeval *tv)
{
	unsigned long flags;
	unsigned long seq;
	unsigned long usec, sec;
	unsigned long max_ntp_tick = tick_usec - tickadj;

	do {
		seq = read_seqbegin_irqsave(&xtime_lock, flags);
		usec = do_gettimeoffset();

		/*
		 * If time_adjust is negative then NTP is slowing the clock
		 * so make sure not to go into next possible interval.
		 * Better to lose some accuracy than have time go backwards..
		 */
		if (unlikely(time_adjust < 0))
			usec = min(usec, max_ntp_tick);

		sec = xtime.tv_sec;
		usec += (xtime.tv_nsec / 1000);
	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));

	while (usec >= 1000000) {
		usec -= 1000000;
		sec++;
	return usec * 1000;
}

	tv->tv_sec = sec;
	tv->tv_usec = usec;
}

EXPORT_SYMBOL(do_gettimeofday);

int do_settimeofday(struct timespec *tv)
u32 arch_gettimeoffset(void)
{
	int ret;

	write_seqlock_irq(&xtime_lock);
	ret = bus_do_settimeofday(tv);
	write_sequnlock_irq(&xtime_lock);
	clock_was_set();
	return ret;
	if (unlikely(!do_arch_gettimeoffset))
		return 0;
	return do_arch_gettimeoffset();
}

EXPORT_SYMBOL(do_settimeofday);

static int sbus_do_settimeofday(struct timespec *tv)
static void __init sbus_time_init(void)
{
	time_t wtm_sec, sec = tv->tv_sec;
	long wtm_nsec, nsec = tv->tv_nsec;
	do_arch_gettimeoffset = sbus_do_gettimeoffset;

	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
		return -EINVAL;

	/*
	 * This is revolting. We need to set "xtime" correctly. However, the
	 * value in this location is the value at the most recent update of
	 * wall time.  Discover what correction gettimeofday() would have
	 * made, and then undo it!
	 */
	nsec -= 1000 * do_gettimeoffset();

	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
	btfixup();

	set_normalized_timespec(&xtime, sec, nsec);
	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
	sparc_init_timers(timer_interrupt);
}

	ntp_clear();
	return 0;
void __init time_init(void)
{
#ifdef CONFIG_PCI
	extern void pci_time_init(void);
	if (pcic_present()) {
		pci_time_init();
		return;
	}
#endif
	sbus_time_init();
}


static int set_rtc_mmss(unsigned long secs)
{