Cleanup the clock code. This includes:
o Remove alpha specific timer code (mc146818A) and compiled-out calibration of said timer. o Remove i386 inherited timer code (i8253) and related acquire and release functions. o Move sysbeep() from clock.c to machdep.c and have it return ENODEV. Console beeps should be implemented using ACPI or if no such device is described, using the sound driver. o Move the sysctls related to adjkerntz, disable_rtc_set and wall_cmos_clock from machdep.c to clock.c, where the variables are. o Don't hardcode a hz value of 1024 in cpu_initclocks() and don't bother faking a stathz that's 1/8 of that. Keep it simple: hz defaults to HZ and stathz equals hz. This is also how it's done for sparc64. o Keep a per-CPU ITC counter (pc_clock) and adjustment (pc_clockadj) to calculate ITC skew and corrections. On average, we adjust the ITC match register once every ~1500 interrupts for a duration of 2 consequtive interruprs. This is to correct the non-deterministic behaviour of the ITC interrupt (there's a delay between the match and the raising of the interrupt). o Add 4 debugging sysctls to monitor clock behaviour. Those are debug.clock_adjust_edges, debug.clock_adjust_excess, debug.clock_adjust_lost and debug.clock_adjust_ticks. The first counts the individual adjustment cycles (when the skew first crosses the threshold), the second counts the number of times the adjustment was excessive (any non-zero value is to be considered a bug), the third counts lost clock interrupts and the last counts the number of interrupts for which we applied an adjustment (debug.clock_adjust_ticks / debug.clock_adjust_edges gives the avarage duration of an individual adjustment -- should be ~2). While here, remove some nearby (trivial) left-overs from alpha and other cleanups.
This commit is contained in:
parent
0c6d0d5962
commit
a9b84efaa9
@ -1,6 +1,3 @@
|
||||
/* $FreeBSD$ */
|
||||
/* $NetBSD: clock.c,v 1.20 1998/01/31 10:32:47 ross Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988 University of Utah.
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -42,8 +39,10 @@
|
||||
*
|
||||
* @(#)clock.c 8.1 (Berkeley) 6/10/93
|
||||
*/
|
||||
/* $NetBSD: clock.c,v 1.20 1998/01/31 10:32:47 ross Exp $ */
|
||||
|
||||
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -52,13 +51,11 @@
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/timetc.h>
|
||||
#include <sys/pcpu.h>
|
||||
|
||||
#include <machine/pal.h>
|
||||
#include <machine/sal.h>
|
||||
#include <machine/clock.h>
|
||||
#include <machine/clockvar.h>
|
||||
#include <isa/isareg.h>
|
||||
#include <ia64/ia64/timerreg.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#define SECMIN ((unsigned)60) /* seconds per minute */
|
||||
#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */
|
||||
@ -68,198 +65,107 @@
|
||||
/*
|
||||
* 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
|
||||
* can use a simple formula for leap years.
|
||||
* XXX time_t is 64-bits on ia64.
|
||||
*/
|
||||
#define LEAPYEAR(y) (((y) % 4) == 0)
|
||||
|
||||
kobj_t clockdev;
|
||||
int clockinitted;
|
||||
int tickfix;
|
||||
int tickfixinterval;
|
||||
static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
int disable_rtc_set; /* disable resettodr() if != 0 */
|
||||
SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set,
|
||||
CTLFLAG_RW, &disable_rtc_set, 0, "");
|
||||
|
||||
int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
|
||||
SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock,
|
||||
CTLFLAG_RW, &wall_cmos_clock, 0, "");
|
||||
|
||||
int adjkerntz; /* local offset from GMT in seconds */
|
||||
int disable_rtc_set; /* disable resettodr() if != 0 */
|
||||
int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
|
||||
u_int64_t itm_reload; /* reload ticks for clock */
|
||||
static int beeping = 0;
|
||||
SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW,
|
||||
&adjkerntz, 0, sysctl_machdep_adjkerntz, "I", "");
|
||||
|
||||
kobj_t clockdev;
|
||||
int todr_initialized;
|
||||
|
||||
uint64_t ia64_clock_reload;
|
||||
|
||||
#ifndef SMP
|
||||
static timecounter_get_t ia64_get_timecount;
|
||||
static timecounter_get_t ia64_get_timecount;
|
||||
|
||||
static struct timecounter ia64_timecounter = {
|
||||
ia64_get_timecount, /* get_timecount */
|
||||
0, /* no poll_pps */
|
||||
~0u, /* counter_mask */
|
||||
~0u, /* counter_mask */
|
||||
0, /* frequency */
|
||||
"ITC" /* name */
|
||||
};
|
||||
|
||||
static unsigned
|
||||
ia64_get_timecount(struct timecounter* tc)
|
||||
{
|
||||
return ia64_get_itc();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Values for timerX_state: */
|
||||
#define RELEASED 0
|
||||
#define RELEASE_PENDING 1
|
||||
#define ACQUIRED 2
|
||||
#define ACQUIRE_PENDING 3
|
||||
static int
|
||||
sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* static u_char timer0_state; */
|
||||
static u_char timer2_state;
|
||||
|
||||
/*
|
||||
* Algorithm for missed clock ticks from Linux/alpha.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Shift amount by which scaled_ticks_per_cycle is scaled. Shifting
|
||||
* by 48 gives us 16 bits for HZ while keeping the accuracy good even
|
||||
* for large CPU clock rates.
|
||||
*/
|
||||
#define FIX_SHIFT 48
|
||||
|
||||
static u_int64_t scaled_ticks_per_cycle;
|
||||
static u_int32_t max_cycles_per_tick;
|
||||
static u_int32_t last_time;
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static u_int32_t calibrate_clocks(u_int32_t firmware_freq);
|
||||
#endif
|
||||
error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
|
||||
if (!error && req->newptr)
|
||||
resettodr();
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
clockattach(kobj_t dev)
|
||||
{
|
||||
|
||||
/*
|
||||
* Just bookkeeping.
|
||||
*/
|
||||
if (clockdev)
|
||||
panic("clockattach: multiple clocks");
|
||||
|
||||
clockdev = dev;
|
||||
|
||||
#ifdef EVCNT_COUNTERS
|
||||
evcnt_attach(dev, "intr", &clock_intr_evcnt);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the clock started.
|
||||
*/
|
||||
/* Get the clock started. */
|
||||
CLOCK_INIT(clockdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Machine-dependent clock routines.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
pcpu_initclock(void)
|
||||
{
|
||||
|
||||
PCPU_SET(clockadj, 0);
|
||||
PCPU_SET(clock, ia64_get_itc());
|
||||
ia64_set_itm(PCPU_GET(clock) + ia64_clock_reload);
|
||||
ia64_set_itv(CLOCK_VECTOR); /* highest priority class */
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the real-time and statistics clocks. Leave stathz 0 since there
|
||||
* are no other timers available.
|
||||
* Start the real-time and statistics clocks. We use cr.itc and cr.itm
|
||||
* to implement a 1000hz clock.
|
||||
*/
|
||||
void
|
||||
cpu_initclocks()
|
||||
{
|
||||
u_int32_t freq;
|
||||
|
||||
/*
|
||||
* We use cr.itc and cr.itm to implement a 1024hz clock.
|
||||
*/
|
||||
hz = 1024;
|
||||
tick = 1000000 / hz; /* number of microseconds between interrupts */
|
||||
tickfix = 1000000 - (hz * tick);
|
||||
if (tickfix) {
|
||||
int ftp;
|
||||
|
||||
ftp = min(ffs(tickfix), ffs(hz));
|
||||
tickfix >>= (ftp - 1);
|
||||
tickfixinterval = hz >> (ftp - 1);
|
||||
}
|
||||
|
||||
if (!itc_frequency)
|
||||
if (itc_frequency == 0)
|
||||
panic("Unknown clock frequency");
|
||||
|
||||
freq = itc_frequency;
|
||||
last_time = ia64_get_itc();
|
||||
scaled_ticks_per_cycle = ((u_int64_t)hz << FIX_SHIFT) / freq;
|
||||
max_cycles_per_tick = 2*freq / hz;
|
||||
stathz = hz;
|
||||
ia64_clock_reload = (itc_frequency + hz/2) / hz;
|
||||
|
||||
#ifndef SMP
|
||||
ia64_timecounter.tc_frequency = freq;
|
||||
ia64_timecounter.tc_frequency = itc_frequency;
|
||||
tc_init(&ia64_timecounter);
|
||||
#endif
|
||||
|
||||
itm_reload = (itc_frequency + hz/2) / hz;
|
||||
ia64_set_itm(ia64_get_itc() + itm_reload);
|
||||
ia64_set_itv(CLOCK_VECTOR); /* highest priority class */
|
||||
|
||||
stathz = 128;
|
||||
pcpu_initclock();
|
||||
}
|
||||
|
||||
#if 0 /* not used yet */
|
||||
static u_int32_t
|
||||
calibrate_clocks(u_int32_t firmware_freq)
|
||||
{
|
||||
u_int32_t start_pcc, stop_pcc;
|
||||
int sec, start_sec;
|
||||
|
||||
if (bootverbose)
|
||||
printf("Calibrating clock(s) ... ");
|
||||
|
||||
/* Read the mc146818A seconds counter. */
|
||||
if (CLOCK_GETSECS(clockdev, &sec))
|
||||
goto fail;
|
||||
|
||||
/* Wait for the mC146818A seconds counter to change. */
|
||||
start_sec = sec;
|
||||
for (;;) {
|
||||
if (CLOCK_GETSECS(clockdev, &sec))
|
||||
goto fail;
|
||||
if (sec != start_sec)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Start keeping track of the PCC. */
|
||||
start_pcc = ia64_get_itc();
|
||||
|
||||
/*
|
||||
* Wait for the mc146818A seconds counter to change.
|
||||
*/
|
||||
start_sec = sec;
|
||||
for (;;) {
|
||||
if (CLOCK_GETSECS(clockdev, &sec))
|
||||
goto fail;
|
||||
if (sec != start_sec)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the PCC again to work out frequency.
|
||||
*/
|
||||
stop_pcc = ia64_get_itc();
|
||||
|
||||
if (bootverbose) {
|
||||
printf("PCC clock: %u Hz (firmware %u Hz)\n",
|
||||
stop_pcc - start_pcc, firmware_freq);
|
||||
}
|
||||
return (stop_pcc - start_pcc);
|
||||
|
||||
fail:
|
||||
if (bootverbose)
|
||||
printf("failed, using firmware default of %u Hz\n",
|
||||
firmware_freq);
|
||||
return (firmware_freq);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We assume newhz is either stathz or profhz, and that neither will
|
||||
* change after being set up above. Could recalculate intervals here
|
||||
* but that would be a drag.
|
||||
*/
|
||||
|
||||
void
|
||||
cpu_startprofclock(void)
|
||||
{
|
||||
@ -283,20 +189,17 @@ static short dayyr[12] = {
|
||||
};
|
||||
|
||||
/*
|
||||
* 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,
|
||||
* Initialize 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;
|
||||
inittodr(time_t base)
|
||||
{
|
||||
register int days, yr;
|
||||
struct clocktime ct;
|
||||
time_t deltat;
|
||||
int badbase;
|
||||
int s;
|
||||
struct timespec ts;
|
||||
time_t deltat;
|
||||
int badbase, days, s, yr;
|
||||
|
||||
if (base < 5*SECYR) {
|
||||
printf("WARNING: preposterous time in filesystem");
|
||||
@ -307,7 +210,7 @@ inittodr(base)
|
||||
badbase = 0;
|
||||
|
||||
CLOCK_GET(clockdev, base, &ct);
|
||||
clockinitted = 1;
|
||||
todr_initialized = 1;
|
||||
|
||||
/* simple sanity checks */
|
||||
if (ct.year < 70 || ct.mon < 1 || ct.mon > 12 || ct.day < 1 ||
|
||||
@ -333,12 +236,13 @@ inittodr(base)
|
||||
days += dayyr[ct.mon - 1] + ct.day - 1;
|
||||
if (LEAPYEAR(yr) && ct.mon > 2)
|
||||
days++;
|
||||
|
||||
/* now have days since Jan 1, 1970; the rest is easy... */
|
||||
s = splclock();
|
||||
ts.tv_sec =
|
||||
ts.tv_sec =
|
||||
days * SECDAY + ct.hour * SECHOUR + ct.min * SECMIN + ct.sec;
|
||||
if (wall_cmos_clock)
|
||||
ts.tv_sec += adjkerntz;
|
||||
ts.tv_sec += adjkerntz;
|
||||
ts.tv_nsec = 0;
|
||||
tc_setclock(&ts);
|
||||
splx(s);
|
||||
@ -361,29 +265,26 @@ inittodr(base)
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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()
|
||||
{
|
||||
register int t, t2, s;
|
||||
struct clocktime ct;
|
||||
unsigned long tm;
|
||||
unsigned long tm;
|
||||
int s, t, t2;
|
||||
|
||||
if (disable_rtc_set)
|
||||
if (!todr_initialized || disable_rtc_set)
|
||||
return;
|
||||
|
||||
s = splclock();
|
||||
tm = time_second;
|
||||
splx(s);
|
||||
|
||||
if (!clockinitted)
|
||||
return;
|
||||
|
||||
/* Calculate local time to put in RTC */
|
||||
tm -= (wall_cmos_clock ? adjkerntz : 0);
|
||||
|
||||
@ -419,86 +320,3 @@ resettodr()
|
||||
|
||||
CLOCK_SET(clockdev, &ct);
|
||||
}
|
||||
|
||||
#ifndef SMP
|
||||
static unsigned
|
||||
ia64_get_timecount(struct timecounter* tc)
|
||||
{
|
||||
return ia64_get_itc();
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
acquire_timer2(int mode)
|
||||
{
|
||||
|
||||
if (timer2_state != RELEASED)
|
||||
return (-1);
|
||||
timer2_state = ACQUIRED;
|
||||
|
||||
/*
|
||||
* This access to the timer registers is as atomic as possible
|
||||
* because it is a single instruction. We could do better if we
|
||||
* knew the rate. Use of splclock() limits glitches to 10-100us,
|
||||
* and this is probably good enough for timer2, so we aren't as
|
||||
* careful with it as with timer0.
|
||||
*/
|
||||
outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
release_timer2()
|
||||
{
|
||||
|
||||
if (timer2_state != ACQUIRED)
|
||||
return (-1);
|
||||
timer2_state = RELEASED;
|
||||
outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
sysbeepstop(void *chan)
|
||||
{
|
||||
outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
|
||||
release_timer2();
|
||||
beeping = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frequency of all three count-down timers; (TIMER_FREQ/freq) is the
|
||||
* appropriate count to generate a frequency of freq hz.
|
||||
*/
|
||||
#ifndef TIMER_FREQ
|
||||
#define TIMER_FREQ 1193182
|
||||
#endif
|
||||
#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
|
||||
|
||||
int
|
||||
sysbeep(int pitch, int period)
|
||||
{
|
||||
int x = splhigh();
|
||||
|
||||
if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
|
||||
if (!beeping) {
|
||||
/* Something else owns it. */
|
||||
splx(x);
|
||||
return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */
|
||||
}
|
||||
|
||||
if (pitch) pitch = TIMER_DIV(pitch);
|
||||
|
||||
outb(TIMER_CNTR2, pitch);
|
||||
outb(TIMER_CNTR2, (pitch>>8));
|
||||
if (!beeping) {
|
||||
/* enable counter2 output to speaker */
|
||||
if (pitch) outb(IO_PPI, inb(IO_PPI) | 3);
|
||||
beeping = period;
|
||||
timeout(sysbeepstop, (void *)NULL, period);
|
||||
}
|
||||
splx(x);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -85,21 +85,51 @@ dummy_perf(unsigned long vector, struct trapframe *framep)
|
||||
void (*perf_irq)(unsigned long, struct trapframe *) = dummy_perf;
|
||||
|
||||
static unsigned int ints[MAXCPU];
|
||||
static unsigned int clks[MAXCPU];
|
||||
static unsigned int asts[MAXCPU];
|
||||
static unsigned int rdvs[MAXCPU];
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, ints, CTLFLAG_RW, &ints, sizeof(ints), "IU","");
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, clks, CTLFLAG_RW, &clks, sizeof(clks), "IU","");
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, asts, CTLFLAG_RW, &asts, sizeof(asts), "IU","");
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, rdvs, CTLFLAG_RW, &rdvs, sizeof(rdvs), "IU","");
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, ints, CTLFLAG_RW, &ints, sizeof(ints), "IU",
|
||||
"");
|
||||
|
||||
static u_int schedclk2;
|
||||
static unsigned int clks[MAXCPU];
|
||||
#ifdef SMP
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, clks, CTLFLAG_RW, &clks, sizeof(clks), "IU",
|
||||
"");
|
||||
#else
|
||||
SYSCTL_INT(_debug, OID_AUTO, clks, CTLFLAG_RW, clks, 0, "");
|
||||
#endif
|
||||
|
||||
#ifdef SMP
|
||||
static unsigned int asts[MAXCPU];
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, asts, CTLFLAG_RW, &asts, sizeof(asts), "IU",
|
||||
"");
|
||||
|
||||
static unsigned int rdvs[MAXCPU];
|
||||
SYSCTL_OPAQUE(_debug, OID_AUTO, rdvs, CTLFLAG_RW, &rdvs, sizeof(rdvs), "IU",
|
||||
"");
|
||||
#endif
|
||||
|
||||
static int adjust_edges = 0;
|
||||
SYSCTL_INT(_debug, OID_AUTO, clock_adjust_edges, CTLFLAG_RW,
|
||||
&adjust_edges, 0, "Number of times ITC got more than 12.5% behind");
|
||||
|
||||
static int adjust_excess = 0;
|
||||
SYSCTL_INT(_debug, OID_AUTO, clock_adjust_excess, CTLFLAG_RW,
|
||||
&adjust_excess, 0, "Total number of ignored ITC interrupts");
|
||||
|
||||
static int adjust_lost = 0;
|
||||
SYSCTL_INT(_debug, OID_AUTO, clock_adjust_lost, CTLFLAG_RW,
|
||||
&adjust_lost, 0, "Total number of lost ITC interrupts");
|
||||
|
||||
static int adjust_ticks = 0;
|
||||
SYSCTL_INT(_debug, OID_AUTO, clock_adjust_ticks, CTLFLAG_RW,
|
||||
&adjust_ticks, 0, "Total number of ITC interrupts with adjustment");
|
||||
|
||||
void
|
||||
interrupt(u_int64_t vector, struct trapframe *framep)
|
||||
{
|
||||
struct thread *td;
|
||||
volatile struct ia64_interrupt_block *ib = IA64_INTERRUPT_BLOCK;
|
||||
uint64_t adj, clk, itc;
|
||||
int64_t delta;
|
||||
int count;
|
||||
|
||||
td = curthread;
|
||||
atomic_add_int(&td->td_intr_nesting_level, 1);
|
||||
@ -115,39 +145,55 @@ interrupt(u_int64_t vector, struct trapframe *framep)
|
||||
|
||||
if (vector == CLOCK_VECTOR) {/* clock interrupt */
|
||||
/* CTR0(KTR_INTR, "clock interrupt"); */
|
||||
|
||||
|
||||
cnt.v_intr++;
|
||||
#ifdef EVCNT_COUNTERS
|
||||
clock_intr_evcnt.ev_count++;
|
||||
#else
|
||||
intrcnt[INTRCNT_CLOCK]++;
|
||||
#endif
|
||||
critical_enter();
|
||||
/* Rearm so we get the next clock interrupt */
|
||||
ia64_set_itm(ia64_get_itc() + itm_reload);
|
||||
#ifdef SMP
|
||||
clks[PCPU_GET(cpuid)]++;
|
||||
/* Only the BSP runs the real clock */
|
||||
if (PCPU_GET(cpuid) == 0) {
|
||||
#endif
|
||||
hardclock((struct clockframe *)framep);
|
||||
/* divide hz (1024) by 8 to get stathz (128) */
|
||||
if ((++schedclk2 & 0x7) == 0) {
|
||||
if (profprocs != 0)
|
||||
profclock((struct clockframe *)framep);
|
||||
statclock((struct clockframe *)framep);
|
||||
}
|
||||
#ifdef SMP
|
||||
} else {
|
||||
hardclock_process((struct clockframe *)framep);
|
||||
if ((schedclk2 & 0x7) == 0) {
|
||||
if (profprocs != 0)
|
||||
profclock((struct clockframe *)framep);
|
||||
statclock((struct clockframe *)framep);
|
||||
}
|
||||
|
||||
critical_enter();
|
||||
|
||||
adj = PCPU_GET(clockadj);
|
||||
itc = ia64_get_itc();
|
||||
ia64_set_itm(itc + ia64_clock_reload - adj);
|
||||
clk = PCPU_GET(clock);
|
||||
delta = itc - clk;
|
||||
count = 0;
|
||||
while (delta >= ia64_clock_reload) {
|
||||
/* Only the BSP runs the real clock */
|
||||
if (PCPU_GET(cpuid) == 0)
|
||||
hardclock((struct clockframe *)framep);
|
||||
else
|
||||
hardclock_process((struct clockframe *)framep);
|
||||
if (profprocs != 0)
|
||||
profclock((struct clockframe *)framep);
|
||||
statclock((struct clockframe *)framep);
|
||||
delta -= ia64_clock_reload;
|
||||
clk += ia64_clock_reload;
|
||||
if (adj != 0)
|
||||
adjust_ticks++;
|
||||
count++;
|
||||
}
|
||||
#endif
|
||||
if (count > 0) {
|
||||
adjust_lost += count - 1;
|
||||
if (delta > (ia64_clock_reload >> 3)) {
|
||||
if (adj == 0)
|
||||
adjust_edges++;
|
||||
adj = ia64_clock_reload >> 4;
|
||||
} else if (delta < (ia64_clock_reload >> 3))
|
||||
adj = 0;
|
||||
} else {
|
||||
adj = 0;
|
||||
adjust_excess++;
|
||||
}
|
||||
PCPU_SET(clock, clk);
|
||||
PCPU_SET(clockadj, adj);
|
||||
|
||||
critical_exit();
|
||||
|
||||
#ifdef SMP
|
||||
} else if (vector == ipi_vector[IPI_AST]) {
|
||||
asts[PCPU_GET(cpuid)]++;
|
||||
@ -186,23 +232,6 @@ interrupt(u_int64_t vector, struct trapframe *framep)
|
||||
atomic_subtract_int(&td->td_intr_nesting_level, 1);
|
||||
}
|
||||
|
||||
int
|
||||
badaddr(addr, size)
|
||||
void *addr;
|
||||
size_t size;
|
||||
{
|
||||
return(badaddr_read(addr, size, NULL));
|
||||
}
|
||||
|
||||
int
|
||||
badaddr_read(addr, size, rptr)
|
||||
void *addr;
|
||||
size_t size;
|
||||
void *rptr;
|
||||
{
|
||||
return (1); /* XXX implement */
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware irqs have vectors starting at this offset.
|
||||
*/
|
||||
|
@ -1357,26 +1357,6 @@ Debugger(const char *msg)
|
||||
}
|
||||
#endif /* no DDB */
|
||||
|
||||
static int
|
||||
sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
int error;
|
||||
error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2,
|
||||
req);
|
||||
if (!error && req->newptr)
|
||||
resettodr();
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW,
|
||||
&adjkerntz, 0, sysctl_machdep_adjkerntz, "I", "");
|
||||
|
||||
SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set,
|
||||
CTLFLAG_RW, &disable_rtc_set, 0, "");
|
||||
|
||||
SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock,
|
||||
CTLFLAG_RW, &wall_cmos_clock, 0, "");
|
||||
|
||||
/*
|
||||
* Utility functions for manipulating instruction bundles.
|
||||
*/
|
||||
@ -1400,3 +1380,9 @@ ia64_pack_bundle(u_int64_t *lowp, u_int64_t *highp,
|
||||
*lowp = low;
|
||||
*highp = high;
|
||||
}
|
||||
|
||||
int
|
||||
sysbeep(int pitch, int period)
|
||||
{
|
||||
return (ENODEV);
|
||||
}
|
||||
|
@ -123,10 +123,11 @@ ia64_ap_startup(void)
|
||||
|
||||
mtx_lock_spin(&sched_lock);
|
||||
|
||||
/* kick off the clock on this AP */
|
||||
ia64_set_itm(ia64_get_itc() + itm_reload);
|
||||
ia64_set_itv(CLOCK_VECTOR);
|
||||
ia64_set_tpr(0);
|
||||
|
||||
/* kick off the clock on this AP */
|
||||
pcpu_initclock();
|
||||
|
||||
cpu_throw(NULL, choosethread());
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
@ -1,110 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 1993 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Register definitions for the Intel 8253 Programmable Interval Timer.
|
||||
*
|
||||
* This chip has three independent 16-bit down counters that can be
|
||||
* read on the fly. There are three mode registers and three countdown
|
||||
* registers. The countdown registers are addressed directly, via the
|
||||
* first three I/O ports. The three mode registers are accessed via
|
||||
* the fourth I/O port, with two bits in the mode byte indicating the
|
||||
* register. (Why are hardware interfaces always so braindead?).
|
||||
*
|
||||
* To write a value into the countdown register, the mode register
|
||||
* is first programmed with a command indicating the which byte of
|
||||
* the two byte register is to be modified. The three possibilities
|
||||
* are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
|
||||
* msb (TMR_MR_BOTH).
|
||||
*
|
||||
* To read the current value ("on the fly") from the countdown register,
|
||||
* you write a "latch" command into the mode register, then read the stable
|
||||
* value from the corresponding I/O port. For example, you write
|
||||
* TMR_MR_LATCH into the corresponding mode register. Presumably,
|
||||
* after doing this, a write operation to the I/O port would result
|
||||
* in undefined behavior (but hopefully not fry the chip).
|
||||
* Reading in this manner has no side effects.
|
||||
*
|
||||
* [IBM-PC]
|
||||
* The outputs of the three timers are connected as follows:
|
||||
*
|
||||
* timer 0 -> irq 0
|
||||
* timer 1 -> dma chan 0 (for dram refresh)
|
||||
* timer 2 -> speaker (via keyboard controller)
|
||||
*
|
||||
* Timer 0 is used to call hardclock.
|
||||
* Timer 2 is used to generate console beeps.
|
||||
*
|
||||
* [PC-9801]
|
||||
* The outputs of the three timers are connected as follows:
|
||||
*
|
||||
* timer 0 -> irq 0
|
||||
* timer 1 -> speaker (via keyboard controller)
|
||||
* timer 2 -> RS232C
|
||||
*
|
||||
* Timer 0 is used to call hardclock.
|
||||
* Timer 1 is used to generate console beeps.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Macros for specifying values to be written into a mode register.
|
||||
*/
|
||||
#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
|
||||
#ifdef PC98
|
||||
#define TIMER_CNTR1 0x3fdb /* timer 1 counter port */
|
||||
#define TIMER_CNTR2 (IO_TIMER1 + 4) /* timer 2 counter port */
|
||||
#define TIMER_MODE (IO_TIMER1 + 6) /* timer mode port */
|
||||
#else
|
||||
#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
|
||||
#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
|
||||
#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
|
||||
#endif
|
||||
#define TIMER_SEL0 0x00 /* select counter 0 */
|
||||
#define TIMER_SEL1 0x40 /* select counter 1 */
|
||||
#define TIMER_SEL2 0x80 /* select counter 2 */
|
||||
#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
|
||||
#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
|
||||
#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
|
||||
#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
|
||||
#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
|
||||
#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
|
||||
#define TIMER_LATCH 0x00 /* latch counter for reading */
|
||||
#define TIMER_LSB 0x10 /* r/w counter LSB */
|
||||
#define TIMER_MSB 0x20 /* r/w counter MSB */
|
||||
#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
|
||||
#define TIMER_BCD 0x01 /* count in BCD */
|
||||
|
@ -13,16 +13,14 @@
|
||||
|
||||
#define CLOCK_VECTOR 254
|
||||
|
||||
extern int disable_rtc_set;
|
||||
extern int wall_cmos_clock;
|
||||
extern int adjkerntz;
|
||||
extern int adjkerntz;
|
||||
extern int disable_rtc_set;
|
||||
extern int wall_cmos_clock;
|
||||
|
||||
extern u_int64_t itc_frequency;
|
||||
extern u_int64_t itm_reload;
|
||||
extern uint64_t ia64_clock_reload;
|
||||
extern uint64_t itc_frequency;
|
||||
|
||||
int sysbeep(int pitch, int period);
|
||||
int acquire_timer2(int mode);
|
||||
int release_timer2(void);
|
||||
int sysbeep(int pitch, int period);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -75,18 +75,14 @@ struct clockframe {
|
||||
* CTL_MACHDEP definitions.
|
||||
*/
|
||||
#define CPU_CONSDEV 1 /* dev_t: console terminal device */
|
||||
#define CPU_ROOT_DEVICE 2 /* string: root device name */
|
||||
#define CPU_BOOTED_KERNEL 3 /* string: booted kernel name */
|
||||
#define CPU_ADJKERNTZ 4 /* int: timezone offset (seconds) */
|
||||
#define CPU_DISRTCSET 5 /* int: disable resettodr() call */
|
||||
#define CPU_WALLCLOCK 6 /* int: indicates wall CMOS clock */
|
||||
#define CPU_MAXID 7 /* valid machdep IDs */
|
||||
#define CPU_ADJKERNTZ 2 /* int: timezone offset (seconds) */
|
||||
#define CPU_DISRTCSET 3 /* int: disable resettodr() call */
|
||||
#define CPU_WALLCLOCK 4 /* int: indicates wall CMOS clock */
|
||||
#define CPU_MAXID 5 /* valid machdep IDs */
|
||||
|
||||
#define CTL_MACHDEP_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
{ "console_device", CTLTYPE_STRUCT }, \
|
||||
{ "root_device", CTLTYPE_STRING }, \
|
||||
{ "booted_kernel", CTLTYPE_STRING }, \
|
||||
{ "adjkerntz", CTLTYPE_INT }, \
|
||||
{ "disable_rtc_set", CTLTYPE_INT }, \
|
||||
{ "wall_cmos_clock", CTLTYPE_INT }, \
|
||||
@ -100,11 +96,6 @@ struct reg;
|
||||
struct rpb;
|
||||
struct trapframe;
|
||||
|
||||
extern struct rpb *hwrpb;
|
||||
extern volatile int mc_expected, mc_received;
|
||||
|
||||
int badaddr(void *, size_t);
|
||||
int badaddr_read(void *, size_t, void *);
|
||||
u_int64_t console_restart(u_int64_t, u_int64_t, u_int64_t);
|
||||
int do_ast(struct trapframe *);
|
||||
void dumpconf(void);
|
||||
@ -118,8 +109,6 @@ void init_prom_interface(struct rpb*);
|
||||
void interrupt(u_int64_t, struct trapframe *);
|
||||
void machine_check(unsigned long, struct trapframe *, unsigned long,
|
||||
unsigned long);
|
||||
u_int64_t hwrpb_checksum(void);
|
||||
void hwrpb_restart_setup(void);
|
||||
void regdump(struct trapframe *);
|
||||
void regtoframe(struct reg *, struct trapframe *);
|
||||
void set_iointr(void (*)(void *, unsigned long));
|
||||
|
@ -35,8 +35,10 @@
|
||||
#define PCPU_MD_FIELDS \
|
||||
struct pcb *pc_pcb; /* Used by IPI_STOP */ \
|
||||
struct pmap *pc_current_pmap; /* active pmap */ \
|
||||
u_int64_t pc_lid; /* local CPU ID */ \
|
||||
u_int32_t pc_awake:1; /* CPU is awake? */
|
||||
uint64_t pc_lid; /* local CPU ID */ \
|
||||
uint32_t pc_awake:1; /* CPU is awake? */ \
|
||||
uint64_t pc_clock; /* Clock counter. */ \
|
||||
uint64_t pc_clockadj; /* Clock adjust. */
|
||||
|
||||
struct pcpu;
|
||||
|
||||
@ -46,6 +48,8 @@ register struct pcpu *pcpup __asm__("r13");
|
||||
#define PCPU_PTR(member) (&pcpup->pc_ ## member)
|
||||
#define PCPU_SET(member,value) (pcpup->pc_ ## member = (value))
|
||||
|
||||
void pcpu_initclock(void);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_MACHINE_PCPU_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user