Commit f2783c15 authored by Paul Mackerras's avatar Paul Mackerras

powerpc: Merge time.c and asm/time.h.

We now use the merged time.c for both 32-bit and 64-bit compilation
with ARCH=powerpc, and for ARCH=ppc64, but not for ARCH=ppc32.
This removes setup_default_decr (folds its function into time_init)
and moves wakeup_decrementer into time.c.  This also makes an
asm-powerpc/rtc.h.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 03f88e9f
...@@ -29,7 +29,7 @@ extra-$(CONFIG_PPC64) += entry_64.o ...@@ -29,7 +29,7 @@ extra-$(CONFIG_PPC64) += entry_64.o
extra-$(CONFIG_PPC_FPU) += fpu.o extra-$(CONFIG_PPC_FPU) += fpu.o
extra-y += vmlinux.lds extra-y += vmlinux.lds
obj-y += process.o init_task.o \ obj-y += process.o init_task.o time.o \
prom.o systbl.o traps.o prom.o systbl.o traps.o
obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o obj-$(CONFIG_PPC32) += entry_32.o idle_6xx.o setup_32.o misc_32.o
obj-$(CONFIG_PPC64) += setup_64.o misc_64.o obj-$(CONFIG_PPC64) += setup_64.o misc_64.o
...@@ -44,7 +44,7 @@ endif ...@@ -44,7 +44,7 @@ endif
else else
# stuff used from here for ARCH=ppc or ARCH=ppc64 # stuff used from here for ARCH=ppc or ARCH=ppc64
obj-$(CONFIG_PPC64) += traps.o process.o init_task.o obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o
fpux-$(CONFIG_PPC32) += fpu.o fpux-$(CONFIG_PPC32) += fpu.o
extra-$(CONFIG_PPC_FPU) += $(fpux-y) extra-$(CONFIG_PPC_FPU) += $(fpux-y)
......
...@@ -35,6 +35,33 @@ _GLOBAL(__delay) ...@@ -35,6 +35,33 @@ _GLOBAL(__delay)
1: bdnz 1b 1: bdnz 1b
blr blr
/*
* This returns the high 64 bits of the product of two 64-bit numbers.
*/
_GLOBAL(mulhdu)
cmpwi r6,0
cmpwi cr1,r3,0
mr r10,r4
mulhwu r4,r4,r5
beq 1f
mulhwu r0,r10,r6
mullw r7,r10,r5
addc r7,r0,r7
addze r4,r4
1: beqlr cr1 /* all done if high part of A is 0 */
mr r10,r3
mullw r9,r3,r5
mulhwu r3,r3,r5
beq 2f
mullw r0,r10,r6
mulhwu r8,r10,r6
addc r7,r0,r7
adde r4,r4,r8
addze r3,r3
2: addc r4,r4,r9
addze r3,r3
blr
/* /*
* Returns (address we're running at) - (address we were linked at) * Returns (address we're running at) - (address we were linked at)
* for use before the text and data are mapped to KERNELBASE. * for use before the text and data are mapped to KERNELBASE.
......
...@@ -260,7 +260,6 @@ EXPORT_SYMBOL(__res); ...@@ -260,7 +260,6 @@ EXPORT_SYMBOL(__res);
#ifdef CONFIG_PPC32 #ifdef CONFIG_PPC32
EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(next_mmu_context);
EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(set_context);
EXPORT_SYMBOL(disarm_decr);
#endif #endif
#ifdef CONFIG_PPC_STD_MMU_32 #ifdef CONFIG_PPC_STD_MMU_32
......
...@@ -1083,15 +1083,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) ...@@ -1083,15 +1083,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg)
printk("[terminate]%04x %s\n", src, msg); printk("[terminate]%04x %s\n", src, msg);
} }
/* This should only be called on processor 0 during calibrate decr */
void __init setup_default_decr(void)
{
struct paca_struct *lpaca = get_paca();
lpaca->default_decr = tb_ticks_per_jiffy;
lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
}
#ifndef CONFIG_PPC_ISERIES #ifndef CONFIG_PPC_ISERIES
/* /*
* This function can be used by platforms to "find" legacy serial ports. * This function can be used by platforms to "find" legacy serial ports.
......
...@@ -110,15 +110,6 @@ static inline void local_delay(unsigned long ms) ...@@ -110,15 +110,6 @@ static inline void local_delay(unsigned long ms)
msleep(ms); msleep(ms);
} }
static inline void wakeup_decrementer(void)
{
set_dec(tb_ticks_per_jiffy);
/* No currently-supported powerbook has a 601,
* so use get_tbl, not native
*/
last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
}
#ifdef DEBUG_FREQ #ifdef DEBUG_FREQ
static inline void debug_calc_bogomips(void) static inline void debug_calc_bogomips(void)
{ {
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* *
* Paul Mackerras August 1996. * Paul Mackerras August 1996.
* Copyright (C) 1996 Paul Mackerras. * Copyright (C) 1996 Paul Mackerras.
* Copyright (C) 2003-2005 Benjamin Herrenschmidt.
*
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -19,7 +21,9 @@ ...@@ -19,7 +21,9 @@
#include <linux/adb.h> #include <linux/adb.h>
#include <linux/cuda.h> #include <linux/cuda.h>
#include <linux/pmu.h> #include <linux/pmu.h>
#include <linux/interrupt.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/rtc.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/prom.h> #include <asm/prom.h>
...@@ -30,6 +34,14 @@ ...@@ -30,6 +34,14 @@
#include <asm/time.h> #include <asm/time.h>
#include <asm/nvram.h> #include <asm/nvram.h>
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
/* Apparently the RTC stores seconds since 1 Jan 1904 */ /* Apparently the RTC stores seconds since 1 Jan 1904 */
#define RTC_OFFSET 2082844800 #define RTC_OFFSET 2082844800
...@@ -54,10 +66,7 @@ ...@@ -54,10 +66,7 @@
/* Bits in IFR and IER */ /* Bits in IFR and IER */
#define T1_INT 0x40 /* Timer 1 interrupt */ #define T1_INT 0x40 /* Timer 1 interrupt */
extern struct timezone sys_tz; long __init pmac_time_init(void)
long __init
pmac_time_init(void)
{ {
#ifdef CONFIG_NVRAM #ifdef CONFIG_NVRAM
s32 delta = 0; s32 delta = 0;
...@@ -210,7 +219,7 @@ via_calibrate_decr(void) ...@@ -210,7 +219,7 @@ via_calibrate_decr(void)
tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100);
tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %lu (%u ticks)\n",
tb_ticks_per_jiffy, dstart - dend); tb_ticks_per_jiffy, dstart - dend);
iounmap(via); iounmap(via);
...@@ -228,6 +237,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -228,6 +237,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when)
static unsigned long time_diff; static unsigned long time_diff;
unsigned long flags; unsigned long flags;
unsigned long seq; unsigned long seq;
struct timespec tv;
switch (when) { switch (when) {
case PBOOK_SLEEP_NOW: case PBOOK_SLEEP_NOW:
...@@ -237,11 +247,9 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -237,11 +247,9 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when)
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
break; break;
case PBOOK_WAKE: case PBOOK_WAKE:
write_seqlock_irqsave(&xtime_lock, flags); tv.tv_sec = pmac_get_boot_time() + time_diff;
xtime.tv_sec = pmac_get_rtc_time() + time_diff; tv.tv_nsec = 0;
xtime.tv_nsec = 0; do_settimeofday(&tv);
last_rtc_update = xtime.tv_sec;
write_sequnlock_irqrestore(&xtime_lock, flags);
break; break;
} }
return PBOOK_SLEEP_OK; return PBOOK_SLEEP_OK;
......
...@@ -37,7 +37,7 @@ endif ...@@ -37,7 +37,7 @@ endif
# These are here while we do the architecture merge # These are here while we do the architecture merge
else else
obj-y := irq.o idle.o time.o \ obj-y := irq.o idle.o \
align.o perfmon.o align.o perfmon.o
obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
......
...@@ -121,6 +121,15 @@ unsigned long profile_pc(struct pt_regs *regs) ...@@ -121,6 +121,15 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc); EXPORT_SYMBOL(profile_pc);
#endif #endif
void wakeup_decrementer(void)
{
set_dec(tb_ticks_per_jiffy);
/* No currently-supported powerbook has a 601,
* so use get_tbl, not native
*/
last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
}
/* /*
* timer_interrupt - gets called when the decrementer overflows, * timer_interrupt - gets called when the decrementer overflows,
* with interrupts disabled. * with interrupts disabled.
......
...@@ -12,7 +12,7 @@ obj-y := setup.o entry.o misc.o prom.o ...@@ -12,7 +12,7 @@ obj-y := setup.o entry.o misc.o prom.o
endif endif
obj-y += irq.o idle.o dma.o \ obj-y += irq.o idle.o dma.o \
time.o signal.o \ signal.o \
align.o bitops.o pacaData.o \ align.o bitops.o pacaData.o \
udbg.o ioctl32.o \ udbg.o ioctl32.o \
rtc.o \ rtc.o \
......
...@@ -180,7 +180,5 @@ void __init pmac_calibrate_decr(void) ...@@ -180,7 +180,5 @@ void __init pmac_calibrate_decr(void)
if (fp == 0) if (fp == 0)
panic("can't get cpu processor frequency"); panic("can't get cpu processor frequency");
ppc_proc_freq = *fp; ppc_proc_freq = *fp;
setup_default_decr();
} }
...@@ -1083,15 +1083,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) ...@@ -1083,15 +1083,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg)
printk("[terminate]%04x %s\n", src, msg); printk("[terminate]%04x %s\n", src, msg);
} }
/* This should only be called on processor 0 during calibrate decr */
void __init setup_default_decr(void)
{
struct paca_struct *lpaca = get_paca();
lpaca->default_decr = tb_ticks_per_jiffy;
lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
}
#ifndef CONFIG_PPC_ISERIES #ifndef CONFIG_PPC_ISERIES
/* /*
* This function can be used by platforms to "find" legacy serial ports. * This function can be used by platforms to "find" legacy serial ports.
......
...@@ -588,17 +588,6 @@ pmu_get_model(void) ...@@ -588,17 +588,6 @@ pmu_get_model(void)
return pmu_kind; return pmu_kind;
} }
#ifndef CONFIG_PPC64
static inline void wakeup_decrementer(void)
{
set_dec(tb_ticks_per_jiffy);
/* No currently-supported powerbook has a 601,
* so use get_tbl, not native
*/
last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
}
#endif
static void pmu_set_server_mode(int server_mode) static void pmu_set_server_mode(int server_mode)
{ {
struct adb_request req; struct adb_request req;
......
...@@ -496,5 +496,7 @@ extern int call_handle_IRQ_event(int irq, struct pt_regs *regs, ...@@ -496,5 +496,7 @@ extern int call_handle_IRQ_event(int irq, struct pt_regs *regs,
#endif /* CONFIG_IRQSTACKS */ #endif /* CONFIG_IRQSTACKS */
extern void do_IRQ(struct pt_regs *regs);
#endif /* _ASM_IRQ_H */ #endif /* _ASM_IRQ_H */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
/*
* Real-time clock definitions and interfaces
*
* Author: Tom Rini <trini@mvista.com>
*
* 2002 (c) MontaVista, Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*
* Based on:
* include/asm-m68k/rtc.h
*
* Copyright Richard Zidlicky
* implementation details for genrtc/q40rtc driver
*
* And the old drivers/macintosh/rtc.c which was heavily based on:
* Linux/SPARC Real Time Clock Driver
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
*
* With additional work by Paul Mackerras and Franz Sirl.
*/
#ifndef __ASM_POWERPC_RTC_H__
#define __ASM_POWERPC_RTC_H__
#ifdef __KERNEL__
#include <linux/rtc.h>
#include <asm/machdep.h>
#include <asm/time.h>
#define RTC_PIE 0x40 /* periodic interrupt enable */
#define RTC_AIE 0x20 /* alarm interrupt enable */
#define RTC_UIE 0x10 /* update-finished interrupt enable */
/* some dummy definitions */
#define RTC_BATT_BAD 0x100 /* battery bad */
#define RTC_SQWE 0x08 /* enable square-wave output */
#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
static inline unsigned int get_rtc_time(struct rtc_time *time)
{
if (ppc_md.get_rtc_time)
ppc_md.get_rtc_time(time);
return RTC_24H;
}
/* Set the current date and time in the real time clock. */
static inline int set_rtc_time(struct rtc_time *time)
{
if (ppc_md.get_rtc_time) {
ppc_md.set_rtc_time(time);
return 0;
}
return -EINVAL;
}
static inline unsigned int get_rtc_ss(void)
{
struct rtc_time h;
get_rtc_time(&h);
return h.tm_sec;
}
static inline int get_rtc_pll(struct rtc_pll_info *pll)
{
return -EINVAL;
}
static inline int set_rtc_pll(struct rtc_pll_info *pll)
{
return -EINVAL;
}
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_RTC_H__ */
...@@ -10,32 +10,36 @@ ...@@ -10,32 +10,36 @@
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#ifndef __PPC64_TIME_H #ifndef __POWERPC_TIME_H
#define __PPC64_TIME_H #define __POWERPC_TIME_H
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/mc146818rtc.h> #include <linux/percpu.h>
#include <asm/processor.h> #include <asm/processor.h>
#ifdef CONFIG_PPC64
#include <asm/paca.h> #include <asm/paca.h>
#include <asm/iSeries/HvCall.h> #include <asm/iSeries/HvCall.h>
#endif
/* time.c */ /* time.c */
extern unsigned long tb_ticks_per_jiffy; extern unsigned long tb_ticks_per_jiffy;
extern unsigned long tb_ticks_per_usec; extern unsigned long tb_ticks_per_usec;
extern unsigned long tb_ticks_per_sec; extern unsigned long tb_ticks_per_sec;
extern unsigned long tb_to_xs; extern u64 tb_to_xs;
extern unsigned tb_to_us; extern unsigned tb_to_us;
extern unsigned long tb_last_stamp; extern u64 tb_last_stamp;
DECLARE_PER_CPU(unsigned long, last_jiffy);
struct rtc_time; struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm); extern void to_tm(int tim, struct rtc_time * tm);
extern time_t last_rtc_update; extern time_t last_rtc_update;
void generic_calibrate_decr(void); extern void generic_calibrate_decr(void);
void setup_default_decr(void); extern void wakeup_decrementer(void);
/* Some sane defaults: 125 MHz timebase, 1GHz processor */ /* Some sane defaults: 125 MHz timebase, 1GHz processor */
extern unsigned long ppc_proc_freq; extern unsigned long ppc_proc_freq;
...@@ -47,12 +51,12 @@ extern unsigned long ppc_tb_freq; ...@@ -47,12 +51,12 @@ extern unsigned long ppc_tb_freq;
* By putting all of this stuff into a single struct we * By putting all of this stuff into a single struct we
* reduce the number of cache lines touched by do_gettimeofday. * reduce the number of cache lines touched by do_gettimeofday.
* Both by collecting all of the data in one cache line and * Both by collecting all of the data in one cache line and
* by touching only one TOC entry * by touching only one TOC entry on ppc64.
*/ */
struct gettimeofday_vars { struct gettimeofday_vars {
unsigned long tb_to_xs; u64 tb_to_xs;
unsigned long stamp_xsec; u64 stamp_xsec;
unsigned long tb_orig_stamp; u64 tb_orig_stamp;
}; };
struct gettimeofday_struct { struct gettimeofday_struct {
...@@ -64,25 +68,100 @@ struct gettimeofday_struct { ...@@ -64,25 +68,100 @@ struct gettimeofday_struct {
}; };
struct div_result { struct div_result {
unsigned long result_high; u64 result_high;
unsigned long result_low; u64 result_low;
}; };
int via_calibrate_decr(void); /* Accessor functions for the timebase (RTC on 601) registers. */
/* If one day CONFIG_POWER is added just define __USE_RTC as 1 */
#ifdef CONFIG_6xx
#define __USE_RTC() cpu_has_feature(CPU_FTR_USE_TB)
#else
#define __USE_RTC() 0
#endif
/* On ppc64 this gets us the whole timebase; on ppc32 just the lower half */
static inline unsigned long get_tbl(void)
{
unsigned long tbl;
#if defined(CONFIG_403GCX)
asm volatile("mfspr %0, 0x3dd" : "=r" (tbl));
#else
asm volatile("mftb %0" : "=r" (tbl));
#endif
return tbl;
}
static inline unsigned int get_tbu(void)
{
unsigned int tbu;
#if defined(CONFIG_403GCX)
asm volatile("mfspr %0, 0x3dc" : "=r" (tbu));
#else
asm volatile("mftbu %0" : "=r" (tbu));
#endif
return tbu;
}
static inline unsigned int get_rtcl(void)
{
unsigned int rtcl;
asm volatile("mfrtcl %0" : "=r" (rtcl));
return rtcl;
}
static __inline__ unsigned long get_tb(void) #ifdef CONFIG_PPC64
static inline u64 get_tb(void)
{ {
return mftb(); return mftb();
} }
#else
static inline u64 get_tb(void)
{
unsigned int tbhi, tblo, tbhi2;
do {
tbhi = get_tbu();
tblo = get_tbl();
tbhi2 = get_tbu();
} while (tbhi != tbhi2);
return ((u64)tbhi << 32) | tblo;
}
#endif
/* Accessor functions for the decrementer register. */ static inline void set_tb(unsigned int upper, unsigned int lower)
static __inline__ unsigned int get_dec(void)
{ {
mtspr(SPRN_TBWL, 0);
mtspr(SPRN_TBWU, upper);
mtspr(SPRN_TBWL, lower);
}
/* Accessor functions for the decrementer register.
* The 4xx doesn't even have a decrementer. I tried to use the
* generic timer interrupt code, which seems OK, with the 4xx PIT
* in auto-reload mode. The problem is PIT stops counting when it
* hits zero. If it would wrap, we could use it just like a decrementer.
*/
static inline unsigned int get_dec(void)
{
#if defined(CONFIG_40x)
return (mfspr(SPRN_PIT));
#else
return (mfspr(SPRN_DEC)); return (mfspr(SPRN_DEC));
#endif
} }
static __inline__ void set_dec(int val) static inline void set_dec(int val)
{ {
#if defined(CONFIG_40x)
return; /* Have to let it auto-reload */
#elif defined(CONFIG_8xx_CPU6)
set_dec_cpu6(val);
#else
#ifdef CONFIG_PPC_ISERIES #ifdef CONFIG_PPC_ISERIES
struct paca_struct *lpaca = get_paca(); struct paca_struct *lpaca = get_paca();
int cur_dec; int cur_dec;
...@@ -95,22 +174,31 @@ static __inline__ void set_dec(int val) ...@@ -95,22 +174,31 @@ static __inline__ void set_dec(int val)
} else } else
#endif #endif
mtspr(SPRN_DEC, val); mtspr(SPRN_DEC, val);
#endif /* not 40x or 8xx_CPU6 */
} }
static inline unsigned long tb_ticks_since(unsigned long tstamp) static inline unsigned long tb_ticks_since(unsigned long tstamp)
{ {
return get_tb() - tstamp; if (__USE_RTC()) {
int delta = get_rtcl() - (unsigned int) tstamp;
return delta < 0 ? delta + 1000000000 : delta;
}
return get_tbl() - tstamp;
} }
#define mulhwu(x,y) \ #define mulhwu(x,y) \
({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) ({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
#ifdef CONFIG_PPC64
#define mulhdu(x,y) \ #define mulhdu(x,y) \
({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) ({unsigned long z; asm ("mulhdu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
#else
extern u64 mulhdu(u64, u64);
#endif
unsigned mulhwu_scale_factor(unsigned, unsigned); unsigned mulhwu_scale_factor(unsigned, unsigned);
void div128_by_32( unsigned long dividend_high, unsigned long dividend_low, void div128_by_32(u64 dividend_high, u64 dividend_low,
unsigned divisor, struct div_result *dr ); unsigned divisor, struct div_result *dr);
/* Used to store Processor Utilization register (purr) values */ /* Used to store Processor Utilization register (purr) values */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment