Timecounter and generic todr support for pmax. From Garret D'Amore.

This commit is contained in:
joerg 2008-01-03 23:02:24 +00:00
parent 26ecc8b33a
commit 28b31e738f
13 changed files with 187 additions and 342 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: mcclock_ibus.c,v 1.12 2002/10/02 04:15:09 thorpej Exp $ */
/* $NetBSD: mcclock_ibus.c,v 1.13 2008/01/03 23:02:24 joerg Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@ -28,12 +28,13 @@
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: mcclock_ibus.c,v 1.12 2002/10/02 04:15:09 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: mcclock_ibus.c,v 1.13 2008/01/03 23:02:24 joerg Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <dev/clock_subr.h>
#include <dev/dec/mcclockvar.h>
#include <dev/dec/mcclock_pad32.h>

View File

@ -1,4 +1,4 @@
/* $NetBSD: sysconf.h,v 1.11 2007/03/04 06:00:33 christos Exp $ */
/* $NetBSD: sysconf.h,v 1.12 2008/01/03 23:02:24 joerg Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@ -63,7 +63,7 @@ struct platform {
* iointr - I/O interrupt handler
* intr_establish - establish interrupt handler
* intr_disestablish - disestablish interrupt handler
* clkread - interporate HZ with hi-resolution timer
* tc_init - initialize timecounters
*/
void (*bus_reset) __P((void));
void (*cons_init) __P((void));
@ -71,7 +71,7 @@ struct platform {
void (*intr_establish) __P((struct device *, void *, int,
int (*)(void *), void *));
int (*memsize) __P((void *));
unsigned (*clkread) __P((void));
void (*tc_init)(void);
};
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: types.h,v 1.23 2007/10/17 19:56:15 garbled Exp $ */
/* $NetBSD: types.h,v 1.24 2008/01/03 23:02:24 joerg Exp $ */
#include <mips/types.h>
@ -7,3 +7,5 @@
/* MIPS specific options */
#define __HAVE_BOOTINFO_H
#define __HAVE_MIPS_MACHDEP_CACHE_CONFIG
#define __HAVE_GENERIC_TODR
#define __HAVE_TIMECOUNTER

View File

