diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-07-14 19:50:13 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-07-14 19:50:13 +0000 |
commit | aea0f3f6660b5a1bf2fa8be69b01257a54274c55 (patch) | |
tree | f981a29a2e3913112bcdd7a8c8b43d0014b1537c /sys/arch | |
parent | 6e8e3cdb8f352d4f3938d0fb81b9d2353485a578 (diff) |
Split the existing mips64 clock code into time-of-day and generic duties in
machdep.c, and internal clock interrupting on level 5, still in clock.c; this
will allow other clock sources to be used in the near future. (delay() will
remain tied to the internal clock)
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/mips64/include/cpu.h | 14 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/clock.c | 324 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/mips64_machdep.c | 267 |
3 files changed, 311 insertions, 294 deletions
diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h index 7f63995eb18..08a468ec8ad 100644 --- a/sys/arch/mips64/include/cpu.h +++ b/sys/arch/mips64/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.82 2012/06/24 16:26:02 miod Exp $ */ +/* $OpenBSD: cpu.h,v 1.83 2012/07/14 19:50:11 miod Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -266,6 +266,15 @@ #define COP_0_EBASE $15, 1 /* + * COP_0_COUNT speed divider. + */ +#if defined(CPU_OCTEON) +#define CP0_CYCLE_DIVIDER 1 +#else +#define CP0_CYCLE_DIVIDER 2 +#endif + +/* * Values for the code field in a break instruction. */ #define BREAK_INSTR 0x0000000d @@ -458,7 +467,8 @@ void smp_rendezvous_cpus(unsigned long, void (*)(void *), void *arg); #define get_cpu_info(i) (&cpu_info_primary) #endif -void cpu_startclock(struct cpu_info *); +extern void (*md_startclock)(struct cpu_info *); +void cp0_calibrate(struct cpu_info *); #include <machine/frame.h> diff --git a/sys/arch/mips64/mips64/clock.c b/sys/arch/mips64/mips64/clock.c index 3241c1fbcb3..2379b038a5e 100644 --- a/sys/arch/mips64/mips64/clock.c +++ b/sys/arch/mips64/mips64/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.36 2011/07/10 17:47:41 miod Exp $ */ +/* $OpenBSD: clock.c,v 1.37 2012/07/14 19:50:12 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -26,20 +26,27 @@ * */ +/* + * Clock code for systems using the on-cpu counter register, when both the + * counter and comparator registers are available (i.e. everything MIPS-III + * or MIPS-IV capable but the R8000). + * + * On most processors, this register counts at half the pipeline frequency. + */ + #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/device.h> #include <sys/evcount.h> -#include <sys/timetc.h> #include <machine/autoconf.h> #include <machine/cpu.h> + #include <mips64/dev/clockvar.h> -#include <mips64/archtype.h> -static struct evcount clk_count; -static int clk_irq = 5; +static struct evcount cp0_clock_count; +static int cp0_clock_irq = 5; int clockmatch(struct device *, void *, void *); void clockattach(struct device *, struct device *, void *); @@ -52,73 +59,47 @@ struct cfattach clock_ca = { sizeof(struct device), clockmatch, clockattach }; -void clock_calibrate(struct cpu_info *); -uint32_t clock_int5(uint32_t, struct trap_frame *); - -#ifndef MULTIPROCESSOR -u_int cp0_get_timecount(struct timecounter *); - -struct timecounter cp0_timecounter = { - cp0_get_timecount, /* get_timecount */ - 0, /* no poll_pps */ - 0xffffffff, /* counter_mask */ - 0, /* frequency */ - "CP0", /* name */ - 0 /* quality */ -}; -#endif - -#define SECMIN (60) /* seconds per minute */ -#define SECHOUR (60*SECMIN) /* seconds per hour */ - -#define YEARDAYS(year) (((((year) + 1900) % 4) == 0 && \ - ((((year) + 1900) % 100) != 0 || \ - (((year) + 1900) % 400) == 0)) ? 366 : 365) +void cp0_startclock(struct cpu_info *); +uint32_t cp0_int5(uint32_t, struct trap_frame *); int clockmatch(struct device *parent, void *vcf, void *aux) { struct mainbus_attach_args *maa = aux; - if (strcmp(maa->maa_name, clock_cd.cd_name) != 0) - return 0; - - return 10; /* Try to get clock early */ +#ifdef CPU_R8000 + return 0; /* shouldn't be in the kernel configuration anyway */ +#endif + return strcmp(maa->maa_name, clock_cd.cd_name) == 0; } void clockattach(struct device *parent, struct device *self, void *aux) { - printf(": ticker on int5 using count register\n"); + printf(": int 5\n"); /* * We need to register the interrupt now, for idle_mask to * be computed correctly. */ - set_intr(INTPRI_CLOCK, CR_INT_5, clock_int5); - evcount_attach(&clk_count, "clock", &clk_irq); + set_intr(INTPRI_CLOCK, CR_INT_5, cp0_int5); + evcount_attach(&cp0_clock_count, "clock", &cp0_clock_irq); + /* try to avoid getting clock interrupts early */ cp0_set_compare(cp0_get_count() - 1); -} -/* - * Clock interrupt code for machines using the on cpu chip - * counter register. This register counts at half the pipeline - * frequency so the frequency must be known and the options - * register wired to allow its use. - * - * The code is enabled by setting 'cpu_counter_interval'. - */ + md_startclock = cp0_startclock; +} /* * Interrupt handler for targets using the internal count register * as interval clock. Normally the system is run with the clock * interrupt always enabled. Masking is done here and if the clock * can not be run the tick is just counted and handled later when - * the clock is unmasked again. + * the clock is logically unmasked again. */ uint32_t -clock_int5(uint32_t mask, struct trap_frame *tf) +cp0_int5(uint32_t mask, struct trap_frame *tf) { u_int32_t clkdiff; struct cpu_info *ci = curcpu(); @@ -163,14 +144,14 @@ clock_int5(uint32_t mask, struct trap_frame *tf) */ if (tf->ipl < IPL_CLOCK) { #ifdef MULTIPROCESSOR - u_int32_t sr; + register_t sr; /* Enable interrupts at this (hardware) level again */ sr = getsr(); ENABLEIPI(); __mp_lock(&kernel_lock); #endif while (ci->ci_pendingticks) { - clk_count.ec_count++; + cp0_clock_count.ec_count++; hardclock(tf); ci->ci_pendingticks--; } @@ -184,106 +165,15 @@ clock_int5(uint32_t mask, struct trap_frame *tf) } /* - * Wait "n" microseconds. - */ -void -delay(int n) -{ - int dly; - int p, c; - struct cpu_info *ci = curcpu(); - uint32_t delayconst; - - delayconst = ci->ci_delayconst; - if (delayconst == 0) -#if CPU_OCTEON - delayconst = bootcpu_hwinfo.clock; -#else - delayconst = bootcpu_hwinfo.clock / 2; -#endif - p = cp0_get_count(); - dly = (delayconst / 1000000) * n; - while (dly > 0) { - c = cp0_get_count(); - dly -= c - p; - p = c; - } -} - -/* - * Mips machine independent clock routines. - */ - -struct tod_desc sys_tod; - -/* - * Calibrate cpu clock against the TOD clock if available. - */ -void -clock_calibrate(struct cpu_info *ci) -{ - struct tod_desc *cd = &sys_tod; - struct tod_time ct; - u_int first_cp0, second_cp0, cycles_per_sec; - int first_sec; - - if (cd->tod_get == NULL) - return; - - (*cd->tod_get)(cd->tod_cookie, 0, &ct); - first_sec = ct.sec; - - /* Let the clock tick one second. */ - do { - first_cp0 = cp0_get_count(); - (*cd->tod_get)(cd->tod_cookie, 0, &ct); - } while (ct.sec == first_sec); - first_sec = ct.sec; - /* Let the clock tick one more second. */ - do { - second_cp0 = cp0_get_count(); - (*cd->tod_get)(cd->tod_cookie, 0, &ct); - } while (ct.sec == first_sec); - - cycles_per_sec = second_cp0 - first_cp0; - ci->ci_hw.clock = cycles_per_sec * 2; - ci->ci_delayconst = cycles_per_sec; -} - -/* * Start the real-time and statistics clocks. Leave stathz 0 since there * are no other timers available. */ void -cpu_initclocks() -{ - struct cpu_info *ci = curcpu(); - - hz = 100; - profhz = 100; - stathz = 0; /* XXX no stat clock yet */ - - clock_calibrate(ci); - - tick = 1000000 / hz; /* number of micro-seconds between interrupts */ - tickadj = 240000 / (60 * hz); /* can adjust 240ms in 60s */ - -#ifndef MULTIPROCESSOR -#ifdef CPU_OCTEON - cp0_timecounter.tc_frequency = (uint64_t)ci->ci_hw.clock; -#else - cp0_timecounter.tc_frequency = (uint64_t)ci->ci_hw.clock / 2; -#endif - tc_init(&cp0_timecounter); -#endif - cpu_startclock(ci); -} - -void -cpu_startclock(struct cpu_info *ci) +cp0_startclock(struct cpu_info *ci) { int s; +#ifdef MULTIPROCESSOR if (!CPU_IS_PRIMARY(ci)) { s = splhigh(); microuptime(&ci->ci_schedstate.spc_runtime); @@ -292,162 +182,16 @@ cpu_startclock(struct cpu_info *ci) /* try to avoid getting clock interrupts early */ cp0_set_compare(cp0_get_count() - 1); - clock_calibrate(ci); + cp0_calibrate(ci); } +#endif /* Start the clock. */ s = splclock(); -#ifdef CPU_OCTEON - ci->ci_cpu_counter_interval = (ci->ci_hw.clock) / hz; -#else - ci->ci_cpu_counter_interval = (ci->ci_hw.clock / 2) / hz; -#endif + ci->ci_cpu_counter_interval = + (ci->ci_hw.clock / CP0_CYCLE_DIVIDER) / hz; ci->ci_cpu_counter_last = cp0_get_count() + ci->ci_cpu_counter_interval; cp0_set_compare(ci->ci_cpu_counter_last); ci->ci_clock_started++; splx(s); } - -/* - * 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 -setstatclockrate(int newhz) -{ -} - -/* - * This code is defunct after 2099. Will Unix still be here then?? - */ -static short dayyr[12] = { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 -}; - -/* - * Initialize the time of day register, based on the time base which - * is, e.g. from a filesystem. - */ -void -inittodr(time_t base) -{ - struct timespec ts; - struct tod_time c; - struct tod_desc *cd = &sys_tod; - int days, yr; - - ts.tv_nsec = 0; - - if (base < 35 * SECYR) { - printf("WARNING: preposterous time in file system"); - /* read the system clock anyway */ - base = 40 * SECYR; /* 2010 */ - } - - /* - * Read RTC chip registers NOTE: Read routines are responsible - * for sanity checking clock. Dates after 19991231 should be - * returned as year >= 100. - */ - if (cd->tod_get) { - (*cd->tod_get)(cd->tod_cookie, base, &c); - } else { - printf("WARNING: No TOD clock, believing file system.\n"); - goto bad; - } - - days = 0; - for (yr = 70; yr < c.year; yr++) { - days += YEARDAYS(yr); - } - - days += dayyr[c.mon - 1] + c.day - 1; - if (YEARDAYS(c.year) == 366 && c.mon > 2) { - days++; - } - - /* now have days since Jan 1, 1970; the rest is easy... */ - ts.tv_sec = days * SECDAY + c.hour * 3600 + c.min * 60 + c.sec; - tc_setclock(&ts); - cd->tod_valid = 1; - - /* - * See if we gained/lost time. - */ - if (base < ts.tv_sec - 5*SECYR) { - printf("WARNING: file system time much less than clock time\n"); - } else if (base > ts.tv_sec + 5*SECYR) { - printf("WARNING: clock time much less than file system time\n"); - printf("WARNING: using file system time\n"); - } else { - return; - } - -bad: - ts.tv_sec = base; - tc_setclock(&ts); - cd->tod_valid = 1; - printf("WARNING: CHECK AND RESET THE DATE!\n"); -} - -/* - * Reset the TOD clock. This is done when the system is halted or - * when the time is reset by the stime system call. - */ -void -resettodr() -{ - struct tod_time c; - struct tod_desc *cd = &sys_tod; - int t, t2; - - /* - * Don't reset TOD if time has not been set! - */ - if (!cd->tod_valid) - return; - - /* compute the day of week. 1 is Sunday*/ - t2 = time_second / SECDAY; - c.dow = (t2 + 5) % 7 + 1; /* 1/1/1970 was thursday */ - - /* compute the year */ - t = 0; - t2 = time_second / SECDAY; - c.year = 69; - while (t2 >= 0) { /* whittle off years */ - t = t2; - c.year++; - t2 -= YEARDAYS(c.year); - } - - /* t = month + day; separate */ - t2 = YEARDAYS(c.year); - for (c.mon = 1; c.mon < 12; c.mon++) { - if (t < dayyr[c.mon] + (t2 == 366 && c.mon > 1)) - break; - } - - c.day = t - dayyr[c.mon - 1] + 1; - if (t2 == 366 && c.mon > 2) { - c.day--; - } - - t = time_second % SECDAY; - c.hour = t / 3600; - t %= 3600; - c.min = t / 60; - c.sec = t % 60; - - if (cd->tod_set) - (*cd->tod_set)(cd->tod_cookie, &c); -} - -#ifndef MULTIPROCESSOR -u_int -cp0_get_timecount(struct timecounter *tc) -{ - return (cp0_get_count()); -} -#endif diff --git a/sys/arch/mips64/mips64/mips64_machdep.c b/sys/arch/mips64/mips64/mips64_machdep.c index 463cb8a3825..64adb643a9f 100644 --- a/sys/arch/mips64/mips64/mips64_machdep.c +++ b/sys/arch/mips64/mips64/mips64_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mips64_machdep.c,v 1.3 2012/03/24 22:10:59 miod Exp $ */ +/* $OpenBSD: mips64_machdep.c,v 1.4 2012/07/14 19:50:12 miod Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* - * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) + * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,16 +40,21 @@ * SUCH DAMAGE. * */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/proc.h> #include <sys/exec.h> +#include <sys/timetc.h> +#include <machine/autoconf.h> #include <machine/cpu.h> #include <uvm/uvm.h> +#include <mips64/dev/clockvar.h> + /* * Build a tlb trampoline */ @@ -183,3 +188,261 @@ exec_md_map(struct proc *p, struct exec_package *pack) return 0; } + +/* + * Mips machine independent clock routines. + */ + +struct tod_desc sys_tod; +void (*md_startclock)(struct cpu_info *); + +/* + * Wait "n" microseconds. + */ +void +delay(int n) +{ + int dly; + int p, c; + struct cpu_info *ci = curcpu(); + uint32_t delayconst; + + delayconst = ci->ci_delayconst; + if (delayconst == 0) + delayconst = bootcpu_hwinfo.clock / CP0_CYCLE_DIVIDER; + p = cp0_get_count(); + dly = (delayconst / 1000000) * n; + while (dly > 0) { + c = cp0_get_count(); + dly -= c - p; + p = c; + } +} + +#ifndef MULTIPROCESSOR +u_int cp0_get_timecount(struct timecounter *); + +struct timecounter cp0_timecounter = { + cp0_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + 0xffffffff, /* counter_mask */ + 0, /* frequency */ + "CP0", /* name */ + 0 /* quality */ +}; + +u_int +cp0_get_timecount(struct timecounter *tc) +{ + return (cp0_get_count()); +} +#endif + +/* + * Calibrate cpu internal counter against the TOD clock if available. + */ +void +cp0_calibrate(struct cpu_info *ci) +{ + struct tod_desc *cd = &sys_tod; + struct tod_time ct; + u_int first_cp0, second_cp0, cycles_per_sec; + int first_sec; + + if (cd->tod_get == NULL) + return; + + (*cd->tod_get)(cd->tod_cookie, 0, &ct); + first_sec = ct.sec; + + /* Let the clock tick one second. */ + do { + first_cp0 = cp0_get_count(); + (*cd->tod_get)(cd->tod_cookie, 0, &ct); + } while (ct.sec == first_sec); + first_sec = ct.sec; + /* Let the clock tick one more second. */ + do { + second_cp0 = cp0_get_count(); + (*cd->tod_get)(cd->tod_cookie, 0, &ct); + } while (ct.sec == first_sec); + + cycles_per_sec = second_cp0 - first_cp0; + ci->ci_hw.clock = cycles_per_sec * CP0_CYCLE_DIVIDER; + ci->ci_delayconst = cycles_per_sec; +} + +/* + * Start the real-time and statistics clocks. Leave stathz 0 since there + * are no other timers available. + */ +void +cpu_initclocks() +{ + struct cpu_info *ci = curcpu(); + + hz = 100; + profhz = 100; + stathz = 0; /* XXX no stat clock yet */ + + tick = 1000000 / hz; /* number of micro-seconds between interrupts */ + tickadj = 240000 / (60 * hz); /* can adjust 240ms in 60s */ + + cp0_calibrate(ci); + +#ifndef MULTIPROCESSOR + cp0_timecounter.tc_frequency = + (uint64_t)ci->ci_hw.clock / CP0_CYCLE_DIVIDER; + tc_init(&cp0_timecounter); +#endif + +#ifdef DIAGNOSTIC + if (md_startclock == NULL) + panic("no clock"); +#endif + (*md_startclock)(ci); +} + +/* + * 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 +setstatclockrate(int newhz) +{ +} + +/* XXX switch to kern/clock_subr.c routines */ +/* + * This code is defunct after 2099. Will Unix still be here then?? + */ +static short dayyr[12] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +#define SECMIN (60) /* seconds per minute */ +#define SECHOUR (60*SECMIN) /* seconds per hour */ + +#define YEARDAYS(year) (((((year) + 1900) % 4) == 0 && \ + ((((year) + 1900) % 100) != 0 || \ + (((year) + 1900) % 400) == 0)) ? 366 : 365) + +/* + * Initialize the time of day register, based on the time base which + * is, e.g. from a filesystem. + */ +void +inittodr(time_t base) +{ + struct timespec ts; + struct tod_time c; + struct tod_desc *cd = &sys_tod; + int days, yr; + + ts.tv_nsec = 0; + + if (base < 35 * SECYR) { + printf("WARNING: preposterous time in file system"); + /* read the system clock anyway */ + base = 40 * SECYR; /* 2010 */ + } + + /* + * Read RTC chip registers NOTE: Read routines are responsible + * for sanity checking clock. Dates after 19991231 should be + * returned as year >= 100. + */ + if (cd->tod_get) { + (*cd->tod_get)(cd->tod_cookie, base, &c); + } else { + printf("WARNING: No TOD clock, believing file system.\n"); + goto bad; + } + + days = 0; + for (yr = 70; yr < c.year; yr++) { + days += YEARDAYS(yr); + } + + days += dayyr[c.mon - 1] + c.day - 1; + if (YEARDAYS(c.year) == 366 && c.mon > 2) { + days++; + } + + /* now have days since Jan 1, 1970; the rest is easy... */ + ts.tv_sec = days * SECDAY + c.hour * 3600 + c.min * 60 + c.sec; + tc_setclock(&ts); + cd->tod_valid = 1; + + /* + * See if we gained/lost time. + */ + if (base < ts.tv_sec - 5*SECYR) { + printf("WARNING: file system time much less than clock time\n"); + } else if (base > ts.tv_sec + 5*SECYR) { + printf("WARNING: clock time much less than file system time\n"); + printf("WARNING: using file system time\n"); + } else { + return; + } + +bad: + ts.tv_sec = base; + tc_setclock(&ts); + cd->tod_valid = 1; + printf("WARNING: CHECK AND RESET THE DATE!\n"); +} + +/* + * Reset the TOD clock. This is done when the system is halted or + * when the time is reset by the stime system call. + */ +void +resettodr() +{ + struct tod_time c; + struct tod_desc *cd = &sys_tod; + int t, t2; + + /* + * Don't reset TOD if time has not been set! + */ + if (!cd->tod_valid) + return; + + /* compute the day of week. 1 is Sunday*/ + t2 = time_second / SECDAY; + c.dow = (t2 + 5) % 7 + 1; /* 1/1/1970 was thursday */ + + /* compute the year */ + t = 0; + t2 = time_second / SECDAY; + c.year = 69; + while (t2 >= 0) { /* whittle off years */ + t = t2; + c.year++; + t2 -= YEARDAYS(c.year); + } + + /* t = month + day; separate */ + t2 = YEARDAYS(c.year); + for (c.mon = 1; c.mon < 12; c.mon++) { + if (t < dayyr[c.mon] + (t2 == 366 && c.mon > 1)) + break; + } + + c.day = t - dayyr[c.mon - 1] + 1; + if (t2 == 366 && c.mon > 2) { + c.day--; + } + + t = time_second % SECDAY; + c.hour = t / 3600; + t %= 3600; + c.min = t / 60; + c.sec = t % 60; + + if (cd->tod_set) + (*cd->tod_set)(cd->tod_cookie, &c); +} |