284 lines
7.9 KiB
C
Executable File
284 lines
7.9 KiB
C
Executable File
/*
|
|
* Copyright (c) 1991, 1993 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#ifndef _SYS_CLOCK_H
|
|
#define _SYS_CLOCK_H
|
|
|
|
#pragma ident "@(#)clock.h 1.20 95/07/23 SMI"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <sys/spl.h>
|
|
|
|
#ifndef _ASM
|
|
|
|
#define NCLKS 2
|
|
struct clk_info {
|
|
volatile u_longlong_t *clk_clrintr_addr;
|
|
volatile u_longlong_t *clk_mapintr_addr;
|
|
volatile u_longlong_t *clk_count_addr;
|
|
volatile u_longlong_t *clk_limit_addr;
|
|
u_int clk_inum;
|
|
u_int clk_limit;
|
|
u_char clk_use;
|
|
u_char clk_cpuid;
|
|
u_short clk_level;
|
|
};
|
|
extern struct clk_info clks[NCLKS];
|
|
|
|
#ifdef _KERNEL
|
|
|
|
#define CLK0_CNT_OFFSET 0x0
|
|
#define CLK0_LMT_OFFSET 0x8
|
|
#define CLK1_CNT_OFFSET 0x10
|
|
#define CLK1_LMT_OFFSET 0x18
|
|
#define CLK0_CLR_OFFSET 0x0
|
|
#define CLK1_CLR_OFFSET 0x8
|
|
#define CLK0_MAP_OFFSET 0x0
|
|
#define CLK1_MAP_OFFSET 0x8
|
|
|
|
#define SYSIO_CLK0_INO 0x30
|
|
|
|
extern caddr_t v_eeprom_addr;
|
|
#define V_TOD_OFFSET 0x1FF0
|
|
#define V_TODCLKADDR (v_eeprom_addr+V_TOD_OFFSET)
|
|
|
|
extern int Cpudelay;
|
|
extern void setcpudelay(void);
|
|
extern u_int cpu_tick_freq;
|
|
|
|
extern u_int nsec_scale;
|
|
|
|
extern char clock_started;
|
|
extern void start_mon_clock(void);
|
|
extern void stop_mon_clock(void);
|
|
|
|
extern void clkstart();
|
|
extern void start_snooping(int);
|
|
|
|
/*
|
|
* TICKINT Support
|
|
*
|
|
*/
|
|
|
|
/* tickint client info structure */
|
|
struct tick_info {
|
|
void (*handler)();
|
|
long long interval;
|
|
u_int skip;
|
|
};
|
|
|
|
#define TICK_CLNTS 2
|
|
|
|
#endif /* _KERNEL */
|
|
|
|
#endif /* _ASM */
|
|
|
|
/*
|
|
* Limit Register defines
|
|
*/
|
|
#define LIMIT_INT_EN 0x80000000 /* Enable interrupts from counter */
|
|
#define LIMIT_RELOAD 0x40000000 /* counter resstarts at 0 */
|
|
#define LIMIT_PERIODIC 0x20000000 /* ditto when limit is reached */
|
|
#define LIMIT_MASK 0x1FFFFFFF /* counter intr. comparison value */
|
|
|
|
/*
|
|
* Level (pil) defines
|
|
*/
|
|
#define LEVEL10 10
|
|
#define LEVEL14 14
|
|
|
|
/*
|
|
* Use defines
|
|
*/
|
|
#define CLK_NOTINUSE 0x00
|
|
#define CLK_PROM 0x01
|
|
#define CLK_SYSTEM 0x02
|
|
|
|
/*
|
|
* Definitions for the Mostek 48T02 clock chip. We use this chip as
|
|
* our TOD clock. Clock interrupts are generated by a separate timer
|
|
* circuit.
|
|
*/
|
|
|
|
#define YRBASE 68 /* 1968 - what year 0 in chip represents */
|
|
|
|
#define NANOSEC 1000000000
|
|
#define ADJ_SHIFT 4 /* used in get_hrestime and _level10 */
|
|
#define NSEC_SHIFT 11
|
|
#define NSEC_SHIFT1 4
|
|
#define NSEC_SHIFT2 7
|
|
|
|
#ifndef _ASM
|
|
struct mostek48T59 {
|
|
volatile u_char clk_flags; /* flags register */
|
|
volatile u_char clk_unused; /* unused */
|
|
volatile u_char clk_alm_secs; /* alarm - seconds 0-59 */
|
|
volatile u_char clk_alm_mins; /* alarm - minutes 0-59 */
|
|
volatile u_char clk_alm_hours; /* alarm - hours 0-23 */
|
|
volatile u_char clk_alm_day; /* alarm - day 1-31 */
|
|
volatile u_char clk_interrupts; /* interrupts register */
|
|
volatile u_char clk_watchdog; /* watchdog register */
|
|
volatile u_char clk_ctrl; /* ctrl register */
|
|
volatile u_char clk_sec; /* counter - seconds 0-59 */
|
|
volatile u_char clk_min; /* counter - minutes 0-59 */
|
|
volatile u_char clk_hour; /* counter - hours 0-23 */
|
|
volatile u_char clk_weekday; /* counter - weekday 1-7 */
|
|
volatile u_char clk_day; /* counter - day 1-31 */
|
|
volatile u_char clk_month; /* counter - month 1-12 */
|
|
volatile u_char clk_year; /* counter - year 0-99 */
|
|
};
|
|
#define CLOCK ((struct mostek48T59 *)(V_TODCLKADDR))
|
|
#endif /* _ASM */
|
|
|
|
/*
|
|
* Bit masks for various operations and register limits.
|
|
*/
|
|
#define CLK_CTRL_WRITE 0x80
|
|
#define CLK_CTRL_READ 0x40
|
|
#define CLK_CTRL_SIGN 0x20
|
|
|
|
#define CLK_STOP 0x80
|
|
#define CLK_KICK 0x80
|
|
#define CLK_FREQT 0x40
|
|
|
|
#define CLK_MONTH_MASK 0x1f
|
|
#define CLK_DAY_MASK 0x3f
|
|
#define CLK_WEEKDAY_MASK 0x07
|
|
#define CLK_HOUR_MASK 0x3f
|
|
#define CLK_MIN_MASK 0x7f
|
|
#define CLK_SEC_MASK 0x7f
|
|
|
|
/*
|
|
* These macros were split from sparc9/sys/machlock.h because of the
|
|
* way sun4u's cross-call handshake works. If a cross-call happens
|
|
* while one cpu has hres_lock and another is trying to acquire it
|
|
* in its clock interrupt handler; the system will deadlock since
|
|
* the first cpu will never release hres_lock since it's waiting
|
|
* to be released from the cross-call, and the cross-call can't
|
|
* complete because the second cpu is spinning on hres_lock with
|
|
* traps disabled. The fix is to block cross-calls while holding
|
|
* hres_lock.
|
|
*/
|
|
|
|
/*
|
|
* CLOCK_LOCK() puts a "ff" in the lowest byte of the hres_lock. The
|
|
* higher three bytes are used as a counter. This lock is acquired
|
|
* around "hrestime" and "timedelta". This lock is acquired to make
|
|
* sure that level10 accounts for changes to this variable in that
|
|
* interrupt itself. The level10 interrupt code also acquires this
|
|
* lock.
|
|
*
|
|
* CLOCK_UNLOCK() increments the lower bytes straight, thus clearing the
|
|
* lock and also incrementing the 3 byte counter. This way GET_HRESTIME()
|
|
* can figure out if the value in the lock got changed or not.
|
|
*/
|
|
|
|
#define HRES_LOCK_OFFSET 3
|
|
|
|
#define CLOCK_LOCK() \
|
|
lock_set_spl(((lock_t *)&hres_lock) + HRES_LOCK_OFFSET, \
|
|
ipltospl(XCALL_PIL))
|
|
|
|
#define CLOCK_UNLOCK(spl) \
|
|
hres_lock++; \
|
|
(void) splx(spl)
|
|
|
|
|
|
/*
|
|
* NOTE: the macros below assume that the various time-related variables
|
|
* (hrestime, hrestime_adj, hres_last_tick, timedelta, etc) are all
|
|
* stored together at a 64-byte boundary. The real motivation is cache
|
|
* performance, but here we take advantage of the side effect that all
|
|
* these variables have the same high 22 address bits -- thus, only one
|
|
* sethi is required.
|
|
*/
|
|
|
|
/*
|
|
* macro to get time in nanoseconds since boot from %tick
|
|
* nsec = count << NSEC_SHIFT * nsec_scale
|
|
* (%tick gets reset only by XIR)
|
|
*/
|
|
#define GET_NSEC(scr1, scr2); \
|
|
rd %asr4, scr1; /* read %tick register */ \
|
|
sllx scr1, 1, scr1; /* clear NPT bit */ \
|
|
srlx scr1, 1, scr1; \
|
|
sethi %hi(nsec_scale), scr2; \
|
|
ld [scr2 + %lo(nsec_scale)], scr2; \
|
|
srlx scr1, NSEC_SHIFT1, scr1; \
|
|
mulx scr1, scr2, scr1; \
|
|
srlx scr1, NSEC_SHIFT2, scr1;
|
|
|
|
/*
|
|
* macro to get high res time in nanoseconds since boot to the registers
|
|
* outh and outl.
|
|
* scr1 and scr2 need to be global registers in order to contain 64bit data
|
|
*/
|
|
|
|
#define GET_HRTIME(outh, outl, scr1, scr2); \
|
|
GET_NSEC(scr1, scr2); \
|
|
srlx scr1, 32, outh; /* outh = scr1:hi(32bit) */ \
|
|
sllx scr1, 32, scr1; /* outl = scr1:lo(32bit) */ \
|
|
srlx scr1, 32, outl;
|
|
|
|
|
|
/*
|
|
* This macro return the value of hrestime, hrestime_adj and the counter.
|
|
* It reads the value of hres_lock before and after loading the above
|
|
* values. If the lock value changed in the meanwhile (i.e. level10 is/was
|
|
* being processed on another processor or someone updated the hrestime_adj
|
|
* and/or hrestime), the macro reads the value again.
|
|
*
|
|
* It assumes that the adj and hrest are global registers in order to
|
|
* contain 64 bit data.
|
|
* This macro is called from trap (0x127) in sparc9_subr.s.
|
|
*/
|
|
|
|
/*
|
|
* WARNING: branches are hand-computed to prevent hidden conflicts with
|
|
* local labels in the caller. If you ever change these macros, make
|
|
* sure you recompute the branch targets.
|
|
*/
|
|
|
|
#define GET_HRESTIME(out, scr, scr1, adj, hrest); \
|
|
/* 1 */ sethi %hi(hres_lock), scr; \
|
|
ld [scr + %lo(hres_lock)], scr1; /* load clock lock */ \
|
|
GET_NSEC(hrest, adj); /* get nsec in hrest */ \
|
|
ldx [scr + %lo(hres_last_tick)], adj; \
|
|
sub hrest, adj, out; \
|
|
ldx [scr + %lo(hrestime)], hrest; /* load hrestime */ \
|
|
ldx [scr + %lo(hrestime_adj)], adj; /* load hrestime_adj */ \
|
|
ld [scr + %lo(hres_lock)], scr; /* load clock lock */ \
|
|
andn scr1, 1, scr1; /* so cmp can detect lock still held */ \
|
|
cmp scr1, scr; \
|
|
/* CSTYLED */ \
|
|
bne,pn %xcc, . - 17*4; /* 1b */ \
|
|
nop;
|
|
/*
|
|
* This macro is here to support vtrace 3.x, which is microsecond-based.
|
|
* This will go away with vtrace 4.0.0, which will be nanosecond-based.
|
|
*/
|
|
|
|
/*
|
|
* XXX
|
|
* It's called from the macro "TRACE_DUMP_HEAD()" in asm_linkage.h.
|
|
* It assumes that scr1 and scr2 are global registers.
|
|
*/
|
|
|
|
#define GET_VTRACE_TIME(out, scr1, scr2); \
|
|
GET_NSEC(scr1, scr2); /* get nsec */ \
|
|
udivx scr1, 1000, scr1; /* convert to usec */ \
|
|
srl scr1, 0, out; /* XXX assume it's 32 bit */
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* !_SYS_CLOCK_H */
|