@ -1,4 +1,4 @@
/* $NetBSD: clock.c,v 1.34 2005/12/11 12:18:39 christos Exp $ */
/* $NetBSD: clock.c,v 1.35 2008/01/03 23:02:24 joerg Exp $ */
/*
* Copyright (c) 1992, 1993
@ -78,7 +78,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.34 2005/12/11 12:18:39 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.35 2008/01/03 23:02:24 joerg Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -87,11 +87,10 @@ __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.34 2005/12/11 12:18:39 christos Exp $");
#include <dev/clock_subr.h>
#include <dev/dec/clockvar.h>
#include <machine/sysconf.h>
#include "opt_ntp.h"
#define MINYEAR 1998 /* "today" */
struct device *clockdev;
const struct clockfns *clockfns;
int clockinitted;
@ -126,12 +125,6 @@ clockattach(dev, fns)
*
* Startrtclock restarts the real-time clock, which provides
* hardclock interrupts to kern_clock.c.
*
* Inittodr initializes the time of day hardware which provides
* date functions. Its primary function is to use some file
* system information in case the hardare clock lost state.
*
* Resettodr restores the time of day hardware after a time change.
*/
/*
@ -168,17 +161,10 @@ cpu_initclocks()
* case the initialisation routines adjusted hz.
*/
tick = 1000000 / hz; /* number of microseconds between interrupts */
tickfix = 1000000 - (hz * tick);
#ifdef NTP
fixtick = tickfix;
#endif
if (tickfix) {
int ftp;
ftp = min(ffs(tickfix), ffs(hz));
tickfix >>= (ftp - 1);
tickfixinterval = hz >> (ftp - 1);
}
/* setup time counters */
if (platform.tc_init)
(*platform.tc_init)();
}
/*
@ -194,160 +180,3 @@ setstatclockrate(newhz)
/* nothing we can do */
}
/*
* Experiments (and passing years) show that Decstation PROMS
* assume the kernel uses the clock chip as a time-of-year clock.
* The PROM assumes the clock is always set to 1972 or 1973, and contains
* time-of-year in seconds. The PROM checks the clock at boot time,
* and if it's outside that range, sets it to 1972-01-01.
*
* XXX should be at the mc146818 layer?
*/
/*
* Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem. Base provides the time to within six months,
* and the time of year clock (if any) provides the rest.
*/
void
inittodr(base)
time_t base;
{
struct clocktime ct;
struct clock_ymdhms dt;
time_t yearsecs;
time_t deltat;
int badbase;
if (base < (MINYEAR-1970)*SECYR) {
printf("WARNING: preposterous time in file system");
/* read the system clock anyway */
base = (MINYEAR-1970)*SECYR;
badbase = 1;
} else
badbase = 0;
(*clockfns->cf_get)(clockdev, base, &ct);
#ifdef DEBUG
printf("readclock: %d/%d/%d/%d/%d/%d", ct.year, ct.mon, ct.day,
ct.hour, ct.min, ct.sec);
#endif
clockinitted = 1;
/* simple sanity checks */
if (ct.year < 70 || ct.mon < 1 || ct.mon > 12 || ct.day < 1 ||
ct.day > 31 || ct.hour > 23 || ct.min > 59 || ct.sec > 59) {
/*
* Believe the time in the file system for lack of
* anything better, resetting the TODR.
*/
time.tv_sec = base;
if (!badbase) {
printf("WARNING: preposterous clock chip time\n");
resettodr();
}
goto bad;
}
/*
* The clock lives in 1972 (leapyear!);
* calculate seconds relative to this year.
*/
dt.dt_year = 1972;
dt.dt_mon = ct.mon;
dt.dt_day = ct.day;
dt.dt_hour = ct.hour;
dt.dt_min = ct.min;
dt.dt_sec = ct.sec;
yearsecs = clock_ymdhms_to_secs(&dt) - (72 - 70) * SECYR;
/*
* Take the actual year from the filesystem if possible;
* allow for 2 days of clock loss and 363 days of clock gain.
*/
dt.dt_year = 1972; /* or MINYEAR or base/SECYR+1970 ... */
dt.dt_mon = 1;
dt.dt_day = 1;
dt.dt_hour = 0;
dt.dt_min = 0;
dt.dt_sec = 0;
for(;;) {
time.tv_sec = yearsecs + clock_ymdhms_to_secs(&dt);
if (badbase || (time.tv_sec > base - 2 * SECDAY))
break;
dt.dt_year++;
}
#ifdef DEBUG
printf("=>%ld (%ld)\n", time.tv_sec, base);
#endif
if (!badbase) {
/*
* See if we gained/lost two or more days;
* if so, assume something is amiss.
*/
deltat = time.tv_sec - base;
if (deltat < 0)
deltat = -deltat;
if (deltat < 2 * SECDAY)
return;
printf("WARNING: clock %s %d days",
time.tv_sec < base ? "lost" : "gained",
(int) (deltat / SECDAY));
}
bad:
printf(" -- CHECK AND RESET THE DATE!\n");
}
/*
* Reset the TODR based on the time value; used when the TODR
* has a preposterous value and also when the time is reset
* by the stime system call. Also called when the TODR goes past
* TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
* to wrap the TODR around.
*/
void
resettodr()
{
time_t yearsecs;
struct clock_ymdhms dt;
struct clocktime ct;
if (!clockinitted)
return;
/*
* calculate seconds relative to this year
*/
clock_secs_to_ymdhms(time.tv_sec, &dt); /* get the year */
dt.dt_mon = 1;
dt.dt_day = 1;
dt.dt_hour = 0;
dt.dt_min = 0;
dt.dt_sec = 0;
yearsecs = time.tv_sec - clock_ymdhms_to_secs(&dt);
/*
* The clock lives in 1972 (leapyear!); calc fictious date.
*/
#define first72 ((72 - 70) * SECYR)
clock_secs_to_ymdhms(first72 + yearsecs, &dt);
#ifdef DEBUG
if (dt.dt_year != 1972)
printf("resettodr: botch (%ld, %ld)\n", yearsecs, time.tv_sec);
#endif
ct.year = dt.dt_year % 100; /* rt clock wants 2 digits */
ct.mon = dt.dt_mon;
ct.day = dt.dt_day;
ct.hour = dt.dt_hour;
ct.min = dt.dt_min;
ct.sec = dt.dt_sec;
ct.dow = dt.dt_wday;
#ifdef DEBUG
printf("setclock: %d/%d/%d/%d/%d/%d\n", ct.year, ct.mon, ct.day,
ct.hour, ct.min, ct.sec);
#endif
(*clockfns->cf_set)(clockdev, &ct);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: dec_3maxplus.c,v 1.57 2007/12/03 15:34:10 ad Exp $ */
/* $NetBSD: dec_3maxplus.c,v 1.58 2008/01/03 23:02:24 joerg Exp $ */
/*
* Copyright (c) 1998 Jonathan Stone. All rights reserved.
@ -106,11 +106,12 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: dec_3maxplus.c,v 1.57 2007/12/03 15:34:10 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: dec_3maxplus.c,v 1.58 2008/01/03 23:02:24 joerg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/timetc.h>
#include <machine/cpu.h>
#include <machine/sysconf.h>
@ -140,7 +141,8 @@ static void dec_3maxplus_intr_establish __P((struct device *, void *,
int, int (*)(void *), void *));
static void kn03_wbflush __P((void));
static unsigned kn03_clkread __P((void));
static void dec_3maxplus_tc_init(void);
/*
* Local declarations
@ -173,8 +175,8 @@ dec_3maxplus_init()
platform.iointr = dec_3maxplus_intr;
platform.intr_establish = dec_3maxplus_intr_establish;
platform.memsize = memsize_bitmap;
platform.clkread = kn03_clkread;
/* 3MAX+ has IOASIC free-running high resolution timer */
platform.tc_init = dec_3maxplus_tc_init;
/* clear any memory errors */
*(u_int32_t *)MIPS_PHYS_TO_KSEG1(KN03_SYS_ERRADR) = 0;
@ -337,7 +339,6 @@ dec_3maxplus_intr(status, cause, pc, ipending)
__asm volatile("lbu $0,48(%0)" ::
"r"(ioasic_base + IOASIC_SLOT_8_START));
latched_cycle_cnt = *(u_int32_t *)(ioasic_base + IOASIC_CTR);
cf.pc = pc;
cf.sr = status;
hardclock(&cf);
@ -455,34 +456,25 @@ kn03_wbflush()
}
/*
* TURBOchannel bus-cycle counter provided by IOASIC;
* Interpolate micro-seconds since the last RTC clock tick. The
* interpolation base is the copy of the bus cycle-counter taken by
* the RTC interrupt handler.
* TURBOchannel bus-cycle counter provided by IOASIC; 25 MHz
*/
static unsigned
kn03_clkread()
dec_3maxplus_get_timecount(struct timecounter *tc)
{
u_int32_t usec, cycles;
cycles = *(u_int32_t*)(ioasic_base + IOASIC_CTR);
cycles = cycles - latched_cycle_cnt;
/*
* Scale from 40ns to microseconds.
* Avoid a kernel FP divide (by 25) using the approximation
* 1/25 = 40/1000 =~ 41/ 1024, which is good to 0.0975 %
*/
usec = cycles + (cycles << 3) + (cycles << 5);
usec = usec >> 10;
#ifdef CLOCK_DEBUG
if (usec > 3906 +4) {
addlog("clkread: usec %d, counter=%lx\n",
usec, latched_cycle_cnt);
stacktrace();
return *(u_int32_t*)(ioasic_base + IOASIC_CTR);
}
#endif /*CLOCK_DEBUG*/
return usec;
static void
dec_3maxplus_tc_init(void)
{
static struct timecounter tc = {
.tc_get_timecount = dec_3maxplus_get_timecount,
.tc_quality = 100,
.tc_frequency = 25000000,
.tc_counter_mask = ~0,
.tc_name = "turbochannel_counter",
};
tc_init(&tc);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: dec_3min.c,v 1.58 2007/12/03 15:34:10 ad Exp $ */
/* $NetBSD: dec_3min.c,v 1.59 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1998 Jonathan Stone. All rights reserved.
@ -106,11 +106,12 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: dec_3min.c,v 1.58 2007/12/03 15:34:10 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: dec_3min.c,v 1.59 2008/01/03 23:02:25 joerg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/timetc.h>
#include <machine/cpu.h>
#include <machine/intr.h>
@ -140,18 +141,14 @@ static void dec_3min_intr_establish __P((struct device *, void *,
int, int (*)(void *), void *));
static void kn02ba_wbflush __P((void));
static unsigned kn02ba_clkread __P((void));
static void dec_3min_tc_init(void);
/*
* Local declarations.
*/
static u_int32_t kmin_tc3_imask;
#ifdef MIPS3
static unsigned latched_cycle_cnt;
#endif
static const int dec_3min_ipl2spl_table[] = {
[IPL_NONE] = 0,
[IPL_SOFTCLOCK] = _SPL_SOFTCLOCK,
@ -176,7 +173,7 @@ dec_3min_init()
platform.iointr = dec_3min_intr;
platform.intr_establish = dec_3min_intr_establish;
platform.memsize = memsize_bitmap;
platform.clkread = kn02ba_clkread;
platform.tc_init = dec_3min_tc_init;
/* clear any memory errors */
*(u_int32_t *)MIPS_PHYS_TO_KSEG1(KMIN_REG_TIMEOUT) = 0;
@ -409,11 +406,7 @@ dec_3min_intr(status, cause, pc, ipending)
__asm volatile("lbu $0,48(%0)" ::
"r"(ioasic_base + IOASIC_SLOT_8_START));
#ifdef MIPS3
if (CPUISMIPS3) {
latched_cycle_cnt = mips3_cp0_count_read();
}
#endif
cf.pc = pc;
cf.sr = status;
hardclock(&cf);
@ -502,18 +495,26 @@ kn02ba_wbflush()
"i"(MIPS_PHYS_TO_KSEG1(KMIN_REG_IMSK)));
}
static unsigned
kn02ba_clkread()
{
#ifdef MIPS3
if (CPUISMIPS3) {
u_int32_t mips3_cycles;
/*
* Support for using the MIPS 3 clock as a timecounter.
*/
mips3_cycles = mips3_cp0_count_read() - latched_cycle_cnt;
/* XXX divides take 78 cycles: approximate with * 41/2048 */
return((mips3_cycles >> 6) + (mips3_cycles >> 8) +
(mips3_cycles >> 11));
void
dec_3min_tc_init(void)
{
static struct timecounter tc = {
.tc_get_timecount = (timecounter_get_t *)mips3_cp0_count_read,
.tc_counter_mask = ~0u,
.tc_name = "mips3_cp0_counter",
.tc_quality = 100,
};
if (MIPS_HAS_CLOCK) {
tc.tc_frequency = cpu_mhz * 1000000;
if (mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) {
tc.tc_frequency /= 2;
}
tc_init(&tc);
}
#endif
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: dec_maxine.c,v 1.51 2007/12/03 15:34:11 ad Exp $ */
/* $NetBSD: dec_maxine.c,v 1.52 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1998 Jonathan Stone. All rights reserved.
@ -106,11 +106,12 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: dec_maxine.c,v 1.51 2007/12/03 15:34:11 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: dec_maxine.c,v 1.52 2008/01/03 23:02:25 joerg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/timetc.h>
#include <machine/cpu.h>
#include <machine/sysconf.h>
@ -137,14 +138,14 @@ static void dec_maxine_intr __P((unsigned, unsigned, unsigned, unsigned));
static void dec_maxine_intr_establish __P((struct device *, void *,
int, int (*)(void *), void *));
static void dec_maxine_tc_init(void);
static void kn02ca_wbflush __P((void));
static unsigned kn02ca_clkread __P((void));
/*
* local declarations
*/
static u_int32_t xine_tc3_imask;
static unsigned latched_cycle_cnt;
static const int dec_maxine_ipl2spl_table[] = {
[IPL_NONE] = 0,
@ -169,7 +170,7 @@ dec_maxine_init()
platform.iointr = dec_maxine_intr;
platform.intr_establish = dec_maxine_intr_establish;
platform.memsize = memsize_bitmap;
platform.clkread = kn02ca_clkread;
platform.tc_init = dec_maxine_tc_init;
/* MAXINE has 1 microsec. free-running high resolution timer */
/* clear any memory errors */
@ -331,8 +332,6 @@ dec_maxine_intr(status, cause, pc, ipending)
__asm volatile("lbu $0,48(%0)" ::
"r"(ioasic_base + IOASIC_SLOT_8_START));
latched_cycle_cnt =
*(u_int32_t *)MIPS_PHYS_TO_KSEG1(XINE_REG_FCTR);
cf.pc = pc;
cf.sr = status;
hardclock(&cf);
@ -408,11 +407,22 @@ kn02ca_wbflush()
"i"(MIPS_PHYS_TO_KSEG1(XINE_REG_IMSK)));
}
static unsigned
kn02ca_clkread()
static uint32_t
dec_maxine_get_timecount(struct timecounter *tc)
{
u_int32_t cycles;
cycles = *(u_int32_t *)MIPS_PHYS_TO_KSEG1(XINE_REG_FCTR);
return cycles - latched_cycle_cnt;
return *(u_int32_t *)MIPS_PHYS_TO_KSEG1(XINE_REG_FCTR);
}
static void
dec_maxine_tc_init(void)
{
static struct timecounter tc = {
.tc_get_timecount = dec_maxine_get_timecount,
.tc_quality = 100,
.tc_frequency = 1000000,
.tc_counter_mask = ~0,
.tc_name = "maxine_fctr",
};
tc_init(&tc);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.221 2007/10/17 19:56:15 garbled Exp $ */
/* $NetBSD: machdep.c,v 1.222 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1992, 1993
@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.221 2007/10/17 19:56:15 garbled Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.222 2008/01/03 23:02:25 joerg Exp $");
#include "fs_mfs.h"
#include "opt_ddb.h"
@ -704,38 +704,6 @@ nullwork()
return (0);
}
/*
* Return the best possible estimate of the time in the timeval to
* which tvp points. We guarantee that the time will be greater than
* the value obtained by a previous call. Some models of DECstations
* provide a high resolution timer circuit.
*/
void
microtime(tvp)
struct timeval *tvp;
{
int s = splclock();
static struct timeval lasttime;
*tvp = time;
#if defined(DEC_3MIN) || defined(DEC_MAXINE) || defined(DEC_3MAXPLUS)
tvp->tv_usec += (*platform.clkread)();
#endif
if (tvp->tv_usec >= 1000000) {
tvp->tv_usec -= 1000000;
tvp->tv_sec++;
}
if (tvp->tv_sec == lasttime.tv_sec &&
tvp->tv_usec <= lasttime.tv_usec &&
(tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
tvp->tv_sec++;
tvp->tv_usec -= 1000000;
}
lasttime = *tvp;
splx(s);
}
/*
* Wait "n" microseconds. (scsi code needs this).
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: mcclock_ioasic.c,v 1.18 2002/10/02 04:15:10 thorpej Exp $ */
/* $NetBSD: mcclock_ioasic.c,v 1.19 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@ -28,11 +28,12 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mcclock_ioasic.c,v 1.18 2002/10/02 04:15:10 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: mcclock_ioasic.c,v 1.19 2008/01/03 23:02:25 joerg Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <dev/clock_subr.h>
#include <dev/dec/mcclockvar.h>
#include <dev/dec/mcclock_pad32.h>

View File

@ -1,4 +1,4 @@
/* $NetBSD: clockvar.h,v 1.8 2005/12/11 12:21:20 christos Exp $ */
/* $NetBSD: clockvar.h,v 1.9 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
@ -31,22 +31,6 @@
* Definitions for CPU-independent clock handling for the alpha and pmax.
*/
/*
* clocktime structure:
*
* structure passed to TOY clocks when setting them. broken out this
* way, so that the time_t -> field conversion can be shared.
*/
struct clocktime {
int year; /* year - 1900 */
int mon; /* month (1 - 12) */
int day; /* day (1 - 31) */
int hour; /* hour (0 - 23) */
int min; /* minute (0 - 59) */
int sec; /* second (0 - 59) */
int dow; /* day of week (0 - 6; 0 = Sunday) */
};
/*
* clockfns structure:
*
@ -55,8 +39,6 @@ struct clocktime {
*/
struct clockfns {
void (*cf_init)(struct device *);
void (*cf_get)(struct device *, time_t, struct clocktime *);
void (*cf_set)(struct device *, struct clocktime *);
};
void clockattach(struct device *, const struct clockfns *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: mcclock.c,v 1.17 2005/12/11 12:21:20 christos Exp $ */
/* $NetBSD: mcclock.c,v 1.18 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@ -28,12 +28,13 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.17 2005/12/11 12:21:20 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.18 2008/01/03 23:02:25 joerg Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <dev/clock_subr.h>
#include <dev/dec/clockvar.h>
#include <dev/dec/mcclockvar.h>
@ -51,11 +52,11 @@ __KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.17 2005/12/11 12:21:20 christos Exp $"
void mcclock_init(struct device *);
void mcclock_get(struct device *, time_t, struct clocktime *);
void mcclock_set(struct device *, struct clocktime *);
int mcclock_get(todr_chip_handle_t, volatile struct timeval *);
int mcclock_set(todr_chip_handle_t, volatile struct timeval *);
const struct clockfns mcclock_clockfns = {
mcclock_init, mcclock_get, mcclock_set,
mcclock_init,
};
#define mc146818_write(dev, reg, datum) \
@ -69,7 +70,7 @@ mcclock_attach(sc, busfns)
const struct mcclock_busfns *busfns;
{
printf(": mc146818 or compatible");
printf(": mc146818 or compatible\n");
sc->sc_busfns = busfns;
@ -77,6 +78,11 @@ mcclock_attach(sc, busfns)
mc146818_write(sc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR);
clockattach(&sc->sc_dev, &mcclock_clockfns);
sc->sc_todr.todr_gettime = mcclock_get;
sc->sc_todr.todr_settime = mcclock_set;
sc->sc_todr.cookie = sc;
todr_attach(&sc->sc_todr);
}
void
@ -132,57 +138,108 @@ again:
MC_REGB_PIE | MC_REGB_SQWE | MC_REGB_BINARY | MC_REGB_24HR);
}
/*
* Experiments (and passing years) show that Decstation PROMS
* assume the kernel uses the clock chip as a time-of-year clock.
* The PROM assumes the clock is always set to 1972 or 1973, and contains
* time-of-year in seconds. The PROM checks the clock at boot time,
* and if it's outside that range, sets it to 1972-01-01.
*
* XXX should be at the mc146818 layer?
*/
/*
* Get the time of day, based on the clock's value and/or the base value.
*/
void
mcclock_get(dev, base, ct)
struct device *dev;
time_t base;
struct clocktime *ct;
int
mcclock_get(todr_chip_handle_t tch, volatile struct timeval *tvp)
{
struct mcclock_softc *sc = (struct mcclock_softc *)dev;
struct mcclock_softc *sc = (struct mcclock_softc *)tch->cookie;
uint32_t yearsecs;
mc_todregs regs;
int s;
struct clock_ymdhms dt;
s = splclock();
MC146818_GETTOD(sc, &regs)
splx(s);
ct->sec = regs[MC_SEC];
ct->min = regs[MC_MIN];
ct->hour = regs[MC_HOUR];
ct->dow = regs[MC_DOW];
ct->day = regs[MC_DOM];
ct->mon = regs[MC_MONTH];
ct->year = regs[MC_YEAR];
dt.dt_sec = regs[MC_SEC];
dt.dt_min = regs[MC_MIN];
dt.dt_hour = regs[MC_HOUR];
dt.dt_day = regs[MC_DOM];
dt.dt_mon = regs[MC_MONTH];
dt.dt_year = 1972;
yearsecs = clock_ymdhms_to_secs(&dt) - (72 - 70) * SECYR;
/*
* Take the actual year from the filesystem if possible;
* allow for 2 days of clock loss and 363 days of clock gain.
*/
dt.dt_year = 1972; /* or MINYEAR or base/SECYR+1970 ... */
dt.dt_mon = 1;
dt.dt_day = 1;
dt.dt_hour = 0;
dt.dt_min = 0;
dt.dt_sec = 0;
for(;;) {
tvp->tv_sec = yearsecs + clock_ymdhms_to_secs(&dt);
if (tvp->tv_sec > tch->base_time - 2 * SECDAY)
break;
dt.dt_year++;
}
tvp->tv_usec = 0;
return 0;
}
/*
* Reset the TODR based on the time value.
*/
void
mcclock_set(dev, ct)
struct device *dev;
struct clocktime *ct;
int
mcclock_set(todr_chip_handle_t tch, volatile struct timeval *tvp)
{
struct mcclock_softc *sc = (struct mcclock_softc *)dev;
struct mcclock_softc *sc = (struct mcclock_softc *)tch->cookie;
struct clock_ymdhms dt;
uint32_t yearsecs;
mc_todregs regs;
int s;
/*
* calculate seconds relative to this year
*/
clock_secs_to_ymdhms(tvp->tv_sec, &dt); /* get the year */
dt.dt_mon = 1;
dt.dt_day = 1;
dt.dt_hour = 0;
dt.dt_min = 0;
dt.dt_sec = 0;
yearsecs = tvp->tv_sec - clock_ymdhms_to_secs(&dt);
#define first72 ((72 - 70) * SECYR)
clock_secs_to_ymdhms(first72 + yearsecs, &dt);
#ifdef DEBUG
if (dt.dt_year != 1972)
printf("resettodr: botch (%ld, %ld)\n", yearsecs, time.tv_sec);
#endif
s = splclock();
MC146818_GETTOD(sc, &regs);
splx(s);
regs[MC_SEC] = ct->sec;
regs[MC_MIN] = ct->min;
regs[MC_HOUR] = ct->hour;
regs[MC_DOW] = ct->dow;
regs[MC_DOM] = ct->day;
regs[MC_MONTH] = ct->mon;
regs[MC_YEAR] = ct->year;
regs[MC_SEC] = dt.dt_sec;
regs[MC_MIN] = dt.dt_min;
regs[MC_HOUR] = dt.dt_hour;
regs[MC_DOW] = dt.dt_wday;
regs[MC_DOM] = dt.dt_day;
regs[MC_MONTH] = dt.dt_mon;
regs[MC_YEAR] = dt.dt_year;
s = splclock();
MC146818_PUTTOD(sc, &regs);
splx(s);
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: mcclock_pad32.c,v 1.13 2005/12/11 12:21:20 christos Exp $ */
/* $NetBSD: mcclock_pad32.c,v 1.14 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mcclock_pad32.c,v 1.13 2005/12/11 12:21:20 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: mcclock_pad32.c,v 1.14 2008/01/03 23:02:25 joerg Exp $");
/*
@ -49,6 +49,7 @@ __KERNEL_RCSID(0, "$NetBSD: mcclock_pad32.c,v 1.13 2005/12/11 12:21:20 christos
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <dev/clock_subr.h>
#include <machine/autoconf.h>
#include <dev/dec/clockvar.h>

View File

@ -1,4 +1,4 @@
/* $NetBSD: mcclockvar.h,v 1.6 2005/12/11 12:21:20 christos Exp $ */
/* $NetBSD: mcclockvar.h,v 1.7 2008/01/03 23:02:25 joerg Exp $ */
/*
* Copyright (c) 1996 Carnegie-Mellon University.
@ -30,6 +30,7 @@
struct mcclock_softc {
struct device sc_dev;
const struct mcclock_busfns *sc_busfns;
struct todr_chip_handle sc_todr;
};
struct mcclock_busfns {